feat(frontend): adapters, services, state and forms engine - #77
Open
maan-iitd2 wants to merge 1 commit into
Open
feat(frontend): adapters, services, state and forms engine#77maan-iitd2 wants to merge 1 commit into
maan-iitd2 wants to merge 1 commit into
Conversation
DhirajRathore
approved these changes
Sep 5, 2026
There was a problem hiding this comment.
🟡 Changes recommended
Several generated configuration shapes are incompatible with backend contracts, alongside adapter and shortcut correctness issues.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds the frontend data, state, hook, and schema-driven form foundations for InGen Studio.
Changes:
- Adds mock/HTTP adapters and domain services.
- Adds shared React contexts, history, and workspace hooks.
- Adds reusable schema-based form fields and backend configuration schemas.
File summaries
| File | Description |
|---|---|
frontend/src/state/ViewModeContext.jsx |
Shares editor view mode. |
frontend/src/state/useModelHistory.test.js |
Tests history transitions. |
frontend/src/state/useModelHistory.js |
Implements bounded undo/redo. |
frontend/src/state/RunContext.jsx |
Manages run lifecycle. |
frontend/src/state/GraphSelectionContext.jsx |
Shares graph selection. |
frontend/src/state/ConfigContext.jsx |
Manages editing and autosave. |
frontend/src/state/ChatSessionContext.jsx |
Coordinates chat sessions. |
frontend/src/state/CatalogContext.jsx |
Provides catalog data. |
frontend/src/services/validationService.js |
Defines validation contract. |
frontend/src/services/runService.js |
Defines run contract. |
frontend/src/services/index.js |
Locates configured services. |
frontend/src/services/historyService.js |
Defines history contract. |
frontend/src/services/fileService.js |
Adds file/source requests. |
frontend/src/services/configService.js |
Defines config contract. |
frontend/src/services/chatHistoryService.js |
Persists chat sessions. |
frontend/src/services/catalogService.js |
Defines catalog contract. |
frontend/src/lib/columnStore.js |
Caches source columns. |
frontend/src/hooks/useWorkspaceShortcuts.js |
Adds workspace shortcuts. |
frontend/src/hooks/useSourceActions.js |
Centralizes source actions. |
frontend/src/hooks/useDocTitle.js |
Updates document titles. |
frontend/src/forms/schemas/validationSchemas.js |
Defines validation metadata. |
frontend/src/forms/schemas/sourceSchemas.js |
Defines source forms. |
frontend/src/forms/schemas/preProcessorSchemas.js |
Defines preprocessor forms. |
frontend/src/forms/schemas/outputSchemas.js |
Defines output forms. |
frontend/src/forms/schemas/formatterSchemas.js |
Defines formatter forms. |
frontend/src/forms/SchemaForm.jsx |
Renders descriptor-driven forms. |
frontend/src/forms/fields/Fields.jsx |
Provides form primitives. |
frontend/src/adapters/mockValidationAdapter.js |
Simulates validation results. |
frontend/src/adapters/mockRunAdapter.js |
Simulates run execution. |
frontend/src/adapters/mockHistoryAdapter.js |
Stores local run history. |
frontend/src/adapters/mockConfigAdapter.js |
Stores local configurations. |
frontend/src/adapters/mockChatAdapter.js |
Provides mock chat fallback. |
frontend/src/adapters/mockCatalogAdapter.js |
Supplies static catalog data. |
frontend/src/adapters/index.js |
Selects adapter implementations. |
frontend/src/adapters/httpValidationAdapter.js |
Provides HTTP validation preview. |
frontend/src/adapters/httpRunAdapter.js |
Executes runs through FastAPI. |
frontend/src/adapters/httpHistoryAdapter.js |
Reads backend run history. |
frontend/src/adapters/httpConfigAdapter.js |
Adds backend config validation. |
frontend/src/adapters/httpClient.js |
Wraps JSON HTTP requests. |
frontend/src/adapters/httpChatAdapter.js |
Connects to backend chat. |
Review details
Suppressed comments (1)
frontend/src/services/fileService.js:20
- Column discovery also always calls FastAPI, so selecting mock mode does not provide the stated zero-backend workflow for configured sources. Put this operation behind the adapter/service seam or expose it as unsupported and prevent the mock UI from invoking it.
const res = await fetch(`${API}/api/sources/columns`, {
- Files reviewed: 40/40 changed files
- Comments generated: 10
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| column, | ||
| expectation: v.type, | ||
| severity: v.severity ?? 'warning', | ||
| status: 'passed', // preview only — real status comes from a run |
Comment on lines
+35
to
+39
| json_writer: { | ||
| label: 'JSON writer', | ||
| schema: [ | ||
| { key: 'destination', label: 'Destination', kind: 'select', options: ['file', 'api'], help: 'Where to write the JSON output' }, | ||
| { key: 'destination_props', label: 'Destination props', kind: 'group', fields: [ |
Comment on lines
+48
to
+52
| splitted_file: { | ||
| label: 'Splitted file', | ||
| schema: [ | ||
| { key: 'path', label: 'Output directory', kind: 'text', placeholder: 'out/splits/', help: 'Files are written as <directory>/<split_col_value>.<ext>' }, | ||
| { key: 'split_col', label: 'Split column', kind: 'text', help: 'Each unique value in this column produces a separate file' }, |
Comment on lines
+27
to
+29
| async clear() { | ||
| // No-op: no delete endpoint in scope; history is backend-owned in HTTP mode. | ||
| } |
| let interfaceAborted = false; | ||
| for (const stage of order) { | ||
| if (isCancelled?.()) { cancelled = true; break; } | ||
| if (interfaceAborted) { stages.push({ interface: name, stage, status: 'skipped', durationMs: 0 }); continue; } |
| <select | ||
| className="field__input" | ||
| value={value ?? ''} | ||
| onChange={(e) => onChange(e.target.value === '' ? undefined : e.target.value)} |
| { key: 'data_node', label: 'data_node', kind: 'tags' }, | ||
| { key: 'data_key', label: 'data_key', kind: 'tags' }, | ||
| { key: 'success_criteria', label: 'Success criteria', kind: 'text' }, | ||
| { key: 'criteria_option', label: 'Criteria option', kind: 'json', rows: 2, visibleIf: (v) => !!v.success_criteria }, |
| } else if (e.key === 'z' && !e.shiftKey) { | ||
| e.preventDefault(); | ||
| onUndo?.(); | ||
| } else if (e.key === 'y' || (e.key === 'z' && e.shiftKey)) { |
| export async function uploadFile(file) { | ||
| const body = new FormData(); | ||
| body.append('file', file); | ||
| const res = await fetch(`${API}/api/files/upload`, { method: 'POST', body }); |
Comment on lines
+15
to
+17
| export function pushSnapshot(past, model, max = MAX_HISTORY) { | ||
| return [...past.slice(-(max - 1)), model]; | ||
| } |
Signed-off-by: maan-iitd2 <maan.iitd.ac.in@gmail.com>
Jatin-8898
force-pushed
the
pr/frontend-services-state
branch
from
September 9, 2026 18:52
62d5640 to
91935b1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the service layer that sits between InGen Studio's UI and its data: pluggable adapters, the
services that wrap them, React context providers for shared state, two small hooks, and a
schema-driven forms engine.
This is part 2 of the frontend series. It is all new files under
frontend/src/— nothingexisting is modified.
src/adapters/mock*(localStorage, no server needed) andhttp*(talks to the FastAPI wrapper). Selected byNEXT_PUBLIC_ADAPTER_MODE.src/services/src/state/useModelHistory(undo/redo).src/hooks/useDocTitle,useWorkspaceShortcuts.src/forms/SchemaForm+ field components — renders the source/column editors from schema definitions rather than hand-written forms.src/lib/columnStore.jsThis builds on #76 and CI will fail here until #76 merges. These modules import
@/models/*and@/serializers/*, which #76 introduces. That is expected — not a defect in thisbranch.
The diff itself is conflict-free and independent: this PR touches no file that #76 or any other
open PR touches, so it can be merged in any order once #76 lands.
src/lib/fuzzy.jsandsrc/utils/id.jsare absent by design — they are already in #76, wherethey were needed for that PR's tests to run. This PR does not re-ship them.
Design notes for reviewers
interface, so the whole UI runs with zero backend in
mockmode. That is what makes the appdemo-able and testable without standing up Python.
re-renders localised. If you'd prefer a single reducer, say so — it's a contained change.
useModelHistorykeeps bounded undo/redo stacks with a max size, so long editing sessions don'tgrow memory without limit.
Testing
Verified on a local integration branch (
main+ #76 + this PR + the two follow-up frontend PRs):npm run test— 57/57 pass, including this PR'sstate/useModelHistory.test.jsnpm run build— fullnext buildcompiles clean, all 6 routes generatednpm run devin mock mode — browser smoke pass over start screen → editor → run console, 0console errors
pytest test/andpytest backend/tests/(42 passed) show no new failuresQuality gates
All green on the integration branch:
npm run lintnpm run testnpm run buildpytest test/pytest backend/tests/What it looks like
The schema-driven forms engine in action — this source editor is not hand-written JSX. It is
generated from a field-descriptor array in
src/forms/schemas/, which is what keeps source,pre-processor, formatter and output forms from being four copies of the same code:
The state and adapter layers in this PR are what keep the YAML panel on the right in sync on every
edit.
🤖 Generated with Claude Code