@contractspec/example.integration-hub 3.7.6 → 3.7.7

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.
@@ -1,126 +1,539 @@
1
- // src/ui/renderers/integration.markdown.ts
2
- var mockIntegrations = [
3
- {
4
- id: "int-1",
5
- name: "Salesforce",
6
- type: "CRM",
7
- status: "ACTIVE",
8
- connectionCount: 3
9
- },
10
- {
11
- id: "int-2",
12
- name: "HubSpot",
13
- type: "MARKETING",
14
- status: "ACTIVE",
15
- connectionCount: 2
16
- },
17
- {
18
- id: "int-3",
19
- name: "Stripe",
20
- type: "PAYMENT",
21
- status: "ACTIVE",
22
- connectionCount: 1
23
- },
24
- {
25
- id: "int-4",
26
- name: "Slack",
27
- type: "COMMUNICATION",
28
- status: "INACTIVE",
29
- connectionCount: 0
30
- },
31
- {
32
- id: "int-5",
33
- name: "Google Sheets",
34
- type: "DATA",
35
- status: "ACTIVE",
36
- connectionCount: 5
37
- },
38
- {
39
- id: "int-6",
40
- name: "PostHog",
41
- type: "ANALYTICS",
42
- status: "ACTIVE",
43
- connectionCount: 1
44
- }
1
+ // src/ui/hooks/useIntegrationData.ts
2
+ import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
3
+ import { useCallback, useEffect, useState } from "react";
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
+
56
+ // src/ui/IntegrationHubChat.tsx
57
+ import { ChatWithSidebar } from "@contractspec/module.ai-chat";
58
+ import { jsxDEV } from "react/jsx-dev-runtime";
59
+ "use client";
60
+ var DEFAULT_SUGGESTIONS = [
61
+ "List my integrations",
62
+ "Show sync status",
63
+ "Add a connection"
45
64
  ];
46
- var mockConnections = [
47
- {
48
- id: "conn-1",
49
- integrationId: "int-1",
50
- name: "Production Salesforce",
51
- status: "CONNECTED",
52
- lastSyncAt: "2024-01-16T10:00:00Z"
53
- },
54
- {
55
- id: "conn-2",
56
- integrationId: "int-1",
57
- name: "Sandbox Salesforce",
58
- status: "CONNECTED",
59
- lastSyncAt: "2024-01-15T14:00:00Z"
60
- },
61
- {
62
- id: "conn-3",
63
- integrationId: "int-2",
64
- name: "Marketing HubSpot",
65
- status: "CONNECTED",
66
- lastSyncAt: "2024-01-16T08:00:00Z"
67
- },
68
- {
69
- id: "conn-4",
70
- integrationId: "int-3",
71
- name: "Stripe Live",
72
- status: "CONNECTED",
73
- lastSyncAt: "2024-01-16T12:00:00Z"
74
- },
75
- {
76
- id: "conn-5",
77
- integrationId: "int-5",
78
- name: "Analytics Sheet",
79
- status: "ERROR",
80
- lastSyncAt: "2024-01-14T09:00:00Z",
81
- error: "Authentication expired"
82
- },
83
- {
84
- id: "conn-6",
85
- integrationId: "int-6",
86
- name: "PostHog Workspace",
87
- status: "CONNECTED",
88
- lastSyncAt: "2024-01-16T11:45:00Z"
65
+ var DEFAULT_SYSTEM_PROMPT = `You are an Integration Hub assistant. Help users manage integrations, connections, and sync configurations. When asked about integrations, connections, or syncs, provide clear, actionable guidance.`;
66
+ function IntegrationHubChat({
67
+ proxyUrl = "/api/chat",
68
+ mcpServers,
69
+ thinkingLevel = "thinking",
70
+ suggestions = DEFAULT_SUGGESTIONS,
71
+ systemPrompt = DEFAULT_SYSTEM_PROMPT,
72
+ className
73
+ }) {
74
+ return /* @__PURE__ */ jsxDEV("div", {
75
+ className: className ?? "flex h-[500px] flex-col",
76
+ children: /* @__PURE__ */ jsxDEV(ChatWithSidebar, {
77
+ className: "flex-1",
78
+ systemPrompt,
79
+ proxyUrl,
80
+ mcpServers,
81
+ thinkingLevel,
82
+ suggestions,
83
+ showSuggestionsWhenEmpty: true
84
+ }, undefined, false, undefined, this)
85
+ }, undefined, false, undefined, this);
86
+ }
87
+
88
+ // src/ui/IntegrationDashboard.tsx
89
+ import {
90
+ Button,
91
+ ErrorState,
92
+ LoaderBlock,
93
+ StatCard,
94
+ StatCardGroup
95
+ } from "@contractspec/lib.design-system";
96
+ import { useState as useState2 } from "react";
97
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
98
+ "use client";
99
+ var STATUS_COLORS = {
100
+ ACTIVE: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
101
+ INACTIVE: "bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400",
102
+ CONNECTED: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
103
+ DISCONNECTED: "bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400",
104
+ PENDING: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400",
105
+ ERROR: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400",
106
+ PAUSED: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400"
107
+ };
108
+ var TYPE_ICONS = {
109
+ CRM: "\uD83D\uDCCA",
110
+ MARKETING: "\uD83D\uDCE3",
111
+ PAYMENT: "\uD83D\uDCB3",
112
+ COMMUNICATION: "\uD83D\uDCAC",
113
+ DATA: "\uD83D\uDDC4️",
114
+ CUSTOM: "⚙️"
115
+ };
116
+ function IntegrationDashboard() {
117
+ const [activeTab, setActiveTab] = useState2("integrations");
118
+ const {
119
+ integrations,
120
+ connections,
121
+ syncConfigs,
122
+ loading,
123
+ error,
124
+ stats,
125
+ refetch
126
+ } = useIntegrationData();
127
+ const tabs = [
128
+ { id: "integrations", label: "Integrations", icon: "\uD83D\uDD0C" },
129
+ { id: "connections", label: "Connections", icon: "\uD83D\uDD17" },
130
+ { id: "syncs", label: "Sync Configs", icon: "\uD83D\uDD04" },
131
+ { id: "chat", label: "Chat", icon: "\uD83D\uDCAC" }
132
+ ];
133
+ if (loading) {
134
+ return /* @__PURE__ */ jsxDEV2(LoaderBlock, {
135
+ label: "Loading Integrations..."
136
+ }, undefined, false, undefined, this);
89
137
  }
90
- ];
91
- var mockSyncConfigs = [
92
- {
93
- id: "sync-1",
94
- connectionId: "conn-1",
95
- name: "Contacts Sync",
96
- frequency: "HOURLY",
97
- lastRunAt: "2024-01-16T10:00:00Z",
98
- status: "SUCCESS",
99
- recordsSynced: 1250
100
- },
101
- {
102
- id: "sync-2",
103
- connectionId: "conn-1",
104
- name: "Opportunities Sync",
105
- frequency: "DAILY",
106
- lastRunAt: "2024-01-16T00:00:00Z",
107
- status: "SUCCESS",
108
- recordsSynced: 340
109
- },
110
- {
111
- id: "sync-3",
112
- connectionId: "conn-3",
113
- name: "Orders Sync",
114
- frequency: "REALTIME",
115
- lastRunAt: "2024-01-16T12:30:00Z",
116
- status: "SUCCESS",
117
- recordsSynced: 89
118
- },
119
- {
120
- id: "sync-4",
121
- connectionId: "conn-5",
122
- name: "Metrics Export",
123
- frequency: "DAILY",
138
+ if (error) {
139
+ return /* @__PURE__ */ jsxDEV2(ErrorState, {
140
+ title: "Failed to load Integrations",
141
+ description: error.message,
142
+ onRetry: refetch,
143
+ retryLabel: "Retry"
144
+ }, undefined, false, undefined, this);
145
+ }
146
+ return /* @__PURE__ */ jsxDEV2("div", {
147
+ className: "space-y-6",
148
+ children: [
149
+ /* @__PURE__ */ jsxDEV2("div", {
150
+ className: "flex items-center justify-between",
151
+ children: [
152
+ /* @__PURE__ */ jsxDEV2("h2", {
153
+ className: "font-bold text-2xl",
154
+ children: "Integration Hub"
155
+ }, undefined, false, undefined, this),
156
+ /* @__PURE__ */ jsxDEV2(Button, {
157
+ onClick: () => alert("Add integration modal"),
158
+ children: [
159
+ /* @__PURE__ */ jsxDEV2("span", {
160
+ className: "mr-2",
161
+ children: "+"
162
+ }, undefined, false, undefined, this),
163
+ " Add Integration"
164
+ ]
165
+ }, undefined, true, undefined, this)
166
+ ]
167
+ }, undefined, true, undefined, this),
168
+ /* @__PURE__ */ jsxDEV2(StatCardGroup, {
169
+ children: [
170
+ /* @__PURE__ */ jsxDEV2(StatCard, {
171
+ label: "Integrations",
172
+ value: stats.totalIntegrations,
173
+ hint: `${stats.activeIntegrations} active`
174
+ }, undefined, false, undefined, this),
175
+ /* @__PURE__ */ jsxDEV2(StatCard, {
176
+ label: "Connections",
177
+ value: stats.totalConnections,
178
+ hint: `${stats.connectedCount} connected`
179
+ }, undefined, false, undefined, this),
180
+ /* @__PURE__ */ jsxDEV2(StatCard, {
181
+ label: "Syncs",
182
+ value: stats.totalSyncs,
183
+ hint: `${stats.activeSyncs} active`
184
+ }, undefined, false, undefined, this)
185
+ ]
186
+ }, undefined, true, undefined, this),
187
+ /* @__PURE__ */ jsxDEV2("nav", {
188
+ className: "flex gap-1 rounded-lg bg-muted p-1",
189
+ role: "tablist",
190
+ children: tabs.map((tab) => /* @__PURE__ */ jsxDEV2(Button, {
191
+ type: "button",
192
+ role: "tab",
193
+ "aria-selected": activeTab === tab.id,
194
+ onClick: () => setActiveTab(tab.id),
195
+ 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"}`,
196
+ children: [
197
+ /* @__PURE__ */ jsxDEV2("span", {
198
+ children: tab.icon
199
+ }, undefined, false, undefined, this),
200
+ tab.label
201
+ ]
202
+ }, tab.id, true, undefined, this))
203
+ }, undefined, false, undefined, this),
204
+ /* @__PURE__ */ jsxDEV2("div", {
205
+ className: "min-h-[400px]",
206
+ role: "tabpanel",
207
+ children: [
208
+ activeTab === "integrations" && /* @__PURE__ */ jsxDEV2("div", {
209
+ className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
210
+ children: [
211
+ integrations.map((integration) => /* @__PURE__ */ jsxDEV2("div", {
212
+ className: "cursor-pointer rounded-lg border border-border bg-card p-4 transition-colors hover:bg-muted/50",
213
+ children: [
214
+ /* @__PURE__ */ jsxDEV2("div", {
215
+ className: "mb-3 flex items-center gap-3",
216
+ children: [
217
+ /* @__PURE__ */ jsxDEV2("span", {
218
+ className: "text-2xl",
219
+ children: TYPE_ICONS[integration.type] ?? "⚙️"
220
+ }, undefined, false, undefined, this),
221
+ /* @__PURE__ */ jsxDEV2("div", {
222
+ children: [
223
+ /* @__PURE__ */ jsxDEV2("h3", {
224
+ className: "font-medium",
225
+ children: integration.name
226
+ }, undefined, false, undefined, this),
227
+ /* @__PURE__ */ jsxDEV2("p", {
228
+ className: "text-muted-foreground text-sm",
229
+ children: integration.type
230
+ }, undefined, false, undefined, this)
231
+ ]
232
+ }, undefined, true, undefined, this)
233
+ ]
234
+ }, undefined, true, undefined, this),
235
+ /* @__PURE__ */ jsxDEV2("div", {
236
+ className: "flex items-center justify-between",
237
+ children: [
238
+ /* @__PURE__ */ jsxDEV2("span", {
239
+ className: `inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${STATUS_COLORS[integration.status] ?? ""}`,
240
+ children: integration.status
241
+ }, undefined, false, undefined, this),
242
+ /* @__PURE__ */ jsxDEV2("span", {
243
+ className: "text-muted-foreground text-xs",
244
+ children: integration.createdAt.toLocaleDateString()
245
+ }, undefined, false, undefined, this)
246
+ ]
247
+ }, undefined, true, undefined, this)
248
+ ]
249
+ }, integration.id, true, undefined, this)),
250
+ integrations.length === 0 && /* @__PURE__ */ jsxDEV2("div", {
251
+ className: "col-span-full flex h-64 items-center justify-center text-muted-foreground",
252
+ children: "No integrations configured"
253
+ }, undefined, false, undefined, this)
254
+ ]
255
+ }, undefined, true, undefined, this),
256
+ activeTab === "connections" && /* @__PURE__ */ jsxDEV2("div", {
257
+ className: "rounded-lg border border-border",
258
+ children: /* @__PURE__ */ jsxDEV2("table", {
259
+ className: "w-full",
260
+ children: [
261
+ /* @__PURE__ */ jsxDEV2("thead", {
262
+ className: "border-border border-b bg-muted/30",
263
+ children: /* @__PURE__ */ jsxDEV2("tr", {
264
+ children: [
265
+ /* @__PURE__ */ jsxDEV2("th", {
266
+ className: "px-4 py-3 text-left font-medium text-sm",
267
+ children: "Connection"
268
+ }, undefined, false, undefined, this),
269
+ /* @__PURE__ */ jsxDEV2("th", {
270
+ className: "px-4 py-3 text-left font-medium text-sm",
271
+ children: "Status"
272
+ }, undefined, false, undefined, this),
273
+ /* @__PURE__ */ jsxDEV2("th", {
274
+ className: "px-4 py-3 text-left font-medium text-sm",
275
+ children: "Last Sync"
276
+ }, undefined, false, undefined, this)
277
+ ]
278
+ }, undefined, true, undefined, this)
279
+ }, undefined, false, undefined, this),
280
+ /* @__PURE__ */ jsxDEV2("tbody", {
281
+ className: "divide-y divide-border",
282
+ children: [
283
+ connections.map((conn) => /* @__PURE__ */ jsxDEV2("tr", {
284
+ className: "hover:bg-muted/50",
285
+ children: [
286
+ /* @__PURE__ */ jsxDEV2("td", {
287
+ className: "px-4 py-3",
288
+ children: /* @__PURE__ */ jsxDEV2("div", {
289
+ className: "font-medium",
290
+ children: conn.name
291
+ }, undefined, false, undefined, this)
292
+ }, undefined, false, undefined, this),
293
+ /* @__PURE__ */ jsxDEV2("td", {
294
+ className: "px-4 py-3",
295
+ children: /* @__PURE__ */ jsxDEV2("span", {
296
+ className: `inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${STATUS_COLORS[conn.status] ?? ""}`,
297
+ children: conn.status
298
+ }, undefined, false, undefined, this)
299
+ }, undefined, false, undefined, this),
300
+ /* @__PURE__ */ jsxDEV2("td", {
301
+ className: "px-4 py-3 text-muted-foreground text-sm",
302
+ children: conn.lastSyncAt?.toLocaleString() ?? "Never"
303
+ }, undefined, false, undefined, this)
304
+ ]
305
+ }, conn.id, true, undefined, this)),
306
+ connections.length === 0 && /* @__PURE__ */ jsxDEV2("tr", {
307
+ children: /* @__PURE__ */ jsxDEV2("td", {
308
+ colSpan: 3,
309
+ className: "px-4 py-8 text-center text-muted-foreground",
310
+ children: "No connections found"
311
+ }, undefined, false, undefined, this)
312
+ }, undefined, false, undefined, this)
313
+ ]
314
+ }, undefined, true, undefined, this)
315
+ ]
316
+ }, undefined, true, undefined, this)
317
+ }, undefined, false, undefined, this),
318
+ activeTab === "chat" && /* @__PURE__ */ jsxDEV2(IntegrationHubChat, {
319
+ proxyUrl: "/api/chat",
320
+ thinkingLevel: "thinking",
321
+ suggestions: [
322
+ "List my integrations",
323
+ "Show sync status",
324
+ "Add a connection"
325
+ ],
326
+ className: "min-h-[400px]"
327
+ }, undefined, false, undefined, this),
328
+ activeTab === "syncs" && /* @__PURE__ */ jsxDEV2("div", {
329
+ className: "rounded-lg border border-border",
330
+ children: /* @__PURE__ */ jsxDEV2("table", {
331
+ className: "w-full",
332
+ children: [
333
+ /* @__PURE__ */ jsxDEV2("thead", {
334
+ className: "border-border border-b bg-muted/30",
335
+ children: /* @__PURE__ */ jsxDEV2("tr", {
336
+ children: [
337
+ /* @__PURE__ */ jsxDEV2("th", {
338
+ className: "px-4 py-3 text-left font-medium text-sm",
339
+ children: "Sync Config"
340
+ }, undefined, false, undefined, this),
341
+ /* @__PURE__ */ jsxDEV2("th", {
342
+ className: "px-4 py-3 text-left font-medium text-sm",
343
+ children: "Frequency"
344
+ }, undefined, false, undefined, this),
345
+ /* @__PURE__ */ jsxDEV2("th", {
346
+ className: "px-4 py-3 text-left font-medium text-sm",
347
+ children: "Status"
348
+ }, undefined, false, undefined, this),
349
+ /* @__PURE__ */ jsxDEV2("th", {
350
+ className: "px-4 py-3 text-left font-medium text-sm",
351
+ children: "Records"
352
+ }, undefined, false, undefined, this)
353
+ ]
354
+ }, undefined, true, undefined, this)
355
+ }, undefined, false, undefined, this),
356
+ /* @__PURE__ */ jsxDEV2("tbody", {
357
+ className: "divide-y divide-border",
358
+ children: [
359
+ syncConfigs.map((sync) => /* @__PURE__ */ jsxDEV2("tr", {
360
+ className: "hover:bg-muted/50",
361
+ children: [
362
+ /* @__PURE__ */ jsxDEV2("td", {
363
+ className: "px-4 py-3",
364
+ children: [
365
+ /* @__PURE__ */ jsxDEV2("div", {
366
+ className: "font-medium",
367
+ children: sync.name
368
+ }, undefined, false, undefined, this),
369
+ /* @__PURE__ */ jsxDEV2("div", {
370
+ className: "text-muted-foreground text-sm",
371
+ children: [
372
+ sync.sourceEntity,
373
+ " → ",
374
+ sync.targetEntity
375
+ ]
376
+ }, undefined, true, undefined, this)
377
+ ]
378
+ }, undefined, true, undefined, this),
379
+ /* @__PURE__ */ jsxDEV2("td", {
380
+ className: "px-4 py-3 text-sm",
381
+ children: sync.frequency
382
+ }, undefined, false, undefined, this),
383
+ /* @__PURE__ */ jsxDEV2("td", {
384
+ className: "px-4 py-3",
385
+ children: /* @__PURE__ */ jsxDEV2("span", {
386
+ className: `inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${STATUS_COLORS[sync.status] ?? ""}`,
387
+ children: sync.status
388
+ }, undefined, false, undefined, this)
389
+ }, undefined, false, undefined, this),
390
+ /* @__PURE__ */ jsxDEV2("td", {
391
+ className: "px-4 py-3 text-muted-foreground text-sm",
392
+ children: sync.recordsSynced.toLocaleString()
393
+ }, undefined, false, undefined, this)
394
+ ]
395
+ }, sync.id, true, undefined, this)),
396
+ syncConfigs.length === 0 && /* @__PURE__ */ jsxDEV2("tr", {
397
+ children: /* @__PURE__ */ jsxDEV2("td", {
398
+ colSpan: 4,
399
+ className: "px-4 py-8 text-center text-muted-foreground",
400
+ children: "No sync configurations found"
401
+ }, undefined, false, undefined, this)
402
+ }, undefined, false, undefined, this)
403
+ ]
404
+ }, undefined, true, undefined, this)
405
+ ]
406
+ }, undefined, true, undefined, this)
407
+ }, undefined, false, undefined, this)
408
+ ]
409
+ }, undefined, true, undefined, this)
410
+ ]
411
+ }, undefined, true, undefined, this);
412
+ }
413
+
414
+ // src/ui/renderers/integration.markdown.ts
415
+ var mockIntegrations = [
416
+ {
417
+ id: "int-1",
418
+ name: "Salesforce",
419
+ type: "CRM",
420
+ status: "ACTIVE",
421
+ connectionCount: 3
422
+ },
423
+ {
424
+ id: "int-2",
425
+ name: "HubSpot",
426
+ type: "MARKETING",
427
+ status: "ACTIVE",
428
+ connectionCount: 2
429
+ },
430
+ {
431
+ id: "int-3",
432
+ name: "Stripe",
433
+ type: "PAYMENT",
434
+ status: "ACTIVE",
435
+ connectionCount: 1
436
+ },
437
+ {
438
+ id: "int-4",
439
+ name: "Slack",
440
+ type: "COMMUNICATION",
441
+ status: "INACTIVE",
442
+ connectionCount: 0
443
+ },
444
+ {
445
+ id: "int-5",
446
+ name: "Google Sheets",
447
+ type: "DATA",
448
+ status: "ACTIVE",
449
+ connectionCount: 5
450
+ },
451
+ {
452
+ id: "int-6",
453
+ name: "PostHog",
454
+ type: "ANALYTICS",
455
+ status: "ACTIVE",
456
+ connectionCount: 1
457
+ }
458
+ ];
459
+ var mockConnections = [
460
+ {
461
+ id: "conn-1",
462
+ integrationId: "int-1",
463
+ name: "Production Salesforce",
464
+ status: "CONNECTED",
465
+ lastSyncAt: "2024-01-16T10:00:00Z"
466
+ },
467
+ {
468
+ id: "conn-2",
469
+ integrationId: "int-1",
470
+ name: "Sandbox Salesforce",
471
+ status: "CONNECTED",
472
+ lastSyncAt: "2024-01-15T14:00:00Z"
473
+ },
474
+ {
475
+ id: "conn-3",
476
+ integrationId: "int-2",
477
+ name: "Marketing HubSpot",
478
+ status: "CONNECTED",
479
+ lastSyncAt: "2024-01-16T08:00:00Z"
480
+ },
481
+ {
482
+ id: "conn-4",
483
+ integrationId: "int-3",
484
+ name: "Stripe Live",
485
+ status: "CONNECTED",
486
+ lastSyncAt: "2024-01-16T12:00:00Z"
487
+ },
488
+ {
489
+ id: "conn-5",
490
+ integrationId: "int-5",
491
+ name: "Analytics Sheet",
492
+ status: "ERROR",
493
+ lastSyncAt: "2024-01-14T09:00:00Z",
494
+ error: "Authentication expired"
495
+ },
496
+ {
497
+ id: "conn-6",
498
+ integrationId: "int-6",
499
+ name: "PostHog Workspace",
500
+ status: "CONNECTED",
501
+ lastSyncAt: "2024-01-16T11:45:00Z"
502
+ }
503
+ ];
504
+ var mockSyncConfigs = [
505
+ {
506
+ id: "sync-1",
507
+ connectionId: "conn-1",
508
+ name: "Contacts Sync",
509
+ frequency: "HOURLY",
510
+ lastRunAt: "2024-01-16T10:00:00Z",
511
+ status: "SUCCESS",
512
+ recordsSynced: 1250
513
+ },
514
+ {
515
+ id: "sync-2",
516
+ connectionId: "conn-1",
517
+ name: "Opportunities Sync",
518
+ frequency: "DAILY",
519
+ lastRunAt: "2024-01-16T00:00:00Z",
520
+ status: "SUCCESS",
521
+ recordsSynced: 340
522
+ },
523
+ {
524
+ id: "sync-3",
525
+ connectionId: "conn-3",
526
+ name: "Orders Sync",
527
+ frequency: "REALTIME",
528
+ lastRunAt: "2024-01-16T12:30:00Z",
529
+ status: "SUCCESS",
530
+ recordsSynced: 89
531
+ },
532
+ {
533
+ id: "sync-4",
534
+ connectionId: "conn-5",
535
+ name: "Metrics Export",
536
+ frequency: "DAILY",
124
537
  lastRunAt: "2024-01-14T09:00:00Z",
125
538
  status: "FAILED",
126
539
  recordsSynced: 0
@@ -254,430 +667,18 @@ var syncConfigMarkdownRenderer = {
254
667
  }
255
668
  lines.push("## Frequency Options");
256
669
  lines.push("");
257
- lines.push("- **REALTIME**: Sync on every change");
258
- lines.push("- **HOURLY**: Sync every hour");
259
- lines.push("- **DAILY**: Sync once per day");
260
- lines.push("- **WEEKLY**: Sync once per week");
261
- lines.push("- **MANUAL**: Sync only when triggered");
262
- return {
263
- mimeType: "text/markdown",
264
- body: lines.join(`
265
- `)
266
- };
267
- }
268
- };
269
- // src/ui/hooks/useIntegrationData.ts
270
- import { useCallback, useEffect, useState } from "react";
271
- import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
272
- "use client";
273
- function useIntegrationData(projectId = "local-project") {
274
- const { handlers } = useTemplateRuntime();
275
- const integration = handlers.integration;
276
- const [integrations, setIntegrations] = useState([]);
277
- const [connections, setConnections] = useState([]);
278
- const [syncConfigs, setSyncConfigs] = useState([]);
279
- const [loading, setLoading] = useState(true);
280
- const [error, setError] = useState(null);
281
- const fetchData = useCallback(async () => {
282
- try {
283
- setLoading(true);
284
- setError(null);
285
- const [integResult, connResult, syncResult] = await Promise.all([
286
- integration.listIntegrations({ projectId, limit: 100 }),
287
- integration.listConnections({ limit: 100 }),
288
- integration.listSyncConfigs({ limit: 100 })
289
- ]);
290
- setIntegrations(integResult.integrations);
291
- setConnections(connResult.connections);
292
- setSyncConfigs(syncResult.configs);
293
- } catch (err) {
294
- setError(err instanceof Error ? err : new Error("Failed to load integrations"));
295
- } finally {
296
- setLoading(false);
297
- }
298
- }, [integration, projectId]);
299
- useEffect(() => {
300
- fetchData();
301
- }, [fetchData]);
302
- const stats = {
303
- totalIntegrations: integrations.length,
304
- activeIntegrations: integrations.filter((i) => i.status === "ACTIVE").length,
305
- totalConnections: connections.length,
306
- connectedCount: connections.filter((c) => c.status === "CONNECTED").length,
307
- totalSyncs: syncConfigs.length,
308
- activeSyncs: syncConfigs.filter((s) => s.status === "ACTIVE").length
309
- };
310
- return {
311
- integrations,
312
- connections,
313
- syncConfigs,
314
- loading,
315
- error,
316
- stats,
317
- refetch: fetchData
318
- };
319
- }
320
-
321
- // src/ui/IntegrationHubChat.tsx
322
- import { ChatWithSidebar } from "@contractspec/module.ai-chat";
323
- import { jsxDEV } from "react/jsx-dev-runtime";
324
- "use client";
325
- var DEFAULT_SUGGESTIONS = [
326
- "List my integrations",
327
- "Show sync status",
328
- "Add a connection"
329
- ];
330
- var DEFAULT_SYSTEM_PROMPT = `You are an Integration Hub assistant. Help users manage integrations, connections, and sync configurations. When asked about integrations, connections, or syncs, provide clear, actionable guidance.`;
331
- function IntegrationHubChat({
332
- proxyUrl = "/api/chat",
333
- mcpServers,
334
- thinkingLevel = "thinking",
335
- suggestions = DEFAULT_SUGGESTIONS,
336
- systemPrompt = DEFAULT_SYSTEM_PROMPT,
337
- className
338
- }) {
339
- return /* @__PURE__ */ jsxDEV("div", {
340
- className: className ?? "flex h-[500px] flex-col",
341
- children: /* @__PURE__ */ jsxDEV(ChatWithSidebar, {
342
- className: "flex-1",
343
- systemPrompt,
344
- proxyUrl,
345
- mcpServers,
346
- thinkingLevel,
347
- suggestions,
348
- showSuggestionsWhenEmpty: true
349
- }, undefined, false, undefined, this)
350
- }, undefined, false, undefined, this);
351
- }
352
-
353
- // src/ui/IntegrationDashboard.tsx
354
- import { useState as useState2 } from "react";
355
- import {
356
- Button,
357
- ErrorState,
358
- LoaderBlock,
359
- StatCard,
360
- StatCardGroup
361
- } from "@contractspec/lib.design-system";
362
- import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
363
- "use client";
364
- var STATUS_COLORS = {
365
- ACTIVE: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
366
- INACTIVE: "bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400",
367
- CONNECTED: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
368
- DISCONNECTED: "bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400",
369
- PENDING: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400",
370
- ERROR: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400",
371
- PAUSED: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400"
372
- };
373
- var TYPE_ICONS = {
374
- CRM: "\uD83D\uDCCA",
375
- MARKETING: "\uD83D\uDCE3",
376
- PAYMENT: "\uD83D\uDCB3",
377
- COMMUNICATION: "\uD83D\uDCAC",
378
- DATA: "\uD83D\uDDC4️",
379
- CUSTOM: "⚙️"
380
- };
381
- function IntegrationDashboard() {
382
- const [activeTab, setActiveTab] = useState2("integrations");
383
- const {
384
- integrations,
385
- connections,
386
- syncConfigs,
387
- loading,
388
- error,
389
- stats,
390
- refetch
391
- } = useIntegrationData();
392
- const tabs = [
393
- { id: "integrations", label: "Integrations", icon: "\uD83D\uDD0C" },
394
- { id: "connections", label: "Connections", icon: "\uD83D\uDD17" },
395
- { id: "syncs", label: "Sync Configs", icon: "\uD83D\uDD04" },
396
- { id: "chat", label: "Chat", icon: "\uD83D\uDCAC" }
397
- ];
398
- if (loading) {
399
- return /* @__PURE__ */ jsxDEV2(LoaderBlock, {
400
- label: "Loading Integrations..."
401
- }, undefined, false, undefined, this);
402
- }
403
- if (error) {
404
- return /* @__PURE__ */ jsxDEV2(ErrorState, {
405
- title: "Failed to load Integrations",
406
- description: error.message,
407
- onRetry: refetch,
408
- retryLabel: "Retry"
409
- }, undefined, false, undefined, this);
670
+ lines.push("- **REALTIME**: Sync on every change");
671
+ lines.push("- **HOURLY**: Sync every hour");
672
+ lines.push("- **DAILY**: Sync once per day");
673
+ lines.push("- **WEEKLY**: Sync once per week");
674
+ lines.push("- **MANUAL**: Sync only when triggered");
675
+ return {
676
+ mimeType: "text/markdown",
677
+ body: lines.join(`
678
+ `)
679
+ };
410
680
  }
411
- return /* @__PURE__ */ jsxDEV2("div", {
412
- className: "space-y-6",
413
- children: [
414
- /* @__PURE__ */ jsxDEV2("div", {
415
- className: "flex items-center justify-between",
416
- children: [
417
- /* @__PURE__ */ jsxDEV2("h2", {
418
- className: "text-2xl font-bold",
419
- children: "Integration Hub"
420
- }, undefined, false, undefined, this),
421
- /* @__PURE__ */ jsxDEV2(Button, {
422
- onClick: () => alert("Add integration modal"),
423
- children: [
424
- /* @__PURE__ */ jsxDEV2("span", {
425
- className: "mr-2",
426
- children: "+"
427
- }, undefined, false, undefined, this),
428
- " Add Integration"
429
- ]
430
- }, undefined, true, undefined, this)
431
- ]
432
- }, undefined, true, undefined, this),
433
- /* @__PURE__ */ jsxDEV2(StatCardGroup, {
434
- children: [
435
- /* @__PURE__ */ jsxDEV2(StatCard, {
436
- label: "Integrations",
437
- value: stats.totalIntegrations,
438
- hint: `${stats.activeIntegrations} active`
439
- }, undefined, false, undefined, this),
440
- /* @__PURE__ */ jsxDEV2(StatCard, {
441
- label: "Connections",
442
- value: stats.totalConnections,
443
- hint: `${stats.connectedCount} connected`
444
- }, undefined, false, undefined, this),
445
- /* @__PURE__ */ jsxDEV2(StatCard, {
446
- label: "Syncs",
447
- value: stats.totalSyncs,
448
- hint: `${stats.activeSyncs} active`
449
- }, undefined, false, undefined, this)
450
- ]
451
- }, undefined, true, undefined, this),
452
- /* @__PURE__ */ jsxDEV2("nav", {
453
- className: "bg-muted flex gap-1 rounded-lg p-1",
454
- role: "tablist",
455
- children: tabs.map((tab) => /* @__PURE__ */ jsxDEV2(Button, {
456
- type: "button",
457
- role: "tab",
458
- "aria-selected": activeTab === tab.id,
459
- onClick: () => setActiveTab(tab.id),
460
- 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"}`,
461
- children: [
462
- /* @__PURE__ */ jsxDEV2("span", {
463
- children: tab.icon
464
- }, undefined, false, undefined, this),
465
- tab.label
466
- ]
467
- }, tab.id, true, undefined, this))
468
- }, undefined, false, undefined, this),
469
- /* @__PURE__ */ jsxDEV2("div", {
470
- className: "min-h-[400px]",
471
- role: "tabpanel",
472
- children: [
473
- activeTab === "integrations" && /* @__PURE__ */ jsxDEV2("div", {
474
- className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
475
- children: [
476
- integrations.map((integration) => /* @__PURE__ */ jsxDEV2("div", {
477
- className: "border-border bg-card hover:bg-muted/50 cursor-pointer rounded-lg border p-4 transition-colors",
478
- children: [
479
- /* @__PURE__ */ jsxDEV2("div", {
480
- className: "mb-3 flex items-center gap-3",
481
- children: [
482
- /* @__PURE__ */ jsxDEV2("span", {
483
- className: "text-2xl",
484
- children: TYPE_ICONS[integration.type] ?? "⚙️"
485
- }, undefined, false, undefined, this),
486
- /* @__PURE__ */ jsxDEV2("div", {
487
- children: [
488
- /* @__PURE__ */ jsxDEV2("h3", {
489
- className: "font-medium",
490
- children: integration.name
491
- }, undefined, false, undefined, this),
492
- /* @__PURE__ */ jsxDEV2("p", {
493
- className: "text-muted-foreground text-sm",
494
- children: integration.type
495
- }, undefined, false, undefined, this)
496
- ]
497
- }, undefined, true, undefined, this)
498
- ]
499
- }, undefined, true, undefined, this),
500
- /* @__PURE__ */ jsxDEV2("div", {
501
- className: "flex items-center justify-between",
502
- children: [
503
- /* @__PURE__ */ jsxDEV2("span", {
504
- className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[integration.status] ?? ""}`,
505
- children: integration.status
506
- }, undefined, false, undefined, this),
507
- /* @__PURE__ */ jsxDEV2("span", {
508
- className: "text-muted-foreground text-xs",
509
- children: integration.createdAt.toLocaleDateString()
510
- }, undefined, false, undefined, this)
511
- ]
512
- }, undefined, true, undefined, this)
513
- ]
514
- }, integration.id, true, undefined, this)),
515
- integrations.length === 0 && /* @__PURE__ */ jsxDEV2("div", {
516
- className: "text-muted-foreground col-span-full flex h-64 items-center justify-center",
517
- children: "No integrations configured"
518
- }, undefined, false, undefined, this)
519
- ]
520
- }, undefined, true, undefined, this),
521
- activeTab === "connections" && /* @__PURE__ */ jsxDEV2("div", {
522
- className: "border-border rounded-lg border",
523
- children: /* @__PURE__ */ jsxDEV2("table", {
524
- className: "w-full",
525
- children: [
526
- /* @__PURE__ */ jsxDEV2("thead", {
527
- className: "border-border bg-muted/30 border-b",
528
- children: /* @__PURE__ */ jsxDEV2("tr", {
529
- children: [
530
- /* @__PURE__ */ jsxDEV2("th", {
531
- className: "px-4 py-3 text-left text-sm font-medium",
532
- children: "Connection"
533
- }, undefined, false, undefined, this),
534
- /* @__PURE__ */ jsxDEV2("th", {
535
- className: "px-4 py-3 text-left text-sm font-medium",
536
- children: "Status"
537
- }, undefined, false, undefined, this),
538
- /* @__PURE__ */ jsxDEV2("th", {
539
- className: "px-4 py-3 text-left text-sm font-medium",
540
- children: "Last Sync"
541
- }, undefined, false, undefined, this)
542
- ]
543
- }, undefined, true, undefined, this)
544
- }, undefined, false, undefined, this),
545
- /* @__PURE__ */ jsxDEV2("tbody", {
546
- className: "divide-border divide-y",
547
- children: [
548
- connections.map((conn) => /* @__PURE__ */ jsxDEV2("tr", {
549
- className: "hover:bg-muted/50",
550
- children: [
551
- /* @__PURE__ */ jsxDEV2("td", {
552
- className: "px-4 py-3",
553
- children: /* @__PURE__ */ jsxDEV2("div", {
554
- className: "font-medium",
555
- children: conn.name
556
- }, undefined, false, undefined, this)
557
- }, undefined, false, undefined, this),
558
- /* @__PURE__ */ jsxDEV2("td", {
559
- className: "px-4 py-3",
560
- children: /* @__PURE__ */ jsxDEV2("span", {
561
- className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[conn.status] ?? ""}`,
562
- children: conn.status
563
- }, undefined, false, undefined, this)
564
- }, undefined, false, undefined, this),
565
- /* @__PURE__ */ jsxDEV2("td", {
566
- className: "text-muted-foreground px-4 py-3 text-sm",
567
- children: conn.lastSyncAt?.toLocaleString() ?? "Never"
568
- }, undefined, false, undefined, this)
569
- ]
570
- }, conn.id, true, undefined, this)),
571
- connections.length === 0 && /* @__PURE__ */ jsxDEV2("tr", {
572
- children: /* @__PURE__ */ jsxDEV2("td", {
573
- colSpan: 3,
574
- className: "text-muted-foreground px-4 py-8 text-center",
575
- children: "No connections found"
576
- }, undefined, false, undefined, this)
577
- }, undefined, false, undefined, this)
578
- ]
579
- }, undefined, true, undefined, this)
580
- ]
581
- }, undefined, true, undefined, this)
582
- }, undefined, false, undefined, this),
583
- activeTab === "chat" && /* @__PURE__ */ jsxDEV2(IntegrationHubChat, {
584
- proxyUrl: "/api/chat",
585
- thinkingLevel: "thinking",
586
- suggestions: [
587
- "List my integrations",
588
- "Show sync status",
589
- "Add a connection"
590
- ],
591
- className: "min-h-[400px]"
592
- }, undefined, false, undefined, this),
593
- activeTab === "syncs" && /* @__PURE__ */ jsxDEV2("div", {
594
- className: "border-border rounded-lg border",
595
- children: /* @__PURE__ */ jsxDEV2("table", {
596
- className: "w-full",
597
- children: [
598
- /* @__PURE__ */ jsxDEV2("thead", {
599
- className: "border-border bg-muted/30 border-b",
600
- children: /* @__PURE__ */ jsxDEV2("tr", {
601
- children: [
602
- /* @__PURE__ */ jsxDEV2("th", {
603
- className: "px-4 py-3 text-left text-sm font-medium",
604
- children: "Sync Config"
605
- }, undefined, false, undefined, this),
606
- /* @__PURE__ */ jsxDEV2("th", {
607
- className: "px-4 py-3 text-left text-sm font-medium",
608
- children: "Frequency"
609
- }, undefined, false, undefined, this),
610
- /* @__PURE__ */ jsxDEV2("th", {
611
- className: "px-4 py-3 text-left text-sm font-medium",
612
- children: "Status"
613
- }, undefined, false, undefined, this),
614
- /* @__PURE__ */ jsxDEV2("th", {
615
- className: "px-4 py-3 text-left text-sm font-medium",
616
- children: "Records"
617
- }, undefined, false, undefined, this)
618
- ]
619
- }, undefined, true, undefined, this)
620
- }, undefined, false, undefined, this),
621
- /* @__PURE__ */ jsxDEV2("tbody", {
622
- className: "divide-border divide-y",
623
- children: [
624
- syncConfigs.map((sync) => /* @__PURE__ */ jsxDEV2("tr", {
625
- className: "hover:bg-muted/50",
626
- children: [
627
- /* @__PURE__ */ jsxDEV2("td", {
628
- className: "px-4 py-3",
629
- children: [
630
- /* @__PURE__ */ jsxDEV2("div", {
631
- className: "font-medium",
632
- children: sync.name
633
- }, undefined, false, undefined, this),
634
- /* @__PURE__ */ jsxDEV2("div", {
635
- className: "text-muted-foreground text-sm",
636
- children: [
637
- sync.sourceEntity,
638
- " → ",
639
- sync.targetEntity
640
- ]
641
- }, undefined, true, undefined, this)
642
- ]
643
- }, undefined, true, undefined, this),
644
- /* @__PURE__ */ jsxDEV2("td", {
645
- className: "px-4 py-3 text-sm",
646
- children: sync.frequency
647
- }, undefined, false, undefined, this),
648
- /* @__PURE__ */ jsxDEV2("td", {
649
- className: "px-4 py-3",
650
- children: /* @__PURE__ */ jsxDEV2("span", {
651
- className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[sync.status] ?? ""}`,
652
- children: sync.status
653
- }, undefined, false, undefined, this)
654
- }, undefined, false, undefined, this),
655
- /* @__PURE__ */ jsxDEV2("td", {
656
- className: "text-muted-foreground px-4 py-3 text-sm",
657
- children: sync.recordsSynced.toLocaleString()
658
- }, undefined, false, undefined, this)
659
- ]
660
- }, sync.id, true, undefined, this)),
661
- syncConfigs.length === 0 && /* @__PURE__ */ jsxDEV2("tr", {
662
- children: /* @__PURE__ */ jsxDEV2("td", {
663
- colSpan: 4,
664
- className: "text-muted-foreground px-4 py-8 text-center",
665
- children: "No sync configurations found"
666
- }, undefined, false, undefined, this)
667
- }, undefined, false, undefined, this)
668
- ]
669
- }, undefined, true, undefined, this)
670
- ]
671
- }, undefined, true, undefined, this)
672
- }, undefined, false, undefined, this)
673
- ]
674
- }, undefined, true, undefined, this)
675
- ]
676
- }, undefined, true, undefined, this);
677
- }
678
-
679
- // src/ui/hooks/index.ts
680
- "use client";
681
+ };
681
682
  export {
682
683
  useIntegrationData,
683
684
  syncConfigMarkdownRenderer,