@altertable/data-app 0.65.0 → 0.67.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/AGENTS.md +38 -1
- package/CONTRIBUTING.md +54 -14
- package/README.md +1 -1
- package/dist/chunks/index-23dktynd.js +80 -0
- package/dist/chunks/index-23dktynd.js.map +10 -0
- package/dist/chunks/index-8qfxv0h5.js +14160 -0
- package/dist/chunks/index-8qfxv0h5.js.map +108 -0
- package/dist/chunks/index-ag0cgnvq.js +639 -0
- package/dist/chunks/index-ag0cgnvq.js.map +13 -0
- package/dist/chunks/index-dq7b35fn.js +307 -0
- package/dist/chunks/index-dq7b35fn.js.map +13 -0
- package/dist/chunks/{contract-a061yj6r.js → index-ev2b5aaf.js} +41 -72
- package/dist/chunks/index-ev2b5aaf.js.map +12 -0
- package/dist/chunks/{contract-awa2d5b1.js → index-f5cnbrjz.js} +19 -2
- package/dist/chunks/{contract-awa2d5b1.js.map → index-f5cnbrjz.js.map} +4 -3
- package/dist/chunks/{contract-sm7j7k95.js → index-ktmvs916.js} +9 -150
- package/dist/chunks/index-ktmvs916.js.map +13 -0
- package/dist/chunks/{contract-txjy0en2.js → index-m6n8ctfc.js} +64 -72
- package/dist/chunks/index-m6n8ctfc.js.map +10 -0
- package/dist/chunks/index-mt93ff2b.js +28 -0
- package/dist/chunks/index-mt93ff2b.js.map +10 -0
- package/dist/chunks/{contract-tf8c3qpv.js → index-qd5xgx6y.js} +46 -5
- package/dist/chunks/index-qd5xgx6y.js.map +13 -0
- package/dist/chunks/index-x69p7cv7.js +149 -0
- package/dist/chunks/index-x69p7cv7.js.map +10 -0
- package/dist/client/index.js +12 -7
- package/dist/client/index.js.map +1 -1
- package/dist/core/appearance.js +1 -1
- package/dist/core/config.js +7 -3
- package/dist/core/config.js.map +1 -1
- package/dist/core/contract.js +24 -6
- package/dist/core/contract.js.map +1 -1
- package/dist/core/format.js +1 -1
- package/dist/embed/index.js +16 -12
- package/dist/embed/index.js.map +4 -4
- package/dist/index.js +12 -0
- package/dist/index.js.map +9 -0
- package/dist/local.js +20 -30
- package/dist/local.js.map +7 -8
- package/dist/react/embed/index.js +1 -1
- package/dist/react/embed/index.js.map +2 -2
- package/dist/react/index.js +2567 -11542
- package/dist/react/index.js.map +16 -91
- package/dist/react/ui/index.js +2272 -0
- package/dist/react/ui/index.js.map +28 -0
- package/dist/server.js +13 -26
- package/dist/server.js.map +6 -7
- package/dist/types/client/annotations.d.ts +27 -0
- package/dist/types/client/data-client.d.ts +1 -2
- package/dist/types/client/iframe.d.ts +4 -2
- package/dist/types/client/index.d.ts +1 -0
- package/dist/types/core/annotations.d.ts +94 -0
- package/dist/types/core/appearance.d.ts +2 -2
- package/dist/types/core/config.d.ts +48 -4
- package/dist/types/core/contract.d.ts +21 -11
- package/dist/types/core/dimension.d.ts +6 -4
- package/dist/types/core/filters.d.ts +44 -0
- package/dist/types/core/messages.d.ts +2 -0
- package/dist/types/core/operation-types.d.ts +5 -2
- package/dist/types/core/operation.d.ts +3 -4
- package/dist/types/core/presentation.d.ts +2 -0
- package/dist/types/core/queries.d.ts +16 -0
- package/dist/types/core/uuid.d.ts +2 -0
- package/dist/types/core/variables.d.ts +34 -18
- package/dist/types/embed/runtime-html.d.ts +2 -0
- package/dist/types/embed/source.d.ts +2 -1
- package/dist/types/index.d.ts +3 -0
- package/dist/types/react/annotations/AnnotationBar.d.ts +30 -0
- package/dist/types/react/annotations/AnnotationControls.d.ts +10 -0
- package/dist/types/react/annotations/AnnotationEditor.d.ts +16 -0
- package/dist/types/react/annotations/AnnotationMarkers.d.ts +19 -0
- package/dist/types/react/annotations/AnnotationSelectionLayer.d.ts +12 -0
- package/dist/types/react/annotations/AnnotationTarget.d.ts +9 -0
- package/dist/types/react/annotations/AnnotationTooltip.d.ts +9 -0
- package/dist/types/react/annotations/AnnotationTrigger.d.ts +10 -0
- package/dist/types/react/annotations/annotation-editor-state.d.ts +56 -0
- package/dist/types/react/annotations/annotation-screenshot.d.ts +4 -0
- package/dist/types/react/annotations/annotation-targets.d.ts +33 -0
- package/dist/types/react/annotations/getAnnotationProps.d.ts +15 -0
- package/dist/types/react/annotations/styles.d.ts +3 -0
- package/dist/types/react/annotations/useAnnotationGeometry.d.ts +22 -0
- package/dist/types/react/annotations/useDataAppAnnotations.d.ts +22 -0
- package/dist/types/react/app-context.d.ts +3 -0
- package/dist/types/react/bindings.d.ts +110 -0
- package/dist/types/react/content.d.ts +24 -11
- package/dist/types/react/hooks.d.ts +29 -787
- package/dist/types/react/index.d.ts +31 -106
- package/dist/types/react/mount.d.ts +6 -4
- package/dist/types/react/source-owner.d.ts +2 -0
- package/dist/types/react/style-contract.d.ts +80 -0
- package/dist/types/react/style-validation.d.ts +2 -0
- package/dist/types/react/ui/AboutData.d.ts +9 -1
- package/dist/types/react/ui/AppHeader.d.ts +1 -2
- package/dist/types/react/ui/AppLayout.d.ts +3 -9
- package/dist/types/react/ui/AppToolbar.d.ts +5 -8
- package/dist/types/react/ui/AreaChart.d.ts +7 -0
- package/dist/types/react/ui/BarChart.d.ts +6 -0
- package/dist/types/react/ui/Button.d.ts +3 -3
- package/dist/types/react/ui/ChartLegend.d.ts +31 -0
- package/dist/types/react/ui/Checkbox.d.ts +15 -4
- package/dist/types/react/ui/CheckboxGroup.d.ts +7 -0
- package/dist/types/react/ui/{Combobox.d.ts → ChoicePicker.d.ts} +10 -15
- package/dist/types/react/ui/{ComparisonVisual.d.ts → Comparison.d.ts} +3 -3
- package/dist/types/react/ui/ComposedChart.d.ts +41 -0
- package/dist/types/react/ui/ComposedChartLegend.d.ts +8 -0
- package/dist/types/react/ui/ContentSkeleton.d.ts +2 -0
- package/dist/types/react/ui/DataApp.d.ts +17 -58
- package/dist/types/react/ui/DataAppFrame.d.ts +41 -0
- package/dist/types/react/ui/DataBoundary.d.ts +4 -5
- package/dist/types/react/ui/DataSection.d.ts +6 -18
- package/dist/types/react/ui/DataSectionBoundary.d.ts +30 -0
- package/dist/types/react/ui/DataValue.d.ts +9 -0
- package/dist/types/react/ui/DataWidget.d.ts +2 -1
- package/dist/types/react/ui/DateTimeTooltip.d.ts +1 -1
- package/dist/types/react/ui/DimensionPicker.d.ts +1 -1
- package/dist/types/react/ui/ExportControl.d.ts +1 -1
- package/dist/types/react/ui/FilterActions.d.ts +10 -0
- package/dist/types/react/ui/FilterBar.d.ts +3 -0
- package/dist/types/react/ui/GettingStarted.d.ts +2 -4
- package/dist/types/react/ui/HelpPopover.d.ts +3 -4
- package/dist/types/react/ui/InspectionContext.d.ts +2 -0
- package/dist/types/react/ui/InspectionProvider.d.ts +29 -0
- package/dist/types/react/ui/LineChart.d.ts +7 -0
- package/dist/types/react/ui/Menu.d.ts +12 -0
- package/dist/types/react/ui/MetricWidget.d.ts +4 -3
- package/dist/types/react/ui/NumberField.d.ts +27 -0
- package/dist/types/react/ui/NumberFilterPicker.d.ts +9 -0
- package/dist/types/react/ui/PieChart.d.ts +11 -0
- package/dist/types/react/ui/PresentStory.d.ts +2 -5
- package/dist/types/react/ui/RadioGroup.d.ts +18 -0
- package/dist/types/react/ui/RefreshControl.d.ts +1 -2
- package/dist/types/react/ui/ScatterChart.d.ts +17 -0
- package/dist/types/react/ui/SearchField.d.ts +1 -2
- package/dist/types/react/ui/SearchInput.d.ts +3 -1
- package/dist/types/react/ui/Select.d.ts +14 -0
- package/dist/types/react/ui/SelectionMark.d.ts +2 -1
- package/dist/types/react/ui/Sheet.d.ts +2 -1
- package/dist/types/react/ui/Skeleton.d.ts +5 -2
- package/dist/types/react/ui/StaticDataApp.d.ts +4 -0
- package/dist/types/react/ui/TableWidget.d.ts +19 -16
- package/dist/types/react/ui/Tabs.d.ts +6 -2
- package/dist/types/react/ui/TextWidget.d.ts +2 -1
- package/dist/types/react/ui/Tooltip.d.ts +4 -3
- package/dist/types/react/ui/TooltipSurface.d.ts +3 -0
- package/dist/types/react/ui/TrendChart.d.ts +5 -0
- package/dist/types/react/ui/UpdatedAt.d.ts +1 -1
- package/dist/types/react/ui/VisualizationWidget.d.ts +12 -13
- package/dist/types/react/ui/WidgetViewTabs.d.ts +1 -1
- package/dist/types/react/ui/chart-data.d.ts +25 -0
- package/dist/types/react/ui/chart-primitives.d.ts +20 -0
- package/dist/types/react/ui/data-context.d.ts +18 -7
- package/dist/types/react/ui/icons.d.ts +2 -0
- package/dist/types/react/ui/index.d.ts +98 -0
- package/dist/types/react/ui/keyboard.d.ts +6 -0
- package/dist/types/react/ui/metric.d.ts +1 -1
- package/dist/types/react/ui/presentation.d.ts +5 -1
- package/dist/types/react/ui/shortcuts.d.ts +14 -1
- package/dist/types/react/ui/useAppAppearance.d.ts +1 -1
- package/dist/types/react/ui/variables.d.ts +4 -2
- package/dist/types/react/view-controls.d.ts +3 -1
- package/dist/types/react/view-runtime.d.ts +29 -0
- package/dist/types/react/view.d.ts +21 -4
- package/dist/types/react/widgets.d.ts +79 -0
- package/dist/types/server/handler.d.ts +4 -4
- package/dist/worker.js +20 -737
- package/docs/app-authoring.md +72 -50
- package/docs/client.md +8 -8
- package/docs/contract.md +42 -20
- package/docs/data-context.md +91 -0
- package/docs/embed.md +10 -2
- package/docs/formatting-and-appearance.md +68 -0
- package/docs/hosted-apps.md +9 -15
- package/docs/layout.md +5 -3
- package/docs/react-embed.md +5 -4
- package/docs/react.md +22 -317
- package/docs/server-bun.md +1 -1
- package/docs/server.md +4 -4
- package/docs/stories-and-export.md +52 -0
- package/docs/styling.md +62 -0
- package/docs/ui-quality.md +20 -0
- package/docs/ui.md +196 -0
- package/docs/variables.md +171 -0
- package/docs/views.md +123 -0
- package/docs/widgets.md +145 -0
- package/examples/starter-data-app/index.tsx +115 -86
- package/package.json +25 -12
- package/dist/chunks/contract-a061yj6r.js.map +0 -12
- package/dist/chunks/contract-g6hky7x6.js +0 -282
- package/dist/chunks/contract-g6hky7x6.js.map +0 -12
- package/dist/chunks/contract-sm7j7k95.js.map +0 -14
- package/dist/chunks/contract-tf8c3qpv.js.map +0 -11
- package/dist/chunks/contract-txjy0en2.js.map +0 -10
- package/dist/chunks/contract-wz59z8pq.js +0 -8
- package/dist/chunks/contract-wz59z8pq.js.map +0 -10
- package/dist/chunks/contract-yxbjea23.js +0 -328
- package/dist/chunks/contract-yxbjea23.js.map +0 -12
- package/dist/types/react/ui/RefreshRegion.d.ts +0 -9
- package/dist/types/react/ui/SelectableBarChart.d.ts +0 -15
- package/docs/releasing.md +0 -79
- /package/dist/chunks/{contract-mev09s5v.js → index-mev09s5v.js} +0 -0
- /package/dist/chunks/{contract-mev09s5v.js.map → index-mev09s5v.js.map} +0 -0
- /package/dist/types/react/ui/{comparison.d.ts → metric-comparison.d.ts} +0 -0
package/docs/app-authoring.md
CHANGED
|
@@ -7,6 +7,13 @@ queries, definitions, and evidence.
|
|
|
7
7
|
|
|
8
8
|
## Inspect the data
|
|
9
9
|
|
|
10
|
+
Declare the query source of truth with `defineDataApp()`. Generate
|
|
11
|
+
operations with `dataApp.defineOperation()` and execute queries by
|
|
12
|
+
name with parameter values. When a query registry is supplied, use only its queries
|
|
13
|
+
and preserve its SQL. Otherwise, inspect the data and declare the queries the app needs.
|
|
14
|
+
Derive displays, exports, and findings from their results. See
|
|
15
|
+
[named queries](contract.md#execute-named-queries).
|
|
16
|
+
|
|
10
17
|
Inspect the relevant catalogs, tables, and fields, their time coverage, and
|
|
11
18
|
existing definitions. Choose a question the available data can answer.
|
|
12
19
|
|
|
@@ -21,69 +28,84 @@ Choose the execution path:
|
|
|
21
28
|
|
|
22
29
|
Lead with a supported finding and expose the relevant fields as filter variables. Use a date filter for questions worth exploring over time,
|
|
23
30
|
or a fixed period snapshot for a deliberate historical analysis.
|
|
31
|
+
|
|
32
|
+
Use relevant user-controlled query parameters as app filters. Map filter values to
|
|
33
|
+
declared parameters through operation inputs, and reuse query defaults when they
|
|
34
|
+
match the initial selection. One filter may supply several parameters, such as a
|
|
35
|
+
date range supplying `start` and `end`. Keep protected parameters, such as `orgId`,
|
|
36
|
+
and internal execution settings out of filter controls.
|
|
37
|
+
|
|
24
38
|
Register inspected tables and fields with `defineDataIdentifiers()` and use
|
|
25
39
|
`<DataIdentifier>` when naming sources. Register terms and query evidence so
|
|
26
40
|
readers can inspect the source of each claim.
|
|
27
41
|
|
|
28
42
|
Connect visualizations with introductions and explanations. Use `<TextWidget>`
|
|
29
43
|
for a narrative panel with the standard widget frame, or `<TextContent>` for
|
|
30
|
-
borderless prose.
|
|
31
|
-
|
|
32
|
-
and
|
|
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
|
-
and
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
44
|
+
borderless prose. Render the app title, description, and instructions immediately. Use metric and dataset
|
|
45
|
+
bindings for dynamic values and `<DataValue>` for values within static prose.
|
|
46
|
+
Skeletonize only the content that needs data. Reuse bindings and the displayed
|
|
47
|
+
source in narrative so values, formatting, and evidence follow filter changes,
|
|
48
|
+
refresh, and failure.
|
|
49
|
+
|
|
50
|
+
| Task | Documentation |
|
|
51
|
+
| ------------------------------------------------ | ----------------------------------------------------------------- |
|
|
52
|
+
| Choose components, CSS tokens, and styling hooks | [Styling](styling.md) |
|
|
53
|
+
| Define queries, inputs, and result parsing | [Operations](contract.md) |
|
|
54
|
+
| Build views, filters, and request states | [Views](views.md) |
|
|
55
|
+
| Introduce and explain visualizations | [Narrative text](widgets.md#narrative-text) |
|
|
56
|
+
| Find formatters and presentation helpers | [App helpers](formatting-and-appearance.md) |
|
|
57
|
+
| Register source names | [Source identifiers](data-context.md#register-source-identifiers) |
|
|
58
|
+
| Choose date and field filters | [Filter variables](variables.md) |
|
|
59
|
+
| Handle refresh and stale results | [Displayed results](views.md#preserve-displayed-results) |
|
|
60
|
+
| Export displayed data as CSV | [CSV export](stories-and-export.md#export-displayed-data-as-csv) |
|
|
61
|
+
| Render widgets and custom visuals | [Widgets](widgets.md) |
|
|
62
|
+
| Bind definitions and source evidence | [Data context](data-context.md#bind-evidence) |
|
|
63
|
+
|
|
64
|
+
Declare reusable [datasets and metrics](widgets.md#declare-datasets-and-metrics)
|
|
65
|
+
on the view so tables, exports, and stories share values and evidence.
|
|
66
|
+
|
|
67
|
+
Every data app supplies a [story and CSV export](stories-and-export.md)
|
|
68
|
+
from the displayed result. Export all distinct datasets at their displayed grain;
|
|
69
|
+
reuse a dataset when several visuals derive from the same rows. Present the
|
|
70
|
+
findings that answer the reader's question, rather than every row or chart.
|
|
71
|
+
Use the [standard layout](layout.md) and built-in toolbar actions.
|
|
72
|
+
|
|
73
|
+
### Organize the exploration
|
|
74
|
+
|
|
75
|
+
Use sections for a focused question and for findings readers should compare
|
|
76
|
+
side by side. Add app-level `<Tabs>` from `/react/ui` when the exploration has
|
|
77
|
+
distinct analytical questions, such as Overview, Retention, and Segments, each
|
|
78
|
+
with its own context and group of widgets. Lead with the most useful overview
|
|
79
|
+
and label tabs by the question or subject they explore.
|
|
80
|
+
|
|
81
|
+
Use `<VisualizationWidget>`'s `views` for alternate representations of the same
|
|
82
|
+
dataset, such as a chart and its rows. Keep these choices within the widget;
|
|
83
|
+
use filter variables when the reader is changing the data scope.
|
|
84
|
+
|
|
85
|
+
Navigation tabs, widget views, and declared data views have different roles.
|
|
86
|
+
A declared view owns inputs, requests, and displayed results; a tab does not
|
|
87
|
+
require a separate data view. Keep related datasets in one view for a coherent
|
|
88
|
+
snapshot. Use independent views and `<DataSection>` boundaries when content
|
|
89
|
+
needs separate requests. Keep filter placement consistent across tabs and make
|
|
90
|
+
each filter's scope clear. Derive findings, story, and export from the displayed
|
|
91
|
+
results and their inputs.
|
|
92
|
+
|
|
93
|
+
Choose each visual for the question it answers; see
|
|
94
|
+
[visualization selection](widgets.md#choose-a-visualization).
|
|
75
95
|
|
|
76
96
|
## Verify the app
|
|
77
97
|
|
|
98
|
+
Follow the [UI quality contract](ui-quality.md) for hierarchy, responsive
|
|
99
|
+
composition, typography, and control states.
|
|
100
|
+
|
|
78
101
|
Verify findings against the source and the user's question. Distinguish measured
|
|
79
102
|
zero, unavailable values, and empty results. Check filters, refresh, loading,
|
|
80
103
|
empty, error, and stale states, then present the story. Download CSV from the
|
|
81
104
|
standalone and embedded toolbar and verify its filename, columns, raw values,
|
|
82
105
|
and filter scope against the displayed result. Export and Present story must be
|
|
83
|
-
available once
|
|
84
|
-
errors
|
|
106
|
+
available once results are shown; initial loading, empty, and initial
|
|
107
|
+
errors keep both actions visible and disabled. Inspect both experiences
|
|
85
108
|
at phone and desktop widths in light and dark themes.
|
|
86
109
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
stay backend-owned. Edit app-owned files; installed package files are dependencies.
|
|
110
|
+
Keep credentials, authorization, and enforced query limits in the host/backend.
|
|
111
|
+
Edit app-owned files; installed package files are dependencies.
|
package/docs/client.md
CHANGED
|
@@ -15,8 +15,9 @@ const response = await client.query('activity', input, { signal });
|
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
The app defines `operations`, `input`, and an optional cancellation `signal`.
|
|
18
|
-
Operation input and output types are inferred from the server
|
|
19
|
-
|
|
18
|
+
Operation input and output types are inferred from the server operation map. Keep the
|
|
19
|
+
server operation map import type-only so its implementations stay on the server.
|
|
20
|
+
The shared app declaration contains the query registry and is browser-safe.
|
|
20
21
|
|
|
21
22
|
The default endpoint is `/api/data`. Override it with
|
|
22
23
|
`createDataClient({ endpoint, fetch })` to change the base URL or supply a Fetch
|
|
@@ -24,8 +25,7 @@ implementation. Calls POST JSON to `/api/data/:operation`; the client sends
|
|
|
24
25
|
operation inputs rather than SQL or credentials.
|
|
25
26
|
|
|
26
27
|
`DataResponse` contains `data`, the exact request `input`, `requestId`,
|
|
27
|
-
`queriedAt`,
|
|
28
|
-
and the execution runtime permits disclosure. Use the returned input when labeling stale data during a refresh.
|
|
28
|
+
`queriedAt`, `queryIds`, and executed `queries`. Use the returned input when labeling stale data during a refresh.
|
|
29
29
|
HTTP and iframe delivery validate the same success envelope: data, request ID,
|
|
30
30
|
query timestamp, query IDs, and optional query evidence. Malformed responses
|
|
31
31
|
reject with `invalid_response`.
|
|
@@ -46,17 +46,17 @@ Bundle apps pass their operation registry as a value:
|
|
|
46
46
|
import { connectionCheck } from '@altertable/data-app/contract';
|
|
47
47
|
import { createDataClient } from '@altertable/data-app/client';
|
|
48
48
|
|
|
49
|
+
// dataApp declares a connection query.
|
|
49
50
|
const client = createDataClient({
|
|
50
|
-
operations: { connection: connectionCheck() },
|
|
51
|
+
operations: { connection: connectionCheck(dataApp.queries) },
|
|
51
52
|
});
|
|
52
53
|
const response = await client.query('connection', {});
|
|
53
54
|
```
|
|
54
55
|
|
|
55
56
|
The client runs input parsing, operation logic, and output parsing in the browser.
|
|
56
|
-
Operation policy bounds rows, duration, and response size and records query evidence. Each query sends `{ statement, limit }`
|
|
57
|
+
Operation policy bounds rows, duration, and response size and records query evidence. Each query sends `{ statement, limit, params? }`
|
|
57
58
|
to the installed iframe bridge's `data:sql` route; the host needs no operation
|
|
58
|
-
registry.
|
|
59
|
-
only controls evidence in the returned response. Credentials remain backend-owned.
|
|
59
|
+
registry. Results include query evidence. Credentials remain backend-owned.
|
|
60
60
|
|
|
61
61
|
The trusted bootstrap installs the bridge for bundle apps. A custom runtime must
|
|
62
62
|
install it before querying. An explicit `lakehouse` can supply another authorized
|
package/docs/contract.md
CHANGED
|
@@ -2,35 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
Import operation definitions, parsers, and shared types from
|
|
4
4
|
`@altertable/data-app/contract`. This entry is safe to import in browser and server
|
|
5
|
-
modules.
|
|
6
|
-
|
|
5
|
+
modules. The app declaration is browser-safe and includes its SQL registry. For HTTP apps,
|
|
6
|
+
keep operation implementations, credentials, and authorization on the server; browser modules
|
|
7
|
+
import operation types using `import type`.
|
|
7
8
|
|
|
8
9
|
## Execute named queries
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
Declare SQL once with `defineDataApp()` to preserve exact query and parameter
|
|
12
|
+
names. Use stable `lowerCamelCase` IDs describing the result, such as `products`,
|
|
13
|
+
`productsByCategory`, or `dailyRevenue`. Use plural names for row lists; keep parameter
|
|
14
|
+
values in `params`.
|
|
15
|
+
The app owns an immutable registry snapshot. Define operations with
|
|
16
|
+
`dataApp.defineOperation()`.
|
|
12
17
|
|
|
13
18
|
```ts
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
import { defineDataApp } from '@altertable/data-app';
|
|
20
|
+
import { rowsAsRecords } from '@altertable/data-app/contract';
|
|
21
|
+
|
|
22
|
+
const dataApp = defineDataApp({
|
|
23
|
+
title: 'Products',
|
|
24
|
+
description: 'Explore products for the selected organization.',
|
|
25
|
+
scope: { organization: 'demo', environment: 'production' },
|
|
26
|
+
appearance: { theme: 'system' },
|
|
27
|
+
queries: {
|
|
28
|
+
products: {
|
|
29
|
+
statement: 'SELECT * FROM products WHERE org_id = $orgId LIMIT $limit',
|
|
30
|
+
params: { orgId: {}, limit: { defaultValue: 10 } },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
});
|
|
18
34
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
checks: [checkInput],
|
|
25
|
-
policy: { maxQueryRows: 100, maxDurationMs: 15000, exposeSql: true },
|
|
35
|
+
const products = dataApp.defineOperation({
|
|
36
|
+
input: parseProductInput,
|
|
37
|
+
output: parseProducts,
|
|
38
|
+
checks: [{}],
|
|
39
|
+
policy: { maxQueryRows: 100, maxDurationMs: 15000 },
|
|
26
40
|
async run({ query }, input) {
|
|
27
|
-
const result = await query(
|
|
28
|
-
return
|
|
41
|
+
const result = await query('products', input);
|
|
42
|
+
return rowsAsRecords(result, ['org_id']);
|
|
29
43
|
},
|
|
30
44
|
});
|
|
31
45
|
```
|
|
32
46
|
|
|
33
|
-
`
|
|
47
|
+
`parseProductInput()` and `parseProducts()` are app-owned example functions, not
|
|
48
|
+
package exports. Validate
|
|
49
|
+
filter values in the input parser. `{}` declares a required parameter; `{ defaultValue }` supplies
|
|
50
|
+
a fallback. `query(name, params, { limit })` executes only registered queries and
|
|
51
|
+
inherits the operation's row limit and cancellation signal.
|
|
52
|
+
|
|
53
|
+
SQL and resolved parameter values pass unchanged to the backend. Results include
|
|
54
|
+
query evidence; use `products.queryNames` with `createDataContext()` to bind it.
|
|
55
|
+
For HTTP apps, authorization can supply protected `queryParams`, such as `orgId`.
|
|
56
|
+
The host/backend enforces data access and limits.
|
|
34
57
|
|
|
35
58
|
## Shared date ranges
|
|
36
59
|
|
|
@@ -50,8 +73,7 @@ export const calendar = defineDateRangeContract({
|
|
|
50
73
|
```
|
|
51
74
|
|
|
52
75
|
`parseEmptyInput()`, `parseTrue()`, `parseCount()`, and `parseDateRangeInput()` validate
|
|
53
|
-
common inputs and results. `connectionCheck()`
|
|
54
|
-
operation. A successful connectivity check confirms access; it is not an
|
|
76
|
+
common inputs and results. `connectionCheck(dataApp.queries)` runs the registered `connection` query. A successful connectivity check confirms access; it is not an
|
|
55
77
|
analysis result.
|
|
56
78
|
|
|
57
79
|
See [server authorization](server.md) and [React views](react.md) for the two
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Data context and evidence
|
|
2
|
+
|
|
3
|
+
Set `dataContext: context` in each view for source descriptions, glossary, and
|
|
4
|
+
permitted query evidence. App inspection and the view's sections use that context.
|
|
5
|
+
Render registered identifiers where `<DataIdentifier>` is used.
|
|
6
|
+
|
|
7
|
+
Physical source identifiers name inspected tables and columns. Glossary entries
|
|
8
|
+
explain business meaning. Query names link those definitions and displayed claims
|
|
9
|
+
to their execution evidence. Keep all three explicit.
|
|
10
|
+
|
|
11
|
+
## Register source identifiers
|
|
12
|
+
|
|
13
|
+
Use `defineDataIdentifiers()` from `/react` to register exact catalog, schema,
|
|
14
|
+
table, and field names. Use `<DataIdentifier>` in descriptions and glossary
|
|
15
|
+
entries to render those source references consistently.
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { defineDataIdentifiers } from '@altertable/data-app/react';
|
|
19
|
+
|
|
20
|
+
const identifiers = defineDataIdentifiers({
|
|
21
|
+
tables: {
|
|
22
|
+
events: {
|
|
23
|
+
catalog: 'product_analytics',
|
|
24
|
+
schema: 'analytics',
|
|
25
|
+
name: 'events',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
columns: { identity: { table: 'events', name: 'identity_uuid' } },
|
|
29
|
+
});
|
|
30
|
+
const { DataIdentifier } = identifiers;
|
|
31
|
+
|
|
32
|
+
<DataIdentifier id="tables.events" />;
|
|
33
|
+
<DataIdentifier id="columns.events.identity" />;
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Pass `identifiers.definitions` to `createDataContext()` to reuse the source
|
|
37
|
+
registry.
|
|
38
|
+
|
|
39
|
+
## Bind evidence
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
const queries = activity.queryNames;
|
|
43
|
+
const context = createDataContext(queries)({
|
|
44
|
+
identifiers: identifiers.definitions,
|
|
45
|
+
description: (
|
|
46
|
+
<>
|
|
47
|
+
Explore activity in <DataIdentifier id="tables.events" />.
|
|
48
|
+
</>
|
|
49
|
+
),
|
|
50
|
+
glossary: {
|
|
51
|
+
identities: {
|
|
52
|
+
term: 'Tracked identities',
|
|
53
|
+
definition: (
|
|
54
|
+
<>
|
|
55
|
+
Distinct <DataIdentifier id="columns.events.identity" /> values.
|
|
56
|
+
</>
|
|
57
|
+
),
|
|
58
|
+
queryNames: [queries.activity],
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
const evidence = context.evidence({
|
|
63
|
+
id: 'identities',
|
|
64
|
+
glossaryIds: ['identities'],
|
|
65
|
+
queryNames: [queries.activity],
|
|
66
|
+
});
|
|
67
|
+
// activityView is declared with dataContext: context.
|
|
68
|
+
const trackedIdentities = activityView.metric(
|
|
69
|
+
{
|
|
70
|
+
id: 'identities',
|
|
71
|
+
glossaryId: 'identities',
|
|
72
|
+
format: { kind: 'count', compact: true },
|
|
73
|
+
},
|
|
74
|
+
data => ({ current: data.count })
|
|
75
|
+
);
|
|
76
|
+
const finding = context.finding({
|
|
77
|
+
id: 'activity',
|
|
78
|
+
headline: 'What people do',
|
|
79
|
+
visual: <ActivityChart />,
|
|
80
|
+
evidence: { id: 'activity-evidence', queryNames: [queries.activity] },
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Query inspection shows the executed SQL and resolved parameters; copy actions include both.
|
|
85
|
+
|
|
86
|
+
Import context and identifier factories from `/react`. Use the operation’s derived `queryNames` for evidence.
|
|
87
|
+
|
|
88
|
+
Use `view.metric(definition, select)` to register and bind a metric in one call.
|
|
89
|
+
Declare dataset evidence references inside `view.dataset()`; the view registers
|
|
90
|
+
and validates them too.
|
|
91
|
+
Widgets and stories share its values and evidence; see [datasets and metrics](widgets.md#declare-datasets-and-metrics).
|
package/docs/embed.md
CHANGED
|
@@ -31,11 +31,18 @@ A bundle source has this shape:
|
|
|
31
31
|
```ts
|
|
32
32
|
const source = {
|
|
33
33
|
type: 'bundle' as const,
|
|
34
|
-
bootstrapUrl: 'https://my-report-app-1.apps.example.net/',
|
|
35
34
|
javascript: bundle.javascript,
|
|
36
35
|
};
|
|
37
36
|
```
|
|
38
37
|
|
|
38
|
+
Omit `bootstrapUrl` to load the SDK's packaged bootstrap as a `data:` document.
|
|
39
|
+
This supports MCP hosts that permit opaque child frames but block remote frame
|
|
40
|
+
URLs. The SDK embeds the exact host origin and applies a CSP that prohibits
|
|
41
|
+
direct network access. Data requests go through the host's dispatcher.
|
|
42
|
+
|
|
43
|
+
Supply an HTTP(S) `bootstrapUrl` to use an externally served trusted bootstrap,
|
|
44
|
+
such as the [Worker asset](worker.md).
|
|
45
|
+
|
|
39
46
|
The host provides a self-contained JavaScript bundle. React bridges replace the
|
|
40
47
|
iframe whenever its JavaScript content changes. Serve the bootstrap page with a CSP compatible with the bundle.
|
|
41
48
|
Bundle mode uses `sandbox="allow-scripts"` and an opaque origin; it cannot read
|
|
@@ -129,7 +136,8 @@ as public `source_*` errors with request IDs. Authorization failures return
|
|
|
129
136
|
public failures with `MessageRoutingError`.
|
|
130
137
|
|
|
131
138
|
`SqlQueryInput` (exported from `/contract`) carries
|
|
132
|
-
`{ statement: string, limit: number }`;
|
|
139
|
+
`{ statement: string, limit: number, params?: QueryParameters }`; the backend
|
|
140
|
+
interprets the unchanged statement and parameter values. Responses are
|
|
133
141
|
`{ columns: { name: string, type?: string }[], rows: unknown[][], queryId?: string }`.
|
|
134
142
|
The route rejects empty statements, unsafe or nonpositive limits, malformed
|
|
135
143
|
results, and results exceeding the requested limit. The bridge's existing payload
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Formatting and appearance
|
|
2
|
+
|
|
3
|
+
Use package helpers so a value has the same meaning in prose, tables, charts,
|
|
4
|
+
and stories. TypeScript and JSDoc describe options and supported values.
|
|
5
|
+
|
|
6
|
+
## Format values
|
|
7
|
+
|
|
8
|
+
Import formatting helpers from `@altertable/data-app/format`.
|
|
9
|
+
|
|
10
|
+
| Helper | Use |
|
|
11
|
+
| ------------------- | ------------------------------------------------------ |
|
|
12
|
+
| `formatNumber()` | General numerical values |
|
|
13
|
+
| `formatCount()` | Nonnegative integer counts, optionally compact |
|
|
14
|
+
| `formatPercent()` | Ratios represented as a fraction, such as 0.12 for 12% |
|
|
15
|
+
| `formatMetric()` | A metric definition's count, ratio, or currency format |
|
|
16
|
+
| `formatDateRange()` | Inclusive calendar ranges |
|
|
17
|
+
| `pluralize()` | Count-dependent labels |
|
|
18
|
+
|
|
19
|
+
Missing values render distinctly from measured zero. Declare formatting once on
|
|
20
|
+
`view.metric()` so widgets, comparisons, and narrative share it; reuse the
|
|
21
|
+
definition with `formatMetric()` in story headlines.
|
|
22
|
+
|
|
23
|
+
Use compact counts for headline metrics and chart labels. Declare count metrics
|
|
24
|
+
with `format: { kind: 'count', compact: true }`. Keep full counts in tables used
|
|
25
|
+
for precise comparisons and raw numeric values in datasets for CSV export.
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
formatCount(2_200_000, { compact: true }); // "2.2M"
|
|
29
|
+
formatCount(2_200_000); // "2,200,000"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
For signed or fractional measures, use `formatNumber()` with
|
|
33
|
+
`notation: 'compact'` and preserve the measure's units.
|
|
34
|
+
|
|
35
|
+
Import `chartColor()` from `/react` to select colors from the configured palette.
|
|
36
|
+
`<PeriodSummary>` describes reporting periods; `<UpdatedAt>` and
|
|
37
|
+
`<DateTimeTooltip>` expose readable timestamps with exact-date details.
|
|
38
|
+
`<DataTableTimestamp>` and `<DataTableShare>` format custom table cells.
|
|
39
|
+
|
|
40
|
+
## Configure identity and appearance
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { defineDataApp } from '@altertable/data-app';
|
|
44
|
+
|
|
45
|
+
const dataApp = defineDataApp({
|
|
46
|
+
title: 'Product activity',
|
|
47
|
+
description: 'Explore product usage and trends.',
|
|
48
|
+
scope: { organization: 'Acme', environment: 'Production' },
|
|
49
|
+
appearance: {
|
|
50
|
+
theme: 'system',
|
|
51
|
+
accentColor: '#405d47',
|
|
52
|
+
density: 'comfortable',
|
|
53
|
+
},
|
|
54
|
+
queries: {},
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Scope labels describe the configured connection; they do not grant access.
|
|
59
|
+
`dataAppTitle()` produces the scoped document title used by `mountDataApp()`.
|
|
60
|
+
|
|
61
|
+
Title and description explain the app and can be revised when regenerating it.
|
|
62
|
+
Omit appearance to use the standard defaults.
|
|
63
|
+
|
|
64
|
+
Appearance controls the brand palette, typography, density, corner radius, and
|
|
65
|
+
elevation. Those settings apply consistently to the app instead of tuning each
|
|
66
|
+
widget. Theme preference is reader-owned in standalone apps. A trusted parent's
|
|
67
|
+
resolved theme takes precedence and hides local theme controls; see
|
|
68
|
+
[parent presentation](embed.md#parent-presentation).
|
package/docs/hosted-apps.md
CHANGED
|
@@ -4,7 +4,14 @@ Follow the [shared authoring flow](app-authoring.md) using [index.tsx](../exampl
|
|
|
4
4
|
one file with public package imports; omit server files, HTML, credentials, and
|
|
5
5
|
relative or app-alias imports.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Declare exactly one top-level const initialized with `defineDataApp({ ... })`, imported
|
|
8
|
+
from `@altertable/data-app`. Keep executable composition outside its literal argument.
|
|
9
|
+
For the future backend extractor, use schema-valid literals without spreads, computed keys,
|
|
10
|
+
references, calls, or template interpolation. Extraction will read and validate the argument
|
|
11
|
+
before bundling, without evaluating app code or parsing SQL. Import aliases and any variable
|
|
12
|
+
name are allowed; export only for other modules. Static apps use `queries: {}`.
|
|
13
|
+
|
|
14
|
+
Replace the sample app declaration, operations, filters, data context, CSV export, and story with
|
|
8
15
|
an exploration of the source data you inspected. The starter uses two SQL
|
|
9
16
|
`VALUES` rows, so it needs no production table.
|
|
10
17
|
|
|
@@ -13,7 +20,7 @@ For execution details, see [browser-owned operations](client.md#browser-owned-op
|
|
|
13
20
|
## Convert a local data app
|
|
14
21
|
|
|
15
22
|
1. Combine the app's operations and parsers, data context, views, story,
|
|
16
|
-
CSV export,
|
|
23
|
+
CSV export, app declaration, and browser entry into one `index.tsx`, following the
|
|
17
24
|
[single-file starter](../examples/starter-data-app/index.tsx).
|
|
18
25
|
2. Replace the HTTP client with `createDataClient({ operations })`, using the
|
|
19
26
|
operation registry as a value. See [browser-owned operations](client.md#browser-owned-operations-for-bundle-apps)
|
|
@@ -24,16 +31,3 @@ For execution details, see [browser-owned operations](client.md#browser-owned-op
|
|
|
24
31
|
4. Confirm the host can query the same catalogs, tables, and fields.
|
|
25
32
|
[Verify the app](app-authoring.md#verify-the-app) in the hosted runtime against
|
|
26
33
|
the local version's filters and findings.
|
|
27
|
-
|
|
28
|
-
## Preview in this repository
|
|
29
|
-
|
|
30
|
-
```fish
|
|
31
|
-
bun install --frozen-lockfile
|
|
32
|
-
bun run build
|
|
33
|
-
bun browser-tests/server.ts
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Open [the starter preview](http://127.0.0.1:27418/starter-data-app).
|
|
37
|
-
Its test host executes the sample SQL through the iframe bridge using SQLite.
|
|
38
|
-
|
|
39
|
-
For checks, see [Contributing](../CONTRIBUTING.md).
|
package/docs/layout.md
CHANGED
|
@@ -6,9 +6,11 @@ for sections, `<Grid>` for peer widgets, and `<GridItem>` for spans. Use
|
|
|
6
6
|
external spacing. Keep widget customization inside the widget so its parent can maintain consistent
|
|
7
7
|
spacing between sections and cards.
|
|
8
8
|
|
|
9
|
-
By default, section and widget gaps use `--
|
|
10
|
-
in `
|
|
11
|
-
on the available container width.
|
|
9
|
+
By default, section and widget gaps use `--atbl-layout-gap`, with density configured once
|
|
10
|
+
in `app.appearance`. The package owns wrapping and span collapse based
|
|
11
|
+
on the available container width and configured gap. Custom length values for
|
|
12
|
+
`--atbl-layout-gap`, `--atbl-space-sm`, and `--atbl-space-md` also drive span
|
|
13
|
+
collapse; a two-column span activates only when two minimum-width tracks fit.
|
|
12
14
|
|
|
13
15
|
```tsx
|
|
14
16
|
<Stack>
|
package/docs/react-embed.md
CHANGED
|
@@ -45,10 +45,11 @@ The local URL must have a different origin from its shell. For hosted bundles,
|
|
|
45
45
|
replace `source` with:
|
|
46
46
|
|
|
47
47
|
```tsx
|
|
48
|
-
source={{ type: 'bundle',
|
|
48
|
+
source={{ type: 'bundle', javascript }}
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
The host supplies
|
|
51
|
+
The host supplies the JavaScript bundle. Omit `bootstrapUrl` for the packaged
|
|
52
|
+
opaque bootstrap, or supply an HTTP(S) URL for an external bootstrap. See [embedding](embed.md) for trust,
|
|
52
53
|
sandbox, CSP, and bootstrap setup.
|
|
53
54
|
|
|
54
55
|
Source URL or JavaScript content changes replace the entire iframe. Change the
|
|
@@ -93,8 +94,8 @@ are mutually exclusive.
|
|
|
93
94
|
|
|
94
95
|
## Loading an embedded app
|
|
95
96
|
|
|
96
|
-
Use `<DataAppSkeleton>` from `/react` while the host builds or starts an app.
|
|
97
|
-
Call `injectDataAppShellStyles()` from `/react` before rendering the placeholder.
|
|
97
|
+
Use `<DataAppSkeleton>` from `/react/ui` while the host builds or starts an app.
|
|
98
|
+
Call `injectDataAppShellStyles()` from `/react/ui` before rendering the placeholder.
|
|
98
99
|
The host owns when to show it and supplies any surrounding header or footer.
|
|
99
100
|
`/react/embed` itself remains independent of UI components and styles.
|
|
100
101
|
|