Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
d62e6d1
fix: increase token limit sent to LLM
elainefan331 Apr 1, 2026
843f0a2
fix: resolve leaks in previewModal 3D viewer
elainefan331 Apr 1, 2026
e54ea6f
fix: resolve memory leaks in 2D plot viewer
elainefan331 Apr 2, 2026
ecf15eb
[debug] print github action server IP
fangq Apr 2, 2026
66f6e43
feat: add executorHelpers and plannerHelpers
elainefan331 Apr 2, 2026
edb2a8f
feat: reorganize the code for integrated autobidsify
elainefan331 Apr 3, 2026
99be7a9
Merge pull request #124 from NeuroJSON/dev-fan
elainefan331 Apr 9, 2026
d7176a3
fix: support double-click to reset uPlot series on Mac
elainefan331 Apr 14, 2026
ad92d72
fix: strip markdown fences from BIDSPlan YAML string before saving
elainefan331 Apr 16, 2026
072db3d
fix: expand external data path segments and add 2D plot interaction tips
elainefan331 Apr 16, 2026
2fffdb9
feat: show source path and index above 2D chart panel
elainefan331 Apr 16, 2026
badf503
feat: add axis labels to 2D plot(Sample / a.u.
elainefan331 May 6, 2026
7a303ed
refactor: point baseURL to Express server and remove cors proxy logic…
elainefan331 May 6, 2026
0f7fbff
feat: map all external API calls through Express to bypass firewall p…
elainefan331 May 6, 2026
c450eb4
fix: clear stale document and revision state when navigating between …
elainefan331 May 6, 2026
9fff3dc
Merge pull request #126 from NeuroJSON/dev-fan
elainefan331 May 7, 2026
67cb50e
feat: add search tables migration and update db config for local post…
elainefan331 May 7, 2026
7432b35
feat: add incremental sync script to populate ioviews and iolinks fro…
elainefan331 May 8, 2026
f686418
feat: refactor incremental sync with transactions, concurrency, and e…
elainefan331 May 8, 2026
9d69223
feat: add ioviews unique constraint migration and disable sequelize l…
elainefan331 May 8, 2026
627e598
feat: replace CGI search with PostgreSQL query in searchAllDatabases …
elainefan331 May 11, 2026
207c634
fix: widen ioviews and iolinks text columns to handle longer values
elainefan331 May 11, 2026
4490af6
fix: make suggested databases refresh on Search click
elainefan331 May 11, 2026
5966b09
feat: modality-aware combobox for Data type filter
elainefan331 May 11, 2026
d101e5c
feat(search): add draggable age-range slider at top of subject filters
elainefan331 May 11, 2026
88474cc
feat(search): add placeholder hints to task/session/run keyword fields
elainefan331 May 11, 2026
b9be29f
feat(search): pair min/max count fields on one row and tighten gaps(s…
elainefan331 May 11, 2026
df73e1c
feat(search): show run count in subject card
elainefan331 May 11, 2026
44635bd
feat(backend): add file type filter to search using iolinks table
elainefan331 May 12, 2026
1b0aa65
feat(search): add multi-select File types filter (dataset-level)
elainefan331 May 12, 2026
9f826d4
fix(search): age slider per-handle clearing + non-BIDS file-type warning
elainefan331 May 12, 2026
38fc1cb
fix(search): highlight each word of multi-word keyword independently
elainefan331 May 12, 2026
bebd036
fix(search): keyword highlight reads from appliedFilters, not formData
elainefan331 May 12, 2026
fba0240
feat: add file download endpoints for dataset search results
elainefan331 May 13, 2026
51960cf
feat(search): show matching files in dataset card with selective and …
elainefan331 May 13, 2026
5677c74
fix(search): use plainto_tsquery + normalize ILIKE separators for key…
elainefan331 May 13, 2026
bf1abe3
fix(search): match dataset display name via json->>'name' ILIKE
elainefan331 May 13, 2026
6fce063
feat(search): add Mac/Linux and Windows script options to file download
elainefan331 May 14, 2026
8be3fa1
fix(dataset-detail): keep all downloaded files in one visible folder
elainefan331 May 15, 2026
e21c661
feat(dataset-detail): three script formats for download all files button
elainefan331 May 15, 2026
909cd36
feat(sync): pull database list from registry
elainefan331 May 20, 2026
0cee8b6
feat(search): add dataset-level modality filter with AND/OR mode
elainefan331 May 21, 2026
601d90b
feat(search): add tooltip to Subject-Level Filters explaining result …
elainefan331 May 22, 2026
5aab808
fix(sync): reject malformed file extensions from CouchDB links view
elainefan331 May 22, 2026
f834a47
style(search): match dataset modality filter UI to file types field
elainefan331 May 25, 2026
faf548f
fix(search): resolve relative-path iolinks URLs for openneuro file links
elainefan331 May 26, 2026
3761e82
feat(bids-converter): add public BIDS Converter page and navbar link
elainefan331 May 26, 2026
11b77bd
feat(bids-converter): add mode selection dialog and private/save togg…
elainefan331 May 26, 2026
7dbb335
feat(dashboard): open Projects tab directly from BIDS Converter redirect
elainefan331 May 27, 2026
71e5ffb
feat(bids-converter): add private mode visual indicator with slate gr…
elainefan331 May 27, 2026
d0537a4
feat(bids-converter): improve UI labels, tooltips, and private mode UX
elainefan331 May 27, 2026
b023711
feat(llm-panel): improve AI Assistant UI labels and UX
elainefan331 May 27, 2026
cf2e445
fix(llm-panel): clear bidsPlan on step 2 re-run so progress shows in …
elainefan331 May 27, 2026
028ee23
feat(llm-panel): UI polish for file tree and output panel
elainefan331 May 27, 2026
60f51ad
feat(ollama): require authentication on Ollama proxy endpoints
elainefan331 May 27, 2026
68218d5
feat(ollama): add public endpoint with 10 requests/day IP rate limit
elainefan331 May 27, 2026
6171e7b
Merge pull request #127 from NeuroJSON/dev-fan
elainefan331 May 28, 2026
1aa509a
feat(llm-panel): add local Ollama provider for private mode with conf…
elainefan331 May 29, 2026
72b6b97
feat(navbar): add AutoBIDSify dropdown with GitHub link and web app; …
elainefan331 May 29, 2026
f344482
feat(autobidsify): rebrand BIDS Converter to AutoBIDSify with navbar …
elainefan331 May 29, 2026
a69ff4a
feat(llm-panel): add local AI support for Ollama, LM Studio, and Jan …
elainefan331 May 29, 2026
1dfc255
feat(ollama): use qwen3.6:27b on server for LLM, hide model selector
elainefan331 May 29, 2026
34d0260
fix(ollama): increase public endpoint rate limit to 20 requests/day
elainefan331 May 29, 2026
60cfdb0
fix(preview): make 2D chart responsive to container width
elainefan331 Jun 1, 2026
ce7db75
Merge pull request #128 from NeuroJSON/dev-fan
elainefan331 Jun 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build-deploy-zodiac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ jobs:
- name: Check out the repository
uses: actions/checkout@v3

- name: Check IP
run: curl https://api.ipify.org

- name: Install dependencies
run: yarn install --frozen-lockfile

Expand Down
15 changes: 12 additions & 3 deletions backend/config/config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
require("dotenv").config();

module.exports = {
// development: {
// dialect: "sqlite",
// storage: "./database.sqlite",
// logging: console.log,
// },
development: {
dialect: "sqlite",
storage: "./database.sqlite",
logging: console.log,
dialect: "postgres",
host: "localhost",
port: 5432,
database: "neurojson_dev",
username: process.env.DB_USER_LOCAL,
password: process.env.DB_PASSWORD_LOCAL,
logging: false,
},
test: {
dialect: "sqlite",
Expand Down
130 changes: 130 additions & 0 deletions backend/migrations/20260507145253-create-search-tables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"use strict";

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
// ioviews table
await queryInterface.createTable("ioviews", {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
dbname: {
type: Sequelize.STRING(30),
allowNull: true,
},
dsname: {
type: Sequelize.STRING(30),
allowNull: true,
},
subj: {
type: Sequelize.STRING(12),
allowNull: true,
},
view: {
type: Sequelize.STRING(12),
allowNull: true,
},
json: {
type: Sequelize.JSONB,
allowNull: true,
},
search_vector: {
type: Sequelize.DataTypes.TSVECTOR,
allowNull: true,
},
updated_at: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"),
},
});

// ioviews indexes
await queryInterface.addIndex("ioviews", ["view"], {
name: "idx_ioviews_view",
});
await queryInterface.addIndex("ioviews", ["dbname"], {
name: "idx_ioviews_dbname",
});
await queryInterface.addIndex("ioviews", ["updated_at"], {
name: "idx_ioviews_updated_at",
});

// GIN indexes need raw query (not supported by addIndex)
await queryInterface.sequelize.query(`
CREATE INDEX IF NOT EXISTS idx_ioviews_search
ON ioviews USING GIN(search_vector);
CREATE INDEX IF NOT EXISTS idx_ioviews_json
ON ioviews USING GIN(json);
`);

// iolinks table
await queryInterface.createTable("iolinks", {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
dbname: {
type: Sequelize.STRING(30),
allowNull: true,
},
dsname: {
type: Sequelize.STRING(30),
allowNull: true,
},
subj: {
type: Sequelize.TEXT,
allowNull: true,
},
view: {
type: Sequelize.TEXT,
allowNull: true,
},
json: {
type: Sequelize.JSONB,
allowNull: true,
},
});

// iolinks indexes
await queryInterface.addIndex("iolinks", ["view"], {
name: "idx_iolinks_view",
});
await queryInterface.addIndex("iolinks", ["dbname"], {
name: "idx_iolinks_dbname",
});
await queryInterface.sequelize.query(`
CREATE INDEX IF NOT EXISTS idx_iolinks_json
ON iolinks USING GIN(json);
`);

// sync_state table
await queryInterface.createTable("sync_state", {
dbname: {
type: Sequelize.STRING(30),
primaryKey: true,
allowNull: false,
},
last_seq: {
type: Sequelize.TEXT,
allowNull: true,
},
synced_at: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"),
},
});
},

async down(queryInterface, Sequelize) {
await queryInterface.dropTable("ioviews");
await queryInterface.dropTable("iolinks");
await queryInterface.dropTable("sync_state");
},
};
20 changes: 20 additions & 0 deletions backend/migrations/20260508195500-add-ioviews-unique-constraint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"use strict";

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
// Required by upsertIoview's ON CONFLICT (dbname, dsname, subj, view).
await queryInterface.addConstraint("ioviews", {
fields: ["dbname", "dsname", "subj", "view"],
type: "unique",
name: "ioviews_dbname_dsname_subj_view_unique",
});
},

async down(queryInterface, Sequelize) {
await queryInterface.removeConstraint(
"ioviews",
"ioviews_dbname_dsname_subj_view_unique"
);
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"use strict";

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
// VARCHAR(n) → TEXT is a metadata-only change in Postgres (no table rewrite,
// no need to drop the unique constraint or indexes).
await queryInterface.changeColumn("ioviews", "dbname", {
type: Sequelize.TEXT,
allowNull: true,
});
await queryInterface.changeColumn("ioviews", "dsname", {
type: Sequelize.TEXT,
allowNull: true,
});
await queryInterface.changeColumn("ioviews", "subj", {
type: Sequelize.TEXT,
allowNull: true,
});
await queryInterface.changeColumn("iolinks", "dbname", {
type: Sequelize.TEXT,
allowNull: true,
});
await queryInterface.changeColumn("iolinks", "dsname", {
type: Sequelize.TEXT,
allowNull: true,
});
await queryInterface.changeColumn("sync_state", "dbname", {
type: Sequelize.TEXT,
allowNull: false,
});
},

async down(queryInterface, Sequelize) {
await queryInterface.changeColumn("ioviews", "dbname", {
type: Sequelize.STRING(30),
allowNull: true,
});
await queryInterface.changeColumn("ioviews", "dsname", {
type: Sequelize.STRING(30),
allowNull: true,
});
await queryInterface.changeColumn("ioviews", "subj", {
type: Sequelize.STRING(12),
allowNull: true,
});
await queryInterface.changeColumn("iolinks", "dbname", {
type: Sequelize.STRING(30),
allowNull: true,
});
await queryInterface.changeColumn("iolinks", "dsname", {
type: Sequelize.STRING(30),
allowNull: true,
});
await queryInterface.changeColumn("sync_state", "dbname", {
type: Sequelize.STRING(30),
allowNull: false,
});
},
};
26 changes: 22 additions & 4 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"migrate:undo:all": "npx sequelize-cli db:migrate:undo:all",
"seed": "npx sequelize-cli db:seed:all",
"seed:undo": "npx sequelize-cli db:seed:undo:all",
"db:reset": "npx sequelize-cli db:migrate:undo:all && npx sequelize-cli db:migrate"
"db:reset": "npx sequelize-cli db:migrate:undo:all && npx sequelize-cli db:migrate",
"sync": "node sync/incrementalSync.js"
},
"keywords": [
"express",
Expand All @@ -28,6 +29,7 @@
"cors": "^2.8.5",
"dotenv": "^17.2.3",
"express": "^5.1.0",
"express-rate-limit": "^8.5.2",
"jsonwebtoken": "^9.0.2",
"nanoid": "^3.3.11",
"nodemailer": "^7.0.11",
Expand Down
Loading
Loading