| # Frontend modules |
|
|
| Module reference for `src/frontend/src/`. The SPA is Vue 3 + Vite + Pinia + Fomantic UI. State is held in Pinia stores; HTTP via axios; streaming inference via a `fetch`-based composable that parses [SSE](../glossary.md#sse-server-sent-events). For an overview of how the SPA fits into the deployed container, see [explanation/architecture.md](../explanation/architecture.md). |
|
|
| ## Project layout |
|
|
| ``` |
| src/frontend/src/ |
| βββ main.js # bootstrap (Pinia, router, theme init) |
| βββ App.vue # shell with NavBar, RouterView, GraphBackground |
| βββ api/ # axios client + per-method API wrappers |
| βββ composables/ # reusable logic (SSE stream) |
| βββ stores/ # Pinia stores (one per demo + theme) |
| βββ router/ # vue-router routes incl. SPA 404 |
| βββ views/ # page-level components |
| βββ components/ # feature-grouped components |
| βββ data/ # static data (CV) |
| βββ styles/ # design tokens + theme + responsive CSS |
| ``` |
|
|
| ## `main.js` β bootstrap |
|
|
| Imports Fomantic CSS, design-token sheets, the App shell, the router and the theme store. Creates a Pinia instance, wires it into the app, calls `useThemeStore().init()` to apply the persisted theme, and mounts to `#app`. |
|
|
| ## `api/` β HTTP client and endpoint wrappers |
|
|
| ### `client.js` |
| Creates the axios instance. The base URL is `${import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:8000'}/api/v1`. The `??` (not `||`) is load-bearing: the production env file sets `VITE_API_BASE_URL=` to an empty string so the SPA hits the same origin, and `??` preserves that empty string while `||` would have fallen back to `localhost`. |
|
|
| Also exports `apiError(error)` β pulls the structured `{ code, message, details }` envelope back out of an axios error. |
|
|
| ### `coins.js`, `graphGeneration.js`, `kgAnomaly.js`, `health.js` |
| Thin wrappers around the discovery endpoints. Each function returns the parsed JSON response. The streaming endpoints are *not* hit through these wrappers β they go through `useSseStream` directly. |
|
|
| ## `composables/useSseStream.js` |
|
|
| The SSE client. Implements: |
|
|
| - `InferenceHttpError` β typed error with `status`, `code`, `details` (matches the backend error envelope). |
| - `useSseStream({ path, body, onProgress, onPreview, onResult, signal })` β POSTs to `${baseURL}${path}`, reads the response body as a stream, parses SSE frames, and dispatches them. Honours an `AbortSignal` for client-side cancellation. |
|
|
| The base URL is computed the same way as in `client.js` β same `??` rule applies. |
|
|
| This composable is the only place in the frontend that talks to the streaming endpoints. Stores instantiate it from their action functions. |
|
|
| ## `stores/` β Pinia state |
|
|
| ### `theme.js` |
| Stores the active theme (`light` / `dark` / `auto`), persists it to `localStorage`, and toggles `<html>` classes on change. `init()` reads the persisted value at app start. |
|
|
| ### `coinsDemo.js` |
| Holds: |
|
|
| - The dataset / algorithm / query-structure metadata fetched from `/coins/*`. |
| - The user's currently selected `(dataset_id, queryStructure, algorithm, anchors, variables, relations, topK)`. |
| - `loading`, `error`, `errorCode`, `result` for the prediction call. |
|
|
| Getters expose `selectedStructure` and `allowedAlgorithms` (the intersection of the algorithms the dataset has and the ones that support the chosen query structure). Actions wrap the API client functions. |
|
|
| ### `multiproxanDemo.js` |
| Mirrors `coinsDemo.js` for the graph-generation demo. State includes the chosen `model_type` (discrete / continuous), `sampling_mode` (standard / multiprox), generation parameters, the live preview URL, the `kg_log_likelihood` trace (only for the kg-anomaly correction case but kept here too for future symmetry), and the continuation `state` blob between Gibbs rounds. |
|
|
| ### `kgAnomalyDemo.js` |
| The KG-anomaly demo state. Holds the picked sample subgraph, the user's edits, the running progress, the preview reel and the `kg_log_likelihood` trace. |
|
|
| ## `router/index.js` |
|
|
| Five named routes: |
|
|
| | Path | Name | View | |
| |---|---|---| |
| | `/` | `home` | `HomeView.vue` | |
| | `/cv` | `cv` | `CVView.vue` | |
| | `/demos/coins` | `demo-coins` | `CoinsView.vue` (lazy) | |
| | `/demos/multiproxan` | `demo-multiproxan` | `MultiProxAnView.vue` (lazy) | |
| | `/demos/kganomaly` | `demo-kganomaly` | `KgAnomalyView.vue` (lazy) | |
| | `/:pathMatch(.*)*` | `not-found` | `NotFoundView.vue` | |
|
|
| The catch-all is the [Lara Croft 404](../glossary.md#hf-space) β the Django backend serves the SPA shell for unknown paths and Vue Router takes it from there. `meta.title` is applied to `document.title` in `router.afterEach`. |
|
|
| ## `views/` β pages |
|
|
| | View | Purpose | |
| |---|---| |
| | `HomeView.vue` | Hero intro, demo preview cards, fact of the day, system status. | |
| | `CVView.vue` | CV rendering driven by `data/cv.js`. | |
| | `NotFoundView.vue` | Lara Croft 404 with random hero image and credits. | |
| | `demos/CoinsView.vue` | The COINs demo (query construction, prediction results). | |
| | `demos/MultiProxAnView.vue` | Graph-generation demo (parameter panel, preview reel, chain GIF). | |
| | `demos/KgAnomalyView.vue` | KG-anomaly demo (subgraph picker, change list, log-likelihood plot). | |
|
|
| ## `components/` β feature groups |
|
|
| Components are grouped by feature folder, not by type. Cross-feature primitives live in `common/` and `layout/`. |
|
|
| | Folder | Notable components | |
| |---|---| |
| | `background/` | `GraphBackground.vue`, `FloatingMotif.vue` β animated graph drawing background. | |
| | `common/` | `EtaTracker.js`, `FitText.vue`, `InferenceErrorBanner.vue`, `PreviewReel.vue`, `SseProgressBar.vue`, `StepTimeline.vue` β primitives used across demos. | |
| | `layout/` | `NavBar.vue`, `PageSection.vue`, `ThemeToggle.vue`. | |
| | `home/` | `HeroIntro.vue`, `DemoPreviewCard.vue`, `FactOfTheDay.vue`, `SystemStatus.vue`. | |
| | `cv/` | `Education.vue`, `WorkExperience.vue`, `Publication.vue`, `ProjectCard.vue`, `Skill.vue`, `Language.vue`, `LogoOrAcronym.vue`, `Reference.vue`, `SocialLink.vue`. | |
| | `coins/` | `AlgorithmSelector.vue`, `QueryStructurePicker.vue`, `QueryGraph.vue`, `QueryDescription.vue`, `SearchableEntityDropdown.vue`, `SearchableRelationDropdown.vue`, `SearchablePicker.vue`, `PredictionList.vue`, `ResultsDashboard.vue`, `CommunityRankCallout.vue`, `TimingPanel.vue`. | |
| | `multiproxan/` | `ParametersPanel.vue` β parameter form for both sampling modes. | |
| | `kganomaly/` | `SampleSubgraphCard.vue`, `ChangeList.vue` β subgraph picker and per-edge change explanations. | |
|
|
| ## `data/cv.js` |
|
|
| A static JS module exporting the CV's structured data (education, work, publications, etc.). Updating the CV is a plain code edit β no DB. |
|
|
| ## `styles/` |
|
|
| | File | Purpose | |
| |---|---| |
| | `tokens.css` | Design tokens (color, spacing, font sizes). | |
| | `theme.css` | Light / dark theme variable bindings. | |
| | `responsive.css` | Breakpoint helpers. | |
|
|
| ## Build and env |
|
|
| - `npm run dev` β Vite dev server on `http://localhost:5173`, proxied to the Django dev server at `http://localhost:8000` via `VITE_API_BASE_URL` from `.env.development`. |
| - `npm run build` β emits `dist/` (the production bundle that the container copies into Django's `dist/` so WhiteNoise serves it). |
| - `.env.development` β `VITE_API_BASE_URL=http://localhost:8000`. |
| - `.env.production` β `VITE_API_BASE_URL=` (empty for same-origin). |
|
|
| ## See also |
|
|
| - [explanation/architecture.md](../explanation/architecture.md) β how the SPA is served by the Django container. |
| - [reference/sse-protocol.md](sse-protocol.md) β exactly what the demo stores parse from streaming responses. |
| - [guides/local-development.md](../guides/local-development.md) β running the frontend dev server alongside Django. |
|
|