@tangle-network/sandbox-ui 0.113.4 → 0.113.6
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/README.md +3 -1
- package/dist/chat.js +1 -1
- package/dist/{chunk-JZCRK2BJ.js → chunk-3KBNPQQF.js} +117 -44
- package/dist/chunk-ANSC5AFC.js +314 -0
- package/dist/{chunk-LDAKIKTV.js → chunk-DYXXYGS4.js} +299 -166
- package/dist/{chunk-EKYA6AFY.js → chunk-TADGS4Q7.js} +15 -7
- package/dist/{chunk-XFEJ66AG.js → chunk-UCQNOUN3.js} +165 -68
- package/dist/{chunk-PZVUIUUW.js → chunk-ULPLRBMF.js} +8 -2
- package/dist/{chunk-TK46XFLM.js → chunk-X3YXP7FG.js} +10 -0
- package/dist/connectors.js +2 -1
- package/dist/dashboard.d.ts +8 -8
- package/dist/dashboard.js +2 -2
- package/dist/files.d.ts +1 -1
- package/dist/files.js +9 -3
- package/dist/globals.css +446 -147
- package/dist/index.d.ts +5 -4
- package/dist/index.js +26 -8
- package/dist/integrations.js +10 -7
- package/dist/logo-DiAjq759.d.ts +15 -0
- package/dist/pages.js +69 -46
- package/dist/primitives.d.ts +3 -2
- package/dist/primitives.js +3 -1
- package/dist/styles.css +446 -147
- package/dist/tokens.css +37 -0
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +11 -1
- package/dist/workbench.d.ts +6 -3
- package/dist/workbench.js +4 -4
- package/dist/workspace.js +1 -1
- package/package.json +5 -5
- package/dist/chunk-2XPJ2XF7.js +0 -345
- package/dist/logo-CaIvk3J1.d.ts +0 -18
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Button,
|
|
3
3
|
Logo
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ANSC5AFC.js";
|
|
5
5
|
import {
|
|
6
6
|
moonshot_default
|
|
7
7
|
} from "./chunk-RQZRXKMR.js";
|
|
@@ -227,7 +227,8 @@ function RailTooltip({ label, children, disabled, className }) {
|
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
// src/dashboard/app-sidebar.tsx
|
|
230
|
-
import {
|
|
230
|
+
import { focusRing } from "@tangle-network/ui/utils";
|
|
231
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
231
232
|
function DefaultLink({
|
|
232
233
|
href,
|
|
233
234
|
to,
|
|
@@ -286,7 +287,7 @@ function RailThemeToggle({ className }) {
|
|
|
286
287
|
"flex h-9 w-9 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors",
|
|
287
288
|
MOTION_CONTROL,
|
|
288
289
|
"hover:bg-[var(--accent-surface-soft)] hover:text-foreground",
|
|
289
|
-
|
|
290
|
+
focusRing,
|
|
290
291
|
className
|
|
291
292
|
),
|
|
292
293
|
children: isDark ? /* @__PURE__ */ jsx3(SunIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx3(MoonIcon, { className: "h-4 w-4" })
|
|
@@ -320,7 +321,7 @@ function RailCollapseToggle({ collapsed, showLabel, onToggle, className }) {
|
|
|
320
321
|
MOTION_CONTROL,
|
|
321
322
|
showLabel ? "h-9 w-full justify-start gap-2.5 px-2.5" : "h-9 w-9 justify-center",
|
|
322
323
|
"hover:bg-[var(--accent-surface-soft)] hover:text-foreground",
|
|
323
|
-
|
|
324
|
+
focusRing,
|
|
324
325
|
className
|
|
325
326
|
),
|
|
326
327
|
children: [
|
|
@@ -344,15 +345,22 @@ function PanelToggleButton({ collapsed, onToggle, className }) {
|
|
|
344
345
|
"flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors",
|
|
345
346
|
MOTION_CONTROL,
|
|
346
347
|
"hover:bg-[var(--accent-surface-soft)] hover:text-foreground",
|
|
347
|
-
|
|
348
|
+
focusRing,
|
|
348
349
|
className
|
|
349
350
|
),
|
|
350
351
|
children: /* @__PURE__ */ jsx3(PanelLeft, { className: "h-[18px] w-[18px] shrink-0" })
|
|
351
352
|
}
|
|
352
353
|
);
|
|
353
354
|
}
|
|
355
|
+
function isRenderable(node) {
|
|
356
|
+
return React3.Children.toArray(node).some(
|
|
357
|
+
(child) => React3.isValidElement(child) && child.type === React3.Fragment ? isRenderable(child.props.children) : true
|
|
358
|
+
);
|
|
359
|
+
}
|
|
354
360
|
function RailHeader({ brand, brandHref, children, collapsed, onToggle, collapsible = true, LinkComponent, className }) {
|
|
355
361
|
const Link = LinkComponent ?? DefaultLink;
|
|
362
|
+
const hasBrand = isRenderable(brand);
|
|
363
|
+
const hasChildren = isRenderable(children);
|
|
356
364
|
const brandNode = brandHref !== void 0 ? /* @__PURE__ */ jsx3(
|
|
357
365
|
Link,
|
|
358
366
|
{
|
|
@@ -371,21 +379,50 @@ function RailHeader({ brand, brandHref, children, collapsed, onToggle, collapsib
|
|
|
371
379
|
collapsed ? "justify-center px-2" : "gap-2 px-3",
|
|
372
380
|
className
|
|
373
381
|
),
|
|
374
|
-
children: collapsed ?
|
|
382
|
+
children: collapsed ? !hasBrand && hasChildren ? (
|
|
383
|
+
// No brand mark: `children` (SidebarLayout's `railHeaderContent`) is
|
|
384
|
+
// the only rail-top content the consumer gave us, so render it here
|
|
385
|
+
// too. Dropping it left an EMPTY header — the collapsed rail showed
|
|
386
|
+
// nothing at all where the product's mark belongs. With neither a
|
|
387
|
+
// brand nor children, the plain expand button below still owns the
|
|
388
|
+
// rail top so the rail stays expandable.
|
|
389
|
+
//
|
|
390
|
+
// Rendered outside the expand button on purpose: content that owns
|
|
391
|
+
// the rail top is routinely interactive itself (a mark that expands
|
|
392
|
+
// the rail on click), and a <button> inside a <button> is invalid
|
|
393
|
+
// HTML that React refuses to hydrate.
|
|
394
|
+
//
|
|
395
|
+
// The explicit "Expand sidebar" control stays in the tree for
|
|
396
|
+
// keyboard and assistive-tech users (the content may be a passive
|
|
397
|
+
// switcher, and the empty-rail click fallback is mouse-only). It sits
|
|
398
|
+
// over the content, invisible and non-interactive until it receives
|
|
399
|
+
// keyboard focus, so it costs no rail width.
|
|
400
|
+
/* @__PURE__ */ jsxs2("div", { className: "relative flex min-w-0 items-center justify-center", children: [
|
|
401
|
+
children,
|
|
402
|
+
collapsible && /* @__PURE__ */ jsx3(
|
|
403
|
+
PanelToggleButton,
|
|
404
|
+
{
|
|
405
|
+
collapsed,
|
|
406
|
+
onToggle,
|
|
407
|
+
className: "pointer-events-none absolute inset-0 m-auto bg-background opacity-0 focus-visible:pointer-events-auto focus-visible:opacity-100"
|
|
408
|
+
}
|
|
409
|
+
)
|
|
410
|
+
] })
|
|
411
|
+
) : collapsible ? /* @__PURE__ */ jsx3(RailTooltip, { label: "Expand sidebar", children: /* @__PURE__ */ jsxs2(
|
|
375
412
|
"button",
|
|
376
413
|
{
|
|
377
414
|
type: "button",
|
|
378
415
|
onClick: onToggle,
|
|
379
416
|
"aria-label": "Expand sidebar",
|
|
380
417
|
"aria-pressed": true,
|
|
381
|
-
className: cn("group/brand relative flex h-9 w-9 items-center justify-center rounded-md transition-colors hover:bg-[var(--accent-surface-soft)]
|
|
418
|
+
className: cn("group/brand relative flex h-9 w-9 items-center justify-center rounded-md transition-colors hover:bg-[var(--accent-surface-soft)]", focusRing, MOTION_CONTROL),
|
|
382
419
|
children: [
|
|
383
420
|
/* @__PURE__ */ jsx3("span", { className: cn("flex items-center justify-center transition-opacity group-hover/brand:opacity-0", MOTION_CONTROL), children: brand }),
|
|
384
421
|
/* @__PURE__ */ jsx3("span", { className: cn("pointer-events-none absolute inset-0 flex items-center justify-center text-foreground opacity-0 transition-opacity group-hover/brand:opacity-100", MOTION_CONTROL), children: /* @__PURE__ */ jsx3(PanelLeft, { className: "h-[18px] w-[18px]" }) })
|
|
385
422
|
]
|
|
386
423
|
}
|
|
387
|
-
) }) : brandNode : /* @__PURE__ */ jsxs2(
|
|
388
|
-
|
|
424
|
+
) }) : brandNode : /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
425
|
+
hasBrand && brandNode,
|
|
389
426
|
/* @__PURE__ */ jsx3("div", { className: "min-w-0 flex-1", children }),
|
|
390
427
|
collapsible && /* @__PURE__ */ jsx3(PanelToggleButton, { collapsed, onToggle })
|
|
391
428
|
] })
|
|
@@ -445,7 +482,7 @@ function RailButton({ icon: Icon2, label, isActive, badge, onClick, className, s
|
|
|
445
482
|
MOTION_CONTROL,
|
|
446
483
|
showLabel ? "w-full justify-start px-2.5 h-9 gap-2.5" : "w-9 h-9 justify-center",
|
|
447
484
|
// Quiet press feedback via color only — no scale on the full-width row.
|
|
448
|
-
|
|
485
|
+
focusRing,
|
|
449
486
|
// The active item (route matches) and any explicit primary share one
|
|
450
487
|
// emphasized look — a filled accent pill with an accent ring — so the
|
|
451
488
|
// current destination clearly stands out from the default rows.
|
|
@@ -456,7 +493,7 @@ function RailButton({ icon: Icon2, label, isActive, badge, onClick, className, s
|
|
|
456
493
|
/* @__PURE__ */ jsx3(Icon2, { className: "h-[17px] w-[17px] shrink-0" }),
|
|
457
494
|
badge !== void 0 && badge > 0 && /* @__PURE__ */ jsx3("span", { className: "absolute -top-1.5 -right-1.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-primary text-[9px] font-bold text-[var(--md3-on-primary)] px-1", children: badge > 99 ? "99+" : badge })
|
|
458
495
|
] });
|
|
459
|
-
const content = /* @__PURE__ */ jsxs2(
|
|
496
|
+
const content = /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
460
497
|
iconWithBadge,
|
|
461
498
|
showLabel && /* @__PURE__ */ jsx3("span", { className: "text-[13.5px] font-medium", children: label })
|
|
462
499
|
] });
|
|
@@ -512,7 +549,7 @@ function RailFlyout({
|
|
|
512
549
|
"relative flex shrink-0 items-center rounded-md transition-colors",
|
|
513
550
|
MOTION_CONTROL,
|
|
514
551
|
showLabel ? "w-full justify-start px-2.5 h-9 gap-2.5" : "w-9 h-9 justify-center",
|
|
515
|
-
|
|
552
|
+
focusRing,
|
|
516
553
|
active ? "bg-[var(--accent-surface-strong)] text-[var(--accent-text)]" : "text-muted-foreground hover:bg-[var(--accent-surface-soft)] hover:text-foreground",
|
|
517
554
|
className
|
|
518
555
|
);
|
|
@@ -724,7 +761,7 @@ function RailExpandable({
|
|
|
724
761
|
const triggerClasses = cn(
|
|
725
762
|
"relative flex h-9 w-9 items-center justify-center rounded-md transition-colors",
|
|
726
763
|
MOTION_CONTROL,
|
|
727
|
-
|
|
764
|
+
focusRing,
|
|
728
765
|
isActive || open ? "bg-[var(--accent-surface-strong)] text-[var(--accent-text)] font-medium ring-1 ring-inset ring-[var(--border-accent)]" : "text-muted-foreground hover:bg-[var(--accent-surface-soft)] hover:text-foreground"
|
|
729
766
|
);
|
|
730
767
|
const openFlyout = () => {
|
|
@@ -828,7 +865,7 @@ function RailExpandable({
|
|
|
828
865
|
"aria-expanded": open,
|
|
829
866
|
"aria-controls": discloseId,
|
|
830
867
|
"aria-label": open ? `Collapse ${label}` : `Expand ${label}`,
|
|
831
|
-
className:
|
|
868
|
+
className: `relative flex h-9 w-9 shrink-0 items-center justify-center rounded-md ${focusRing}`,
|
|
832
869
|
children: [
|
|
833
870
|
/* @__PURE__ */ jsx3(
|
|
834
871
|
Icon2,
|
|
@@ -945,7 +982,7 @@ function AppearanceMenuSection({ appearance, divider = true }) {
|
|
|
945
982
|
const resolved = appearance.value === "system" ? systemDark ? "dark" : "light" : appearance.value;
|
|
946
983
|
const TriggerIcon = resolved === "dark" ? MoonIcon : SunIcon;
|
|
947
984
|
const caption = appearance.value === "system" ? `System (${resolved === "dark" ? "Dark" : "Light"})` : APPEARANCE_META[appearance.value].label;
|
|
948
|
-
return /* @__PURE__ */ jsxs2(
|
|
985
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
949
986
|
divider && /* @__PURE__ */ jsx3(DropdownMenuSeparator, {}),
|
|
950
987
|
/* @__PURE__ */ jsxs2(DropdownMenuSub, { children: [
|
|
951
988
|
/* @__PURE__ */ jsxs2(DropdownMenuSubTrigger, { children: [
|
|
@@ -999,7 +1036,7 @@ function ProfileAvatar({
|
|
|
999
1036
|
className: cn(
|
|
1000
1037
|
"flex items-center rounded-lg transition-colors hover:bg-[var(--accent-surface-soft)]",
|
|
1001
1038
|
MOTION_CONTROL,
|
|
1002
|
-
|
|
1039
|
+
focusRing,
|
|
1003
1040
|
showDetails ? "w-full gap-2.5 px-3 py-2 text-left" : "justify-center w-12 h-12",
|
|
1004
1041
|
className
|
|
1005
1042
|
),
|
|
@@ -1019,10 +1056,10 @@ function ProfileAvatar({
|
|
|
1019
1056
|
user?.avatarUrl && /* @__PURE__ */ jsx3(AvatarImage, { src: user.avatarUrl, alt: "" }),
|
|
1020
1057
|
/* @__PURE__ */ jsx3(AvatarFallback, { className: "text-sm bg-[var(--surface-violet-bg)] text-[var(--surface-violet-text)]", children: getInitials(user?.name, user?.email) })
|
|
1021
1058
|
] }),
|
|
1022
|
-
/* @__PURE__ */ jsx3("div", { className: "min-w-0 flex-1", children: isLoading ? /* @__PURE__ */ jsxs2(
|
|
1059
|
+
/* @__PURE__ */ jsx3("div", { className: "min-w-0 flex-1", children: isLoading ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1023
1060
|
/* @__PURE__ */ jsx3(Skeleton, { className: "h-4 w-24 mb-1" }),
|
|
1024
1061
|
/* @__PURE__ */ jsx3(Skeleton, { className: "h-3 w-32" })
|
|
1025
|
-
] }) : /* @__PURE__ */ jsxs2(
|
|
1062
|
+
] }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1026
1063
|
/* @__PURE__ */ jsx3("p", { className: "text-sm font-semibold truncate", children: user?.name ?? user?.email ?? "Not logged in" }),
|
|
1027
1064
|
user?.email && user?.name && /* @__PURE__ */ jsx3("p", { className: "text-xs text-muted-foreground truncate", children: user.email }),
|
|
1028
1065
|
user?.tier && /* @__PURE__ */ jsxs2("p", { className: "text-xs text-muted-foreground capitalize", children: [
|
|
@@ -1041,7 +1078,7 @@ function ProfileAvatar({
|
|
|
1041
1078
|
/* @__PURE__ */ jsx3(SettingsIcon, { className: "mr-2 h-4 w-4", "aria-hidden": "true" }),
|
|
1042
1079
|
"Settings"
|
|
1043
1080
|
] }) }),
|
|
1044
|
-
onLogout && /* @__PURE__ */ jsxs2(
|
|
1081
|
+
onLogout && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1045
1082
|
/* @__PURE__ */ jsx3(DropdownMenuSeparator, {}),
|
|
1046
1083
|
/* @__PURE__ */ jsxs2(DropdownMenuItem, { className: "text-[var(--surface-danger-text)]", onClick: onLogout, children: [
|
|
1047
1084
|
/* @__PURE__ */ jsx3(LogOutIcon, { className: "mr-2 h-4 w-4", "aria-hidden": "true" }),
|
|
@@ -1054,6 +1091,7 @@ function ProfileAvatar({
|
|
|
1054
1091
|
|
|
1055
1092
|
// src/dashboard/credit-balance.tsx
|
|
1056
1093
|
import * as React4 from "react";
|
|
1094
|
+
import { focusFieldWithin } from "@tangle-network/ui/utils";
|
|
1057
1095
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1058
1096
|
function CreditBalance({
|
|
1059
1097
|
amount,
|
|
@@ -1063,6 +1101,7 @@ function CreditBalance({
|
|
|
1063
1101
|
className
|
|
1064
1102
|
}) {
|
|
1065
1103
|
const [topUpValue, setTopUpValue] = React4.useState("50.00");
|
|
1104
|
+
const topUpId = React4.useId();
|
|
1066
1105
|
return /* @__PURE__ */ jsxs3(
|
|
1067
1106
|
"div",
|
|
1068
1107
|
{
|
|
@@ -1080,11 +1119,14 @@ function CreditBalance({
|
|
|
1080
1119
|
/* @__PURE__ */ jsx4("p", { className: "text-sm text-muted-foreground leading-relaxed", children: description })
|
|
1081
1120
|
] }),
|
|
1082
1121
|
onTopUp && /* @__PURE__ */ jsxs3("div", { className: "space-y-2.5 mt-5", children: [
|
|
1083
|
-
/* @__PURE__ */
|
|
1122
|
+
/* @__PURE__ */ jsx4("label", { htmlFor: topUpId, className: "block text-xs font-medium text-muted-foreground", children: "Top-up amount (USD)" }),
|
|
1123
|
+
/* @__PURE__ */ jsxs3("div", { className: `bg-surface-container-low border p-1 rounded-lg flex items-center ${focusFieldWithin}`, children: [
|
|
1084
1124
|
/* @__PURE__ */ jsx4(
|
|
1085
1125
|
"input",
|
|
1086
1126
|
{
|
|
1127
|
+
id: topUpId,
|
|
1087
1128
|
type: "text",
|
|
1129
|
+
inputMode: "decimal",
|
|
1088
1130
|
value: `$${topUpValue}`,
|
|
1089
1131
|
onChange: (e) => {
|
|
1090
1132
|
const raw = e.target.value.replace(/[^0-9.]/g, "");
|
|
@@ -1193,7 +1235,7 @@ function OutOfCreditsModal({
|
|
|
1193
1235
|
|
|
1194
1236
|
// src/dashboard/cluster-status-bar.tsx
|
|
1195
1237
|
import * as React5 from "react";
|
|
1196
|
-
import { Fragment as
|
|
1238
|
+
import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1197
1239
|
function ClusterStatusBar({ items, latency, className }) {
|
|
1198
1240
|
if (!items?.length) return null;
|
|
1199
1241
|
return /* @__PURE__ */ jsx6("div", { className: cn("fixed bottom-6 left-1/2 -translate-x-1/2 z-40 w-max max-w-[90vw] animate-in slide-in-from-bottom flex justify-center", className), children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-4 overflow-x-auto rounded-full border border-[var(--md3-outline-variant)] bg-surface-container px-5 py-2.5 shadow-sm", children: [
|
|
@@ -1207,7 +1249,7 @@ function ClusterStatusBar({ items, latency, className }) {
|
|
|
1207
1249
|
] })
|
|
1208
1250
|
] })
|
|
1209
1251
|
] }, i)),
|
|
1210
|
-
latency && /* @__PURE__ */ jsxs5(
|
|
1252
|
+
latency && /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
1211
1253
|
/* @__PURE__ */ jsx6("span", { "aria-hidden": true, className: "h-5 w-px shrink-0 bg-border" }),
|
|
1212
1254
|
/* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1213
1255
|
/* @__PURE__ */ jsxs5("span", { className: "relative flex h-2.5 w-2.5 items-center justify-center", children: [
|
|
@@ -1357,7 +1399,8 @@ import {
|
|
|
1357
1399
|
HardDrive,
|
|
1358
1400
|
Box
|
|
1359
1401
|
} from "lucide-react";
|
|
1360
|
-
import {
|
|
1402
|
+
import { focusRing as focusRing2 } from "@tangle-network/ui/utils";
|
|
1403
|
+
import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1361
1404
|
function canAdminSandbox(sandbox) {
|
|
1362
1405
|
if (!sandbox.team) return true;
|
|
1363
1406
|
return sandbox.team.role === "owner" || sandbox.team.role === "admin";
|
|
@@ -1451,13 +1494,13 @@ function SandboxCard({
|
|
|
1451
1494
|
"button",
|
|
1452
1495
|
{
|
|
1453
1496
|
type: "button",
|
|
1454
|
-
className:
|
|
1497
|
+
className: `rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-surface-container-high hover:text-foreground ${focusRing2}`,
|
|
1455
1498
|
"aria-label": "Sandbox options",
|
|
1456
1499
|
children: /* @__PURE__ */ jsx10(MoreVertical, { className: "h-4 w-4" })
|
|
1457
1500
|
}
|
|
1458
1501
|
) }),
|
|
1459
1502
|
/* @__PURE__ */ jsxs9(DropdownMenuContent2, { align: "end", className: "min-w-[180px]", children: [
|
|
1460
|
-
isRunning && /* @__PURE__ */ jsxs9(
|
|
1503
|
+
isRunning && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
1461
1504
|
onStop && /* @__PURE__ */ jsxs9(DropdownMenuItem2, { onClick: () => onStop(sandbox.id), children: [
|
|
1462
1505
|
/* @__PURE__ */ jsx10(PowerOff, { className: "mr-2 h-4 w-4" }),
|
|
1463
1506
|
" Stop Sandbox"
|
|
@@ -1476,7 +1519,7 @@ function SandboxCard({
|
|
|
1476
1519
|
" Health Check"
|
|
1477
1520
|
] }),
|
|
1478
1521
|
(onUsage || onHealth) && /* @__PURE__ */ jsx10(DropdownMenuSeparator2, {}),
|
|
1479
|
-
onFork && /* @__PURE__ */ jsxs9(
|
|
1522
|
+
onFork && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
1480
1523
|
/* @__PURE__ */ jsxs9(DropdownMenuItem2, { onClick: () => onFork(sandbox.id), children: [
|
|
1481
1524
|
/* @__PURE__ */ jsx10(Copy, { className: "mr-2 h-4 w-4" }),
|
|
1482
1525
|
" Fork Sandbox"
|
|
@@ -1484,7 +1527,7 @@ function SandboxCard({
|
|
|
1484
1527
|
/* @__PURE__ */ jsx10(DropdownMenuSeparator2, {})
|
|
1485
1528
|
] })
|
|
1486
1529
|
] }),
|
|
1487
|
-
isStopped && /* @__PURE__ */ jsxs9(
|
|
1530
|
+
isStopped && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
1488
1531
|
resumeHandler && /* @__PURE__ */ jsxs9(DropdownMenuItem2, { onClick: () => resumeHandler(sandbox.id), children: [
|
|
1489
1532
|
/* @__PURE__ */ jsx10(Power, { className: "mr-2 h-4 w-4" }),
|
|
1490
1533
|
" ",
|
|
@@ -1647,7 +1690,8 @@ import {
|
|
|
1647
1690
|
DropdownMenuSeparator as DropdownMenuSeparator3,
|
|
1648
1691
|
DropdownMenuTrigger as DropdownMenuTrigger3
|
|
1649
1692
|
} from "@tangle-network/ui/primitives";
|
|
1650
|
-
import {
|
|
1693
|
+
import { focusRing as focusRing3 } from "@tangle-network/ui/utils";
|
|
1694
|
+
import { Fragment as Fragment7, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1651
1695
|
var statusColors = {
|
|
1652
1696
|
running: { dot: "bg-[var(--code-success)] animate-pulse", text: "text-[var(--code-success)]", bar: "bg-[var(--code-success)]" },
|
|
1653
1697
|
hibernating: { dot: "bg-muted-foreground", text: "text-muted-foreground", bar: "bg-muted-foreground" },
|
|
@@ -1803,7 +1847,7 @@ function SandboxTable({
|
|
|
1803
1847
|
/* @__PURE__ */ jsx11(MiniMeter, { label: "RAM", percent: 0 })
|
|
1804
1848
|
] }) : null }),
|
|
1805
1849
|
/* @__PURE__ */ jsx11("td", { className: "px-6 py-5 text-right", children: /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-end gap-1", children: [
|
|
1806
|
-
isActive && /* @__PURE__ */ jsxs10(
|
|
1850
|
+
isActive && /* @__PURE__ */ jsxs10(Fragment7, { children: [
|
|
1807
1851
|
/* @__PURE__ */ jsx11("button", { type: "button", onClick: (e) => {
|
|
1808
1852
|
stopRowClick(e);
|
|
1809
1853
|
onOpenIDE?.(sb.id);
|
|
@@ -1895,8 +1939,8 @@ function SandboxTable({
|
|
|
1895
1939
|
{
|
|
1896
1940
|
type: "button",
|
|
1897
1941
|
onClick: stopRowClick,
|
|
1898
|
-
className:
|
|
1899
|
-
"aria-label":
|
|
1942
|
+
className: `p-2 rounded-lg hover:bg-surface-container-high text-muted-foreground hover:text-foreground transition-all active:scale-90 ${focusRing3}`,
|
|
1943
|
+
"aria-label": `More actions for ${sb.name}`,
|
|
1900
1944
|
title: "More actions",
|
|
1901
1945
|
children: /* @__PURE__ */ jsx11(MoreVertical2, { className: "h-4 w-4" })
|
|
1902
1946
|
}
|
|
@@ -1907,10 +1951,10 @@ function SandboxTable({
|
|
|
1907
1951
|
] }, sectionIdx)) })
|
|
1908
1952
|
] });
|
|
1909
1953
|
})(),
|
|
1910
|
-
onDelete && canAdminSandbox(sb) && /* @__PURE__ */ jsx11("button", { type: "button", onClick: (e) => {
|
|
1954
|
+
onDelete && canAdminSandbox(sb) && /* @__PURE__ */ jsx11("button", { type: "button", "aria-label": `Delete ${sb.name}`, onClick: (e) => {
|
|
1911
1955
|
stopRowClick(e);
|
|
1912
1956
|
onDelete(sb.id);
|
|
1913
|
-
}, className:
|
|
1957
|
+
}, className: `p-2 rounded-lg hover:bg-[var(--surface-danger-bg)] text-muted-foreground hover:text-[var(--surface-danger-text)] transition-all active:scale-90 ${focusRing3}`, title: "Delete", children: /* @__PURE__ */ jsx11(Trash22, { className: "h-4 w-4" }) })
|
|
1914
1958
|
] }) })
|
|
1915
1959
|
]
|
|
1916
1960
|
},
|
|
@@ -2040,6 +2084,7 @@ function PlanCards({ plans, className }) {
|
|
|
2040
2084
|
// src/dashboard/backend-selector.tsx
|
|
2041
2085
|
import { ChevronDown } from "lucide-react";
|
|
2042
2086
|
import * as Select from "@radix-ui/react-select";
|
|
2087
|
+
import { focusRing as focusRing4 } from "@tangle-network/ui/utils";
|
|
2043
2088
|
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2044
2089
|
function BackendSelector({
|
|
2045
2090
|
backends,
|
|
@@ -2063,7 +2108,7 @@ function BackendSelector({
|
|
|
2063
2108
|
"px-2.5 text-xs font-medium text-foreground shadow-sm",
|
|
2064
2109
|
"transition-colors duration-[var(--transition-fast)]",
|
|
2065
2110
|
"hover:border-[var(--md3-outline-variant)] hover:bg-surface-container-high",
|
|
2066
|
-
|
|
2111
|
+
focusRing4,
|
|
2067
2112
|
"data-[state=open]:border-[var(--md3-outline)] data-[state=open]:bg-surface-container-high",
|
|
2068
2113
|
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
2069
2114
|
triggerClassName
|
|
@@ -2084,7 +2129,7 @@ function BackendSelector({
|
|
|
2084
2129
|
"border border-[var(--md3-outline-variant)] bg-surface-container px-3 py-2.5 text-sm text-left",
|
|
2085
2130
|
"transition-colors duration-[var(--transition-fast)]",
|
|
2086
2131
|
"hover:border-[var(--md3-outline-variant)] hover:bg-surface-container-high",
|
|
2087
|
-
|
|
2132
|
+
focusRing4,
|
|
2088
2133
|
"data-[state=open]:border-[var(--md3-outline)] data-[state=open]:bg-surface-container-high",
|
|
2089
2134
|
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
2090
2135
|
triggerClassName
|
|
@@ -2338,7 +2383,7 @@ function useBrandThemeSync() {
|
|
|
2338
2383
|
}
|
|
2339
2384
|
|
|
2340
2385
|
// src/dashboard/dashboard-layout.tsx
|
|
2341
|
-
import { Fragment as
|
|
2386
|
+
import { Fragment as Fragment9, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2342
2387
|
function MenuIcon({ className }) {
|
|
2343
2388
|
return /* @__PURE__ */ jsxs14("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
2344
2389
|
/* @__PURE__ */ jsx17("title", { children: "Menu icon" }),
|
|
@@ -2425,7 +2470,7 @@ function DashboardLayoutInner({
|
|
|
2425
2470
|
);
|
|
2426
2471
|
const activePanel = panels.find((p) => p.mode === mode);
|
|
2427
2472
|
const buildSidebarContent = React9.useCallback(
|
|
2428
|
-
(showLabels, allowCollapse) => /* @__PURE__ */ jsxs14(
|
|
2473
|
+
(showLabels, allowCollapse) => /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
2429
2474
|
/* @__PURE__ */ jsxs14(SidebarRail, { wide: showLabels, children: [
|
|
2430
2475
|
/* @__PURE__ */ jsx17(
|
|
2431
2476
|
RailHeader,
|
|
@@ -2706,7 +2751,7 @@ function DashboardLayout({ defaultPanelOpen, defaultMode, labeledRail, defaultRa
|
|
|
2706
2751
|
|
|
2707
2752
|
// src/dashboard/sidebar-layout.tsx
|
|
2708
2753
|
import * as React10 from "react";
|
|
2709
|
-
import { Fragment as
|
|
2754
|
+
import { Fragment as Fragment10, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2710
2755
|
var HIDE_BELOW_CLASS = {
|
|
2711
2756
|
md: "max-md:hidden",
|
|
2712
2757
|
lg: "max-lg:hidden"
|
|
@@ -2939,7 +2984,7 @@ function SidebarLayoutInner({
|
|
|
2939
2984
|
breakpoint: hideBelow,
|
|
2940
2985
|
onClose: closeMobileNav,
|
|
2941
2986
|
header: railHeaderContent ?? logo,
|
|
2942
|
-
footer: railFooter !== void 0 || hasProfile ? /* @__PURE__ */ jsxs15(
|
|
2987
|
+
footer: railFooter !== void 0 || hasProfile ? /* @__PURE__ */ jsxs15(Fragment10, { children: [
|
|
2943
2988
|
railFooter,
|
|
2944
2989
|
hasProfile && /* @__PURE__ */ jsx18(
|
|
2945
2990
|
ProfileAvatar,
|
|
@@ -3096,7 +3141,7 @@ import {
|
|
|
3096
3141
|
DropdownMenuSeparator as DropdownMenuSeparator4,
|
|
3097
3142
|
DropdownMenuTrigger as DropdownMenuTrigger4
|
|
3098
3143
|
} from "@tangle-network/ui/primitives";
|
|
3099
|
-
import { Fragment as
|
|
3144
|
+
import { Fragment as Fragment11, jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
3100
3145
|
function ProfileSelector({
|
|
3101
3146
|
profiles,
|
|
3102
3147
|
selectedId,
|
|
@@ -3130,7 +3175,7 @@ function ProfileSelector({
|
|
|
3130
3175
|
]
|
|
3131
3176
|
}
|
|
3132
3177
|
),
|
|
3133
|
-
builtinProfiles.length > 0 && /* @__PURE__ */ jsxs16(
|
|
3178
|
+
builtinProfiles.length > 0 && /* @__PURE__ */ jsxs16(Fragment11, { children: [
|
|
3134
3179
|
/* @__PURE__ */ jsx19(DropdownMenuSeparator4, {}),
|
|
3135
3180
|
/* @__PURE__ */ jsx19(DropdownMenuLabel2, { children: "Built-in Profiles" }),
|
|
3136
3181
|
builtinProfiles.map((profile) => /* @__PURE__ */ jsxs16(
|
|
@@ -3155,7 +3200,7 @@ function ProfileSelector({
|
|
|
3155
3200
|
profile.id
|
|
3156
3201
|
))
|
|
3157
3202
|
] }),
|
|
3158
|
-
customProfiles.length > 0 && /* @__PURE__ */ jsxs16(
|
|
3203
|
+
customProfiles.length > 0 && /* @__PURE__ */ jsxs16(Fragment11, { children: [
|
|
3159
3204
|
/* @__PURE__ */ jsx19(DropdownMenuSeparator4, {}),
|
|
3160
3205
|
/* @__PURE__ */ jsx19(DropdownMenuLabel2, { children: "Custom Profiles" }),
|
|
3161
3206
|
customProfiles.map((profile) => /* @__PURE__ */ jsxs16(
|
|
@@ -3192,7 +3237,7 @@ function ProfileSelector({
|
|
|
3192
3237
|
profile.id
|
|
3193
3238
|
))
|
|
3194
3239
|
] }),
|
|
3195
|
-
(onCreateClick || onManageClick) && /* @__PURE__ */ jsxs16(
|
|
3240
|
+
(onCreateClick || onManageClick) && /* @__PURE__ */ jsxs16(Fragment11, { children: [
|
|
3196
3241
|
/* @__PURE__ */ jsx19(DropdownMenuSeparator4, {}),
|
|
3197
3242
|
onCreateClick && /* @__PURE__ */ jsxs16(
|
|
3198
3243
|
DropdownMenuItem4,
|
|
@@ -3434,7 +3479,7 @@ import {
|
|
|
3434
3479
|
} from "lucide-react";
|
|
3435
3480
|
import { Button as Button3 } from "@tangle-network/ui/primitives";
|
|
3436
3481
|
import { Badge as Badge2 } from "@tangle-network/ui/primitives";
|
|
3437
|
-
import { Fragment as
|
|
3482
|
+
import { Fragment as Fragment13, jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
3438
3483
|
var statusConfig = {
|
|
3439
3484
|
pending: {
|
|
3440
3485
|
icon: Clock3,
|
|
@@ -3558,7 +3603,7 @@ function VariantList({
|
|
|
3558
3603
|
children: outcomeConfig[variant.outcome].label
|
|
3559
3604
|
}
|
|
3560
3605
|
),
|
|
3561
|
-
variant.status === "completed" && variant.outcome === "pending_review" && onAccept && onReject && /* @__PURE__ */ jsxs18(
|
|
3606
|
+
variant.status === "completed" && variant.outcome === "pending_review" && onAccept && onReject && /* @__PURE__ */ jsxs18(Fragment13, { children: [
|
|
3562
3607
|
/* @__PURE__ */ jsxs18(
|
|
3563
3608
|
Button3,
|
|
3564
3609
|
{
|
|
@@ -3872,16 +3917,38 @@ function GitPanel({ status, log, loading = false, onRefresh, className }) {
|
|
|
3872
3917
|
// src/dashboard/ports-list.tsx
|
|
3873
3918
|
import * as React13 from "react";
|
|
3874
3919
|
import { Copy as Copy3, Check as Check5, Globe, Plus as Plus4, Trash2 as Trash23 } from "lucide-react";
|
|
3920
|
+
import { focusField, focusRing as focusRing5 } from "@tangle-network/ui/utils";
|
|
3875
3921
|
import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
3876
3922
|
function PortsList({ ports, onExposePort, onRemovePort, isExposing = false, className }) {
|
|
3877
3923
|
const [newPort, setNewPort] = React13.useState("");
|
|
3878
3924
|
const [copiedPort, setCopiedPort] = React13.useState(null);
|
|
3925
|
+
const [statusMessage, setStatusMessage] = React13.useState("");
|
|
3879
3926
|
const copyTimerRef = React13.useRef(null);
|
|
3927
|
+
const pendingRemovalRef = React13.useRef(null);
|
|
3928
|
+
const removeButtonsRef = React13.useRef(/* @__PURE__ */ new Map());
|
|
3929
|
+
const portInputRef = React13.useRef(null);
|
|
3930
|
+
const portInputId = React13.useId();
|
|
3931
|
+
const portErrorId = React13.useId();
|
|
3932
|
+
const portNumber = Number(newPort);
|
|
3933
|
+
const validPort = /^\d+$/.test(newPort) && portNumber >= 1 && portNumber <= 65535;
|
|
3934
|
+
const duplicatePort = validPort && ports.some((port) => port.port === portNumber);
|
|
3935
|
+
const portError = newPort === "" ? null : !validPort ? "Enter a whole port number from 1 to 65535." : duplicatePort ? `Port ${portNumber} is already exposed.` : null;
|
|
3880
3936
|
React13.useEffect(() => {
|
|
3881
3937
|
return () => {
|
|
3882
3938
|
if (copyTimerRef.current) clearTimeout(copyTimerRef.current);
|
|
3883
3939
|
};
|
|
3884
3940
|
}, []);
|
|
3941
|
+
React13.useEffect(() => {
|
|
3942
|
+
const pending = pendingRemovalRef.current;
|
|
3943
|
+
if (!pending || ports.some((port) => port.port === pending.removed)) return;
|
|
3944
|
+
setStatusMessage(`Port ${pending.removed} removed.`);
|
|
3945
|
+
if (pending.restoreFocus) {
|
|
3946
|
+
const nextButton = pending.next == null ? null : removeButtonsRef.current.get(pending.next);
|
|
3947
|
+
const focusTarget = nextButton ?? removeButtonsRef.current.values().next().value ?? portInputRef.current;
|
|
3948
|
+
focusTarget?.focus();
|
|
3949
|
+
}
|
|
3950
|
+
pendingRemovalRef.current = null;
|
|
3951
|
+
}, [ports]);
|
|
3885
3952
|
const handleCopy = async (url, port) => {
|
|
3886
3953
|
try {
|
|
3887
3954
|
await navigator.clipboard.writeText(url);
|
|
@@ -3893,86 +3960,114 @@ function PortsList({ ports, onExposePort, onRemovePort, isExposing = false, clas
|
|
|
3893
3960
|
}
|
|
3894
3961
|
};
|
|
3895
3962
|
const handleExpose = () => {
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
onExposePort(port);
|
|
3963
|
+
if (validPort && !duplicatePort && !isExposing) {
|
|
3964
|
+
onExposePort(portNumber);
|
|
3899
3965
|
setNewPort("");
|
|
3900
3966
|
}
|
|
3901
3967
|
};
|
|
3902
3968
|
return /* @__PURE__ */ jsxs22("div", { className: cn("space-y-4", className), children: [
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
/* @__PURE__ */ jsx25("
|
|
3907
|
-
/* @__PURE__ */ jsx25("
|
|
3908
|
-
/* @__PURE__ */ jsx25("
|
|
3909
|
-
] })
|
|
3910
|
-
/* @__PURE__ */ jsx25("
|
|
3911
|
-
/* @__PURE__ */
|
|
3912
|
-
|
|
3969
|
+
/* @__PURE__ */ jsx25("span", { role: "status", className: "sr-only", children: statusMessage }),
|
|
3970
|
+
ports.length > 0 ? /* @__PURE__ */ jsxs22("div", { className: "overflow-hidden rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container text-sm", children: [
|
|
3971
|
+
/* @__PURE__ */ jsxs22("div", { "aria-hidden": "true", className: "hidden border-b border-[var(--md3-outline-variant)] bg-surface-container-high px-3 py-2.5 text-xs font-medium text-muted-foreground sm:grid sm:grid-cols-[4rem_minmax(0,1fr)_5.5rem_3rem] sm:gap-x-2", children: [
|
|
3972
|
+
/* @__PURE__ */ jsx25("span", { children: "Port" }),
|
|
3973
|
+
/* @__PURE__ */ jsx25("span", { children: "Public URL" }),
|
|
3974
|
+
/* @__PURE__ */ jsx25("span", { children: "Status" })
|
|
3975
|
+
] }),
|
|
3976
|
+
/* @__PURE__ */ jsx25("ul", { className: "divide-y divide-border", children: ports.map((p, index) => /* @__PURE__ */ jsxs22("li", { className: "grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-2 gap-y-1 px-3 py-2 sm:grid-cols-[4rem_minmax(0,1fr)_5.5rem_3rem] sm:py-1", children: [
|
|
3977
|
+
/* @__PURE__ */ jsxs22("span", { className: "col-start-1 row-start-1 font-mono text-xs text-foreground", children: [
|
|
3978
|
+
/* @__PURE__ */ jsx25("span", { className: "sr-only", children: "Port " }),
|
|
3979
|
+
p.port
|
|
3980
|
+
] }),
|
|
3981
|
+
/* @__PURE__ */ jsxs22(
|
|
3913
3982
|
"button",
|
|
3914
3983
|
{
|
|
3915
3984
|
type: "button",
|
|
3985
|
+
"aria-label": copiedPort === p.port ? `Copied public URL for port ${p.port}` : `Copy public URL for port ${p.port}: ${p.url}`,
|
|
3916
3986
|
onClick: () => handleCopy(p.url, p.port),
|
|
3917
|
-
className:
|
|
3987
|
+
className: `col-span-2 row-start-3 flex min-h-10 min-w-0 items-center gap-2 rounded text-left font-mono text-xs text-[var(--accent-text)] hover:underline sm:col-span-1 sm:col-start-2 sm:row-start-1 ${focusRing5}`,
|
|
3918
3988
|
children: [
|
|
3919
|
-
/* @__PURE__ */ jsx25("span", { className: "
|
|
3920
|
-
copiedPort === p.port ? /* @__PURE__ */ jsx25(Check5, { className: "h-
|
|
3989
|
+
/* @__PURE__ */ jsx25("span", { "aria-hidden": "true", className: "min-w-0 flex-1 break-all sm:truncate", children: p.url }),
|
|
3990
|
+
copiedPort === p.port ? /* @__PURE__ */ jsx25(Check5, { className: "h-4 w-4 shrink-0 text-[var(--surface-success-text)]", "aria-hidden": "true" }) : /* @__PURE__ */ jsx25(Copy3, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" })
|
|
3921
3991
|
]
|
|
3922
3992
|
}
|
|
3923
|
-
)
|
|
3924
|
-
/* @__PURE__ */
|
|
3925
|
-
"inline-flex items-center
|
|
3993
|
+
),
|
|
3994
|
+
/* @__PURE__ */ jsxs22("span", { className: cn(
|
|
3995
|
+
"col-start-1 row-start-2 inline-flex items-center justify-self-start rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider sm:col-start-3 sm:row-start-1",
|
|
3926
3996
|
p.status === "active" ? "bg-[var(--surface-success-bg)] text-[var(--surface-success-text)]" : "bg-[var(--surface-warning-bg)] text-[var(--surface-warning-text)]"
|
|
3927
|
-
), children:
|
|
3928
|
-
|
|
3997
|
+
), children: [
|
|
3998
|
+
/* @__PURE__ */ jsx25("span", { className: "sr-only", children: "Status: " }),
|
|
3999
|
+
p.status
|
|
4000
|
+
] }),
|
|
4001
|
+
onRemovePort && /* @__PURE__ */ jsx25(
|
|
3929
4002
|
"button",
|
|
3930
4003
|
{
|
|
3931
4004
|
type: "button",
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
4005
|
+
"aria-label": `Remove port ${p.port}`,
|
|
4006
|
+
ref: (button) => {
|
|
4007
|
+
if (button) removeButtonsRef.current.set(p.port, button);
|
|
4008
|
+
else removeButtonsRef.current.delete(p.port);
|
|
4009
|
+
},
|
|
4010
|
+
onClick: (event) => {
|
|
4011
|
+
pendingRemovalRef.current = {
|
|
4012
|
+
removed: p.port,
|
|
4013
|
+
next: ports[index + 1]?.port ?? ports[index - 1]?.port ?? null,
|
|
4014
|
+
restoreFocus: event.detail === 0
|
|
4015
|
+
};
|
|
4016
|
+
onRemovePort(p.port);
|
|
4017
|
+
},
|
|
4018
|
+
className: `col-start-2 row-start-1 inline-flex min-h-10 min-w-10 items-center justify-center rounded text-muted-foreground transition-colors hover:text-destructive sm:col-start-4 ${focusRing5}`,
|
|
4019
|
+
children: /* @__PURE__ */ jsx25(Trash23, { className: "h-4 w-4", "aria-hidden": "true" })
|
|
3935
4020
|
}
|
|
3936
|
-
)
|
|
4021
|
+
)
|
|
3937
4022
|
] }, p.port)) })
|
|
3938
|
-
] })
|
|
4023
|
+
] }) : /* @__PURE__ */ jsxs22("div", { className: "rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container p-6 text-center", children: [
|
|
3939
4024
|
/* @__PURE__ */ jsx25(Globe, { className: "mx-auto h-8 w-8 text-muted-foreground mb-2" }),
|
|
3940
4025
|
/* @__PURE__ */ jsx25("p", { className: "text-sm text-muted-foreground", children: "No ports exposed yet" })
|
|
3941
4026
|
] }),
|
|
3942
|
-
/* @__PURE__ */ jsxs22("div", { className: "flex items-
|
|
3943
|
-
/* @__PURE__ */
|
|
3944
|
-
"
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
4027
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex flex-wrap items-end gap-3", children: [
|
|
4028
|
+
/* @__PURE__ */ jsxs22("div", { className: "min-w-0 flex-[1_1_10rem]", children: [
|
|
4029
|
+
/* @__PURE__ */ jsx25("label", { htmlFor: portInputId, className: "mb-1 block text-xs font-medium text-muted-foreground", children: "Port number" }),
|
|
4030
|
+
/* @__PURE__ */ jsx25(
|
|
4031
|
+
"input",
|
|
4032
|
+
{
|
|
4033
|
+
ref: portInputRef,
|
|
4034
|
+
id: portInputId,
|
|
4035
|
+
type: "number",
|
|
4036
|
+
min: 1,
|
|
4037
|
+
max: 65535,
|
|
4038
|
+
step: 1,
|
|
4039
|
+
"aria-invalid": Boolean(portError),
|
|
4040
|
+
"aria-describedby": portError ? portErrorId : void 0,
|
|
4041
|
+
placeholder: "3000",
|
|
4042
|
+
value: newPort,
|
|
4043
|
+
onChange: (e) => setNewPort(e.target.value),
|
|
4044
|
+
onKeyDown: (e) => e.key === "Enter" && handleExpose(),
|
|
4045
|
+
className: `w-full min-w-0 rounded-lg border bg-surface-container-low px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground ${focusField}`
|
|
4046
|
+
}
|
|
4047
|
+
)
|
|
4048
|
+
] }),
|
|
3956
4049
|
/* @__PURE__ */ jsxs22(
|
|
3957
4050
|
"button",
|
|
3958
4051
|
{
|
|
3959
4052
|
type: "button",
|
|
3960
4053
|
onClick: handleExpose,
|
|
3961
|
-
disabled: !
|
|
3962
|
-
className:
|
|
4054
|
+
disabled: !validPort || duplicatePort || isExposing,
|
|
4055
|
+
className: `inline-flex shrink-0 items-center gap-2 rounded-lg bg-[var(--btn-primary-bg)] px-4 py-2 text-sm font-semibold text-[var(--btn-primary-text)] shadow-sm transition-colors hover:bg-[var(--btn-primary-hover)] disabled:cursor-not-allowed disabled:opacity-55 disabled:shadow-none ${focusRing5}`,
|
|
3963
4056
|
children: [
|
|
3964
4057
|
/* @__PURE__ */ jsx25(Plus4, { className: "h-4 w-4" }),
|
|
3965
4058
|
"Expose"
|
|
3966
4059
|
]
|
|
3967
4060
|
}
|
|
3968
4061
|
)
|
|
3969
|
-
] })
|
|
4062
|
+
] }),
|
|
4063
|
+
portError && /* @__PURE__ */ jsx25("p", { id: portErrorId, className: "text-xs text-[var(--surface-danger-text)]", children: portError })
|
|
3970
4064
|
] });
|
|
3971
4065
|
}
|
|
3972
4066
|
|
|
3973
4067
|
// src/dashboard/process-list.tsx
|
|
3974
4068
|
import * as React14 from "react";
|
|
3975
4069
|
import { Activity as Activity3, Plus as Plus5, Skull, Terminal as Terminal4 } from "lucide-react";
|
|
4070
|
+
import { focusField as focusField2, focusRing as focusRing6 } from "@tangle-network/ui/utils";
|
|
3976
4071
|
import { jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3977
4072
|
function formatUptime(startedAt) {
|
|
3978
4073
|
if (!startedAt) return "-";
|
|
@@ -3984,6 +4079,18 @@ function formatUptime(startedAt) {
|
|
|
3984
4079
|
}
|
|
3985
4080
|
function ProcessList({ processes, onSpawn, onKill, loading = false, className }) {
|
|
3986
4081
|
const [newCommand, setNewCommand] = React14.useState("");
|
|
4082
|
+
const [statusMessage, setStatusMessage] = React14.useState("");
|
|
4083
|
+
const commandId = React14.useId();
|
|
4084
|
+
const commandInputRef = React14.useRef(null);
|
|
4085
|
+
const pendingKillRef = React14.useRef(null);
|
|
4086
|
+
React14.useEffect(() => {
|
|
4087
|
+
const pending = pendingKillRef.current;
|
|
4088
|
+
if (!pending || processes.some((process) => process.pid === pending.pid && process.running)) return;
|
|
4089
|
+
const stopped = processes.find((process) => process.pid === pending.pid);
|
|
4090
|
+
setStatusMessage(stopped?.exitCode == null ? `Process ${pending.pid} stopped.` : `Process ${pending.pid} exited with code ${stopped.exitCode}.`);
|
|
4091
|
+
if (pending.restoreFocus) commandInputRef.current?.focus();
|
|
4092
|
+
pendingKillRef.current = null;
|
|
4093
|
+
}, [processes]);
|
|
3987
4094
|
const handleSpawn = () => {
|
|
3988
4095
|
const cmd = newCommand.trim();
|
|
3989
4096
|
if (cmd) {
|
|
@@ -3992,61 +4099,73 @@ function ProcessList({ processes, onSpawn, onKill, loading = false, className })
|
|
|
3992
4099
|
}
|
|
3993
4100
|
};
|
|
3994
4101
|
return /* @__PURE__ */ jsxs23("div", { className: cn("space-y-4", className), children: [
|
|
4102
|
+
/* @__PURE__ */ jsx26("span", { role: "status", className: "sr-only", children: statusMessage }),
|
|
3995
4103
|
loading ? /* @__PURE__ */ jsxs23("div", { className: "rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container p-6 text-center", children: [
|
|
3996
4104
|
/* @__PURE__ */ jsx26(Activity3, { className: "mx-auto h-6 w-6 text-muted-foreground animate-spin mb-2", "data-motion": "essential" }),
|
|
3997
4105
|
/* @__PURE__ */ jsx26("p", { className: "text-sm text-muted-foreground", children: "Loading processes..." })
|
|
3998
|
-
] }) : processes.length > 0 ? /* @__PURE__ */ jsx26("div", { className: "rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container overflow-hidden", children: /* @__PURE__ */
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
/* @__PURE__ */
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4106
|
+
] }) : processes.length > 0 ? /* @__PURE__ */ jsx26("div", { className: "rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container overflow-hidden", children: /* @__PURE__ */ jsx26("ul", { "aria-label": "Processes", className: "divide-y divide-border", children: processes.map((p) => {
|
|
4107
|
+
const age = formatUptime(p.startedAt);
|
|
4108
|
+
return /* @__PURE__ */ jsxs23("li", { className: "flex min-w-0 items-start gap-3 px-3 py-3", children: [
|
|
4109
|
+
/* @__PURE__ */ jsxs23("div", { className: "min-w-0 flex-1", children: [
|
|
4110
|
+
/* @__PURE__ */ jsx26("code", { className: "block break-all font-mono text-xs leading-5 text-foreground", children: p.command }),
|
|
4111
|
+
/* @__PURE__ */ jsxs23("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
4112
|
+
/* @__PURE__ */ jsxs23("span", { className: "font-mono tabular-nums", children: [
|
|
4113
|
+
"PID ",
|
|
4114
|
+
p.pid
|
|
4115
|
+
] }),
|
|
4116
|
+
/* @__PURE__ */ jsx26("span", { className: cn(
|
|
4117
|
+
"inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider",
|
|
4118
|
+
p.running ? "bg-[var(--surface-success-bg)] text-[var(--surface-success-text)]" : "bg-surface-container-high text-muted-foreground"
|
|
4119
|
+
), children: p.running ? "running" : `exited (${p.exitCode ?? "?"})` }),
|
|
4120
|
+
age !== "-" && /* @__PURE__ */ jsx26("span", { className: "font-mono tabular-nums", children: p.running ? `Uptime ${age}` : `Started ${age} ago` })
|
|
4121
|
+
] })
|
|
4122
|
+
] }),
|
|
4123
|
+
p.running && /* @__PURE__ */ jsx26(
|
|
4015
4124
|
"button",
|
|
4016
4125
|
{
|
|
4017
4126
|
type: "button",
|
|
4018
|
-
onClick: () =>
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4127
|
+
onClick: (event) => {
|
|
4128
|
+
pendingKillRef.current = { pid: p.pid, restoreFocus: event.detail === 0 };
|
|
4129
|
+
onKill(p.pid);
|
|
4130
|
+
},
|
|
4131
|
+
className: `flex size-10 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive ${focusRing6}`,
|
|
4132
|
+
"aria-label": `Kill process ${p.pid}`,
|
|
4133
|
+
title: `Kill process ${p.pid}`,
|
|
4134
|
+
children: /* @__PURE__ */ jsx26(Skull, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
4022
4135
|
}
|
|
4023
|
-
)
|
|
4024
|
-
] }, `${p.pid}-${p.startedAt ?? p.command}`)
|
|
4025
|
-
|
|
4136
|
+
)
|
|
4137
|
+
] }, `${p.pid}-${p.startedAt ?? p.command}`);
|
|
4138
|
+
}) }) }) : /* @__PURE__ */ jsxs23("div", { className: "rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container p-6 text-center", children: [
|
|
4026
4139
|
/* @__PURE__ */ jsx26(Terminal4, { className: "mx-auto h-8 w-8 text-muted-foreground mb-2" }),
|
|
4027
4140
|
/* @__PURE__ */ jsx26("p", { className: "text-sm text-muted-foreground", children: "No processes running" })
|
|
4028
4141
|
] }),
|
|
4029
|
-
/* @__PURE__ */ jsxs23("
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4142
|
+
/* @__PURE__ */ jsxs23("form", { onSubmit: (event) => {
|
|
4143
|
+
event.preventDefault();
|
|
4144
|
+
handleSpawn();
|
|
4145
|
+
}, className: "flex min-w-0 flex-wrap items-end gap-2", children: [
|
|
4146
|
+
/* @__PURE__ */ jsxs23("div", { className: "min-w-0 flex-[1_1_12rem]", children: [
|
|
4147
|
+
/* @__PURE__ */ jsx26("label", { htmlFor: commandId, className: "mb-1 block text-xs font-medium text-muted-foreground", children: "Command" }),
|
|
4148
|
+
/* @__PURE__ */ jsx26(
|
|
4149
|
+
"input",
|
|
4150
|
+
{
|
|
4151
|
+
ref: commandInputRef,
|
|
4152
|
+
id: commandId,
|
|
4153
|
+
type: "text",
|
|
4154
|
+
placeholder: "node app.js",
|
|
4155
|
+
value: newCommand,
|
|
4156
|
+
onChange: (e) => setNewCommand(e.target.value),
|
|
4157
|
+
className: `w-full min-w-0 rounded-lg border bg-surface-container-low px-3 py-2 text-sm font-mono text-foreground placeholder:text-muted-foreground ${focusField2}`
|
|
4158
|
+
}
|
|
4159
|
+
)
|
|
4160
|
+
] }),
|
|
4041
4161
|
/* @__PURE__ */ jsxs23(
|
|
4042
4162
|
"button",
|
|
4043
4163
|
{
|
|
4044
|
-
type: "
|
|
4045
|
-
onClick: handleSpawn,
|
|
4164
|
+
type: "submit",
|
|
4046
4165
|
disabled: !newCommand.trim(),
|
|
4047
|
-
className:
|
|
4166
|
+
className: `inline-flex h-10 shrink-0 items-center gap-2 rounded-lg border border-[var(--border-accent)] bg-[var(--accent-surface-soft)] px-3 text-sm font-medium text-[var(--accent-text)] transition-colors hover:bg-[var(--btn-primary-bg)] hover:text-[var(--btn-primary-text)] disabled:opacity-50 ${focusRing6}`,
|
|
4048
4167
|
children: [
|
|
4049
|
-
/* @__PURE__ */ jsx26(Plus5, { className: "h-4 w-4" }),
|
|
4168
|
+
/* @__PURE__ */ jsx26(Plus5, { "aria-hidden": "true", className: "h-4 w-4" }),
|
|
4050
4169
|
"Spawn"
|
|
4051
4170
|
]
|
|
4052
4171
|
}
|
|
@@ -4058,6 +4177,7 @@ function ProcessList({ processes, onSpawn, onKill, loading = false, className })
|
|
|
4058
4177
|
// src/dashboard/network-config.tsx
|
|
4059
4178
|
import * as React15 from "react";
|
|
4060
4179
|
import { Network as Network2, Plus as Plus6, Trash2 as Trash24, ShieldAlert } from "lucide-react";
|
|
4180
|
+
import { focusField as focusField3, focusRing as focusRing7 } from "@tangle-network/ui/utils";
|
|
4061
4181
|
import { jsx as jsx27, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
4062
4182
|
function NetworkConfig({ config, onUpdate, loading = false, className }) {
|
|
4063
4183
|
const [newCidr, setNewCidr] = React15.useState("");
|
|
@@ -4127,8 +4247,9 @@ function NetworkConfig({ config, onUpdate, loading = false, className }) {
|
|
|
4127
4247
|
"button",
|
|
4128
4248
|
{
|
|
4129
4249
|
type: "button",
|
|
4250
|
+
"aria-label": `Remove ${cidr} from allowlist`,
|
|
4130
4251
|
onClick: () => handleRemoveCidr(cidr),
|
|
4131
|
-
className:
|
|
4252
|
+
className: `p-2 text-muted-foreground hover:text-destructive transition-colors rounded ${focusRing7}`,
|
|
4132
4253
|
children: /* @__PURE__ */ jsx27(Trash24, { className: "h-3 w-3" })
|
|
4133
4254
|
}
|
|
4134
4255
|
)
|
|
@@ -4138,11 +4259,12 @@ function NetworkConfig({ config, onUpdate, loading = false, className }) {
|
|
|
4138
4259
|
"input",
|
|
4139
4260
|
{
|
|
4140
4261
|
type: "text",
|
|
4262
|
+
"aria-label": "CIDR to allow",
|
|
4141
4263
|
placeholder: "CIDR (e.g. 10.0.0.0/8)",
|
|
4142
4264
|
value: newCidr,
|
|
4143
4265
|
onChange: (e) => setNewCidr(e.target.value),
|
|
4144
4266
|
onKeyDown: (e) => e.key === "Enter" && handleAddCidr(),
|
|
4145
|
-
className:
|
|
4267
|
+
className: `flex-1 rounded-lg border bg-surface-container-low px-3 py-2 text-sm font-mono text-foreground placeholder:text-muted-foreground ${focusField3}`
|
|
4146
4268
|
}
|
|
4147
4269
|
),
|
|
4148
4270
|
/* @__PURE__ */ jsxs24(
|
|
@@ -4166,7 +4288,8 @@ function NetworkConfig({ config, onUpdate, loading = false, className }) {
|
|
|
4166
4288
|
// src/dashboard/backend-config.tsx
|
|
4167
4289
|
import * as React16 from "react";
|
|
4168
4290
|
import { Bot as Bot2, Plus as Plus7, Trash2 as Trash25, Server, Wrench } from "lucide-react";
|
|
4169
|
-
import {
|
|
4291
|
+
import { focusField as focusField4, focusRing as focusRing8 } from "@tangle-network/ui/utils";
|
|
4292
|
+
import { Fragment as Fragment14, jsx as jsx28, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
4170
4293
|
function BackendConfig({
|
|
4171
4294
|
status,
|
|
4172
4295
|
mcpServers,
|
|
@@ -4223,7 +4346,7 @@ function BackendConfig({
|
|
|
4223
4346
|
), children: status.running ? "Running" : "Stopped" }) }),
|
|
4224
4347
|
/* @__PURE__ */ jsx28("dt", { className: "text-muted-foreground", children: "Model" }),
|
|
4225
4348
|
/* @__PURE__ */ jsx28("dd", { className: "font-mono text-xs", children: status.model ?? "Default" }),
|
|
4226
|
-
status.provider && /* @__PURE__ */ jsxs25(
|
|
4349
|
+
status.provider && /* @__PURE__ */ jsxs25(Fragment14, { children: [
|
|
4227
4350
|
/* @__PURE__ */ jsx28("dt", { className: "text-muted-foreground", children: "Provider" }),
|
|
4228
4351
|
/* @__PURE__ */ jsx28("dd", { className: "font-mono text-xs", children: status.provider })
|
|
4229
4352
|
] })
|
|
@@ -4269,44 +4392,53 @@ function BackendConfig({
|
|
|
4269
4392
|
"button",
|
|
4270
4393
|
{
|
|
4271
4394
|
type: "button",
|
|
4395
|
+
"aria-label": `Remove ${s.name} MCP server`,
|
|
4272
4396
|
onClick: () => onRemoveMcp(s.name),
|
|
4273
|
-
className:
|
|
4397
|
+
className: `p-2 text-muted-foreground hover:text-destructive transition-colors rounded ${focusRing8}`,
|
|
4274
4398
|
children: /* @__PURE__ */ jsx28(Trash25, { className: "h-3.5 w-3.5" })
|
|
4275
4399
|
}
|
|
4276
4400
|
)
|
|
4277
4401
|
] })
|
|
4278
4402
|
] }, s.name)) }) : /* @__PURE__ */ jsx28("div", { className: "p-4 text-center", children: /* @__PURE__ */ jsx28("p", { className: "text-xs text-muted-foreground", children: "No MCP servers configured" }) }),
|
|
4279
4403
|
showAddMcp && /* @__PURE__ */ jsxs25("div", { className: "p-4 border-t border-[var(--md3-outline-variant)] bg-surface-container-high space-y-2", children: [
|
|
4280
|
-
/* @__PURE__ */
|
|
4281
|
-
"
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4404
|
+
/* @__PURE__ */ jsxs25("label", { className: "block space-y-1 text-xs font-medium text-muted-foreground", children: [
|
|
4405
|
+
/* @__PURE__ */ jsx28("span", { children: "Server name" }),
|
|
4406
|
+
/* @__PURE__ */ jsx28(
|
|
4407
|
+
"input",
|
|
4408
|
+
{
|
|
4409
|
+
type: "text",
|
|
4410
|
+
value: mcpName,
|
|
4411
|
+
onChange: (e) => setMcpName(e.target.value),
|
|
4412
|
+
className: `w-full rounded-lg border bg-surface-container-low px-3 py-2 text-sm text-foreground ${focusField4}`
|
|
4413
|
+
}
|
|
4414
|
+
)
|
|
4415
|
+
] }),
|
|
4416
|
+
/* @__PURE__ */ jsxs25("label", { className: "block space-y-1 text-xs font-medium text-muted-foreground", children: [
|
|
4417
|
+
/* @__PURE__ */ jsx28("span", { children: "Command" }),
|
|
4418
|
+
/* @__PURE__ */ jsx28(
|
|
4419
|
+
"input",
|
|
4420
|
+
{
|
|
4421
|
+
type: "text",
|
|
4422
|
+
placeholder: "npx @server/mcp",
|
|
4423
|
+
value: mcpCommand,
|
|
4424
|
+
onChange: (e) => setMcpCommand(e.target.value),
|
|
4425
|
+
className: `w-full rounded-lg border bg-surface-container-low px-3 py-2 text-sm font-mono text-foreground placeholder:text-muted-foreground ${focusField4}`
|
|
4426
|
+
}
|
|
4427
|
+
)
|
|
4428
|
+
] }),
|
|
4429
|
+
/* @__PURE__ */ jsxs25("label", { className: "block space-y-1 text-xs font-medium text-muted-foreground", children: [
|
|
4430
|
+
/* @__PURE__ */ jsx28("span", { children: "Arguments (optional)" }),
|
|
4431
|
+
/* @__PURE__ */ jsx28(
|
|
4432
|
+
"input",
|
|
4433
|
+
{
|
|
4434
|
+
type: "text",
|
|
4435
|
+
placeholder: "Space-separated arguments",
|
|
4436
|
+
value: mcpArgs,
|
|
4437
|
+
onChange: (e) => setMcpArgs(e.target.value),
|
|
4438
|
+
className: `w-full rounded-lg border bg-surface-container-low px-3 py-2 text-sm font-mono text-foreground placeholder:text-muted-foreground ${focusField4}`
|
|
4439
|
+
}
|
|
4440
|
+
)
|
|
4441
|
+
] }),
|
|
4310
4442
|
/* @__PURE__ */ jsxs25("div", { className: "flex justify-end gap-2 pt-1", children: [
|
|
4311
4443
|
/* @__PURE__ */ jsx28(
|
|
4312
4444
|
"button",
|
|
@@ -4336,6 +4468,7 @@ function BackendConfig({
|
|
|
4336
4468
|
// src/dashboard/snapshot-list.tsx
|
|
4337
4469
|
import * as React17 from "react";
|
|
4338
4470
|
import { Camera, Clock as Clock5, HardDrive as HardDrive2, Plus as Plus8, RotateCcw } from "lucide-react";
|
|
4471
|
+
import { focusField as focusField5 } from "@tangle-network/ui/utils";
|
|
4339
4472
|
import { jsx as jsx29, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
4340
4473
|
function formatBytes(bytes) {
|
|
4341
4474
|
if (bytes == null || bytes < 0) return "-";
|
|
@@ -4385,7 +4518,7 @@ function SnapshotList({ snapshots, onCreate, onRestore, onSaveAsTemplate, loadin
|
|
|
4385
4518
|
value: tags,
|
|
4386
4519
|
onChange: (e) => setTags(e.target.value),
|
|
4387
4520
|
onKeyDown: (e) => e.key === "Enter" && handleCreate(),
|
|
4388
|
-
className:
|
|
4521
|
+
className: `w-full rounded-lg border bg-surface-container-low px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground ${focusField5}`
|
|
4389
4522
|
}
|
|
4390
4523
|
),
|
|
4391
4524
|
/* @__PURE__ */ jsxs26("div", { className: "flex justify-end gap-2", children: [
|
|
@@ -4469,7 +4602,7 @@ function SnapshotList({ snapshots, onCreate, onRestore, onSaveAsTemplate, loadin
|
|
|
4469
4602
|
}
|
|
4470
4603
|
|
|
4471
4604
|
// src/dashboard/promo-banner.tsx
|
|
4472
|
-
import { Fragment as
|
|
4605
|
+
import { Fragment as Fragment15, jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
4473
4606
|
function PromoBanner({
|
|
4474
4607
|
title,
|
|
4475
4608
|
description,
|
|
@@ -4484,7 +4617,7 @@ function PromoBanner({
|
|
|
4484
4617
|
"mt-6 inline-flex items-center gap-2 rounded-md border border-white/20 bg-[var(--btn-primary-bg)] px-4 py-2 text-sm font-medium text-[var(--btn-primary-text)] transition-colors",
|
|
4485
4618
|
disabled ? "opacity-50 cursor-not-allowed" : "hover:bg-[var(--btn-primary-hover)]"
|
|
4486
4619
|
);
|
|
4487
|
-
const buttonContent = /* @__PURE__ */ jsxs27(
|
|
4620
|
+
const buttonContent = /* @__PURE__ */ jsxs27(Fragment15, { children: [
|
|
4488
4621
|
buttonLabel,
|
|
4489
4622
|
/* @__PURE__ */ jsxs27("svg", { "aria-hidden": "true", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "h-4 w-4", children: [
|
|
4490
4623
|
/* @__PURE__ */ jsx30("path", { d: "M5 12h14" }),
|