@contractspec/example.integration-hub 3.7.6 → 3.8.2

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.
Files changed (57) hide show
  1. package/README.md +73 -183
  2. package/dist/connection/index.d.ts +1 -1
  3. package/dist/docs/index.js +2 -1
  4. package/dist/docs/integration-hub.docblock.js +2 -1
  5. package/dist/events.js +1 -1
  6. package/dist/index.d.ts +5 -4
  7. package/dist/index.js +1243 -749
  8. package/dist/integration/index.d.ts +1 -1
  9. package/dist/integration-hub.feature.js +202 -0
  10. package/dist/node/docs/index.js +2 -1
  11. package/dist/node/docs/integration-hub.docblock.js +2 -1
  12. package/dist/node/events.js +1 -1
  13. package/dist/node/index.js +1243 -749
  14. package/dist/node/integration-hub.feature.js +202 -0
  15. package/dist/node/ui/IntegrationDashboard.js +654 -180
  16. package/dist/node/ui/IntegrationDashboard.visualizations.js +250 -0
  17. package/dist/node/ui/hooks/index.js +1 -1
  18. package/dist/node/ui/hooks/useIntegrationData.js +1 -1
  19. package/dist/node/ui/index.js +970 -485
  20. package/dist/node/ui/renderers/index.js +216 -5
  21. package/dist/node/ui/renderers/integration.markdown.js +216 -5
  22. package/dist/node/ui/tables/ConnectionsTable.js +211 -0
  23. package/dist/node/ui/tables/IntegrationTables.js +361 -0
  24. package/dist/node/ui/tables/SyncConfigsTable.js +230 -0
  25. package/dist/node/ui/tables/integration-table.shared.js +84 -0
  26. package/dist/node/visualizations/catalog.js +137 -0
  27. package/dist/node/visualizations/index.js +211 -0
  28. package/dist/node/visualizations/selectors.js +204 -0
  29. package/dist/sync/index.d.ts +3 -3
  30. package/dist/ui/IntegrationDashboard.js +654 -180
  31. package/dist/ui/IntegrationDashboard.visualizations.d.ts +6 -0
  32. package/dist/ui/IntegrationDashboard.visualizations.js +251 -0
  33. package/dist/ui/hooks/index.d.ts +1 -1
  34. package/dist/ui/hooks/index.js +1 -1
  35. package/dist/ui/hooks/useIntegrationData.js +1 -1
  36. package/dist/ui/index.d.ts +2 -2
  37. package/dist/ui/index.js +970 -485
  38. package/dist/ui/renderers/index.d.ts +1 -1
  39. package/dist/ui/renderers/index.js +216 -5
  40. package/dist/ui/renderers/integration.markdown.js +216 -5
  41. package/dist/ui/tables/ConnectionsTable.d.ts +4 -0
  42. package/dist/ui/tables/ConnectionsTable.js +212 -0
  43. package/dist/ui/tables/IntegrationTables.d.ts +2 -0
  44. package/dist/ui/tables/IntegrationTables.js +362 -0
  45. package/dist/ui/tables/IntegrationTables.smoke.test.d.ts +1 -0
  46. package/dist/ui/tables/SyncConfigsTable.d.ts +4 -0
  47. package/dist/ui/tables/SyncConfigsTable.js +231 -0
  48. package/dist/ui/tables/integration-table.shared.d.ts +18 -0
  49. package/dist/ui/tables/integration-table.shared.js +85 -0
  50. package/dist/visualizations/catalog.d.ts +11 -0
  51. package/dist/visualizations/catalog.js +138 -0
  52. package/dist/visualizations/index.d.ts +2 -0
  53. package/dist/visualizations/index.js +212 -0
  54. package/dist/visualizations/selectors.d.ts +10 -0
  55. package/dist/visualizations/selectors.js +205 -0
  56. package/dist/visualizations/selectors.test.d.ts +1 -0
  57. package/package.json +110 -12
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  // src/ui/hooks/useIntegrationData.ts
3
- import { useCallback, useEffect, useState } from "react";
4
3
  import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
4
+ import { useCallback, useEffect, useState } from "react";
5
5
  "use client";
6
6
  function useIntegrationData(projectId = "local-project") {
7
7
  const { handlers } = useTemplateRuntime();
@@ -51,9 +51,257 @@ function useIntegrationData(projectId = "local-project") {
51
51
  };
52
52
  }
53
53
 
54
+ // src/visualizations/catalog.ts
55
+ import {
56
+ defineVisualization,
57
+ VisualizationRegistry
58
+ } from "@contractspec/lib.contracts-spec/visualizations";
59
+ var INTEGRATION_LIST_REF = {
60
+ key: "integration.list",
61
+ version: "1.0.0"
62
+ };
63
+ var CONNECTION_LIST_REF = {
64
+ key: "integration.connection.list",
65
+ version: "1.0.0"
66
+ };
67
+ var SYNC_CONFIG_REF = {
68
+ key: "integration.syncConfig.list",
69
+ version: "1.0.0"
70
+ };
71
+ var META = {
72
+ version: "1.0.0",
73
+ domain: "integration",
74
+ stability: "experimental",
75
+ owners: ["@example.integration-hub"],
76
+ tags: ["integration", "visualization", "sync"]
77
+ };
78
+ var IntegrationTypeVisualization = defineVisualization({
79
+ meta: {
80
+ ...META,
81
+ key: "integration-hub.visualization.integration-types",
82
+ title: "Integration Types",
83
+ description: "Distribution of configured integration categories.",
84
+ goal: "Show where integration coverage is concentrated.",
85
+ context: "Integration overview."
86
+ },
87
+ source: { primary: INTEGRATION_LIST_REF, resultPath: "data" },
88
+ visualization: {
89
+ kind: "pie",
90
+ nameDimension: "type",
91
+ valueMeasure: "count",
92
+ dimensions: [
93
+ { key: "type", label: "Type", dataPath: "type", type: "category" }
94
+ ],
95
+ measures: [
96
+ { key: "count", label: "Count", dataPath: "count", format: "number" }
97
+ ],
98
+ table: { caption: "Integration counts by type." }
99
+ }
100
+ });
101
+ var ConnectionStatusVisualization = defineVisualization({
102
+ meta: {
103
+ ...META,
104
+ key: "integration-hub.visualization.connection-status",
105
+ title: "Connection Status",
106
+ description: "Status distribution across configured connections.",
107
+ goal: "Highlight connection health and instability.",
108
+ context: "Connection monitoring."
109
+ },
110
+ source: { primary: CONNECTION_LIST_REF, resultPath: "data" },
111
+ visualization: {
112
+ kind: "cartesian",
113
+ variant: "bar",
114
+ xDimension: "status",
115
+ yMeasures: ["count"],
116
+ dimensions: [
117
+ { key: "status", label: "Status", dataPath: "status", type: "category" }
118
+ ],
119
+ measures: [
120
+ {
121
+ key: "count",
122
+ label: "Connections",
123
+ dataPath: "count",
124
+ format: "number",
125
+ color: "#1d4ed8"
126
+ }
127
+ ],
128
+ table: { caption: "Connection counts by status." }
129
+ }
130
+ });
131
+ var HealthySyncMetricVisualization = defineVisualization({
132
+ meta: {
133
+ ...META,
134
+ key: "integration-hub.visualization.sync-healthy",
135
+ title: "Healthy Syncs",
136
+ description: "Sync configurations currently healthy or recently successful.",
137
+ goal: "Summarize healthy synchronization capacity.",
138
+ context: "Sync-state comparison."
139
+ },
140
+ source: { primary: SYNC_CONFIG_REF, resultPath: "data" },
141
+ visualization: {
142
+ kind: "metric",
143
+ measure: "value",
144
+ measures: [
145
+ { key: "value", label: "Syncs", dataPath: "value", format: "number" }
146
+ ],
147
+ table: { caption: "Healthy sync count." }
148
+ }
149
+ });
150
+ var AttentionSyncMetricVisualization = defineVisualization({
151
+ meta: {
152
+ ...META,
153
+ key: "integration-hub.visualization.sync-attention",
154
+ title: "Attention Needed",
155
+ description: "Sync configurations paused, failing, or otherwise needing review.",
156
+ goal: "Summarize syncs needing action.",
157
+ context: "Sync-state comparison."
158
+ },
159
+ source: { primary: SYNC_CONFIG_REF, resultPath: "data" },
160
+ visualization: {
161
+ kind: "metric",
162
+ measure: "value",
163
+ measures: [
164
+ { key: "value", label: "Syncs", dataPath: "value", format: "number" }
165
+ ],
166
+ table: { caption: "Syncs requiring attention." }
167
+ }
168
+ });
169
+ var IntegrationVisualizationSpecs = [
170
+ IntegrationTypeVisualization,
171
+ ConnectionStatusVisualization,
172
+ HealthySyncMetricVisualization,
173
+ AttentionSyncMetricVisualization
174
+ ];
175
+ var IntegrationVisualizationRegistry = new VisualizationRegistry([
176
+ ...IntegrationVisualizationSpecs
177
+ ]);
178
+ var IntegrationVisualizationRefs = IntegrationVisualizationSpecs.map((spec) => ({
179
+ key: spec.meta.key,
180
+ version: spec.meta.version
181
+ }));
182
+
183
+ // src/visualizations/selectors.ts
184
+ function isHealthySync(status) {
185
+ return status === "ACTIVE" || status === "SUCCESS";
186
+ }
187
+ function createIntegrationVisualizationSections(integrations, connections, syncConfigs) {
188
+ const integrationTypes = new Map;
189
+ const connectionStatuses = new Map;
190
+ let healthySyncs = 0;
191
+ let attentionSyncs = 0;
192
+ for (const integration of integrations) {
193
+ integrationTypes.set(integration.type, (integrationTypes.get(integration.type) ?? 0) + 1);
194
+ }
195
+ for (const connection of connections) {
196
+ connectionStatuses.set(connection.status, (connectionStatuses.get(connection.status) ?? 0) + 1);
197
+ }
198
+ for (const syncConfig of syncConfigs) {
199
+ if (isHealthySync(syncConfig.status)) {
200
+ healthySyncs += 1;
201
+ } else {
202
+ attentionSyncs += 1;
203
+ }
204
+ }
205
+ const primaryItems = [
206
+ {
207
+ key: "integration-types",
208
+ spec: IntegrationTypeVisualization,
209
+ data: {
210
+ data: Array.from(integrationTypes.entries()).map(([type, count]) => ({
211
+ type,
212
+ count
213
+ }))
214
+ },
215
+ title: "Integration Types",
216
+ description: "Configured integrations grouped by category.",
217
+ height: 260
218
+ },
219
+ {
220
+ key: "connection-status",
221
+ spec: ConnectionStatusVisualization,
222
+ data: {
223
+ data: Array.from(connectionStatuses.entries()).map(([status, count]) => ({
224
+ status,
225
+ count
226
+ }))
227
+ },
228
+ title: "Connection Status",
229
+ description: "Operational health across current connections."
230
+ }
231
+ ];
232
+ const comparisonItems = [
233
+ {
234
+ key: "healthy-syncs",
235
+ spec: HealthySyncMetricVisualization,
236
+ data: { data: [{ value: healthySyncs }] },
237
+ title: "Healthy Syncs",
238
+ description: "Active or recently successful sync configurations.",
239
+ height: 200
240
+ },
241
+ {
242
+ key: "attention-syncs",
243
+ spec: AttentionSyncMetricVisualization,
244
+ data: { data: [{ value: attentionSyncs }] },
245
+ title: "Attention Needed",
246
+ description: "Paused, failed, or degraded sync configurations.",
247
+ height: 200
248
+ }
249
+ ];
250
+ return {
251
+ primaryItems,
252
+ comparisonItems
253
+ };
254
+ }
255
+ // src/ui/IntegrationDashboard.visualizations.tsx
256
+ import {
257
+ ComparisonView,
258
+ VisualizationCard,
259
+ VisualizationGrid
260
+ } from "@contractspec/lib.design-system";
261
+ import { jsxDEV } from "react/jsx-dev-runtime";
262
+ "use client";
263
+ function IntegrationVisualizationOverview({
264
+ integrations,
265
+ connections,
266
+ syncConfigs
267
+ }) {
268
+ const { primaryItems, comparisonItems } = createIntegrationVisualizationSections(integrations, connections, syncConfigs);
269
+ return /* @__PURE__ */ jsxDEV("section", {
270
+ className: "space-y-4",
271
+ children: [
272
+ /* @__PURE__ */ jsxDEV("div", {
273
+ children: [
274
+ /* @__PURE__ */ jsxDEV("h3", {
275
+ className: "font-semibold text-lg",
276
+ children: "Integration Visualizations"
277
+ }, undefined, false, undefined, this),
278
+ /* @__PURE__ */ jsxDEV("p", {
279
+ className: "text-muted-foreground text-sm",
280
+ children: "Contract-backed charts for integration coverage and sync health."
281
+ }, undefined, false, undefined, this)
282
+ ]
283
+ }, undefined, true, undefined, this),
284
+ /* @__PURE__ */ jsxDEV(VisualizationGrid, {
285
+ children: primaryItems.map((item) => /* @__PURE__ */ jsxDEV(VisualizationCard, {
286
+ data: item.data,
287
+ description: item.description,
288
+ height: item.height,
289
+ spec: item.spec,
290
+ title: item.title
291
+ }, item.key, false, undefined, this))
292
+ }, undefined, false, undefined, this),
293
+ /* @__PURE__ */ jsxDEV(ComparisonView, {
294
+ description: "Comparison surface for healthy versus attention-needed syncs.",
295
+ items: comparisonItems,
296
+ title: "Sync-State Comparison"
297
+ }, undefined, false, undefined, this)
298
+ ]
299
+ }, undefined, true, undefined, this);
300
+ }
301
+
54
302
  // src/ui/IntegrationHubChat.tsx
55
303
  import { ChatWithSidebar } from "@contractspec/module.ai-chat";
56
- import { jsxDEV } from "react/jsx-dev-runtime";
304
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
57
305
  "use client";
58
306
  var DEFAULT_SUGGESTIONS = [
59
307
  "List my integrations",
@@ -69,9 +317,9 @@ function IntegrationHubChat({
69
317
  systemPrompt = DEFAULT_SYSTEM_PROMPT,
70
318
  className
71
319
  }) {
72
- return /* @__PURE__ */ jsxDEV("div", {
320
+ return /* @__PURE__ */ jsxDEV2("div", {
73
321
  className: className ?? "flex h-[500px] flex-col",
74
- children: /* @__PURE__ */ jsxDEV(ChatWithSidebar, {
322
+ children: /* @__PURE__ */ jsxDEV2(ChatWithSidebar, {
75
323
  className: "flex-1",
76
324
  systemPrompt,
77
325
  proxyUrl,
@@ -83,16 +331,373 @@ function IntegrationHubChat({
83
331
  }, undefined, false, undefined, this);
84
332
  }
85
333
 
334
+ // src/ui/tables/integration-table.shared.tsx
335
+ import { Button } from "@contractspec/lib.design-system";
336
+ import { Badge } from "@contractspec/lib.ui-kit-web/ui/badge";
337
+ import { HStack } from "@contractspec/lib.ui-kit-web/ui/stack";
338
+ import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
339
+ "use client";
340
+ var STATUS_VARIANTS = {
341
+ ACTIVE: "default",
342
+ CONNECTED: "default",
343
+ SUCCESS: "default",
344
+ PENDING: "secondary",
345
+ PAUSED: "secondary",
346
+ ERROR: "destructive",
347
+ DISCONNECTED: "outline"
348
+ };
349
+ function formatDateTime(value) {
350
+ return value ? value.toLocaleString() : "Never";
351
+ }
352
+ function formatJson(value) {
353
+ return value ? JSON.stringify(value, null, 2) : "No configuration";
354
+ }
355
+ function StatusBadge({ status }) {
356
+ return /* @__PURE__ */ jsxDEV3(Badge, {
357
+ variant: STATUS_VARIANTS[status] ?? "outline",
358
+ children: status
359
+ }, undefined, false, undefined, this);
360
+ }
361
+ function IntegrationTableToolbar({
362
+ controller,
363
+ label,
364
+ toggleColumnId,
365
+ toggleVisibleLabel,
366
+ toggleHiddenLabel,
367
+ pinColumnId,
368
+ pinLabel,
369
+ resizeColumnId,
370
+ resizeLabel
371
+ }) {
372
+ const firstRow = controller.rows[0];
373
+ const toggleColumn = controller.columns.find((column) => column.id === toggleColumnId);
374
+ const pinColumn = controller.columns.find((column) => column.id === pinColumnId);
375
+ const resizeColumn = controller.columns.find((column) => column.id === resizeColumnId);
376
+ const pinTarget = pinColumn?.pinState === "left" ? false : "left";
377
+ return /* @__PURE__ */ jsxDEV3(HStack, {
378
+ gap: "sm",
379
+ className: "flex-wrap",
380
+ children: [
381
+ /* @__PURE__ */ jsxDEV3(Badge, {
382
+ variant: "outline",
383
+ children: label
384
+ }, undefined, false, undefined, this),
385
+ /* @__PURE__ */ jsxDEV3(Button, {
386
+ variant: "outline",
387
+ size: "sm",
388
+ onPress: () => firstRow?.toggleExpanded?.(!firstRow?.isExpanded),
389
+ children: "Expand First Row"
390
+ }, undefined, false, undefined, this),
391
+ /* @__PURE__ */ jsxDEV3(Button, {
392
+ variant: "outline",
393
+ size: "sm",
394
+ onPress: () => toggleColumn?.toggleVisibility?.(!toggleColumn?.visible),
395
+ children: toggleColumn?.visible ? toggleVisibleLabel : toggleHiddenLabel
396
+ }, undefined, false, undefined, this),
397
+ /* @__PURE__ */ jsxDEV3(Button, {
398
+ variant: "outline",
399
+ size: "sm",
400
+ onPress: () => pinColumn?.pin?.(pinTarget),
401
+ children: pinColumn?.pinState === "left" ? `Unpin ${pinLabel}` : `Pin ${pinLabel}`
402
+ }, undefined, false, undefined, this),
403
+ /* @__PURE__ */ jsxDEV3(Button, {
404
+ variant: "outline",
405
+ size: "sm",
406
+ onPress: () => resizeColumn?.resizeBy?.(40),
407
+ children: resizeLabel
408
+ }, undefined, false, undefined, this)
409
+ ]
410
+ }, undefined, true, undefined, this);
411
+ }
412
+
413
+ // src/ui/tables/ConnectionsTable.tsx
414
+ import { DataTable } from "@contractspec/lib.design-system";
415
+ import { useContractTable } from "@contractspec/lib.presentation-runtime-react";
416
+ import { VStack } from "@contractspec/lib.ui-kit-web/ui/stack";
417
+ import { Text } from "@contractspec/lib.ui-kit-web/ui/text";
418
+ import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
419
+ "use client";
420
+ function ConnectionsTable({
421
+ connections
422
+ }) {
423
+ const controller = useContractTable({
424
+ data: connections,
425
+ columns: [
426
+ {
427
+ id: "connection",
428
+ header: "Connection",
429
+ label: "Connection",
430
+ accessor: (connection) => connection.name,
431
+ cell: ({ item }) => /* @__PURE__ */ jsxDEV4(VStack, {
432
+ gap: "xs",
433
+ children: [
434
+ /* @__PURE__ */ jsxDEV4(Text, {
435
+ className: "font-medium text-sm",
436
+ children: item.name
437
+ }, undefined, false, undefined, this),
438
+ /* @__PURE__ */ jsxDEV4(Text, {
439
+ className: "text-muted-foreground text-xs",
440
+ children: [
441
+ "Created ",
442
+ item.createdAt.toLocaleDateString()
443
+ ]
444
+ }, undefined, true, undefined, this)
445
+ ]
446
+ }, undefined, true, undefined, this),
447
+ size: 240,
448
+ minSize: 180,
449
+ canSort: true,
450
+ canPin: true,
451
+ canResize: true
452
+ },
453
+ {
454
+ id: "status",
455
+ header: "Status",
456
+ label: "Status",
457
+ accessorKey: "status",
458
+ cell: ({ value }) => /* @__PURE__ */ jsxDEV4(StatusBadge, {
459
+ status: String(value)
460
+ }, undefined, false, undefined, this),
461
+ size: 150,
462
+ canSort: true,
463
+ canPin: true,
464
+ canResize: true
465
+ },
466
+ {
467
+ id: "lastSyncAt",
468
+ header: "Last Sync",
469
+ label: "Last Sync",
470
+ accessor: (connection) => connection.lastSyncAt?.getTime() ?? 0,
471
+ cell: ({ item }) => formatDateTime(item.lastSyncAt),
472
+ size: 200,
473
+ canSort: true,
474
+ canHide: true,
475
+ canResize: true
476
+ },
477
+ {
478
+ id: "errorMessage",
479
+ header: "Errors",
480
+ label: "Errors",
481
+ accessor: (connection) => connection.errorMessage ?? "",
482
+ cell: ({ value }) => String(value || "No errors"),
483
+ size: 240,
484
+ canHide: true,
485
+ canResize: true
486
+ }
487
+ ],
488
+ initialState: {
489
+ pagination: { pageIndex: 0, pageSize: 3 },
490
+ columnVisibility: { errorMessage: false },
491
+ columnPinning: { left: ["connection"], right: [] }
492
+ },
493
+ renderExpandedContent: (connection) => /* @__PURE__ */ jsxDEV4(VStack, {
494
+ gap: "sm",
495
+ className: "py-2",
496
+ children: [
497
+ /* @__PURE__ */ jsxDEV4(Text, {
498
+ className: "font-medium text-sm",
499
+ children: "Credentials"
500
+ }, undefined, false, undefined, this),
501
+ /* @__PURE__ */ jsxDEV4("pre", {
502
+ className: "overflow-auto rounded-md bg-muted/40 p-3 text-xs",
503
+ children: formatJson(connection.credentials)
504
+ }, undefined, false, undefined, this),
505
+ /* @__PURE__ */ jsxDEV4(Text, {
506
+ className: "font-medium text-sm",
507
+ children: "Config"
508
+ }, undefined, false, undefined, this),
509
+ /* @__PURE__ */ jsxDEV4("pre", {
510
+ className: "overflow-auto rounded-md bg-muted/40 p-3 text-xs",
511
+ children: formatJson(connection.config)
512
+ }, undefined, false, undefined, this),
513
+ /* @__PURE__ */ jsxDEV4(Text, {
514
+ className: "text-muted-foreground text-sm",
515
+ children: connection.errorMessage ?? "No sync errors recorded."
516
+ }, undefined, false, undefined, this)
517
+ ]
518
+ }, undefined, true, undefined, this),
519
+ getCanExpand: () => true
520
+ });
521
+ return /* @__PURE__ */ jsxDEV4(DataTable, {
522
+ controller,
523
+ title: "Connections",
524
+ description: "Client-mode ContractSpec table with visibility, pinning, resizing, and expanded diagnostics.",
525
+ toolbar: /* @__PURE__ */ jsxDEV4(IntegrationTableToolbar, {
526
+ controller,
527
+ label: `${connections.length} total connections`,
528
+ toggleColumnId: "errorMessage",
529
+ toggleVisibleLabel: "Hide Error Column",
530
+ toggleHiddenLabel: "Show Error Column",
531
+ pinColumnId: "status",
532
+ pinLabel: "Status",
533
+ resizeColumnId: "connection",
534
+ resizeLabel: "Widen Connection"
535
+ }, undefined, false, undefined, this),
536
+ emptyState: /* @__PURE__ */ jsxDEV4("div", {
537
+ className: "rounded-md border border-dashed p-8 text-center text-muted-foreground text-sm",
538
+ children: "No connections found"
539
+ }, undefined, false, undefined, this)
540
+ }, undefined, false, undefined, this);
541
+ }
542
+
543
+ // src/ui/tables/SyncConfigsTable.tsx
544
+ import { DataTable as DataTable2 } from "@contractspec/lib.design-system";
545
+ import { useContractTable as useContractTable2 } from "@contractspec/lib.presentation-runtime-react";
546
+ import { VStack as VStack2 } from "@contractspec/lib.ui-kit-web/ui/stack";
547
+ import { Text as Text2 } from "@contractspec/lib.ui-kit-web/ui/text";
548
+ import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
549
+ "use client";
550
+ function SyncConfigsTable({
551
+ syncConfigs
552
+ }) {
553
+ const controller = useContractTable2({
554
+ data: syncConfigs,
555
+ columns: [
556
+ {
557
+ id: "sync",
558
+ header: "Sync Config",
559
+ label: "Sync Config",
560
+ accessor: (sync) => sync.name,
561
+ cell: ({ item }) => /* @__PURE__ */ jsxDEV5(VStack2, {
562
+ gap: "xs",
563
+ children: [
564
+ /* @__PURE__ */ jsxDEV5(Text2, {
565
+ className: "font-medium text-sm",
566
+ children: item.name
567
+ }, undefined, false, undefined, this),
568
+ /* @__PURE__ */ jsxDEV5(Text2, {
569
+ className: "text-muted-foreground text-xs",
570
+ children: [
571
+ item.sourceEntity,
572
+ " \u2192 ",
573
+ item.targetEntity
574
+ ]
575
+ }, undefined, true, undefined, this)
576
+ ]
577
+ }, undefined, true, undefined, this),
578
+ size: 260,
579
+ minSize: 200,
580
+ canSort: true,
581
+ canPin: true,
582
+ canResize: true
583
+ },
584
+ {
585
+ id: "frequency",
586
+ header: "Frequency",
587
+ label: "Frequency",
588
+ accessorKey: "frequency",
589
+ size: 160,
590
+ canSort: true,
591
+ canHide: true,
592
+ canResize: true
593
+ },
594
+ {
595
+ id: "status",
596
+ header: "Status",
597
+ label: "Status",
598
+ accessorKey: "status",
599
+ cell: ({ value }) => /* @__PURE__ */ jsxDEV5(StatusBadge, {
600
+ status: String(value)
601
+ }, undefined, false, undefined, this),
602
+ size: 150,
603
+ canSort: true,
604
+ canPin: true,
605
+ canResize: true
606
+ },
607
+ {
608
+ id: "recordsSynced",
609
+ header: "Records",
610
+ label: "Records",
611
+ accessorKey: "recordsSynced",
612
+ align: "right",
613
+ size: 140,
614
+ canSort: true,
615
+ canResize: true
616
+ },
617
+ {
618
+ id: "lastRunAt",
619
+ header: "Last Run",
620
+ label: "Last Run",
621
+ accessor: (sync) => sync.lastRunAt?.getTime() ?? 0,
622
+ cell: ({ item }) => formatDateTime(item.lastRunAt),
623
+ size: 200,
624
+ canSort: true,
625
+ canHide: true,
626
+ canResize: true
627
+ }
628
+ ],
629
+ initialState: {
630
+ pagination: { pageIndex: 0, pageSize: 3 },
631
+ columnVisibility: { lastRunAt: false },
632
+ columnPinning: { left: ["sync"], right: [] }
633
+ },
634
+ renderExpandedContent: (sync) => /* @__PURE__ */ jsxDEV5(VStack2, {
635
+ gap: "sm",
636
+ className: "py-2",
637
+ children: [
638
+ /* @__PURE__ */ jsxDEV5(Text2, {
639
+ className: "text-muted-foreground text-sm",
640
+ children: [
641
+ "Connection ",
642
+ sync.connectionId
643
+ ]
644
+ }, undefined, true, undefined, this),
645
+ /* @__PURE__ */ jsxDEV5(Text2, {
646
+ className: "text-muted-foreground text-sm",
647
+ children: [
648
+ "Last run: ",
649
+ formatDateTime(sync.lastRunAt)
650
+ ]
651
+ }, undefined, true, undefined, this),
652
+ /* @__PURE__ */ jsxDEV5(Text2, {
653
+ className: "text-muted-foreground text-sm",
654
+ children: [
655
+ "Last status: ",
656
+ sync.lastRunStatus ?? "No runs recorded"
657
+ ]
658
+ }, undefined, true, undefined, this),
659
+ /* @__PURE__ */ jsxDEV5(Text2, {
660
+ className: "text-muted-foreground text-sm",
661
+ children: [
662
+ "Updated ",
663
+ sync.updatedAt.toLocaleString()
664
+ ]
665
+ }, undefined, true, undefined, this)
666
+ ]
667
+ }, undefined, true, undefined, this),
668
+ getCanExpand: () => true
669
+ });
670
+ return /* @__PURE__ */ jsxDEV5(DataTable2, {
671
+ controller,
672
+ title: "Sync Configs",
673
+ description: "Shared table primitives applied to sync monitoring without changing the surrounding dashboard layout.",
674
+ toolbar: /* @__PURE__ */ jsxDEV5(IntegrationTableToolbar, {
675
+ controller,
676
+ label: `${syncConfigs.length} syncs`,
677
+ toggleColumnId: "lastRunAt",
678
+ toggleVisibleLabel: "Hide Last Run",
679
+ toggleHiddenLabel: "Show Last Run",
680
+ pinColumnId: "status",
681
+ pinLabel: "Status",
682
+ resizeColumnId: "sync",
683
+ resizeLabel: "Widen Sync"
684
+ }, undefined, false, undefined, this),
685
+ emptyState: /* @__PURE__ */ jsxDEV5("div", {
686
+ className: "rounded-md border border-dashed p-8 text-center text-muted-foreground text-sm",
687
+ children: "No sync configurations found"
688
+ }, undefined, false, undefined, this)
689
+ }, undefined, false, undefined, this);
690
+ }
86
691
  // src/ui/IntegrationDashboard.tsx
87
- import { useState as useState2 } from "react";
88
692
  import {
89
- Button,
693
+ Button as Button2,
90
694
  ErrorState,
91
695
  LoaderBlock,
92
696
  StatCard,
93
697
  StatCardGroup
94
698
  } from "@contractspec/lib.design-system";
95
- import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
699
+ import { useState as useState2 } from "react";
700
+ import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
96
701
  "use client";
97
702
  var STATUS_COLORS = {
98
703
  ACTIVE: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
@@ -129,32 +734,32 @@ function IntegrationDashboard() {
129
734
  { id: "chat", label: "Chat", icon: "\uD83D\uDCAC" }
130
735
  ];
131
736
  if (loading) {
132
- return /* @__PURE__ */ jsxDEV2(LoaderBlock, {
737
+ return /* @__PURE__ */ jsxDEV6(LoaderBlock, {
133
738
  label: "Loading Integrations..."
134
739
  }, undefined, false, undefined, this);
135
740
  }
136
741
  if (error) {
137
- return /* @__PURE__ */ jsxDEV2(ErrorState, {
742
+ return /* @__PURE__ */ jsxDEV6(ErrorState, {
138
743
  title: "Failed to load Integrations",
139
744
  description: error.message,
140
745
  onRetry: refetch,
141
746
  retryLabel: "Retry"
142
747
  }, undefined, false, undefined, this);
143
748
  }
144
- return /* @__PURE__ */ jsxDEV2("div", {
749
+ return /* @__PURE__ */ jsxDEV6("div", {
145
750
  className: "space-y-6",
146
751
  children: [
147
- /* @__PURE__ */ jsxDEV2("div", {
752
+ /* @__PURE__ */ jsxDEV6("div", {
148
753
  className: "flex items-center justify-between",
149
754
  children: [
150
- /* @__PURE__ */ jsxDEV2("h2", {
151
- className: "text-2xl font-bold",
755
+ /* @__PURE__ */ jsxDEV6("h2", {
756
+ className: "font-bold text-2xl",
152
757
  children: "Integration Hub"
153
758
  }, undefined, false, undefined, this),
154
- /* @__PURE__ */ jsxDEV2(Button, {
759
+ /* @__PURE__ */ jsxDEV6(Button2, {
155
760
  onClick: () => alert("Add integration modal"),
156
761
  children: [
157
- /* @__PURE__ */ jsxDEV2("span", {
762
+ /* @__PURE__ */ jsxDEV6("span", {
158
763
  className: "mr-2",
159
764
  children: "+"
160
765
  }, undefined, false, undefined, this),
@@ -163,66 +768,71 @@ function IntegrationDashboard() {
163
768
  }, undefined, true, undefined, this)
164
769
  ]
165
770
  }, undefined, true, undefined, this),
166
- /* @__PURE__ */ jsxDEV2(StatCardGroup, {
771
+ /* @__PURE__ */ jsxDEV6(StatCardGroup, {
167
772
  children: [
168
- /* @__PURE__ */ jsxDEV2(StatCard, {
773
+ /* @__PURE__ */ jsxDEV6(StatCard, {
169
774
  label: "Integrations",
170
775
  value: stats.totalIntegrations,
171
776
  hint: `${stats.activeIntegrations} active`
172
777
  }, undefined, false, undefined, this),
173
- /* @__PURE__ */ jsxDEV2(StatCard, {
778
+ /* @__PURE__ */ jsxDEV6(StatCard, {
174
779
  label: "Connections",
175
780
  value: stats.totalConnections,
176
781
  hint: `${stats.connectedCount} connected`
177
782
  }, undefined, false, undefined, this),
178
- /* @__PURE__ */ jsxDEV2(StatCard, {
783
+ /* @__PURE__ */ jsxDEV6(StatCard, {
179
784
  label: "Syncs",
180
785
  value: stats.totalSyncs,
181
786
  hint: `${stats.activeSyncs} active`
182
787
  }, undefined, false, undefined, this)
183
788
  ]
184
789
  }, undefined, true, undefined, this),
185
- /* @__PURE__ */ jsxDEV2("nav", {
186
- className: "bg-muted flex gap-1 rounded-lg p-1",
790
+ /* @__PURE__ */ jsxDEV6(IntegrationVisualizationOverview, {
791
+ connections,
792
+ integrations,
793
+ syncConfigs
794
+ }, undefined, false, undefined, this),
795
+ /* @__PURE__ */ jsxDEV6("nav", {
796
+ className: "flex gap-1 rounded-lg bg-muted p-1",
187
797
  role: "tablist",
188
- children: tabs.map((tab) => /* @__PURE__ */ jsxDEV2(Button, {
798
+ children: tabs.map((tab) => /* @__PURE__ */ jsxDEV6(Button2, {
189
799
  type: "button",
190
800
  role: "tab",
191
801
  "aria-selected": activeTab === tab.id,
192
802
  onClick: () => setActiveTab(tab.id),
193
- className: `flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors ${activeTab === tab.id ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
803
+ className: `flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 font-medium text-sm transition-colors ${activeTab === tab.id ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
194
804
  children: [
195
- /* @__PURE__ */ jsxDEV2("span", {
805
+ /* @__PURE__ */ jsxDEV6("span", {
196
806
  children: tab.icon
197
807
  }, undefined, false, undefined, this),
198
808
  tab.label
199
809
  ]
200
810
  }, tab.id, true, undefined, this))
201
811
  }, undefined, false, undefined, this),
202
- /* @__PURE__ */ jsxDEV2("div", {
812
+ /* @__PURE__ */ jsxDEV6("div", {
203
813
  className: "min-h-[400px]",
204
814
  role: "tabpanel",
205
815
  children: [
206
- activeTab === "integrations" && /* @__PURE__ */ jsxDEV2("div", {
816
+ activeTab === "integrations" && /* @__PURE__ */ jsxDEV6("div", {
207
817
  className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
208
818
  children: [
209
- integrations.map((integration) => /* @__PURE__ */ jsxDEV2("div", {
210
- className: "border-border bg-card hover:bg-muted/50 cursor-pointer rounded-lg border p-4 transition-colors",
819
+ integrations.map((integration) => /* @__PURE__ */ jsxDEV6("div", {
820
+ className: "cursor-pointer rounded-lg border border-border bg-card p-4 transition-colors hover:bg-muted/50",
211
821
  children: [
212
- /* @__PURE__ */ jsxDEV2("div", {
822
+ /* @__PURE__ */ jsxDEV6("div", {
213
823
  className: "mb-3 flex items-center gap-3",
214
824
  children: [
215
- /* @__PURE__ */ jsxDEV2("span", {
825
+ /* @__PURE__ */ jsxDEV6("span", {
216
826
  className: "text-2xl",
217
827
  children: TYPE_ICONS[integration.type] ?? "\u2699\uFE0F"
218
828
  }, undefined, false, undefined, this),
219
- /* @__PURE__ */ jsxDEV2("div", {
829
+ /* @__PURE__ */ jsxDEV6("div", {
220
830
  children: [
221
- /* @__PURE__ */ jsxDEV2("h3", {
831
+ /* @__PURE__ */ jsxDEV6("h3", {
222
832
  className: "font-medium",
223
833
  children: integration.name
224
834
  }, undefined, false, undefined, this),
225
- /* @__PURE__ */ jsxDEV2("p", {
835
+ /* @__PURE__ */ jsxDEV6("p", {
226
836
  className: "text-muted-foreground text-sm",
227
837
  children: integration.type
228
838
  }, undefined, false, undefined, this)
@@ -230,14 +840,14 @@ function IntegrationDashboard() {
230
840
  }, undefined, true, undefined, this)
231
841
  ]
232
842
  }, undefined, true, undefined, this),
233
- /* @__PURE__ */ jsxDEV2("div", {
843
+ /* @__PURE__ */ jsxDEV6("div", {
234
844
  className: "flex items-center justify-between",
235
845
  children: [
236
- /* @__PURE__ */ jsxDEV2("span", {
237
- className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[integration.status] ?? ""}`,
846
+ /* @__PURE__ */ jsxDEV6("span", {
847
+ className: `inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${STATUS_COLORS[integration.status] ?? ""}`,
238
848
  children: integration.status
239
849
  }, undefined, false, undefined, this),
240
- /* @__PURE__ */ jsxDEV2("span", {
850
+ /* @__PURE__ */ jsxDEV6("span", {
241
851
  className: "text-muted-foreground text-xs",
242
852
  children: integration.createdAt.toLocaleDateString()
243
853
  }, undefined, false, undefined, this)
@@ -245,75 +855,16 @@ function IntegrationDashboard() {
245
855
  }, undefined, true, undefined, this)
246
856
  ]
247
857
  }, integration.id, true, undefined, this)),
248
- integrations.length === 0 && /* @__PURE__ */ jsxDEV2("div", {
249
- className: "text-muted-foreground col-span-full flex h-64 items-center justify-center",
858
+ integrations.length === 0 && /* @__PURE__ */ jsxDEV6("div", {
859
+ className: "col-span-full flex h-64 items-center justify-center text-muted-foreground",
250
860
  children: "No integrations configured"
251
861
  }, undefined, false, undefined, this)
252
862
  ]
253
863
  }, undefined, true, undefined, this),
254
- activeTab === "connections" && /* @__PURE__ */ jsxDEV2("div", {
255
- className: "border-border rounded-lg border",
256
- children: /* @__PURE__ */ jsxDEV2("table", {
257
- className: "w-full",
258
- children: [
259
- /* @__PURE__ */ jsxDEV2("thead", {
260
- className: "border-border bg-muted/30 border-b",
261
- children: /* @__PURE__ */ jsxDEV2("tr", {
262
- children: [
263
- /* @__PURE__ */ jsxDEV2("th", {
264
- className: "px-4 py-3 text-left text-sm font-medium",
265
- children: "Connection"
266
- }, undefined, false, undefined, this),
267
- /* @__PURE__ */ jsxDEV2("th", {
268
- className: "px-4 py-3 text-left text-sm font-medium",
269
- children: "Status"
270
- }, undefined, false, undefined, this),
271
- /* @__PURE__ */ jsxDEV2("th", {
272
- className: "px-4 py-3 text-left text-sm font-medium",
273
- children: "Last Sync"
274
- }, undefined, false, undefined, this)
275
- ]
276
- }, undefined, true, undefined, this)
277
- }, undefined, false, undefined, this),
278
- /* @__PURE__ */ jsxDEV2("tbody", {
279
- className: "divide-border divide-y",
280
- children: [
281
- connections.map((conn) => /* @__PURE__ */ jsxDEV2("tr", {
282
- className: "hover:bg-muted/50",
283
- children: [
284
- /* @__PURE__ */ jsxDEV2("td", {
285
- className: "px-4 py-3",
286
- children: /* @__PURE__ */ jsxDEV2("div", {
287
- className: "font-medium",
288
- children: conn.name
289
- }, undefined, false, undefined, this)
290
- }, undefined, false, undefined, this),
291
- /* @__PURE__ */ jsxDEV2("td", {
292
- className: "px-4 py-3",
293
- children: /* @__PURE__ */ jsxDEV2("span", {
294
- className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[conn.status] ?? ""}`,
295
- children: conn.status
296
- }, undefined, false, undefined, this)
297
- }, undefined, false, undefined, this),
298
- /* @__PURE__ */ jsxDEV2("td", {
299
- className: "text-muted-foreground px-4 py-3 text-sm",
300
- children: conn.lastSyncAt?.toLocaleString() ?? "Never"
301
- }, undefined, false, undefined, this)
302
- ]
303
- }, conn.id, true, undefined, this)),
304
- connections.length === 0 && /* @__PURE__ */ jsxDEV2("tr", {
305
- children: /* @__PURE__ */ jsxDEV2("td", {
306
- colSpan: 3,
307
- className: "text-muted-foreground px-4 py-8 text-center",
308
- children: "No connections found"
309
- }, undefined, false, undefined, this)
310
- }, undefined, false, undefined, this)
311
- ]
312
- }, undefined, true, undefined, this)
313
- ]
314
- }, undefined, true, undefined, this)
864
+ activeTab === "connections" && /* @__PURE__ */ jsxDEV6(ConnectionsTable, {
865
+ connections
315
866
  }, undefined, false, undefined, this),
316
- activeTab === "chat" && /* @__PURE__ */ jsxDEV2(IntegrationHubChat, {
867
+ activeTab === "chat" && /* @__PURE__ */ jsxDEV6(IntegrationHubChat, {
317
868
  proxyUrl: "/api/chat",
318
869
  thinkingLevel: "thinking",
319
870
  suggestions: [
@@ -323,85 +874,8 @@ function IntegrationDashboard() {
323
874
  ],
324
875
  className: "min-h-[400px]"
325
876
  }, undefined, false, undefined, this),
326
- activeTab === "syncs" && /* @__PURE__ */ jsxDEV2("div", {
327
- className: "border-border rounded-lg border",
328
- children: /* @__PURE__ */ jsxDEV2("table", {
329
- className: "w-full",
330
- children: [
331
- /* @__PURE__ */ jsxDEV2("thead", {
332
- className: "border-border bg-muted/30 border-b",
333
- children: /* @__PURE__ */ jsxDEV2("tr", {
334
- children: [
335
- /* @__PURE__ */ jsxDEV2("th", {
336
- className: "px-4 py-3 text-left text-sm font-medium",
337
- children: "Sync Config"
338
- }, undefined, false, undefined, this),
339
- /* @__PURE__ */ jsxDEV2("th", {
340
- className: "px-4 py-3 text-left text-sm font-medium",
341
- children: "Frequency"
342
- }, undefined, false, undefined, this),
343
- /* @__PURE__ */ jsxDEV2("th", {
344
- className: "px-4 py-3 text-left text-sm font-medium",
345
- children: "Status"
346
- }, undefined, false, undefined, this),
347
- /* @__PURE__ */ jsxDEV2("th", {
348
- className: "px-4 py-3 text-left text-sm font-medium",
349
- children: "Records"
350
- }, undefined, false, undefined, this)
351
- ]
352
- }, undefined, true, undefined, this)
353
- }, undefined, false, undefined, this),
354
- /* @__PURE__ */ jsxDEV2("tbody", {
355
- className: "divide-border divide-y",
356
- children: [
357
- syncConfigs.map((sync) => /* @__PURE__ */ jsxDEV2("tr", {
358
- className: "hover:bg-muted/50",
359
- children: [
360
- /* @__PURE__ */ jsxDEV2("td", {
361
- className: "px-4 py-3",
362
- children: [
363
- /* @__PURE__ */ jsxDEV2("div", {
364
- className: "font-medium",
365
- children: sync.name
366
- }, undefined, false, undefined, this),
367
- /* @__PURE__ */ jsxDEV2("div", {
368
- className: "text-muted-foreground text-sm",
369
- children: [
370
- sync.sourceEntity,
371
- " \u2192 ",
372
- sync.targetEntity
373
- ]
374
- }, undefined, true, undefined, this)
375
- ]
376
- }, undefined, true, undefined, this),
377
- /* @__PURE__ */ jsxDEV2("td", {
378
- className: "px-4 py-3 text-sm",
379
- children: sync.frequency
380
- }, undefined, false, undefined, this),
381
- /* @__PURE__ */ jsxDEV2("td", {
382
- className: "px-4 py-3",
383
- children: /* @__PURE__ */ jsxDEV2("span", {
384
- className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[sync.status] ?? ""}`,
385
- children: sync.status
386
- }, undefined, false, undefined, this)
387
- }, undefined, false, undefined, this),
388
- /* @__PURE__ */ jsxDEV2("td", {
389
- className: "text-muted-foreground px-4 py-3 text-sm",
390
- children: sync.recordsSynced.toLocaleString()
391
- }, undefined, false, undefined, this)
392
- ]
393
- }, sync.id, true, undefined, this)),
394
- syncConfigs.length === 0 && /* @__PURE__ */ jsxDEV2("tr", {
395
- children: /* @__PURE__ */ jsxDEV2("td", {
396
- colSpan: 4,
397
- className: "text-muted-foreground px-4 py-8 text-center",
398
- children: "No sync configurations found"
399
- }, undefined, false, undefined, this)
400
- }, undefined, false, undefined, this)
401
- ]
402
- }, undefined, true, undefined, this)
403
- ]
404
- }, undefined, true, undefined, this)
877
+ activeTab === "syncs" && /* @__PURE__ */ jsxDEV6(SyncConfigsTable, {
878
+ syncConfigs
405
879
  }, undefined, false, undefined, this)
406
880
  ]
407
881
  }, undefined, true, undefined, this)