@tangle-network/sandbox-ui 0.24.2 → 0.26.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.
@@ -1629,7 +1629,15 @@ function SidebarLayoutInner({
1629
1629
  showLabel: railLabels
1630
1630
  },
1631
1631
  item.id
1632
- ) : /* @__PURE__ */ jsx14(RailButton, { icon: item.icon, label: item.label, badge: item.badge, isActive: activeId === item.id, showLabel: railLabels, asChild: true, children: /* @__PURE__ */ jsx14(Link, { href: item.href, to: item.href, onClick: handleNavClick }) }, item.id)
1632
+ ) : /* @__PURE__ */ jsx14(RailButton, { icon: item.icon, label: item.label, badge: item.badge, isActive: activeId === item.id, showLabel: railLabels, asChild: true, children: /* @__PURE__ */ jsx14(
1633
+ Link,
1634
+ {
1635
+ href: item.href,
1636
+ to: item.href,
1637
+ onClick: handleNavClick,
1638
+ ...item.prefetch !== void 0 ? { prefetch: item.prefetch } : {}
1639
+ }
1640
+ ) }, item.id)
1633
1641
  ) }),
1634
1642
  (railFooter !== void 0 || hasProfile) && /* @__PURE__ */ jsxs13(SidebarRailFooter, { className: cn("border-t border-border pt-2", railLabels && "items-stretch px-2"), children: [
1635
1643
  railFooter,
@@ -544,6 +544,12 @@ interface SidebarLayoutNavItem {
544
544
  /** Render this item as the panel toggle instead of a link. */
545
545
  togglesPanel?: boolean;
546
546
  badge?: number;
547
+ /**
548
+ * React Router prefetch behavior for this link, forwarded to the underlying
549
+ * `<Link prefetch>`. Omit to preserve the router's default (no prefetch).
550
+ * Ignored for panel-toggle items and for `LinkComponent`s that don't support it.
551
+ */
552
+ prefetch?: "none" | "intent" | "render" | "viewport";
547
553
  }
548
554
  interface SidebarLayoutProps {
549
555
  children: React.ReactNode;
package/dist/dashboard.js CHANGED
@@ -47,7 +47,7 @@ import {
47
47
  canAdminSandbox,
48
48
  parseInsufficientBalance,
49
49
  useSidebar
50
- } from "./chunk-76TCOY2R.js";
50
+ } from "./chunk-LDETDX7W.js";
51
51
  import {
52
52
  BillingDashboard,
53
53
  InfoPanel,
package/dist/globals.css CHANGED
@@ -30,7 +30,6 @@
30
30
  --color-violet-300: oklch(81.1% 0.111 293.571);
31
31
  --color-violet-400: oklch(70.2% 0.183 293.541);
32
32
  --color-violet-500: oklch(60.6% 0.25 292.717);
33
- --color-gray-900: oklch(21% 0.034 264.665);
34
33
  --color-zinc-400: oklch(70.5% 0.015 286.067);
35
34
  --color-neutral-400: oklch(70.8% 0 0);
36
35
  --color-neutral-500: oklch(55.6% 0 0);
@@ -2022,9 +2021,6 @@
2022
2021
  background-color: color-mix(in oklab, var(--color-emerald-500) 10%, transparent);
2023
2022
  }
2024
2023
  }
2025
- .bg-gray-900 {
2026
- background-color: var(--color-gray-900);
2027
- }
2028
2024
  .bg-green-400 {
2029
2025
  background-color: var(--color-green-400);
2030
2026
  }
@@ -3428,11 +3424,6 @@
3428
3424
  border-color: var(--border-accent-hover);
3429
3425
  }
3430
3426
  }
3431
- .focus\:border-transparent {
3432
- &:focus {
3433
- border-color: transparent;
3434
- }
3435
- }
3436
3427
  .focus\:text-\[var\(--surface-danger-text\)\] {
3437
3428
  &:focus {
3438
3429
  color: var(--surface-danger-text);
package/dist/index.js CHANGED
@@ -189,7 +189,7 @@ import {
189
189
  canAdminSandbox,
190
190
  parseInsufficientBalance,
191
191
  useSidebar
192
- } from "./chunk-76TCOY2R.js";
192
+ } from "./chunk-LDETDX7W.js";
193
193
  import {
194
194
  BillingDashboard,
195
195
  InfoPanel,
package/dist/pages.js CHANGED
@@ -15,6 +15,11 @@ import {
15
15
  DialogHeader,
16
16
  DialogTitle,
17
17
  Input,
18
+ Select,
19
+ SelectContent,
20
+ SelectItem,
21
+ SelectTrigger,
22
+ SelectValue,
18
23
  Switch,
19
24
  Textarea
20
25
  } from "./chunk-7ZA5SEK3.js";
@@ -478,7 +483,9 @@ import {
478
483
  Settings,
479
484
  Plus,
480
485
  Trash2,
481
- Check
486
+ Check,
487
+ Eye,
488
+ EyeOff
482
489
  } from "lucide-react";
483
490
 
484
491
  // src/pages/add-ssh-key-dialog.tsx
@@ -893,6 +900,37 @@ function SshAccessStep({ config }) {
893
900
  )
894
901
  ] });
895
902
  }
903
+ function EnvVarValueInput({
904
+ value,
905
+ onChange,
906
+ placeholder
907
+ }) {
908
+ const [revealed, setRevealed] = React3.useState(false);
909
+ return /* @__PURE__ */ jsxs4("div", { className: "relative flex-[2]", children: [
910
+ /* @__PURE__ */ jsx4(
911
+ Input,
912
+ {
913
+ type: revealed ? "text" : "password",
914
+ value,
915
+ onChange: (e) => onChange(e.target.value),
916
+ autoComplete: "off",
917
+ className: "h-9 px-3 pr-10 font-mono text-sm",
918
+ placeholder
919
+ }
920
+ ),
921
+ /* @__PURE__ */ jsx4(
922
+ "button",
923
+ {
924
+ type: "button",
925
+ onClick: () => setRevealed((s) => !s),
926
+ "aria-label": revealed ? "Hide value" : "Show value",
927
+ "aria-pressed": revealed,
928
+ className: "absolute right-2 top-1/2 -translate-y-1/2 rounded p-1 text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
929
+ children: revealed ? /* @__PURE__ */ jsx4(EyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx4(Eye, { className: "h-4 w-4" })
930
+ }
931
+ )
932
+ ] });
933
+ }
896
934
  function ProvisioningWizard({
897
935
  environments: environmentsProp,
898
936
  onLoadEnvironments,
@@ -907,17 +945,11 @@ function ProvisioningWizard({
907
945
  pricingRates,
908
946
  planTiers
909
947
  }) {
910
- const cpuMax = Math.max(
911
- CPU_MIN,
912
- Math.min(resourceLimits?.cpuMax ?? CPU_MAX, CPU_MAX)
913
- );
914
- const ramMax = Math.max(
915
- RAM_MIN,
916
- Math.min(resourceLimits?.ramMaxGB ?? RAM_MAX, RAM_MAX)
917
- );
948
+ const cpuMax = Math.max(CPU_MIN, resourceLimits?.cpuMax ?? CPU_MAX);
949
+ const ramMax = Math.max(RAM_MIN, resourceLimits?.ramMaxGB ?? RAM_MAX);
918
950
  const storageMax = Math.max(
919
951
  STORAGE_MIN,
920
- Math.min(resourceLimits?.storageMaxGB ?? STORAGE_MAX, STORAGE_MAX)
952
+ resourceLimits?.storageMaxGB ?? STORAGE_MAX
921
953
  );
922
954
  const cpuStep = alignSliderStep(CPU_MIN, cpuMax, CPU_STEP);
923
955
  const ramStep = alignSliderStep(RAM_MIN, ramMax, RAM_STEP);
@@ -958,6 +990,7 @@ function ProvisioningWizard({
958
990
  };
959
991
  }, [environmentsProp]);
960
992
  const environments = envList;
993
+ const showEnvironmentSection = isLoadingEnvironments || environments.length !== 1;
961
994
  const effectiveDefault = dc?.environment ?? defaultEnvironment;
962
995
  const [selectedEnv, setSelectedEnv] = React3.useState(
963
996
  effectiveDefault ?? environments[0]?.id ?? ""
@@ -991,7 +1024,17 @@ function ProvisioningWizard({
991
1024
  }, [cpuMax, ramMax, storageMax, cpuStep, ramStep, storageStep]);
992
1025
  const [name, setName] = React3.useState(dc?.name ?? "");
993
1026
  const [gitUrl, setGitUrl] = React3.useState(dc?.gitUrl ?? "");
994
- const [envVars, setEnvVars] = React3.useState(dc?.envVars ?? [{ key: "", value: "" }]);
1027
+ const envVarUidRef = React3.useRef(0);
1028
+ const makeEnvVarRow = (key = "", value = "") => ({
1029
+ uid: `env-${envVarUidRef.current++}`,
1030
+ key,
1031
+ value
1032
+ });
1033
+ const [envVars, setEnvVars] = React3.useState(
1034
+ () => (dc?.envVars ?? [{ key: "", value: "" }]).map(
1035
+ (e) => makeEnvVarRow(e.key, e.value)
1036
+ )
1037
+ );
995
1038
  const [driver, setDriver] = React3.useState(dc?.driver ?? "docker");
996
1039
  const [bare, setBare] = React3.useState(dc?.bare ?? false);
997
1040
  const [startupScriptIds, setStartupScriptIds] = React3.useState(
@@ -1037,7 +1080,7 @@ function ProvisioningWizard({
1037
1080
  storageGB,
1038
1081
  name,
1039
1082
  gitUrl,
1040
- envVars: envVars.filter((e) => e.key.trim() !== ""),
1083
+ envVars: envVars.filter((e) => e.key.trim() !== "").map(({ key, value }) => ({ key, value })),
1041
1084
  driver,
1042
1085
  bare,
1043
1086
  startupScriptIds: startupScriptIds.filter(
@@ -1137,11 +1180,12 @@ function ProvisioningWizard({
1137
1180
  /* @__PURE__ */ jsx4("p", { className: "text-sm font-medium text-destructive", children: loadError })
1138
1181
  ] }),
1139
1182
  /* @__PURE__ */ jsxs4("div", { className: "flex-1 overflow-y-auto min-h-0 space-y-4", children: [
1140
- /* @__PURE__ */ jsxs4("section", { className: SECTION_CARD_CLASS, children: [
1183
+ showEnvironmentSection && /* @__PURE__ */ jsxs4("section", { className: SECTION_CARD_CLASS, children: [
1141
1184
  /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 mb-4", children: [
1142
1185
  /* @__PURE__ */ jsx4(Layers, { className: "h-4 w-4 text-primary shrink-0" }),
1143
1186
  /* @__PURE__ */ jsx4("h2", { className: "text-sm font-semibold uppercase tracking-[0.06em] text-muted-foreground", children: "Environment Selection" })
1144
1187
  ] }),
1188
+ !isLoadingEnvironments && environments.length === 0 && /* @__PURE__ */ jsx4("p", { className: "text-sm text-muted-foreground", children: "No environments are available to select right now. Refresh to try again." }),
1145
1189
  /* @__PURE__ */ jsx4("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-3", children: isLoadingEnvironments && environments.length === 0 ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsxs4(
1146
1190
  "div",
1147
1191
  {
@@ -1333,27 +1377,22 @@ function ProvisioningWizard({
1333
1377
  /* @__PURE__ */ jsxs4("div", { children: [
1334
1378
  /* @__PURE__ */ jsx4("label", { className: cn(FIELD_LABEL_CLASS, "mb-1.5"), children: "Virtualization Driver" }),
1335
1379
  /* @__PURE__ */ jsxs4(
1336
- "select",
1380
+ Select,
1337
1381
  {
1338
1382
  value: driver,
1339
- onChange: (e) => {
1340
- if (VALID_DRIVERS.has(e.target.value))
1383
+ onValueChange: (value) => {
1384
+ if (VALID_DRIVERS.has(value))
1341
1385
  setDriver(
1342
- e.target.value
1386
+ value
1343
1387
  );
1344
1388
  },
1345
- className: "w-full bg-card border border-border rounded-lg h-9 px-3 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:border-transparent appearance-none",
1346
1389
  children: [
1347
- /* @__PURE__ */ jsx4("option", { value: "docker", className: "bg-gray-900", children: "Docker container (Default)" }),
1348
- /* @__PURE__ */ jsx4(
1349
- "option",
1350
- {
1351
- value: "firecracker",
1352
- className: "bg-gray-900",
1353
- children: "Firecracker microVM (Secure)"
1354
- }
1355
- ),
1356
- /* @__PURE__ */ jsx4("option", { value: "tangle", className: "bg-gray-900", children: "Tangle Distributed Node" })
1390
+ /* @__PURE__ */ jsx4(SelectTrigger, { className: "h-9", children: /* @__PURE__ */ jsx4(SelectValue, {}) }),
1391
+ /* @__PURE__ */ jsxs4(SelectContent, { children: [
1392
+ /* @__PURE__ */ jsx4(SelectItem, { value: "docker", children: "Docker container (Default)" }),
1393
+ /* @__PURE__ */ jsx4(SelectItem, { value: "firecracker", children: "Firecracker microVM (Secure)" }),
1394
+ /* @__PURE__ */ jsx4(SelectItem, { value: "tangle", children: "Tangle Distributed Node" })
1395
+ ] })
1357
1396
  ]
1358
1397
  }
1359
1398
  )
@@ -1379,10 +1418,7 @@ function ProvisioningWizard({
1379
1418
  "button",
1380
1419
  {
1381
1420
  type: "button",
1382
- onClick: () => setEnvVars([
1383
- ...envVars,
1384
- { key: "", value: "" }
1385
- ]),
1421
+ onClick: () => setEnvVars([...envVars, makeEnvVarRow()]),
1386
1422
  className: "flex items-center gap-1 text-xs text-primary hover:text-primary/70 transition-colors font-medium",
1387
1423
  children: [
1388
1424
  /* @__PURE__ */ jsx4(Plus, { className: "h-3 w-3" }),
@@ -1392,7 +1428,7 @@ function ProvisioningWizard({
1392
1428
  )
1393
1429
  ] }),
1394
1430
  /* @__PURE__ */ jsxs4("div", { className: "space-y-2", children: [
1395
- envVars.map((env, i) => /* @__PURE__ */ jsxs4("div", { className: "flex gap-2", children: [
1431
+ envVars.map((env) => /* @__PURE__ */ jsxs4("div", { className: "flex gap-2", children: [
1396
1432
  /* @__PURE__ */ jsx4(
1397
1433
  Input,
1398
1434
  {
@@ -1400,7 +1436,7 @@ function ProvisioningWizard({
1400
1436
  value: env.key,
1401
1437
  onChange: (e) => setEnvVars(
1402
1438
  envVars.map(
1403
- (v, idx) => idx === i ? { ...v, key: e.target.value } : v
1439
+ (v) => v.uid === env.uid ? { ...v, key: e.target.value } : v
1404
1440
  )
1405
1441
  ),
1406
1442
  className: "flex-1 h-9 px-3 font-mono text-sm",
@@ -1408,16 +1444,14 @@ function ProvisioningWizard({
1408
1444
  }
1409
1445
  ),
1410
1446
  /* @__PURE__ */ jsx4(
1411
- Input,
1447
+ EnvVarValueInput,
1412
1448
  {
1413
- type: "password",
1414
1449
  value: env.value,
1415
- onChange: (e) => setEnvVars(
1450
+ onChange: (value) => setEnvVars(
1416
1451
  envVars.map(
1417
- (v, idx) => idx === i ? { ...v, value: e.target.value } : v
1452
+ (v) => v.uid === env.uid ? { ...v, value } : v
1418
1453
  )
1419
1454
  ),
1420
- className: "flex-[2] h-9 px-3 font-mono text-sm",
1421
1455
  placeholder: "sk-xxxxxxxxxxx"
1422
1456
  }
1423
1457
  ),
@@ -1427,14 +1461,15 @@ function ProvisioningWizard({
1427
1461
  type: "button",
1428
1462
  variant: "outline",
1429
1463
  size: "icon",
1464
+ "aria-label": "Remove variable",
1430
1465
  onClick: () => setEnvVars(
1431
- envVars.filter((_, idx) => idx !== i)
1466
+ envVars.filter((v) => v.uid !== env.uid)
1432
1467
  ),
1433
1468
  className: "h-9 w-9 shrink-0 text-destructive hover:bg-destructive/10 hover:border-destructive/30",
1434
1469
  children: /* @__PURE__ */ jsx4(Trash2, { className: "h-4 w-4" })
1435
1470
  }
1436
1471
  )
1437
- ] }, i)),
1472
+ ] }, env.uid)),
1438
1473
  envVars.length === 0 && /* @__PURE__ */ jsx4("div", { className: "text-center p-3 border border-dashed border-border rounded-lg text-muted-foreground/60 text-xs italic", children: "No environment variables set" })
1439
1474
  ] })
1440
1475
  ] }),
@@ -1527,16 +1562,10 @@ function ProvisioningWizard({
1527
1562
  className: "mt-0.5"
1528
1563
  }
1529
1564
  )
1530
- ] })
1565
+ ] }),
1566
+ sshAccess && /* @__PURE__ */ jsx4("div", { className: "pt-3 border-t border-border", children: /* @__PURE__ */ jsx4(SshAccessStep, { config: sshAccess }) })
1531
1567
  ] })
1532
- ] }) }),
1533
- sshAccess && /* @__PURE__ */ jsxs4("section", { className: SECTION_CARD_CLASS, children: [
1534
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 mb-4", children: [
1535
- /* @__PURE__ */ jsx4(Settings, { className: "h-4 w-4 text-primary shrink-0" }),
1536
- /* @__PURE__ */ jsx4("h2", { className: "text-sm font-semibold uppercase tracking-[0.06em] text-muted-foreground", children: "Access Configuration" })
1537
- ] }),
1538
- /* @__PURE__ */ jsx4(SshAccessStep, { config: sshAccess })
1539
- ] })
1568
+ ] }) })
1540
1569
  ] })
1541
1570
  ] }),
1542
1571
  /* @__PURE__ */ jsxs4("div", { className: "col-span-12 xl:col-span-4 sticky top-4 space-y-4", children: [
@@ -2448,7 +2477,7 @@ function ProfileDetailDialog({
2448
2477
 
2449
2478
  // src/pages/secrets-page.tsx
2450
2479
  import * as React6 from "react";
2451
- import { Lock, Plus as Plus3, Trash2 as Trash23, Eye, EyeOff, AlertCircle as AlertCircle2, Key, Shield, CheckCircle, Users, ArrowRight, Upload } from "lucide-react";
2480
+ import { Lock, Plus as Plus3, Trash2 as Trash23, Eye as Eye2, EyeOff as EyeOff2, AlertCircle as AlertCircle2, Key, Shield, CheckCircle, Users, ArrowRight, Upload } from "lucide-react";
2452
2481
  import {
2453
2482
  Dialog as Dialog3,
2454
2483
  DialogContent as DialogContent3,
@@ -2838,7 +2867,7 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
2838
2867
  onClick: () => setShowValue(!showValue),
2839
2868
  className: "absolute right-2 top-1/2 -translate-y-1/2 p-1 text-muted-foreground hover:text-foreground",
2840
2869
  "aria-label": showValue ? "Hide value" : "Show value",
2841
- children: showValue ? /* @__PURE__ */ jsx7(EyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx7(Eye, { className: "h-4 w-4" })
2870
+ children: showValue ? /* @__PURE__ */ jsx7(EyeOff2, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx7(Eye2, { className: "h-4 w-4" })
2842
2871
  }
2843
2872
  )
2844
2873
  ] }),
@@ -2977,7 +3006,7 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
2977
3006
  onClick: () => setShowImportValues((s) => !s),
2978
3007
  className: "inline-flex items-center gap-1 text-xs font-semibold text-muted-foreground hover:text-foreground",
2979
3008
  children: [
2980
- showImportValues ? /* @__PURE__ */ jsx7(EyeOff, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx7(Eye, { className: "h-3.5 w-3.5" }),
3009
+ showImportValues ? /* @__PURE__ */ jsx7(EyeOff2, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx7(Eye2, { className: "h-3.5 w-3.5" }),
2981
3010
  showImportValues ? "Hide values" : "Show values"
2982
3011
  ]
2983
3012
  }
package/dist/styles.css CHANGED
@@ -30,7 +30,6 @@
30
30
  --color-violet-300: oklch(81.1% 0.111 293.571);
31
31
  --color-violet-400: oklch(70.2% 0.183 293.541);
32
32
  --color-violet-500: oklch(60.6% 0.25 292.717);
33
- --color-gray-900: oklch(21% 0.034 264.665);
34
33
  --color-zinc-400: oklch(70.5% 0.015 286.067);
35
34
  --color-neutral-400: oklch(70.8% 0 0);
36
35
  --color-neutral-500: oklch(55.6% 0 0);
@@ -2022,9 +2021,6 @@
2022
2021
  background-color: color-mix(in oklab, var(--color-emerald-500) 10%, transparent);
2023
2022
  }
2024
2023
  }
2025
- .bg-gray-900 {
2026
- background-color: var(--color-gray-900);
2027
- }
2028
2024
  .bg-green-400 {
2029
2025
  background-color: var(--color-green-400);
2030
2026
  }
@@ -3428,11 +3424,6 @@
3428
3424
  border-color: var(--border-accent-hover);
3429
3425
  }
3430
3426
  }
3431
- .focus\:border-transparent {
3432
- &:focus {
3433
- border-color: transparent;
3434
- }
3435
- }
3436
3427
  .focus\:text-\[var\(--surface-danger-text\)\] {
3437
3428
  &:focus {
3438
3429
  color: var(--surface-danger-text);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-ui",
3
- "version": "0.24.2",
3
+ "version": "0.26.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",