@tangle-network/sandbox-ui 0.46.0 → 0.48.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 {
2
2
  ProviderIcon
3
- } from "./chunk-CXV6X33U.js";
3
+ } from "./chunk-GTJ5PSK5.js";
4
4
  import {
5
5
  buildWorkflowGraph
6
6
  } from "./chunk-SUC6ZJZW.js";
package/dist/assistant.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ProviderIcon
3
- } from "./chunk-CXV6X33U.js";
3
+ } from "./chunk-GTJ5PSK5.js";
4
4
  import {
5
5
  providerLabel
6
6
  } from "./chunk-7JLB7UZ3.js";
@@ -1899,6 +1899,7 @@ function SidebarLayoutInner({
1899
1899
  profileMenuItems,
1900
1900
  showThemeToggle = false,
1901
1901
  railFooter,
1902
+ railCollapseToggle = "footer",
1902
1903
  LinkComponent,
1903
1904
  hideBelow,
1904
1905
  railLabels = false,
@@ -1915,15 +1916,20 @@ function SidebarLayoutInner({
1915
1916
  return /* @__PURE__ */ jsxs14("div", { className: cn("min-h-screen bg-surface text-foreground", className), children: [
1916
1917
  /* @__PURE__ */ jsx15("div", { className: cn(hideBelow && HIDE_BELOW_CLASS[hideBelow]), children: /* @__PURE__ */ jsxs14(Sidebar, { className: sidebarClassName, children: [
1917
1918
  /* @__PURE__ */ jsxs14(SidebarRail, { children: [
1918
- (railHeaderContent !== void 0 || logo !== void 0) && /* @__PURE__ */ jsx15(SidebarRailHeader, { className: cn(showLabels && (railHeaderContent !== void 0 ? "px-2" : "justify-start px-4")), children: railHeaderContent !== void 0 ? railHeaderContent : /* @__PURE__ */ jsx15(
1919
- Link,
1920
- {
1921
- href: logoHref,
1922
- to: logoHref,
1923
- className: "flex items-center justify-center rounded-lg p-1 transition-colors hover:bg-surface-container-high",
1924
- children: logo
1925
- }
1926
- ) }),
1919
+ (railHeaderContent !== void 0 || logo !== void 0 || railLabels && railCollapseToggle === "header") && /* @__PURE__ */ jsxs14(SidebarRailHeader, { className: cn(showLabels && (railHeaderContent !== void 0 ? "px-2" : "justify-start px-4")), children: [
1920
+ railHeaderContent !== void 0 ? railHeaderContent : logo !== void 0 ? /* @__PURE__ */ jsx15(
1921
+ Link,
1922
+ {
1923
+ href: logoHref,
1924
+ to: logoHref,
1925
+ className: "flex items-center justify-center rounded-lg p-1 transition-colors hover:bg-surface-container-high",
1926
+ children: logo
1927
+ }
1928
+ ) : null,
1929
+ railLabels && railCollapseToggle === "header" && // Icon-only in the header row (the labeled, full-width variant is
1930
+ // for the vertical footer stack); sits beside the logo/content.
1931
+ /* @__PURE__ */ jsx15(RailCollapseToggle, { collapsed: railCollapsed, showLabel: false, onToggle: toggleRail, className: "shrink-0" })
1932
+ ] }),
1927
1933
  /* @__PURE__ */ jsx15(SidebarRailNav, { className: showLabels ? "px-2" : void 0, children: navItems.map((item) => {
1928
1934
  if (item.flyoutItems && item.flyoutItems.length > 0) {
1929
1935
  const activeSet = new Set(item.flyoutActiveIds ?? []);
@@ -1983,7 +1989,7 @@ function SidebarLayoutInner({
1983
1989
  ) }, item.id);
1984
1990
  }) }),
1985
1991
  (railLabels || railFooter !== void 0 || hasProfile) && /* @__PURE__ */ jsxs14(SidebarRailFooter, { className: cn("border-t border-[var(--md3-outline-variant)] pt-2", showLabels && "items-stretch px-2"), children: [
1986
- railLabels && /* @__PURE__ */ jsx15(RailCollapseToggle, { collapsed: railCollapsed, showLabel: showLabels, onToggle: toggleRail }),
1992
+ railLabels && railCollapseToggle === "footer" && /* @__PURE__ */ jsx15(RailCollapseToggle, { collapsed: railCollapsed, showLabel: showLabels, onToggle: toggleRail }),
1987
1993
  railFooter,
1988
1994
  hasProfile && (() => {
1989
1995
  const profile = /* @__PURE__ */ jsx15(
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-3J6FG3FJ.js";
4
4
  import {
5
5
  PortsList
6
- } from "./chunk-PZ62T5PM.js";
6
+ } from "./chunk-3WUSPCPC.js";
7
7
  import {
8
8
  TerminalView
9
9
  } from "./chunk-VIREDUBF.js";
@@ -97,6 +97,74 @@ var PROVIDER_LOGO_SLUGS = {
97
97
  buffer: "buffer",
98
98
  hootsuite: "hootsuite"
99
99
  };
100
+ var ACTIVEPIECES_CDN = "https://cdn.activepieces.com/pieces";
101
+ var PROVIDER_LOGO_URLS = {
102
+ // Catalog logo whose filename/extension differs from the provider id.
103
+ "cal-com": `${ACTIVEPIECES_CDN}/cal.com.png`,
104
+ "customer-io": `${ACTIVEPIECES_CDN}/customerio.png`,
105
+ anthropic: `${ACTIVEPIECES_CDN}/claude.png`,
106
+ telegram: `${ACTIVEPIECES_CDN}/telegram_bot.png`,
107
+ "twilio-sms": `${ACTIVEPIECES_CDN}/twilio.png`,
108
+ "amazon-sqs": `${ACTIVEPIECES_CDN}/aws-sqs.png`,
109
+ frame: `${ACTIVEPIECES_CDN}/frameio.png`,
110
+ "jira-cloud": `${ACTIVEPIECES_CDN}/jira.png`,
111
+ "jira-data-center": `${ACTIVEPIECES_CDN}/jira.png`,
112
+ stripe: `${ACTIVEPIECES_CDN}/stripe.png`,
113
+ "stripe-pack": `${ACTIVEPIECES_CDN}/stripe.png`,
114
+ gemini: `${ACTIVEPIECES_CDN}/google-gemini.png`,
115
+ "google-gemini": `${ACTIVEPIECES_CDN}/google-gemini.png`,
116
+ bluesky: `${ACTIVEPIECES_CDN}/bluesky.png`,
117
+ emailit: `${ACTIVEPIECES_CDN}/emailit.svg`,
118
+ cloutly: `${ACTIVEPIECES_CDN}/cloutly.svg`,
119
+ gistly: `${ACTIVEPIECES_CDN}/gistly.svg`,
120
+ jotform: `${ACTIVEPIECES_CDN}/jotform.svg`,
121
+ supadata: `${ACTIVEPIECES_CDN}/supadata.svg`,
122
+ "hugging-face": `${ACTIVEPIECES_CDN}/huggingface.svg`,
123
+ huggingface: `${ACTIVEPIECES_CDN}/huggingface.svg`,
124
+ heygen: `${ACTIVEPIECES_CDN}/heygen.jpg`,
125
+ instasent: `${ACTIVEPIECES_CDN}/instasent.jpg`,
126
+ "chainalysis-api": `${ACTIVEPIECES_CDN}/chainalysis-api.jpg`,
127
+ scrapegraphai: `${ACTIVEPIECES_CDN}/scrapegraphai.jpg`,
128
+ localai: `${ACTIVEPIECES_CDN}/localai.jpeg`,
129
+ talkable: "https://www.talkable.com/wp-content/uploads/2021/12/talkable-favicon.svg",
130
+ // Sub-connector or variant reusing its parent connector's catalog logo.
131
+ "facebook-leads": `${ACTIVEPIECES_CDN}/facebook.png`,
132
+ "facebook-pages": `${ACTIVEPIECES_CDN}/facebook.png`,
133
+ "whatsapp-business": `${ACTIVEPIECES_CDN}/whatsapp.png`,
134
+ onedrive: `${ACTIVEPIECES_CDN}/oneDrive.png`,
135
+ "microsoft-onedrive": `${ACTIVEPIECES_CDN}/oneDrive.png`,
136
+ "outlook-mail": `${ACTIVEPIECES_CDN}/microsoft-outlook.png`,
137
+ "microsoft-calendar": `${ACTIVEPIECES_CDN}/microsoft-outlook.png`,
138
+ "microsoft-outlook-calendar": `${ACTIVEPIECES_CDN}/microsoft-outlook.png`,
139
+ sharepoint: `${ACTIVEPIECES_CDN}/microsoft-sharepoint.png`,
140
+ "notion-database": `${ACTIVEPIECES_CDN}/notion.png`,
141
+ "slack-inbound": `${ACTIVEPIECES_CDN}/slack.png`,
142
+ helpscout: `${ACTIVEPIECES_CDN}/help-scout.png`,
143
+ figjam: `${ACTIVEPIECES_CDN}/figma.png`,
144
+ webhook: `${ACTIVEPIECES_CDN}/new-core/webhooks.svg`,
145
+ // Absent from the catalog CDN — served from a public icon source.
146
+ make: "https://cdn.simpleicons.org/make",
147
+ n8n: "https://cdn.simpleicons.org/n8n",
148
+ zapier: "https://cdn.simpleicons.org/zapier",
149
+ auth0: "https://cdn.simpleicons.org/auth0",
150
+ basecamp: "https://cdn.simpleicons.org/basecamp",
151
+ ebay: "https://cdn.simpleicons.org/ebay",
152
+ gusto: "https://cdn.simpleicons.org/gusto",
153
+ miro: "https://cdn.simpleicons.org/miro",
154
+ sanity: "https://cdn.simpleicons.org/sanity",
155
+ sentry: "https://cdn.simpleicons.org/sentry",
156
+ opsgenie: "https://cdn.simpleicons.org/opsgenie",
157
+ phony: "https://www.google.com/s2/favicons?sz=64&domain_url=https://ph0ny.com",
158
+ docuseal: "https://www.google.com/s2/favicons?sz=64&domain_url=https://docuseal.com",
159
+ braze: "https://www.google.com/s2/favicons?sz=64&domain_url=https://braze.com",
160
+ pipedream: "https://www.google.com/s2/favicons?sz=64&domain_url=https://pipedream.com",
161
+ weaviate: "https://www.google.com/s2/favicons?sz=64&domain_url=https://weaviate.io",
162
+ "adobe-creative-cloud": "https://www.google.com/s2/favicons?sz=64&domain_url=https://adobe.com",
163
+ clio: "https://www.google.com/s2/favicons?sz=64&domain_url=https://clio.com",
164
+ marketo: "https://www.google.com/s2/favicons?sz=64&domain_url=https://marketo.com",
165
+ rippling: "https://www.google.com/s2/favicons?sz=64&domain_url=https://rippling.com",
166
+ "microsoft-graph": "https://www.google.com/s2/favicons?sz=64&domain_url=https://graph.microsoft.com"
167
+ };
100
168
  var PROVIDER_VECTOR_LOGOS = {
101
169
  slack: "slack",
102
170
  salesforce: "salesforce",
@@ -121,6 +189,9 @@ function providerLogoCandidates(opts) {
121
189
  const curated = PROVIDER_LOGO_SLUGS[raw] ?? PROVIDER_LOGO_SLUGS[norm];
122
190
  const vectorName = PROVIDER_VECTOR_LOGOS[raw] ?? PROVIDER_VECTOR_LOGOS[norm] ?? (curated ? PROVIDER_VECTOR_LOGOS[curated] : void 0);
123
191
  if (vectorName) out.push(`https://svgl.app/library/${vectorName}.svg`);
192
+ const pinned = PROVIDER_LOGO_URLS[raw] ?? PROVIDER_LOGO_URLS[norm];
193
+ if (pinned) out.push(pinned);
194
+ if (raw) out.push(`${ACTIVEPIECES_CDN}/${encodeURIComponent(raw)}.png`);
124
195
  const slugs = /* @__PURE__ */ new Set();
125
196
  if (curated) slugs.add(curated);
126
197
  slugs.add(norm.replace(/-/g, ""));
@@ -203,7 +274,5 @@ function ProviderIcon({
203
274
 
204
275
  export {
205
276
  normalizeProviderId,
206
- providerLogoCandidates,
207
- monogramColor,
208
277
  ProviderIcon
209
278
  };
@@ -806,6 +806,13 @@ interface SidebarLayoutProps {
806
806
  showThemeToggle?: boolean;
807
807
  /** Extra content in the rail footer, above the profile avatar. */
808
808
  railFooter?: React.ReactNode;
809
+ /**
810
+ * Where the rail collapse/expand control sits. Defaults to `"footer"` (the
811
+ * historical placement, above the profile avatar). Set `"header"` to move it
812
+ * to the top of the rail instead, alongside the logo/`railHeaderContent`.
813
+ * Only takes effect when `railLabels` is set (the rail is collapsible).
814
+ */
815
+ railCollapseToggle?: "header" | "footer";
809
816
  LinkComponent?: React.ComponentType<any>;
810
817
  /**
811
818
  * Controlled panel-open state. Provide it (seeded from a server-readable
package/dist/dashboard.js CHANGED
@@ -52,7 +52,7 @@ import {
52
52
  canAdminSandbox,
53
53
  parseInsufficientBalance,
54
54
  useSidebar
55
- } from "./chunk-PZ62T5PM.js";
55
+ } from "./chunk-3WUSPCPC.js";
56
56
  import {
57
57
  BillingDashboard,
58
58
  InfoPanel,
package/dist/globals.css CHANGED
@@ -2857,6 +2857,10 @@
2857
2857
  .text-\[length\:var\(--font-size-xl\,1\.25rem\)\] {
2858
2858
  font-size: var(--font-size-xl,1.25rem);
2859
2859
  }
2860
+ .leading-4 {
2861
+ --tw-leading: calc(var(--spacing) * 4);
2862
+ line-height: calc(var(--spacing) * 4);
2863
+ }
2860
2864
  .leading-6 {
2861
2865
  --tw-leading: calc(var(--spacing) * 6);
2862
2866
  line-height: calc(var(--spacing) * 6);
@@ -4555,6 +4559,11 @@
4555
4559
  }
4556
4560
  }
4557
4561
  }
4562
+ .focus-visible\:bg-background {
4563
+ &:focus-visible {
4564
+ background-color: var(--color-background);
4565
+ }
4566
+ }
4558
4567
  .focus-visible\:bg-primary\/40 {
4559
4568
  &:focus-visible {
4560
4569
  background-color: color-mix(in srgb, hsl(var(--primary)) 40%, transparent);
@@ -4568,6 +4577,11 @@
4568
4577
  background-color: transparent;
4569
4578
  }
4570
4579
  }
4580
+ .focus-visible\:text-foreground {
4581
+ &:focus-visible {
4582
+ color: var(--color-foreground);
4583
+ }
4584
+ }
4571
4585
  .focus-visible\:opacity-100 {
4572
4586
  &:focus-visible {
4573
4587
  opacity: 100%;
@@ -4611,6 +4625,14 @@
4611
4625
  }
4612
4626
  }
4613
4627
  }
4628
+ .focus-visible\:ring-primary\/40 {
4629
+ &:focus-visible {
4630
+ --tw-ring-color: color-mix(in srgb, hsl(var(--primary)) 40%, transparent);
4631
+ @supports (color: color-mix(in lab, red, red)) {
4632
+ --tw-ring-color: color-mix(in oklab, var(--color-primary) 40%, transparent);
4633
+ }
4634
+ }
4635
+ }
4614
4636
  .focus-visible\:ring-primary\/60 {
4615
4637
  &:focus-visible {
4616
4638
  --tw-ring-color: color-mix(in srgb, hsl(var(--primary)) 60%, transparent);
package/dist/index.js CHANGED
@@ -148,7 +148,7 @@ import {
148
148
  buildUnifiedPatch,
149
149
  computeDiffStats,
150
150
  resolveLanguage
151
- } from "./chunk-NXUSLH7H.js";
151
+ } from "./chunk-4HLWA2VN.js";
152
152
  import {
153
153
  FileArtifactPane,
154
154
  FilePreview,
@@ -211,7 +211,7 @@ import {
211
211
  canAdminSandbox,
212
212
  parseInsufficientBalance,
213
213
  useSidebar
214
- } from "./chunk-PZ62T5PM.js";
214
+ } from "./chunk-3WUSPCPC.js";
215
215
  import {
216
216
  BillingDashboard,
217
217
  InfoPanel,
@@ -13,10 +13,7 @@ interface IntegrationConnection {
13
13
  connectorId?: string;
14
14
  status: "connected" | "pending" | "revoked" | "expired" | (string & {});
15
15
  grantedScopes?: string[];
16
- account?: {
17
- identity?: string;
18
- displayName?: string;
19
- } & Record<string, unknown>;
16
+ accountDisplay?: string | null;
20
17
  expiresAt?: string | null;
21
18
  createdAt?: string;
22
19
  updatedAt?: string;
@@ -57,8 +54,10 @@ interface IntegrationsPanelProps {
57
54
  connectorId: string;
58
55
  }) => void | Promise<void>;
59
56
  /**
60
- * Invoked when the user manages (disconnects) a live connection via the
61
- * hover-revealed affordance on a connected tile.
57
+ * Invoked when the user confirms disconnecting a live connection from the
58
+ * disconnect control on a connected tile. May return a promise; the
59
+ * confirmation dialog shows a loading state until it settles and surfaces a
60
+ * thrown error inline.
62
61
  */
63
62
  onDisconnect: (connectionId: string) => void | Promise<void>;
64
63
  /** Empty-state message when the catalog hasn't loaded any providers. */
@@ -1,15 +1,25 @@
1
1
  import {
2
- monogramColor,
3
- normalizeProviderId,
4
- providerLogoCandidates
5
- } from "./chunk-CXV6X33U.js";
2
+ ProviderIcon,
3
+ normalizeProviderId
4
+ } from "./chunk-GTJ5PSK5.js";
6
5
  import "./chunk-U67V476Y.js";
7
6
 
8
7
  // src/integrations/integrations-panel.tsx
9
8
  import * as React from "react";
10
- import { Card, CardContent, EmptyState } from "@tangle-network/ui/primitives";
9
+ import {
10
+ Button,
11
+ Card,
12
+ CardContent,
13
+ Dialog,
14
+ DialogContent,
15
+ DialogDescription,
16
+ DialogFooter,
17
+ DialogHeader,
18
+ DialogTitle,
19
+ EmptyState
20
+ } from "@tangle-network/ui/primitives";
11
21
  import { cn } from "@tangle-network/ui/utils";
12
- import { Check, Search, Settings2 } from "lucide-react";
22
+ import { Check, Search, Unplug } from "lucide-react";
13
23
  import { jsx, jsxs } from "react/jsx-runtime";
14
24
  var DEFAULT_FEATURED_IDS = [
15
25
  "gmail",
@@ -49,51 +59,7 @@ var DEFAULT_FEATURED_IDS = [
49
59
  function defaultConnectorOf(provider) {
50
60
  return provider.connectors?.[0]?.connectorId ?? provider.providerId;
51
61
  }
52
- function ProviderLogo({
53
- provider,
54
- size = 56
55
- }) {
56
- const candidates = React.useMemo(
57
- () => providerLogoCandidates({
58
- id: provider.providerId,
59
- iconUrl: provider.iconUrl
60
- }),
61
- [provider]
62
- );
63
- const [index, setIndex] = React.useState(0);
64
- const label = (provider.displayName ?? provider.providerId).trim();
65
- const initial = label.charAt(0).toUpperCase() || "?";
66
- const src = candidates[index];
67
- if (!src) {
68
- return /* @__PURE__ */ jsx(
69
- "span",
70
- {
71
- className: "flex shrink-0 items-center justify-center rounded-2xl font-semibold text-white",
72
- style: {
73
- width: size,
74
- height: size,
75
- backgroundColor: monogramColor(provider.providerId),
76
- fontSize: Math.round(size * 0.42)
77
- },
78
- "aria-hidden": true,
79
- children: initial
80
- }
81
- );
82
- }
83
- return /* @__PURE__ */ jsx(
84
- "img",
85
- {
86
- src,
87
- alt: "",
88
- width: size,
89
- height: size,
90
- loading: "lazy",
91
- className: "shrink-0 object-contain",
92
- style: { width: size, height: size },
93
- onError: () => setIndex((i) => i + 1)
94
- }
95
- );
96
- }
62
+ var LOGO_SIZE = 48;
97
63
  function buildConnectionIndex(connections) {
98
64
  const index = /* @__PURE__ */ new Map();
99
65
  for (const conn of connections) {
@@ -140,6 +106,12 @@ function IntegrationsPanel({
140
106
  }) {
141
107
  const [query, setQuery] = React.useState("");
142
108
  const [sort, setSort] = React.useState(defaultSort);
109
+ const [disconnectTarget, setDisconnectTarget] = React.useState(null);
110
+ const [isDisconnecting, setIsDisconnecting] = React.useState(false);
111
+ const [disconnectError, setDisconnectError] = React.useState(
112
+ null
113
+ );
114
+ const activeDisconnect = React.useRef(0);
143
115
  const connectionIndex = React.useMemo(
144
116
  () => buildConnectionIndex(connections),
145
117
  [connections]
@@ -162,6 +134,30 @@ function IntegrationsPanel({
162
134
  });
163
135
  return sorted;
164
136
  }, [catalog, query, sort, featuredRank]);
137
+ const closeDisconnect = React.useCallback(() => {
138
+ activeDisconnect.current += 1;
139
+ setIsDisconnecting(false);
140
+ setDisconnectTarget(null);
141
+ setDisconnectError(null);
142
+ }, []);
143
+ const confirmDisconnect = React.useCallback(async () => {
144
+ if (!disconnectTarget) return;
145
+ const reqId = activeDisconnect.current += 1;
146
+ setIsDisconnecting(true);
147
+ setDisconnectError(null);
148
+ try {
149
+ await Promise.resolve(onDisconnect(disconnectTarget.connectionId));
150
+ if (activeDisconnect.current !== reqId) return;
151
+ setDisconnectTarget(null);
152
+ } catch (e) {
153
+ if (activeDisconnect.current !== reqId) return;
154
+ setDisconnectError(
155
+ e instanceof Error ? e.message : "Failed to disconnect."
156
+ );
157
+ } finally {
158
+ if (activeDisconnect.current === reqId) setIsDisconnecting(false);
159
+ }
160
+ }, [disconnectTarget, onDisconnect]);
165
161
  if (error) {
166
162
  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: [
167
163
  "Failed to load integrations: ",
@@ -196,6 +192,7 @@ function IntegrationsPanel({
196
192
  }
197
193
  );
198
194
  }
195
+ const disconnectAccountLabel = disconnectTarget?.accountDisplay;
199
196
  return /* @__PURE__ */ jsxs("div", { className: cn("space-y-4", className), children: [
200
197
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between", children: [
201
198
  /* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center gap-2 rounded-lg border border-border bg-card px-3 py-2", children: [
@@ -260,8 +257,9 @@ function IntegrationsPanel({
260
257
  {
261
258
  "data-testid": `integration-${provider.providerId}`,
262
259
  "data-connected": "true",
260
+ title: live.accountDisplay ? `${name} \u2014 ${live.accountDisplay}` : name,
263
261
  className: cn(
264
- "group relative flex aspect-square flex-col items-center justify-center gap-2 rounded-xl border p-3 text-center",
262
+ "relative flex aspect-square flex-col items-center justify-center gap-2 rounded-xl border p-3 text-center",
265
263
  "border-[var(--surface-success-border)] bg-[var(--surface-success-bg)]"
266
264
  ),
267
265
  children: [
@@ -270,16 +268,48 @@ function IntegrationsPanel({
270
268
  "button",
271
269
  {
272
270
  type: "button",
273
- onClick: () => onDisconnect(live.id),
274
- "data-testid": `manage-${provider.providerId}`,
275
- "aria-label": `Manage ${name}`,
276
- title: "Manage connection",
277
- className: "absolute right-1.5 top-1.5 flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground opacity-0 transition-opacity hover:bg-background hover:text-foreground group-hover:opacity-100",
278
- children: /* @__PURE__ */ jsx(Settings2, { className: "h-3.5 w-3.5" })
271
+ onClick: () => setDisconnectTarget({
272
+ connectionId: live.id,
273
+ name,
274
+ accountDisplay: live.accountDisplay
275
+ }),
276
+ "data-testid": `disconnect-${provider.providerId}`,
277
+ "aria-label": `Disconnect ${name}`,
278
+ title: "Disconnect",
279
+ className: "absolute right-1.5 top-1.5 flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground/70 transition-colors hover:bg-background hover:text-foreground focus-visible:bg-background focus-visible:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40",
280
+ children: /* @__PURE__ */ jsx(Unplug, { className: "h-3.5 w-3.5" })
281
+ }
282
+ ),
283
+ /* @__PURE__ */ jsx(
284
+ ProviderIcon,
285
+ {
286
+ id: provider.providerId,
287
+ iconUrl: provider.iconUrl,
288
+ displayName: provider.displayName,
289
+ size: LOGO_SIZE,
290
+ className: "rounded-2xl"
279
291
  }
280
292
  ),
281
- /* @__PURE__ */ jsx(ProviderLogo, { provider, size: 48 }),
282
- /* @__PURE__ */ jsx("span", { className: "line-clamp-2 w-full text-xs font-medium text-foreground", children: name })
293
+ /* @__PURE__ */ jsxs("div", { className: "flex h-8 w-full flex-col justify-center leading-4", children: [
294
+ /* @__PURE__ */ jsx(
295
+ "span",
296
+ {
297
+ className: cn(
298
+ "w-full text-xs font-medium text-foreground",
299
+ live.accountDisplay ? "truncate" : "line-clamp-2"
300
+ ),
301
+ children: name
302
+ }
303
+ ),
304
+ live.accountDisplay ? /* @__PURE__ */ jsx(
305
+ "span",
306
+ {
307
+ className: "w-full truncate text-[11px] leading-4 text-muted-foreground",
308
+ "data-testid": `account-${provider.providerId}`,
309
+ children: live.accountDisplay
310
+ }
311
+ ) : null
312
+ ] })
283
313
  ]
284
314
  },
285
315
  `${provider.providerId}:${connectorId}`
@@ -298,13 +328,77 @@ function IntegrationsPanel({
298
328
  "hover:border-primary/40 hover:bg-accent/40 hover:shadow-sm focus:outline-none focus-visible:border-primary/50 focus-visible:ring-2 focus-visible:ring-primary/20"
299
329
  ),
300
330
  children: [
301
- /* @__PURE__ */ jsx(ProviderLogo, { provider, size: 56 }),
302
- /* @__PURE__ */ jsx("span", { className: "line-clamp-2 w-full text-xs font-medium text-foreground", children: name })
331
+ /* @__PURE__ */ jsx(
332
+ ProviderIcon,
333
+ {
334
+ id: provider.providerId,
335
+ iconUrl: provider.iconUrl,
336
+ displayName: provider.displayName,
337
+ size: LOGO_SIZE,
338
+ className: "rounded-2xl"
339
+ }
340
+ ),
341
+ /* @__PURE__ */ jsx("span", { className: "line-clamp-2 h-8 w-full text-xs font-medium leading-4 text-foreground", children: name })
303
342
  ]
304
343
  },
305
344
  `${provider.providerId}:${connectorId}`
306
345
  );
307
- }) })
346
+ }) }),
347
+ /* @__PURE__ */ jsx(
348
+ Dialog,
349
+ {
350
+ open: !!disconnectTarget,
351
+ onOpenChange: (open) => {
352
+ if (!open) closeDisconnect();
353
+ },
354
+ children: /* @__PURE__ */ jsxs(
355
+ DialogContent,
356
+ {
357
+ className: "max-w-sm",
358
+ onCloseAutoFocus: (e) => e.preventDefault(),
359
+ children: [
360
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
361
+ /* @__PURE__ */ jsxs(DialogTitle, { children: [
362
+ "Disconnect ",
363
+ disconnectTarget?.name ?? "integration",
364
+ "?"
365
+ ] }),
366
+ /* @__PURE__ */ jsxs(DialogDescription, { children: [
367
+ "This removes Sandbox's access to your",
368
+ " ",
369
+ disconnectTarget?.name ?? "this",
370
+ " account",
371
+ disconnectAccountLabel ? ` (${disconnectAccountLabel})` : "",
372
+ ". You can reconnect anytime."
373
+ ] })
374
+ ] }),
375
+ disconnectError ? /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", role: "alert", children: disconnectError }) : null,
376
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
377
+ /* @__PURE__ */ jsx(
378
+ Button,
379
+ {
380
+ variant: "outline",
381
+ onClick: closeDisconnect,
382
+ "data-testid": "cancel-disconnect",
383
+ children: "Cancel"
384
+ }
385
+ ),
386
+ /* @__PURE__ */ jsx(
387
+ Button,
388
+ {
389
+ variant: "destructive",
390
+ loading: isDisconnecting,
391
+ onClick: confirmDisconnect,
392
+ "data-testid": "confirm-disconnect",
393
+ children: "Disconnect"
394
+ }
395
+ )
396
+ ] })
397
+ ]
398
+ }
399
+ )
400
+ }
401
+ )
308
402
  ] });
309
403
  }
310
404
 
package/dist/styles.css CHANGED
@@ -2857,6 +2857,10 @@
2857
2857
  .text-\[length\:var\(--font-size-xl\,1\.25rem\)\] {
2858
2858
  font-size: var(--font-size-xl,1.25rem);
2859
2859
  }
2860
+ .leading-4 {
2861
+ --tw-leading: calc(var(--spacing) * 4);
2862
+ line-height: calc(var(--spacing) * 4);
2863
+ }
2860
2864
  .leading-6 {
2861
2865
  --tw-leading: calc(var(--spacing) * 6);
2862
2866
  line-height: calc(var(--spacing) * 6);
@@ -4555,6 +4559,11 @@
4555
4559
  }
4556
4560
  }
4557
4561
  }
4562
+ .focus-visible\:bg-background {
4563
+ &:focus-visible {
4564
+ background-color: var(--color-background);
4565
+ }
4566
+ }
4558
4567
  .focus-visible\:bg-primary\/40 {
4559
4568
  &:focus-visible {
4560
4569
  background-color: color-mix(in srgb, hsl(var(--primary)) 40%, transparent);
@@ -4568,6 +4577,11 @@
4568
4577
  background-color: transparent;
4569
4578
  }
4570
4579
  }
4580
+ .focus-visible\:text-foreground {
4581
+ &:focus-visible {
4582
+ color: var(--color-foreground);
4583
+ }
4584
+ }
4571
4585
  .focus-visible\:opacity-100 {
4572
4586
  &:focus-visible {
4573
4587
  opacity: 100%;
@@ -4611,6 +4625,14 @@
4611
4625
  }
4612
4626
  }
4613
4627
  }
4628
+ .focus-visible\:ring-primary\/40 {
4629
+ &:focus-visible {
4630
+ --tw-ring-color: color-mix(in srgb, hsl(var(--primary)) 40%, transparent);
4631
+ @supports (color: color-mix(in lab, red, red)) {
4632
+ --tw-ring-color: color-mix(in oklab, var(--color-primary) 40%, transparent);
4633
+ }
4634
+ }
4635
+ }
4614
4636
  .focus-visible\:ring-primary\/60 {
4615
4637
  &:focus-visible {
4616
4638
  --tw-ring-color: color-mix(in srgb, hsl(var(--primary)) 60%, transparent);
package/dist/workbench.js CHANGED
@@ -12,9 +12,9 @@ import {
12
12
  buildUnifiedPatch,
13
13
  computeDiffStats,
14
14
  resolveLanguage
15
- } from "./chunk-NXUSLH7H.js";
15
+ } from "./chunk-4HLWA2VN.js";
16
16
  import "./chunk-3J6FG3FJ.js";
17
- import "./chunk-PZ62T5PM.js";
17
+ import "./chunk-3WUSPCPC.js";
18
18
  import "./chunk-OMUIPJQZ.js";
19
19
  import "./chunk-VIREDUBF.js";
20
20
  import "./chunk-77WVVJA4.js";
package/dist/workflows.js CHANGED
@@ -27,7 +27,7 @@ function retryImport(factory, retries = 2, delayMs = 350) {
27
27
  function lazyWorkflowGraph() {
28
28
  return lazy(
29
29
  () => retryImport(
30
- () => import("./WorkflowGraph-6IKZYPST.js").then((m) => ({ default: m.WorkflowGraph }))
30
+ () => import("./WorkflowGraph-EOV2P5AM.js").then((m) => ({ default: m.WorkflowGraph }))
31
31
  )
32
32
  );
33
33
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-ui",
3
- "version": "0.46.0",
3
+ "version": "0.48.0",
4
4
  "description": "Unified UI component library for Tangle Sandbox — primitives, chat, dashboard, terminal, editor, and workspace components",
5
5
  "repository": {
6
6
  "type": "git",