@contractspec/example.integration-hub 1.57.0 → 1.58.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.
Files changed (190) hide show
  1. package/dist/browser/connection/connection.enum.js +12 -0
  2. package/dist/browser/connection/connection.operation.js +101 -0
  3. package/dist/browser/connection/connection.presentation.js +99 -0
  4. package/dist/browser/connection/connection.schema.js +48 -0
  5. package/dist/browser/connection/index.js +104 -0
  6. package/dist/browser/docs/index.js +104 -0
  7. package/dist/browser/docs/integration-hub.docblock.js +104 -0
  8. package/dist/browser/events.js +211 -0
  9. package/dist/browser/example.js +42 -0
  10. package/dist/browser/handlers/index.js +246 -0
  11. package/dist/browser/handlers/integration.handlers.js +246 -0
  12. package/dist/browser/index.js +1595 -0
  13. package/dist/browser/integration/index.js +92 -0
  14. package/dist/browser/integration/integration.enum.js +12 -0
  15. package/dist/browser/integration/integration.operations.js +89 -0
  16. package/dist/browser/integration/integration.presentation.js +117 -0
  17. package/dist/browser/integration/integration.schema.js +42 -0
  18. package/dist/browser/integration-hub.capability.js +40 -0
  19. package/dist/browser/integration-hub.feature.js +114 -0
  20. package/dist/browser/seeders/index.js +60 -0
  21. package/dist/browser/sync/index.js +332 -0
  22. package/dist/browser/sync/sync.enum.js +26 -0
  23. package/dist/browser/sync/sync.operations.js +321 -0
  24. package/dist/browser/sync/sync.presentation.js +298 -0
  25. package/dist/browser/sync/sync.schema.js +154 -0
  26. package/dist/browser/sync-engine/index.js +186 -0
  27. package/dist/browser/tests/operations.test-spec.js +85 -0
  28. package/dist/browser/ui/IntegrationDashboard.js +369 -0
  29. package/dist/browser/ui/hooks/index.js +57 -0
  30. package/dist/browser/ui/hooks/useIntegrationData.js +54 -0
  31. package/dist/browser/ui/index.js +644 -0
  32. package/dist/browser/ui/renderers/index.js +273 -0
  33. package/dist/browser/ui/renderers/integration.markdown.js +273 -0
  34. package/dist/connection/connection.enum.d.ts +1 -6
  35. package/dist/connection/connection.enum.d.ts.map +1 -1
  36. package/dist/connection/connection.enum.js +11 -15
  37. package/dist/connection/connection.operation.d.ts +78 -84
  38. package/dist/connection/connection.operation.d.ts.map +1 -1
  39. package/dist/connection/connection.operation.js +99 -60
  40. package/dist/connection/connection.presentation.d.ts +2 -7
  41. package/dist/connection/connection.presentation.d.ts.map +1 -1
  42. package/dist/connection/connection.presentation.js +96 -56
  43. package/dist/connection/connection.schema.d.ts +54 -59
  44. package/dist/connection/connection.schema.d.ts.map +1 -1
  45. package/dist/connection/connection.schema.js +46 -73
  46. package/dist/connection/index.d.ts +7 -4
  47. package/dist/connection/index.d.ts.map +1 -0
  48. package/dist/connection/index.js +104 -4
  49. package/dist/docs/index.d.ts +2 -1
  50. package/dist/docs/index.d.ts.map +1 -0
  51. package/dist/docs/index.js +105 -1
  52. package/dist/docs/integration-hub.docblock.d.ts +2 -1
  53. package/dist/docs/integration-hub.docblock.d.ts.map +1 -0
  54. package/dist/docs/integration-hub.docblock.js +45 -56
  55. package/dist/events.d.ts +137 -143
  56. package/dist/events.d.ts.map +1 -1
  57. package/dist/events.js +210 -287
  58. package/dist/example.d.ts +2 -6
  59. package/dist/example.d.ts.map +1 -1
  60. package/dist/example.js +41 -55
  61. package/dist/handlers/index.d.ts +2 -2
  62. package/dist/handlers/index.d.ts.map +1 -0
  63. package/dist/handlers/index.js +247 -3
  64. package/dist/handlers/integration.handlers.d.ts +114 -113
  65. package/dist/handlers/integration.handlers.d.ts.map +1 -1
  66. package/dist/handlers/integration.handlers.js +232 -267
  67. package/dist/index.d.ts +12 -19
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +1596 -20
  70. package/dist/integration/index.d.ts +7 -4
  71. package/dist/integration/index.d.ts.map +1 -0
  72. package/dist/integration/index.js +92 -4
  73. package/dist/integration/integration.enum.d.ts +1 -6
  74. package/dist/integration/integration.enum.d.ts.map +1 -1
  75. package/dist/integration/integration.enum.js +11 -15
  76. package/dist/integration/integration.operations.d.ts +74 -80
  77. package/dist/integration/integration.operations.d.ts.map +1 -1
  78. package/dist/integration/integration.operations.js +87 -54
  79. package/dist/integration/integration.presentation.d.ts +3 -8
  80. package/dist/integration/integration.presentation.d.ts.map +1 -1
  81. package/dist/integration/integration.presentation.js +114 -73
  82. package/dist/integration/integration.schema.d.ts +54 -59
  83. package/dist/integration/integration.schema.d.ts.map +1 -1
  84. package/dist/integration/integration.schema.js +40 -73
  85. package/dist/integration-hub.capability.d.ts +3 -8
  86. package/dist/integration-hub.capability.d.ts.map +1 -1
  87. package/dist/integration-hub.capability.js +41 -38
  88. package/dist/integration-hub.feature.d.ts +1 -6
  89. package/dist/integration-hub.feature.d.ts.map +1 -1
  90. package/dist/integration-hub.feature.js +113 -242
  91. package/dist/node/connection/connection.enum.js +12 -0
  92. package/dist/node/connection/connection.operation.js +101 -0
  93. package/dist/node/connection/connection.presentation.js +99 -0
  94. package/dist/node/connection/connection.schema.js +48 -0
  95. package/dist/node/connection/index.js +104 -0
  96. package/dist/node/docs/index.js +104 -0
  97. package/dist/node/docs/integration-hub.docblock.js +104 -0
  98. package/dist/node/events.js +211 -0
  99. package/dist/node/example.js +42 -0
  100. package/dist/node/handlers/index.js +246 -0
  101. package/dist/node/handlers/integration.handlers.js +246 -0
  102. package/dist/node/index.js +1595 -0
  103. package/dist/node/integration/index.js +92 -0
  104. package/dist/node/integration/integration.enum.js +12 -0
  105. package/dist/node/integration/integration.operations.js +89 -0
  106. package/dist/node/integration/integration.presentation.js +117 -0
  107. package/dist/node/integration/integration.schema.js +42 -0
  108. package/dist/node/integration-hub.capability.js +40 -0
  109. package/dist/node/integration-hub.feature.js +114 -0
  110. package/dist/node/seeders/index.js +60 -0
  111. package/dist/node/sync/index.js +332 -0
  112. package/dist/node/sync/sync.enum.js +26 -0
  113. package/dist/node/sync/sync.operations.js +321 -0
  114. package/dist/node/sync/sync.presentation.js +298 -0
  115. package/dist/node/sync/sync.schema.js +154 -0
  116. package/dist/node/sync-engine/index.js +186 -0
  117. package/dist/node/tests/operations.test-spec.js +85 -0
  118. package/dist/node/ui/IntegrationDashboard.js +369 -0
  119. package/dist/node/ui/hooks/index.js +57 -0
  120. package/dist/node/ui/hooks/useIntegrationData.js +54 -0
  121. package/dist/node/ui/index.js +644 -0
  122. package/dist/node/ui/renderers/index.js +273 -0
  123. package/dist/node/ui/renderers/integration.markdown.js +273 -0
  124. package/dist/seeders/index.d.ts +4 -8
  125. package/dist/seeders/index.d.ts.map +1 -1
  126. package/dist/seeders/index.js +54 -52
  127. package/dist/sync/index.d.ts +7 -4
  128. package/dist/sync/index.d.ts.map +1 -0
  129. package/dist/sync/index.js +332 -4
  130. package/dist/sync/sync.enum.d.ts +3 -8
  131. package/dist/sync/sync.enum.d.ts.map +1 -1
  132. package/dist/sync/sync.enum.js +23 -31
  133. package/dist/sync/sync.operations.d.ts +413 -419
  134. package/dist/sync/sync.operations.d.ts.map +1 -1
  135. package/dist/sync/sync.operations.js +316 -197
  136. package/dist/sync/sync.presentation.d.ts +6 -11
  137. package/dist/sync/sync.presentation.d.ts.map +1 -1
  138. package/dist/sync/sync.presentation.js +291 -160
  139. package/dist/sync/sync.schema.d.ts +317 -322
  140. package/dist/sync/sync.schema.d.ts.map +1 -1
  141. package/dist/sync/sync.schema.js +146 -295
  142. package/dist/sync-engine/index.d.ts +88 -91
  143. package/dist/sync-engine/index.d.ts.map +1 -1
  144. package/dist/sync-engine/index.js +181 -142
  145. package/dist/tests/operations.test-spec.d.ts +3 -8
  146. package/dist/tests/operations.test-spec.d.ts.map +1 -1
  147. package/dist/tests/operations.test-spec.js +82 -90
  148. package/dist/ui/IntegrationDashboard.d.ts +1 -6
  149. package/dist/ui/IntegrationDashboard.d.ts.map +1 -1
  150. package/dist/ui/IntegrationDashboard.js +365 -261
  151. package/dist/ui/hooks/index.d.ts +2 -2
  152. package/dist/ui/hooks/index.d.ts.map +1 -0
  153. package/dist/ui/hooks/index.js +57 -4
  154. package/dist/ui/hooks/useIntegrationData.d.ts +16 -20
  155. package/dist/ui/hooks/useIntegrationData.d.ts.map +1 -1
  156. package/dist/ui/hooks/useIntegrationData.js +51 -55
  157. package/dist/ui/index.d.ts +7 -6
  158. package/dist/ui/index.d.ts.map +1 -0
  159. package/dist/ui/index.js +644 -5
  160. package/dist/ui/renderers/index.d.ts +2 -2
  161. package/dist/ui/renderers/index.d.ts.map +1 -0
  162. package/dist/ui/renderers/index.js +274 -3
  163. package/dist/ui/renderers/integration.markdown.d.ts +13 -14
  164. package/dist/ui/renderers/integration.markdown.d.ts.map +1 -1
  165. package/dist/ui/renderers/integration.markdown.js +268 -264
  166. package/package.json +360 -71
  167. package/dist/connection/connection.enum.js.map +0 -1
  168. package/dist/connection/connection.operation.js.map +0 -1
  169. package/dist/connection/connection.presentation.js.map +0 -1
  170. package/dist/connection/connection.schema.js.map +0 -1
  171. package/dist/docs/integration-hub.docblock.js.map +0 -1
  172. package/dist/events.js.map +0 -1
  173. package/dist/example.js.map +0 -1
  174. package/dist/handlers/integration.handlers.js.map +0 -1
  175. package/dist/integration/integration.enum.js.map +0 -1
  176. package/dist/integration/integration.operations.js.map +0 -1
  177. package/dist/integration/integration.presentation.js.map +0 -1
  178. package/dist/integration/integration.schema.js.map +0 -1
  179. package/dist/integration-hub.capability.js.map +0 -1
  180. package/dist/integration-hub.feature.js.map +0 -1
  181. package/dist/seeders/index.js.map +0 -1
  182. package/dist/sync/sync.enum.js.map +0 -1
  183. package/dist/sync/sync.operations.js.map +0 -1
  184. package/dist/sync/sync.presentation.js.map +0 -1
  185. package/dist/sync/sync.schema.js.map +0 -1
  186. package/dist/sync-engine/index.js.map +0 -1
  187. package/dist/tests/operations.test-spec.js.map +0 -1
  188. package/dist/ui/IntegrationDashboard.js.map +0 -1
  189. package/dist/ui/hooks/useIntegrationData.js.map +0 -1
  190. package/dist/ui/renderers/integration.markdown.js.map +0 -1
@@ -0,0 +1,85 @@
1
+ // src/tests/operations.test-spec.ts
2
+ import { defineTestSpec } from "@contractspec/lib.contracts";
3
+ var SyncConfigCreateTest = defineTestSpec({
4
+ meta: {
5
+ key: "integration.syncConfig.create.test",
6
+ version: "1.0.0",
7
+ stability: "experimental",
8
+ owners: ["@example.integration-hub"],
9
+ description: "Test for creating sync config",
10
+ tags: ["test"]
11
+ },
12
+ target: {
13
+ type: "operation",
14
+ operation: { key: "integration.syncConfig.create", version: "1.0.0" }
15
+ },
16
+ scenarios: [
17
+ {
18
+ key: "success",
19
+ when: { operation: { key: "integration.syncConfig.create" } },
20
+ then: [{ type: "expectOutput", match: {} }]
21
+ },
22
+ {
23
+ key: "error",
24
+ when: { operation: { key: "integration.syncConfig.create" } },
25
+ then: [{ type: "expectError" }]
26
+ }
27
+ ]
28
+ });
29
+ var FieldMappingAddTest = defineTestSpec({
30
+ meta: {
31
+ key: "integration.fieldMapping.add.test",
32
+ version: "1.0.0",
33
+ stability: "experimental",
34
+ owners: ["@example.integration-hub"],
35
+ description: "Test for adding field mapping",
36
+ tags: ["test"]
37
+ },
38
+ target: {
39
+ type: "operation",
40
+ operation: { key: "integration.fieldMapping.add", version: "1.0.0" }
41
+ },
42
+ scenarios: [
43
+ {
44
+ key: "success",
45
+ when: { operation: { key: "integration.fieldMapping.add" } },
46
+ then: [{ type: "expectOutput", match: {} }]
47
+ },
48
+ {
49
+ key: "error",
50
+ when: { operation: { key: "integration.fieldMapping.add" } },
51
+ then: [{ type: "expectError" }]
52
+ }
53
+ ]
54
+ });
55
+ var SyncRunListTest = defineTestSpec({
56
+ meta: {
57
+ key: "integration.syncRun.list.test",
58
+ version: "1.0.0",
59
+ stability: "experimental",
60
+ owners: ["@example.integration-hub"],
61
+ description: "Test for listing sync runs",
62
+ tags: ["test"]
63
+ },
64
+ target: {
65
+ type: "operation",
66
+ operation: { key: "integration.syncRun.list", version: "1.0.0" }
67
+ },
68
+ scenarios: [
69
+ {
70
+ key: "success",
71
+ when: { operation: { key: "integration.syncRun.list" } },
72
+ then: [{ type: "expectOutput", match: {} }]
73
+ },
74
+ {
75
+ key: "error",
76
+ when: { operation: { key: "integration.syncRun.list" } },
77
+ then: [{ type: "expectError" }]
78
+ }
79
+ ]
80
+ });
81
+ export {
82
+ SyncRunListTest,
83
+ SyncConfigCreateTest,
84
+ FieldMappingAddTest
85
+ };
@@ -0,0 +1,369 @@
1
+ // src/ui/hooks/useIntegrationData.ts
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
4
+ "use client";
5
+ function useIntegrationData(projectId = "local-project") {
6
+ const { handlers } = useTemplateRuntime();
7
+ const integration = handlers.integration;
8
+ const [integrations, setIntegrations] = useState([]);
9
+ const [connections, setConnections] = useState([]);
10
+ const [syncConfigs, setSyncConfigs] = useState([]);
11
+ const [loading, setLoading] = useState(true);
12
+ const [error, setError] = useState(null);
13
+ const fetchData = useCallback(async () => {
14
+ try {
15
+ setLoading(true);
16
+ setError(null);
17
+ const [integResult, connResult, syncResult] = await Promise.all([
18
+ integration.listIntegrations({ projectId, limit: 100 }),
19
+ integration.listConnections({ limit: 100 }),
20
+ integration.listSyncConfigs({ limit: 100 })
21
+ ]);
22
+ setIntegrations(integResult.integrations);
23
+ setConnections(connResult.connections);
24
+ setSyncConfigs(syncResult.configs);
25
+ } catch (err) {
26
+ setError(err instanceof Error ? err : new Error("Failed to load integrations"));
27
+ } finally {
28
+ setLoading(false);
29
+ }
30
+ }, [integration, projectId]);
31
+ useEffect(() => {
32
+ fetchData();
33
+ }, [fetchData]);
34
+ const stats = {
35
+ totalIntegrations: integrations.length,
36
+ activeIntegrations: integrations.filter((i) => i.status === "ACTIVE").length,
37
+ totalConnections: connections.length,
38
+ connectedCount: connections.filter((c) => c.status === "CONNECTED").length,
39
+ totalSyncs: syncConfigs.length,
40
+ activeSyncs: syncConfigs.filter((s) => s.status === "ACTIVE").length
41
+ };
42
+ return {
43
+ integrations,
44
+ connections,
45
+ syncConfigs,
46
+ loading,
47
+ error,
48
+ stats,
49
+ refetch: fetchData
50
+ };
51
+ }
52
+
53
+ // src/ui/IntegrationDashboard.tsx
54
+ import { useState as useState2 } from "react";
55
+ import {
56
+ Button,
57
+ ErrorState,
58
+ LoaderBlock,
59
+ StatCard,
60
+ StatCardGroup
61
+ } from "@contractspec/lib.design-system";
62
+ import { jsxDEV } from "react/jsx-dev-runtime";
63
+ "use client";
64
+ var STATUS_COLORS = {
65
+ ACTIVE: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
66
+ INACTIVE: "bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400",
67
+ CONNECTED: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
68
+ DISCONNECTED: "bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400",
69
+ PENDING: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400",
70
+ ERROR: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400",
71
+ PAUSED: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400"
72
+ };
73
+ var TYPE_ICONS = {
74
+ CRM: "\uD83D\uDCCA",
75
+ MARKETING: "\uD83D\uDCE3",
76
+ PAYMENT: "\uD83D\uDCB3",
77
+ COMMUNICATION: "\uD83D\uDCAC",
78
+ DATA: "\uD83D\uDDC4️",
79
+ CUSTOM: "⚙️"
80
+ };
81
+ function IntegrationDashboard() {
82
+ const [activeTab, setActiveTab] = useState2("integrations");
83
+ const {
84
+ integrations,
85
+ connections,
86
+ syncConfigs,
87
+ loading,
88
+ error,
89
+ stats,
90
+ refetch
91
+ } = useIntegrationData();
92
+ const tabs = [
93
+ { id: "integrations", label: "Integrations", icon: "\uD83D\uDD0C" },
94
+ { id: "connections", label: "Connections", icon: "\uD83D\uDD17" },
95
+ { id: "syncs", label: "Sync Configs", icon: "\uD83D\uDD04" }
96
+ ];
97
+ if (loading) {
98
+ return /* @__PURE__ */ jsxDEV(LoaderBlock, {
99
+ label: "Loading Integrations..."
100
+ }, undefined, false, undefined, this);
101
+ }
102
+ if (error) {
103
+ return /* @__PURE__ */ jsxDEV(ErrorState, {
104
+ title: "Failed to load Integrations",
105
+ description: error.message,
106
+ onRetry: refetch,
107
+ retryLabel: "Retry"
108
+ }, undefined, false, undefined, this);
109
+ }
110
+ return /* @__PURE__ */ jsxDEV("div", {
111
+ className: "space-y-6",
112
+ children: [
113
+ /* @__PURE__ */ jsxDEV("div", {
114
+ className: "flex items-center justify-between",
115
+ children: [
116
+ /* @__PURE__ */ jsxDEV("h2", {
117
+ className: "text-2xl font-bold",
118
+ children: "Integration Hub"
119
+ }, undefined, false, undefined, this),
120
+ /* @__PURE__ */ jsxDEV(Button, {
121
+ onClick: () => alert("Add integration modal"),
122
+ children: [
123
+ /* @__PURE__ */ jsxDEV("span", {
124
+ className: "mr-2",
125
+ children: "+"
126
+ }, undefined, false, undefined, this),
127
+ " Add Integration"
128
+ ]
129
+ }, undefined, true, undefined, this)
130
+ ]
131
+ }, undefined, true, undefined, this),
132
+ /* @__PURE__ */ jsxDEV(StatCardGroup, {
133
+ children: [
134
+ /* @__PURE__ */ jsxDEV(StatCard, {
135
+ label: "Integrations",
136
+ value: stats.totalIntegrations,
137
+ hint: `${stats.activeIntegrations} active`
138
+ }, undefined, false, undefined, this),
139
+ /* @__PURE__ */ jsxDEV(StatCard, {
140
+ label: "Connections",
141
+ value: stats.totalConnections,
142
+ hint: `${stats.connectedCount} connected`
143
+ }, undefined, false, undefined, this),
144
+ /* @__PURE__ */ jsxDEV(StatCard, {
145
+ label: "Syncs",
146
+ value: stats.totalSyncs,
147
+ hint: `${stats.activeSyncs} active`
148
+ }, undefined, false, undefined, this)
149
+ ]
150
+ }, undefined, true, undefined, this),
151
+ /* @__PURE__ */ jsxDEV("nav", {
152
+ className: "bg-muted flex gap-1 rounded-lg p-1",
153
+ role: "tablist",
154
+ children: tabs.map((tab) => /* @__PURE__ */ jsxDEV(Button, {
155
+ type: "button",
156
+ role: "tab",
157
+ "aria-selected": activeTab === tab.id,
158
+ onClick: () => setActiveTab(tab.id),
159
+ 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"}`,
160
+ children: [
161
+ /* @__PURE__ */ jsxDEV("span", {
162
+ children: tab.icon
163
+ }, undefined, false, undefined, this),
164
+ tab.label
165
+ ]
166
+ }, tab.id, true, undefined, this))
167
+ }, undefined, false, undefined, this),
168
+ /* @__PURE__ */ jsxDEV("div", {
169
+ className: "min-h-[400px]",
170
+ role: "tabpanel",
171
+ children: [
172
+ activeTab === "integrations" && /* @__PURE__ */ jsxDEV("div", {
173
+ className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
174
+ children: [
175
+ integrations.map((integration) => /* @__PURE__ */ jsxDEV("div", {
176
+ className: "border-border bg-card hover:bg-muted/50 cursor-pointer rounded-lg border p-4 transition-colors",
177
+ children: [
178
+ /* @__PURE__ */ jsxDEV("div", {
179
+ className: "mb-3 flex items-center gap-3",
180
+ children: [
181
+ /* @__PURE__ */ jsxDEV("span", {
182
+ className: "text-2xl",
183
+ children: TYPE_ICONS[integration.type] ?? "⚙️"
184
+ }, undefined, false, undefined, this),
185
+ /* @__PURE__ */ jsxDEV("div", {
186
+ children: [
187
+ /* @__PURE__ */ jsxDEV("h3", {
188
+ className: "font-medium",
189
+ children: integration.name
190
+ }, undefined, false, undefined, this),
191
+ /* @__PURE__ */ jsxDEV("p", {
192
+ className: "text-muted-foreground text-sm",
193
+ children: integration.type
194
+ }, undefined, false, undefined, this)
195
+ ]
196
+ }, undefined, true, undefined, this)
197
+ ]
198
+ }, undefined, true, undefined, this),
199
+ /* @__PURE__ */ jsxDEV("div", {
200
+ className: "flex items-center justify-between",
201
+ children: [
202
+ /* @__PURE__ */ jsxDEV("span", {
203
+ className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[integration.status] ?? ""}`,
204
+ children: integration.status
205
+ }, undefined, false, undefined, this),
206
+ /* @__PURE__ */ jsxDEV("span", {
207
+ className: "text-muted-foreground text-xs",
208
+ children: integration.createdAt.toLocaleDateString()
209
+ }, undefined, false, undefined, this)
210
+ ]
211
+ }, undefined, true, undefined, this)
212
+ ]
213
+ }, integration.id, true, undefined, this)),
214
+ integrations.length === 0 && /* @__PURE__ */ jsxDEV("div", {
215
+ className: "text-muted-foreground col-span-full flex h-64 items-center justify-center",
216
+ children: "No integrations configured"
217
+ }, undefined, false, undefined, this)
218
+ ]
219
+ }, undefined, true, undefined, this),
220
+ activeTab === "connections" && /* @__PURE__ */ jsxDEV("div", {
221
+ className: "border-border rounded-lg border",
222
+ children: /* @__PURE__ */ jsxDEV("table", {
223
+ className: "w-full",
224
+ children: [
225
+ /* @__PURE__ */ jsxDEV("thead", {
226
+ className: "border-border bg-muted/30 border-b",
227
+ children: /* @__PURE__ */ jsxDEV("tr", {
228
+ children: [
229
+ /* @__PURE__ */ jsxDEV("th", {
230
+ className: "px-4 py-3 text-left text-sm font-medium",
231
+ children: "Connection"
232
+ }, undefined, false, undefined, this),
233
+ /* @__PURE__ */ jsxDEV("th", {
234
+ className: "px-4 py-3 text-left text-sm font-medium",
235
+ children: "Status"
236
+ }, undefined, false, undefined, this),
237
+ /* @__PURE__ */ jsxDEV("th", {
238
+ className: "px-4 py-3 text-left text-sm font-medium",
239
+ children: "Last Sync"
240
+ }, undefined, false, undefined, this)
241
+ ]
242
+ }, undefined, true, undefined, this)
243
+ }, undefined, false, undefined, this),
244
+ /* @__PURE__ */ jsxDEV("tbody", {
245
+ className: "divide-border divide-y",
246
+ children: [
247
+ connections.map((conn) => /* @__PURE__ */ jsxDEV("tr", {
248
+ className: "hover:bg-muted/50",
249
+ children: [
250
+ /* @__PURE__ */ jsxDEV("td", {
251
+ className: "px-4 py-3",
252
+ children: /* @__PURE__ */ jsxDEV("div", {
253
+ className: "font-medium",
254
+ children: conn.name
255
+ }, undefined, false, undefined, this)
256
+ }, undefined, false, undefined, this),
257
+ /* @__PURE__ */ jsxDEV("td", {
258
+ className: "px-4 py-3",
259
+ children: /* @__PURE__ */ jsxDEV("span", {
260
+ className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[conn.status] ?? ""}`,
261
+ children: conn.status
262
+ }, undefined, false, undefined, this)
263
+ }, undefined, false, undefined, this),
264
+ /* @__PURE__ */ jsxDEV("td", {
265
+ className: "text-muted-foreground px-4 py-3 text-sm",
266
+ children: conn.lastSyncAt?.toLocaleString() ?? "Never"
267
+ }, undefined, false, undefined, this)
268
+ ]
269
+ }, conn.id, true, undefined, this)),
270
+ connections.length === 0 && /* @__PURE__ */ jsxDEV("tr", {
271
+ children: /* @__PURE__ */ jsxDEV("td", {
272
+ colSpan: 3,
273
+ className: "text-muted-foreground px-4 py-8 text-center",
274
+ children: "No connections found"
275
+ }, undefined, false, undefined, this)
276
+ }, undefined, false, undefined, this)
277
+ ]
278
+ }, undefined, true, undefined, this)
279
+ ]
280
+ }, undefined, true, undefined, this)
281
+ }, undefined, false, undefined, this),
282
+ activeTab === "syncs" && /* @__PURE__ */ jsxDEV("div", {
283
+ className: "border-border rounded-lg border",
284
+ children: /* @__PURE__ */ jsxDEV("table", {
285
+ className: "w-full",
286
+ children: [
287
+ /* @__PURE__ */ jsxDEV("thead", {
288
+ className: "border-border bg-muted/30 border-b",
289
+ children: /* @__PURE__ */ jsxDEV("tr", {
290
+ children: [
291
+ /* @__PURE__ */ jsxDEV("th", {
292
+ className: "px-4 py-3 text-left text-sm font-medium",
293
+ children: "Sync Config"
294
+ }, undefined, false, undefined, this),
295
+ /* @__PURE__ */ jsxDEV("th", {
296
+ className: "px-4 py-3 text-left text-sm font-medium",
297
+ children: "Frequency"
298
+ }, undefined, false, undefined, this),
299
+ /* @__PURE__ */ jsxDEV("th", {
300
+ className: "px-4 py-3 text-left text-sm font-medium",
301
+ children: "Status"
302
+ }, undefined, false, undefined, this),
303
+ /* @__PURE__ */ jsxDEV("th", {
304
+ className: "px-4 py-3 text-left text-sm font-medium",
305
+ children: "Records"
306
+ }, undefined, false, undefined, this)
307
+ ]
308
+ }, undefined, true, undefined, this)
309
+ }, undefined, false, undefined, this),
310
+ /* @__PURE__ */ jsxDEV("tbody", {
311
+ className: "divide-border divide-y",
312
+ children: [
313
+ syncConfigs.map((sync) => /* @__PURE__ */ jsxDEV("tr", {
314
+ className: "hover:bg-muted/50",
315
+ children: [
316
+ /* @__PURE__ */ jsxDEV("td", {
317
+ className: "px-4 py-3",
318
+ children: [
319
+ /* @__PURE__ */ jsxDEV("div", {
320
+ className: "font-medium",
321
+ children: sync.name
322
+ }, undefined, false, undefined, this),
323
+ /* @__PURE__ */ jsxDEV("div", {
324
+ className: "text-muted-foreground text-sm",
325
+ children: [
326
+ sync.sourceEntity,
327
+ " → ",
328
+ sync.targetEntity
329
+ ]
330
+ }, undefined, true, undefined, this)
331
+ ]
332
+ }, undefined, true, undefined, this),
333
+ /* @__PURE__ */ jsxDEV("td", {
334
+ className: "px-4 py-3 text-sm",
335
+ children: sync.frequency
336
+ }, undefined, false, undefined, this),
337
+ /* @__PURE__ */ jsxDEV("td", {
338
+ className: "px-4 py-3",
339
+ children: /* @__PURE__ */ jsxDEV("span", {
340
+ className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[sync.status] ?? ""}`,
341
+ children: sync.status
342
+ }, undefined, false, undefined, this)
343
+ }, undefined, false, undefined, this),
344
+ /* @__PURE__ */ jsxDEV("td", {
345
+ className: "text-muted-foreground px-4 py-3 text-sm",
346
+ children: sync.recordsSynced.toLocaleString()
347
+ }, undefined, false, undefined, this)
348
+ ]
349
+ }, sync.id, true, undefined, this)),
350
+ syncConfigs.length === 0 && /* @__PURE__ */ jsxDEV("tr", {
351
+ children: /* @__PURE__ */ jsxDEV("td", {
352
+ colSpan: 4,
353
+ className: "text-muted-foreground px-4 py-8 text-center",
354
+ children: "No sync configurations found"
355
+ }, undefined, false, undefined, this)
356
+ }, undefined, false, undefined, this)
357
+ ]
358
+ }, undefined, true, undefined, this)
359
+ ]
360
+ }, undefined, true, undefined, this)
361
+ }, undefined, false, undefined, this)
362
+ ]
363
+ }, undefined, true, undefined, this)
364
+ ]
365
+ }, undefined, true, undefined, this);
366
+ }
367
+ export {
368
+ IntegrationDashboard
369
+ };
@@ -0,0 +1,57 @@
1
+ // src/ui/hooks/useIntegrationData.ts
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
4
+ "use client";
5
+ function useIntegrationData(projectId = "local-project") {
6
+ const { handlers } = useTemplateRuntime();
7
+ const integration = handlers.integration;
8
+ const [integrations, setIntegrations] = useState([]);
9
+ const [connections, setConnections] = useState([]);
10
+ const [syncConfigs, setSyncConfigs] = useState([]);
11
+ const [loading, setLoading] = useState(true);
12
+ const [error, setError] = useState(null);
13
+ const fetchData = useCallback(async () => {
14
+ try {
15
+ setLoading(true);
16
+ setError(null);
17
+ const [integResult, connResult, syncResult] = await Promise.all([
18
+ integration.listIntegrations({ projectId, limit: 100 }),
19
+ integration.listConnections({ limit: 100 }),
20
+ integration.listSyncConfigs({ limit: 100 })
21
+ ]);
22
+ setIntegrations(integResult.integrations);
23
+ setConnections(connResult.connections);
24
+ setSyncConfigs(syncResult.configs);
25
+ } catch (err) {
26
+ setError(err instanceof Error ? err : new Error("Failed to load integrations"));
27
+ } finally {
28
+ setLoading(false);
29
+ }
30
+ }, [integration, projectId]);
31
+ useEffect(() => {
32
+ fetchData();
33
+ }, [fetchData]);
34
+ const stats = {
35
+ totalIntegrations: integrations.length,
36
+ activeIntegrations: integrations.filter((i) => i.status === "ACTIVE").length,
37
+ totalConnections: connections.length,
38
+ connectedCount: connections.filter((c) => c.status === "CONNECTED").length,
39
+ totalSyncs: syncConfigs.length,
40
+ activeSyncs: syncConfigs.filter((s) => s.status === "ACTIVE").length
41
+ };
42
+ return {
43
+ integrations,
44
+ connections,
45
+ syncConfigs,
46
+ loading,
47
+ error,
48
+ stats,
49
+ refetch: fetchData
50
+ };
51
+ }
52
+
53
+ // src/ui/hooks/index.ts
54
+ "use client";
55
+ export {
56
+ useIntegrationData
57
+ };
@@ -0,0 +1,54 @@
1
+ // src/ui/hooks/useIntegrationData.ts
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
4
+ "use client";
5
+ function useIntegrationData(projectId = "local-project") {
6
+ const { handlers } = useTemplateRuntime();
7
+ const integration = handlers.integration;
8
+ const [integrations, setIntegrations] = useState([]);
9
+ const [connections, setConnections] = useState([]);
10
+ const [syncConfigs, setSyncConfigs] = useState([]);
11
+ const [loading, setLoading] = useState(true);
12
+ const [error, setError] = useState(null);
13
+ const fetchData = useCallback(async () => {
14
+ try {
15
+ setLoading(true);
16
+ setError(null);
17
+ const [integResult, connResult, syncResult] = await Promise.all([
18
+ integration.listIntegrations({ projectId, limit: 100 }),
19
+ integration.listConnections({ limit: 100 }),
20
+ integration.listSyncConfigs({ limit: 100 })
21
+ ]);
22
+ setIntegrations(integResult.integrations);
23
+ setConnections(connResult.connections);
24
+ setSyncConfigs(syncResult.configs);
25
+ } catch (err) {
26
+ setError(err instanceof Error ? err : new Error("Failed to load integrations"));
27
+ } finally {
28
+ setLoading(false);
29
+ }
30
+ }, [integration, projectId]);
31
+ useEffect(() => {
32
+ fetchData();
33
+ }, [fetchData]);
34
+ const stats = {
35
+ totalIntegrations: integrations.length,
36
+ activeIntegrations: integrations.filter((i) => i.status === "ACTIVE").length,
37
+ totalConnections: connections.length,
38
+ connectedCount: connections.filter((c) => c.status === "CONNECTED").length,
39
+ totalSyncs: syncConfigs.length,
40
+ activeSyncs: syncConfigs.filter((s) => s.status === "ACTIVE").length
41
+ };
42
+ return {
43
+ integrations,
44
+ connections,
45
+ syncConfigs,
46
+ loading,
47
+ error,
48
+ stats,
49
+ refetch: fetchData
50
+ };
51
+ }
52
+ export {
53
+ useIntegrationData
54
+ };