@antelopejs/dms-ai 0.8.0 → 0.9.1
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 +2 -1
- package/dist/lifecycle/skill-sources.js +19 -146
- package/dist/lifecycle/skill-sources.js.map +1 -1
- package/dist/pages/settings/availability.js +8 -1
- package/dist/pages/settings/availability.js.map +1 -1
- package/dist/pages/settings/options.d.ts +2 -1
- package/dist/pages/settings/options.js +29 -8
- package/dist/pages/settings/options.js.map +1 -1
- package/dist/pages/settings/sections.js +25 -4
- package/dist/pages/settings/sections.js.map +1 -1
- package/dist/routes/builder.d.ts +3 -3
- package/dist/routes/builder.js +10 -2
- package/dist/routes/builder.js.map +1 -1
- package/dist/routes/settings.js +1 -1
- package/dist/routes/settings.js.map +1 -1
- package/dist/sidecar/settings-values.d.ts +3 -0
- package/dist/sidecar/settings-values.js +33 -1
- package/dist/sidecar/settings-values.js.map +1 -1
- package/dist/vocabulary/enumerations.js +2 -0
- package/dist/vocabulary/enumerations.js.map +1 -1
- package/dist/vocabulary/tools.js +3 -0
- package/dist/vocabulary/tools.js.map +1 -1
- package/frontend-vue/app/chat/components/ChatView.vue +53 -85
- package/frontend-vue/app/chat/components/Composer.vue +23 -39
- package/frontend-vue/app/chat/components/NoticeCard.vue +25 -0
- package/frontend-vue/app/chat/components/PanelHeader.vue +2 -6
- package/frontend-vue/app/chat/components/ProviderNotice.vue +14 -3
- package/frontend-vue/app/chat/composables/conversation-events.ts +4 -3
- package/frontend-vue/app/chat/composables/useConversation.ts +6 -0
- package/frontend-vue/app/chat/composables/useConversationMode.ts +8 -11
- package/frontend-vue/app/chat/composables/useFollowScroll.ts +77 -0
- package/frontend-vue/app/chat/constants/modes.ts +15 -0
- package/frontend-vue/app/chat/constants/protocol.ts +0 -1
- package/frontend-vue/app/chat/constants/settings.ts +1 -1
- package/frontend-vue/app/chat/types/protocol.ts +19 -9
- package/frontend-vue/app/chat/types/settings.ts +7 -2
- package/frontend-vue/app/chat/utils/permission-view.ts +1 -0
- package/frontend-vue/app/chat/utils/status-label.ts +50 -0
- package/frontend-vue/app/chat/utils/tool-lexicon.ts +16 -0
- package/frontend-vue/app/plugins/ai.client.ts +2 -2
- package/frontend-vue/app/runtime/assistant-actions.ts +4 -2
- package/frontend-vue/app/runtime/assistant-session.ts +5 -1
- package/frontend-vue/app/runtime/block-health.ts +135 -0
- package/frontend-vue/app/runtime/constants.ts +1 -0
- package/frontend-vue/app/runtime/navigation-complete.ts +47 -6
- package/frontend-vue/app/runtime/panel-intents.ts +6 -2
- package/frontend-vue/app/views/constants.ts +2 -0
- package/frontend-vue/app/views/types.ts +3 -1
- package/frontend-vue/i18n/locales/dms-ai-pages-en-GB.json +28 -11
- package/frontend-vue/i18n/locales/dms-ai-pages-fr-FR.json +28 -11
- package/frontend-vue/i18n/locales/dms-ai-panel-en-GB.json +17 -22
- package/frontend-vue/i18n/locales/dms-ai-panel-fr-FR.json +17 -22
- package/frontend-vue/i18n/locales/dms-ai-views-en-GB.json +2 -0
- package/frontend-vue/i18n/locales/dms-ai-views-fr-FR.json +2 -0
- package/frontend-vue/tests/assistant-actions.test.ts +37 -0
- package/frontend-vue/tests/block-health.test.ts +142 -0
- package/frontend-vue/tests/chat/chat-scroll.test.ts +251 -0
- package/frontend-vue/tests/chat/conversation-events.test.ts +35 -3
- package/frontend-vue/tests/chat/provider-notice.test.ts +33 -0
- package/frontend-vue/tests/chat/tool-lexicon.test.ts +1 -0
- package/frontend-vue/tests/chat-panel.test.ts +2 -4
- package/frontend-vue/tests/navigation.test.ts +67 -2
- package/frontend-vue/tests/panel-modes.test.ts +146 -0
- package/frontend-vue/tests/panel-questions.test.ts +1 -19
- package/frontend-vue/tests/panel-states.test.ts +3 -15
- package/frontend-vue/tests/support/fake-layout.ts +119 -0
- package/frontend-vue/tests/support/panel-harness.ts +16 -8
- package/frontend-vue/tests/support/setup-layout.ts +3 -0
- package/frontend-vue/tests/support/stubs.ts +2 -0
- package/frontend-vue/vitest.config.ts +1 -0
- package/package.json +6 -5
- package/sidecar/dist/agent/always-ask-files.d.ts +2 -0
- package/sidecar/dist/agent/always-ask-files.js +34 -0
- package/sidecar/dist/agent/always-ask-files.js.map +1 -0
- package/sidecar/dist/agent/conversation-modes.d.ts +3 -12
- package/sidecar/dist/agent/conversation-modes.js +16 -69
- package/sidecar/dist/agent/conversation-modes.js.map +1 -1
- package/sidecar/dist/agent/effective-mode.d.ts +2 -5
- package/sidecar/dist/agent/effective-mode.js +1 -15
- package/sidecar/dist/agent/effective-mode.js.map +1 -1
- package/sidecar/dist/agent/permission-bus.d.ts +1 -2
- package/sidecar/dist/agent/permission-bus.js +1 -3
- package/sidecar/dist/agent/permission-bus.js.map +1 -1
- package/sidecar/dist/agent/permission-preview.d.ts +6 -0
- package/sidecar/dist/agent/permission-preview.js +35 -10
- package/sidecar/dist/agent/permission-preview.js.map +1 -1
- package/sidecar/dist/agent/permission-rules.js +2 -2
- package/sidecar/dist/agent/permission-rules.js.map +1 -1
- package/sidecar/dist/agent/project-secrets.d.ts +7 -0
- package/sidecar/dist/agent/project-secrets.js +61 -0
- package/sidecar/dist/agent/project-secrets.js.map +1 -0
- package/sidecar/dist/agent/provider.d.ts +10 -4
- package/sidecar/dist/agent/runner.d.ts +8 -2
- package/sidecar/dist/agent/runner.js +11 -3
- package/sidecar/dist/agent/runner.js.map +1 -1
- package/sidecar/dist/agent/session.d.ts +3 -3
- package/sidecar/dist/agent/session.js.map +1 -1
- package/sidecar/dist/agent/tool-kinds.d.ts +7 -1
- package/sidecar/dist/agent/tool-kinds.js +24 -5
- package/sidecar/dist/agent/tool-kinds.js.map +1 -1
- package/sidecar/dist/audit/activity-query.js +2 -0
- package/sidecar/dist/audit/activity-query.js.map +1 -1
- package/sidecar/dist/audit/activity.js +1 -0
- package/sidecar/dist/audit/activity.js.map +1 -1
- package/sidecar/dist/builder/builder-client.js +14 -2
- package/sidecar/dist/builder/builder-client.js.map +1 -1
- package/sidecar/dist/constants/audit.d.ts +1 -3
- package/sidecar/dist/constants/audit.js +2 -1
- package/sidecar/dist/constants/audit.js.map +1 -1
- package/sidecar/dist/constants/builder.d.ts +5 -1
- package/sidecar/dist/constants/builder.js +15 -0
- package/sidecar/dist/constants/builder.js.map +1 -1
- package/sidecar/dist/constants/claude.d.ts +8 -0
- package/sidecar/dist/constants/claude.js +8 -0
- package/sidecar/dist/constants/claude.js.map +1 -1
- package/sidecar/dist/constants/codex.d.ts +4 -0
- package/sidecar/dist/constants/codex.js +4 -0
- package/sidecar/dist/constants/codex.js.map +1 -1
- package/sidecar/dist/constants/mcp.d.ts +1 -1
- package/sidecar/dist/constants/mcp.js +1 -1
- package/sidecar/dist/constants/mcp.js.map +1 -1
- package/sidecar/dist/constants/native-binary.d.ts +5 -2
- package/sidecar/dist/constants/native-binary.js +5 -2
- package/sidecar/dist/constants/native-binary.js.map +1 -1
- package/sidecar/dist/constants/permissions.d.ts +2 -0
- package/sidecar/dist/constants/permissions.js +23 -0
- package/sidecar/dist/constants/permissions.js.map +1 -1
- package/sidecar/dist/constants/project-secrets.d.ts +5 -0
- package/sidecar/dist/constants/project-secrets.js +20 -0
- package/sidecar/dist/constants/project-secrets.js.map +1 -0
- package/sidecar/dist/constants/providers.d.ts +2 -0
- package/sidecar/dist/constants/providers.js +1 -0
- package/sidecar/dist/constants/providers.js.map +1 -1
- package/sidecar/dist/constants/settings.d.ts +2 -2
- package/sidecar/dist/constants/settings.js +4 -9
- package/sidecar/dist/constants/settings.js.map +1 -1
- package/sidecar/dist/constants/timing.d.ts +1 -0
- package/sidecar/dist/constants/timing.js +1 -0
- package/sidecar/dist/constants/timing.js.map +1 -1
- package/sidecar/dist/constants/tool-kinds.d.ts +67 -2
- package/sidecar/dist/constants/tool-kinds.js +111 -33
- package/sidecar/dist/constants/tool-kinds.js.map +1 -1
- package/sidecar/dist/mcp/tools/builder-compose.d.ts +51 -0
- package/sidecar/dist/mcp/tools/builder-compose.js +96 -0
- package/sidecar/dist/mcp/tools/builder-compose.js.map +1 -0
- package/sidecar/dist/mcp/tools/builder-gate.js +3 -1
- package/sidecar/dist/mcp/tools/builder-gate.js.map +1 -1
- package/sidecar/dist/mcp/tools/builder-project.js +119 -4
- package/sidecar/dist/mcp/tools/builder-project.js.map +1 -1
- package/sidecar/dist/mcp/tools/builder-queries.d.ts +31 -0
- package/sidecar/dist/mcp/tools/builder-queries.js +30 -13
- package/sidecar/dist/mcp/tools/builder-queries.js.map +1 -1
- package/sidecar/dist/mcp/tools/builder-table-view-schema.d.ts +99 -0
- package/sidecar/dist/mcp/tools/builder-table-view-schema.js +118 -0
- package/sidecar/dist/mcp/tools/builder-table-view-schema.js.map +1 -0
- package/sidecar/dist/mcp/tools/builder-table-view.d.ts +102 -0
- package/sidecar/dist/mcp/tools/builder-table-view.js +24 -0
- package/sidecar/dist/mcp/tools/builder-table-view.js.map +1 -0
- package/sidecar/dist/mcp/tools/builder.d.ts +135 -1
- package/sidecar/dist/mcp/tools/builder.js +17 -4
- package/sidecar/dist/mcp/tools/builder.js.map +1 -1
- package/sidecar/dist/mcp/tools/navigate-to-page.js +12 -4
- package/sidecar/dist/mcp/tools/navigate-to-page.js.map +1 -1
- package/sidecar/dist/pages/block-health.d.ts +14 -0
- package/sidecar/dist/pages/block-health.js +60 -0
- package/sidecar/dist/pages/block-health.js.map +1 -0
- package/sidecar/dist/prompts/agent.d.ts +1 -1
- package/sidecar/dist/prompts/agent.js +4 -3
- package/sidecar/dist/prompts/agent.js.map +1 -1
- package/sidecar/dist/protocol/events.d.ts +140 -63
- package/sidecar/dist/protocol/events.js +24 -8
- package/sidecar/dist/protocol/events.js.map +1 -1
- package/sidecar/dist/protocol/messages.d.ts +111 -49
- package/sidecar/dist/protocol/messages.js +30 -13
- package/sidecar/dist/protocol/messages.js.map +1 -1
- package/sidecar/dist/providers/claude/config.d.ts +19 -5
- package/sidecar/dist/providers/claude/config.js +21 -7
- package/sidecar/dist/providers/claude/config.js.map +1 -1
- package/sidecar/dist/providers/claude/model-fallback.d.ts +9 -0
- package/sidecar/dist/providers/claude/model-fallback.js +37 -0
- package/sidecar/dist/providers/claude/model-fallback.js.map +1 -0
- package/sidecar/dist/providers/claude/provider.js +35 -40
- package/sidecar/dist/providers/claude/provider.js.map +1 -1
- package/sidecar/dist/providers/claude/resolve-binary.js +18 -13
- package/sidecar/dist/providers/claude/resolve-binary.js.map +1 -1
- package/sidecar/dist/providers/claude/safe-mode.d.ts +5 -5
- package/sidecar/dist/providers/claude/safe-mode.js +49 -30
- package/sidecar/dist/providers/claude/safe-mode.js.map +1 -1
- package/sidecar/dist/providers/claude/secret-files.d.ts +2 -0
- package/sidecar/dist/providers/claude/secret-files.js +50 -0
- package/sidecar/dist/providers/claude/secret-files.js.map +1 -0
- package/sidecar/dist/providers/claude/session-stream.d.ts +18 -0
- package/sidecar/dist/providers/claude/session-stream.js +80 -0
- package/sidecar/dist/providers/claude/session-stream.js.map +1 -0
- package/sidecar/dist/providers/claude/tool-guard.d.ts +14 -0
- package/sidecar/dist/providers/claude/tool-guard.js +112 -0
- package/sidecar/dist/providers/claude/tool-guard.js.map +1 -0
- package/sidecar/dist/providers/codex/adapter.d.ts +10 -0
- package/sidecar/dist/providers/codex/adapter.js +20 -5
- package/sidecar/dist/providers/codex/adapter.js.map +1 -1
- package/sidecar/dist/providers/codex/config.d.ts +6 -17
- package/sidecar/dist/providers/codex/config.js +9 -56
- package/sidecar/dist/providers/codex/config.js.map +1 -1
- package/sidecar/dist/providers/codex/mcp-elicitation.d.ts +21 -0
- package/sidecar/dist/providers/codex/mcp-elicitation.js +66 -0
- package/sidecar/dist/providers/codex/mcp-elicitation.js.map +1 -0
- package/sidecar/dist/providers/codex/module.js +1 -1
- package/sidecar/dist/providers/codex/module.js.map +1 -1
- package/sidecar/dist/providers/codex/patch-directories.d.ts +6 -0
- package/sidecar/dist/providers/codex/patch-directories.js +53 -0
- package/sidecar/dist/providers/codex/patch-directories.js.map +1 -0
- package/sidecar/dist/providers/codex/permission-profiles.d.ts +11 -0
- package/sidecar/dist/providers/codex/permission-profiles.js +37 -0
- package/sidecar/dist/providers/codex/permission-profiles.js.map +1 -0
- package/sidecar/dist/providers/codex/permissions.d.ts +13 -4
- package/sidecar/dist/providers/codex/permissions.js +28 -2
- package/sidecar/dist/providers/codex/permissions.js.map +1 -1
- package/sidecar/dist/providers/codex/process.d.ts +1 -0
- package/sidecar/dist/providers/codex/process.js +3 -1
- package/sidecar/dist/providers/codex/process.js.map +1 -1
- package/sidecar/dist/providers/codex/protocol/common.d.ts +16 -4
- package/sidecar/dist/providers/codex/protocol/index.d.ts +2 -2
- package/sidecar/dist/providers/codex/protocol/index.js +1 -1
- package/sidecar/dist/providers/codex/protocol/index.js.map +1 -1
- package/sidecar/dist/providers/codex/protocol/v2.d.ts +23 -32
- package/sidecar/dist/providers/codex/provider.js +13 -12
- package/sidecar/dist/providers/codex/provider.js.map +1 -1
- package/sidecar/dist/providers/codex/secret-file-globs.d.ts +2 -0
- package/sidecar/dist/providers/codex/secret-file-globs.js +45 -0
- package/sidecar/dist/providers/codex/secret-file-globs.js.map +1 -0
- package/sidecar/dist/providers/types.d.ts +3 -1
- package/sidecar/dist/providers/types.js +2 -2
- package/sidecar/dist/providers/types.js.map +1 -1
- package/sidecar/dist/server/chat-events.js +1 -0
- package/sidecar/dist/server/chat-events.js.map +1 -1
- package/sidecar/dist/server/http-routes.js +1 -1
- package/sidecar/dist/server/http-routes.js.map +1 -1
- package/sidecar/dist/server/navigation-completer.d.ts +15 -2
- package/sidecar/dist/server/navigation-completer.js +42 -41
- package/sidecar/dist/server/navigation-completer.js.map +1 -1
- package/sidecar/dist/server/permission-events.d.ts +1 -1
- package/sidecar/dist/server/permission-events.js +5 -8
- package/sidecar/dist/server/permission-events.js.map +1 -1
- package/sidecar/dist/server/routing.js +11 -6
- package/sidecar/dist/server/routing.js.map +1 -1
- package/sidecar/dist/server/tool-calls.d.ts +0 -2
- package/sidecar/dist/server/tool-calls.js +7 -8
- package/sidecar/dist/server/tool-calls.js.map +1 -1
- package/sidecar/dist/server/turns.js +17 -1
- package/sidecar/dist/server/turns.js.map +1 -1
- package/sidecar/dist/server/ws.js +4 -15
- package/sidecar/dist/server/ws.js.map +1 -1
- package/sidecar/dist/skills/skill-usage.js +2 -2
- package/sidecar/dist/skills/skill-usage.js.map +1 -1
- package/sidecar/dist/state/conversations.d.ts +1 -0
- package/sidecar/dist/state/conversations.js +8 -0
- package/sidecar/dist/state/conversations.js.map +1 -1
- package/sidecar/dist/state/settings-store.d.ts +14 -5
- package/sidecar/dist/state/settings-store.js +34 -8
- package/sidecar/dist/state/settings-store.js.map +1 -1
- package/sidecar/dist/state/settings-types.d.ts +16 -2
- package/sidecar/dist/state/settings-types.js +14 -1
- package/sidecar/dist/state/settings-types.js.map +1 -1
- package/sidecar/dist/state/types.d.ts +14 -6
- package/sidecar/dist/state/types.js.map +1 -1
- package/sidecar/package.json +3 -3
- package/skills/dms-ai/SKILL.md +2 -1
- package/skills/dms-builder-safe/REFERENCE.md +5 -6
- package/skills/dms-builder-safe/SKILL.md +12 -10
- package/skills/dms-external-database/REFERENCE.md +20 -8
- package/skills/dms-external-database/SKILL.md +69 -20
- package/skills/dms-page-design/SKILL.md +192 -0
- package/skills/dms-page-design/cases.json +57 -0
- package/frontend-vue/app/chat/components/FullAutoBanner.vue +0 -76
- package/frontend-vue/app/chat/components/FullAutoDialog.vue +0 -103
|
@@ -38,9 +38,9 @@ its safe-mode branch.
|
|
|
38
38
|
TableView `Column` `type`, a resource field's `dataType`), pass a **DataType value**
|
|
39
39
|
`{ $dataType: "<id>", config: {…} }` — an id from `BuilderCatalog`'s `dataTypes`.
|
|
40
40
|
Never pass a raw `$expr`; safe mode refuses it.
|
|
41
|
-
- Config fields the catalog marks `x-component` hold a nested
|
|
42
|
-
ChartCard's `chart`)
|
|
43
|
-
|
|
41
|
+
- Config fields the catalog marks `x-component` hold a nested block (e.g. a
|
|
42
|
+
ChartCard's `chart`): pass a **block value** `{ $block: { type: "<type>", config: {…} } }`
|
|
43
|
+
with a `type` from `BuilderCatalog`. It is validated and allowed in safe mode.
|
|
44
44
|
- To name a builder-generated resource class inside config — e.g. a relation column's
|
|
45
45
|
`dataApiController` — pass a **reference value**
|
|
46
46
|
`{ $ref: { resource: "<ref>", as?: "dataApi" | "table" | "model" } }` (default `as`
|
|
@@ -92,14 +92,16 @@ resource workflow (`BuilderListResources` / `BuilderCreateResource` with `locati
|
|
|
92
92
|
and `routes` / field ops / `BuilderDeleteResource`), field semantics and reserved
|
|
93
93
|
names, and the engine-support caveat for resource ops.
|
|
94
94
|
|
|
95
|
-
## Queries (computed
|
|
95
|
+
## Queries (computed data a DataAPI can't serve)
|
|
96
96
|
|
|
97
|
-
A **query** is a derived-data endpoint on a *page*: a GET route
|
|
98
|
-
|
|
99
|
-
The DataAPI serves rows; a query serves
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
A **query** is a derived-data endpoint on a *page*: a GET route serving an aggregate (a
|
|
98
|
+
count, a sum, an average) or one point per group (a series), backed by a generated method on
|
|
99
|
+
a resource's model. The DataAPI serves rows; a query serves what KPI cards, charts and ranked
|
|
100
|
+
lists read. Its `response` arranges the answer for the block: `value` for a `KpiCard`,
|
|
101
|
+
`card` for a `ChartCard`, `items` for a `TopListCard`, `series` for a bare chart. Run
|
|
102
|
+
`BuilderPreviewQuery` first to see the answer, then add it with `BuilderAddQuery` on the page
|
|
103
|
+
that will display it (not the resource's page), wire the returned `route` as the block's
|
|
104
|
+
`fetchUrl`, and read it back through `BuilderPageStructure`'s `queries`. See [REFERENCE.md](REFERENCE.md) for the
|
|
103
105
|
template catalog, route-bound params, opaque read-back, and the full query workflow.
|
|
104
106
|
|
|
105
107
|
## Errors & escalation
|
|
@@ -109,11 +109,20 @@ erp · postgresql 17.5 · role erp_reader (read only) · 42 relations: 9 TableVi
|
|
|
109
109
|
- sales.events (R8, stats only) → TableView: named and commented as calendar events people edit
|
|
110
110
|
- sales.orders: editable, as asked; the role here writes nothing
|
|
111
111
|
|
|
112
|
-
##
|
|
113
|
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
|
|
112
|
+
## Questions
|
|
113
|
+
- How does revenue trend, and how does it compare with last year? (sales.orders, sum of total, by ordered_at)
|
|
114
|
+
- Which statuses do orders end in? (sales.orders, count, by status)
|
|
115
|
+
- Which countries buy most? (sales.orders, sum of total, by country)
|
|
116
|
+
|
|
117
|
+
## Analytics pages
|
|
118
|
+
### Sales (sales.orders)
|
|
119
|
+
- Period: ordered_at runs 2024-01-03 to 2026-10-28 → default last-90-days vs previous-period; presets last-90-days, ytd, last-year, custom
|
|
120
|
+
- Toolbar: PageToolbar › PeriodSelector
|
|
121
|
+
- KPIs: revenue (sum of total) · orders (count) · units (sum of quantity), each with delta and sparkline
|
|
122
|
+
- ChartCard › ChartArea: revenue per month
|
|
123
|
+
- ChartCard › ChartDonut: orders by status (5 values)
|
|
124
|
+
- ChartCard › ChartBar: top 10 countries by revenue
|
|
125
|
+
- TopListCard: top 10 cities by orders
|
|
117
126
|
|
|
118
127
|
## Left open
|
|
119
128
|
- label:legacy.t_ord — no column names an order; the integrator picks one in the Builder
|
|
@@ -132,9 +141,10 @@ The proposal's values, without their rules, plus what you changed:
|
|
|
132
141
|
"fields": [ { "column": "name", "searchable": true, "sortable": true },
|
|
133
142
|
{ "column": "segment", "filterable": true },
|
|
134
143
|
{ "column": "email" }, { "column": "created_at", "sortable": true } ] },
|
|
135
|
-
{ "relation": "sales.orders", "tableView": true, "writable": false,
|
|
136
|
-
"fields": [ { "column": "status", "filterable": true
|
|
137
|
-
|
|
144
|
+
{ "relation": "sales.orders", "tableView": true, "writable": false, "tabs": { "column": "status" },
|
|
145
|
+
"fields": [ { "column": "status", "filterable": true,
|
|
146
|
+
"display": { "kind": "badge", "items": [ { "value": "paid", "label": "Paid", "tone": "success" } ] } },
|
|
147
|
+
{ "column": "ordered_at", "sortable": true }, { "column": "total", "display": { "kind": "price", "currency": "USD" } },
|
|
138
148
|
{ "column": "customer_code", "relation": "sales.customers", "label": "Customer" } ] },
|
|
139
149
|
{ "relation": "sales.audit_log", "tableView": false, "writable": false,
|
|
140
150
|
"fields": [ { "column": "at" }, { "column": "action" } ] }
|
|
@@ -145,6 +155,8 @@ The proposal's values, without their rules, plus what you changed:
|
|
|
145
155
|
- `declared` defaults to the column's `accepts[0]`. Set it only to take another accepted
|
|
146
156
|
declaration, and always for a column a `field-type` item asked about: give the answer as its
|
|
147
157
|
`declared`.
|
|
158
|
+
- Send `display` (each field) and `tabs` (each relation) as the proposal has them; `null` turns
|
|
159
|
+
one off.
|
|
148
160
|
- Key columns are added for you.
|
|
149
161
|
- A relation column's target must be in the same call, with a `label`, or mapped in the module
|
|
150
162
|
before.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dms-external-database
|
|
3
|
-
description: Connects a DMS project to a client's existing database, runs the Builder's analysis of it, settles what the analysis could not decide from the catalog and aggregates, generates TableViews through the Builder, and
|
|
3
|
+
description: Connects a DMS project to a client's existing database, runs the Builder's analysis of it, settles what the analysis could not decide from the catalog and aggregates, generates TableViews through the Builder, names them and gives each the table features its data supports, and always builds an analytics dashboard first in the menu. Use when the user wants pages over a database the project does not own, PostgreSQL, MongoDB or RethinkDB ("plug in our client's Postgres", "map their Mongo database", "generate the admin for this database", "finish the mapping the Builder proposed").
|
|
4
4
|
icon: i-ph-database
|
|
5
5
|
category: Builder
|
|
6
6
|
tags: [Database, Builder, Pages, DMS]
|
|
@@ -10,12 +10,15 @@ tags: [Database, Builder, Pages, DMS]
|
|
|
10
10
|
|
|
11
11
|
The Builder analyses the database by itself: from the catalog and the profiles, fixed rules
|
|
12
12
|
propose a mapping and name every choice's rule. Your work is what those rules cannot do: answer
|
|
13
|
-
the questions they left open, revisit the defaults the names and comments contradict, and
|
|
14
|
-
|
|
13
|
+
the questions they left open, revisit the defaults the names and comments contradict, and plan the
|
|
14
|
+
analytics pages from the data. You never start from scratch.
|
|
15
15
|
|
|
16
16
|
You work through the `Database*` and `Builder*` tools only. You never read rows of the client's
|
|
17
|
-
database: the catalog and aggregates are what you have, and they are enough.
|
|
18
|
-
|
|
17
|
+
database: the catalog and aggregates are what you have, and they are enough. The database's URL
|
|
18
|
+
lives in the project's `.env`. The sidecar refuses your file tools on `.env` files and keeps their
|
|
19
|
+
variables out of your environment. Under Claude Code a shell in Code mode can still read them; under
|
|
20
|
+
Codex the sandbox refuses that too. Never read `.env` or print the environment, and never write a
|
|
21
|
+
credential yourself.
|
|
19
22
|
|
|
20
23
|
The flow is **connect → analyse → settle → validate → apply → check**. Analysing and settling
|
|
21
24
|
read only, so they run in plan mode. Nothing is written before the integrator presses **Run** on
|
|
@@ -91,17 +94,48 @@ profile of the whole database again: the Builder did it.
|
|
|
91
94
|
neither is an array of ids as a relation.
|
|
92
95
|
- **Editable.** Every TableView is proposed read-only. Make one editable only where the integrator
|
|
93
96
|
wants it; show `writes` beside it, so a read-only role in this environment is visible.
|
|
94
|
-
- **
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
- **Pages people can work with.** Load the `dms-page-design` skill. For every TableView, plan
|
|
98
|
+
from its columns, profiles and categories, as *Name every page* and *Tables* there say: a
|
|
99
|
+
title, an icon and a description; the tabs, saved views, display modes, footer totals and
|
|
100
|
+
KPI cards its data supports. Decide each from the data, and leave out what the data does
|
|
101
|
+
not support.
|
|
102
|
+
- **The analytics dashboard,** which the analysis does not make. Every run ends with one,
|
|
103
|
+
first in the menu, even when the integrator only asked for the tables. Plan it from the data:
|
|
104
|
+
1. **Inspect.** For each relation, read from the proposal its rows, its `time-axis` columns
|
|
105
|
+
with their `range`, its `measure` columns, and its `enum-like` columns with their
|
|
106
|
+
`categories`. Profile a column the proposal leaves without them, such as the main date
|
|
107
|
+
column's range. Write each range down: the period rule needs the last date.
|
|
108
|
+
2. **Ask.** Write the 4 to 8 questions the owner of this data asks every week: how revenue
|
|
109
|
+
or volume trends, what sells, who buys, where, and how it compares with last year. Each
|
|
110
|
+
question names the relation, the measure (a sum of a `measure` column or a row count)
|
|
111
|
+
and the grouping (the time axis or a column of the same relation).
|
|
112
|
+
3. **Plan pages.** The relation with a time axis, a measure and the most rows is the main
|
|
113
|
+
fact relation. It gets the dashboard, named for its area ("Sales", or "Overview" when it
|
|
114
|
+
also carries the other relations' headline figures), holding every question about it.
|
|
115
|
+
Another relation gets its own analytics page only when it has its own time axis and at
|
|
116
|
+
least 100 rows. When no relation has a time axis, the dashboard still exists: KPI cards
|
|
117
|
+
of counts and sums, and breakdowns by the category columns, with no period selector.
|
|
118
|
+
4. **Choose blocks** for each question with `dms-page-design`, and its default period from
|
|
119
|
+
the main time axis's real range.
|
|
120
|
+
- **The minimum.** Your plan, and the pages you write, meet all of these:
|
|
121
|
+
- one analytics dashboard, first in the connection's menu (`order: 0`), opened by a toolbar
|
|
122
|
+
with a period selector when the data has dates;
|
|
123
|
+
- every page with a title in the owner's words, an icon and a description, never the raw
|
|
124
|
+
relation name;
|
|
125
|
+
- every table given the tabs, views, display modes, footer totals and KPI cards its data
|
|
126
|
+
supports, as `dms-page-design` *Tables* decides;
|
|
127
|
+
- at least 3 different chart kinds on it when the data has the shapes for them;
|
|
128
|
+
- a default period computed from the data's real dates, never assumed;
|
|
129
|
+
- every page built with one `BuilderComposePage` call, previewed first, and every block whose
|
|
130
|
+
preview is empty, zero or failed dropped or changed;
|
|
131
|
+
- every page opened with `NavigateToPage` and its block report read before you report.
|
|
99
132
|
- **Not possible yet:** breakdowns by a related entity's name, such as revenue per customer.
|
|
100
133
|
Templates read one relation, so they would show ids. List them under *Not possible yet*,
|
|
101
134
|
never as pages.
|
|
102
135
|
|
|
103
136
|
Write your plan (`ExitPlanMode`) in the format of REFERENCE.md *Plan*: what you change in the
|
|
104
|
-
proposal and why, the
|
|
137
|
+
proposal and why, the questions and the analytics pages that answer them, the open items you
|
|
138
|
+
leave, and what is not possible yet.
|
|
105
139
|
|
|
106
140
|
## 4. Validate
|
|
107
141
|
|
|
@@ -110,18 +144,29 @@ again. Write nothing before Run.
|
|
|
110
144
|
|
|
111
145
|
## 5. Apply
|
|
112
146
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
147
|
+
Work in this order, so the most visible result lands first: map the tables, build the
|
|
148
|
+
dashboard and check it, then add KPI rows above tables, then any second analytics page.
|
|
149
|
+
|
|
150
|
+
1. `BuilderMapResources` in batches of 3 or 4 relations per call, TableViews and stats-only
|
|
151
|
+
relations alike; the relations decided against go in `excluded` on the first call
|
|
152
|
+
(REFERENCE.md *Mapping*). One call with every relation of a large database can abort.
|
|
153
|
+
- Send the proposal's choices as they stand where you changed nothing, plus per resource
|
|
154
|
+
the `title`, `icon`, `description` and `tableOptions` you planned.
|
|
117
155
|
- On `invalid_config`, fix the choice it names and call again: a refused call writes nothing.
|
|
156
|
+
When the same choice is refused twice, drop it (send the relation without that display or
|
|
157
|
+
option) and say so in your report, rather than trying more variants.
|
|
118
158
|
- It answers each relation's `ref`, which queries name it by, `category`, the connection's
|
|
119
159
|
category ref (`pages.<connection>`), and `leftOut`: carry those into your report.
|
|
120
|
-
2. Per
|
|
121
|
-
set to the `category`
|
|
122
|
-
|
|
123
|
-
`dms-
|
|
160
|
+
2. Per analytics page, one `BuilderComposePage` call with `create` (`name`, `displayName`,
|
|
161
|
+
`module` set to the generated module, `category` set to the `category` MapResources
|
|
162
|
+
answered, an icon, a description, and `order: 0` for the dashboard, 1, 2… for the next
|
|
163
|
+
ones) and every block in the order `dms-page-design` lays out, each data block with its
|
|
164
|
+
query inline. Preview first, then write, as `dms-page-design` *Build a page in one call*
|
|
165
|
+
says.
|
|
124
166
|
- Queries read the mapped resources by their refs (`<connection>/<schema>/<relation>`).
|
|
167
|
+
3. Per table page that gets KPI cards above its table, one `BuilderComposePage` call with
|
|
168
|
+
`placement: { "before": "table" }`, previewed first. A table option MapResources refused
|
|
169
|
+
comes back as a warning: fix it with `BuilderConfigureTableView`.
|
|
125
170
|
|
|
126
171
|
To change a relation later, read its current choices with `BuilderMapping`, then call
|
|
127
172
|
`BuilderMapResources` with that relation alone, its included columns as they are and only your
|
|
@@ -137,11 +182,15 @@ change made: a mapped relation is rewritten from the choices sent, and its page
|
|
|
137
182
|
investigate further.
|
|
138
183
|
- `QueryLogs` for registration warnings (lossy fields, unserved indexes) and for the errors of
|
|
139
184
|
the routes the pages called.
|
|
185
|
+
- On each analytics page, fix or remove every block `NavigateToPage` reports as empty or
|
|
186
|
+
failed, and navigate again, as in `dms-page-design` *Check every block*.
|
|
140
187
|
|
|
141
188
|
Then report:
|
|
142
189
|
|
|
143
190
|
- what the Builder mapped by its rules, and what you changed;
|
|
144
|
-
- the pages made
|
|
191
|
+
- the pages made, with each analytics page's default period and the date range it came from,
|
|
192
|
+
and per table the features you gave it and why;
|
|
193
|
+
- every block that still shows no data, and why;
|
|
145
194
|
- what was left out and why;
|
|
146
195
|
- the open items left, which the integrator finds in the Builder's *Database* workspace;
|
|
147
196
|
- the variable every deployment must set.
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dms-page-design
|
|
3
|
+
description: Designs DMS pages that show data, through the Builder tools. Use when building or changing an analytics, stats or dashboard page or a table page, choosing a chart or a KPI for some data, picking a page's period, naming a page and its icon, or deciding how a table displays (badges, prices, relation labels, status tabs, saved views, kanban, cards, footer totals, KPI cards above the table).
|
|
4
|
+
icon: i-ph-chart-pie-slice
|
|
5
|
+
category: Builder
|
|
6
|
+
tags: [Pages, Charts, Dashboard, Tables, DMS]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Designing data pages
|
|
10
|
+
|
|
11
|
+
A data page answers the questions its owner asks about the data. Each block answers one
|
|
12
|
+
question, and its title says which ("Revenue per month", "Top 10 countries by revenue").
|
|
13
|
+
Build every page from the questions, the shapes below and the checks at the end, in that
|
|
14
|
+
order, so that two runs over the same data produce the same page.
|
|
15
|
+
|
|
16
|
+
This skill decides **what** to build. The tools and their arguments are in `dms-builder-safe`
|
|
17
|
+
(safe mode) and `dms-pages` (code); `dms-best-practices` still holds.
|
|
18
|
+
|
|
19
|
+
## Pick the block from the data's shape
|
|
20
|
+
|
|
21
|
+
| The data | Block | Query |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| A measure or a row count over time | `ChartCard` around `ChartArea`, full width | `series`, `groupBy` the time axis, `bucket`, `response: "card"` |
|
|
24
|
+
| A second series over time (orders beside revenue) | `ChartCard` around `ChartColumn` or `ChartLine` | as above |
|
|
25
|
+
| A column with 2 to 6 values (status, segment, media type) | `ChartCard` around `ChartDonut`, with `showSeriesLegend: true` | `series`, `groupBy` the column, `response: "card"` |
|
|
26
|
+
| A column with 7 or more values, a top N | A bare `ChartBar`, or a `TopListCard` with `showBar` | `series`, `orderBy: "measure"`, `direction: "desc"`, `limit: 10`; `response: "card"` for the chart, `"items"` for the list |
|
|
27
|
+
| One figure with its trend (revenue, orders, customers) | `KpiCard` with `showDelta`, `showSparkline` | `series` by the time axis (never `count` or `aggregate`, which answer no previous period and no sparkline), `response: "value"`, `compare: true` |
|
|
28
|
+
| Numbers used as categories (a rating 1 to 5, a year) | `ChartCard` around `ChartColumn` with `xaxisType: "category"` | `series`, `groupBy` the column |
|
|
29
|
+
| A status column on a table | Tabs on the `TableView`, plus a donut on the analytics page | see *Tables* |
|
|
30
|
+
|
|
31
|
+
- Put a chart in a `ChartCard`: it adds the headline figure. In safe mode its `chart` is a
|
|
32
|
+
nested block value, `{ "$block": { "type": "ChartArea", "config": {} } }`. A horizontal
|
|
33
|
+
`ChartBar` stays bare: inside a card its category labels read `NaN`.
|
|
34
|
+
- The `response` must match the block: `card` for a `ChartCard` or a bare chart, `value` for a
|
|
35
|
+
`KpiCard`, `items` for a `TopListCard`. Any other pairing draws nothing.
|
|
36
|
+
- Compare periods on KPI cards and top lists (`compare: true`), never on a chart over time:
|
|
37
|
+
the previous period's buckets are other categories, so they draw beside the period instead
|
|
38
|
+
of under it.
|
|
39
|
+
- Sum a measure that adds up (a total, a quantity). Count rows for everything else. Never sum
|
|
40
|
+
a unit price or a rate.
|
|
41
|
+
- Format money with `valueFormat: "currency"` and a `currencyCode` only when the data names its
|
|
42
|
+
currency (a currency column, a comment). Otherwise use `valueFormat: "number"`: the default
|
|
43
|
+
currency is the euro, and a wrong symbol is worse than none.
|
|
44
|
+
- Grouping by a foreign key shows ids. Group by the relation's own columns only; a breakdown by
|
|
45
|
+
a related entity's name goes under *Not possible yet* in your report.
|
|
46
|
+
|
|
47
|
+
## Lay out an analytics page
|
|
48
|
+
|
|
49
|
+
Add the blocks in this order. Every analytics page has items 1 to 4.
|
|
50
|
+
|
|
51
|
+
1. A `PageToolbar` holding a `PeriodSelector`, first on the page (see *Period*).
|
|
52
|
+
2. One `GridRow` of 3 or 4 `KpiCard`s, each bound to the period.
|
|
53
|
+
3. The main series over time, a full-width `ChartCard`.
|
|
54
|
+
4. A `GridRow` of two breakdowns: a bare `ChartBar` for the largest category column, and a
|
|
55
|
+
`ChartDonut` or a `ChartColumn` for another column or a second measure over time.
|
|
56
|
+
5. A `TopListCard` for a second category column, when one exists.
|
|
57
|
+
|
|
58
|
+
Use at least 3 different chart kinds on the page when the data has the shapes for them. The
|
|
59
|
+
chart kinds are `ChartArea`, `ChartLine`, `ChartColumn`, `ChartBar` and `ChartDonut`; KPI cards
|
|
60
|
+
and top lists are not chart kinds. Use a second kind before you repeat one. A page of KPI cards
|
|
61
|
+
alone is never done.
|
|
62
|
+
|
|
63
|
+
Every card binds the page's period: `periodScope: "page"` on the block, and on its query
|
|
64
|
+
`where` filters on the time axis bound to the request,
|
|
65
|
+
`{ "field": "<time axis>", "op": "ge", "value": { "$param": { "name": "from" } } }` and
|
|
66
|
+
`"le"` with `"to"`. A card over a relation with no time axis stays unbound.
|
|
67
|
+
|
|
68
|
+
## Period
|
|
69
|
+
|
|
70
|
+
The default period is computed from the data's real dates, never assumed. Read the time
|
|
71
|
+
axis's `range` from the analysis, or profile that column. Then take the first rule that holds,
|
|
72
|
+
counting from today:
|
|
73
|
+
|
|
74
|
+
1. The data reaches into the last 30 days and spans at least 90 days: `last-90-days`,
|
|
75
|
+
compared with `previous-period`.
|
|
76
|
+
2. The current year holds at least 3 months of data: `ytd`, compared with `previous-year`.
|
|
77
|
+
3. Last calendar year holds data: `last-year`, compared with `previous-year` when the year
|
|
78
|
+
before it holds data too, else `none`.
|
|
79
|
+
4. Otherwise bind nothing to a period, leave the selector out, and say so in your report.
|
|
80
|
+
|
|
81
|
+
Set it on the selector: `defaultPreset`, `defaultComparison`, `presets` (the default, any
|
|
82
|
+
other preset whose window holds data, and `custom`) and `comparisons`. Leave `all` out of
|
|
83
|
+
`presets`: it sends no `from` or `to`, and every bound query fails without them.
|
|
84
|
+
|
|
85
|
+
Pick the bucket so the default window holds 8 to 31 points: `day` up to 31 days, `week` up to about 7 months (a 90-day window is 13 weeks), `month` beyond. A time chart with fewer than 8 points reads as a curve with no story. An axis
|
|
86
|
+
chart (area, line, column, bar) over time takes `xaxisType: "category"`, unless a preview's
|
|
87
|
+
`x` values are epoch milliseconds, which take `xaxisType: "datetime"`. A donut or pie takes
|
|
88
|
+
no axis option.
|
|
89
|
+
|
|
90
|
+
## Name every page
|
|
91
|
+
|
|
92
|
+
Every page you create or map gets a title, an icon and a description; a raw relation name is
|
|
93
|
+
never a title.
|
|
94
|
+
|
|
95
|
+
- **Title**: what the owner calls the content, in their words and plural for lists ("Support
|
|
96
|
+
tickets", not "support_ticket"; "Sales", not "orders stats"). Drop technical prefixes and
|
|
97
|
+
suffixes (`tbl_`, `_v2`). An analytics page is named for the area it covers ("Sales",
|
|
98
|
+
"Customers", "Overview"). Two pages never share a title: when a table page is already
|
|
99
|
+
"Customers", its analytics page is "Customer insights".
|
|
100
|
+
- **Icon**: a Phosphor icon, `i-ph-<name>`, that a reader links to the content at a glance
|
|
101
|
+
(`i-ph-users` for people, `i-ph-package` for goods, `i-ph-receipt` for invoices,
|
|
102
|
+
`i-ph-chart-line-up` for an analytics page). Two pages in one menu never share an icon.
|
|
103
|
+
- **Description**: one sentence on what the page holds or answers, from the data
|
|
104
|
+
("Every order with its payment and shipping status").
|
|
105
|
+
- **Order**: the main analytics page first (`order: 0`), then the most used lists. Keep a
|
|
106
|
+
table page's order at 100 or more unless it must sit among the dashboards.
|
|
107
|
+
|
|
108
|
+
Set them with `BuilderCreatePage` on new pages, per resource in `BuilderMapResources`
|
|
109
|
+
(`title`, `icon`, `description`, `order`), or with `BuilderConfigurePage` afterwards.
|
|
110
|
+
|
|
111
|
+
## Tables
|
|
112
|
+
|
|
113
|
+
A table page is a working tool: the reader finds a row, sees its state, and acts. Read the
|
|
114
|
+
relation's columns with `BuilderResourceStructure` (and the proposal's profiles when there
|
|
115
|
+
is one), then give the table every feature its data supports, and none it does not. Each
|
|
116
|
+
rule below names the shape that earns the feature; decide from the columns and their values,
|
|
117
|
+
never from the relation's name.
|
|
118
|
+
|
|
119
|
+
**Columns.** A primary key gets no display and is never a row's label. A boolean keeps its
|
|
120
|
+
default display (no badge). A column that a view filters on, a tab splits on, or a footer
|
|
121
|
+
`where` reads must be `filterable` in the mapping; one that a view sorts on, `sortable`.
|
|
122
|
+
Keep the Builder's proposed displays unless the column's meaning says otherwise:
|
|
123
|
+
a column with few distinct values (a status, a type, a channel, a priority, under about 12
|
|
124
|
+
values) shows coloured badges, one tone per value (green for done or good, amber for waiting,
|
|
125
|
+
red for failed or lost, grey for closed or neutral); free text (a subject, a note, a name)
|
|
126
|
+
never shows badges, even when the sample repeats. A money column shows a price. A relation
|
|
127
|
+
column (a `customer_id`, an `order_id`) is titled by its target ("Customer") and shows the
|
|
128
|
+
target's label, never the raw number: map the target relation with a label first, then send
|
|
129
|
+
the relation column as a relation. Raw id columns stay off the list. Send each field's `display` and the relation's `tabs` in `BuilderMapResources`.
|
|
130
|
+
|
|
131
|
+
**Tabs.** A single-choice column with 2 to 6 values that splits the rows into states people
|
|
132
|
+
work through (a status, a stage) gives one tab per value after "All". One tab column per table.
|
|
133
|
+
|
|
134
|
+
**Saved views** (`views`). Add 2 to 4 views when a recurring question is a fixed filter on the
|
|
135
|
+
table: rows waiting for action (a status that means "to do"), recent rows (a date
|
|
136
|
+
`greater_than` `{{now-7d}}` or `{{now-30d}}`), rows assigned to the reader (an owner column
|
|
137
|
+
equal to `{{user.id}}`), outliers worth a look (a stock or a score under a threshold read from
|
|
138
|
+
the profile, a high amount). Each view has a short label that states the question
|
|
139
|
+
("Awaiting shipment", "This week", "Low stock"), a sort that puts the first row to handle on
|
|
140
|
+
top, and `count: true` when the number itself matters. Keep views and tabs from repeating each
|
|
141
|
+
other: views for questions that cross columns or dates, tabs for the plain split by state.
|
|
142
|
+
|
|
143
|
+
**Display modes.** Offer another display when the data reads better that way, and make it the
|
|
144
|
+
default only when it is the main way to work the table:
|
|
145
|
+
|
|
146
|
+
- **Kanban** (`kanban.groupBy`) when a single-choice status or stage column describes a flow
|
|
147
|
+
rows move through, with 3 to 7 values and rows that are handled one by one (tickets, tasks,
|
|
148
|
+
deliveries, applications). Not for a column that only classifies (a country, a category).
|
|
149
|
+
Kanban works on a read-only table: it shows the flow without moving cards. Leave `draggable`
|
|
150
|
+
off unless the table is editable.
|
|
151
|
+
- **Cards** (`cards.fields`) when each row is an entity people recognise by a few fields
|
|
152
|
+
rather than compare across many columns (a product, a person, a place): 3 to 5 fields, the
|
|
153
|
+
label first, then the badge and the key figure.
|
|
154
|
+
- **Grouped** (`grouped`) when rows are read by day or week (a log, bookings, events): group by
|
|
155
|
+
the main date column with `by: "day"` or `"week"`.
|
|
156
|
+
|
|
157
|
+
**Footer totals** (`footer.summary`). When the table has an additive money or quantity column,
|
|
158
|
+
show its `sum`, and a `count` of rows; add a `count` with a `where` on a status value when that
|
|
159
|
+
number is what the reader checks ("Refunded"). Never sum a unit price, a rate or a score.
|
|
160
|
+
|
|
161
|
+
**KPI cards above the table.** When the relation has a measure or a state worth tracking (an
|
|
162
|
+
amount, rows waiting, a share of a status), put a `GridRow` of 3 or 4 `KpiCard`s above the
|
|
163
|
+
`TableView`, each answering one question the table's reader asks ("Revenue this month",
|
|
164
|
+
"Awaiting shipment", "Refund rate"), with the series and `compare` rules above. A lookup list
|
|
165
|
+
(a reference table, tags, settings) gets none.
|
|
166
|
+
|
|
167
|
+
Set displays, views and footer per resource as `tableOptions` in `BuilderMapResources`, or on
|
|
168
|
+
an existing page with `BuilderConfigureTableView`. A refused choice comes back as
|
|
169
|
+
`invalid_config` with the setting it names: fix that one and send again.
|
|
170
|
+
|
|
171
|
+
## Build a page in one call, and check it first
|
|
172
|
+
|
|
173
|
+
Build every page, or every set of blocks added to a page, with one `BuilderComposePage` call:
|
|
174
|
+
the blocks as an ordered tree (containers carry `children`), each data block with its `query`
|
|
175
|
+
inline (same fields as `BuilderAddQuery`). It writes everything at once and typechecks once.
|
|
176
|
+
Use the single-block tools only for a small fix afterwards.
|
|
177
|
+
|
|
178
|
+
1. Call it first with `"preview": true` and the default period's `from` and `to` as `args`.
|
|
179
|
+
It writes nothing and answers each block's status. Change or drop every block marked
|
|
180
|
+
`empty`, `zero` or `error` (another measure, the whole history for a card that should not
|
|
181
|
+
follow the period), then preview again. Never write a block over an empty answer.
|
|
182
|
+
2. Call it again without `preview` to write. A refusal lists every refused block by pointer:
|
|
183
|
+
fix those and call again; nothing was written.
|
|
184
|
+
3. KPI cards above a table: `pageRef` of the table page, `placement: { "before": "table" }`,
|
|
185
|
+
and the `GridRow` of `KpiCard`s as `blocks`. A later remap keeps them.
|
|
186
|
+
4. After the last page, `NavigateToPage` once per page and fix any block it reports as empty
|
|
187
|
+
or failed.
|
|
188
|
+
5. Your report names every block that still shows no data, and why.
|
|
189
|
+
|
|
190
|
+
The page is done when every block has data in the default period, the page meets the
|
|
191
|
+
layout above, it has a title, an icon and a description, and each table uses every feature
|
|
192
|
+
its data supports.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"cases": [
|
|
4
|
+
{
|
|
5
|
+
"id": "dms-page-design-dashboard",
|
|
6
|
+
"area": "dms-ai",
|
|
7
|
+
"style": "clean",
|
|
8
|
+
"prompt": "Build a sales dashboard over the orders table with the Builder: KPIs, a trend over time and a breakdown by status.",
|
|
9
|
+
"expect": {
|
|
10
|
+
"skills": ["dms-page-design"],
|
|
11
|
+
"acceptable": ["dms-builder-safe", "dms-best-practices", "dms-pages"]
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "dms-page-design-chart-choice",
|
|
16
|
+
"area": "dms-ai",
|
|
17
|
+
"style": "casual",
|
|
18
|
+
"prompt": "which chart should i use for orders by country, theres like 24 countries",
|
|
19
|
+
"expect": {
|
|
20
|
+
"skills": ["dms-page-design"],
|
|
21
|
+
"acceptable": ["dms-builder-safe", "dms-pages"]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "dms-page-design-period",
|
|
26
|
+
"area": "dms-ai",
|
|
27
|
+
"style": "clean",
|
|
28
|
+
"prompt": "The charts on the stats page are empty because the period defaults to the last 30 days and the data stops last year. Fix the default period.",
|
|
29
|
+
"expect": {
|
|
30
|
+
"skills": ["dms-page-design"],
|
|
31
|
+
"acceptable": ["dms-builder-safe", "dms-pages", "dms-best-practices"],
|
|
32
|
+
"mustMention": ["PeriodSelector"]
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "dms-page-design-table-badges",
|
|
37
|
+
"area": "dms-ai",
|
|
38
|
+
"style": "clean",
|
|
39
|
+
"prompt": "On the orders table, show the status as coloured badges, the total as a price, and add a tab per status.",
|
|
40
|
+
"expect": {
|
|
41
|
+
"skills": ["dms-page-design"],
|
|
42
|
+
"acceptable": ["dms-builder-safe", "dms-external-database", "dms-pages"]
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "dms-page-design-not-safe-mode-approval",
|
|
47
|
+
"area": "dms-ai",
|
|
48
|
+
"style": "clean",
|
|
49
|
+
"prompt": "In safe mode the Builder refuses to add a block to the sales page until I approve it. Where do I approve a pending Builder change?",
|
|
50
|
+
"expect": {
|
|
51
|
+
"skills": ["dms-builder-safe"],
|
|
52
|
+
"acceptable": ["dms-builder", "dms-pages"],
|
|
53
|
+
"avoid": ["dms-page-design"]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from "vue";
|
|
3
|
-
import { useChatI18n } from "../composables/useChatI18n";
|
|
4
|
-
import type { FullAutoState } from "../types/protocol";
|
|
5
|
-
import { formatClock } from "../utils/format";
|
|
6
|
-
|
|
7
|
-
interface Props {
|
|
8
|
-
fullAuto: FullAutoState;
|
|
9
|
-
nowMs: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface Emits {
|
|
13
|
-
turnOff: [];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const props = defineProps<Props>();
|
|
17
|
-
const emit = defineEmits<Emits>();
|
|
18
|
-
const { t } = useChatI18n();
|
|
19
|
-
|
|
20
|
-
const scope = computed<string>(() => {
|
|
21
|
-
const { duration, untilMs } = props.fullAuto;
|
|
22
|
-
if (duration === "30m" && untilMs !== undefined)
|
|
23
|
-
return t("dms_ai.panel.full_auto.banner_until", {
|
|
24
|
-
time: formatClock(Math.max(0, untilMs - props.nowMs)),
|
|
25
|
-
});
|
|
26
|
-
return t(`dms_ai.panel.full_auto.banner_${duration}`);
|
|
27
|
-
});
|
|
28
|
-
</script>
|
|
29
|
-
|
|
30
|
-
<template>
|
|
31
|
-
<div class="cb-banner-auto" role="status">
|
|
32
|
-
<UIcon name="i-ph-lightning" class="cb-banner-auto__icon" />
|
|
33
|
-
<span class="cb-banner-auto__text">
|
|
34
|
-
<b>{{ t("dms_ai.common.mode.auto") }}</b>
|
|
35
|
-
· {{ scope }}
|
|
36
|
-
</span>
|
|
37
|
-
<UButton
|
|
38
|
-
size="xs"
|
|
39
|
-
color="neutral"
|
|
40
|
-
variant="outline"
|
|
41
|
-
:label="t('dms_ai.panel.full_auto.turn_off')"
|
|
42
|
-
@click="emit('turnOff')"
|
|
43
|
-
/>
|
|
44
|
-
</div>
|
|
45
|
-
</template>
|
|
46
|
-
|
|
47
|
-
<style scoped>
|
|
48
|
-
.cb-banner-auto {
|
|
49
|
-
display: flex;
|
|
50
|
-
flex: none;
|
|
51
|
-
align-items: center;
|
|
52
|
-
gap: 8px;
|
|
53
|
-
padding: 8px 10px 8px 14px;
|
|
54
|
-
border-bottom: 1px solid var(--dms-error-line);
|
|
55
|
-
background: var(--dms-error-tint);
|
|
56
|
-
font-size: 12.5px;
|
|
57
|
-
color: var(--ui-text-toned);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.cb-banner-auto__icon {
|
|
61
|
-
width: 15px;
|
|
62
|
-
height: 15px;
|
|
63
|
-
flex: none;
|
|
64
|
-
color: var(--ui-error);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.cb-banner-auto__text {
|
|
68
|
-
flex: 1;
|
|
69
|
-
min-width: 0;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.cb-banner-auto__text b {
|
|
73
|
-
font-weight: 600;
|
|
74
|
-
color: var(--ui-text-highlighted);
|
|
75
|
-
}
|
|
76
|
-
</style>
|