@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
|
@@ -1,25 +1,41 @@
|
|
|
1
|
+
import { formatMetric } from '@altertable/data-app/format';
|
|
1
2
|
import { createDataClient } from '@altertable/data-app/client';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
defineOperation,
|
|
5
|
-
defineQueryNames,
|
|
6
|
-
parseCount,
|
|
7
|
-
} from '@altertable/data-app/contract';
|
|
3
|
+
import { defineDataApp } from '@altertable/data-app';
|
|
4
|
+
import { parseCount } from '@altertable/data-app/contract';
|
|
8
5
|
import {
|
|
9
6
|
createDataContext,
|
|
10
7
|
createDataHooks,
|
|
11
8
|
DataApp,
|
|
9
|
+
DataSection,
|
|
10
|
+
DataValue,
|
|
11
|
+
TableWidget,
|
|
12
12
|
Grid,
|
|
13
13
|
Stack,
|
|
14
14
|
TextContent,
|
|
15
15
|
injectDataAppStyles,
|
|
16
16
|
mountDataApp,
|
|
17
17
|
MetricWidget,
|
|
18
|
-
|
|
18
|
+
searchVariable,
|
|
19
19
|
} from '@altertable/data-app/react';
|
|
20
20
|
|
|
21
|
-
const
|
|
22
|
-
|
|
21
|
+
const dataApp = defineDataApp({
|
|
22
|
+
title: 'Sample counts',
|
|
23
|
+
description: 'Explore sample counts by group.',
|
|
24
|
+
scope: { organization: 'demo', environment: 'sample' },
|
|
25
|
+
appearance: { theme: 'system' },
|
|
26
|
+
queries: {
|
|
27
|
+
sampleCountsByGroup: {
|
|
28
|
+
statement: `
|
|
29
|
+
WITH sample_counts(group_name, sample_count) AS (VALUES ('Alpha', 2200000), ('Beta', 0))
|
|
30
|
+
SELECT group_name, sample_count FROM sample_counts
|
|
31
|
+
WHERE $groupName = '' OR group_name = $groupName
|
|
32
|
+
ORDER BY group_name LIMIT $limit`,
|
|
33
|
+
params: {
|
|
34
|
+
groupName: { defaultValue: '' },
|
|
35
|
+
limit: { defaultValue: 10 },
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
23
39
|
});
|
|
24
40
|
function parseSampleCountFilter(value: unknown) {
|
|
25
41
|
if (
|
|
@@ -47,8 +63,7 @@ function parseSampleCounts(
|
|
|
47
63
|
});
|
|
48
64
|
}
|
|
49
65
|
const operations = {
|
|
50
|
-
sampleCountsByGroup: defineOperation({
|
|
51
|
-
queryNames,
|
|
66
|
+
sampleCountsByGroup: dataApp.defineOperation({
|
|
52
67
|
input: parseSampleCountFilter,
|
|
53
68
|
output: parseSampleCounts,
|
|
54
69
|
checks: [
|
|
@@ -56,18 +71,9 @@ const operations = {
|
|
|
56
71
|
{ groupName: 'Alpha' },
|
|
57
72
|
{ groupName: 'missing' },
|
|
58
73
|
],
|
|
59
|
-
policy: { maxQueryRows: 10, maxDurationMs: 15000
|
|
74
|
+
policy: { maxQueryRows: 10, maxDurationMs: 15000 },
|
|
60
75
|
async run({ query }, { groupName }) {
|
|
61
|
-
|
|
62
|
-
const escapedGroupName = groupName.replaceAll("'", "''");
|
|
63
|
-
const queryResult = await query(
|
|
64
|
-
queryNames.sampleCountsByGroup,
|
|
65
|
-
`
|
|
66
|
-
WITH sample_counts(group_name, sample_count) AS (VALUES ('Alpha', 3), ('Beta', 0))
|
|
67
|
-
SELECT group_name, sample_count FROM sample_counts
|
|
68
|
-
WHERE '${escapedGroupName}' = '' OR group_name = '${escapedGroupName}'
|
|
69
|
-
ORDER BY group_name LIMIT 10`
|
|
70
|
-
);
|
|
76
|
+
const queryResult = await query('sampleCountsByGroup', { groupName });
|
|
71
77
|
return parseSampleCounts(
|
|
72
78
|
queryResult.rows.map(([groupName, sampleCount]) => ({
|
|
73
79
|
groupName,
|
|
@@ -77,101 +83,124 @@ ORDER BY group_name LIMIT 10`
|
|
|
77
83
|
},
|
|
78
84
|
}),
|
|
79
85
|
};
|
|
80
|
-
const
|
|
81
|
-
title: 'Sample counts',
|
|
82
|
-
scope: { organization: 'demo', environment: 'sample' },
|
|
83
|
-
appearance: { theme: 'system' },
|
|
84
|
-
};
|
|
86
|
+
const queryNames = operations.sampleCountsByGroup.queryNames;
|
|
85
87
|
const sampleDataContext = createDataContext(queryNames)({
|
|
86
88
|
description:
|
|
87
89
|
'Two SQL VALUES rows demonstrate the host query path. Replace them with inspected source data before publishing findings.',
|
|
88
90
|
glossary: {
|
|
89
91
|
sampleCount: {
|
|
90
92
|
term: 'Sample count',
|
|
91
|
-
definition:
|
|
93
|
+
definition:
|
|
94
|
+
'A fixture value: Alpha is 2,200,000 and Beta is a measured zero.',
|
|
92
95
|
queryNames: [queryNames.sampleCountsByGroup],
|
|
93
96
|
},
|
|
94
97
|
},
|
|
95
98
|
});
|
|
96
|
-
const { defineDataView
|
|
97
|
-
createDataClient({ operations })
|
|
98
|
-
);
|
|
99
|
+
const { defineDataView } = createDataHooks(createDataClient({ operations }));
|
|
99
100
|
const sampleCountsView = defineDataView({
|
|
101
|
+
dataContext: sampleDataContext,
|
|
100
102
|
operation: 'sampleCountsByGroup',
|
|
101
103
|
variables: {
|
|
102
|
-
groupName:
|
|
104
|
+
groupName: searchVariable({
|
|
105
|
+
key: 'group',
|
|
106
|
+
label: 'Group',
|
|
107
|
+
defaultValue: '',
|
|
108
|
+
}),
|
|
103
109
|
},
|
|
104
|
-
input: ({ groupName }) => ({ groupName }),
|
|
105
110
|
describeInput: ({ groupName }) =>
|
|
106
111
|
groupName ? `group ${groupName}` : 'all groups',
|
|
107
112
|
isEmpty: sampleCounts => sampleCounts.length === 0,
|
|
108
|
-
|
|
113
|
+
emptyFallback: {
|
|
109
114
|
title: 'No matching groups',
|
|
110
115
|
description: 'Try Alpha, Beta, or clear the group filter.',
|
|
111
116
|
},
|
|
112
117
|
});
|
|
118
|
+
const sampleCounts = sampleCountsView.dataset({
|
|
119
|
+
name: 'Sample counts',
|
|
120
|
+
select: rows => rows,
|
|
121
|
+
rowKey: row => row.groupName,
|
|
122
|
+
columns: {
|
|
123
|
+
groupName: { label: 'Group', value: row => row.groupName },
|
|
124
|
+
sampleCount: { value: row => row.sampleCount, format: { kind: 'count' } },
|
|
125
|
+
},
|
|
126
|
+
evidence: {
|
|
127
|
+
id: 'counts-by-group',
|
|
128
|
+
glossaryIds: ['sampleCount'],
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
const totalSamples = sampleCountsView.metric(
|
|
132
|
+
{
|
|
133
|
+
id: 'total-samples',
|
|
134
|
+
glossaryId: 'sampleCount',
|
|
135
|
+
label: 'Total samples',
|
|
136
|
+
format: { kind: 'count', compact: true },
|
|
137
|
+
},
|
|
138
|
+
rows => ({ current: rows.reduce((sum, row) => sum + row.sampleCount, 0) })
|
|
139
|
+
);
|
|
140
|
+
const sampleContent = sampleCountsView.content(result => (
|
|
141
|
+
<Stack aria-label="Sample results">
|
|
142
|
+
<TextContent>
|
|
143
|
+
<p>
|
|
144
|
+
Showing <DataValue scope={result.scope} />
|
|
145
|
+
</p>
|
|
146
|
+
</TextContent>
|
|
147
|
+
<Grid columns={2}>
|
|
148
|
+
<MetricWidget
|
|
149
|
+
metric={totalSamples}
|
|
150
|
+
source={result}
|
|
151
|
+
description="Sum of the fixture counts in the selected groups."
|
|
152
|
+
/>
|
|
153
|
+
<TableWidget
|
|
154
|
+
dataset={sampleCounts}
|
|
155
|
+
source={result}
|
|
156
|
+
title="Counts by group"
|
|
157
|
+
description="Alpha and Beta demonstrate measured values, including zero."
|
|
158
|
+
pagination={false}
|
|
159
|
+
/>
|
|
160
|
+
</Grid>
|
|
161
|
+
</Stack>
|
|
162
|
+
));
|
|
113
163
|
function App() {
|
|
114
|
-
const sampleCountsRequest = useView(sampleCountsView);
|
|
115
164
|
return (
|
|
116
165
|
<DataApp
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
166
|
+
view={sampleCountsView}
|
|
167
|
+
datasets={[sampleCounts]}
|
|
168
|
+
story={snapshot => {
|
|
169
|
+
const total = totalSamples.read(snapshot);
|
|
170
|
+
const scope = sampleCountsView.scope(snapshot);
|
|
171
|
+
return [
|
|
123
172
|
{
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
173
|
+
id: 'total-samples',
|
|
174
|
+
headline: `Total samples: ${formatMetric(total.value.current, totalSamples.definition.format)}`,
|
|
175
|
+
context: `Demonstration values for ${scope}.`,
|
|
176
|
+
visual: <MetricWidget metric={totalSamples} source={snapshot} />,
|
|
177
|
+
visualKind: 'metric',
|
|
178
|
+
evidence: totalSamples,
|
|
130
179
|
},
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
sampleDataContext.finding({
|
|
136
|
-
id: `sample-count-${groupName}`,
|
|
137
|
-
headline: `${groupName} has ${sampleCount} samples`,
|
|
138
|
-
context: `Demonstration values for ${displayedInput.groupName || 'all groups'}.`,
|
|
180
|
+
{
|
|
181
|
+
id: 'counts-by-group',
|
|
182
|
+
headline: 'Counts by group',
|
|
183
|
+
context: `Demonstration values for ${scope}.`,
|
|
139
184
|
visual: (
|
|
140
|
-
<
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
185
|
+
<TableWidget
|
|
186
|
+
dataset={sampleCounts}
|
|
187
|
+
source={snapshot}
|
|
188
|
+
pagination={false}
|
|
144
189
|
/>
|
|
145
190
|
),
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
},
|
|
151
|
-
})
|
|
152
|
-
)
|
|
153
|
-
}
|
|
191
|
+
evidence: sampleCounts,
|
|
192
|
+
},
|
|
193
|
+
];
|
|
194
|
+
}}
|
|
154
195
|
>
|
|
155
|
-
|
|
156
|
-
<
|
|
157
|
-
<
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
<Grid columns={2}>
|
|
162
|
-
{sampleCounts.map(({ groupName, sampleCount }) => (
|
|
163
|
-
<MetricWidget
|
|
164
|
-
key={groupName}
|
|
165
|
-
label={`${groupName}: ${sampleCount}`}
|
|
166
|
-
value={sampleCount}
|
|
167
|
-
format={{ kind: 'count' }}
|
|
168
|
-
/>
|
|
169
|
-
))}
|
|
170
|
-
</Grid>
|
|
171
|
-
</Stack>
|
|
172
|
-
)}
|
|
196
|
+
<Stack>
|
|
197
|
+
<TextContent>
|
|
198
|
+
<h2>Sample counts</h2>
|
|
199
|
+
</TextContent>
|
|
200
|
+
<DataSection content={sampleContent} />
|
|
201
|
+
</Stack>
|
|
173
202
|
</DataApp>
|
|
174
203
|
);
|
|
175
204
|
}
|
|
176
205
|
injectDataAppStyles();
|
|
177
|
-
mountDataApp({
|
|
206
|
+
mountDataApp({ app: dataApp, component: App });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@altertable/data-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.67.0",
|
|
4
4
|
"description": "Contracts, transport, and React UI for Altertable data apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"altertable",
|
|
@@ -36,6 +36,10 @@
|
|
|
36
36
|
"type": "module",
|
|
37
37
|
"sideEffects": false,
|
|
38
38
|
"exports": {
|
|
39
|
+
".": {
|
|
40
|
+
"types": "./dist/types/index.d.ts",
|
|
41
|
+
"import": "./dist/index.js"
|
|
42
|
+
},
|
|
39
43
|
"./contract": {
|
|
40
44
|
"types": "./dist/types/core/contract.d.ts",
|
|
41
45
|
"import": "./dist/core/contract.js"
|
|
@@ -78,6 +82,10 @@
|
|
|
78
82
|
"./react/embed": {
|
|
79
83
|
"types": "./dist/types/react/embed/index.d.ts",
|
|
80
84
|
"import": "./dist/react/embed/index.js"
|
|
85
|
+
},
|
|
86
|
+
"./react/ui": {
|
|
87
|
+
"types": "./dist/types/react/ui/index.d.ts",
|
|
88
|
+
"import": "./dist/react/ui/index.js"
|
|
81
89
|
}
|
|
82
90
|
},
|
|
83
91
|
"publishConfig": {
|
|
@@ -86,20 +94,21 @@
|
|
|
86
94
|
},
|
|
87
95
|
"scripts": {
|
|
88
96
|
"build": "bun run scripts/build.ts && tsc -p tsconfig.build.json && bun run scripts/build-declarations.ts",
|
|
97
|
+
"dev": "bun run scripts/dev.ts",
|
|
89
98
|
"typecheck": "bun install --frozen-lockfile && tsc --noEmit",
|
|
90
|
-
"lint": "oxlint --type-aware src tests scripts
|
|
99
|
+
"lint": "oxlint --type-aware src tests scripts dev examples/starter-data-app vitest.config.ts",
|
|
91
100
|
"format": "oxfmt .",
|
|
92
101
|
"format:check": "oxfmt --check .",
|
|
93
|
-
"test": "
|
|
94
|
-
"check": "bun run build && bun run typecheck && bun run lint && bun run lint:md && bun run check:links && bun run format:check && bun run test && bun run
|
|
95
|
-
"
|
|
102
|
+
"test": "vitest run",
|
|
103
|
+
"check": "bun run build && bun run typecheck && bun run lint && bun run check:styles && bun run lint:md && bun run check:links && bun run format:check && bun run test && bun run check:package && bun run check:starter",
|
|
104
|
+
"check:package": "bun run scripts/check-package.ts",
|
|
96
105
|
"check:workflows": "bash scripts/check-workflows.sh",
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"test:starter": "bun run scripts/check-starter.ts",
|
|
106
|
+
"lint:fix": "oxlint --type-aware --fix src tests scripts dev vitest.config.ts",
|
|
107
|
+
"check:starter": "bun run scripts/check-starter.ts",
|
|
100
108
|
"lint:md": "markdownlint-cli2",
|
|
101
109
|
"check:links": "remark . --ext md --rc-path .remarkrc.json --frail --no-stdout",
|
|
102
|
-
"check:links:external": "remark . --ext md --rc-path .remarkrc-external.json --frail --no-stdout"
|
|
110
|
+
"check:links:external": "remark . --ext md --rc-path .remarkrc-external.json --frail --no-stdout",
|
|
111
|
+
"check:styles": "bun run scripts/check-app-styles.ts"
|
|
103
112
|
},
|
|
104
113
|
"dependencies": {
|
|
105
114
|
"@floating-ui/react": "0.27.20",
|
|
@@ -107,11 +116,12 @@
|
|
|
107
116
|
"@tanstack/react-query": "5.104.0",
|
|
108
117
|
"fflate": "0.8.3",
|
|
109
118
|
"fuzzysort": "4.0.2",
|
|
119
|
+
"html-to-image": "1.11.13",
|
|
110
120
|
"lucide-react": "1.48.0",
|
|
111
|
-
"react-aria-components": "1.21.1"
|
|
121
|
+
"react-aria-components": "1.21.1",
|
|
122
|
+
"recharts": "3.10.1"
|
|
112
123
|
},
|
|
113
124
|
"devDependencies": {
|
|
114
|
-
"@playwright/test": "1.63.0",
|
|
115
125
|
"@types/bun": "1.4.2",
|
|
116
126
|
"@types/react": "19.3.0",
|
|
117
127
|
"@types/react-dom": "19.3.0",
|
|
@@ -119,13 +129,16 @@
|
|
|
119
129
|
"oxfmt": "0.70.0",
|
|
120
130
|
"oxlint": "1.85.0",
|
|
121
131
|
"oxlint-tsgolint": "7.0.2003",
|
|
132
|
+
"playwright": "1.63.0",
|
|
122
133
|
"react": "19.3.0",
|
|
123
134
|
"react-dom": "19.3.0",
|
|
124
135
|
"remark-cli": "12.0.1",
|
|
125
136
|
"remark-gfm": "4.0.1",
|
|
126
137
|
"remark-lint-no-dead-urls": "2.0.1",
|
|
127
138
|
"remark-validate-links": "13.1.0",
|
|
128
|
-
"
|
|
139
|
+
"testcontainers": "12.2.0",
|
|
140
|
+
"typescript": "7.0.2",
|
|
141
|
+
"vitest": "4.1.11"
|
|
129
142
|
},
|
|
130
143
|
"peerDependencies": {
|
|
131
144
|
"react": ">=19.2.0",
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/client/data-client.ts", "../src/client/location.ts", "../src/client/navigation.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import { createHttpTransport, DataAppError } from '@/src/client/transport';\nimport { getDataAppTransport, localFrameBridge } from '@/src/client/iframe';\nimport {\n executeDataOperation,\n toDataOperationFailure,\n} from '@/src/core/operation';\nimport type { DataOperations, Lakehouse } from '@/src/core/contract';\nimport { defineDataQueryRoute, MessageRoutingError } from '@/src/core/messages';\nimport type { DataTransport } from '@/src/client/transport';\nimport type {\n DataQueryBody,\n InputOf,\n OutputOf,\n} from '@/src/core/operation-types';\nexport type { InputOf, OutputOf } from '@/src/core/operation-types';\n\n/**\n * Parsed operation data and query evidence. `queries` is present only when SQL disclosure is\n * allowed.\n */\nexport type DataResponse<Output, Input = unknown> = DataQueryBody<Output> & {\n /** The exact browser input that produced this response. */\n input: Input;\n};\n\nexport type DataClient<Operations extends DataOperations> = {\n query<Name extends keyof Operations & string>(\n name: Name,\n input: InputOf<Operations[Name]>,\n options?: { signal?: AbortSignal }\n ): Promise<\n DataResponse<OutputOf<Operations[Name]>, InputOf<Operations[Name]>>\n >;\n};\n\n/** Browser operations and named-operation delivery are mutually exclusive configurations. */\nexport type DataClientOptions<Operations extends DataOperations> =\n | {\n operations: Operations;\n lakehouse?: Lakehouse;\n transport?: never;\n endpoint?: never;\n fetch?: never;\n }\n | {\n operations?: never;\n lakehouse?: never;\n transport?: DataTransport;\n endpoint?: string;\n fetch?: typeof fetch;\n };\n\nconst dataQueryRoute = defineDataQueryRoute();\n\n/** Named HTTP operations, or browser-owned operations executed through an authorized SQL bridge. */\nexport function createDataClient<Operations extends DataOperations>(\n options: DataClientOptions<Operations> = {}\n): DataClient<Operations> {\n if (options.operations)\n return createOperationClient({\n operations: options.operations,\n lakehouse: options.lakehouse,\n });\n const http = createHttpTransport(options);\n const useHttp = options.endpoint !== undefined || options.fetch !== undefined;\n\n return {\n async query(name, input, { signal } = {}) {\n const transport =\n options.transport ??\n (useHttp ? http : (localFrameBridge()?.transport ?? http));\n const response = await transport(name, input, signal);\n const ok = response.status >= 200 && response.status < 300;\n let body: Omit<DataResponse<OutputOf<Operations[typeof name]>>, 'input'>;\n try {\n body = dataQueryRoute.output(response, { operation: name, input })\n .body as typeof body;\n } catch (error) {\n if (signal?.aborted) throw error;\n if (error instanceof MessageRoutingError)\n throw new DataAppError(error.message, error.code, error.requestId);\n throw new DataAppError(\n ok ? 'The data response was invalid.' : 'Could not load data.',\n ok ? 'invalid_response' : 'request_failed'\n );\n }\n\n return { ...body, input };\n },\n };\n}\n\nfunction createOperationClient<Operations extends DataOperations>(options: {\n operations: Operations;\n lakehouse?: Lakehouse;\n}): DataClient<Operations> {\n return {\n async query(name, input, { signal } = {}) {\n signal?.throwIfAborted();\n const requestId = crypto.randomUUID();\n if (!Object.hasOwn(options.operations, name))\n throw new DataAppError(\n 'Unknown data operation.',\n 'not_found',\n requestId\n );\n const lakehouse =\n options.lakehouse ??\n (typeof window === 'undefined'\n ? undefined\n : getDataAppTransport()?.lakehouse);\n if (!lakehouse)\n throw new DataAppError(\n 'An authorized SQL bridge must be installed first.',\n 'bridge_unavailable',\n requestId\n );\n\n try {\n const { body } = await executeDataOperation(\n options.operations[name]!,\n input,\n {\n lakehouse,\n signal: signal ?? new AbortController().signal,\n includeSql: true,\n requestId,\n operationName: name,\n }\n );\n\n return { ...body, input } as DataResponse<\n OutputOf<Operations[typeof name]>,\n InputOf<Operations[typeof name]>\n >;\n } catch (error) {\n if (signal?.aborted) throw signal.reason;\n if (error instanceof DataAppError) throw error;\n const failure = toDataOperationFailure(error);\n throw new DataAppError(failure.message, failure.code, requestId);\n }\n },\n };\n}\n",
|
|
6
|
-
"import { PARENT_PARAM } from '@/src/core/bridge';\nimport { validLocation } from '@/src/core/navigation';\n\nimport type { AppLocation, HistoryMode } from '@/src/core/navigation';\nexport type { AppLocation } from '@/src/core/navigation';\nexport type DataAppLocation = {\n snapshot(): AppLocation;\n subscribe(listener: () => void): () => void;\n update(location: AppLocation, mode?: HistoryMode): void;\n};\n\n/** Opaque sandboxes keep app state in memory; URL frames retain their real URL for HMR. */\nexport function createAppLocation(\n frame: Window,\n virtual: boolean,\n publish: (location: AppLocation, mode: HistoryMode) => void\n) {\n let state: AppLocation = { search: '', hash: '' };\n let disposed = false;\n const listeners = new Set<() => void>();\n\n function notify() {\n for (const listener of listeners) listener();\n }\n\n function snapshot(): AppLocation {\n if (virtual) return state;\n const url = new URL(frame.location.href);\n url.searchParams.delete(PARENT_PARAM);\n if (state.search !== url.search || state.hash !== url.hash)\n state = { search: url.search, hash: url.hash };\n\n return state;\n }\n\n function apply(next: AppLocation) {\n const previous = snapshot();\n if (previous.search === next.search && previous.hash === next.hash) return;\n if (virtual) state = next;\n else {\n const url = new URL(frame.location.href);\n const parent = url.searchParams.get(PARENT_PARAM);\n url.search = next.search;\n if (parent) url.searchParams.set(PARENT_PARAM, parent);\n url.hash = next.hash;\n frame.history.replaceState(null, '', url);\n frame.dispatchEvent(new Event('popstate'));\n }\n if (virtual) notify();\n }\n\n const location: DataAppLocation = {\n snapshot,\n subscribe(listener) {\n listeners.add(listener);\n if (!virtual) frame.addEventListener('popstate', listener);\n\n return () => {\n listeners.delete(listener);\n frame.removeEventListener('popstate', listener);\n };\n },\n update(next, mode = 'replace') {\n if (disposed) return;\n if (!validLocation(next)) throw new Error('Invalid app location.');\n const before = snapshot();\n if (before.search === next.search && before.hash === next.hash) return;\n apply(next);\n publish(next, mode);\n },\n };\n\n function dispose() {\n disposed = true;\n for (const listener of listeners)\n frame.removeEventListener('popstate', listener);\n listeners.clear();\n }\n\n return { location, apply, dispose };\n}\n",
|
|
7
|
-
"import type { AppLocation, HistoryMode } from '@/src/core/navigation';\nimport { createAppLocation, type DataAppLocation } from '@/src/client/location';\nimport { validLocation } from '@/src/core/navigation';\nimport {\n navigationUpdateRoute,\n type NavigationUpdate,\n} from '@/src/core/messages';\nimport { createMessageClient } from '@/src/client/messages';\nimport {\n getDataAppTransport,\n localFrameBridge,\n type IframeTransport,\n} from '@/src/client/iframe';\n\nexport type DataAppNavigation = DataAppLocation & {\n /** Publish URL changes made outside the adapter, including the document title. */\n publish(mode?: HistoryMode): void;\n dispose(): void;\n};\n\n/** Attach app URL behavior to an already authenticated bridge. */\nexport function createDataAppNavigation({\n bridge,\n window: frame = window,\n}: {\n bridge: IframeTransport;\n window?: Window;\n}): DataAppNavigation {\n return attachNavigation(frame, bridge.mode === 'bundle', bridge).navigation;\n}\n\nfunction attachNavigation(\n frame: Window,\n virtual: boolean,\n connection: IframeTransport | Promise<IframeTransport>\n) {\n let disposed = false;\n let unsubscribe: (() => void) | undefined;\n let send: ((update: NavigationUpdate) => void) | undefined;\n let pendingUpdate: NavigationUpdate | undefined;\n const { location, apply, dispose } = createAppLocation(\n frame,\n virtual,\n publish\n );\n\n function publish(location: AppLocation, mode: HistoryMode) {\n const update = { ...location, mode, title: frame.document.title };\n if (send) send(update);\n else pendingUpdate = update;\n }\n\n function attach(bridge: IframeTransport) {\n if (disposed) return;\n unsubscribe?.();\n const messages = createMessageClient(\n { 'navigation:update': navigationUpdateRoute },\n bridge.request\n );\n\n function sendUpdate(update: NavigationUpdate) {\n void messages.request('navigation:update', update).catch(() => {});\n }\n\n function receiveState(state: unknown) {\n if (!validLocation(state)) return;\n pendingUpdate = undefined;\n apply(state);\n }\n\n send = sendUpdate;\n unsubscribe = bridge.subscribe(receiveState);\n receiveState(bridge.snapshot());\n if (pendingUpdate) {\n sendUpdate(pendingUpdate);\n pendingUpdate = undefined;\n }\n }\n\n if ('then' in connection) void connection.then(attach).catch(() => {});\n else attach(connection);\n\n const navigation: DataAppNavigation = {\n ...location,\n publish(mode = 'replace') {\n if (!disposed) publish(location.snapshot(), mode);\n },\n dispose() {\n disposed = true;\n unsubscribe?.();\n dispose();\n send = undefined;\n pendingUpdate = undefined;\n },\n };\n\n return {\n navigation,\n attach,\n isDisposed() {\n return disposed;\n },\n };\n}\n\nconst navigationKey = Symbol.for('altertable.appNavigation');\ntype NavigationWindow = Window & {\n [navigationKey]?: ReturnType<typeof attachNavigation> & {\n bridge?: IframeTransport;\n };\n};\n\n/** URL controls attach navigation on demand; bootstrap and data-only clients do not. */\nexport function getDataAppNavigation(\n frame: Window = window\n): DataAppNavigation | undefined {\n const target = frame as NavigationWindow;\n const bridge = getDataAppTransport(frame);\n const cached = target[navigationKey]?.isDisposed()\n ? undefined\n : target[navigationKey];\n if (cached) {\n if (bridge && cached.bridge !== bridge) {\n cached.attach(bridge);\n cached.bridge = bridge;\n }\n\n return cached.navigation;\n }\n if (bridge) {\n const adapter = attachNavigation(frame, bridge.mode === 'bundle', bridge);\n target[navigationKey] = { bridge, ...adapter };\n\n return adapter.navigation;\n }\n const preview = localFrameBridge(frame);\n if (!preview?.connect) return undefined;\n const connection = preview.connect();\n const adapter = attachNavigation(frame, false, connection);\n const entry = {\n ...adapter,\n bridge: undefined as IframeTransport | undefined,\n };\n target[navigationKey] = entry;\n void connection\n .then(bridge => {\n entry.bridge = bridge;\n })\n .catch(() => {});\n\n return adapter.navigation;\n}\n"
|
|
8
|
-
],
|
|
9
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAoDA,IAAM,iBAAiB,sBAAqB;AAGrC,SAAS,iBAAmD,CACjE,UAAyC,CAAC,GAClB;AAAA,EACxB,IAAI,QAAQ;AAAA,IACV,OAAO,sBAAsB;AAAA,MAC3B,YAAY,QAAQ;AAAA,MACpB,WAAW,QAAQ;AAAA,IACrB,CAAC;AAAA,EACH,MAAM,OAAO,qBAAoB,OAAO;AAAA,EACxC,MAAM,UAAU,QAAQ,aAAa,aAAa,QAAQ,UAAU;AAAA,EAEpE,OAAO;AAAA,SACC,MAAK,CAAC,MAAM,SAAS,WAAW,CAAC,GAAG;AAAA,MACxC,MAAM,YACJ,QAAQ,cACP,UAAU,OAAQ,iBAAiB,GAAG,aAAa;AAAA,MACtD,MAAM,WAAW,MAAM,UAAU,MAAM,OAAO,MAAM;AAAA,MACpD,MAAM,KAAK,SAAS,UAAU,OAAO,SAAS,SAAS;AAAA,MACvD,IAAI;AAAA,MACJ,IAAI;AAAA,QACF,OAAO,eAAe,OAAO,UAAU,EAAE,WAAW,MAAM,MAAM,CAAC,EAC9D;AAAA,QACH,OAAO,OAAO;AAAA,QACd,IAAI,QAAQ;AAAA,UAAS,MAAM;AAAA,QAC3B,IAAI,iBAAiB;AAAA,UACnB,MAAM,IAAI,cAAa,MAAM,SAAS,MAAM,MAAM,MAAM,SAAS;AAAA,QACnE,MAAM,IAAI,cACR,KAAK,mCAAmC,wBACxC,KAAK,qBAAqB,gBAC5B;AAAA;AAAA,MAGF,OAAO,KAAK,MAAM,MAAM;AAAA;AAAA,EAE5B;AAAA;AAGF,SAAS,qBAAwD,CAAC,SAGvC;AAAA,EACzB,OAAO;AAAA,SACC,MAAK,CAAC,MAAM,SAAS,WAAW,CAAC,GAAG;AAAA,MACxC,QAAQ,eAAe;AAAA,MACvB,MAAM,YAAY,OAAO,WAAW;AAAA,MACpC,IAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,IAAI;AAAA,QACzC,MAAM,IAAI,cACR,2BACA,aACA,SACF;AAAA,MACF,MAAM,YACJ,QAAQ,cACP,OAAO,WAAW,cACf,YACA,qBAAoB,GAAG;AAAA,MAC7B,IAAI,CAAC;AAAA,QACH,MAAM,IAAI,cACR,qDACA,sBACA,SACF;AAAA,MAEF,IAAI;AAAA,QACF,QAAQ,SAAS,MAAM,qBACrB,QAAQ,WAAW,OACnB,OACA;AAAA,UACE;AAAA,UACA,QAAQ,UAAU,IAAI,gBAAgB,EAAE;AAAA,UACxC,YAAY;AAAA,UACZ;AAAA,UACA,eAAe;AAAA,QACjB,CACF;AAAA,QAEA,OAAO,KAAK,MAAM,MAAM;AAAA,QAIxB,OAAO,OAAO;AAAA,QACd,IAAI,QAAQ;AAAA,UAAS,MAAM,OAAO;AAAA,QAClC,IAAI,iBAAiB;AAAA,UAAc,MAAM;AAAA,QACzC,MAAM,UAAU,uBAAuB,KAAK;AAAA,QAC5C,MAAM,IAAI,cAAa,QAAQ,SAAS,QAAQ,MAAM,SAAS;AAAA;AAAA;AAAA,EAGrE;AAAA;;;AClIK,SAAS,iBAAiB,CAC/B,OACA,SACA,SACA;AAAA,EACA,IAAI,QAAqB,EAAE,QAAQ,IAAI,MAAM,GAAG;AAAA,EAChD,IAAI,WAAW;AAAA,EACf,MAAM,YAAY,IAAI;AAAA,EAEtB,SAAS,MAAM,GAAG;AAAA,IAChB,WAAW,YAAY;AAAA,MAAW,SAAS;AAAA;AAAA,EAG7C,SAAS,QAAQ,GAAgB;AAAA,IAC/B,IAAI;AAAA,MAAS,OAAO;AAAA,IACpB,MAAM,MAAM,IAAI,IAAI,MAAM,SAAS,IAAI;AAAA,IACvC,IAAI,aAAa,OAAO,YAAY;AAAA,IACpC,IAAI,MAAM,WAAW,IAAI,UAAU,MAAM,SAAS,IAAI;AAAA,MACpD,QAAQ,EAAE,QAAQ,IAAI,QAAQ,MAAM,IAAI,KAAK;AAAA,IAE/C,OAAO;AAAA;AAAA,EAGT,SAAS,KAAK,CAAC,MAAmB;AAAA,IAChC,MAAM,WAAW,SAAS;AAAA,IAC1B,IAAI,SAAS,WAAW,KAAK,UAAU,SAAS,SAAS,KAAK;AAAA,MAAM;AAAA,IACpE,IAAI;AAAA,MAAS,QAAQ;AAAA,IAChB;AAAA,MACH,MAAM,MAAM,IAAI,IAAI,MAAM,SAAS,IAAI;AAAA,MACvC,MAAM,SAAS,IAAI,aAAa,IAAI,YAAY;AAAA,MAChD,IAAI,SAAS,KAAK;AAAA,MAClB,IAAI;AAAA,QAAQ,IAAI,aAAa,IAAI,cAAc,MAAM;AAAA,MACrD,IAAI,OAAO,KAAK;AAAA,MAChB,MAAM,QAAQ,aAAa,MAAM,IAAI,GAAG;AAAA,MACxC,MAAM,cAAc,IAAI,MAAM,UAAU,CAAC;AAAA;AAAA,IAE3C,IAAI;AAAA,MAAS,OAAO;AAAA;AAAA,EAGtB,MAAM,WAA4B;AAAA,IAChC;AAAA,IACA,SAAS,CAAC,UAAU;AAAA,MAClB,UAAU,IAAI,QAAQ;AAAA,MACtB,IAAI,CAAC;AAAA,QAAS,MAAM,iBAAiB,YAAY,QAAQ;AAAA,MAEzD,OAAO,MAAM;AAAA,QACX,UAAU,OAAO,QAAQ;AAAA,QACzB,MAAM,oBAAoB,YAAY,QAAQ;AAAA;AAAA;AAAA,IAGlD,MAAM,CAAC,MAAM,OAAO,WAAW;AAAA,MAC7B,IAAI;AAAA,QAAU;AAAA,MACd,IAAI,CAAC,cAAc,IAAI;AAAA,QAAG,MAAM,IAAI,MAAM,uBAAuB;AAAA,MACjE,MAAM,SAAS,SAAS;AAAA,MACxB,IAAI,OAAO,WAAW,KAAK,UAAU,OAAO,SAAS,KAAK;AAAA,QAAM;AAAA,MAChE,MAAM,IAAI;AAAA,MACV,QAAQ,MAAM,IAAI;AAAA;AAAA,EAEtB;AAAA,EAEA,SAAS,OAAO,GAAG;AAAA,IACjB,WAAW;AAAA,IACX,WAAW,YAAY;AAAA,MACrB,MAAM,oBAAoB,YAAY,QAAQ;AAAA,IAChD,UAAU,MAAM;AAAA;AAAA,EAGlB,OAAO,EAAE,UAAU,OAAO,QAAQ;AAAA;;;AC1D7B,SAAS,wBAAuB;AAAA,EACrC;AAAA,EACA,QAAQ,QAAQ;AAAA,GAII;AAAA,EACpB,OAAO,iBAAiB,OAAO,OAAO,SAAS,UAAU,MAAM,EAAE;AAAA;AAGnE,SAAS,gBAAgB,CACvB,OACA,SACA,YACA;AAAA,EACA,IAAI,WAAW;AAAA,EACf,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,QAAQ,UAAU,OAAO,YAAY,kBACnC,OACA,SACA,OACF;AAAA,EAEA,SAAS,OAAO,CAAC,UAAuB,MAAmB;AAAA,IACzD,MAAM,SAAS,KAAK,UAAU,MAAM,OAAO,MAAM,SAAS,MAAM;AAAA,IAChE,IAAI;AAAA,MAAM,KAAK,MAAM;AAAA,IAChB;AAAA,sBAAgB;AAAA;AAAA,EAGvB,SAAS,MAAM,CAAC,QAAyB;AAAA,IACvC,IAAI;AAAA,MAAU;AAAA,IACd,cAAc;AAAA,IACd,MAAM,WAAW,qBACf,EAAE,qBAAqB,uBAAsB,GAC7C,OAAO,OACT;AAAA,IAEA,SAAS,UAAU,CAAC,QAA0B;AAAA,MACvC,SAAS,QAAQ,qBAAqB,MAAM,EAAE,MAAM,MAAM,EAAE;AAAA;AAAA,IAGnE,SAAS,YAAY,CAAC,OAAgB;AAAA,MACpC,IAAI,CAAC,cAAc,KAAK;AAAA,QAAG;AAAA,MAC3B,gBAAgB;AAAA,MAChB,MAAM,KAAK;AAAA;AAAA,IAGb,OAAO;AAAA,IACP,cAAc,OAAO,UAAU,YAAY;AAAA,IAC3C,aAAa,OAAO,SAAS,CAAC;AAAA,IAC9B,IAAI,eAAe;AAAA,MACjB,WAAW,aAAa;AAAA,MACxB,gBAAgB;AAAA,IAClB;AAAA;AAAA,EAGF,IAAI,UAAU;AAAA,IAAiB,WAAW,KAAK,MAAM,EAAE,MAAM,MAAM,EAAE;AAAA,EAChE;AAAA,WAAO,UAAU;AAAA,EAEtB,MAAM,aAAgC;AAAA,OACjC;AAAA,IACH,OAAO,CAAC,OAAO,WAAW;AAAA,MACxB,IAAI,CAAC;AAAA,QAAU,QAAQ,SAAS,SAAS,GAAG,IAAI;AAAA;AAAA,IAElD,OAAO,GAAG;AAAA,MACR,WAAW;AAAA,MACX,cAAc;AAAA,MACd,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,gBAAgB;AAAA;AAAA,EAEpB;AAAA,EAEA,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,GAAG;AAAA,MACX,OAAO;AAAA;AAAA,EAEX;AAAA;AAGF,IAAM,gBAAgB,OAAO,IAAI,0BAA0B;AAQpD,SAAS,qBAAoB,CAClC,QAAgB,QACe;AAAA,EAC/B,MAAM,SAAS;AAAA,EACf,MAAM,SAAS,qBAAoB,KAAK;AAAA,EACxC,MAAM,SAAS,OAAO,gBAAgB,WAAW,IAC7C,YACA,OAAO;AAAA,EACX,IAAI,QAAQ;AAAA,IACV,IAAI,UAAU,OAAO,WAAW,QAAQ;AAAA,MACtC,OAAO,OAAO,MAAM;AAAA,MACpB,OAAO,SAAS;AAAA,IAClB;AAAA,IAEA,OAAO,OAAO;AAAA,EAChB;AAAA,EACA,IAAI,QAAQ;AAAA,IACV,MAAM,UAAU,iBAAiB,OAAO,OAAO,SAAS,UAAU,MAAM;AAAA,IACxE,OAAO,iBAAiB,EAAE,WAAW,QAAQ;AAAA,IAE7C,OAAO,QAAQ;AAAA,EACjB;AAAA,EACA,MAAM,UAAU,iBAAiB,KAAK;AAAA,EACtC,IAAI,CAAC,SAAS;AAAA,IAAS;AAAA,EACvB,MAAM,aAAa,QAAQ,QAAQ;AAAA,EACnC,MAAM,UAAU,iBAAiB,OAAO,OAAO,UAAU;AAAA,EACzD,MAAM,QAAQ;AAAA,OACT;AAAA,IACH,QAAQ;AAAA,EACV;AAAA,EACA,OAAO,iBAAiB;AAAA,EACnB,WACF,KAAK,YAAU;AAAA,IACd,MAAM,SAAS;AAAA,GAChB,EACA,MAAM,MAAM,EAAE;AAAA,EAEjB,OAAO,QAAQ;AAAA;",
|
|
10
|
-
"debugId": "B2D2C0A1B4F5737F64756E2164756E21",
|
|
11
|
-
"names": []
|
|
12
|
-
}
|