udi-yac 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +373 -0
- package/dist/app/ErrorBoundary.d.ts +18 -0
- package/dist/app/UDIChat.d.ts +3 -0
- package/dist/app/UDIChatConfig.d.ts +23 -0
- package/dist/app/UDIChatContext.d.ts +26 -0
- package/dist/app/validateConfig.d.ts +14 -0
- package/dist/app/validateConfig.test.d.ts +1 -0
- package/dist/assets/domainWorker-Cd9KoNXV.js +16 -0
- package/dist/ce-entry-C4ngOj0B.js +42577 -0
- package/dist/components/ui/badge.d.ts +7 -0
- package/dist/components/ui/button.d.ts +8 -0
- package/dist/components/ui/card.d.ts +11 -0
- package/dist/components/ui/checkbox.d.ts +3 -0
- package/dist/components/ui/dialog.d.ts +17 -0
- package/dist/components/ui/dropdown-menu.d.ts +29 -0
- package/dist/components/ui/input.d.ts +3 -0
- package/dist/components/ui/label.d.ts +3 -0
- package/dist/components/ui/scroll-area.d.ts +4 -0
- package/dist/components/ui/select.d.ts +15 -0
- package/dist/components/ui/separator.d.ts +3 -0
- package/dist/components/ui/slider.d.ts +3 -0
- package/dist/components/ui/switch.d.ts +5 -0
- package/dist/components/ui/tabs.d.ts +10 -0
- package/dist/components/ui/textarea.d.ts +3 -0
- package/dist/components/ui/tooltip.d.ts +6 -0
- package/dist/data/hubmap_2025-05-05/datapackage_udi.json +19606 -0
- package/dist/data/hubmap_2025-05-05/datasets.csv +6324 -0
- package/dist/data/hubmap_2025-05-05/datasets.tsv +6324 -0
- package/dist/data/hubmap_2025-05-05/donors.csv +433 -0
- package/dist/data/hubmap_2025-05-05/donors.tsv +433 -0
- package/dist/data/hubmap_2025-05-05/samples.csv +4490 -0
- package/dist/data/hubmap_2025-05-05/samples.tsv +4490 -0
- package/dist/data/hubmap_api/datapackage.json +14110 -0
- package/dist/data/readme.md +41 -0
- package/dist/favicon.svg +1 -0
- package/dist/features/chat/api/completions.d.ts +12 -0
- package/dist/features/chat/components/ApiKeyInput.d.ts +5 -0
- package/dist/features/chat/components/ChatHeaderBar.d.ts +19 -0
- package/dist/features/chat/components/ChatInput.d.ts +7 -0
- package/dist/features/chat/components/ChatPanel.d.ts +13 -0
- package/dist/features/chat/components/ClosedVisualizationsPanel.d.ts +6 -0
- package/dist/features/chat/components/ConversationList.d.ts +1 -0
- package/dist/features/chat/components/DebugToggleSection.d.ts +13 -0
- package/dist/features/chat/components/MessageBubble.d.ts +8 -0
- package/dist/features/chat/components/MessageList.d.ts +7 -0
- package/dist/features/chat/hooks/useChatApi.d.ts +6 -0
- package/dist/features/chat/hooks/useDebugExports.d.ts +11 -0
- package/dist/features/chat/hooks/useExamplePrompts.d.ts +7 -0
- package/dist/features/chat/hooks/useResetHandlers.d.ts +8 -0
- package/dist/features/chat/index.d.ts +9 -0
- package/dist/features/chat/stores/conversationStore.d.ts +10 -0
- package/dist/features/chat/stores/conversationStore.test.d.ts +1 -0
- package/dist/features/dashboard/components/DashboardCard.d.ts +9 -0
- package/dist/features/dashboard/components/DashboardPanel.d.ts +1 -0
- package/dist/features/dashboard/components/DataCounts.d.ts +1 -0
- package/dist/features/dashboard/components/DownloadButton.d.ts +1 -0
- package/dist/features/dashboard/components/FilterToolbar.d.ts +1 -0
- package/dist/features/dashboard/components/VizTweakComponent.d.ts +8 -0
- package/dist/features/dashboard/components/VizTweakComponent.types.d.ts +20 -0
- package/dist/features/dashboard/components/WelcomeSplash.d.ts +1 -0
- package/dist/features/dashboard/index.d.ts +10 -0
- package/dist/features/dashboard/stores/dashboardStore.d.ts +70 -0
- package/dist/features/dashboard/stores/dashboardStore.test.d.ts +1 -0
- package/dist/features/dashboard/stores/dataFiltersStore.d.ts +34 -0
- package/dist/features/dashboard/stores/dataFiltersStore.test.d.ts +1 -0
- package/dist/features/dashboard/stores/memoryBankStore.d.ts +8 -0
- package/dist/features/dashboard/stores/memoryBankStore.test.d.ts +1 -0
- package/dist/features/dashboard/stores/selectionsStore.d.ts +7 -0
- package/dist/features/dashboard/stores/selectionsStore.test.d.ts +1 -0
- package/dist/features/data-package/index.d.ts +7 -0
- package/dist/features/data-package/stores/dataPackageStore.d.ts +25 -0
- package/dist/features/data-package/stores/dataPackageStore.test.d.ts +1 -0
- package/dist/features/data-package/types.d.ts +27 -0
- package/dist/features/data-package/utils/joinDataPath.d.ts +7 -0
- package/dist/features/data-package/utils/joinDataPath.test.d.ts +1 -0
- package/dist/features/data-package/utils/structuredTextParser.d.ts +7 -0
- package/dist/features/data-package/utils/structuredTextParser.test.d.ts +1 -0
- package/dist/features/data-package/workers/domainWorker.d.ts +13 -0
- package/dist/features/tool-calls/components/ClarifyVariable.d.ts +6 -0
- package/dist/features/tool-calls/components/FilterComponent.d.ts +9 -0
- package/dist/features/tool-calls/components/FreeTextExplain.d.ts +2 -0
- package/dist/features/tool-calls/components/IntervalFilterComponent.d.ts +9 -0
- package/dist/features/tool-calls/components/PointFilterComponent.d.ts +8 -0
- package/dist/features/tool-calls/components/RebuffNotice.d.ts +7 -0
- package/dist/features/tool-calls/components/ToolCallRenderer.d.ts +11 -0
- package/dist/features/tool-calls/components/VisualizationCard.d.ts +10 -0
- package/dist/features/tool-calls/index.d.ts +6 -0
- package/dist/features/tool-calls/types.d.ts +52 -0
- package/dist/icons.svg +24 -0
- package/dist/images/yac-mascot.svg +22 -0
- package/dist/index.d.ts +5 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/stores/globalStore.d.ts +6 -0
- package/dist/stores/globalStore.test.d.ts +1 -0
- package/dist/test/setup.d.ts +0 -0
- package/dist/types/dataPackage.d.ts +64 -0
- package/dist/types/messages.d.ts +24 -0
- package/dist/udi-yac.css +3 -0
- package/dist/udi-yac.js +25877 -0
- package/dist/utils/specMutations.d.ts +45 -0
- package/dist/utils/specMutations.test.d.ts +1 -0
- package/package.json +110 -0
package/README.md
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
# udi-yac
|
|
2
|
+
|
|
3
|
+
React implementation of the UDI Chat interface — an AI-powered system for querying and visualizing biomedical datasets via natural language. This is a React port of the original Vue 3/Quasar `udi-chat` app. Published on npm as [`udi-yac`](https://www.npmjs.com/package/udi-yac); the repository directory remains `udi-chat-react`.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm install
|
|
9
|
+
pnpm dev # dev server
|
|
10
|
+
pnpm build # standalone app build (dist/)
|
|
11
|
+
pnpm build:lib # library build (dist/, consumes entry from src/index.ts)
|
|
12
|
+
pnpm lint # eslint
|
|
13
|
+
pnpm format # prettier
|
|
14
|
+
pnpm typecheck # tsc --noEmit
|
|
15
|
+
pnpm test # vitest (one-shot)
|
|
16
|
+
pnpm test:watch # vitest in watch mode
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Standalone app config (env vars)
|
|
20
|
+
|
|
21
|
+
The standalone `App.tsx` reads these Vite env vars (see `.env.example`). Copy `.env.example` to `.env.local` to override locally:
|
|
22
|
+
|
|
23
|
+
| Var | Default | Purpose |
|
|
24
|
+
| -------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
25
|
+
| `VITE_UDI_API_BASE_URL` | `http://localhost:8007` | UDIAgent FastAPI server URL |
|
|
26
|
+
| `VITE_UDI_DATA_PACKAGE` | (unset → inline HuBMAP API package from `src/data/hubmapRemote.ts`) | Optional path/URL to a `datapackage_udi.json`. Overrides the inline default when set. |
|
|
27
|
+
| `VITE_UDI_REQUIRE_API_KEY` | `true` | Set to `false` to skip the in-app OpenAI key prompt |
|
|
28
|
+
| `VITE_UDI_MODEL` | (unset) | Optional LLM model override |
|
|
29
|
+
|
|
30
|
+
By default the standalone app talks to the live HuBMAP Portal metadata API. To use the locally bundled snapshot instead, set:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
VITE_UDI_DATA_PACKAGE=/data/hubmap_2025-05-05/datapackage_udi.json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
> **Note on `build` vs `build:lib`**: `pnpm build` produces a deployable standalone SPA — this is the default so CI/deploy pipelines behave as expected. To build the publishable library bundle (the `UDIChat` React component), use `pnpm build:lib`, which invokes `vite build --mode lib` and emits both JS and `.d.ts` files under `dist/`.
|
|
37
|
+
|
|
38
|
+
## Stack
|
|
39
|
+
|
|
40
|
+
- **React 19** with TypeScript
|
|
41
|
+
- **Tailwind 4** + **shadcn/ui** (Base UI primitives)
|
|
42
|
+
- **Zustand** for state management (vanilla stores via React Context)
|
|
43
|
+
- **UDI Toolkit** (Vue Custom Elements) for grammar-based visualization rendering
|
|
44
|
+
- **Arquero** for client-side data loading and domain computation
|
|
45
|
+
- **Vite** for dev server and library builds
|
|
46
|
+
|
|
47
|
+
## Architecture
|
|
48
|
+
|
|
49
|
+
### Dual Build Modes
|
|
50
|
+
|
|
51
|
+
The project builds as both a **library** and a **standalone app**:
|
|
52
|
+
|
|
53
|
+
- **Library** (`pnpm build`): Exports the `UDIChat` component and `UDIChatConfig` type. Consumers provide React and render `<UDIChat>` with configuration props.
|
|
54
|
+
- **Standalone** (`pnpm build:app`): Builds `App.tsx` as a full SPA with dev defaults.
|
|
55
|
+
|
|
56
|
+
### Library Usage
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { UDIChat } from 'udi-yac';
|
|
60
|
+
import 'udi-yac/style.css';
|
|
61
|
+
|
|
62
|
+
<UDIChat
|
|
63
|
+
apiBaseUrl="http://localhost:8007"
|
|
64
|
+
dataPackagePath="./data/hubmap_2025-05-05/datapackage_udi.json"
|
|
65
|
+
authToken="your-jwt-token" // optional
|
|
66
|
+
requireApiKey // optional — prompts for OpenAI key
|
|
67
|
+
model="agenticx/UDI-VIS-Beta-v2" // optional
|
|
68
|
+
/>;
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Config Props
|
|
72
|
+
|
|
73
|
+
| Prop | Type | Description |
|
|
74
|
+
| ------------------ | -------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
75
|
+
| `apiBaseUrl` | `string` | Base URL for the UDIAgent API |
|
|
76
|
+
| `dataPackagePath` | `string?` | URL/path to `datapackage_udi.json`. Ignored when `dataPackage` is provided. |
|
|
77
|
+
| `dataPackage` | `DataPackage?` | Provide a data package object directly instead of fetching from a URL. Takes precedence over `dataPackagePath`. |
|
|
78
|
+
| `dataFieldDomains` | `DataFieldDomain[]?` | Pre-computed field domains. Skips CSV loading for domain computation when provided with `dataPackage`. |
|
|
79
|
+
| `fetchOptions` | `RequestInit?` | Custom fetch options (headers, credentials, etc.) forwarded to all data-loading fetch calls. |
|
|
80
|
+
| `authToken` | `string?` | JWT bearer token for API auth |
|
|
81
|
+
| `requireApiKey` | `boolean?` | Show API key input before chatting |
|
|
82
|
+
| `model` | `string?` | LLM model name override |
|
|
83
|
+
| `className` | `string?` | CSS class for the root element |
|
|
84
|
+
| `style` | `CSSProperties?` | Inline styles for the root element |
|
|
85
|
+
|
|
86
|
+
### Data Source Configuration
|
|
87
|
+
|
|
88
|
+
There are three ways to provide data to `UDIChat`, from simplest to most flexible:
|
|
89
|
+
|
|
90
|
+
#### 1. Local data package file (default)
|
|
91
|
+
|
|
92
|
+
Point `dataPackagePath` to a `datapackage_udi.json` file. The JSON must contain a `udi:path` base path and `resources` with relative file paths. CSVs are loaded client-side via Arquero.
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
<UDIChat
|
|
96
|
+
apiBaseUrl="http://localhost:8007"
|
|
97
|
+
dataPackagePath="./data/hubmap_2025-05-05/datapackage_udi.json"
|
|
98
|
+
/>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### 2. Remote data sources
|
|
102
|
+
|
|
103
|
+
Data packages can reference remote URLs. Set `udi:path` to a remote base URL and keep resource `path` values as relative filenames. Arquero's `loadCSV` uses `fetch()` internally, so remote URLs work out of the box.
|
|
104
|
+
|
|
105
|
+
If the remote server requires authentication, pass `fetchOptions` with the necessary headers. These are forwarded to all `fetch()` calls — both the data package JSON fetch and CSV loading:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
<UDIChat
|
|
109
|
+
apiBaseUrl="http://localhost:8007"
|
|
110
|
+
dataPackagePath="https://portal.example.com/metadata/datapackage_udi.json"
|
|
111
|
+
fetchOptions={{
|
|
112
|
+
headers: { Authorization: 'Bearer <token>' },
|
|
113
|
+
credentials: 'include',
|
|
114
|
+
}}
|
|
115
|
+
/>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
> **Note:** The remote server must send appropriate CORS headers (`Access-Control-Allow-Origin`) for browser-based fetching to work.
|
|
119
|
+
|
|
120
|
+
#### 3. Inline data package (no fetch)
|
|
121
|
+
|
|
122
|
+
Pass a `DataPackage` object directly via the `dataPackage` prop. This is useful when you build the schema programmatically or receive it from an API. CSVs are still loaded from the URLs in `udi:path` + `resource.path` for domain computation, unless you also provide `dataFieldDomains` to skip that step entirely.
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
import type { DataPackage } from 'udi-yac';
|
|
126
|
+
|
|
127
|
+
const myDataPackage: DataPackage = {
|
|
128
|
+
'udi:path': 'https://portal.hubmapconsortium.org/metadata/v0/',
|
|
129
|
+
resources: [
|
|
130
|
+
{
|
|
131
|
+
name: 'donors',
|
|
132
|
+
path: 'donors.tsv',
|
|
133
|
+
'udi:row_count': 281,
|
|
134
|
+
schema: {
|
|
135
|
+
fields: [
|
|
136
|
+
{
|
|
137
|
+
name: 'age_value',
|
|
138
|
+
description: 'The time elapsed since birth.',
|
|
139
|
+
'udi:data_type': 'quantitative',
|
|
140
|
+
},
|
|
141
|
+
{ name: 'sex', description: 'Biological sex of the donor.', 'udi:data_type': 'nominal' },
|
|
142
|
+
// ... more fields
|
|
143
|
+
],
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
// ... more resources
|
|
147
|
+
],
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
<UDIChat apiBaseUrl="http://localhost:8007" dataPackage={myDataPackage} />;
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
To skip CSV loading entirely (e.g. when you already have domain metadata), pass pre-computed domains:
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import type { DataFieldDomain } from 'udi-yac';
|
|
157
|
+
|
|
158
|
+
const myDomains: DataFieldDomain[] = [
|
|
159
|
+
{
|
|
160
|
+
entity: 'donors',
|
|
161
|
+
field: 'age_value',
|
|
162
|
+
type: 'interval',
|
|
163
|
+
fieldDescription: 'The time elapsed since birth.',
|
|
164
|
+
domain: { min: 1, max: 87 },
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
entity: 'donors',
|
|
168
|
+
field: 'sex',
|
|
169
|
+
type: 'point',
|
|
170
|
+
fieldDescription: 'Biological sex of the donor.',
|
|
171
|
+
domain: { values: ['Male', 'Female'] },
|
|
172
|
+
},
|
|
173
|
+
// ...
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
<UDIChat
|
|
177
|
+
apiBaseUrl="http://localhost:8007"
|
|
178
|
+
dataPackage={myDataPackage}
|
|
179
|
+
dataFieldDomains={myDomains}
|
|
180
|
+
/>;
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
See [`src/data/hubmapRemote.ts`](src/data/hubmapRemote.ts) for the canonical inline DataPackage example targeting the live HuBMAP Portal — this is also the default the standalone `App.tsx` uses.
|
|
184
|
+
|
|
185
|
+
## Features
|
|
186
|
+
|
|
187
|
+
### Chat Interface
|
|
188
|
+
|
|
189
|
+
- Natural language input with LLM-powered responses
|
|
190
|
+
- Tool call rendering: visualizations, filters, explanations, clarifications, rebuffs
|
|
191
|
+
- Example prompts dialog (fetched from backend `/v1/yac/examples`)
|
|
192
|
+
- Conversation reset, save/export as JSON
|
|
193
|
+
- API key input with localStorage persistence
|
|
194
|
+
|
|
195
|
+
### Visualization Dashboard
|
|
196
|
+
|
|
197
|
+
- Auto-pinned visualizations from assistant responses
|
|
198
|
+
- Interactive Vega-Lite charts via UDI Grammar spec → UDIVis (Vue CE)
|
|
199
|
+
- **Cross-chart filtering**: brush selections on one chart filter all others
|
|
200
|
+
- **Expand/collapse** visualizations to full width
|
|
201
|
+
- **Table view toggle**: switch between chart and raw data table
|
|
202
|
+
- **Field tweaking**: swap x/y/color encodings via dropdowns
|
|
203
|
+
- **Spec inspector**: view/copy JSON spec, open in UDI Grammar Editor (lz-string compressed URL)
|
|
204
|
+
- **Hover highlighting** across chat messages and dashboard cards
|
|
205
|
+
- **Memory bank**: restore recently closed visualizations
|
|
206
|
+
|
|
207
|
+
### Data Filtering
|
|
208
|
+
|
|
209
|
+
- **Interval filters**: range sliders for numeric fields
|
|
210
|
+
- **Point filters**: checkbox selection for categorical fields
|
|
211
|
+
- **Filter toolbar**: active filter chips with clear buttons
|
|
212
|
+
- **Cross-entity filtering**: filters propagate across related entities via foreign keys
|
|
213
|
+
- **Null value filtering** toggle
|
|
214
|
+
|
|
215
|
+
### Data Management
|
|
216
|
+
|
|
217
|
+
- **Entity counts**: per-entity row counts with dynamic filtered counts
|
|
218
|
+
- **Download**: filtered data as ZIP of CSVs, or manifest (hubmap_id extraction)
|
|
219
|
+
- Data package loading with domain computation (Arquero)
|
|
220
|
+
|
|
221
|
+
### Debug Mode (type `!/admin` in chat)
|
|
222
|
+
|
|
223
|
+
- System prompts toggle (show/hide system messages)
|
|
224
|
+
- Conversation sidebar drawer (load saved session JSON files)
|
|
225
|
+
- Export test case for benchmarking
|
|
226
|
+
- Download data domains / data schema as JSON
|
|
227
|
+
- Save conversation export
|
|
228
|
+
|
|
229
|
+
## Project Structure
|
|
230
|
+
|
|
231
|
+
The codebase follows a [bulletproof-react](https://github.com/alan2207/bulletproof-react)-style layout. Module boundaries are enforced by [`eslint-plugin-project-structure`](https://www.npmjs.com/package/eslint-plugin-project-structure) (see [eslint.config.js](eslint.config.js)). For the reasoning behind the layout and a guide to working within it, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
src/
|
|
235
|
+
index.ts # Library entry: exports UDIChat + UDIChatConfig
|
|
236
|
+
index.css # Global Tailwind base + custom CSS
|
|
237
|
+
env.d.ts # Vite client types
|
|
238
|
+
|
|
239
|
+
app/ # Composition root (allowed to reach into any feature)
|
|
240
|
+
main.tsx # Vite app bootstrap
|
|
241
|
+
App.tsx # Standalone app entry (inline HuBMAP package)
|
|
242
|
+
UDIChat.tsx # Root component (provider + layout)
|
|
243
|
+
UDIChatConfig.ts # UDIChatConfig type (extracted to break circular)
|
|
244
|
+
UDIChatContext.tsx # Provider + hooks wiring all Zustand stores
|
|
245
|
+
ErrorBoundary.tsx # React error boundary
|
|
246
|
+
validateConfig.ts (+ .test.ts) # Runtime validation for UDIChatConfig
|
|
247
|
+
|
|
248
|
+
features/
|
|
249
|
+
chat/
|
|
250
|
+
index.ts # Public barrel — cross-feature consumers import only from here
|
|
251
|
+
api/
|
|
252
|
+
completions.ts # POST /v1/yac/completions client + QueryConfig type
|
|
253
|
+
components/
|
|
254
|
+
ChatPanel.tsx # Slim orchestrator (~85 lines)
|
|
255
|
+
ChatHeaderBar.tsx # Toolbar — owns debugMode subscription
|
|
256
|
+
DebugToggleSection.tsx # System-prompt toggle — owns debugMode + messages
|
|
257
|
+
ClosedVisualizationsPanel.tsx # Recently-closed viz strip — owns memoryBank
|
|
258
|
+
ChatInput.tsx # Message input
|
|
259
|
+
MessageList.tsx # Message history with auto-scroll
|
|
260
|
+
MessageBubble.tsx # Single message + tool call tabs
|
|
261
|
+
ConversationList.tsx # Sidebar with saved session files
|
|
262
|
+
ApiKeyInput.tsx # OpenAI API key input
|
|
263
|
+
hooks/
|
|
264
|
+
useChatApi.ts # LLM API integration hook
|
|
265
|
+
useExamplePrompts.ts # /v1/yac/examples fetch
|
|
266
|
+
useResetHandlers.ts # Bundled "reset everything" action
|
|
267
|
+
useDebugExports.ts # Debug-mode export buttons (save / test case / data)
|
|
268
|
+
stores/
|
|
269
|
+
conversationStore.ts # Chat messages, save/load/export
|
|
270
|
+
|
|
271
|
+
dashboard/
|
|
272
|
+
index.ts # Public barrel
|
|
273
|
+
components/
|
|
274
|
+
DashboardPanel.tsx # Dashboard layout (counts, filters, viz grid)
|
|
275
|
+
DashboardCard.tsx # Single pinned viz (chart, toolbar, tweak, spec)
|
|
276
|
+
DataCounts.tsx # Per-entity row counts (total + filtered)
|
|
277
|
+
FilterToolbar.tsx # Active filter chips
|
|
278
|
+
DownloadButton.tsx # CSV/manifest download dropdown
|
|
279
|
+
VizTweakComponent.tsx # Field encoding swap dropdowns
|
|
280
|
+
VizTweakComponent.types.ts # TweakableParam, LayerLike, MappingLike
|
|
281
|
+
WelcomeSplash.tsx # Empty dashboard placeholder
|
|
282
|
+
stores/
|
|
283
|
+
dashboardStore.ts # Pinned vizzes, interactivity, expand/table/hover
|
|
284
|
+
dataFiltersStore.ts # Interval/point filter state, message sync
|
|
285
|
+
selectionsStore.ts # Cross-viz brush selection coordination
|
|
286
|
+
memoryBankStore.ts # Closed visualization restoration
|
|
287
|
+
|
|
288
|
+
data-package/
|
|
289
|
+
index.ts # Public barrel
|
|
290
|
+
types.ts # Web Worker protocol types
|
|
291
|
+
stores/
|
|
292
|
+
dataPackageStore.ts # Data schema, field domains, entity relationships
|
|
293
|
+
utils/
|
|
294
|
+
joinDataPath.ts # Path joining for local + remote data URLs
|
|
295
|
+
structuredTextParser.ts # Template function evaluation for explanations
|
|
296
|
+
workers/
|
|
297
|
+
domainWorker.ts # Off-main-thread domain computation
|
|
298
|
+
|
|
299
|
+
tool-calls/
|
|
300
|
+
index.ts # Public barrel
|
|
301
|
+
types.ts # Args for each tool call type
|
|
302
|
+
components/
|
|
303
|
+
ToolCallRenderer.tsx # Dispatches tool calls to renderers
|
|
304
|
+
VisualizationCard.tsx # UDIVis preview (chat) / pinned badge
|
|
305
|
+
FilterComponent.tsx # Filter dispatcher (interval/point)
|
|
306
|
+
IntervalFilterComponent.tsx
|
|
307
|
+
PointFilterComponent.tsx
|
|
308
|
+
FreeTextExplain.tsx # Markdown explanation with structured text
|
|
309
|
+
RebuffNotice.tsx # Rejection with suggestion buttons
|
|
310
|
+
ClarifyVariable.tsx # Field disambiguation UI
|
|
311
|
+
|
|
312
|
+
components/
|
|
313
|
+
ui/ # shadcn/ui primitives (badge, button, dialog, …)
|
|
314
|
+
|
|
315
|
+
stores/
|
|
316
|
+
globalStore.ts # Truly cross-feature state (debug mode)
|
|
317
|
+
|
|
318
|
+
types/
|
|
319
|
+
messages.ts # Message, ToolCall, FlatToolCall (cross-feature)
|
|
320
|
+
dataPackage.ts # DataPackage, DataFieldDomain, etc. (cross-feature)
|
|
321
|
+
|
|
322
|
+
lib/
|
|
323
|
+
utils.ts # cn() helper (clsx + tailwind-merge)
|
|
324
|
+
|
|
325
|
+
utils/
|
|
326
|
+
specMutations.ts # Pure UDI grammar helpers
|
|
327
|
+
|
|
328
|
+
data/
|
|
329
|
+
hubmapRemote.ts # Inline DataPackage targeting the live HuBMAP Portal API
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Module boundaries
|
|
333
|
+
|
|
334
|
+
The `project-structure/independent-modules` rule enforces these import boundaries:
|
|
335
|
+
|
|
336
|
+
| From | Can import |
|
|
337
|
+
| -------------------- | ------------------------------------------------------------------------------------------------ |
|
|
338
|
+
| `src/features/X/**` | own family, **other features' `index.ts` only**, `src/{utils,types,lib,stores,components/ui}/**` |
|
|
339
|
+
| `src/app/**` | any feature internal, all shared layers |
|
|
340
|
+
| `src/components/ui/` | sibling UI, `src/lib/` |
|
|
341
|
+
| `src/utils/` | `src/{utils,types,lib,stores}/`, feature barrels |
|
|
342
|
+
| `src/{types,lib}/` | shared layers only |
|
|
343
|
+
| `src/stores/` | `src/{stores,types,lib}/` |
|
|
344
|
+
|
|
345
|
+
Cross-feature imports must go through the feature's `index.ts` barrel — direct paths like `@/features/dashboard/stores/dataFiltersStore` from another feature will fail lint.
|
|
346
|
+
|
|
347
|
+
## API Integration
|
|
348
|
+
|
|
349
|
+
The app communicates with a UDIAgent backend:
|
|
350
|
+
|
|
351
|
+
| Endpoint | Method | Purpose |
|
|
352
|
+
| ---------------------- | ------ | --------------------------------- |
|
|
353
|
+
| `/v1/yac/completions` | POST | Send messages, receive tool calls |
|
|
354
|
+
| `/v1/yac/examples` | GET | Fetch example prompts |
|
|
355
|
+
| `/sessions/{filename}` | GET | Load saved conversation files |
|
|
356
|
+
|
|
357
|
+
Request body for completions:
|
|
358
|
+
|
|
359
|
+
```json
|
|
360
|
+
{
|
|
361
|
+
"model": "...",
|
|
362
|
+
"messages": [...],
|
|
363
|
+
"dataSchema": "...",
|
|
364
|
+
"dataDomains": "..."
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## Relationship to udi-grammar
|
|
369
|
+
|
|
370
|
+
Visualizations are rendered by the `UDIVis` Vue Custom Element from the `udi-grammar` package, consumed via the published [`udi-toolkit`](https://www.npmjs.com/package/udi-toolkit) npm package. The React wrapper (`udi-toolkit/react`) bridges Vue CE props and events:
|
|
371
|
+
|
|
372
|
+
- **Props** (`spec`, `selections`): set via `useLayoutEffect` on the DOM element
|
|
373
|
+
- **Events** (`selection-change`, `data-ready`): listened via `addEventListener`, with Vue CE array-wrapping unwrapped
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Component, ErrorInfo, ReactNode } from 'react';
|
|
2
|
+
interface Props {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
}
|
|
5
|
+
interface State {
|
|
6
|
+
error: Error | null;
|
|
7
|
+
errorInfo: ErrorInfo | null;
|
|
8
|
+
}
|
|
9
|
+
export declare class ErrorBoundary extends Component<Props, State> {
|
|
10
|
+
state: State;
|
|
11
|
+
static getDerivedStateFromError(error: Error): Partial<State>;
|
|
12
|
+
componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
|
|
13
|
+
private getErrorText;
|
|
14
|
+
private handleCopy;
|
|
15
|
+
private handleReset;
|
|
16
|
+
render(): string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import('react').ReactPortal | import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DataPackage, DataFieldDomain } from '../types/dataPackage';
|
|
2
|
+
/**
|
|
3
|
+
* Public configuration surface for the `UDIChat` root component. Extracted
|
|
4
|
+
* from UDIChat.tsx so that `validateConfig` and other app-layer utilities
|
|
5
|
+
* can import the type without reaching into the component module.
|
|
6
|
+
*/
|
|
7
|
+
export interface UDIChatConfig {
|
|
8
|
+
apiBaseUrl: string;
|
|
9
|
+
/** URL to fetch a datapackage_udi.json from. Ignored when `dataPackage` is provided. */
|
|
10
|
+
dataPackagePath?: string;
|
|
11
|
+
/** Provide a DataPackage object directly instead of fetching from a URL. Takes precedence over `dataPackagePath`. */
|
|
12
|
+
dataPackage?: DataPackage;
|
|
13
|
+
/** Pre-computed field domains. When provided with `dataPackage`, skips CSV loading for domain computation. */
|
|
14
|
+
dataFieldDomains?: DataFieldDomain[];
|
|
15
|
+
/** Custom fetch options (e.g. headers, credentials) forwarded to all data-loading fetch calls. */
|
|
16
|
+
fetchOptions?: RequestInit;
|
|
17
|
+
authToken?: string;
|
|
18
|
+
/** If true, prompt the user to enter an OpenAI API key before chatting. */
|
|
19
|
+
requireApiKey?: boolean;
|
|
20
|
+
model?: string;
|
|
21
|
+
className?: string;
|
|
22
|
+
style?: React.CSSProperties;
|
|
23
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { StoreApi } from 'zustand';
|
|
3
|
+
import { ConversationState } from '../features/chat/stores/conversationStore';
|
|
4
|
+
import { DashboardState } from '../features/dashboard/stores/dashboardStore';
|
|
5
|
+
import { DataPackageState } from '../features/data-package/stores/dataPackageStore';
|
|
6
|
+
import { SelectionsState } from '../features/dashboard/stores/selectionsStore';
|
|
7
|
+
import { DataFiltersState } from '../features/dashboard/stores/dataFiltersStore';
|
|
8
|
+
import { MemoryBankState } from '../features/dashboard/stores/memoryBankStore';
|
|
9
|
+
import { GlobalState } from '../stores/globalStore';
|
|
10
|
+
export declare function UDIChatProvider({ children }: {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function useConversation<T>(selector: (state: ConversationState) => T): T;
|
|
14
|
+
export declare function useConversationStore(): StoreApi<ConversationState>;
|
|
15
|
+
export declare function useDashboard<T>(selector: (state: DashboardState) => T): T;
|
|
16
|
+
export declare function useDashboardStore(): StoreApi<DashboardState>;
|
|
17
|
+
export declare function useDataPackage<T>(selector: (state: DataPackageState) => T): T;
|
|
18
|
+
export declare function useDataPackageStore(): StoreApi<DataPackageState>;
|
|
19
|
+
export declare function useSelections<T>(selector: (state: SelectionsState) => T): T;
|
|
20
|
+
export declare function useSelectionsStore(): StoreApi<SelectionsState>;
|
|
21
|
+
export declare function useDataFilters<T>(selector: (state: DataFiltersState) => T): T;
|
|
22
|
+
export declare function useDataFiltersStore(): StoreApi<DataFiltersState>;
|
|
23
|
+
export declare function useMemoryBank<T>(selector: (state: MemoryBankState) => T): T;
|
|
24
|
+
export declare function useMemoryBankStore(): StoreApi<MemoryBankState>;
|
|
25
|
+
export declare function useGlobal<T>(selector: (state: GlobalState) => T): T;
|
|
26
|
+
export declare function useGlobalStore(): StoreApi<GlobalState>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { UDIChatConfig } from './UDIChatConfig';
|
|
2
|
+
/**
|
|
3
|
+
* Lightweight runtime validation for the UDIChatConfig shape.
|
|
4
|
+
*
|
|
5
|
+
* Catches the most common consumer mistakes (missing apiBaseUrl, malformed
|
|
6
|
+
* URL, no data source provided, malformed DataPackage) before they fail deep
|
|
7
|
+
* inside Arquero or fetch with opaque stack traces. Errors are thrown so the
|
|
8
|
+
* surrounding ErrorBoundary renders a useful message.
|
|
9
|
+
*
|
|
10
|
+
* This is intentionally NOT a full schema validator — it covers the failure
|
|
11
|
+
* modes we've actually seen in practice. If a field has a bad type that React
|
|
12
|
+
* itself will surface clearly, we don't duplicate that check here.
|
|
13
|
+
*/
|
|
14
|
+
export declare function validateConfig(config: UDIChatConfig): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|