@contractspec/bundle.library 3.9.7 → 3.9.9
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/.turbo/turbo-build.log +186 -174
- package/CHANGELOG.md +96 -0
- package/dist/components/docs/DocsIndexPage.js +2 -2
- package/dist/components/docs/docsManifest.js +1 -1
- package/dist/components/docs/getting-started/DataViewTutorialPage.js +117 -6
- package/dist/components/docs/getting-started/index.js +130 -19
- package/dist/components/docs/guides/GuideDataExchangeImportTemplatesPage.content.d.ts +6 -0
- package/dist/components/docs/guides/GuideDataExchangeImportTemplatesPage.content.js +176 -0
- package/dist/components/docs/guides/GuideDataExchangeImportTemplatesPage.d.ts +1 -0
- package/dist/components/docs/guides/GuideDataExchangeImportTemplatesPage.js +176 -0
- package/dist/components/docs/guides/GuidesIndexPage.js +2 -2
- package/dist/components/docs/guides/index.d.ts +1 -0
- package/dist/components/docs/guides/index.js +220 -46
- package/dist/components/docs/index.js +1195 -276
- package/dist/components/docs/libraries/LibrariesApplicationShellPage.content.d.ts +33 -0
- package/dist/components/docs/libraries/LibrariesApplicationShellPage.content.js +236 -0
- package/dist/components/docs/libraries/LibrariesApplicationShellPage.d.ts +1 -0
- package/dist/components/docs/libraries/LibrariesApplicationShellPage.js +236 -0
- package/dist/components/docs/libraries/LibrariesDataViewsPage.js +130 -6
- package/dist/components/docs/libraries/LibrariesDesignSystemPage.js +102 -3
- package/dist/components/docs/libraries/LibrariesOverviewPage.js +1 -1
- package/dist/components/docs/libraries/LibrariesPersonalizationPage.js +58 -4
- package/dist/components/docs/libraries/LibrariesTranslationRuntimePage.content.d.ts +10 -0
- package/dist/components/docs/libraries/LibrariesTranslationRuntimePage.content.js +43 -0
- package/dist/components/docs/libraries/LibrariesTranslationRuntimePage.d.ts +1 -0
- package/dist/components/docs/libraries/LibrariesTranslationRuntimePage.js +43 -0
- package/dist/components/docs/libraries/index.d.ts +2 -0
- package/dist/components/docs/libraries/index.js +616 -64
- package/dist/components/docs/specs/SpecsDataViewsPage.js +85 -3
- package/dist/components/docs/specs/index.js +96 -14
- package/dist/index.js +1206 -287
- package/dist/node/components/docs/DocsIndexPage.js +2 -2
- package/dist/node/components/docs/docsManifest.js +1 -1
- package/dist/node/components/docs/getting-started/DataViewTutorialPage.js +117 -6
- package/dist/node/components/docs/getting-started/index.js +130 -19
- package/dist/node/components/docs/guides/GuideDataExchangeImportTemplatesPage.content.js +175 -0
- package/dist/node/components/docs/guides/GuideDataExchangeImportTemplatesPage.js +175 -0
- package/dist/node/components/docs/guides/GuidesIndexPage.js +2 -2
- package/dist/node/components/docs/guides/index.js +220 -46
- package/dist/node/components/docs/index.js +1195 -276
- package/dist/node/components/docs/libraries/LibrariesApplicationShellPage.content.js +235 -0
- package/dist/node/components/docs/libraries/LibrariesApplicationShellPage.js +235 -0
- package/dist/node/components/docs/libraries/LibrariesDataViewsPage.js +130 -6
- package/dist/node/components/docs/libraries/LibrariesDesignSystemPage.js +102 -3
- package/dist/node/components/docs/libraries/LibrariesOverviewPage.js +1 -1
- package/dist/node/components/docs/libraries/LibrariesPersonalizationPage.js +58 -4
- package/dist/node/components/docs/libraries/LibrariesTranslationRuntimePage.content.js +42 -0
- package/dist/node/components/docs/libraries/LibrariesTranslationRuntimePage.js +42 -0
- package/dist/node/components/docs/libraries/index.js +616 -64
- package/dist/node/components/docs/specs/SpecsDataViewsPage.js +85 -3
- package/dist/node/components/docs/specs/index.js +96 -14
- package/dist/node/index.js +1206 -287
- package/package.json +98 -26
- package/src/components/docs/docsManifest.test.ts +87 -0
- package/src/components/docs/docsManifest.ts +98 -1
- package/src/components/docs/generated/docs-index.notifications.json +7 -7
- package/src/components/docs/getting-started/DataViewTutorialPage.tsx +217 -47
- package/src/components/docs/guides/GuideDataExchangeImportTemplatesPage.content.ts +185 -0
- package/src/components/docs/guides/GuideDataExchangeImportTemplatesPage.tsx +186 -0
- package/src/components/docs/guides/GuidesIndexPage.tsx +49 -42
- package/src/components/docs/guides/index.ts +1 -0
- package/src/components/docs/libraries/LibrariesApplicationShellPage.content.ts +283 -0
- package/src/components/docs/libraries/LibrariesApplicationShellPage.tsx +145 -0
- package/src/components/docs/libraries/LibrariesDataViewsPage.tsx +278 -54
- package/src/components/docs/libraries/LibrariesDesignSystemPage.tsx +244 -0
- package/src/components/docs/libraries/LibrariesOverviewPage.tsx +13 -1
- package/src/components/docs/libraries/LibrariesPersonalizationPage.tsx +141 -31
- package/src/components/docs/libraries/LibrariesTranslationRuntimePage.content.ts +78 -0
- package/src/components/docs/libraries/LibrariesTranslationRuntimePage.tsx +137 -0
- package/src/components/docs/libraries/index.ts +2 -0
- package/src/components/docs/specs/SpecsDataViewsPage.tsx +278 -116
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { CodeBlock } from '@contractspec/lib.design-system';
|
|
2
|
+
import { HStack, VStack } from '@contractspec/lib.design-system/layout';
|
|
3
|
+
import { List, ListItem } from '@contractspec/lib.design-system/list';
|
|
4
|
+
import {
|
|
5
|
+
H1,
|
|
6
|
+
H2,
|
|
7
|
+
H3,
|
|
8
|
+
P,
|
|
9
|
+
Text,
|
|
10
|
+
} from '@contractspec/lib.design-system/typography';
|
|
2
11
|
import Link from '@contractspec/lib.ui-link';
|
|
3
12
|
import { ChevronRight } from 'lucide-react';
|
|
4
13
|
|
|
@@ -45,27 +54,96 @@ export const TransactionHistory = defineDataView({
|
|
|
45
54
|
{ key: 'account', label: 'Account', dataPath: 'account', sortable: true },
|
|
46
55
|
{ key: 'owner', label: 'Owner', dataPath: 'owner', sortable: true },
|
|
47
56
|
{ key: 'status', label: 'Status', dataPath: 'status', sortable: true },
|
|
48
|
-
{
|
|
57
|
+
{
|
|
58
|
+
key: 'amount',
|
|
59
|
+
label: 'Amount',
|
|
60
|
+
dataPath: 'amount',
|
|
61
|
+
sortable: true,
|
|
62
|
+
format: { type: 'currency', currency: 'EUR', rounded: true },
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
key: 'renewalDate',
|
|
66
|
+
label: 'Renewal',
|
|
67
|
+
dataPath: 'renewalDate',
|
|
68
|
+
format: { type: 'date', dateStyle: 'medium' },
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
key: 'processingTime',
|
|
72
|
+
label: 'Processing time',
|
|
73
|
+
dataPath: 'processingMinutes',
|
|
74
|
+
format: { type: 'duration', unit: 'minute', display: 'digital' },
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
key: 'notes',
|
|
78
|
+
label: 'Notes',
|
|
79
|
+
dataPath: 'notes',
|
|
80
|
+
visibility: { minDataDepth: 'detailed' },
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
collection: {
|
|
84
|
+
viewModes: {
|
|
85
|
+
defaultMode: 'table',
|
|
86
|
+
allowedModes: ['list', 'grid', 'table'],
|
|
87
|
+
},
|
|
88
|
+
toolbar: {
|
|
89
|
+
search: true,
|
|
90
|
+
viewMode: true,
|
|
91
|
+
filters: true,
|
|
92
|
+
density: true,
|
|
93
|
+
dataDepth: true,
|
|
94
|
+
},
|
|
95
|
+
pagination: {
|
|
96
|
+
pageSize: 25,
|
|
97
|
+
pageSizeOptions: [10, 25, 50],
|
|
98
|
+
},
|
|
99
|
+
density: 'comfortable',
|
|
100
|
+
dataDepth: 'standard',
|
|
101
|
+
personalization: {
|
|
102
|
+
enabled: true,
|
|
103
|
+
persist: {
|
|
104
|
+
viewMode: true,
|
|
105
|
+
density: true,
|
|
106
|
+
dataDepth: true,
|
|
107
|
+
pageSize: true,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
filters: [
|
|
112
|
+
{ key: 'status', label: 'Status', field: 'status', type: 'enum' },
|
|
113
|
+
{
|
|
114
|
+
key: 'amount',
|
|
115
|
+
label: 'Amount',
|
|
116
|
+
field: 'amount',
|
|
117
|
+
type: 'currency',
|
|
118
|
+
valueMode: 'range',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
key: 'renewalDate',
|
|
122
|
+
label: 'Renewal',
|
|
123
|
+
field: 'renewalDate',
|
|
124
|
+
type: 'date',
|
|
125
|
+
valueMode: 'range',
|
|
126
|
+
},
|
|
49
127
|
],
|
|
50
128
|
},
|
|
51
129
|
});`;
|
|
52
130
|
|
|
53
131
|
export function DataViewTutorialPage() {
|
|
54
132
|
return (
|
|
55
|
-
<
|
|
56
|
-
<
|
|
57
|
-
<
|
|
58
|
-
<
|
|
133
|
+
<VStack className="space-y-8">
|
|
134
|
+
<VStack className="space-y-4">
|
|
135
|
+
<H1 className="font-bold text-4xl">Display Data with DataViews</H1>
|
|
136
|
+
<P className="text-lg text-muted-foreground">
|
|
59
137
|
Define a filterable, sortable transaction history view that works
|
|
60
138
|
across web and mobile without duplicating UI code.
|
|
61
|
-
</
|
|
62
|
-
</
|
|
139
|
+
</P>
|
|
140
|
+
</VStack>
|
|
63
141
|
|
|
64
|
-
<
|
|
65
|
-
<
|
|
66
|
-
<
|
|
142
|
+
<VStack className="space-y-4">
|
|
143
|
+
<H2 className="font-bold text-2xl">1. Define the underlying query</H2>
|
|
144
|
+
<P className="text-muted-foreground">
|
|
67
145
|
First, create a query operation to fetch the data:
|
|
68
|
-
</
|
|
146
|
+
</P>
|
|
69
147
|
<CodeBlock
|
|
70
148
|
language="typescript"
|
|
71
149
|
filename="lib/specs/billing/list-transactions.ts"
|
|
@@ -84,35 +162,35 @@ export const ListTransactions = defineQuery({
|
|
|
84
162
|
policy: { auth: 'user' },
|
|
85
163
|
});`}
|
|
86
164
|
/>
|
|
87
|
-
</
|
|
165
|
+
</VStack>
|
|
88
166
|
|
|
89
|
-
<
|
|
90
|
-
<
|
|
91
|
-
<
|
|
167
|
+
<VStack className="space-y-4">
|
|
168
|
+
<H2 className="font-bold text-2xl">2. Define the DataView spec</H2>
|
|
169
|
+
<P className="text-muted-foreground">
|
|
92
170
|
Wrap your query with presentation metadata:
|
|
93
|
-
</
|
|
171
|
+
</P>
|
|
94
172
|
<CodeBlock
|
|
95
173
|
language="typescript"
|
|
96
174
|
filename="lib/specs/billing/transaction-history.data-view.ts"
|
|
97
175
|
code={DATAVIEW_TUTORIAL_EXAMPLE}
|
|
98
176
|
/>
|
|
99
|
-
<
|
|
177
|
+
<P className="text-muted-foreground text-sm">
|
|
100
178
|
The live version of this pattern is available in the canonical{' '}
|
|
101
179
|
<Link
|
|
102
180
|
href="/docs/examples/data-grid-showcase"
|
|
103
181
|
className="text-[color:var(--rust)] underline underline-offset-4"
|
|
104
182
|
>
|
|
105
|
-
Data Grid Showcase
|
|
183
|
+
<Text>Data Grid Showcase</Text>
|
|
106
184
|
</Link>
|
|
107
185
|
.
|
|
108
|
-
</
|
|
109
|
-
</
|
|
186
|
+
</P>
|
|
187
|
+
</VStack>
|
|
110
188
|
|
|
111
|
-
<
|
|
112
|
-
<
|
|
113
|
-
<
|
|
189
|
+
<VStack className="space-y-4">
|
|
190
|
+
<H2 className="font-bold text-2xl">3. Render on the frontend</H2>
|
|
191
|
+
<P className="text-muted-foreground">
|
|
114
192
|
Use the runtime renderer in your React or React Native app:
|
|
115
|
-
</
|
|
193
|
+
</P>
|
|
116
194
|
<CodeBlock
|
|
117
195
|
language="tsx"
|
|
118
196
|
filename="app/dashboard/transactions/page.tsx"
|
|
@@ -133,8 +211,11 @@ export function TransactionsPage() {
|
|
|
133
211
|
<h1 className="text-3xl font-bold mb-6">Payment History</h1>
|
|
134
212
|
<DataViewRenderer
|
|
135
213
|
spec={TransactionHistory}
|
|
136
|
-
|
|
214
|
+
items={data?.items ?? []}
|
|
137
215
|
loading={isLoading}
|
|
216
|
+
defaultViewMode="table"
|
|
217
|
+
defaultDensity="comfortable"
|
|
218
|
+
defaultDataDepth="standard"
|
|
138
219
|
onFilterChange={(filters) => {
|
|
139
220
|
// refetch with new filters
|
|
140
221
|
}}
|
|
@@ -143,31 +224,120 @@ export function TransactionsPage() {
|
|
|
143
224
|
);
|
|
144
225
|
}`}
|
|
145
226
|
/>
|
|
146
|
-
</
|
|
147
|
-
|
|
148
|
-
<
|
|
149
|
-
<
|
|
150
|
-
<
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
227
|
+
</VStack>
|
|
228
|
+
|
|
229
|
+
<VStack className="space-y-4">
|
|
230
|
+
<H2 className="font-bold text-2xl">4. Add personalization</H2>
|
|
231
|
+
<P className="text-muted-foreground">
|
|
232
|
+
When the app has a user profile or behavior insights, resolve DataView
|
|
233
|
+
preferences before rendering. The renderer receives plain props;
|
|
234
|
+
personalization stays in the app/runtime boundary.
|
|
235
|
+
</P>
|
|
236
|
+
<CodeBlock
|
|
237
|
+
language="tsx"
|
|
238
|
+
filename="app/dashboard/transactions/PersonalizedTransactions.tsx"
|
|
239
|
+
code={`'use client';
|
|
240
|
+
|
|
241
|
+
import { DataViewRenderer } from '@contractspec/lib.design-system';
|
|
242
|
+
import { resolveDataViewPreferences } from '@contractspec/lib.personalization/data-view-preferences';
|
|
243
|
+
import { createBehaviorTracker } from '@contractspec/lib.personalization';
|
|
244
|
+
|
|
245
|
+
const tracker = createBehaviorTracker({
|
|
246
|
+
store,
|
|
247
|
+
context: { tenantId: tenant.id, userId: user.id },
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const resolved = resolveDataViewPreferences({
|
|
251
|
+
spec: TransactionHistory,
|
|
252
|
+
preferences: profile.canonical,
|
|
253
|
+
insights,
|
|
254
|
+
record: savedTransactionViewPreference,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
<DataViewRenderer
|
|
258
|
+
spec={TransactionHistory}
|
|
259
|
+
items={transactions}
|
|
260
|
+
defaultViewMode={resolved.viewMode}
|
|
261
|
+
defaultDensity={resolved.density}
|
|
262
|
+
defaultDataDepth={resolved.dataDepth}
|
|
263
|
+
pagination={{ page, pageSize: resolved.pageSize ?? 25, total }}
|
|
264
|
+
onViewModeChange={(viewMode) =>
|
|
265
|
+
tracker.trackDataViewInteraction({
|
|
266
|
+
dataViewKey: TransactionHistory.meta.key,
|
|
267
|
+
action: 'view_mode_changed',
|
|
268
|
+
viewMode,
|
|
269
|
+
})
|
|
270
|
+
}
|
|
271
|
+
onDataDepthChange={(dataDepth) =>
|
|
272
|
+
tracker.trackDataViewInteraction({
|
|
273
|
+
dataViewKey: TransactionHistory.meta.key,
|
|
274
|
+
action: 'data_depth_changed',
|
|
275
|
+
dataDepth,
|
|
276
|
+
})
|
|
277
|
+
}
|
|
278
|
+
/>;`}
|
|
279
|
+
/>
|
|
280
|
+
</VStack>
|
|
281
|
+
|
|
282
|
+
<VStack className="card-subtle space-y-4 p-6">
|
|
283
|
+
<H3 className="font-bold">Why DataViews?</H3>
|
|
284
|
+
<List className="space-y-2 text-muted-foreground text-sm">
|
|
285
|
+
<ListItem>
|
|
286
|
+
<Text>
|
|
287
|
+
Same spec renders on web (React) and mobile (React Native)
|
|
288
|
+
</Text>
|
|
289
|
+
</ListItem>
|
|
290
|
+
<ListItem>
|
|
291
|
+
<Text>Filters, sorting, and pagination handled automatically</Text>
|
|
292
|
+
</ListItem>
|
|
293
|
+
<ListItem>
|
|
294
|
+
<Text>
|
|
295
|
+
Column visibility, pinning, resizing, and row expansion stay
|
|
296
|
+
contract-driven
|
|
297
|
+
</Text>
|
|
298
|
+
</ListItem>
|
|
299
|
+
<ListItem>
|
|
300
|
+
<Text>
|
|
301
|
+
List, grid, and table modes can share one collection config with
|
|
302
|
+
toolbar and pagination defaults
|
|
303
|
+
</Text>
|
|
304
|
+
</ListItem>
|
|
305
|
+
<ListItem>
|
|
306
|
+
<Text>
|
|
307
|
+
Data depth lets summary screens hide detailed fields without
|
|
308
|
+
forking the spec
|
|
309
|
+
</Text>
|
|
310
|
+
</ListItem>
|
|
311
|
+
<ListItem>
|
|
312
|
+
<Text>
|
|
313
|
+
Typed format rules for numbers, percent values, currency, dates,
|
|
314
|
+
times, datetimes, and durations applied consistently
|
|
315
|
+
</Text>
|
|
316
|
+
</ListItem>
|
|
317
|
+
<ListItem>
|
|
318
|
+
<Text>
|
|
319
|
+
Personalization helpers can seed preferred view mode, density,
|
|
320
|
+
data depth, and page size from user preferences or behavior
|
|
321
|
+
insights
|
|
322
|
+
</Text>
|
|
323
|
+
</ListItem>
|
|
324
|
+
<ListItem>
|
|
325
|
+
<Text>Export to CSV/PDF using the same spec</Text>
|
|
326
|
+
</ListItem>
|
|
327
|
+
<ListItem>
|
|
328
|
+
<Text>A/B test different layouts without touching the backend</Text>
|
|
329
|
+
</ListItem>
|
|
330
|
+
</List>
|
|
331
|
+
</VStack>
|
|
332
|
+
|
|
333
|
+
<HStack className="items-center gap-4 pt-4">
|
|
164
334
|
<Link href="/docs/libraries/data-views" className="btn-primary">
|
|
165
|
-
DataView API Reference <ChevronRight size={16} />
|
|
335
|
+
<Text>DataView API Reference</Text> <ChevronRight size={16} />
|
|
166
336
|
</Link>
|
|
167
337
|
<Link href="/docs/specs/workflows" className="btn-ghost">
|
|
168
|
-
Next: Workflows
|
|
338
|
+
<Text>Next: Workflows</Text>
|
|
169
339
|
</Link>
|
|
170
|
-
</
|
|
171
|
-
</
|
|
340
|
+
</HStack>
|
|
341
|
+
</VStack>
|
|
172
342
|
);
|
|
173
343
|
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
export const accountImportTemplateCode = `import {
|
|
2
|
+
createImportPlan,
|
|
3
|
+
createRecordBatch,
|
|
4
|
+
defineDataExchangeTemplate,
|
|
5
|
+
previewImport,
|
|
6
|
+
} from "@contractspec/lib.data-exchange-core";
|
|
7
|
+
import { defineSchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
|
|
8
|
+
|
|
9
|
+
const AccountImportSchema = defineSchemaModel({
|
|
10
|
+
name: "AccountImport",
|
|
11
|
+
fields: {
|
|
12
|
+
id: { type: ScalarTypeEnum.ID(), isOptional: false },
|
|
13
|
+
status: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
14
|
+
amount: { type: ScalarTypeEnum.Float_unsecure(), isOptional: false },
|
|
15
|
+
active: { type: ScalarTypeEnum.Boolean(), isOptional: false },
|
|
16
|
+
tags: { type: ScalarTypeEnum.JSON(), isOptional: true },
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const accountImportTemplate = defineDataExchangeTemplate({
|
|
21
|
+
key: "accounts.import",
|
|
22
|
+
version: "1.0.0",
|
|
23
|
+
title: "Account import",
|
|
24
|
+
columns: [
|
|
25
|
+
{
|
|
26
|
+
key: "id",
|
|
27
|
+
label: "Account ID",
|
|
28
|
+
targetField: "id",
|
|
29
|
+
required: true,
|
|
30
|
+
sourceAliases: ["Account Identifier", "External ID", "No compte"],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
key: "status",
|
|
34
|
+
label: "Status",
|
|
35
|
+
targetField: "status",
|
|
36
|
+
required: true,
|
|
37
|
+
sourceAliases: ["Statut", "State"],
|
|
38
|
+
format: { kind: "text", trim: true, case: "lowercase" },
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
key: "amount",
|
|
42
|
+
label: "Amount",
|
|
43
|
+
targetField: "amount",
|
|
44
|
+
required: true,
|
|
45
|
+
sourceAliases: ["Montant", "Balance"],
|
|
46
|
+
format: { kind: "number", decimalSeparator: ",", thousandsSeparator: "." },
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
key: "active",
|
|
50
|
+
label: "Active",
|
|
51
|
+
targetField: "active",
|
|
52
|
+
sourceAliases: ["Actif", "Enabled"],
|
|
53
|
+
format: { kind: "boolean", trueValues: ["yes", "oui"], falseValues: ["no", "non"] },
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
key: "tags",
|
|
57
|
+
label: "Tags",
|
|
58
|
+
targetField: "tags",
|
|
59
|
+
format: { kind: "split", delimiter: ";" },
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const sourceBatch = createRecordBatch([
|
|
65
|
+
{
|
|
66
|
+
"No compte": "acc-1",
|
|
67
|
+
Statut: " Active ",
|
|
68
|
+
Montant: "1.234,50",
|
|
69
|
+
Actif: "oui",
|
|
70
|
+
Tags: "vip; beta",
|
|
71
|
+
},
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
const preview = previewImport(
|
|
75
|
+
createImportPlan({
|
|
76
|
+
source: { kind: "memory", batch: sourceBatch, format: "csv" },
|
|
77
|
+
target: { kind: "memory", format: "json" },
|
|
78
|
+
schema: AccountImportSchema,
|
|
79
|
+
sourceBatch,
|
|
80
|
+
template: accountImportTemplate,
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
console.log(preview.plan.mappingSource); // "template"
|
|
85
|
+
console.log(preview.normalizedRecords[0]);`;
|
|
86
|
+
|
|
87
|
+
export const serverDryRunCode = `import { defineDataExchangeTemplate } from "@contractspec/lib.data-exchange-core";
|
|
88
|
+
import { dryRunImport, executeImport } from "@contractspec/lib.data-exchange-server";
|
|
89
|
+
|
|
90
|
+
const template = defineDataExchangeTemplate({
|
|
91
|
+
key: "accounts.import",
|
|
92
|
+
version: "1.0.0",
|
|
93
|
+
columns: [
|
|
94
|
+
{ key: "id", label: "Account ID", targetField: "id", required: true, sourceAliases: ["Account Identifier"] },
|
|
95
|
+
{ key: "amount", label: "Amount", targetField: "amount", format: { kind: "currency", currencySymbol: "€", decimalSeparator: "," } },
|
|
96
|
+
],
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const partnerSource = {
|
|
100
|
+
kind: "file",
|
|
101
|
+
path: "partner-accounts.csv",
|
|
102
|
+
format: "csv",
|
|
103
|
+
codecOptions: { csv: { delimiter: ";", skipRows: 1 } },
|
|
104
|
+
} as const;
|
|
105
|
+
|
|
106
|
+
const formatProfile = {
|
|
107
|
+
columns: {
|
|
108
|
+
amount: { kind: "currency", currencySymbol: "€", decimalSeparator: "," },
|
|
109
|
+
},
|
|
110
|
+
} as const;
|
|
111
|
+
|
|
112
|
+
const preview = await dryRunImport({
|
|
113
|
+
source: partnerSource,
|
|
114
|
+
target: { kind: "memory", format: "json" },
|
|
115
|
+
schema: AccountImportSchema,
|
|
116
|
+
template,
|
|
117
|
+
formatProfile,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const blockingIssues = preview.issues.filter((issue) => issue.severity === "error");
|
|
121
|
+
|
|
122
|
+
if (blockingIssues.length === 0) {
|
|
123
|
+
await executeImport({
|
|
124
|
+
source: partnerSource,
|
|
125
|
+
target: { kind: "memory", format: "json" },
|
|
126
|
+
schema: AccountImportSchema,
|
|
127
|
+
template,
|
|
128
|
+
formatProfile,
|
|
129
|
+
});
|
|
130
|
+
}`;
|
|
131
|
+
|
|
132
|
+
export const clientReviewCode = `"use client";
|
|
133
|
+
|
|
134
|
+
import { useDataExchangeController } from "@contractspec/lib.data-exchange-client";
|
|
135
|
+
|
|
136
|
+
export function ImportMappingReview({ preview }) {
|
|
137
|
+
const controller = useDataExchangeController({ preview });
|
|
138
|
+
const replacementSourceColumn = controller.model.ignoredSourceColumns[0];
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<section>
|
|
142
|
+
{controller.model.templateRows.map((row) => (
|
|
143
|
+
<button
|
|
144
|
+
key={row.id}
|
|
145
|
+
type="button"
|
|
146
|
+
disabled={!replacementSourceColumn}
|
|
147
|
+
onClick={() => {
|
|
148
|
+
if (!replacementSourceColumn) return;
|
|
149
|
+
controller.selectAlias(row.targetField, replacementSourceColumn);
|
|
150
|
+
}}
|
|
151
|
+
>
|
|
152
|
+
{row.label}: {row.sourceField || "Unmatched"} -> {row.targetField}
|
|
153
|
+
{row.required ? " required" : ""}
|
|
154
|
+
{row.formatLabel ? \` (\${row.formatLabel})\` : ""}
|
|
155
|
+
</button>
|
|
156
|
+
))}
|
|
157
|
+
{controller.model.unmatchedRequiredRows.length > 0 ? (
|
|
158
|
+
<p>Resolve required columns before import.</p>
|
|
159
|
+
) : null}
|
|
160
|
+
</section>
|
|
161
|
+
);
|
|
162
|
+
}`;
|
|
163
|
+
|
|
164
|
+
export const developerPrompt = `You are adding an import flow to a ContractSpec app.
|
|
165
|
+
|
|
166
|
+
Define a reusable data-exchange template for this canonical schema:
|
|
167
|
+
- target fields, required flags, and display labels
|
|
168
|
+
- known partner column aliases
|
|
169
|
+
- value formats for numbers, dates, booleans, JSON, split/join lists, currency, and percentages
|
|
170
|
+
|
|
171
|
+
Wire the template into core preview planning and server dry-run execution. Keep explicit mappings higher precedence than template resolution. Return the template, preview call, server dry-run call, and tests for alias matching plus localized formatting.`;
|
|
172
|
+
|
|
173
|
+
export const partnerPrompt = `A partner sent a CSV/JSON/XML file that does not match our recommended import template.
|
|
174
|
+
|
|
175
|
+
Compare the incoming headers and value samples against this ContractSpec data-exchange template. Propose:
|
|
176
|
+
- source-to-target column matches with confidence
|
|
177
|
+
- missing required target fields
|
|
178
|
+
- ignored source columns
|
|
179
|
+
- format overrides for localized numbers, booleans, dates, JSON, split/join lists, currency, or percentages
|
|
180
|
+
|
|
181
|
+
Do not execute the import. Produce a dry-run plan and the user-facing review copy.`;
|
|
182
|
+
|
|
183
|
+
export const verificationCode = `cd packages/libs/data-exchange-core && bun test && bun run typecheck && bun run lint:check
|
|
184
|
+
cd packages/libs/data-exchange-client && bun test && bun run typecheck && bun run lint:check
|
|
185
|
+
cd packages/libs/data-exchange-server && bun test && bun run typecheck && bun run lint:check`;
|