@tangle-network/sandbox-ui 0.91.3 → 0.91.5
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.
- package/dist/globals.css +6 -0
- package/dist/integrations.d.ts +7 -1
- package/dist/integrations.js +153 -65
- package/dist/styles.css +6 -0
- package/package.json +1 -1
package/dist/globals.css
CHANGED
|
@@ -1945,6 +1945,12 @@
|
|
|
1945
1945
|
border-color: color-mix(in oklab, var(--color-destructive) 30%, transparent);
|
|
1946
1946
|
}
|
|
1947
1947
|
}
|
|
1948
|
+
.border-destructive\/40 {
|
|
1949
|
+
border-color: color-mix(in srgb, hsl(var(--destructive)) 40%, transparent);
|
|
1950
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1951
|
+
border-color: color-mix(in oklab, var(--color-destructive) 40%, transparent);
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1948
1954
|
.border-destructive\/50 {
|
|
1949
1955
|
border-color: color-mix(in srgb, hsl(var(--destructive)) 50%, transparent);
|
|
1950
1956
|
@supports (color: color-mix(in lab, red, red)) {
|
package/dist/integrations.d.ts
CHANGED
|
@@ -93,9 +93,15 @@ interface IntegrationsPanelProps {
|
|
|
93
93
|
featuredIds?: string[];
|
|
94
94
|
/** Initial sort mode. Defaults to "featured". */
|
|
95
95
|
defaultSort?: IntegrationSort;
|
|
96
|
+
/**
|
|
97
|
+
* Tiles the loading skeleton draws. A skeleton exists to reserve the space
|
|
98
|
+
* the real content will take, so pass the catalog size you expect when the
|
|
99
|
+
* consumer knows it; the default fills two rows at the widest breakpoint.
|
|
100
|
+
*/
|
|
101
|
+
skeletonCount?: number;
|
|
96
102
|
className?: string;
|
|
97
103
|
}
|
|
98
|
-
declare function IntegrationsPanel({ catalog, connections, healthByConnectionId, isLoading, error, onConnect, onDisconnect, getManageHref, onManage, emptyCatalogLabel, featuredIds, defaultSort, className, }: IntegrationsPanelProps): React.JSX.Element;
|
|
104
|
+
declare function IntegrationsPanel({ catalog, connections, healthByConnectionId, isLoading, error, onConnect, onDisconnect, getManageHref, onManage, emptyCatalogLabel, featuredIds, defaultSort, skeletonCount, className, }: IntegrationsPanelProps): React.JSX.Element;
|
|
99
105
|
|
|
100
106
|
/**
|
|
101
107
|
* Endpoint contract expected on the consumer app's server (which
|
package/dist/integrations.js
CHANGED
|
@@ -64,6 +64,60 @@ var DEFAULT_FEATURED_IDS = [
|
|
|
64
64
|
function defaultConnectorOf(provider) {
|
|
65
65
|
return provider.connectors?.[0]?.connectorId ?? provider.providerId;
|
|
66
66
|
}
|
|
67
|
+
var TILE_GRID_CLASS = "grid grid-cols-3 gap-3 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6";
|
|
68
|
+
var DEFAULT_SKELETON_COUNT = 12;
|
|
69
|
+
var TILE_BOX_CLASS = "flex min-w-0 aspect-square flex-col items-center justify-center gap-2 rounded-xl border p-3 text-center";
|
|
70
|
+
function IntegrationsToolbar({
|
|
71
|
+
query,
|
|
72
|
+
onQueryChange,
|
|
73
|
+
sort,
|
|
74
|
+
onSortChange
|
|
75
|
+
}) {
|
|
76
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
77
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center gap-2 rounded-lg border border-border bg-card px-3 py-2", children: [
|
|
78
|
+
/* @__PURE__ */ jsx(Search, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
|
|
79
|
+
/* @__PURE__ */ jsx(
|
|
80
|
+
"input",
|
|
81
|
+
{
|
|
82
|
+
type: "text",
|
|
83
|
+
value: query,
|
|
84
|
+
onChange: (e) => onQueryChange(e.target.value),
|
|
85
|
+
placeholder: "Search integrations...",
|
|
86
|
+
autoFocus: true,
|
|
87
|
+
"data-testid": "integration-search",
|
|
88
|
+
className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
] }),
|
|
92
|
+
/* @__PURE__ */ jsx(
|
|
93
|
+
"div",
|
|
94
|
+
{
|
|
95
|
+
role: "tablist",
|
|
96
|
+
"aria-label": "Sort integrations",
|
|
97
|
+
className: "flex shrink-0 items-center gap-1 rounded-lg border border-border bg-card p-1",
|
|
98
|
+
children: [
|
|
99
|
+
["featured", "Featured"],
|
|
100
|
+
["alpha", "A\u2013Z"]
|
|
101
|
+
].map(([value, label]) => /* @__PURE__ */ jsx(
|
|
102
|
+
"button",
|
|
103
|
+
{
|
|
104
|
+
type: "button",
|
|
105
|
+
role: "tab",
|
|
106
|
+
"aria-selected": sort === value,
|
|
107
|
+
onClick: () => onSortChange(value),
|
|
108
|
+
"data-testid": `sort-${value}`,
|
|
109
|
+
className: cn(
|
|
110
|
+
"rounded-md px-2.5 py-1 text-xs font-medium transition-colors",
|
|
111
|
+
sort === value ? "bg-accent text-foreground" : "text-muted-foreground hover:text-foreground"
|
|
112
|
+
),
|
|
113
|
+
children: label
|
|
114
|
+
},
|
|
115
|
+
value
|
|
116
|
+
))
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
] });
|
|
120
|
+
}
|
|
67
121
|
var LOGO_SIZE = 48;
|
|
68
122
|
function buildConnectionIndex(connections) {
|
|
69
123
|
const index = /* @__PURE__ */ new Map();
|
|
@@ -109,6 +163,7 @@ function IntegrationsPanel({
|
|
|
109
163
|
emptyCatalogLabel = "No integrations available yet.",
|
|
110
164
|
featuredIds = DEFAULT_FEATURED_IDS,
|
|
111
165
|
defaultSort = "featured",
|
|
166
|
+
skeletonCount = DEFAULT_SKELETON_COUNT,
|
|
112
167
|
className
|
|
113
168
|
}) {
|
|
114
169
|
const [query, setQuery] = React.useState("");
|
|
@@ -147,6 +202,39 @@ function IntegrationsPanel({
|
|
|
147
202
|
setDisconnectTarget(null);
|
|
148
203
|
setDisconnectError(null);
|
|
149
204
|
}, []);
|
|
205
|
+
const [connectingId, setConnectingId] = React.useState(null);
|
|
206
|
+
const [connectError, setConnectError] = React.useState(null);
|
|
207
|
+
const activeConnect = React.useRef(0);
|
|
208
|
+
const startConnect = React.useCallback(
|
|
209
|
+
async (input) => {
|
|
210
|
+
const reqId = activeConnect.current += 1;
|
|
211
|
+
setConnectError(null);
|
|
212
|
+
let pending;
|
|
213
|
+
try {
|
|
214
|
+
pending = onConnect(input);
|
|
215
|
+
} catch (e) {
|
|
216
|
+
setConnectError(
|
|
217
|
+
e instanceof Error ? e.message : "Failed to start the connection."
|
|
218
|
+
);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (typeof pending?.then !== "function") {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
setConnectingId(input.providerId);
|
|
225
|
+
try {
|
|
226
|
+
await pending;
|
|
227
|
+
} catch (e) {
|
|
228
|
+
if (activeConnect.current !== reqId) return;
|
|
229
|
+
setConnectError(
|
|
230
|
+
e instanceof Error ? e.message : "Failed to start the connection."
|
|
231
|
+
);
|
|
232
|
+
} finally {
|
|
233
|
+
if (activeConnect.current === reqId) setConnectingId(null);
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
[onConnect]
|
|
237
|
+
);
|
|
150
238
|
const confirmDisconnect = React.useCallback(async () => {
|
|
151
239
|
if (!disconnectTarget) return;
|
|
152
240
|
const reqId = activeDisconnect.current += 1;
|
|
@@ -172,22 +260,38 @@ function IntegrationsPanel({
|
|
|
172
260
|
] }) }) });
|
|
173
261
|
}
|
|
174
262
|
if (isLoading && catalog.length === 0) {
|
|
175
|
-
return /* @__PURE__ */
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
263
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-4", className), "data-testid": "integrations-skeleton", children: [
|
|
264
|
+
/* @__PURE__ */ jsx(
|
|
265
|
+
IntegrationsToolbar,
|
|
266
|
+
{
|
|
267
|
+
query,
|
|
268
|
+
onQueryChange: setQuery,
|
|
269
|
+
sort,
|
|
270
|
+
onSortChange: setSort
|
|
271
|
+
}
|
|
272
|
+
),
|
|
273
|
+
/* @__PURE__ */ jsx("div", { className: TILE_GRID_CLASS, children: Array.from({ length: skeletonCount }).map((_, i) => /* @__PURE__ */ jsxs(
|
|
274
|
+
"div",
|
|
275
|
+
{
|
|
276
|
+
"aria-hidden": true,
|
|
277
|
+
className: cn(
|
|
278
|
+
TILE_BOX_CLASS,
|
|
279
|
+
"animate-pulse border-border bg-muted/40"
|
|
280
|
+
),
|
|
281
|
+
children: [
|
|
282
|
+
/* @__PURE__ */ jsx(
|
|
283
|
+
"div",
|
|
284
|
+
{
|
|
285
|
+
className: "shrink-0 rounded-2xl bg-muted",
|
|
286
|
+
style: { width: LOGO_SIZE, height: LOGO_SIZE }
|
|
287
|
+
}
|
|
288
|
+
),
|
|
289
|
+
/* @__PURE__ */ jsx("div", { className: "flex h-8 w-full items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "h-2.5 w-3/4 rounded bg-muted" }) })
|
|
290
|
+
]
|
|
291
|
+
},
|
|
292
|
+
i
|
|
293
|
+
)) })
|
|
294
|
+
] });
|
|
191
295
|
}
|
|
192
296
|
if (catalog.length === 0) {
|
|
193
297
|
return /* @__PURE__ */ jsx(
|
|
@@ -200,58 +304,32 @@ function IntegrationsPanel({
|
|
|
200
304
|
);
|
|
201
305
|
}
|
|
202
306
|
const disconnectAccountLabel = disconnectTarget?.accountDisplay;
|
|
203
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-4", className), children: [
|
|
204
|
-
/* @__PURE__ */
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
{
|
|
223
|
-
role: "tablist",
|
|
224
|
-
"aria-label": "Sort integrations",
|
|
225
|
-
className: "flex shrink-0 items-center gap-1 rounded-lg border border-border bg-card p-1",
|
|
226
|
-
children: [
|
|
227
|
-
["featured", "Featured"],
|
|
228
|
-
["alpha", "A\u2013Z"]
|
|
229
|
-
].map(([value, label]) => /* @__PURE__ */ jsx(
|
|
230
|
-
"button",
|
|
231
|
-
{
|
|
232
|
-
type: "button",
|
|
233
|
-
role: "tab",
|
|
234
|
-
"aria-selected": sort === value,
|
|
235
|
-
onClick: () => setSort(value),
|
|
236
|
-
"data-testid": `sort-${value}`,
|
|
237
|
-
className: cn(
|
|
238
|
-
"rounded-md px-2.5 py-1 text-xs font-medium transition-colors",
|
|
239
|
-
sort === value ? "bg-accent text-foreground" : "text-muted-foreground hover:text-foreground"
|
|
240
|
-
),
|
|
241
|
-
children: label
|
|
242
|
-
},
|
|
243
|
-
value
|
|
244
|
-
))
|
|
245
|
-
}
|
|
246
|
-
)
|
|
247
|
-
] }),
|
|
307
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-4", className), "data-testid": "integrations-panel", children: [
|
|
308
|
+
/* @__PURE__ */ jsx(
|
|
309
|
+
IntegrationsToolbar,
|
|
310
|
+
{
|
|
311
|
+
query,
|
|
312
|
+
onQueryChange: setQuery,
|
|
313
|
+
sort,
|
|
314
|
+
onSortChange: setSort
|
|
315
|
+
}
|
|
316
|
+
),
|
|
317
|
+
connectError ? /* @__PURE__ */ jsx(
|
|
318
|
+
"div",
|
|
319
|
+
{
|
|
320
|
+
role: "alert",
|
|
321
|
+
"data-testid": "integration-connect-error",
|
|
322
|
+
className: "mb-3 rounded-lg border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive",
|
|
323
|
+
children: connectError
|
|
324
|
+
}
|
|
325
|
+
) : null,
|
|
248
326
|
visible.length === 0 ? /* @__PURE__ */ jsx(
|
|
249
327
|
EmptyState,
|
|
250
328
|
{
|
|
251
329
|
title: "No matches",
|
|
252
330
|
description: `No integrations match "${query.trim()}".`
|
|
253
331
|
}
|
|
254
|
-
) : /* @__PURE__ */ jsx("div", { className:
|
|
332
|
+
) : /* @__PURE__ */ jsx("div", { className: TILE_GRID_CLASS, children: visible.map((provider) => {
|
|
255
333
|
const connectorId = defaultConnectorOf(provider);
|
|
256
334
|
const live = connectionIndex.get(
|
|
257
335
|
`${provider.providerId}:${connectorId}`
|
|
@@ -268,7 +346,8 @@ function IntegrationsPanel({
|
|
|
268
346
|
"data-connected": "true",
|
|
269
347
|
title: live.accountDisplay ? `${name} \u2014 ${live.accountDisplay}` : name,
|
|
270
348
|
className: cn(
|
|
271
|
-
|
|
349
|
+
TILE_BOX_CLASS,
|
|
350
|
+
"group relative",
|
|
272
351
|
"border-[var(--surface-success-border)] bg-[var(--surface-success-bg)]"
|
|
273
352
|
),
|
|
274
353
|
children: [
|
|
@@ -393,10 +472,19 @@ function IntegrationsPanel({
|
|
|
393
472
|
type: "button",
|
|
394
473
|
"data-testid": `integration-${provider.providerId}`,
|
|
395
474
|
"data-connected": "false",
|
|
396
|
-
|
|
475
|
+
"data-connecting": connectingId === provider.providerId ? "true" : void 0,
|
|
476
|
+
disabled: connectingId === provider.providerId,
|
|
477
|
+
"aria-busy": connectingId === provider.providerId,
|
|
478
|
+
onClick: () => {
|
|
479
|
+
void startConnect({
|
|
480
|
+
providerId: provider.providerId,
|
|
481
|
+
connectorId
|
|
482
|
+
});
|
|
483
|
+
},
|
|
397
484
|
title: provider.description ? provider.description : `Connect ${name}`,
|
|
398
485
|
className: cn(
|
|
399
|
-
|
|
486
|
+
TILE_BOX_CLASS,
|
|
487
|
+
"group border-border bg-card transition-all",
|
|
400
488
|
"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"
|
|
401
489
|
),
|
|
402
490
|
children: [
|
package/dist/styles.css
CHANGED
|
@@ -1945,6 +1945,12 @@
|
|
|
1945
1945
|
border-color: color-mix(in oklab, var(--color-destructive) 30%, transparent);
|
|
1946
1946
|
}
|
|
1947
1947
|
}
|
|
1948
|
+
.border-destructive\/40 {
|
|
1949
|
+
border-color: color-mix(in srgb, hsl(var(--destructive)) 40%, transparent);
|
|
1950
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1951
|
+
border-color: color-mix(in oklab, var(--color-destructive) 40%, transparent);
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1948
1954
|
.border-destructive\/50 {
|
|
1949
1955
|
border-color: color-mix(in srgb, hsl(var(--destructive)) 50%, transparent);
|
|
1950
1956
|
@supports (color: color-mix(in lab, red, red)) {
|
package/package.json
CHANGED