@tangle-network/sandbox-ui 0.16.3 → 0.18.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.
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
- export { B as BillingBalance, a as BillingDashboard, b as BillingDashboardProps, c as BillingSubscription, d as BillingUsage, M as ModelInfo, e as ModelPicker, f as ModelPickerProps, g as ModelPickerVariant, P as PricingPage, h as PricingPageProps, i as PricingTier, T as TemplateCard, j as TemplateCardData, k as TemplateCardProps, U as UsageChart, l as UsageChartProps, m as UsageDataPoint, n as canonicalModelId, o as formatContext, p as formatPrice, q as formatPricing } from './template-card-Dufxl4hV.js';
3
+ export { B as BillingBalance, a as BillingDashboard, b as BillingDashboardProps, c as BillingSubscription, d as BillingUsage, M as ModelInfo, e as ModelPicker, f as ModelPickerProps, g as ModelPickerVariant, P as PricingPage, h as PricingPageProps, i as PricingTier, T as TemplateCard, j as TemplateCardData, k as TemplateCardProps, U as UsageChart, l as UsageChartProps, m as UsageDataPoint, n as canonicalModelId, o as formatContext, p as formatPrice, q as formatPricing } from './template-card-gf-InrfN.js';
4
4
 
5
5
  interface SidebarUser {
6
6
  email: string;
package/dist/dashboard.js CHANGED
@@ -55,7 +55,7 @@ import {
55
55
  formatContext,
56
56
  formatPrice,
57
57
  formatPricing
58
- } from "./chunk-27X3DWMO.js";
58
+ } from "./chunk-N5RYCDLD.js";
59
59
  import "./chunk-7ZA5SEK3.js";
60
60
  import "./chunk-EI44GEQ5.js";
61
61
  export {
package/dist/globals.css CHANGED
@@ -390,6 +390,9 @@
390
390
  max-width: 96rem;
391
391
  }
392
392
  }
393
+ .mx-1 {
394
+ margin-inline: calc(var(--spacing) * 1);
395
+ }
393
396
  .mx-2 {
394
397
  margin-inline: calc(var(--spacing) * 2);
395
398
  }
@@ -588,6 +591,9 @@
588
591
  .h-\[3px\] {
589
592
  height: 3px;
590
593
  }
594
+ .h-\[72\%\] {
595
+ height: 72%;
596
+ }
591
597
  .h-\[500px\] {
592
598
  height: 500px;
593
599
  }
@@ -624,6 +630,9 @@
624
630
  .min-h-\[2px\] {
625
631
  min-height: 2px;
626
632
  }
633
+ .min-h-\[44px\] {
634
+ min-height: 44px;
635
+ }
627
636
  .min-h-\[72px\] {
628
637
  min-height: 72px;
629
638
  }
@@ -708,6 +717,9 @@
708
717
  .w-48 {
709
718
  width: calc(var(--spacing) * 48);
710
719
  }
720
+ .w-64 {
721
+ width: calc(var(--spacing) * 64);
722
+ }
711
723
  .w-72 {
712
724
  width: calc(var(--spacing) * 72);
713
725
  }
@@ -717,6 +729,9 @@
717
729
  .w-\[3px\] {
718
730
  width: 3px;
719
731
  }
732
+ .w-\[72\%\] {
733
+ width: 72%;
734
+ }
720
735
  .w-\[260px\] {
721
736
  width: 260px;
722
737
  }
@@ -789,6 +804,9 @@
789
804
  .max-w-\[460px\] {
790
805
  max-width: 460px;
791
806
  }
807
+ .max-w-\[480px\] {
808
+ max-width: 480px;
809
+ }
792
810
  .max-w-md {
793
811
  max-width: var(--container-md);
794
812
  }
@@ -819,6 +837,9 @@
819
837
  .min-w-\[320px\] {
820
838
  min-width: 320px;
821
839
  }
840
+ .min-w-\[360px\] {
841
+ min-width: 360px;
842
+ }
822
843
  .flex-1 {
823
844
  flex: 1;
824
845
  }
@@ -1020,6 +1041,13 @@
1020
1041
  .gap-px {
1021
1042
  gap: 1px;
1022
1043
  }
1044
+ .space-y-0 {
1045
+ :where(& > :not(:last-child)) {
1046
+ --tw-space-y-reverse: 0;
1047
+ margin-block-start: calc(calc(var(--spacing) * 0) * var(--tw-space-y-reverse));
1048
+ margin-block-end: calc(calc(var(--spacing) * 0) * calc(1 - var(--tw-space-y-reverse)));
1049
+ }
1050
+ }
1023
1051
  .space-y-0\.5 {
1024
1052
  :where(& > :not(:last-child)) {
1025
1053
  --tw-space-y-reverse: 0;
@@ -1486,6 +1514,9 @@
1486
1514
  --tw-gradient-to: transparent;
1487
1515
  --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
1488
1516
  }
1517
+ .object-contain {
1518
+ object-fit: contain;
1519
+ }
1489
1520
  .p-0 {
1490
1521
  padding: calc(var(--spacing) * 0);
1491
1522
  }
@@ -1576,6 +1607,9 @@
1576
1607
  .py-5 {
1577
1608
  padding-block: calc(var(--spacing) * 5);
1578
1609
  }
1610
+ .py-6 {
1611
+ padding-block: calc(var(--spacing) * 6);
1612
+ }
1579
1613
  .py-8 {
1580
1614
  padding-block: calc(var(--spacing) * 8);
1581
1615
  }
@@ -1995,6 +2029,10 @@
1995
2029
  --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
1996
2030
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
1997
2031
  }
2032
+ .shadow-xl {
2033
+ --tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
2034
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
2035
+ }
1998
2036
  .ring {
1999
2037
  --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
2000
2038
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -2138,6 +2176,12 @@
2138
2176
  outline-style: none;
2139
2177
  }
2140
2178
  }
2179
+ .placeholder\:font-normal {
2180
+ &::placeholder {
2181
+ --tw-font-weight: var(--font-weight-normal);
2182
+ font-weight: var(--font-weight-normal);
2183
+ }
2184
+ }
2141
2185
  .after\:absolute {
2142
2186
  &::after {
2143
2187
  content: var(--tw-content);
package/dist/index.d.ts CHANGED
@@ -4,12 +4,14 @@ export { CodeBlock as CodeBlockDisplay, Markdown, MarkdownProps } from '@tangle-
4
4
  export { AgentWorkbench, ApprovalConfidenceStat, ApprovalItem, ApprovalQueue, ApprovalQueueProps, AuditCheck, AuditResults, AuditResultsProps, BannerType, CalendarEvent, CalendarView, CalendarViewProps, ContextBadge, DirectoryPane, DirectoryPaneProps, FormAudit, RuntimePane, RuntimePaneProps, SandboxWorkbench, SandboxWorkbenchArtifact, SandboxWorkbenchCustomArtifact, SandboxWorkbenchFileArtifact, SandboxWorkbenchLayoutOptions, SandboxWorkbenchMarkdownArtifact, SandboxWorkbenchOpenUIArtifact, SandboxWorkbenchProps, SandboxWorkbenchSessionProps, SessionActivityMonitor, SessionActivityMonitorProps, SessionSidebar, SessionSidebarBadge, SessionSidebarFilter, SessionSidebarItem, SessionSidebarLink, SessionSidebarProps, StatusBanner, StatusBannerProps, StatusBar, StatusBarProps, TaskBoard, TaskBoardColumn, TaskBoardItem, TaskBoardProps, TerminalLine, TerminalPanel, TerminalProps, WorkspaceLayout, WorkspaceLayoutProps } from './workspace.js';
5
5
  export { OpenUIAction, OpenUIActionsNode, OpenUIArtifactRenderer, OpenUIArtifactRendererProps, OpenUIBadgeNode, OpenUICardNode, OpenUICodeNode, OpenUIComponentNode, OpenUIGridNode, OpenUIHeadingNode, OpenUIKeyValueNode, OpenUIMarkdownNode, OpenUIPrimitive, OpenUISeparatorNode, OpenUIStackNode, OpenUIStatNode, OpenUITableNode, OpenUITextNode } from '@tangle-network/ui/openui';
6
6
  export { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem, ChatContainer, ChatContainerProps, ChatInput, ChatInputProps, ChatMessage, ChatMessageProps, MessageList, MessageListProps, MessageRole, PendingFile, ThinkingIndicator, ThinkingIndicatorProps, UserMessage, UserMessageProps } from '@tangle-network/ui/chat';
7
+ export { ArtifactAgentDock, ArtifactAgentDockProps, ArtifactAgentDockTransport, ArtifactDockMessage, ArtifactDockStreamEvent, ArtifactKind, ArtifactScope, DEFAULT_REASONING_LEVEL_OPTIONS, ReasoningLevel, ReasoningLevelOption, ReasoningLevelPicker, ReasoningLevelPickerProps, createFetchTransport } from './chat.js';
7
8
  export { ExpandedToolDetail, ExpandedToolDetailProps, InlineThinkingItem, InlineThinkingItemProps, InlineToolItem, InlineToolItemProps, LiveDuration, RunGroup, RunGroupProps } from '@tangle-network/ui/run';
8
9
  export { CommandPreview, DiffPreview, GlobResultsPreview, GrepResultsPreview, QuestionPreview, WebSearchPreview, WriteFilePreview } from '@tangle-network/ui/tool-previews';
9
10
  export { FileArtifactPane, FileArtifactPaneProps, FileNode, FilePreview, FilePreviewProps, FileTabData, FileTabs, FileTabsProps, FileTree, FileTreeProps, FileTreeVisibilityOptions, RichFileTree, RichFileTreeGitEntry, RichFileTreeGitStatus, RichFileTreeProps, RichFileTreeThemeVars, filterFileTree } from '@tangle-network/ui/files';
10
11
  export { Backend, BackendConfig, BackendConfigProps, BackendSelector, BackendSelectorProps, BackendStatusData, ClusterStatusBar, ClusterStatusBarProps, ClusterStatusItem, CreditBalance, CreditBalanceProps, DashboardLayout, DashboardLayoutProps, DashboardProfile, DashboardSnapshotInfo, DashboardUser, ExposedPort, GitCommitData, GitPanel, GitPanelProps, GitStatusData, HARNESS_OPTIONS, HarnessPicker, HarnessPickerProps, HarnessType, InfoPanel, InfoPanelProps, Invoice, InvoiceTable, InvoiceTableProps, McpServer, NavItem, NetworkConfig, NetworkConfigData, NetworkConfigProps, NewSandboxCard, NewSandboxCardProps, PlanCardData, PlanCards, PlanCardsProps, PlanFeature, PortsList, PortsListProps, ProcessInfo, ProcessList, ProcessListProps, ProductVariant, ProfileAvatar, ProfileAvatarProps, ProfileComparison, ProfileComparisonProps, ProfileSelector, ProfileSelectorProps, PromoBanner, PromoBannerProps, RailButton, RailButtonProps, RailModeButton, RailModeButtonProps, RailSeparator, RailSeparatorProps, ResourceMeter, ResourceMeterProps, SIDEBAR_MOBILE_WIDTH, SIDEBAR_PANEL_WIDTH, SIDEBAR_RAIL_WIDTH, SIDEBAR_TOTAL_WIDTH, SandboxCard, SandboxCardData, SandboxCardProps, SandboxStatus, SandboxTable, SandboxTableProps, Sidebar, SidebarContent, SidebarContentProps, SidebarPanel, SidebarPanelContent, SidebarPanelContentProps, SidebarPanelHeader, SidebarPanelHeaderProps, SidebarPanelProps, SidebarProps, SidebarProvider, SidebarProviderProps, SidebarRail, SidebarRailFooter, SidebarRailFooterProps, SidebarRailHeader, SidebarRailHeaderProps, SidebarRailNav, SidebarRailNavProps, SidebarRailProps, SidebarUser, SnapshotList, SnapshotListProps, SystemLogsViewer, SystemLogsViewerProps, TeamRole, UsageSummary, UsageSummaryData, UsageSummaryProps, Variant, VariantList, VariantListProps, VariantOutcome, VariantStatus, canAdminSandbox, useSidebar } from './dashboard.js';
11
- export { B as BillingBalance, a as BillingDashboard, b as BillingDashboardProps, c as BillingSubscription, d as BillingUsage, M as ModelInfo, e as ModelPicker, f as ModelPickerProps, g as ModelPickerVariant, P as PricingPage, h as PricingPageProps, i as PricingTier, T as TemplateCard, j as TemplateCardData, k as TemplateCardProps, U as UsageChart, l as UsageChartProps, m as UsageDataPoint, n as canonicalModelId, o as formatContext, p as formatPrice, q as formatPricing } from './template-card-Dufxl4hV.js';
12
+ export { B as BillingBalance, a as BillingDashboard, b as BillingDashboardProps, c as BillingSubscription, d as BillingUsage, M as ModelInfo, e as ModelPicker, f as ModelPickerProps, g as ModelPickerVariant, P as PricingPage, h as PricingPageProps, i as PricingTier, T as TemplateCard, j as TemplateCardData, k as TemplateCardProps, U as UsageChart, l as UsageChartProps, m as UsageDataPoint, n as canonicalModelId, o as formatContext, p as formatPrice, q as formatPricing } from './template-card-gf-InrfN.js';
12
13
  export { AuthHeader, AuthHeaderProps, GitHubLoginButton, GitHubLoginButtonProps, LoginLayout, LoginLayoutProps, SessionUser, UserMenu, UserMenuProps } from '@tangle-network/ui/auth';
14
+ export { TangleLoginButton, TangleLoginButtonProps } from './auth.js';
13
15
  export { AgentStreamEvent, AppendUserMessageOptions, ApplySdkEventOptions, AuthUser, AutomationStreamEvent, BeginAssistantMessageOptions, BotStreamEvent, CompleteAssistantMessageOptions, RealtimeSessionOptions, RealtimeSessionRegistry, RealtimeSessionRegistryProps, RealtimeSessionState, RealtimeSessionTarget, SSEEvent, SdkSessionAttachment, SdkSessionEvent, SdkSessionSeed, TaskStreamEvent, TerminalStreamEvent, UseAuthOptions, UseAuthResult, UseRunGroupsOptions, UseSSEStreamOptions, UseSSEStreamResult, UseSdkSessionOptions, UseSdkSessionReturn, UseToolCallStreamReturn, createAuthFetcher, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useLiveTime, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useToolCallStream } from '@tangle-network/ui/hooks';
14
16
  export { SandboxMetrics, SidecarMetricsPayload, UsePtySessionOptions, UsePtySessionReturn, UseSandboxMetricsOptions, UseSandboxMetricsResult, useCreateSession, useDeleteSession, usePtySession, useRenameSession, useSandboxMetrics, useSessions } from './hooks.js';
15
17
  export { SessionInfo, SidecarAuth, UseSessionStreamOptions, UseSessionStreamResult, UseSidecarAuthOptions, useSessionStream, useSidecarAuth } from './sdk-hooks.js';
package/dist/index.js CHANGED
@@ -1,3 +1,43 @@
1
+ import {
2
+ activeSessionsAtom,
3
+ addMessage,
4
+ addParts,
5
+ bumpActiveSessionActivity,
6
+ clearChat,
7
+ connectSession,
8
+ disconnectSession,
9
+ getActiveSession,
10
+ getAllActiveSessions,
11
+ getAllProjectActivity,
12
+ getSessionsByActivity,
13
+ getSessionsForNavbar,
14
+ getSessionsForProject,
15
+ getTotalRunningSessionCount,
16
+ hasBackgroundRunningSessions,
17
+ isStreamingAtom,
18
+ messagesAtom,
19
+ partMapAtom,
20
+ registerActiveSession,
21
+ resetActiveSessions,
22
+ sessionAtom,
23
+ setActiveSessionAttention,
24
+ setActiveSessionConnection,
25
+ setActiveSessionError,
26
+ setActiveSessionRunning,
27
+ setForegroundActiveSession,
28
+ unregisterActiveSession,
29
+ updateActiveSessionMeta,
30
+ updatePart,
31
+ useActiveSession,
32
+ useActiveSessions,
33
+ useActiveSessionsState,
34
+ useHasBackgroundRunningSessions,
35
+ useNavbarSessions,
36
+ useProjectActivity,
37
+ useProjectSessions,
38
+ useSessionsByActivity,
39
+ useTotalRunningSessions
40
+ } from "./chunk-WID73FPH.js";
1
41
  import "./chunk-2BUPSB7O.js";
2
42
  import {
3
43
  TOOL_CATEGORY_ICONS,
@@ -16,8 +56,9 @@ import {
16
56
  AuthHeader,
17
57
  GitHubLoginButton,
18
58
  LoginLayout,
59
+ TangleLoginButton,
19
60
  UserMenu
20
- } from "./chunk-NJNME4J4.js";
61
+ } from "./chunk-IOB2PW5Z.js";
21
62
  import {
22
63
  RealtimeSessionRegistry,
23
64
  createAuthFetcher,
@@ -45,55 +86,19 @@ import {
45
86
  useSessionStream,
46
87
  useSidecarAuth
47
88
  } from "./chunk-CMY7W45U.js";
48
- import {
49
- activeSessionsAtom,
50
- addMessage,
51
- addParts,
52
- bumpActiveSessionActivity,
53
- clearChat,
54
- connectSession,
55
- disconnectSession,
56
- getActiveSession,
57
- getAllActiveSessions,
58
- getAllProjectActivity,
59
- getSessionsByActivity,
60
- getSessionsForNavbar,
61
- getSessionsForProject,
62
- getTotalRunningSessionCount,
63
- hasBackgroundRunningSessions,
64
- isStreamingAtom,
65
- messagesAtom,
66
- partMapAtom,
67
- registerActiveSession,
68
- resetActiveSessions,
69
- sessionAtom,
70
- setActiveSessionAttention,
71
- setActiveSessionConnection,
72
- setActiveSessionError,
73
- setActiveSessionRunning,
74
- setForegroundActiveSession,
75
- unregisterActiveSession,
76
- updateActiveSessionMeta,
77
- updatePart,
78
- useActiveSession,
79
- useActiveSessions,
80
- useActiveSessionsState,
81
- useHasBackgroundRunningSessions,
82
- useNavbarSessions,
83
- useProjectActivity,
84
- useProjectSessions,
85
- useSessionsByActivity,
86
- useTotalRunningSessions
87
- } from "./chunk-WID73FPH.js";
88
89
  import {
89
90
  AgentTimeline,
91
+ ArtifactAgentDock,
90
92
  ChatContainer,
91
93
  ChatInput,
92
94
  ChatMessage,
95
+ DEFAULT_REASONING_LEVEL_OPTIONS,
93
96
  MessageList,
97
+ ReasoningLevelPicker,
94
98
  ThinkingIndicator,
95
- UserMessage
96
- } from "./chunk-QPAJR74X.js";
99
+ UserMessage,
100
+ createFetchTransport
101
+ } from "./chunk-CNVE6KOM.js";
97
102
  import {
98
103
  ExpandedToolDetail,
99
104
  InlineThinkingItem,
@@ -186,7 +191,7 @@ import {
186
191
  formatContext,
187
192
  formatPrice,
188
193
  formatPricing
189
- } from "./chunk-27X3DWMO.js";
194
+ } from "./chunk-N5RYCDLD.js";
190
195
  import {
191
196
  Avatar,
192
197
  AvatarFallback,
@@ -297,6 +302,7 @@ export {
297
302
  AgentTimeline,
298
303
  AgentWorkbench,
299
304
  ApprovalQueue,
305
+ ArtifactAgentDock,
300
306
  ArtifactPane,
301
307
  AuditResults,
302
308
  AuthHeader,
@@ -324,6 +330,7 @@ export {
324
330
  CommandPreview,
325
331
  CopyButton,
326
332
  CreditBalance,
333
+ DEFAULT_REASONING_LEVEL_OPTIONS,
327
334
  DashboardLayout,
328
335
  Dialog,
329
336
  DialogClose,
@@ -395,6 +402,7 @@ export {
395
402
  RailModeButton,
396
403
  RailSeparator,
397
404
  RealtimeSessionRegistry,
405
+ ReasoningLevelPicker,
398
406
  ResourceMeter,
399
407
  RichFileTree,
400
408
  RunGroup,
@@ -453,6 +461,7 @@ export {
453
461
  TabsList,
454
462
  TabsTrigger,
455
463
  TangleKnot,
464
+ TangleLoginButton,
456
465
  TaskBoard,
457
466
  TemplateCard,
458
467
  TerminalDisplay,
@@ -487,6 +496,7 @@ export {
487
496
  connectSession,
488
497
  copyText,
489
498
  createAuthFetcher,
499
+ createFetchTransport,
490
500
  disconnectSession,
491
501
  filterFileTree,
492
502
  formatBytes,
@@ -0,0 +1,114 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ /**
4
+ * Shapes for the integrations primitives. Mirrors the platform's
5
+ * `/v1/integrations/*` response shape so consumers can pipe payloads
6
+ * straight through. Defined here (rather than imported from
7
+ * `@tangle-network/agent-runtime/platform`) so the UI package stays
8
+ * leaf-level — no dependency on the server-side client.
9
+ */
10
+ interface IntegrationConnection {
11
+ id: string;
12
+ providerId: string;
13
+ connectorId: string;
14
+ status: "connected" | "pending" | "revoked" | "expired" | (string & {});
15
+ grantedScopes?: string[];
16
+ account?: {
17
+ identity?: string;
18
+ displayName?: string;
19
+ } & Record<string, unknown>;
20
+ expiresAt?: string | null;
21
+ createdAt?: string;
22
+ updatedAt?: string;
23
+ }
24
+ interface IntegrationConnector {
25
+ connectorId: string;
26
+ displayName?: string;
27
+ description?: string;
28
+ scopes?: string[];
29
+ }
30
+ interface IntegrationProvider {
31
+ providerId: string;
32
+ displayName?: string;
33
+ description?: string;
34
+ iconUrl?: string;
35
+ connectors?: IntegrationConnector[];
36
+ }
37
+ interface IntegrationHealth {
38
+ connectionId: string;
39
+ status: "ok" | "degraded" | "failing" | "unknown" | (string & {});
40
+ checkedAt?: string;
41
+ message?: string;
42
+ }
43
+
44
+ interface IntegrationsPanelProps {
45
+ catalog: IntegrationProvider[];
46
+ connections: IntegrationConnection[];
47
+ healthByConnectionId?: Record<string, IntegrationHealth>;
48
+ isLoading?: boolean;
49
+ error?: Error | null;
50
+ /**
51
+ * Invoked when the user clicks "Connect" on a catalog tile. The
52
+ * consumer should call its data hook's `connect(...)` action.
53
+ */
54
+ onConnect: (input: {
55
+ providerId: string;
56
+ connectorId: string;
57
+ }) => void | Promise<void>;
58
+ /** Invoked when the user clicks "Disconnect" on a live connection. */
59
+ onDisconnect: (connectionId: string) => void | Promise<void>;
60
+ /** Empty-state message when the catalog hasn't loaded any providers. */
61
+ emptyCatalogLabel?: string;
62
+ className?: string;
63
+ }
64
+ declare function IntegrationsPanel({ catalog, connections, healthByConnectionId, isLoading, error, onConnect, onDisconnect, emptyCatalogLabel, className, }: IntegrationsPanelProps): react_jsx_runtime.JSX.Element;
65
+
66
+ /**
67
+ * Endpoint contract expected on the consumer app's server (which
68
+ * wraps `PlatformHubClient` from `@tangle-network/agent-runtime/platform`):
69
+ *
70
+ * GET {base}/catalog
71
+ * → { catalog: { providers: IntegrationProvider[] } }
72
+ * GET {base}/connections
73
+ * → { connections: IntegrationConnection[] }
74
+ * GET {base}/healthchecks (optional)
75
+ * → { healthchecks: IntegrationHealth[] }
76
+ * POST {base}/auth/start
77
+ * body { providerId, connectorId, returnUrl, requestedScopes? }
78
+ * → { authorizationUrl: string }
79
+ * DELETE {base}/connections/{connectionId}
80
+ * → { connection: IntegrationConnection }
81
+ */
82
+ interface UseIntegrationsOptions {
83
+ /** Base URL where the consumer mounted the integrations endpoints. */
84
+ apiBaseUrl: string;
85
+ /** Custom fetch (tests / non-browser runtimes). */
86
+ fetchImpl?: typeof fetch;
87
+ /** Whether the initial load happens automatically on mount. */
88
+ autoLoad?: boolean;
89
+ }
90
+ interface UseIntegrationsResult {
91
+ catalog: IntegrationProvider[];
92
+ connections: IntegrationConnection[];
93
+ healthByConnectionId: Record<string, IntegrationHealth>;
94
+ isLoading: boolean;
95
+ error: Error | null;
96
+ refresh: () => Promise<void>;
97
+ /** Kick off OAuth — navigates the window on success. */
98
+ connect: (input: ConnectInput) => Promise<void>;
99
+ /** Revoke a connection by id; refreshes the connections list. */
100
+ disconnect: (connectionId: string) => Promise<void>;
101
+ }
102
+ interface ConnectInput {
103
+ providerId: string;
104
+ connectorId: string;
105
+ /**
106
+ * URL the platform redirects the user back to after OAuth. Must be
107
+ * allow-listed on the platform.
108
+ */
109
+ returnUrl: string;
110
+ requestedScopes?: string[];
111
+ }
112
+ declare function useIntegrations({ apiBaseUrl, fetchImpl, autoLoad, }: UseIntegrationsOptions): UseIntegrationsResult;
113
+
114
+ export { type ConnectInput, type IntegrationConnection, type IntegrationConnector, type IntegrationHealth, type IntegrationProvider, IntegrationsPanel, type IntegrationsPanelProps, type UseIntegrationsOptions, type UseIntegrationsResult, useIntegrations };
@@ -0,0 +1,245 @@
1
+ // src/integrations/integrations-panel.tsx
2
+ import * as React from "react";
3
+ import {
4
+ Badge,
5
+ Button,
6
+ Card,
7
+ CardContent,
8
+ CardHeader,
9
+ EmptyState
10
+ } from "@tangle-network/ui/primitives";
11
+ import { cn } from "@tangle-network/ui/utils";
12
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
+ function statusVariant(status) {
14
+ if (status === "connected" || status === "ok") return "default";
15
+ if (status === "pending") return "secondary";
16
+ if (status === "revoked" || status === "expired" || status === "failing")
17
+ return "destructive";
18
+ return "outline";
19
+ }
20
+ function defaultConnectorOf(provider) {
21
+ return provider.connectors?.[0]?.connectorId ?? provider.providerId;
22
+ }
23
+ function buildConnectionIndex(connections) {
24
+ const index = /* @__PURE__ */ new Map();
25
+ for (const conn of connections) {
26
+ if (conn.status === "revoked") continue;
27
+ index.set(`${conn.providerId}:${conn.connectorId}`, conn);
28
+ }
29
+ return index;
30
+ }
31
+ function IntegrationsPanel({
32
+ catalog,
33
+ connections,
34
+ healthByConnectionId,
35
+ isLoading,
36
+ error,
37
+ onConnect,
38
+ onDisconnect,
39
+ emptyCatalogLabel = "No integrations available yet.",
40
+ className
41
+ }) {
42
+ const connectionIndex = React.useMemo(
43
+ () => buildConnectionIndex(connections),
44
+ [connections]
45
+ );
46
+ if (error) {
47
+ return /* @__PURE__ */ jsx(Card, { className: cn("border-destructive/50", className), children: /* @__PURE__ */ jsx(CardContent, { className: "py-6", children: /* @__PURE__ */ jsxs("p", { className: "text-sm text-destructive", children: [
48
+ "Failed to load integrations: ",
49
+ error.message
50
+ ] }) }) });
51
+ }
52
+ if (isLoading && catalog.length === 0) {
53
+ return /* @__PURE__ */ jsx("div", { className: cn("grid gap-3 sm:grid-cols-2 lg:grid-cols-3", className), children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ jsxs(Card, { className: "animate-pulse", children: [
54
+ /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx("div", { className: "h-5 w-32 rounded bg-muted" }) }),
55
+ /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx("div", { className: "h-4 w-full rounded bg-muted" }) })
56
+ ] }, i)) });
57
+ }
58
+ if (catalog.length === 0) {
59
+ return /* @__PURE__ */ jsx(
60
+ EmptyState,
61
+ {
62
+ title: "No integrations",
63
+ description: emptyCatalogLabel,
64
+ className
65
+ }
66
+ );
67
+ }
68
+ return /* @__PURE__ */ jsx("div", { className: cn("grid gap-3 sm:grid-cols-2 lg:grid-cols-3", className), children: catalog.map((provider) => {
69
+ const connectorId = defaultConnectorOf(provider);
70
+ const live = connectionIndex.get(`${provider.providerId}:${connectorId}`);
71
+ const health = live ? healthByConnectionId?.[live.id] : void 0;
72
+ const headline = provider.displayName ?? provider.providerId.replace(/[-_]/g, " ");
73
+ return /* @__PURE__ */ jsxs(
74
+ Card,
75
+ {
76
+ "data-testid": `integration-${provider.providerId}`,
77
+ children: [
78
+ /* @__PURE__ */ jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-2 space-y-0", children: [
79
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
80
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
81
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold capitalize text-foreground", children: headline }),
82
+ live ? /* @__PURE__ */ jsx(Badge, { variant: statusVariant(live.status), className: "text-xs", children: live.status }) : null
83
+ ] }),
84
+ provider.description ? /* @__PURE__ */ jsx("p", { className: "line-clamp-2 text-xs text-muted-foreground", children: provider.description }) : null
85
+ ] }),
86
+ health ? /* @__PURE__ */ jsx(
87
+ Badge,
88
+ {
89
+ variant: statusVariant(health.status),
90
+ className: "text-xs uppercase",
91
+ children: health.status
92
+ }
93
+ ) : null
94
+ ] }),
95
+ /* @__PURE__ */ jsx(CardContent, { className: "flex items-center justify-between gap-2", children: live ? /* @__PURE__ */ jsxs(Fragment, { children: [
96
+ /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: live.account?.displayName ?? live.account?.identity ?? "Connected" }),
97
+ /* @__PURE__ */ jsx(
98
+ Button,
99
+ {
100
+ size: "sm",
101
+ variant: "outline",
102
+ onClick: () => onDisconnect(live.id),
103
+ "data-testid": `disconnect-${provider.providerId}`,
104
+ children: "Disconnect"
105
+ }
106
+ )
107
+ ] }) : /* @__PURE__ */ jsx(
108
+ Button,
109
+ {
110
+ size: "sm",
111
+ className: "ml-auto",
112
+ onClick: () => onConnect({ providerId: provider.providerId, connectorId }),
113
+ "data-testid": `connect-${provider.providerId}`,
114
+ children: "Connect"
115
+ }
116
+ ) })
117
+ ]
118
+ },
119
+ `${provider.providerId}:${connectorId}`
120
+ );
121
+ }) });
122
+ }
123
+
124
+ // src/integrations/use-integrations.ts
125
+ import * as React2 from "react";
126
+ function unwrap(json) {
127
+ if (json && typeof json === "object" && "data" in json && json.data !== void 0) {
128
+ return json.data;
129
+ }
130
+ return json;
131
+ }
132
+ function useIntegrations({
133
+ apiBaseUrl,
134
+ fetchImpl,
135
+ autoLoad = true
136
+ }) {
137
+ const fetcher = fetchImpl ?? (typeof fetch === "function" ? fetch : null);
138
+ if (!fetcher) {
139
+ throw new Error("useIntegrations: fetch is not available in this environment");
140
+ }
141
+ const base = apiBaseUrl.replace(/\/+$/, "");
142
+ const [catalog, setCatalog] = React2.useState([]);
143
+ const [connections, setConnections] = React2.useState([]);
144
+ const [healthByConnectionId, setHealthByConnectionId] = React2.useState({});
145
+ const [isLoading, setIsLoading] = React2.useState(autoLoad);
146
+ const [error, setError] = React2.useState(null);
147
+ const refresh = React2.useCallback(async () => {
148
+ setIsLoading(true);
149
+ setError(null);
150
+ try {
151
+ const [catalogRes, connectionsRes] = await Promise.all([
152
+ fetcher(`${base}/catalog`, { credentials: "include" }),
153
+ fetcher(`${base}/connections`, { credentials: "include" })
154
+ ]);
155
+ if (!catalogRes.ok) {
156
+ throw new Error(`Failed to load integration catalog (${catalogRes.status})`);
157
+ }
158
+ if (!connectionsRes.ok) {
159
+ throw new Error(
160
+ `Failed to load integration connections (${connectionsRes.status})`
161
+ );
162
+ }
163
+ const catalogJson = unwrap(await catalogRes.json());
164
+ const providers = catalogJson?.catalog?.providers ?? catalogJson?.providers ?? [];
165
+ setCatalog(providers);
166
+ const connectionsJson = unwrap(
167
+ await connectionsRes.json()
168
+ );
169
+ setConnections(connectionsJson?.connections ?? []);
170
+ try {
171
+ const healthRes = await fetcher(`${base}/healthchecks`, {
172
+ credentials: "include"
173
+ });
174
+ if (healthRes.ok) {
175
+ const healthJson = unwrap(
176
+ await healthRes.json()
177
+ );
178
+ const map = {};
179
+ for (const h of healthJson?.healthchecks ?? []) {
180
+ map[h.connectionId] = h;
181
+ }
182
+ setHealthByConnectionId(map);
183
+ }
184
+ } catch {
185
+ }
186
+ } catch (err) {
187
+ setError(err instanceof Error ? err : new Error(String(err)));
188
+ } finally {
189
+ setIsLoading(false);
190
+ }
191
+ }, [base, fetcher]);
192
+ React2.useEffect(() => {
193
+ if (autoLoad) {
194
+ void refresh();
195
+ }
196
+ }, [autoLoad, refresh]);
197
+ const connect = React2.useCallback(
198
+ async (input) => {
199
+ const res = await fetcher(`${base}/auth/start`, {
200
+ method: "POST",
201
+ credentials: "include",
202
+ headers: { "content-type": "application/json" },
203
+ body: JSON.stringify(input)
204
+ });
205
+ if (!res.ok) {
206
+ const text = await res.text().catch(() => "");
207
+ throw new Error(`Failed to start OAuth (${res.status}): ${text}`);
208
+ }
209
+ const json = unwrap(await res.json());
210
+ if (!json?.authorizationUrl) {
211
+ throw new Error("Platform did not return an authorizationUrl");
212
+ }
213
+ window.location.href = json.authorizationUrl;
214
+ },
215
+ [base, fetcher]
216
+ );
217
+ const disconnect = React2.useCallback(
218
+ async (connectionId) => {
219
+ const res = await fetcher(
220
+ `${base}/connections/${encodeURIComponent(connectionId)}`,
221
+ { method: "DELETE", credentials: "include" }
222
+ );
223
+ if (!res.ok) {
224
+ const text = await res.text().catch(() => "");
225
+ throw new Error(`Failed to revoke connection (${res.status}): ${text}`);
226
+ }
227
+ await refresh();
228
+ },
229
+ [base, fetcher, refresh]
230
+ );
231
+ return {
232
+ catalog,
233
+ connections,
234
+ healthByConnectionId,
235
+ isLoading,
236
+ error,
237
+ refresh,
238
+ connect,
239
+ disconnect
240
+ };
241
+ }
242
+ export {
243
+ IntegrationsPanel,
244
+ useIntegrations
245
+ };