@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/react.md
CHANGED
|
@@ -5,331 +5,36 @@ React 19.2 or newer and React DOM 19.2 or newer are peer dependencies.
|
|
|
5
5
|
|
|
6
6
|
## Mount the app
|
|
7
7
|
|
|
8
|
-
`mountDataApp({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
reported to the iframe host as fatal app failures. When mounting through another
|
|
12
|
-
framework, wrap the app in `<DataAppProvider>` yourself.
|
|
8
|
+
Use `mountDataApp({ app, component })` to mount into `#root`. When mounting
|
|
9
|
+
through another framework, wrap the root in `<DataAppProvider app={app}>` from `/react/ui`.
|
|
10
|
+
`<DataApp>` inherits identity and appearance from that root. Mounting sets the document title before React renders.
|
|
13
11
|
|
|
14
12
|
```tsx
|
|
15
13
|
import { injectDataAppStyles, mountDataApp } from '@altertable/data-app/react';
|
|
16
14
|
|
|
17
15
|
injectDataAppStyles();
|
|
18
|
-
mountDataApp({
|
|
16
|
+
mountDataApp({ app, component: App });
|
|
19
17
|
```
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
or separate stylesheet asset is needed.
|
|
19
|
+
Call `injectDataAppStyles()` before mounting; no separate stylesheet is needed.
|
|
20
|
+
For a restrictive CSP, pass the permitted nonce on the first call.
|
|
21
|
+
See [Styling](styling.md) for appearance, CSS tokens, and overrides.
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
Use `/react` for declared views, bound widgets, and layouts. Use
|
|
24
|
+
[`/react/ui`](ui.md) for setup/static screens and direct UI composition.
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
import { createDataClient } from '@altertable/data-app/client';
|
|
30
|
-
import {
|
|
31
|
-
createDataHooks,
|
|
32
|
-
dateRangeVariable,
|
|
33
|
-
DataApp,
|
|
34
|
-
Grid,
|
|
35
|
-
MetricWidget,
|
|
36
|
-
VisualizationWidget,
|
|
37
|
-
Ranking,
|
|
38
|
-
} from '@altertable/data-app/react';
|
|
39
|
-
import type { operations } from '#app/operations.ts';
|
|
40
|
-
import { calendar } from '#app/contracts.ts';
|
|
41
|
-
import { dataContext, trackedIdentities } from '#app/data-context.tsx';
|
|
42
|
-
import config from '#config';
|
|
43
|
-
|
|
44
|
-
const period = dateRangeVariable({
|
|
45
|
-
key: 'period',
|
|
46
|
-
contract: calendar,
|
|
47
|
-
comparison: true,
|
|
48
|
-
defaultValue: { kind: 'preset', id: 'last-30' },
|
|
49
|
-
});
|
|
50
|
-
const { defineDataView, useView } =
|
|
51
|
-
createDataHooks(createDataClient<typeof operations>());
|
|
52
|
-
const activityView = defineDataView({
|
|
53
|
-
operation: 'activity',
|
|
54
|
-
variables: { period },
|
|
55
|
-
input: ({ period }) => period,
|
|
56
|
-
date: { variable: 'period', input: input => input },
|
|
57
|
-
isEmpty: data => data.features.length === 0,
|
|
58
|
-
empty: { title: 'No activity in this range' },
|
|
59
|
-
});
|
|
60
|
-
const featureEvidence = dataContext.evidence({
|
|
61
|
-
id: 'feature-use',
|
|
62
|
-
queryNames: [dataContext.queryNames.activity],
|
|
63
|
-
});
|
|
64
|
-
const content = activityView.content(result => (
|
|
65
|
-
<Grid columns={2}>
|
|
66
|
-
<MetricWidget
|
|
67
|
-
metric={trackedIdentities}
|
|
68
|
-
reading={result.metric(data => ({
|
|
69
|
-
current: data.count,
|
|
70
|
-
previous: data.previousCount,
|
|
71
|
-
}))}
|
|
72
|
-
/>
|
|
73
|
-
<VisualizationWidget
|
|
74
|
-
title="Feature use"
|
|
75
|
-
evidence={featureEvidence}
|
|
76
|
-
reading={result.select(data => data.features)}
|
|
77
|
-
isEmpty={features => features.length === 0}
|
|
78
|
-
empty={{ title: 'No features' }}
|
|
79
|
-
skeleton={{ variant: 'ranking', rows: 6 }}
|
|
80
|
-
>
|
|
81
|
-
{features => <Ranking items={features} />}
|
|
82
|
-
</VisualizationWidget>
|
|
83
|
-
</Grid>
|
|
84
|
-
));
|
|
85
|
-
function App() {
|
|
86
|
-
const activity = useView(activityView);
|
|
87
|
-
return (
|
|
88
|
-
<DataApp
|
|
89
|
-
config={config}
|
|
90
|
-
dataContext={dataContext}
|
|
91
|
-
request={activity}
|
|
92
|
-
csvExport={({ data }) => ({
|
|
93
|
-
filename: 'activity.csv',
|
|
94
|
-
tables: [
|
|
95
|
-
{
|
|
96
|
-
name: 'Tracked identities',
|
|
97
|
-
columns: ['Current count', 'Previous count'],
|
|
98
|
-
rows: [[data.count, data.previousCount]],
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
name: 'Feature use',
|
|
102
|
-
columns: ['Feature ID', 'Count'],
|
|
103
|
-
rows: data.features.map(feature => [feature.id, feature.value]),
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
})}
|
|
107
|
-
story={({ data }) => [
|
|
108
|
-
dataContext.finding({
|
|
109
|
-
id: 'feature-use',
|
|
110
|
-
headline: 'Feature use in the selected period',
|
|
111
|
-
visual: <Ranking items={data.features} />,
|
|
112
|
-
evidence: featureEvidence,
|
|
113
|
-
}),
|
|
114
|
-
]}
|
|
115
|
-
{...content}
|
|
116
|
-
/>
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
The `date` binding identifies the controlling variable and extracts its range from the operation input. Nested inputs use, for example, `input: (input) => input.period`. The runtime rejects mappings that silently change the selected range or comparison. Non-date views supply `describeInput`; date views can override it when other inputs also need describing.
|
|
122
|
-
|
|
123
|
-
Share the [date range contract](contract.md#shared-date-ranges) between the
|
|
124
|
-
operation parser and the view.
|
|
125
|
-
|
|
126
|
-
`useView()` generates controls for date, text and fixed-option select variables; custom controls use `result.variables.bind(name)`. `input` chooses which variables reach the operation, so local search can stay local. Hooks belong in the enclosing component.
|
|
127
|
-
|
|
128
|
-
For large tables, use query-backed pagination with a stable sort and total
|
|
129
|
-
count. Client pagination and search cover only the rows already returned.
|
|
130
|
-
|
|
131
|
-
Bound `<VisualizationWidget>` and `<TableWidget>` components require `evidence` from `context.evidence(...)`. A bound `<MetricWidget>` gets evidence from its metric definition. Evidence must name at least one glossary entry or query. Static widgets may omit it.
|
|
132
|
-
|
|
133
|
-
`<MetricWidget>` and `<ComparisonVisual>` both accept the same `metric` and `reading`. The comparison is enabled by the displayed result's range. The definition supplies formatting and evidence; a reading cannot override those or provide a second value. `favorableDirection` is optional; changes are neutral until the author defines whether up or down is favorable.
|
|
134
|
-
|
|
135
|
-
Use the [app helpers](#reuse-app-helpers) for metric formats and values in tables,
|
|
136
|
-
charts, and custom views.
|
|
137
|
-
|
|
138
|
-
`defineDataContent()` remains available for manually managed requests. Its optional `{ date: (input) => rangeRequest }` binds comparison readings. `<DataSection>` handles independent requests. Low-level widgets, tabs and layout components remain available for custom interfaces.
|
|
139
|
-
|
|
140
|
-
## Layout
|
|
141
|
-
|
|
142
|
-
Use `<Stack>` for sections, `<Grid>` for peer widgets, and `<GridItem>` for spans.
|
|
143
|
-
They share the app layout gap and own responsive behavior. Follow the
|
|
144
|
-
[layout contract](layout.md) for spacing ownership and composition guidance.
|
|
26
|
+
## Choose a task
|
|
145
27
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
provide `evidence`. Derive both the explanation and its scope from those displayed
|
|
157
|
-
values so it stays consistent with the visualizations while filters change.
|
|
158
|
-
Static instructions can use ordinary children; local filters should feed the same
|
|
159
|
-
filtered data to the text and its related visualization.
|
|
160
|
-
|
|
161
|
-
## Reuse app helpers
|
|
162
|
-
|
|
163
|
-
Use the shared helpers for common app tasks. Follow the entry points below to
|
|
164
|
-
find their exports, types, and usage constraints.
|
|
165
|
-
|
|
166
|
-
| Task | Entry point |
|
|
167
|
-
| ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
168
|
-
| Format numbers, counts, percentages, currency, date ranges, and plural labels (`pluralize`) | [Format helpers](https://github.com/altertable-ai/data-app/blob/main/src/core/format.ts) |
|
|
169
|
-
| Choose chart colors | [Chart colors](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/chartColor.ts) |
|
|
170
|
-
| Search items and highlight matches | [Search helpers](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/searchItems.ts) |
|
|
171
|
-
| Read and synchronize URL query state | [URL state helpers](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/search.ts) |
|
|
172
|
-
| Render timestamps, freshness, table shares, periods, and metric comparisons | [React exports](https://github.com/altertable-ai/data-app/blob/main/src/react/index.ts) |
|
|
173
|
-
| Configure appearance and theme preferences | [Appearance helpers](https://github.com/altertable-ai/data-app/blob/main/src/core/appearance.ts) |
|
|
174
|
-
| Build the app's scoped document title | [Configuration helpers](https://github.com/altertable-ai/data-app/blob/main/src/core/config.ts) |
|
|
175
|
-
|
|
176
|
-
## Register source identifiers
|
|
177
|
-
|
|
178
|
-
Use `defineDataIdentifiers()` from `/react` to register exact catalog, schema,
|
|
179
|
-
table, and field names. Use `<DataIdentifier>` in descriptions and glossary
|
|
180
|
-
entries to render those source references consistently.
|
|
181
|
-
|
|
182
|
-
```tsx
|
|
183
|
-
import { defineDataIdentifiers } from '@altertable/data-app/react';
|
|
184
|
-
|
|
185
|
-
const identifiers = defineDataIdentifiers({
|
|
186
|
-
tables: {
|
|
187
|
-
events: {
|
|
188
|
-
catalog: 'product_analytics',
|
|
189
|
-
schema: 'analytics',
|
|
190
|
-
name: 'events',
|
|
191
|
-
},
|
|
192
|
-
},
|
|
193
|
-
columns: { identity: { table: 'events', name: 'identity_uuid' } },
|
|
194
|
-
});
|
|
195
|
-
const { DataIdentifier } = identifiers;
|
|
196
|
-
|
|
197
|
-
<DataIdentifier id="tables.events" />;
|
|
198
|
-
<DataIdentifier id="columns.events.identity" />;
|
|
199
|
-
```
|
|
28
|
+
| Task | Guide |
|
|
29
|
+
| -------------------------------------------------------- | --------------------------------------------------------- |
|
|
30
|
+
| Declare a view and handle loading, refresh, and failures | [Views](views.md) |
|
|
31
|
+
| Configure date, text, select, and dimension controls | [Variables](variables.md) |
|
|
32
|
+
| Render metrics, charts, tables, and narrative | [Widgets](widgets.md) |
|
|
33
|
+
| Compose sections and responsive grids | [Layout](layout.md) |
|
|
34
|
+
| Register sources, definitions, metrics, and evidence | [Data context](data-context.md) |
|
|
35
|
+
| Present findings and export displayed data | [Stories and export](stories-and-export.md) |
|
|
36
|
+
| Format values and configure appearance | [Formatting and appearance](formatting-and-appearance.md) |
|
|
37
|
+
| Host an iframe from React | [React embed](react-embed.md) |
|
|
200
38
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
explain its business meaning, and query evidence records how it was queried.
|
|
204
|
-
|
|
205
|
-
## Bind evidence
|
|
206
|
-
|
|
207
|
-
```tsx
|
|
208
|
-
const queries = defineQueryNames({ activity: 'feature-activity' });
|
|
209
|
-
// In the server operation: queryNames: queries
|
|
210
|
-
const context = createDataContext(queries)({
|
|
211
|
-
identifiers: identifiers.definitions,
|
|
212
|
-
description: (
|
|
213
|
-
<>
|
|
214
|
-
Explore activity in <DataIdentifier id="tables.events" />.
|
|
215
|
-
</>
|
|
216
|
-
),
|
|
217
|
-
glossary: {
|
|
218
|
-
identities: {
|
|
219
|
-
term: 'Tracked identities',
|
|
220
|
-
definition: (
|
|
221
|
-
<>
|
|
222
|
-
Distinct <DataIdentifier id="columns.events.identity" /> values.
|
|
223
|
-
</>
|
|
224
|
-
),
|
|
225
|
-
queryNames: [queries.activity],
|
|
226
|
-
},
|
|
227
|
-
},
|
|
228
|
-
});
|
|
229
|
-
const evidence = context.evidence({
|
|
230
|
-
id: 'identities',
|
|
231
|
-
glossaryIds: ['identities'],
|
|
232
|
-
queryNames: [queries.activity],
|
|
233
|
-
});
|
|
234
|
-
const trackedIdentities = context.metric({
|
|
235
|
-
id: 'actions',
|
|
236
|
-
glossaryId: 'identities',
|
|
237
|
-
label: 'Tracked identities',
|
|
238
|
-
format: { kind: 'count' },
|
|
239
|
-
});
|
|
240
|
-
const finding = context.finding({
|
|
241
|
-
id: 'activity',
|
|
242
|
-
headline: 'What people do',
|
|
243
|
-
visual: <ActivityChart />,
|
|
244
|
-
evidence: { id: 'activity-evidence', queryNames: [queries.activity] },
|
|
245
|
-
});
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
Import `defineQueryNames()` from `/contract` and the context/identifier factories from `/react`. Use the same registry in `defineOperation({ queryNames: queries, ... })`. Unknown glossary/query references fail type checks and registry validation; the server also validates returned query names.
|
|
249
|
-
|
|
250
|
-
## Time views and field filters
|
|
251
|
-
|
|
252
|
-
`createDataHooks(client).defineTimeView()` owns the `period` variable, calendar
|
|
253
|
-
controls, and displayed-period label. Declare `time: { contract, defaultValue }`,
|
|
254
|
-
an operation, `isEmpty`, and `empty`. With no additional variables, its default
|
|
255
|
-
input is the calendar request. With additional variables, it is `{ period, ...variables }`.
|
|
256
|
-
Supply an `input` mapper for a different operation shape and `bindings` to extract
|
|
257
|
-
nested period or field-filter inputs. Mappings must preserve the selected values.
|
|
258
|
-
|
|
259
|
-
`dimensionFilter()` from `/contract` requires exactly one option source: fixed `options` or a `facet`.
|
|
260
|
-
Use `defineFacetFilter()` to bind a facet operation and its typed input. The generated
|
|
261
|
-
`<DimensionPicker>` preserves cached options during refresh and failure, offers
|
|
262
|
-
missing values separately, and retains selected values absent from a result with
|
|
263
|
-
zero counts. `<SelectableBarChart>` can share controlled selection with the picker.
|
|
264
|
-
|
|
265
|
-
## Preserve displayed results
|
|
266
|
-
|
|
267
|
-
The callback in `view.content()` receives the displayed result and its original
|
|
268
|
-
input during refreshes and failures. Use that input when labeling the data.
|
|
269
|
-
|
|
270
|
-
Previous data and evidence are retained only when the input changes within the
|
|
271
|
-
same operation. Switching to another operation shows its own cached response or
|
|
272
|
-
an initial loading/error state; it never inherits another operation's result.
|
|
273
|
-
|
|
274
|
-
Operation and facet caches are scoped to the `DataClient` instance. Hooks created
|
|
275
|
-
from the same client share queries; separate clients do not share results, stale
|
|
276
|
-
data, or cancellation even under one provider. Keep client instances stable
|
|
277
|
-
across renders to preserve their cache.
|
|
278
|
-
|
|
279
|
-
## Findings and inspection
|
|
280
|
-
|
|
281
|
-
`<DataWidget>` composes a body, toolbar feedback, and footer. Widgets and their
|
|
282
|
-
inspection sheets render the same visual and controls. Keep interactive state
|
|
283
|
-
above both mounts when authoring custom children.
|
|
284
|
-
|
|
285
|
-
When a trusted parent supplies [parent presentation](embed.md#parent-presentation),
|
|
286
|
-
`<DataApp>` follows its resolved theme and suppresses local theme controls,
|
|
287
|
-
including in presentations. On an embedded surface (`surface: 'embedded'`),
|
|
288
|
-
only toolbar actions remain above the app body; the title, scope, description, and
|
|
289
|
-
footer are omitted. Variables and request states remain available.
|
|
290
|
-
|
|
291
|
-
## Present data with stories
|
|
292
|
-
|
|
293
|
-
Include a story in every analytical app. Stories turn the exploration's findings
|
|
294
|
-
into a presentation. Set the `story` prop on `<DataApp>`
|
|
295
|
-
to enable **Present story** in the toolbar; use `<PresentStory>` directly for a
|
|
296
|
-
custom shell. Start from the [data app starter](../examples/starter-data-app/index.tsx).
|
|
297
|
-
|
|
298
|
-
Return one to four findings with a headline, a visual, and registered source
|
|
299
|
-
evidence. Use `context.finding()` to bind the evidence.
|
|
300
|
-
|
|
301
|
-
The callback receives the displayed data and its original input, including
|
|
302
|
-
during refresh or failure. Derive the story from that snapshot so it agrees with
|
|
303
|
-
the visible exploration. Initial loading, empty results, and initial errors have
|
|
304
|
-
no story to present.
|
|
305
|
-
|
|
306
|
-
## Export displayed data as CSV
|
|
307
|
-
|
|
308
|
-
Every request-backed `<DataApp>` requires `story` and `csvExport`. Select all distinct named datasets
|
|
309
|
-
from the displayed snapshot so the built-in **Export** action is available
|
|
310
|
-
whenever analytical results are shown. Include this alongside the app's story;
|
|
311
|
-
setup and static shells may omit it. One dataset downloads directly as CSV. Multiple
|
|
312
|
-
datasets offer individual CSV downloads and **Export all** as a ZIP archive.
|
|
313
|
-
|
|
314
|
-
Example:
|
|
315
|
-
|
|
316
|
-
```tsx
|
|
317
|
-
<DataApp
|
|
318
|
-
config={config}
|
|
319
|
-
dataContext={dataContext}
|
|
320
|
-
request={result}
|
|
321
|
-
story={story}
|
|
322
|
-
csvExport={({ data, input }) => ({
|
|
323
|
-
filename: `counts-${input.groupName || 'all'}.csv`,
|
|
324
|
-
tables: [
|
|
325
|
-
{
|
|
326
|
-
name: 'Sample counts',
|
|
327
|
-
columns: ['Group', 'Sample count'],
|
|
328
|
-
rows: data.map(row => [row.groupName, row.sampleCount]),
|
|
329
|
-
},
|
|
330
|
-
],
|
|
331
|
-
})}
|
|
332
|
-
>
|
|
333
|
-
{(data, input) => <Results data={data} input={input} />}
|
|
334
|
-
</DataApp>
|
|
335
|
-
```
|
|
39
|
+
Start with [app authoring](app-authoring.md) and the
|
|
40
|
+
[single-file starter](../examples/starter-data-app/index.tsx).
|
package/docs/server-bun.md
CHANGED
|
@@ -24,6 +24,6 @@ server-only `ALTERTABLE_LAKEHOUSE_USERNAME` and
|
|
|
24
24
|
`ALTERTABLE_LAKEHOUSE_PASSWORD`, with an optional `ALTERTABLE_API_BASE`.
|
|
25
25
|
Missing credentials fail the query. Keep these variables out of browser code.
|
|
26
26
|
|
|
27
|
-
Local serving
|
|
27
|
+
Local serving does not authenticate hosted viewers.
|
|
28
28
|
Use [the portable server handler](server.md) with per-request authorization when
|
|
29
29
|
hosting an app for other people.
|
package/docs/server.md
CHANGED
|
@@ -15,7 +15,7 @@ export const handleDataRequest = createDataHandler(
|
|
|
15
15
|
const viewer = await authenticate(request);
|
|
16
16
|
return {
|
|
17
17
|
lakehouse: await lakehouseFor(viewer, operation),
|
|
18
|
-
|
|
18
|
+
queryParams: { orgId: viewer.organizationId },
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
21
|
);
|
|
@@ -23,12 +23,12 @@ export const handleDataRequest = createDataHandler(
|
|
|
23
23
|
|
|
24
24
|
The app supplies `authenticate()` and `lakehouseFor()`, then routes `/api/data/*`
|
|
25
25
|
requests to the handler. Authorize every viewer and operation, and scope the
|
|
26
|
-
returned lakehouse to the viewer's permitted data.
|
|
26
|
+
returned lakehouse to the viewer's permitted data. Supply trusted registry
|
|
27
|
+
parameters through `queryParams`; query callers cannot override these values. Origin and Fetch Metadata
|
|
27
28
|
checks reject cross-site browser requests; they do not authenticate viewers.
|
|
28
29
|
|
|
29
30
|
The handler validates operation input and output, enforces query row and duration
|
|
30
|
-
bounds, propagates cancellation, and returns request IDs
|
|
31
|
-
disclosed only when both the operation policy and `canDiscloseSql` allow it.
|
|
31
|
+
bounds, propagates cancellation, and returns query evidence and request IDs.
|
|
32
32
|
Keep credentials and operation implementations on the server.
|
|
33
33
|
|
|
34
34
|
See [operation contracts](contract.md), the [client](client.md), and the
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Stories and CSV export
|
|
2
|
+
|
|
3
|
+
Every `<DataApp>` from `/react` supplies both `story` and `datasets`, derived from
|
|
4
|
+
the displayed snapshot. Story and export selectors do not run before a result is available.
|
|
5
|
+
Setup and static screens use `<DataApp>` from `/react/ui`; they may omit both
|
|
6
|
+
or pass a direct `CsvExport` object.
|
|
7
|
+
|
|
8
|
+
## Present data with stories
|
|
9
|
+
|
|
10
|
+
Set `story` on `<DataApp>` to enable **Present story** in the toolbar.
|
|
11
|
+
For custom shells, `/react/ui` provides `<PresentStory>`; see [direct UI composition](ui.md). Start from the [data app starter](../examples/starter-data-app/index.tsx).
|
|
12
|
+
|
|
13
|
+
Return one to four findings with a headline, a visual, and registered source
|
|
14
|
+
evidence. Set `evidence` to the registered dataset or metric binding. The app
|
|
15
|
+
validates that every finding belongs to its view.
|
|
16
|
+
|
|
17
|
+
The callback receives the displayed source and its original input, including
|
|
18
|
+
during refresh or failure. Derive the story from that snapshot so it agrees with
|
|
19
|
+
the visible exploration. Initial loading, empty results, and initial errors have
|
|
20
|
+
no story to present; the toolbar keeps its story action visible and disabled.
|
|
21
|
+
|
|
22
|
+
## Export displayed data as CSV
|
|
23
|
+
|
|
24
|
+
Select all distinct named datasets from the displayed snapshot. One dataset downloads directly as CSV. Multiple
|
|
25
|
+
datasets offer individual CSV downloads and **Export all** as a ZIP archive.
|
|
26
|
+
While no displayed snapshot is available, the export action stays visible and disabled.
|
|
27
|
+
|
|
28
|
+
Declare [datasets](widgets.md#declare-datasets-and-metrics) once and pass
|
|
29
|
+
`datasets={[countries, otherDataset]}` to `<DataApp>`. The toolbar
|
|
30
|
+
exports those datasets with raw values and a safe filename derived from the
|
|
31
|
+
displayed scope. List every distinct dataset the app shows.
|
|
32
|
+
|
|
33
|
+
Reuse bound metrics in story visuals:
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
story={snapshot => {
|
|
37
|
+
const totalReading = total.read(snapshot);
|
|
38
|
+
return [{
|
|
39
|
+
id: 'total',
|
|
40
|
+
headline: `Tracked identities: ${formatMetric(totalReading.value.current, total.definition.format)}`,
|
|
41
|
+
context: activityView.scope(snapshot),
|
|
42
|
+
visual: <MetricWidget metric={total} source={snapshot} />,
|
|
43
|
+
evidence: total,
|
|
44
|
+
}];
|
|
45
|
+
}}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Use the [format helpers](formatting-and-appearance.md) for story prose.
|
|
49
|
+
|
|
50
|
+
Dataset accessors return raw values; do not preformat numbers as display
|
|
51
|
+
labels. Null and undefined become empty cells, while measured zero stays zero.
|
|
52
|
+
The helpers handle quoting and spreadsheet formula protection.
|
package/docs/styling.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Styling
|
|
2
|
+
|
|
3
|
+
Use components and typed props first: `<Stack>` for sections, `<Grid>` for peers,
|
|
4
|
+
and `<TextContent>` for prose. Standard widgets use [views and bindings](widgets.md);
|
|
5
|
+
custom controls and direct widget shells use [`/react/ui`](ui.md).
|
|
6
|
+
|
|
7
|
+
Configure theme, palette, accent, typography, density, radius, and elevation through
|
|
8
|
+
`app.appearance`; see [appearance](formatting-and-appearance.md). Call
|
|
9
|
+
`injectDataAppStyles()` before mounting. Use one `<DataApp>` per document.
|
|
10
|
+
|
|
11
|
+
## Customize
|
|
12
|
+
|
|
13
|
+
Add app-owned classes through `className`. Render package components rather than copying their classes onto markup;
|
|
14
|
+
private descendants are not customization hooks. Public names and stable roots
|
|
15
|
+
are listed in the [typed contract](https://github.com/altertable-ai/data-app/blob/main/src/react/style-contract.ts).
|
|
16
|
+
CSS comments document [inherited defaults](https://github.com/altertable-ai/data-app/blob/main/src/react/tokens.css),
|
|
17
|
+
[interaction overrides](https://github.com/altertable-ai/data-app/blob/main/src/react/interaction.css),
|
|
18
|
+
and [focus overrides](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/Focus.css).
|
|
19
|
+
Widget-specific overrides live beside their uses in
|
|
20
|
+
[metrics](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/MetricWidget.css),
|
|
21
|
+
[bar charts](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/BarChart.css),
|
|
22
|
+
[code](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/QueryList.css),
|
|
23
|
+
and [layout](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/Grid.css).
|
|
24
|
+
The `--atbl-` prefix means Altertable.
|
|
25
|
+
|
|
26
|
+
```css
|
|
27
|
+
.app-action {
|
|
28
|
+
--atbl-control-height: 40px;
|
|
29
|
+
--atbl-focus-color: var(--atbl-accent);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Set tokens on `:root` for the document or on a component for local overrides.
|
|
34
|
+
Inherited tokens are usable in app CSS. Optional overrides fall back where they
|
|
35
|
+
are consumed, so local colors, fonts, and spacing compose. Portals inherit from
|
|
36
|
+
their actual DOM ancestors. Normal unlayered app CSS overrides package rules.
|
|
37
|
+
`DataAppStyle` checks public inline custom-property names.
|
|
38
|
+
|
|
39
|
+
`--atbl-control-text-size` controls editable text, including compact search fields,
|
|
40
|
+
date segments, and annotation editors. It defaults to the body text size.
|
|
41
|
+
Package controls and custom controls with `data-atbl-control="text"` enforce a
|
|
42
|
+
16px minimum on narrow or touch viewports to prevent browser focus zoom. Keep
|
|
43
|
+
that minimum when adding app-owned input styles.
|
|
44
|
+
|
|
45
|
+
When overriding `--atbl-accent` directly, also choose `--atbl-on-accent` with
|
|
46
|
+
sufficient contrast. Prefer appearance configuration for brand and chart colors.
|
|
47
|
+
|
|
48
|
+
## Native controls
|
|
49
|
+
|
|
50
|
+
Use package controls when possible. For a custom native control:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
<button type="button" data-atbl-control="action" data-atbl-focus="ring">
|
|
54
|
+
Run
|
|
55
|
+
</button>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
These hooks provide cursor and focus styling; keep native semantics, accessible
|
|
59
|
+
names, disabled state, and keyboard behavior. `DataAppStyleHooks` checks hook
|
|
60
|
+
values. Use `default` for tooltip targets that only reveal information on hover
|
|
61
|
+
or tap, and `action` for controls that perform an action. Use `inset` focus inside
|
|
62
|
+
clipped surfaces and `group` when a wrapper owns an input's outline. See [UI quality](ui-quality.md) for rendered verification.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# UI quality
|
|
2
|
+
|
|
3
|
+
Lead with a supported finding and visible scope. Explain each chart's purpose,
|
|
4
|
+
measures, units, and source evidence. Use package typography and formatters;
|
|
5
|
+
keep primary values prominent and preserve exact values in records and exports.
|
|
6
|
+
|
|
7
|
+
Compose with `<Stack>`, `<Grid>`, and `<TextContent>`; parents own spacing and
|
|
8
|
+
widgets own padding. Let labels and values wrap, and keep tables and menus
|
|
9
|
+
scrolling inside their frames. Use the [layout](layout.md) and [styling](styling.md)
|
|
10
|
+
guides for customization.
|
|
11
|
+
|
|
12
|
+
Keep static context visible during loading. Skeletonize only dynamic content;
|
|
13
|
+
refresh, errors, and retry retain the displayed result and scope. Loading
|
|
14
|
+
geometry should match ready content.
|
|
15
|
+
|
|
16
|
+
Verify a real app at phone and desktop widths, including 320px, in both themes
|
|
17
|
+
and with enlarged text. Exercise long labels, localized values, many filters,
|
|
18
|
+
and loading, empty, refresh, and error states. Check containment, contrast,
|
|
19
|
+
keyboard focus, date/menu navigation, modal dismissal, and reduced motion.
|
|
20
|
+
Inspect rendered screenshots as well as computed styles.
|