Commit Graph
27 Commits
Author SHA1 Message Date
marcopanandClaude Opus 4.8 4e6d4a4cea feat(frontend): restyle ThothII to the Omics Portal (GSD) design system
Adopt the portal's design language so the app embeds seamlessly into its
header/sidebar chrome later:
- Token layer rewritten as raw OKLCH triplets (the previous oklch()-wrapped
  vars produced invalid colors; the UI was effectively unstyled). Values mirror
  GSD: Manrope + Fraunces fonts, #cb333b red brand, warm off-white surfaces,
  pill buttons, brand focus rings. Dark tokens follow .dark or the portal's
  [data-bs-theme=dark].
- Layout: no left sidebar, no header (the portal supplies them). Conversation
  column flush-left with a slim F1-F8 phase strip; session rail moved to the
  RIGHT, mirroring the portal's left sidebar (red section label, red-tint active
  item). Editorial empty state.
- Transcript component now actually renders the streamed assistant turns (the
  store accumulated them but nothing displayed them). Toaster mounted for errors
  (matchMedia polyfill added to the jsdom test setup).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 18:05:23 +02:00
marcopanandClaude Opus 4.8 abfee5a6fe feat(frontend): add Settings menu item under Nuova domanda
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 16:30:40 +02:00
marcopanandClaude Opus 4.8 5d79437daf fix(frontend): read MSW request body once in SettingsDialog test (pristine output)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 16:29:01 +02:00
marcopanandClaude Opus 4.8 29b7e85510 feat(frontend): SettingsDialog with workspace/provider/model/thinking selects
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 16:26:32 +02:00
marcopanandClaude Opus 4.8 32d963b43d feat(frontend): NewSessionDialog reduced to question-only
Removes workspace/model/provider/thinking fields. Dialog now posts only { question } to createSession and calls onCreated on success.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 16:22:57 +02:00
marcopanandClaude Opus 4.8 fa0f878c97 feat(frontend): settings api, typed PiModel, question-only createSession
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 16:19:51 +02:00
marcopanandClaude Opus 4.8 5295e34898 fix(frontend): wire currentPhase to WorkflowBar (normalized) + WidgetHost error handling
- sessionStore.applyEvent: on ui_request set currentPhase normalized from the
  descriptor's phase to its short id (e.g. "F4_schema_linking" -> "F4"), so
  WorkflowBar actually highlights the active phase; falls back to the existing
  phase when the descriptor has none. setPhase kept for resume/getSession.
- Add pushToast store action; WidgetHost wraps postResponse in try/catch,
  pushes an error toast and keeps the widget pending on failure (clearPending
  only on success) so the user can retry.
- Tests: store currentPhase normalization + no-phase passthrough + pushToast;
  new WorkflowBar.test.tsx asserting the matching phase is highlighted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 13:40:33 +02:00
marcopanandClaude Opus 4.8 ddbbe4d1ac test(frontend): unit tests exercise named SSE events (fidelity) + cleanup
FakeEventSource.addEventListener was a no-op, so emit() only drove onmessage.
Production relies on addEventListener for the backend's NAMED events
(event: ui_request), so the unit tests could pass while prod silently broke.

- fakeEventSource: store named handlers in a Map<string,Set>; add emitNamed()
  that dispatches to them; keep emit() for the unnamed/default onmessage path
- useSessionStream.test: ui_request now driven via emitNamed (production path);
  add a separate test for the unnamed text_delta path via plain emit
- f1-loop.test: widget emission switched to emitNamed("ui_request", ...)
- verified: tests FAIL if addEventListener wiring is removed from
  useSessionStream (then restored)
- cleanup: fake-pi.mjs drops unused execFileSync import, uses static spawnSync

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 13:33:50 +02:00
marcopanandClaude Sonnet 4.6 1171181f9a test(frontend): Playwright e2e F1 vs backend+fake-pi (hermetic)
Adds a real-browser Playwright e2e of the full F1 disambiguation loop,
driven against the real backend + fake binaries (no VPN, no real Pi, no Python).

- frontend/e2e/fixtures/fake-tht.mjs: stubs tht CLI (session new/list/show)
- frontend/e2e/fixtures/fake-pi.mjs: wraps harness fake-pi-rpc with f1_disambiguation.json
- frontend/playwright.config.ts: two webServer entries (backend:8799, frontend:5199)
- frontend/e2e/f1.spec.ts: open app → create session → wait for SelectWidget → respond

Bug fixes discovered during e2e:
- useSessionStream: add addEventListener for named SSE events (backend sends
  'event: ui_request' etc.; onmessage only fires for unnamed 'event: message')
- FakeEventSource: add no-op addEventListener/removeEventListener stubs
- backend SSE route: add CORS headers manually in writeHead() since
  reply.raw bypasses the @fastify/cors onSend hook
- backend: install and register @fastify/cors for all non-SSE routes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 13:27:00 +02:00
marcopanandClaude Opus 4.8 3dec4c3af0 test(frontend): cover NewSessionDialog model degradation + invalidate sessions on resume
- Add NewSessionDialog.test.tsx covering §9 graceful degradation:
  empty models -> free-text input; non-empty models -> dropdown; plus a
  createSession body-keys assertion
- Normalize model entries to {value,label} so object-shaped models
  ({provider,id}) render correctly in the dropdown (was assuming strings)
- NavSessions: invalidate the ["sessions"] query after a successful
  resumeSession so the list/status refreshes immediately

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 13:11:40 +02:00
marcopanandClaude Sonnet 4.6 544882f95b feat(frontend): sessions list/create + steering + resume + selectors
- NavSessions: left nav listing sessions via listSessions (TanStack Query),
  clicking resumes via resumeSession and sets active; active item highlighted
- NewSessionDialog: ShadCn dialog with question textarea, workspace native
  select (from listWorkspaces), graceful model field (dropdown when models
  list is non-empty, free-text input when empty per §9 degradation),
  optional thinking/provider fields; try/catch surfaces errors inline
- SteerInput: text input + button POSTs to postSteer, clears on send,
  supports Enter key; only shown when a session is active
- WorkflowBar: renders 8 phases (F1..F8) with data-active highlighting
  driven by useSessionStore.currentPhase (new store field + setPhase action)
- AppShell: wires all four components; right artifact sidebar now collapsible
  via a toggle button (useState sidebarOpen); replaces old "Nuova domanda"
  button with NewSessionDialog trigger
- f1-loop.test: updated to drive through the new dialog flow (open → fill
  question → submit → wait for SSE → respond)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 13:06:01 +02:00
marcopanandClaude Opus 4.8 3ecfed5d3d fix(frontend): valid scalar markup + selector/truncated coverage in ResultsPanel
- Replace invalid role="strong" with data-testid="scalar-value"
- Add test (d): selecting "tutti" re-fetches preview with the large limit
- Render "(risultati troncati)" indicator when truncated; assert in test (a)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 13:00:50 +02:00
marcopanandClaude Sonnet 4.6 b4ab7b005a feat(frontend): results panel (AGGrid + preview/export)
Add ResultsPanel component with AGGrid v36 for tabular preview results,
bold scalar display for 1×1 results, limit selector (10 / tutti), and
Esporta CSV button delegating export to the backend. MSW-tested with 3
passing scenarios (grid cells, scalar, export endpoint call).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 12:57:08 +02:00
marcopanandClaude Sonnet 4.6 38032877e9 test(frontend): settle async highlight in SqlViewer test (pristine output) + assert toggle flip
Test (a) now drains pending highlightSql microtasks inside act() via
waitFor before synchronous header assertions, eliminating the React
act() warning. Test (c) asserts the layout toggle label flips
Orizzontale -> Verticale rather than merely existing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 12:53:59 +02:00
marcopanandClaude Sonnet 4.6 954f701c3f feat(frontend): SQL/CTE viewer with shiki highlighting
TDD: SqlViewer renders collapsible CTE blocks with name/field-count/
test-status badges, shiki-highlighted SQL body (dangerouslySetInnerHTML),
per-field comments, and a vertical/horizontal layout toggle.
highlight.ts wraps shiki as a lazy singleton; tests mock it for
determinism (pattern mirrors mermaid.ts).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 12:49:58 +02:00
marcopanandClaude Opus 4.8 eb552331a6 fix(frontend): cap schema-linking graph on promoted count + signals in table Perché
- Cap counts promoted candidates only (was all candidates); reuse promoted list (DRY)
- New test: 10 promoted + 50 excluded must not cap, graph stays available
- Extract reasonFor() helper; table Perché falls back to signal keys like the flowchart

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 12:47:29 +02:00
marcopanandClaude Sonnet 4.6 2a23de6825 feat(frontend): schema-linking viewer (mermaid+table) + markdown view
TDD: SchemaLinkingViewer with mocked renderMermaid, toggle flowchart↔table,
≤45 element cap with Italian notice. MarkdownView renders mermaid fences.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 12:43:11 +02:00
marcopan f933b544ff test(frontend): cover ArtifactWidget view-only + multiselect allow_empty gate 2026-06-28 12:40:09 +02:00
marcopan be9e761e0a feat(frontend): multiselect/artifact-gate/artifact widgets + linkage + no-limbo 2026-06-28 12:36:13 +02:00
marcopanandClaude Sonnet 4.6 2b55e96608 feat(frontend): 4-zone shell + F1 loop end-to-end (MSW)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 12:30:35 +02:00
marcopan a267754f8f feat(frontend): F1 widgets (select/info/freetext) + reserved controls 2026-06-28 12:25:50 +02:00
marcopan e9aca179d7 feat(frontend): widget registry + universal fallback 2026-06-28 12:22:37 +02:00
marcopan d238ddd395 feat(frontend): useSessionStream (EventSource -> store) 2026-06-28 12:19:55 +02:00
marcopan ebd3988634 feat(frontend): Zustand session store + applyEvent 2026-06-28 12:17:16 +02:00
marcopanandClaude Sonnet 4.6 913ac30137 feat(frontend): contract types + REST client (MSW-tested)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 12:13:50 +02:00
marcopanandClaude Sonnet 4.6 7e42ac11ef chore(frontend): gitignore tsbuildinfo + shadcn to devDeps
Untrack tsconfig.tsbuildinfo (TS build artifact) and add *.tsbuildinfo
to .gitignore. Move shadcn from dependencies to devDependencies (CLI
generator, not runtime). npm test passes; npm run build clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 12:11:16 +02:00
marcopanandClaude Sonnet 4.6 662d944267 feat(frontend): scaffold Vite+React+TS+Tailwind/ShadCn + Vitest
TDD: App-renders-ThothII test RED then GREEN. ShadCn v4 (base-nova style)
init + button/checkbox/radio-group/textarea/card/dialog/badge/sonner added.
tailwind.config.ts extended with oklch CSS-variable color mapping required
by ShadCn v4 @apply directives. npm test passes; npm run build clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 12:08:22 +02:00