File size: 7,795 Bytes
175b650
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# 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.