183 lines
5.0 KiB
Markdown
183 lines
5.0 KiB
Markdown
# Data Model: Dataset Lifecycle Workspace
|
|
|
|
## Entity Overview
|
|
|
|
```
|
|
GET /api/datasets GET /api/datasets/{id}
|
|
─────────────────────────────────────────────────────────────
|
|
DatasetsResponse DatasetDetailResponse
|
|
├── datasets: DatasetItem[] ├── ... (existing fields)
|
|
│ ├── id ├── metrics: MetricItem[]
|
|
│ ├── table_name │ ├── id
|
|
│ ├── schema │ ├── metric_name
|
|
│ ├── database │ ├── expression
|
|
│ ├── mapped_fields │ ├── verbose_name
|
|
│ └── last_task │ ├── description
|
|
├── stats: StatsCounts │ └── metric_type
|
|
│ ├── total └── metric_count
|
|
│ ├── unmapped_count
|
|
│ ├── mapped_count
|
|
│ └── linked_count
|
|
├── total, page, page_size,
|
|
│ total_pages (existing)
|
|
└── [unchanged pagination]
|
|
|
|
PUT /api/datasets/{id}/columns/{col_id}/description
|
|
PUT /api/datasets/{id}/metrics/{metric_id}/description
|
|
─────────────────────────────────────────────────────────────
|
|
Request: ColumnDescriptionUpdate | MetricDescriptionUpdate
|
|
{ description: string }
|
|
|
|
Response: { success: true, description: string }
|
|
```
|
|
|
|
---
|
|
|
|
## Backend Pydantic Schemas (in `backend/src/api/routes/datasets.py`)
|
|
|
|
### MetricItem (new)
|
|
```python
|
|
class MetricItem(BaseModel):
|
|
id: int
|
|
metric_name: str
|
|
expression: str | None = None
|
|
verbose_name: str | None = None
|
|
description: str | None = None
|
|
metric_type: str | None = None
|
|
```
|
|
|
|
### StatsCounts (new)
|
|
```python
|
|
class StatsCounts(BaseModel):
|
|
total: int # all datasets
|
|
unmapped_count: int # mapped_fields.mapped == 0
|
|
mapped_count: int # mapped_fields.mapped > 0
|
|
linked_count: int # linked_dashboard_count > 0
|
|
```
|
|
|
|
### DatasetsResponse (modified)
|
|
```python
|
|
class DatasetsResponse(BaseModel):
|
|
datasets: list[DatasetItem]
|
|
stats: StatsCounts # NEW
|
|
total: int
|
|
page: int
|
|
page_size: int
|
|
total_pages: int
|
|
```
|
|
|
|
### DatasetDetailResponse (modified)
|
|
```python
|
|
class DatasetDetailResponse(BaseModel):
|
|
# ... existing fields unchanged ...
|
|
metrics: list[MetricItem] # NEW
|
|
metric_count: int # NEW
|
|
```
|
|
|
|
### ColumnDescriptionUpdate (new)
|
|
```python
|
|
class ColumnDescriptionUpdate(BaseModel):
|
|
description: str
|
|
```
|
|
|
|
### MetricDescriptionUpdate (new)
|
|
```python
|
|
class MetricDescriptionUpdate(BaseModel):
|
|
description: str
|
|
```
|
|
|
|
---
|
|
|
|
## Frontend Types (TypeScript / Svelte inferred)
|
|
|
|
```typescript
|
|
interface StatsCounts {
|
|
total: number;
|
|
unmapped_count: number;
|
|
mapped_count: number;
|
|
linked_count: number;
|
|
}
|
|
|
|
interface MetricItem {
|
|
id: number;
|
|
metric_name: string;
|
|
expression?: string;
|
|
verbose_name?: string;
|
|
description?: string;
|
|
metric_type?: string;
|
|
}
|
|
|
|
// UI-only state types (not in API)
|
|
type ColumnRow = {
|
|
column_name: string;
|
|
verbose_name?: string;
|
|
type?: string;
|
|
description?: string;
|
|
is_dttm: boolean;
|
|
is_active: boolean;
|
|
id: number;
|
|
isEditing?: boolean; // UI state for inline edit
|
|
};
|
|
|
|
type MetricRow = {
|
|
metric_name: string;
|
|
expression?: string;
|
|
verbose_name?: string;
|
|
description?: string;
|
|
metric_type?: string;
|
|
id: number;
|
|
isEditing?: boolean; // UI state for inline edit
|
|
};
|
|
|
|
type StatsBarFilter = 'all' | 'unmapped' | 'mapped' | 'linked' | null;
|
|
```
|
|
|
|
---
|
|
|
|
## WebSocket Message
|
|
|
|
```json
|
|
{
|
|
"type": "dataset.updated",
|
|
"payload": {
|
|
"env_id": "ss-dev",
|
|
"dataset_ids": ["242377ce-bdbd-42df-85da-ca1340a72fbb"]
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## State Transitions
|
|
|
|
### Stats Bar Tile States
|
|
```
|
|
Idle → (click tile) → Active (highlighted, list filtered)
|
|
Active → (click same tile) → Idle (filter cleared)
|
|
Active → (click different tile) → Active (new tile, list re-filtered)
|
|
```
|
|
|
|
### Inline Edit States
|
|
```
|
|
Display → (click ✏️) → Editing (textarea visible)
|
|
Editing → (Save + API success) → Display (new description shown)
|
|
Editing → (Save + API error) → Editing (error message, textarea stays)
|
|
Editing → (Cancel) → Display (original description restored)
|
|
```
|
|
|
|
### Detail Panel States
|
|
```
|
|
NoSelection → (click card) → Loading → Loaded
|
|
Loaded → (click different card) → Loading → Loaded
|
|
Loaded → (deselect / bulk mode) → NoSelection
|
|
Loading → (API error) → Error → (Retry) → Loading
|
|
```
|
|
|
|
### Bulk Selection States
|
|
```
|
|
None → (check 1+ cards) → Selecting (bottom panel hidden for 1)
|
|
Selecting → (check 2+ cards) → BulkActive (bottom panel visible)
|
|
BulkActive → (uncheck all) → None
|
|
BulkActive → (click action) → Modal → (complete) → None
|
|
```
|