@tangle-network/sandbox-ui 0.24.0 → 0.24.2
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 +12 -10
- package/dist/pages.d.ts +34 -5
- package/dist/pages.js +1307 -840
- package/dist/styles.css +12 -10
- package/package.json +1 -1
package/dist/pages.js
CHANGED
|
@@ -8,6 +8,12 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
Badge,
|
|
10
10
|
Button,
|
|
11
|
+
Dialog,
|
|
12
|
+
DialogContent,
|
|
13
|
+
DialogDescription,
|
|
14
|
+
DialogFooter,
|
|
15
|
+
DialogHeader,
|
|
16
|
+
DialogTitle,
|
|
11
17
|
Input,
|
|
12
18
|
Switch,
|
|
13
19
|
Textarea
|
|
@@ -50,6 +56,7 @@ function AuthPage({
|
|
|
50
56
|
providers = ["github", "google"],
|
|
51
57
|
socialHref = (p) => `/api/auth/sign-in/social?provider=${p}&callbackURL=/app`,
|
|
52
58
|
onEmailSubmit,
|
|
59
|
+
collectName,
|
|
53
60
|
altHref,
|
|
54
61
|
accent = "#0f172a",
|
|
55
62
|
accentHover = "#1e293b",
|
|
@@ -58,11 +65,13 @@ function AuthPage({
|
|
|
58
65
|
style,
|
|
59
66
|
children
|
|
60
67
|
}) {
|
|
68
|
+
const [name, setName] = useState("");
|
|
61
69
|
const [email, setEmail] = useState("");
|
|
62
70
|
const [password, setPassword] = useState("");
|
|
63
71
|
const [error, setError] = useState("");
|
|
64
72
|
const [loading, setLoading] = useState(false);
|
|
65
73
|
const isSignup = mode === "signup";
|
|
74
|
+
const showName = collectName ?? isSignup;
|
|
66
75
|
const tangleLabel = isSignup ? "Sign up with Tangle" : "Continue with Tangle";
|
|
67
76
|
const emailLabel = isSignup ? "Create account with email" : "Sign in with email";
|
|
68
77
|
const handleSubmit = async (e) => {
|
|
@@ -71,7 +80,7 @@ function AuthPage({
|
|
|
71
80
|
setLoading(true);
|
|
72
81
|
setError("");
|
|
73
82
|
try {
|
|
74
|
-
const err = await onEmailSubmit(email, password);
|
|
83
|
+
const err = await onEmailSubmit(email, password, name);
|
|
75
84
|
if (err) setError(err);
|
|
76
85
|
} catch {
|
|
77
86
|
setError("Connection error \u2014 please try again");
|
|
@@ -181,6 +190,7 @@ function AuthPage({
|
|
|
181
190
|
/* @__PURE__ */ jsx("div", { style: { flex: 1, height: 1, background: C.border } })
|
|
182
191
|
] }),
|
|
183
192
|
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, style: { display: "flex", flexDirection: "column", gap: 12 }, children: [
|
|
193
|
+
showName && /* @__PURE__ */ jsx("input", { type: "text", required: true, "aria-label": "Name", placeholder: "Name", autoComplete: "name", value: name, onChange: (e) => setName(e.target.value), style: inputStyle }),
|
|
184
194
|
/* @__PURE__ */ jsx("input", { type: "email", required: true, "aria-label": "Email", placeholder: "Email", value: email, onChange: (e) => setEmail(e.target.value), style: inputStyle }),
|
|
185
195
|
/* @__PURE__ */ jsx("input", { type: "password", required: true, "aria-label": "Password", placeholder: "Password", value: password, onChange: (e) => setPassword(e.target.value), style: inputStyle }),
|
|
186
196
|
error && /* @__PURE__ */ jsx("p", { role: "alert", style: { fontSize: 14, color: "#b91c1c" }, children: error }),
|
|
@@ -458,19 +468,177 @@ function BillingPage({
|
|
|
458
468
|
}
|
|
459
469
|
|
|
460
470
|
// src/pages/provisioning-wizard.tsx
|
|
461
|
-
import * as
|
|
471
|
+
import * as React3 from "react";
|
|
462
472
|
import {
|
|
463
473
|
ArrowLeft,
|
|
464
474
|
Layers,
|
|
465
475
|
Cpu,
|
|
466
476
|
Info,
|
|
467
|
-
Loader2,
|
|
477
|
+
Loader2 as Loader22,
|
|
468
478
|
Settings,
|
|
469
479
|
Plus,
|
|
470
480
|
Trash2,
|
|
471
481
|
Check
|
|
472
482
|
} from "lucide-react";
|
|
473
|
-
|
|
483
|
+
|
|
484
|
+
// src/pages/add-ssh-key-dialog.tsx
|
|
485
|
+
import * as React2 from "react";
|
|
486
|
+
import { Loader2 } from "lucide-react";
|
|
487
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
488
|
+
var NAME_INPUT_ID = "add-ssh-key-name";
|
|
489
|
+
var KEY_INPUT_ID = "add-ssh-key-public-key";
|
|
490
|
+
var SSH_PUBLIC_KEY_PATTERN = /^(ssh-rsa|ssh-dss|ssh-ed25519|ecdsa-sha2-nistp256|ecdsa-sha2-nistp384|ecdsa-sha2-nistp521|sk-ecdsa-sha2-nistp256@openssh\.com|sk-ssh-ed25519@openssh\.com)\s+[A-Za-z0-9+/]+={0,3}(\s+.+)?$/;
|
|
491
|
+
function validateSshPublicKey(value) {
|
|
492
|
+
const trimmed = value.trim();
|
|
493
|
+
if (!trimmed) return "Public key is required";
|
|
494
|
+
if (!SSH_PUBLIC_KEY_PATTERN.test(trimmed))
|
|
495
|
+
return "Enter a valid public key, e.g. ssh-ed25519 AAAAC3NzaC1lZDI1NTE5...";
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
function AddSshKeyDialog({
|
|
499
|
+
open,
|
|
500
|
+
onOpenChange,
|
|
501
|
+
onCreateKey,
|
|
502
|
+
onRefreshKeys,
|
|
503
|
+
onCreatedKeyId
|
|
504
|
+
}) {
|
|
505
|
+
const [name, setName] = React2.useState("");
|
|
506
|
+
const [publicKey, setPublicKey] = React2.useState("");
|
|
507
|
+
const [errors, setErrors] = React2.useState({
|
|
508
|
+
name: null,
|
|
509
|
+
publicKey: null
|
|
510
|
+
});
|
|
511
|
+
const [submitError, setSubmitError] = React2.useState(null);
|
|
512
|
+
const [isSaving, setIsSaving] = React2.useState(false);
|
|
513
|
+
const resetForm = React2.useCallback(() => {
|
|
514
|
+
setName("");
|
|
515
|
+
setPublicKey("");
|
|
516
|
+
setErrors({ name: null, publicKey: null });
|
|
517
|
+
setSubmitError(null);
|
|
518
|
+
}, []);
|
|
519
|
+
const handleSave = async () => {
|
|
520
|
+
const nameError = name.trim() ? null : "Name is required";
|
|
521
|
+
const keyError = validateSshPublicKey(publicKey);
|
|
522
|
+
if (nameError || keyError) {
|
|
523
|
+
setErrors({ name: nameError, publicKey: keyError });
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
setIsSaving(true);
|
|
527
|
+
setSubmitError(null);
|
|
528
|
+
try {
|
|
529
|
+
const created = await onCreateKey({
|
|
530
|
+
name: name.trim(),
|
|
531
|
+
publicKey: publicKey.trim()
|
|
532
|
+
});
|
|
533
|
+
if (onRefreshKeys) {
|
|
534
|
+
await onRefreshKeys();
|
|
535
|
+
}
|
|
536
|
+
if (created && created.id) {
|
|
537
|
+
onCreatedKeyId?.(created.id);
|
|
538
|
+
}
|
|
539
|
+
resetForm();
|
|
540
|
+
onOpenChange(false);
|
|
541
|
+
} catch (err) {
|
|
542
|
+
setSubmitError(
|
|
543
|
+
err instanceof Error ? err.message : "Failed to add SSH key"
|
|
544
|
+
);
|
|
545
|
+
} finally {
|
|
546
|
+
setIsSaving(false);
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
const handleSubmit = (e) => {
|
|
550
|
+
e.preventDefault();
|
|
551
|
+
if (!isSaving) handleSave();
|
|
552
|
+
};
|
|
553
|
+
return /* @__PURE__ */ jsx3(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs3(DialogContent, { className: "max-w-md", children: [
|
|
554
|
+
/* @__PURE__ */ jsxs3(DialogHeader, { children: [
|
|
555
|
+
/* @__PURE__ */ jsx3(DialogTitle, { children: "Add SSH key" }),
|
|
556
|
+
/* @__PURE__ */ jsx3(DialogDescription, { children: "Save a public key to your account. It will be available to select for this and future sandboxes." })
|
|
557
|
+
] }),
|
|
558
|
+
/* @__PURE__ */ jsxs3("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
559
|
+
/* @__PURE__ */ jsxs3("div", { className: "space-y-1.5", children: [
|
|
560
|
+
/* @__PURE__ */ jsx3(
|
|
561
|
+
"label",
|
|
562
|
+
{
|
|
563
|
+
htmlFor: NAME_INPUT_ID,
|
|
564
|
+
className: "block text-xs font-medium uppercase tracking-[0.06em] text-muted-foreground",
|
|
565
|
+
children: "Name"
|
|
566
|
+
}
|
|
567
|
+
),
|
|
568
|
+
/* @__PURE__ */ jsx3(
|
|
569
|
+
"input",
|
|
570
|
+
{
|
|
571
|
+
id: NAME_INPUT_ID,
|
|
572
|
+
name: "name",
|
|
573
|
+
type: "text",
|
|
574
|
+
value: name,
|
|
575
|
+
onChange: (e) => setName(e.target.value),
|
|
576
|
+
placeholder: "My laptop",
|
|
577
|
+
autoComplete: "off",
|
|
578
|
+
"aria-invalid": errors.name ? true : void 0,
|
|
579
|
+
className: "w-full rounded-md border border-border bg-card px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
|
580
|
+
}
|
|
581
|
+
),
|
|
582
|
+
errors.name && /* @__PURE__ */ jsx3("p", { className: "text-xs text-destructive", children: errors.name })
|
|
583
|
+
] }),
|
|
584
|
+
/* @__PURE__ */ jsxs3("div", { className: "space-y-1.5", children: [
|
|
585
|
+
/* @__PURE__ */ jsx3(
|
|
586
|
+
"label",
|
|
587
|
+
{
|
|
588
|
+
htmlFor: KEY_INPUT_ID,
|
|
589
|
+
className: "block text-xs font-medium uppercase tracking-[0.06em] text-muted-foreground",
|
|
590
|
+
children: "Public key"
|
|
591
|
+
}
|
|
592
|
+
),
|
|
593
|
+
/* @__PURE__ */ jsx3(
|
|
594
|
+
"textarea",
|
|
595
|
+
{
|
|
596
|
+
id: KEY_INPUT_ID,
|
|
597
|
+
name: "public-key",
|
|
598
|
+
value: publicKey,
|
|
599
|
+
onChange: (e) => setPublicKey(e.target.value),
|
|
600
|
+
placeholder: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...",
|
|
601
|
+
autoComplete: "off",
|
|
602
|
+
spellCheck: false,
|
|
603
|
+
"aria-invalid": errors.publicKey ? true : void 0,
|
|
604
|
+
className: "min-h-24 w-full resize-y rounded-md border border-border bg-card px-3 py-2 font-mono text-xs text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
|
605
|
+
}
|
|
606
|
+
),
|
|
607
|
+
errors.publicKey && /* @__PURE__ */ jsx3("p", { className: "text-xs text-destructive", children: errors.publicKey })
|
|
608
|
+
] }),
|
|
609
|
+
submitError && /* @__PURE__ */ jsx3("p", { role: "alert", className: "text-sm text-destructive", children: submitError }),
|
|
610
|
+
/* @__PURE__ */ jsx3("button", { type: "submit", className: "hidden", tabIndex: -1, "aria-hidden": "true", children: "Submit" })
|
|
611
|
+
] }),
|
|
612
|
+
/* @__PURE__ */ jsxs3(DialogFooter, { children: [
|
|
613
|
+
/* @__PURE__ */ jsx3(
|
|
614
|
+
"button",
|
|
615
|
+
{
|
|
616
|
+
type: "button",
|
|
617
|
+
onClick: () => onOpenChange(false),
|
|
618
|
+
disabled: isSaving,
|
|
619
|
+
className: "rounded-md border border-border bg-card px-4 py-2 text-sm font-medium text-foreground hover:bg-muted transition-colors disabled:opacity-50",
|
|
620
|
+
children: "Cancel"
|
|
621
|
+
}
|
|
622
|
+
),
|
|
623
|
+
/* @__PURE__ */ jsxs3(
|
|
624
|
+
"button",
|
|
625
|
+
{
|
|
626
|
+
type: "button",
|
|
627
|
+
onClick: handleSave,
|
|
628
|
+
disabled: isSaving,
|
|
629
|
+
className: "inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-bold text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50 active:scale-[0.97]",
|
|
630
|
+
children: [
|
|
631
|
+
isSaving && /* @__PURE__ */ jsx3(Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
632
|
+
isSaving ? "Saving..." : "Add key"
|
|
633
|
+
]
|
|
634
|
+
}
|
|
635
|
+
)
|
|
636
|
+
] })
|
|
637
|
+
] }) });
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// src/pages/provisioning-wizard.tsx
|
|
641
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
474
642
|
var VALID_DRIVERS = /* @__PURE__ */ new Set([
|
|
475
643
|
"docker",
|
|
476
644
|
"firecracker",
|
|
@@ -523,7 +691,7 @@ function resolveEnvironment(env) {
|
|
|
523
691
|
id: env.id,
|
|
524
692
|
name: templateName,
|
|
525
693
|
description: env.description ?? "User template from snapshot",
|
|
526
|
-
icon: /* @__PURE__ */
|
|
694
|
+
icon: /* @__PURE__ */ jsx4("span", { className: "text-[var(--surface-success-text)] text-2xl font-bold", children: "T" }),
|
|
527
695
|
color: "green"
|
|
528
696
|
};
|
|
529
697
|
}
|
|
@@ -536,7 +704,7 @@ function resolveEnvironment(env) {
|
|
|
536
704
|
id: env.id,
|
|
537
705
|
name,
|
|
538
706
|
description: env.description ?? `${name} development environment`,
|
|
539
|
-
icon: /* @__PURE__ */
|
|
707
|
+
icon: /* @__PURE__ */ jsx4("span", { className: `${textClass} text-2xl font-bold`, children: abbr }),
|
|
540
708
|
color
|
|
541
709
|
};
|
|
542
710
|
}
|
|
@@ -545,21 +713,21 @@ var defaultEnvironments = [
|
|
|
545
713
|
id: "node",
|
|
546
714
|
name: "Node.js",
|
|
547
715
|
description: "v20.x LTS with optimized runtime for asynchronous event-driven agents.",
|
|
548
|
-
icon: /* @__PURE__ */
|
|
716
|
+
icon: /* @__PURE__ */ jsx4("span", { className: "text-[var(--code-success)] text-2xl font-bold", children: "N" }),
|
|
549
717
|
color: "green"
|
|
550
718
|
},
|
|
551
719
|
{
|
|
552
720
|
id: "python",
|
|
553
721
|
name: "Python",
|
|
554
722
|
description: "v3.11 pre-installed with PyTorch and common data science libraries.",
|
|
555
|
-
icon: /* @__PURE__ */
|
|
723
|
+
icon: /* @__PURE__ */ jsx4("span", { className: "text-sky-400 text-2xl font-bold", children: "Py" }),
|
|
556
724
|
color: "blue"
|
|
557
725
|
},
|
|
558
726
|
{
|
|
559
727
|
id: "ubuntu",
|
|
560
728
|
name: "Ubuntu",
|
|
561
729
|
description: "Full 22.04 LTS terminal access for custom containerized workloads.",
|
|
562
|
-
icon: /* @__PURE__ */
|
|
730
|
+
icon: /* @__PURE__ */ jsx4("span", { className: "text-orange-400 text-2xl font-bold", children: "U" }),
|
|
563
731
|
color: "orange"
|
|
564
732
|
}
|
|
565
733
|
];
|
|
@@ -630,47 +798,79 @@ function computeHourlyCost(cpu, ram, storage, rates) {
|
|
|
630
798
|
}
|
|
631
799
|
function SshAccessStep({ config }) {
|
|
632
800
|
const keys = config.keys ?? [];
|
|
801
|
+
const canAddKey = typeof config.onCreateKey === "function";
|
|
802
|
+
const [isAddKeyOpen, setIsAddKeyOpen] = React3.useState(false);
|
|
633
803
|
const inlineKeyCount = config.inlinePublicKeys.split(/\r?\n/).map((key) => key.trim()).filter(Boolean).length;
|
|
634
804
|
const totalKeyCount = config.selectedKeyIds.length + inlineKeyCount;
|
|
635
|
-
return /* @__PURE__ */
|
|
636
|
-
/* @__PURE__ */
|
|
637
|
-
/* @__PURE__ */
|
|
638
|
-
/* @__PURE__ */
|
|
639
|
-
/* @__PURE__ */
|
|
805
|
+
return /* @__PURE__ */ jsxs4("div", { className: "space-y-4", children: [
|
|
806
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-start justify-between gap-4", children: [
|
|
807
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
808
|
+
/* @__PURE__ */ jsx4("p", { className: "font-medium text-foreground text-sm", children: "SSH Access" }),
|
|
809
|
+
/* @__PURE__ */ jsx4("p", { className: "mt-1 text-muted-foreground text-xs", children: "Select stored keys or paste public keys for authorized_keys." })
|
|
640
810
|
] }),
|
|
641
|
-
/* @__PURE__ */
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
811
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
|
|
812
|
+
canAddKey && /* @__PURE__ */ jsxs4(
|
|
813
|
+
Button,
|
|
814
|
+
{
|
|
815
|
+
type: "button",
|
|
816
|
+
variant: "outline",
|
|
817
|
+
size: "sm",
|
|
818
|
+
onClick: () => setIsAddKeyOpen(true),
|
|
819
|
+
children: [
|
|
820
|
+
/* @__PURE__ */ jsx4(Plus, { className: "h-3.5 w-3.5" }),
|
|
821
|
+
"Add SSH key"
|
|
822
|
+
]
|
|
823
|
+
}
|
|
824
|
+
),
|
|
825
|
+
/* @__PURE__ */ jsxs4(Badge, { variant: "outline", children: [
|
|
826
|
+
totalKeyCount,
|
|
827
|
+
" key",
|
|
828
|
+
totalKeyCount === 1 ? "" : "s"
|
|
829
|
+
] })
|
|
645
830
|
] })
|
|
646
831
|
] }),
|
|
647
|
-
keys.length > 0 && /* @__PURE__ */
|
|
832
|
+
keys.length > 0 && /* @__PURE__ */ jsx4("div", { className: "grid gap-2 sm:grid-cols-2", children: keys.map((key) => {
|
|
648
833
|
const selected = config.selectedKeyIds.includes(key.id);
|
|
649
|
-
return /* @__PURE__ */
|
|
650
|
-
|
|
834
|
+
return /* @__PURE__ */ jsx4(
|
|
835
|
+
"button",
|
|
651
836
|
{
|
|
652
837
|
type: "button",
|
|
653
|
-
variant: selected ? "sandbox" : "outline",
|
|
654
|
-
className: "h-auto justify-start p-3 text-left",
|
|
655
838
|
"aria-pressed": selected,
|
|
656
839
|
onClick: () => {
|
|
657
840
|
config.onSelectedKeyIdsChange(
|
|
658
841
|
selected ? config.selectedKeyIds.filter((id) => id !== key.id) : [...config.selectedKeyIds, key.id]
|
|
659
842
|
);
|
|
660
843
|
},
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
844
|
+
className: cn(
|
|
845
|
+
"group p-3 text-left rounded-lg border transition-colors duration-200",
|
|
846
|
+
selected ? "bg-primary/5 border-primary ring-1 ring-primary/20" : "bg-card border-border hover:border-primary/30 active:scale-[0.99]"
|
|
847
|
+
),
|
|
848
|
+
children: /* @__PURE__ */ jsxs4("div", { className: "flex items-start justify-between gap-2", children: [
|
|
849
|
+
/* @__PURE__ */ jsxs4("span", { className: "min-w-0", children: [
|
|
850
|
+
/* @__PURE__ */ jsx4("span", { className: "block font-medium text-sm text-foreground", children: key.name }),
|
|
851
|
+
/* @__PURE__ */ jsxs4("span", { className: "block truncate font-mono text-muted-foreground text-xs", children: [
|
|
852
|
+
key.keyType,
|
|
853
|
+
" \xB7 ",
|
|
854
|
+
key.fingerprint
|
|
855
|
+
] })
|
|
856
|
+
] }),
|
|
857
|
+
/* @__PURE__ */ jsx4(
|
|
858
|
+
"span",
|
|
859
|
+
{
|
|
860
|
+
"aria-hidden": "true",
|
|
861
|
+
className: cn(
|
|
862
|
+
"flex h-4 w-4 shrink-0 items-center justify-center rounded-[4px] border-2 transition-colors duration-200",
|
|
863
|
+
selected ? "border-primary bg-primary" : "border-border group-hover:border-primary/40"
|
|
864
|
+
),
|
|
865
|
+
children: selected && /* @__PURE__ */ jsx4(Check, { className: "h-2.5 w-2.5 text-primary-foreground" })
|
|
866
|
+
}
|
|
867
|
+
)
|
|
668
868
|
] })
|
|
669
869
|
},
|
|
670
870
|
key.id
|
|
671
871
|
);
|
|
672
872
|
}) }),
|
|
673
|
-
/* @__PURE__ */
|
|
873
|
+
/* @__PURE__ */ jsx4(
|
|
674
874
|
Textarea,
|
|
675
875
|
{
|
|
676
876
|
className: "min-h-24 font-mono text-xs",
|
|
@@ -678,6 +878,18 @@ function SshAccessStep({ config }) {
|
|
|
678
878
|
value: config.inlinePublicKeys,
|
|
679
879
|
onChange: (event) => config.onInlinePublicKeysChange(event.target.value)
|
|
680
880
|
}
|
|
881
|
+
),
|
|
882
|
+
canAddKey && /* @__PURE__ */ jsx4(
|
|
883
|
+
AddSshKeyDialog,
|
|
884
|
+
{
|
|
885
|
+
open: isAddKeyOpen,
|
|
886
|
+
onOpenChange: setIsAddKeyOpen,
|
|
887
|
+
onCreateKey: config.onCreateKey,
|
|
888
|
+
onRefreshKeys: config.onRefreshKeys,
|
|
889
|
+
onCreatedKeyId: (id) => config.onSelectedKeyIdsChange(
|
|
890
|
+
config.selectedKeyIds.includes(id) ? config.selectedKeyIds : [...config.selectedKeyIds, id]
|
|
891
|
+
)
|
|
892
|
+
}
|
|
681
893
|
)
|
|
682
894
|
] });
|
|
683
895
|
}
|
|
@@ -687,10 +899,8 @@ function ProvisioningWizard({
|
|
|
687
899
|
onSubmit,
|
|
688
900
|
onBack,
|
|
689
901
|
className,
|
|
690
|
-
variant = "flat",
|
|
691
902
|
defaultEnvironment,
|
|
692
903
|
defaultConfig,
|
|
693
|
-
skipToReview,
|
|
694
904
|
onLoadStartupScripts,
|
|
695
905
|
resourceLimits,
|
|
696
906
|
sshAccess,
|
|
@@ -713,17 +923,17 @@ function ProvisioningWizard({
|
|
|
713
923
|
const ramStep = alignSliderStep(RAM_MIN, ramMax, RAM_STEP);
|
|
714
924
|
const storageStep = alignSliderStep(STORAGE_MIN, storageMax, STORAGE_STEP);
|
|
715
925
|
const dc = defaultConfig;
|
|
716
|
-
const [envList, setEnvList] =
|
|
926
|
+
const [envList, setEnvList] = React3.useState(() => {
|
|
717
927
|
if (environmentsProp) return environmentsProp;
|
|
718
928
|
if (onLoadEnvironments) return [];
|
|
719
929
|
return defaultEnvironments;
|
|
720
930
|
});
|
|
721
|
-
const [isLoadingEnvironments, setIsLoadingEnvironments] =
|
|
931
|
+
const [isLoadingEnvironments, setIsLoadingEnvironments] = React3.useState(
|
|
722
932
|
() => !environmentsProp && !!onLoadEnvironments
|
|
723
933
|
);
|
|
724
|
-
const onLoadEnvironmentsRef =
|
|
934
|
+
const onLoadEnvironmentsRef = React3.useRef(onLoadEnvironments);
|
|
725
935
|
onLoadEnvironmentsRef.current = onLoadEnvironments;
|
|
726
|
-
|
|
936
|
+
React3.useEffect(() => {
|
|
727
937
|
let cancelled = false;
|
|
728
938
|
if (onLoadEnvironmentsRef.current) {
|
|
729
939
|
setIsLoadingEnvironments(true);
|
|
@@ -749,10 +959,10 @@ function ProvisioningWizard({
|
|
|
749
959
|
}, [environmentsProp]);
|
|
750
960
|
const environments = envList;
|
|
751
961
|
const effectiveDefault = dc?.environment ?? defaultEnvironment;
|
|
752
|
-
const [selectedEnv, setSelectedEnv] =
|
|
962
|
+
const [selectedEnv, setSelectedEnv] = React3.useState(
|
|
753
963
|
effectiveDefault ?? environments[0]?.id ?? ""
|
|
754
964
|
);
|
|
755
|
-
|
|
965
|
+
React3.useEffect(() => {
|
|
756
966
|
if (envList.length === 0) return;
|
|
757
967
|
if (effectiveDefault && envList.some((e) => e.id === effectiveDefault)) {
|
|
758
968
|
setSelectedEnv(effectiveDefault);
|
|
@@ -763,38 +973,38 @@ function ProvisioningWizard({
|
|
|
763
973
|
return envList[0]?.id ?? "";
|
|
764
974
|
});
|
|
765
975
|
}, [envList, effectiveDefault]);
|
|
766
|
-
const [cpuCores, setCpuCores] =
|
|
976
|
+
const [cpuCores, setCpuCores] = React3.useState(
|
|
767
977
|
snapSliderValue(dc?.cpuCores ?? 4, CPU_MIN, cpuMax, cpuStep)
|
|
768
978
|
);
|
|
769
|
-
const [ramGB, setRamGB] =
|
|
979
|
+
const [ramGB, setRamGB] = React3.useState(
|
|
770
980
|
snapSliderValue(dc?.ramGB ?? 16, RAM_MIN, ramMax, ramStep)
|
|
771
981
|
);
|
|
772
|
-
const [storageGB, setStorageGB] =
|
|
982
|
+
const [storageGB, setStorageGB] = React3.useState(
|
|
773
983
|
snapSliderValue(dc?.storageGB ?? 128, STORAGE_MIN, storageMax, storageStep)
|
|
774
984
|
);
|
|
775
|
-
|
|
985
|
+
React3.useEffect(() => {
|
|
776
986
|
setCpuCores((prev) => snapSliderValue(prev, CPU_MIN, cpuMax, cpuStep));
|
|
777
987
|
setRamGB((prev) => snapSliderValue(prev, RAM_MIN, ramMax, ramStep));
|
|
778
988
|
setStorageGB(
|
|
779
989
|
(prev) => snapSliderValue(prev, STORAGE_MIN, storageMax, storageStep)
|
|
780
990
|
);
|
|
781
991
|
}, [cpuMax, ramMax, storageMax, cpuStep, ramStep, storageStep]);
|
|
782
|
-
const [name, setName] =
|
|
783
|
-
const [gitUrl, setGitUrl] =
|
|
784
|
-
const [envVars, setEnvVars] =
|
|
785
|
-
const [driver, setDriver] =
|
|
786
|
-
const [bare, setBare] =
|
|
787
|
-
const [startupScriptIds, setStartupScriptIds] =
|
|
992
|
+
const [name, setName] = React3.useState(dc?.name ?? "");
|
|
993
|
+
const [gitUrl, setGitUrl] = React3.useState(dc?.gitUrl ?? "");
|
|
994
|
+
const [envVars, setEnvVars] = React3.useState(dc?.envVars ?? [{ key: "", value: "" }]);
|
|
995
|
+
const [driver, setDriver] = React3.useState(dc?.driver ?? "docker");
|
|
996
|
+
const [bare, setBare] = React3.useState(dc?.bare ?? false);
|
|
997
|
+
const [startupScriptIds, setStartupScriptIds] = React3.useState(
|
|
788
998
|
dc?.startupScriptIds ?? []
|
|
789
999
|
);
|
|
790
|
-
const [availableScripts, setAvailableScripts] =
|
|
791
|
-
const [activePreset, setActivePreset] =
|
|
792
|
-
const [pricingView, setPricingView] =
|
|
793
|
-
const [showAdvanced, setShowAdvanced] =
|
|
794
|
-
const [loadError, setLoadError] =
|
|
795
|
-
const onLoadStartupScriptsRef =
|
|
1000
|
+
const [availableScripts, setAvailableScripts] = React3.useState([]);
|
|
1001
|
+
const [activePreset, setActivePreset] = React3.useState(null);
|
|
1002
|
+
const [pricingView, setPricingView] = React3.useState("hourly");
|
|
1003
|
+
const [showAdvanced, setShowAdvanced] = React3.useState(false);
|
|
1004
|
+
const [loadError, setLoadError] = React3.useState(null);
|
|
1005
|
+
const onLoadStartupScriptsRef = React3.useRef(onLoadStartupScripts);
|
|
796
1006
|
onLoadStartupScriptsRef.current = onLoadStartupScripts;
|
|
797
|
-
|
|
1007
|
+
React3.useEffect(() => {
|
|
798
1008
|
let cancelled = false;
|
|
799
1009
|
if (onLoadStartupScriptsRef.current) {
|
|
800
1010
|
onLoadStartupScriptsRef.current().then((scripts) => {
|
|
@@ -810,14 +1020,8 @@ function ProvisioningWizard({
|
|
|
810
1020
|
cancelled = true;
|
|
811
1021
|
};
|
|
812
1022
|
}, []);
|
|
813
|
-
const
|
|
814
|
-
const
|
|
815
|
-
const finalStep = stepLabels.length;
|
|
816
|
-
const [currentStep, setCurrentStep] = React2.useState(
|
|
817
|
-
skipToReview && dc && isMultistep ? finalStep : 1
|
|
818
|
-
);
|
|
819
|
-
const [isDeploying, setIsDeploying] = React2.useState(false);
|
|
820
|
-
const [deployError, setDeployError] = React2.useState(null);
|
|
1023
|
+
const [isDeploying, setIsDeploying] = React3.useState(false);
|
|
1024
|
+
const [deployError, setDeployError] = React3.useState(null);
|
|
821
1025
|
const handleDeploy = async () => {
|
|
822
1026
|
if (!onSubmit) return;
|
|
823
1027
|
setIsDeploying(true);
|
|
@@ -868,9 +1072,9 @@ function ProvisioningWizard({
|
|
|
868
1072
|
unlockLabel: unlockLabel ?? "Pro"
|
|
869
1073
|
};
|
|
870
1074
|
});
|
|
871
|
-
const didInitPresetFromDcRef =
|
|
872
|
-
const lastLimitsRef =
|
|
873
|
-
|
|
1075
|
+
const didInitPresetFromDcRef = React3.useRef(false);
|
|
1076
|
+
const lastLimitsRef = React3.useRef(null);
|
|
1077
|
+
React3.useEffect(() => {
|
|
874
1078
|
const limitsUnchanged = lastLimitsRef.current !== null && lastLimitsRef.current.cpu === cpuMax && lastLimitsRef.current.ram === ramMax && lastLimitsRef.current.storage === storageMax;
|
|
875
1079
|
if (limitsUnchanged) return;
|
|
876
1080
|
lastLimitsRef.current = { cpu: cpuMax, ram: ramMax, storage: storageMax };
|
|
@@ -908,9 +1112,9 @@ function ProvisioningWizard({
|
|
|
908
1112
|
const pricingSuffix = pricingView === "hourly" ? "/ hour" : "/ sec";
|
|
909
1113
|
const rateSuffix = pricingView === "hourly" ? "/h" : "/s";
|
|
910
1114
|
const fmtRate = (v) => pricingView === "hourly" ? v.toFixed(2) : formatPerSecondValue(v);
|
|
911
|
-
return /* @__PURE__ */
|
|
912
|
-
/* @__PURE__ */
|
|
913
|
-
onBack && /* @__PURE__ */
|
|
1115
|
+
return /* @__PURE__ */ jsxs4("div", { className: cn("max-w-6xl mx-auto flex flex-col", className), children: [
|
|
1116
|
+
/* @__PURE__ */ jsxs4("div", { className: "mb-4 flex items-center gap-3 shrink-0", children: [
|
|
1117
|
+
onBack && /* @__PURE__ */ jsx4(
|
|
914
1118
|
Button,
|
|
915
1119
|
{
|
|
916
1120
|
type: "button",
|
|
@@ -918,109 +1122,43 @@ function ProvisioningWizard({
|
|
|
918
1122
|
size: "icon",
|
|
919
1123
|
onClick: onBack,
|
|
920
1124
|
className: "h-9 w-9 shrink-0",
|
|
921
|
-
children: /* @__PURE__ */
|
|
1125
|
+
children: /* @__PURE__ */ jsx4(ArrowLeft, { className: "h-4 w-4" })
|
|
922
1126
|
}
|
|
923
1127
|
),
|
|
924
|
-
/* @__PURE__ */
|
|
925
|
-
/* @__PURE__ */
|
|
926
|
-
/* @__PURE__ */
|
|
1128
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1129
|
+
/* @__PURE__ */ jsx4("h1", { className: "text-2xl font-semibold tracking-tight text-foreground", children: "Sandbox Provisioning" }),
|
|
1130
|
+
/* @__PURE__ */ jsx4("p", { className: "text-muted-foreground text-sm", children: "Select your stack, allocate resources, and deploy." })
|
|
927
1131
|
] })
|
|
928
1132
|
] }),
|
|
929
|
-
/* @__PURE__ */
|
|
930
|
-
/* @__PURE__ */
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
/* @__PURE__ */ jsx3(
|
|
935
|
-
"div",
|
|
936
|
-
{
|
|
937
|
-
className: cn(
|
|
938
|
-
"h-6 w-6 rounded-full flex items-center justify-center font-semibold text-xs shrink-0 transition-colors duration-200",
|
|
939
|
-
currentStep >= s ? "bg-primary text-primary-foreground" : "bg-muted border border-border text-muted-foreground"
|
|
940
|
-
),
|
|
941
|
-
children: currentStep > s ? /* @__PURE__ */ jsx3(Check, { className: "h-3 w-3" }) : s
|
|
942
|
-
}
|
|
943
|
-
),
|
|
944
|
-
/* @__PURE__ */ jsx3(
|
|
945
|
-
"span",
|
|
946
|
-
{
|
|
947
|
-
className: cn(
|
|
948
|
-
"ml-2 font-medium text-sm hidden sm:inline transition-colors duration-200",
|
|
949
|
-
currentStep === s ? "text-foreground" : currentStep > s ? "text-primary" : "text-muted-foreground"
|
|
950
|
-
),
|
|
951
|
-
children: label
|
|
952
|
-
}
|
|
953
|
-
),
|
|
954
|
-
s < finalStep && /* @__PURE__ */ jsx3(
|
|
955
|
-
"div",
|
|
956
|
-
{
|
|
957
|
-
className: cn(
|
|
958
|
-
"w-4 sm:w-8 h-px mx-2 sm:mx-3 transition-colors duration-300",
|
|
959
|
-
currentStep > s ? "bg-primary" : "bg-border"
|
|
960
|
-
)
|
|
961
|
-
}
|
|
962
|
-
)
|
|
963
|
-
] }, s);
|
|
964
|
-
}) }),
|
|
965
|
-
dc && isMultistep && /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between rounded-lg border border-border bg-card px-4 py-2.5 shadow-sm shrink-0 mb-4", children: [
|
|
966
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 text-sm", children: [
|
|
967
|
-
/* @__PURE__ */ jsx3(Info, { className: "h-4 w-4 text-primary shrink-0" }),
|
|
968
|
-
/* @__PURE__ */ jsx3("span", { className: "text-muted-foreground", children: "Pre-configured from template." })
|
|
969
|
-
] }),
|
|
970
|
-
/* @__PURE__ */ jsx3(
|
|
971
|
-
Button,
|
|
972
|
-
{
|
|
973
|
-
type: "button",
|
|
974
|
-
variant: "link",
|
|
975
|
-
onClick: () => {
|
|
976
|
-
setCurrentStep(1);
|
|
977
|
-
setSelectedEnv(environments[0]?.id ?? "");
|
|
978
|
-
setCpuCores(snapSliderValue(4, CPU_MIN, cpuMax, cpuStep));
|
|
979
|
-
setRamGB(snapSliderValue(16, RAM_MIN, ramMax, ramStep));
|
|
980
|
-
setStorageGB(
|
|
981
|
-
snapSliderValue(128, STORAGE_MIN, storageMax, storageStep)
|
|
982
|
-
);
|
|
983
|
-
setName("");
|
|
984
|
-
setGitUrl("");
|
|
985
|
-
setEnvVars([{ key: "", value: "" }]);
|
|
986
|
-
setDriver("docker");
|
|
987
|
-
setBare(false);
|
|
988
|
-
setStartupScriptIds([]);
|
|
989
|
-
setActivePreset(null);
|
|
990
|
-
setPricingView("hourly");
|
|
991
|
-
},
|
|
992
|
-
className: "h-auto p-0 text-xs",
|
|
993
|
-
children: "Start from scratch"
|
|
994
|
-
}
|
|
995
|
-
)
|
|
996
|
-
] }),
|
|
997
|
-
loadError && /* @__PURE__ */ jsxs3("div", { className: "rounded-lg border border-destructive/30 bg-destructive/10 p-3 flex items-center gap-2 shrink-0 mb-4", children: [
|
|
998
|
-
/* @__PURE__ */ jsx3(Info, { className: "h-4 w-4 text-destructive shrink-0" }),
|
|
999
|
-
/* @__PURE__ */ jsx3("p", { className: "text-sm font-medium text-destructive", children: loadError })
|
|
1133
|
+
/* @__PURE__ */ jsxs4("div", { className: "grid grid-cols-12 gap-5 flex-1 min-h-0", children: [
|
|
1134
|
+
/* @__PURE__ */ jsxs4("div", { className: "col-span-12 xl:col-span-8 flex flex-col min-h-0", children: [
|
|
1135
|
+
loadError && /* @__PURE__ */ jsxs4("div", { className: "rounded-lg border border-destructive/30 bg-destructive/10 p-3 flex items-center gap-2 shrink-0 mb-4", children: [
|
|
1136
|
+
/* @__PURE__ */ jsx4(Info, { className: "h-4 w-4 text-destructive shrink-0" }),
|
|
1137
|
+
/* @__PURE__ */ jsx4("p", { className: "text-sm font-medium text-destructive", children: loadError })
|
|
1000
1138
|
] }),
|
|
1001
|
-
/* @__PURE__ */
|
|
1002
|
-
|
|
1003
|
-
/* @__PURE__ */
|
|
1004
|
-
/* @__PURE__ */
|
|
1005
|
-
/* @__PURE__ */
|
|
1139
|
+
/* @__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: [
|
|
1141
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 mb-4", children: [
|
|
1142
|
+
/* @__PURE__ */ jsx4(Layers, { className: "h-4 w-4 text-primary shrink-0" }),
|
|
1143
|
+
/* @__PURE__ */ jsx4("h2", { className: "text-sm font-semibold uppercase tracking-[0.06em] text-muted-foreground", children: "Environment Selection" })
|
|
1006
1144
|
] }),
|
|
1007
|
-
/* @__PURE__ */
|
|
1145
|
+
/* @__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(
|
|
1008
1146
|
"div",
|
|
1009
1147
|
{
|
|
1010
1148
|
className: "p-3.5 rounded-lg border border-border bg-card/50 animate-pulse",
|
|
1011
1149
|
"aria-hidden": "true",
|
|
1012
1150
|
children: [
|
|
1013
|
-
/* @__PURE__ */
|
|
1014
|
-
/* @__PURE__ */
|
|
1015
|
-
/* @__PURE__ */
|
|
1151
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex justify-between items-start mb-2.5", children: [
|
|
1152
|
+
/* @__PURE__ */ jsx4("div", { className: "w-10 h-10 rounded-full bg-muted/60 border border-border" }),
|
|
1153
|
+
/* @__PURE__ */ jsx4("div", { className: "w-4 h-4 rounded-full border-2 border-border" })
|
|
1016
1154
|
] }),
|
|
1017
|
-
/* @__PURE__ */
|
|
1018
|
-
/* @__PURE__ */
|
|
1019
|
-
/* @__PURE__ */
|
|
1155
|
+
/* @__PURE__ */ jsx4("div", { className: "h-3 w-1/3 rounded bg-muted/60 mb-2" }),
|
|
1156
|
+
/* @__PURE__ */ jsx4("div", { className: "h-2.5 w-5/6 rounded bg-muted/50 mb-1.5" }),
|
|
1157
|
+
/* @__PURE__ */ jsx4("div", { className: "h-2.5 w-2/3 rounded bg-muted/50" })
|
|
1020
1158
|
]
|
|
1021
1159
|
},
|
|
1022
1160
|
`env-skeleton-${i}`
|
|
1023
|
-
)) : environments.map((env) => /* @__PURE__ */
|
|
1161
|
+
)) : environments.map((env) => /* @__PURE__ */ jsxs4(
|
|
1024
1162
|
"button",
|
|
1025
1163
|
{
|
|
1026
1164
|
type: "button",
|
|
@@ -1030,36 +1168,36 @@ function ProvisioningWizard({
|
|
|
1030
1168
|
selectedEnv === env.id ? "bg-primary/5 border-primary ring-1 ring-primary/20" : "bg-card border-border hover:border-primary/30 active:scale-[0.99]"
|
|
1031
1169
|
),
|
|
1032
1170
|
children: [
|
|
1033
|
-
/* @__PURE__ */
|
|
1034
|
-
/* @__PURE__ */
|
|
1035
|
-
/* @__PURE__ */
|
|
1171
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex justify-between items-start mb-2.5", children: [
|
|
1172
|
+
/* @__PURE__ */ jsx4("div", { className: "w-10 h-10 rounded-full flex items-center justify-center bg-muted/50 border border-border", children: env.icon }),
|
|
1173
|
+
/* @__PURE__ */ jsx4(
|
|
1036
1174
|
"div",
|
|
1037
1175
|
{
|
|
1038
1176
|
className: cn(
|
|
1039
1177
|
"w-4 h-4 rounded-full border-2 flex items-center justify-center transition-colors duration-200",
|
|
1040
1178
|
selectedEnv === env.id ? "border-primary bg-primary" : "border-border group-hover:border-primary/40"
|
|
1041
1179
|
),
|
|
1042
|
-
children: selectedEnv === env.id && /* @__PURE__ */
|
|
1180
|
+
children: selectedEnv === env.id && /* @__PURE__ */ jsx4(Check, { className: "h-2.5 w-2.5 text-primary-foreground" })
|
|
1043
1181
|
}
|
|
1044
1182
|
)
|
|
1045
1183
|
] }),
|
|
1046
|
-
/* @__PURE__ */
|
|
1047
|
-
/* @__PURE__ */
|
|
1184
|
+
/* @__PURE__ */ jsx4("h3", { className: "font-semibold text-sm mb-0.5 text-foreground", children: env.name }),
|
|
1185
|
+
/* @__PURE__ */ jsx4("p", { className: "text-xs text-muted-foreground leading-relaxed", children: env.description })
|
|
1048
1186
|
]
|
|
1049
1187
|
},
|
|
1050
1188
|
env.id
|
|
1051
1189
|
)) })
|
|
1052
|
-
] })
|
|
1053
|
-
|
|
1054
|
-
/* @__PURE__ */
|
|
1055
|
-
/* @__PURE__ */
|
|
1056
|
-
/* @__PURE__ */
|
|
1190
|
+
] }),
|
|
1191
|
+
/* @__PURE__ */ jsxs4("section", { className: SECTION_CARD_CLASS, children: [
|
|
1192
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 mb-4", children: [
|
|
1193
|
+
/* @__PURE__ */ jsx4(Cpu, { className: "h-4 w-4 text-primary shrink-0" }),
|
|
1194
|
+
/* @__PURE__ */ jsx4("h2", { className: "text-sm font-semibold uppercase tracking-[0.06em] text-muted-foreground", children: "Resource Allocation" })
|
|
1057
1195
|
] }),
|
|
1058
|
-
/* @__PURE__ */
|
|
1059
|
-
/* @__PURE__ */
|
|
1060
|
-
/* @__PURE__ */
|
|
1196
|
+
/* @__PURE__ */ jsxs4("div", { className: "mb-4", children: [
|
|
1197
|
+
/* @__PURE__ */ jsx4("label", { className: cn(FIELD_LABEL_CLASS, "mb-2"), children: "Compute Presets" }),
|
|
1198
|
+
/* @__PURE__ */ jsx4("div", { className: "grid grid-cols-3 gap-2", children: presets.map((p) => {
|
|
1061
1199
|
const active = activePreset === p.name && !p.locked;
|
|
1062
|
-
return /* @__PURE__ */
|
|
1200
|
+
return /* @__PURE__ */ jsxs4(
|
|
1063
1201
|
"button",
|
|
1064
1202
|
{
|
|
1065
1203
|
type: "button",
|
|
@@ -1070,8 +1208,8 @@ function ProvisioningWizard({
|
|
|
1070
1208
|
active ? "bg-primary/5 border-primary ring-1 ring-primary/20" : p.locked ? "bg-muted/30 border-border opacity-60 cursor-not-allowed" : "bg-card border-border hover:border-primary/30 active:scale-[0.99]"
|
|
1071
1209
|
),
|
|
1072
1210
|
children: [
|
|
1073
|
-
p.locked && /* @__PURE__ */
|
|
1074
|
-
/* @__PURE__ */
|
|
1211
|
+
p.locked && /* @__PURE__ */ jsx4("div", { className: "absolute -top-1.5 -right-1.5 bg-primary text-primary-foreground text-[9px] font-semibold px-1.5 py-0.5 rounded-full uppercase tracking-wider", children: p.unlockLabel }),
|
|
1212
|
+
/* @__PURE__ */ jsx4(
|
|
1075
1213
|
"div",
|
|
1076
1214
|
{
|
|
1077
1215
|
className: cn(
|
|
@@ -1081,7 +1219,7 @@ function ProvisioningWizard({
|
|
|
1081
1219
|
children: p.name
|
|
1082
1220
|
}
|
|
1083
1221
|
),
|
|
1084
|
-
/* @__PURE__ */
|
|
1222
|
+
/* @__PURE__ */ jsxs4("div", { className: "text-xs text-muted-foreground mt-0.5 font-mono", children: [
|
|
1085
1223
|
p.cpu,
|
|
1086
1224
|
" vCPU",
|
|
1087
1225
|
p.cpu === 1 ? "" : "s",
|
|
@@ -1098,7 +1236,7 @@ function ProvisioningWizard({
|
|
|
1098
1236
|
);
|
|
1099
1237
|
}) })
|
|
1100
1238
|
] }),
|
|
1101
|
-
/* @__PURE__ */
|
|
1239
|
+
/* @__PURE__ */ jsx4("div", { className: "space-y-4", children: [
|
|
1102
1240
|
{
|
|
1103
1241
|
label: "Compute Cores (CPU)",
|
|
1104
1242
|
value: cpuCores,
|
|
@@ -1129,12 +1267,12 @@ function ProvisioningWizard({
|
|
|
1129
1267
|
].map(
|
|
1130
1268
|
({ label, value, setter, min, max, step: s, unit }) => {
|
|
1131
1269
|
const displayUnit = unit === "vCPU" ? `${value} vCPU${value === 1 ? "" : "s"}` : `${value}${unit}`;
|
|
1132
|
-
return /* @__PURE__ */
|
|
1133
|
-
/* @__PURE__ */
|
|
1134
|
-
/* @__PURE__ */
|
|
1135
|
-
/* @__PURE__ */
|
|
1270
|
+
return /* @__PURE__ */ jsxs4("div", { children: [
|
|
1271
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex justify-between items-end pb-1 mb-1.5", children: [
|
|
1272
|
+
/* @__PURE__ */ jsx4("label", { className: FIELD_LABEL_CLASS, children: label }),
|
|
1273
|
+
/* @__PURE__ */ jsx4("span", { className: "text-sm font-semibold text-foreground tabular-nums", children: displayUnit })
|
|
1136
1274
|
] }),
|
|
1137
|
-
/* @__PURE__ */
|
|
1275
|
+
/* @__PURE__ */ jsx4(
|
|
1138
1276
|
"input",
|
|
1139
1277
|
{
|
|
1140
1278
|
type: "range",
|
|
@@ -1149,12 +1287,12 @@ function ProvisioningWizard({
|
|
|
1149
1287
|
className: "w-full h-1.5 rounded-full appearance-none cursor-pointer accent-primary [&::-webkit-slider-runnable-track]:bg-border [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:h-1.5 [&::-moz-range-track]:bg-border [&::-moz-range-track]:rounded-full [&::-moz-range-track]:h-1.5 [&::-webkit-slider-thumb]:bg-primary [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:-mt-[5px] [&::-webkit-slider-thumb]:shadow-sm [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-primary-foreground"
|
|
1150
1288
|
}
|
|
1151
1289
|
),
|
|
1152
|
-
/* @__PURE__ */
|
|
1153
|
-
/* @__PURE__ */
|
|
1290
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex justify-between text-[10px] font-mono text-muted-foreground/60 mt-1", children: [
|
|
1291
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
1154
1292
|
min,
|
|
1155
1293
|
unit === "vCPU" ? min === 1 ? " vCPU" : " vCPUs" : unit
|
|
1156
1294
|
] }),
|
|
1157
|
-
/* @__PURE__ */
|
|
1295
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
1158
1296
|
max,
|
|
1159
1297
|
unit === "vCPU" ? max === 1 ? " vCPU" : " vCPUs" : unit
|
|
1160
1298
|
] })
|
|
@@ -1162,25 +1300,25 @@ function ProvisioningWizard({
|
|
|
1162
1300
|
] }, label);
|
|
1163
1301
|
}
|
|
1164
1302
|
) })
|
|
1165
|
-
] })
|
|
1166
|
-
|
|
1167
|
-
/* @__PURE__ */
|
|
1303
|
+
] }),
|
|
1304
|
+
/* @__PURE__ */ jsx4("section", { className: SECTION_CARD_CLASS, children: /* @__PURE__ */ jsxs4("div", { children: [
|
|
1305
|
+
/* @__PURE__ */ jsxs4(
|
|
1168
1306
|
"button",
|
|
1169
1307
|
{
|
|
1170
1308
|
type: "button",
|
|
1171
1309
|
onClick: () => setShowAdvanced(!showAdvanced),
|
|
1172
1310
|
className: "flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors text-sm font-medium focus:outline-none",
|
|
1173
1311
|
children: [
|
|
1174
|
-
/* @__PURE__ */
|
|
1312
|
+
/* @__PURE__ */ jsx4(Settings, { className: "w-4 h-4" }),
|
|
1175
1313
|
showAdvanced ? "Hide Advanced Options" : "Show Advanced Options"
|
|
1176
1314
|
]
|
|
1177
1315
|
}
|
|
1178
1316
|
),
|
|
1179
|
-
showAdvanced && /* @__PURE__ */
|
|
1180
|
-
/* @__PURE__ */
|
|
1181
|
-
/* @__PURE__ */
|
|
1182
|
-
/* @__PURE__ */
|
|
1183
|
-
/* @__PURE__ */
|
|
1317
|
+
showAdvanced && /* @__PURE__ */ jsxs4("div", { className: "mt-4 space-y-4", children: [
|
|
1318
|
+
/* @__PURE__ */ jsxs4("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
1319
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1320
|
+
/* @__PURE__ */ jsx4("label", { className: cn(FIELD_LABEL_CLASS, "mb-1.5"), children: "Workspace Name" }),
|
|
1321
|
+
/* @__PURE__ */ jsx4(
|
|
1184
1322
|
Input,
|
|
1185
1323
|
{
|
|
1186
1324
|
type: "text",
|
|
@@ -1192,9 +1330,9 @@ function ProvisioningWizard({
|
|
|
1192
1330
|
}
|
|
1193
1331
|
)
|
|
1194
1332
|
] }),
|
|
1195
|
-
/* @__PURE__ */
|
|
1196
|
-
/* @__PURE__ */
|
|
1197
|
-
/* @__PURE__ */
|
|
1333
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1334
|
+
/* @__PURE__ */ jsx4("label", { className: cn(FIELD_LABEL_CLASS, "mb-1.5"), children: "Virtualization Driver" }),
|
|
1335
|
+
/* @__PURE__ */ jsxs4(
|
|
1198
1336
|
"select",
|
|
1199
1337
|
{
|
|
1200
1338
|
value: driver,
|
|
@@ -1206,8 +1344,8 @@ function ProvisioningWizard({
|
|
|
1206
1344
|
},
|
|
1207
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",
|
|
1208
1346
|
children: [
|
|
1209
|
-
/* @__PURE__ */
|
|
1210
|
-
/* @__PURE__ */
|
|
1347
|
+
/* @__PURE__ */ jsx4("option", { value: "docker", className: "bg-gray-900", children: "Docker container (Default)" }),
|
|
1348
|
+
/* @__PURE__ */ jsx4(
|
|
1211
1349
|
"option",
|
|
1212
1350
|
{
|
|
1213
1351
|
value: "firecracker",
|
|
@@ -1215,15 +1353,15 @@ function ProvisioningWizard({
|
|
|
1215
1353
|
children: "Firecracker microVM (Secure)"
|
|
1216
1354
|
}
|
|
1217
1355
|
),
|
|
1218
|
-
/* @__PURE__ */
|
|
1356
|
+
/* @__PURE__ */ jsx4("option", { value: "tangle", className: "bg-gray-900", children: "Tangle Distributed Node" })
|
|
1219
1357
|
]
|
|
1220
1358
|
}
|
|
1221
1359
|
)
|
|
1222
1360
|
] })
|
|
1223
1361
|
] }),
|
|
1224
|
-
/* @__PURE__ */
|
|
1225
|
-
/* @__PURE__ */
|
|
1226
|
-
/* @__PURE__ */
|
|
1362
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1363
|
+
/* @__PURE__ */ jsx4("label", { className: cn(FIELD_LABEL_CLASS, "mb-1.5"), children: "Git Repository URL" }),
|
|
1364
|
+
/* @__PURE__ */ jsx4(
|
|
1227
1365
|
Input,
|
|
1228
1366
|
{
|
|
1229
1367
|
type: "text",
|
|
@@ -1234,10 +1372,10 @@ function ProvisioningWizard({
|
|
|
1234
1372
|
}
|
|
1235
1373
|
)
|
|
1236
1374
|
] }),
|
|
1237
|
-
/* @__PURE__ */
|
|
1238
|
-
/* @__PURE__ */
|
|
1239
|
-
/* @__PURE__ */
|
|
1240
|
-
/* @__PURE__ */
|
|
1375
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1376
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex justify-between items-center mb-1.5", children: [
|
|
1377
|
+
/* @__PURE__ */ jsx4("label", { className: FIELD_LABEL_CLASS, children: "Environment Variables" }),
|
|
1378
|
+
/* @__PURE__ */ jsxs4(
|
|
1241
1379
|
"button",
|
|
1242
1380
|
{
|
|
1243
1381
|
type: "button",
|
|
@@ -1247,15 +1385,15 @@ function ProvisioningWizard({
|
|
|
1247
1385
|
]),
|
|
1248
1386
|
className: "flex items-center gap-1 text-xs text-primary hover:text-primary/70 transition-colors font-medium",
|
|
1249
1387
|
children: [
|
|
1250
|
-
/* @__PURE__ */
|
|
1388
|
+
/* @__PURE__ */ jsx4(Plus, { className: "h-3 w-3" }),
|
|
1251
1389
|
" Add Var"
|
|
1252
1390
|
]
|
|
1253
1391
|
}
|
|
1254
1392
|
)
|
|
1255
1393
|
] }),
|
|
1256
|
-
/* @__PURE__ */
|
|
1257
|
-
envVars.map((env, i) => /* @__PURE__ */
|
|
1258
|
-
/* @__PURE__ */
|
|
1394
|
+
/* @__PURE__ */ jsxs4("div", { className: "space-y-2", children: [
|
|
1395
|
+
envVars.map((env, i) => /* @__PURE__ */ jsxs4("div", { className: "flex gap-2", children: [
|
|
1396
|
+
/* @__PURE__ */ jsx4(
|
|
1259
1397
|
Input,
|
|
1260
1398
|
{
|
|
1261
1399
|
type: "text",
|
|
@@ -1269,7 +1407,7 @@ function ProvisioningWizard({
|
|
|
1269
1407
|
placeholder: "API_KEY"
|
|
1270
1408
|
}
|
|
1271
1409
|
),
|
|
1272
|
-
/* @__PURE__ */
|
|
1410
|
+
/* @__PURE__ */ jsx4(
|
|
1273
1411
|
Input,
|
|
1274
1412
|
{
|
|
1275
1413
|
type: "password",
|
|
@@ -1283,7 +1421,7 @@ function ProvisioningWizard({
|
|
|
1283
1421
|
placeholder: "sk-xxxxxxxxxxx"
|
|
1284
1422
|
}
|
|
1285
1423
|
),
|
|
1286
|
-
/* @__PURE__ */
|
|
1424
|
+
/* @__PURE__ */ jsx4(
|
|
1287
1425
|
Button,
|
|
1288
1426
|
{
|
|
1289
1427
|
type: "button",
|
|
@@ -1293,25 +1431,25 @@ function ProvisioningWizard({
|
|
|
1293
1431
|
envVars.filter((_, idx) => idx !== i)
|
|
1294
1432
|
),
|
|
1295
1433
|
className: "h-9 w-9 shrink-0 text-destructive hover:bg-destructive/10 hover:border-destructive/30",
|
|
1296
|
-
children: /* @__PURE__ */
|
|
1434
|
+
children: /* @__PURE__ */ jsx4(Trash2, { className: "h-4 w-4" })
|
|
1297
1435
|
}
|
|
1298
1436
|
)
|
|
1299
1437
|
] }, i)),
|
|
1300
|
-
envVars.length === 0 && /* @__PURE__ */
|
|
1438
|
+
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" })
|
|
1301
1439
|
] })
|
|
1302
1440
|
] }),
|
|
1303
|
-
availableScripts.length > 0 && /* @__PURE__ */
|
|
1304
|
-
/* @__PURE__ */
|
|
1305
|
-
/* @__PURE__ */
|
|
1441
|
+
availableScripts.length > 0 && /* @__PURE__ */ jsxs4("div", { children: [
|
|
1442
|
+
/* @__PURE__ */ jsx4("div", { className: cn(FIELD_LABEL_CLASS, "mb-1.5"), children: "Startup Scripts" }),
|
|
1443
|
+
/* @__PURE__ */ jsx4("div", { className: "space-y-2", children: availableScripts.filter((s) => s.enabled).map((script) => {
|
|
1306
1444
|
const selected = startupScriptIds.includes(
|
|
1307
1445
|
script.id
|
|
1308
1446
|
);
|
|
1309
|
-
return /* @__PURE__ */
|
|
1447
|
+
return /* @__PURE__ */ jsxs4(
|
|
1310
1448
|
"label",
|
|
1311
1449
|
{
|
|
1312
1450
|
className: "flex items-start gap-3 cursor-pointer group rounded-lg border border-border p-3 transition-colors hover:border-primary/30",
|
|
1313
1451
|
children: [
|
|
1314
|
-
/* @__PURE__ */
|
|
1452
|
+
/* @__PURE__ */ jsx4(
|
|
1315
1453
|
"input",
|
|
1316
1454
|
{
|
|
1317
1455
|
type: "checkbox",
|
|
@@ -1324,15 +1462,15 @@ function ProvisioningWizard({
|
|
|
1324
1462
|
className: "mt-0.5 h-4 w-4 rounded border-border text-primary focus:ring-primary/30"
|
|
1325
1463
|
}
|
|
1326
1464
|
),
|
|
1327
|
-
/* @__PURE__ */
|
|
1328
|
-
/* @__PURE__ */
|
|
1329
|
-
script.description && /* @__PURE__ */
|
|
1330
|
-
script.injectSecrets.length > 0 && /* @__PURE__ */
|
|
1465
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex-1 min-w-0", children: [
|
|
1466
|
+
/* @__PURE__ */ jsx4("div", { className: "text-sm font-medium text-foreground group-hover:text-primary transition-colors", children: script.name }),
|
|
1467
|
+
script.description && /* @__PURE__ */ jsx4("div", { className: "text-xs text-muted-foreground mt-0.5", children: script.description }),
|
|
1468
|
+
script.injectSecrets.length > 0 && /* @__PURE__ */ jsx4("div", { className: "flex flex-wrap gap-1 mt-1.5", children: script.injectSecrets.map((s) => /* @__PURE__ */ jsxs4(
|
|
1331
1469
|
"span",
|
|
1332
1470
|
{
|
|
1333
1471
|
className: "inline-flex items-center gap-0.5 rounded-full bg-muted px-2 py-0.5 text-[10px] text-muted-foreground",
|
|
1334
1472
|
children: [
|
|
1335
|
-
/* @__PURE__ */
|
|
1473
|
+
/* @__PURE__ */ jsxs4(
|
|
1336
1474
|
"svg",
|
|
1337
1475
|
{
|
|
1338
1476
|
className: "h-2.5 w-2.5",
|
|
@@ -1341,7 +1479,7 @@ function ProvisioningWizard({
|
|
|
1341
1479
|
stroke: "currentColor",
|
|
1342
1480
|
strokeWidth: "2",
|
|
1343
1481
|
children: [
|
|
1344
|
-
/* @__PURE__ */
|
|
1482
|
+
/* @__PURE__ */ jsx4(
|
|
1345
1483
|
"rect",
|
|
1346
1484
|
{
|
|
1347
1485
|
x: "3",
|
|
@@ -1352,7 +1490,7 @@ function ProvisioningWizard({
|
|
|
1352
1490
|
ry: "2"
|
|
1353
1491
|
}
|
|
1354
1492
|
),
|
|
1355
|
-
/* @__PURE__ */
|
|
1493
|
+
/* @__PURE__ */ jsx4("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })
|
|
1356
1494
|
]
|
|
1357
1495
|
}
|
|
1358
1496
|
),
|
|
@@ -1368,9 +1506,9 @@ function ProvisioningWizard({
|
|
|
1368
1506
|
);
|
|
1369
1507
|
}) })
|
|
1370
1508
|
] }),
|
|
1371
|
-
/* @__PURE__ */
|
|
1372
|
-
/* @__PURE__ */
|
|
1373
|
-
/* @__PURE__ */
|
|
1509
|
+
/* @__PURE__ */ jsxs4("div", { className: "pt-3 border-t border-border flex items-start justify-between gap-3", children: [
|
|
1510
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1511
|
+
/* @__PURE__ */ jsx4(
|
|
1374
1512
|
"label",
|
|
1375
1513
|
{
|
|
1376
1514
|
htmlFor: "wizard-bare-mode",
|
|
@@ -1378,9 +1516,9 @@ function ProvisioningWizard({
|
|
|
1378
1516
|
children: "Bare Mode"
|
|
1379
1517
|
}
|
|
1380
1518
|
),
|
|
1381
|
-
/* @__PURE__ */
|
|
1519
|
+
/* @__PURE__ */ jsx4("p", { className: "text-xs text-muted-foreground mt-0.5", children: "Start as a raw container without an embedded AI Agent backend." })
|
|
1382
1520
|
] }),
|
|
1383
|
-
/* @__PURE__ */
|
|
1521
|
+
/* @__PURE__ */ jsx4(
|
|
1384
1522
|
Switch,
|
|
1385
1523
|
{
|
|
1386
1524
|
id: "wizard-bare-mode",
|
|
@@ -1391,28 +1529,28 @@ function ProvisioningWizard({
|
|
|
1391
1529
|
)
|
|
1392
1530
|
] })
|
|
1393
1531
|
] })
|
|
1394
|
-
] }) })
|
|
1395
|
-
sshAccess &&
|
|
1396
|
-
/* @__PURE__ */
|
|
1397
|
-
/* @__PURE__ */
|
|
1398
|
-
/* @__PURE__ */
|
|
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" })
|
|
1399
1537
|
] }),
|
|
1400
|
-
/* @__PURE__ */
|
|
1401
|
-
] })
|
|
1538
|
+
/* @__PURE__ */ jsx4(SshAccessStep, { config: sshAccess })
|
|
1539
|
+
] })
|
|
1402
1540
|
] })
|
|
1403
1541
|
] }),
|
|
1404
|
-
/* @__PURE__ */
|
|
1405
|
-
/* @__PURE__ */
|
|
1406
|
-
/* @__PURE__ */
|
|
1407
|
-
/* @__PURE__ */
|
|
1408
|
-
/* @__PURE__ */
|
|
1542
|
+
/* @__PURE__ */ jsxs4("div", { className: "col-span-12 xl:col-span-4 sticky top-4 space-y-4", children: [
|
|
1543
|
+
/* @__PURE__ */ jsxs4("div", { className: "rounded-lg border border-border bg-card p-5 shadow-sm", children: [
|
|
1544
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex justify-between items-center mb-3", children: [
|
|
1545
|
+
/* @__PURE__ */ jsx4("span", { className: FIELD_LABEL_CLASS, children: "Run Cost" }),
|
|
1546
|
+
/* @__PURE__ */ jsxs4(
|
|
1409
1547
|
"div",
|
|
1410
1548
|
{
|
|
1411
1549
|
role: "group",
|
|
1412
1550
|
"aria-label": "Pricing view",
|
|
1413
1551
|
className: "inline-flex items-center rounded-md border border-border bg-muted/50 p-0.5",
|
|
1414
1552
|
children: [
|
|
1415
|
-
/* @__PURE__ */
|
|
1553
|
+
/* @__PURE__ */ jsx4(
|
|
1416
1554
|
"button",
|
|
1417
1555
|
{
|
|
1418
1556
|
type: "button",
|
|
@@ -1425,7 +1563,7 @@ function ProvisioningWizard({
|
|
|
1425
1563
|
children: "Per Hour"
|
|
1426
1564
|
}
|
|
1427
1565
|
),
|
|
1428
|
-
/* @__PURE__ */
|
|
1566
|
+
/* @__PURE__ */ jsx4(
|
|
1429
1567
|
"button",
|
|
1430
1568
|
{
|
|
1431
1569
|
type: "button",
|
|
@@ -1442,8 +1580,8 @@ function ProvisioningWizard({
|
|
|
1442
1580
|
}
|
|
1443
1581
|
)
|
|
1444
1582
|
] }),
|
|
1445
|
-
/* @__PURE__ */
|
|
1446
|
-
/* @__PURE__ */
|
|
1583
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-baseline gap-2 mb-4", children: [
|
|
1584
|
+
/* @__PURE__ */ jsxs4(
|
|
1447
1585
|
"span",
|
|
1448
1586
|
{
|
|
1449
1587
|
className: cn(
|
|
@@ -1457,36 +1595,36 @@ function ProvisioningWizard({
|
|
|
1457
1595
|
},
|
|
1458
1596
|
pricingView
|
|
1459
1597
|
),
|
|
1460
|
-
/* @__PURE__ */
|
|
1598
|
+
/* @__PURE__ */ jsx4("span", { className: "text-muted-foreground text-sm", children: pricingSuffix })
|
|
1461
1599
|
] }),
|
|
1462
|
-
/* @__PURE__ */
|
|
1463
|
-
/* @__PURE__ */
|
|
1464
|
-
/* @__PURE__ */
|
|
1465
|
-
/* @__PURE__ */
|
|
1600
|
+
/* @__PURE__ */ jsxs4("div", { className: "space-y-2 rounded-md border border-border bg-muted/30 p-3", children: [
|
|
1601
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex justify-between text-xs font-mono tracking-wide text-muted-foreground", children: [
|
|
1602
|
+
/* @__PURE__ */ jsx4("span", { children: "COMPUTE" }),
|
|
1603
|
+
/* @__PURE__ */ jsxs4("span", { className: "text-foreground", children: [
|
|
1466
1604
|
"$",
|
|
1467
1605
|
fmtRate(hourlyCostBreakdown.compute),
|
|
1468
1606
|
rateSuffix
|
|
1469
1607
|
] })
|
|
1470
1608
|
] }),
|
|
1471
|
-
/* @__PURE__ */
|
|
1472
|
-
/* @__PURE__ */
|
|
1473
|
-
/* @__PURE__ */
|
|
1609
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex justify-between text-xs font-mono tracking-wide text-muted-foreground", children: [
|
|
1610
|
+
/* @__PURE__ */ jsx4("span", { children: "MEMORY" }),
|
|
1611
|
+
/* @__PURE__ */ jsxs4("span", { className: "text-foreground/80", children: [
|
|
1474
1612
|
"$",
|
|
1475
1613
|
fmtRate(hourlyCostBreakdown.memory),
|
|
1476
1614
|
rateSuffix
|
|
1477
1615
|
] })
|
|
1478
1616
|
] }),
|
|
1479
|
-
/* @__PURE__ */
|
|
1480
|
-
/* @__PURE__ */
|
|
1481
|
-
/* @__PURE__ */
|
|
1617
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex justify-between text-xs font-mono tracking-wide text-muted-foreground", children: [
|
|
1618
|
+
/* @__PURE__ */ jsx4("span", { children: "STORAGE" }),
|
|
1619
|
+
/* @__PURE__ */ jsxs4("span", { className: "text-foreground/80", children: [
|
|
1482
1620
|
"$",
|
|
1483
1621
|
fmtRate(hourlyCostBreakdown.storage),
|
|
1484
1622
|
rateSuffix
|
|
1485
1623
|
] })
|
|
1486
1624
|
] }),
|
|
1487
|
-
hourlyCostBreakdown.floorApplies && /* @__PURE__ */
|
|
1488
|
-
/* @__PURE__ */
|
|
1489
|
-
/* @__PURE__ */
|
|
1625
|
+
hourlyCostBreakdown.floorApplies && /* @__PURE__ */ jsxs4("div", { className: "flex justify-between text-xs font-mono tracking-wide text-primary border-t border-border pt-2", children: [
|
|
1626
|
+
/* @__PURE__ */ jsx4("span", { children: "MIN CHARGE" }),
|
|
1627
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
1490
1628
|
"$",
|
|
1491
1629
|
fmtRate(
|
|
1492
1630
|
hourlyCostBreakdown.floor - hourlyCostBreakdown.lineSum
|
|
@@ -1496,54 +1634,19 @@ function ProvisioningWizard({
|
|
|
1496
1634
|
] })
|
|
1497
1635
|
] })
|
|
1498
1636
|
] }),
|
|
1499
|
-
deployError && /* @__PURE__ */
|
|
1500
|
-
/* @__PURE__ */
|
|
1501
|
-
/* @__PURE__ */
|
|
1637
|
+
deployError && /* @__PURE__ */ jsxs4("div", { className: "rounded-lg border border-destructive/30 bg-destructive/10 p-3 flex items-center gap-2", children: [
|
|
1638
|
+
/* @__PURE__ */ jsx4(Info, { className: "h-4 w-4 text-destructive shrink-0" }),
|
|
1639
|
+
/* @__PURE__ */ jsx4("p", { className: "text-sm font-medium text-destructive", children: deployError })
|
|
1502
1640
|
] }),
|
|
1503
|
-
/* @__PURE__ */
|
|
1504
|
-
currentStep < finalStep ? /* @__PURE__ */ jsxs3(
|
|
1505
|
-
Button,
|
|
1506
|
-
{
|
|
1507
|
-
type: "button",
|
|
1508
|
-
onClick: () => setCurrentStep((s) => s + 1),
|
|
1509
|
-
className: "w-full",
|
|
1510
|
-
children: [
|
|
1511
|
-
"Continue to ",
|
|
1512
|
-
stepLabels[currentStep]
|
|
1513
|
-
]
|
|
1514
|
-
}
|
|
1515
|
-
) : /* @__PURE__ */ jsx3(
|
|
1516
|
-
Button,
|
|
1517
|
-
{
|
|
1518
|
-
type: "button",
|
|
1519
|
-
onClick: handleDeploy,
|
|
1520
|
-
disabled: isDeploying || !selectedEnv,
|
|
1521
|
-
className: "w-full",
|
|
1522
|
-
children: isDeploying ? /* @__PURE__ */ jsxs3("span", { className: "flex items-center justify-center gap-2", children: [
|
|
1523
|
-
/* @__PURE__ */ jsx3(Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
1524
|
-
"Deploying..."
|
|
1525
|
-
] }) : "Deploy Workspace"
|
|
1526
|
-
}
|
|
1527
|
-
),
|
|
1528
|
-
currentStep > 1 && /* @__PURE__ */ jsx3(
|
|
1529
|
-
Button,
|
|
1530
|
-
{
|
|
1531
|
-
type: "button",
|
|
1532
|
-
variant: "secondary",
|
|
1533
|
-
onClick: () => setCurrentStep((s) => s - 1),
|
|
1534
|
-
className: "w-full",
|
|
1535
|
-
children: "Back"
|
|
1536
|
-
}
|
|
1537
|
-
)
|
|
1538
|
-
] }) : /* @__PURE__ */ jsx3(
|
|
1641
|
+
/* @__PURE__ */ jsx4("div", { className: "space-y-2", children: /* @__PURE__ */ jsx4(
|
|
1539
1642
|
Button,
|
|
1540
1643
|
{
|
|
1541
1644
|
type: "button",
|
|
1542
1645
|
onClick: handleDeploy,
|
|
1543
1646
|
disabled: isDeploying || !selectedEnv,
|
|
1544
1647
|
className: "w-full",
|
|
1545
|
-
children: isDeploying ? /* @__PURE__ */
|
|
1546
|
-
/* @__PURE__ */
|
|
1648
|
+
children: isDeploying ? /* @__PURE__ */ jsxs4("span", { className: "flex items-center justify-center gap-2", children: [
|
|
1649
|
+
/* @__PURE__ */ jsx4(Loader22, { className: "h-4 w-4 animate-spin" }),
|
|
1547
1650
|
"Spinning up environment..."
|
|
1548
1651
|
] }) : "Deploy Workspace"
|
|
1549
1652
|
}
|
|
@@ -1554,10 +1657,10 @@ function ProvisioningWizard({
|
|
|
1554
1657
|
}
|
|
1555
1658
|
|
|
1556
1659
|
// src/pages/pricing-page.tsx
|
|
1557
|
-
import * as
|
|
1660
|
+
import * as React4 from "react";
|
|
1558
1661
|
import { Skeleton as Skeleton2, SkeletonCard as SkeletonCard2 } from "@tangle-network/ui/primitives";
|
|
1559
1662
|
import { ChevronDown } from "lucide-react";
|
|
1560
|
-
import { jsx as
|
|
1663
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1561
1664
|
async function fetchTiersFromApi(apiBasePath) {
|
|
1562
1665
|
const res = await fetch(`${apiBasePath}/v1/billing/tiers`);
|
|
1563
1666
|
if (!res.ok) throw new Error("Failed to fetch pricing tiers");
|
|
@@ -1589,14 +1692,14 @@ function StandalonePricingPage({
|
|
|
1589
1692
|
eyebrow,
|
|
1590
1693
|
className
|
|
1591
1694
|
}) {
|
|
1592
|
-
const [state, setState] =
|
|
1695
|
+
const [state, setState] = React4.useState({
|
|
1593
1696
|
tiers: initialTiers || [],
|
|
1594
1697
|
loading: !initialTiers,
|
|
1595
1698
|
error: null,
|
|
1596
1699
|
billingPeriod: "monthly",
|
|
1597
1700
|
selectingTier: false
|
|
1598
1701
|
});
|
|
1599
|
-
const loadTiers =
|
|
1702
|
+
const loadTiers = React4.useCallback(async () => {
|
|
1600
1703
|
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
1601
1704
|
try {
|
|
1602
1705
|
const tiers = fetchTiers ? await fetchTiers() : await fetchTiersFromApi(apiBasePath);
|
|
@@ -1609,12 +1712,12 @@ function StandalonePricingPage({
|
|
|
1609
1712
|
}));
|
|
1610
1713
|
}
|
|
1611
1714
|
}, [apiBasePath, fetchTiers]);
|
|
1612
|
-
|
|
1715
|
+
React4.useEffect(() => {
|
|
1613
1716
|
if (!initialTiers) {
|
|
1614
1717
|
loadTiers();
|
|
1615
1718
|
}
|
|
1616
1719
|
}, [initialTiers, loadTiers]);
|
|
1617
|
-
const handleSelectTier =
|
|
1720
|
+
const handleSelectTier = React4.useCallback(
|
|
1618
1721
|
async (tierId) => {
|
|
1619
1722
|
if (onSelectTier) {
|
|
1620
1723
|
onSelectTier(tierId, state.billingPeriod);
|
|
@@ -1641,25 +1744,25 @@ function StandalonePricingPage({
|
|
|
1641
1744
|
},
|
|
1642
1745
|
[apiBasePath, state.billingPeriod, onSelectTier]
|
|
1643
1746
|
);
|
|
1644
|
-
return /* @__PURE__ */
|
|
1645
|
-
/* @__PURE__ */
|
|
1646
|
-
eyebrow && /* @__PURE__ */
|
|
1647
|
-
/* @__PURE__ */
|
|
1648
|
-
/* @__PURE__ */
|
|
1747
|
+
return /* @__PURE__ */ jsxs5("div", { className: cn("mx-auto max-w-6xl px-6 py-16 space-y-16", className), children: [
|
|
1748
|
+
/* @__PURE__ */ jsxs5("div", { className: "space-y-4 text-center", children: [
|
|
1749
|
+
eyebrow && /* @__PURE__ */ jsx5("span", { className: "text-xs font-bold uppercase tracking-widest text-[var(--brand-emerald,#10B981)]", children: eyebrow }),
|
|
1750
|
+
/* @__PURE__ */ jsx5("h1", { className: "text-4xl font-extrabold tracking-tight text-foreground sm:text-5xl font-display", children: title }),
|
|
1751
|
+
/* @__PURE__ */ jsx5("p", { className: "mx-auto max-w-2xl text-lg text-muted-foreground", children: subtitle })
|
|
1649
1752
|
] }),
|
|
1650
|
-
state.loading ? /* @__PURE__ */
|
|
1651
|
-
/* @__PURE__ */
|
|
1652
|
-
/* @__PURE__ */
|
|
1653
|
-
/* @__PURE__ */
|
|
1753
|
+
state.loading ? /* @__PURE__ */ jsxs5("div", { className: "space-y-8", children: [
|
|
1754
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-center gap-4", children: [
|
|
1755
|
+
/* @__PURE__ */ jsx5(Skeleton2, { className: "h-10 w-24" }),
|
|
1756
|
+
/* @__PURE__ */ jsx5(Skeleton2, { className: "h-10 w-24" })
|
|
1654
1757
|
] }),
|
|
1655
|
-
/* @__PURE__ */
|
|
1656
|
-
/* @__PURE__ */
|
|
1657
|
-
/* @__PURE__ */
|
|
1658
|
-
/* @__PURE__ */
|
|
1758
|
+
/* @__PURE__ */ jsxs5("div", { className: "grid grid-cols-1 gap-6 lg:grid-cols-3", children: [
|
|
1759
|
+
/* @__PURE__ */ jsx5(SkeletonCard2, { className: "h-[500px]" }),
|
|
1760
|
+
/* @__PURE__ */ jsx5(SkeletonCard2, { className: "h-[500px]" }),
|
|
1761
|
+
/* @__PURE__ */ jsx5(SkeletonCard2, { className: "h-[500px]" })
|
|
1659
1762
|
] })
|
|
1660
|
-
] }) : state.error ? /* @__PURE__ */
|
|
1661
|
-
/* @__PURE__ */
|
|
1662
|
-
/* @__PURE__ */
|
|
1763
|
+
] }) : state.error ? /* @__PURE__ */ jsxs5("div", { className: "flex flex-col items-center justify-center space-y-4 rounded-xl border border-destructive/20 bg-destructive/5 p-8 text-center", children: [
|
|
1764
|
+
/* @__PURE__ */ jsx5("p", { className: "text-destructive text-sm font-medium", children: state.error }),
|
|
1765
|
+
/* @__PURE__ */ jsx5(
|
|
1663
1766
|
"button",
|
|
1664
1767
|
{
|
|
1665
1768
|
type: "button",
|
|
@@ -1668,7 +1771,7 @@ function StandalonePricingPage({
|
|
|
1668
1771
|
children: "Try Again"
|
|
1669
1772
|
}
|
|
1670
1773
|
)
|
|
1671
|
-
] }) : /* @__PURE__ */
|
|
1774
|
+
] }) : /* @__PURE__ */ jsx5(
|
|
1672
1775
|
PricingPage,
|
|
1673
1776
|
{
|
|
1674
1777
|
tiers: state.tiers,
|
|
@@ -1679,14 +1782,14 @@ function StandalonePricingPage({
|
|
|
1679
1782
|
loading: state.selectingTier
|
|
1680
1783
|
}
|
|
1681
1784
|
),
|
|
1682
|
-
/* @__PURE__ */
|
|
1683
|
-
/* @__PURE__ */
|
|
1684
|
-
FAQ.map(({ q, a }) => /* @__PURE__ */
|
|
1685
|
-
/* @__PURE__ */
|
|
1785
|
+
/* @__PURE__ */ jsxs5("div", { className: "mx-auto max-w-2xl space-y-4 border-t border-border pt-12", children: [
|
|
1786
|
+
/* @__PURE__ */ jsx5("h2", { className: "text-center text-xl font-bold text-foreground mb-6", children: "Frequently Asked Questions" }),
|
|
1787
|
+
FAQ.map(({ q, a }) => /* @__PURE__ */ jsxs5("details", { className: "group rounded-xl border border-border bg-card overflow-hidden", children: [
|
|
1788
|
+
/* @__PURE__ */ jsxs5("summary", { className: "flex cursor-pointer items-center justify-between px-6 py-4 font-medium text-foreground text-sm", children: [
|
|
1686
1789
|
q,
|
|
1687
|
-
/* @__PURE__ */
|
|
1790
|
+
/* @__PURE__ */ jsx5(ChevronDown, { className: "h-4 w-4 text-muted-foreground transition-transform group-open:rotate-180" })
|
|
1688
1791
|
] }),
|
|
1689
|
-
/* @__PURE__ */
|
|
1792
|
+
/* @__PURE__ */ jsx5("div", { className: "px-6 pb-4", children: /* @__PURE__ */ jsx5("p", { className: "text-sm text-muted-foreground leading-relaxed", children: a }) })
|
|
1690
1793
|
] }, q))
|
|
1691
1794
|
] })
|
|
1692
1795
|
] });
|
|
@@ -1698,27 +1801,27 @@ import {
|
|
|
1698
1801
|
ChevronRight,
|
|
1699
1802
|
Copy,
|
|
1700
1803
|
Edit2,
|
|
1701
|
-
Loader2 as
|
|
1804
|
+
Loader2 as Loader23,
|
|
1702
1805
|
Plus as Plus2,
|
|
1703
1806
|
Search,
|
|
1704
1807
|
Settings2,
|
|
1705
1808
|
Trash2 as Trash22
|
|
1706
1809
|
} from "lucide-react";
|
|
1707
|
-
import * as
|
|
1810
|
+
import * as React5 from "react";
|
|
1708
1811
|
import { Button as Button2 } from "@tangle-network/ui/primitives";
|
|
1709
1812
|
import { Badge as Badge2 } from "@tangle-network/ui/primitives";
|
|
1710
1813
|
import { Card } from "@tangle-network/ui/primitives";
|
|
1711
1814
|
import {
|
|
1712
|
-
Dialog,
|
|
1713
|
-
DialogContent,
|
|
1714
|
-
DialogDescription,
|
|
1715
|
-
DialogFooter,
|
|
1716
|
-
DialogHeader,
|
|
1717
|
-
DialogTitle
|
|
1815
|
+
Dialog as Dialog2,
|
|
1816
|
+
DialogContent as DialogContent2,
|
|
1817
|
+
DialogDescription as DialogDescription2,
|
|
1818
|
+
DialogFooter as DialogFooter2,
|
|
1819
|
+
DialogHeader as DialogHeader2,
|
|
1820
|
+
DialogTitle as DialogTitle2
|
|
1718
1821
|
} from "@tangle-network/ui/primitives";
|
|
1719
1822
|
import { EmptyState } from "@tangle-network/ui/primitives";
|
|
1720
1823
|
import { Input as Input2 } from "@tangle-network/ui/primitives";
|
|
1721
|
-
import { jsx as
|
|
1824
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1722
1825
|
var TIER_LIMITS = {
|
|
1723
1826
|
free: 3,
|
|
1724
1827
|
starter: 10,
|
|
@@ -1732,24 +1835,24 @@ function ProfilesPage({
|
|
|
1732
1835
|
onCompareClick,
|
|
1733
1836
|
title = "Profiles"
|
|
1734
1837
|
}) {
|
|
1735
|
-
const [builtinProfiles, setBuiltinProfiles] =
|
|
1736
|
-
const [customProfiles, setCustomProfiles] =
|
|
1737
|
-
const [loading, setLoading] =
|
|
1738
|
-
const [error, setError] =
|
|
1739
|
-
const [searchQuery, setSearchQuery] =
|
|
1740
|
-
const [createDialogOpen, setCreateDialogOpen] =
|
|
1741
|
-
const [editingProfile, setEditingProfile] =
|
|
1838
|
+
const [builtinProfiles, setBuiltinProfiles] = React5.useState([]);
|
|
1839
|
+
const [customProfiles, setCustomProfiles] = React5.useState([]);
|
|
1840
|
+
const [loading, setLoading] = React5.useState(true);
|
|
1841
|
+
const [error, setError] = React5.useState(null);
|
|
1842
|
+
const [searchQuery, setSearchQuery] = React5.useState("");
|
|
1843
|
+
const [createDialogOpen, setCreateDialogOpen] = React5.useState(false);
|
|
1844
|
+
const [editingProfile, setEditingProfile] = React5.useState(
|
|
1742
1845
|
null
|
|
1743
1846
|
);
|
|
1744
|
-
const [deletingProfile, setDeletingProfile] =
|
|
1847
|
+
const [deletingProfile, setDeletingProfile] = React5.useState(
|
|
1745
1848
|
null
|
|
1746
1849
|
);
|
|
1747
|
-
const [detailProfile, setDetailProfile] =
|
|
1850
|
+
const [detailProfile, setDetailProfile] = React5.useState(
|
|
1748
1851
|
null
|
|
1749
1852
|
);
|
|
1750
1853
|
const profileLimit = maxProfiles ?? TIER_LIMITS[tier] ?? 3;
|
|
1751
1854
|
const canCreateMore = customProfiles.length < profileLimit;
|
|
1752
|
-
const loadProfiles =
|
|
1855
|
+
const loadProfiles = React5.useCallback(async () => {
|
|
1753
1856
|
try {
|
|
1754
1857
|
setLoading(true);
|
|
1755
1858
|
setError(null);
|
|
@@ -1762,7 +1865,7 @@ function ProfilesPage({
|
|
|
1762
1865
|
setLoading(false);
|
|
1763
1866
|
}
|
|
1764
1867
|
}, [apiClient]);
|
|
1765
|
-
|
|
1868
|
+
React5.useEffect(() => {
|
|
1766
1869
|
loadProfiles();
|
|
1767
1870
|
}, [loadProfiles]);
|
|
1768
1871
|
const filteredBuiltin = builtinProfiles.filter(
|
|
@@ -1771,14 +1874,14 @@ function ProfilesPage({
|
|
|
1771
1874
|
const filteredCustom = customProfiles.filter(
|
|
1772
1875
|
(p) => p.name.toLowerCase().includes(searchQuery.toLowerCase()) || p.description?.toLowerCase().includes(searchQuery.toLowerCase())
|
|
1773
1876
|
);
|
|
1774
|
-
return /* @__PURE__ */
|
|
1775
|
-
/* @__PURE__ */
|
|
1776
|
-
/* @__PURE__ */
|
|
1777
|
-
/* @__PURE__ */
|
|
1778
|
-
/* @__PURE__ */
|
|
1877
|
+
return /* @__PURE__ */ jsxs6("div", { className: "space-y-6", children: [
|
|
1878
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between", children: [
|
|
1879
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
1880
|
+
/* @__PURE__ */ jsx6("h1", { className: "font-semibold text-2xl", children: title }),
|
|
1881
|
+
/* @__PURE__ */ jsx6("p", { className: "text-muted-foreground", children: "Customize agent behavior with system prompts, models, and instructions" })
|
|
1779
1882
|
] }),
|
|
1780
|
-
/* @__PURE__ */
|
|
1781
|
-
onCompareClick && customProfiles.length >= 2 && /* @__PURE__ */
|
|
1883
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3", children: [
|
|
1884
|
+
onCompareClick && customProfiles.length >= 2 && /* @__PURE__ */ jsx6(
|
|
1782
1885
|
Button2,
|
|
1783
1886
|
{
|
|
1784
1887
|
variant: "outline",
|
|
@@ -1786,30 +1889,30 @@ function ProfilesPage({
|
|
|
1786
1889
|
children: "Compare Profiles"
|
|
1787
1890
|
}
|
|
1788
1891
|
),
|
|
1789
|
-
/* @__PURE__ */
|
|
1892
|
+
/* @__PURE__ */ jsxs6(
|
|
1790
1893
|
Button2,
|
|
1791
1894
|
{
|
|
1792
1895
|
onClick: () => setCreateDialogOpen(true),
|
|
1793
1896
|
disabled: !canCreateMore,
|
|
1794
1897
|
children: [
|
|
1795
|
-
/* @__PURE__ */
|
|
1898
|
+
/* @__PURE__ */ jsx6(Plus2, { className: "mr-2 h-4 w-4" }),
|
|
1796
1899
|
"Create Profile"
|
|
1797
1900
|
]
|
|
1798
1901
|
}
|
|
1799
1902
|
)
|
|
1800
1903
|
] })
|
|
1801
1904
|
] }),
|
|
1802
|
-
!canCreateMore && /* @__PURE__ */
|
|
1803
|
-
/* @__PURE__ */
|
|
1804
|
-
/* @__PURE__ */
|
|
1905
|
+
!canCreateMore && /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 rounded-lg border border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)] p-3 text-sm text-[var(--surface-warning-text)]", children: [
|
|
1906
|
+
/* @__PURE__ */ jsx6(AlertCircle, { className: "h-4 w-4" }),
|
|
1907
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1805
1908
|
"You've reached your profile limit (",
|
|
1806
1909
|
profileLimit,
|
|
1807
1910
|
" profiles). Upgrade your plan to create more."
|
|
1808
1911
|
] })
|
|
1809
1912
|
] }),
|
|
1810
|
-
/* @__PURE__ */
|
|
1811
|
-
/* @__PURE__ */
|
|
1812
|
-
/* @__PURE__ */
|
|
1913
|
+
/* @__PURE__ */ jsxs6("div", { className: "relative max-w-md", children: [
|
|
1914
|
+
/* @__PURE__ */ jsx6(Search, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
|
|
1915
|
+
/* @__PURE__ */ jsx6(
|
|
1813
1916
|
Input2,
|
|
1814
1917
|
{
|
|
1815
1918
|
placeholder: "Search profiles...",
|
|
@@ -1819,33 +1922,33 @@ function ProfilesPage({
|
|
|
1819
1922
|
}
|
|
1820
1923
|
)
|
|
1821
1924
|
] }),
|
|
1822
|
-
error && /* @__PURE__ */
|
|
1823
|
-
/* @__PURE__ */
|
|
1824
|
-
/* @__PURE__ */
|
|
1825
|
-
/* @__PURE__ */
|
|
1925
|
+
error && /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 rounded-lg border border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] p-3 text-[var(--surface-danger-text)] text-sm", children: [
|
|
1926
|
+
/* @__PURE__ */ jsx6(AlertCircle, { className: "h-4 w-4" }),
|
|
1927
|
+
/* @__PURE__ */ jsx6("span", { children: error }),
|
|
1928
|
+
/* @__PURE__ */ jsx6(Button2, { variant: "ghost", size: "sm", onClick: loadProfiles, children: "Retry" })
|
|
1826
1929
|
] }),
|
|
1827
|
-
loading && /* @__PURE__ */
|
|
1828
|
-
!loading && /* @__PURE__ */
|
|
1829
|
-
/* @__PURE__ */
|
|
1830
|
-
/* @__PURE__ */
|
|
1930
|
+
loading && /* @__PURE__ */ jsx6("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx6(Loader23, { className: "h-8 w-8 animate-spin text-muted-foreground" }) }),
|
|
1931
|
+
!loading && /* @__PURE__ */ jsxs6("div", { className: "space-y-8", children: [
|
|
1932
|
+
/* @__PURE__ */ jsxs6("section", { children: [
|
|
1933
|
+
/* @__PURE__ */ jsx6("div", { className: "mb-3 flex items-center justify-between", children: /* @__PURE__ */ jsxs6("h2", { className: "font-medium text-lg", children: [
|
|
1831
1934
|
"Your Profiles (",
|
|
1832
1935
|
customProfiles.length,
|
|
1833
1936
|
"/",
|
|
1834
1937
|
profileLimit === Number.POSITIVE_INFINITY ? "inf" : profileLimit,
|
|
1835
1938
|
")"
|
|
1836
1939
|
] }) }),
|
|
1837
|
-
filteredCustom.length === 0 ? /* @__PURE__ */
|
|
1940
|
+
filteredCustom.length === 0 ? /* @__PURE__ */ jsx6(
|
|
1838
1941
|
EmptyState,
|
|
1839
1942
|
{
|
|
1840
|
-
icon: /* @__PURE__ */
|
|
1943
|
+
icon: /* @__PURE__ */ jsx6(Settings2, { className: "h-8 w-8" }),
|
|
1841
1944
|
title: "No custom profiles yet",
|
|
1842
1945
|
description: "Create a profile to customize agent behavior",
|
|
1843
|
-
action: canCreateMore ? /* @__PURE__ */
|
|
1844
|
-
/* @__PURE__ */
|
|
1946
|
+
action: canCreateMore ? /* @__PURE__ */ jsxs6(Button2, { onClick: () => setCreateDialogOpen(true), children: [
|
|
1947
|
+
/* @__PURE__ */ jsx6(Plus2, { className: "mr-2 h-4 w-4" }),
|
|
1845
1948
|
"Create Profile"
|
|
1846
1949
|
] }) : void 0
|
|
1847
1950
|
}
|
|
1848
|
-
) : /* @__PURE__ */
|
|
1951
|
+
) : /* @__PURE__ */ jsx6("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3", children: filteredCustom.map((profile) => /* @__PURE__ */ jsx6(
|
|
1849
1952
|
ProfileCard,
|
|
1850
1953
|
{
|
|
1851
1954
|
profile,
|
|
@@ -1856,13 +1959,13 @@ function ProfilesPage({
|
|
|
1856
1959
|
profile.id
|
|
1857
1960
|
)) })
|
|
1858
1961
|
] }),
|
|
1859
|
-
/* @__PURE__ */
|
|
1860
|
-
/* @__PURE__ */
|
|
1962
|
+
/* @__PURE__ */ jsxs6("section", { children: [
|
|
1963
|
+
/* @__PURE__ */ jsx6("div", { className: "mb-3 flex items-center justify-between", children: /* @__PURE__ */ jsxs6("h2", { className: "font-medium text-lg", children: [
|
|
1861
1964
|
"Built-in Profiles (",
|
|
1862
1965
|
builtinProfiles.length,
|
|
1863
1966
|
")"
|
|
1864
1967
|
] }) }),
|
|
1865
|
-
filteredBuiltin.length === 0 ? /* @__PURE__ */
|
|
1968
|
+
filteredBuiltin.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "text-muted-foreground text-sm", children: "No matching built-in profiles" }) : /* @__PURE__ */ jsx6("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3", children: filteredBuiltin.map((profile) => /* @__PURE__ */ jsx6(
|
|
1866
1969
|
ProfileCard,
|
|
1867
1970
|
{
|
|
1868
1971
|
profile,
|
|
@@ -1873,7 +1976,7 @@ function ProfilesPage({
|
|
|
1873
1976
|
)) })
|
|
1874
1977
|
] })
|
|
1875
1978
|
] }),
|
|
1876
|
-
/* @__PURE__ */
|
|
1979
|
+
/* @__PURE__ */ jsx6(
|
|
1877
1980
|
ProfileFormDialog,
|
|
1878
1981
|
{
|
|
1879
1982
|
open: createDialogOpen || !!editingProfile,
|
|
@@ -1891,7 +1994,7 @@ function ProfilesPage({
|
|
|
1891
1994
|
}
|
|
1892
1995
|
}
|
|
1893
1996
|
),
|
|
1894
|
-
/* @__PURE__ */
|
|
1997
|
+
/* @__PURE__ */ jsx6(
|
|
1895
1998
|
DeleteProfileDialog,
|
|
1896
1999
|
{
|
|
1897
2000
|
profile: deletingProfile,
|
|
@@ -1903,7 +2006,7 @@ function ProfilesPage({
|
|
|
1903
2006
|
}
|
|
1904
2007
|
}
|
|
1905
2008
|
),
|
|
1906
|
-
/* @__PURE__ */
|
|
2009
|
+
/* @__PURE__ */ jsx6(
|
|
1907
2010
|
ProfileDetailDialog,
|
|
1908
2011
|
{
|
|
1909
2012
|
profile: detailProfile,
|
|
@@ -1932,61 +2035,61 @@ function ProfileCard({
|
|
|
1932
2035
|
onDelete,
|
|
1933
2036
|
isBuiltin
|
|
1934
2037
|
}) {
|
|
1935
|
-
return /* @__PURE__ */
|
|
2038
|
+
return /* @__PURE__ */ jsxs6(
|
|
1936
2039
|
Card,
|
|
1937
2040
|
{
|
|
1938
2041
|
className: "cursor-pointer p-4 transition-colors hover:border-border/80",
|
|
1939
2042
|
onClick: onView,
|
|
1940
2043
|
children: [
|
|
1941
|
-
/* @__PURE__ */
|
|
1942
|
-
/* @__PURE__ */
|
|
1943
|
-
/* @__PURE__ */
|
|
1944
|
-
/* @__PURE__ */
|
|
1945
|
-
isBuiltin && /* @__PURE__ */
|
|
1946
|
-
profile.is_public && !isBuiltin && /* @__PURE__ */
|
|
2044
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-start justify-between", children: [
|
|
2045
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex-1", children: [
|
|
2046
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
2047
|
+
/* @__PURE__ */ jsx6("h3", { className: "font-medium", children: profile.name }),
|
|
2048
|
+
isBuiltin && /* @__PURE__ */ jsx6(Badge2, { variant: "secondary", className: "border-0 text-xs", children: "Built-in" }),
|
|
2049
|
+
profile.is_public && !isBuiltin && /* @__PURE__ */ jsx6(Badge2, { className: "border border-[var(--surface-info-border)] bg-[var(--surface-info-bg)] text-[var(--surface-info-text)] text-xs", children: "Public" })
|
|
1947
2050
|
] }),
|
|
1948
|
-
profile.description && /* @__PURE__ */
|
|
2051
|
+
profile.description && /* @__PURE__ */ jsx6("p", { className: "mt-1 line-clamp-2 text-muted-foreground text-sm", children: profile.description })
|
|
1949
2052
|
] }),
|
|
1950
|
-
!isBuiltin && /* @__PURE__ */
|
|
1951
|
-
onEdit && /* @__PURE__ */
|
|
2053
|
+
!isBuiltin && /* @__PURE__ */ jsxs6("div", { className: "flex gap-1", onClick: (e) => e.stopPropagation(), children: [
|
|
2054
|
+
onEdit && /* @__PURE__ */ jsx6(
|
|
1952
2055
|
Button2,
|
|
1953
2056
|
{
|
|
1954
2057
|
variant: "ghost",
|
|
1955
2058
|
size: "icon",
|
|
1956
2059
|
onClick: onEdit,
|
|
1957
2060
|
"aria-label": "Edit profile",
|
|
1958
|
-
children: /* @__PURE__ */
|
|
2061
|
+
children: /* @__PURE__ */ jsx6(Edit2, { className: "h-4 w-4" })
|
|
1959
2062
|
}
|
|
1960
2063
|
),
|
|
1961
|
-
onDelete && /* @__PURE__ */
|
|
2064
|
+
onDelete && /* @__PURE__ */ jsx6(
|
|
1962
2065
|
Button2,
|
|
1963
2066
|
{
|
|
1964
2067
|
variant: "ghost",
|
|
1965
2068
|
size: "icon",
|
|
1966
2069
|
onClick: onDelete,
|
|
1967
2070
|
"aria-label": "Delete profile",
|
|
1968
|
-
children: /* @__PURE__ */
|
|
2071
|
+
children: /* @__PURE__ */ jsx6(Trash22, { className: "h-4 w-4 text-[var(--surface-danger-text)]" })
|
|
1969
2072
|
}
|
|
1970
2073
|
)
|
|
1971
2074
|
] })
|
|
1972
2075
|
] }),
|
|
1973
|
-
/* @__PURE__ */
|
|
1974
|
-
profile.extends && /* @__PURE__ */
|
|
2076
|
+
/* @__PURE__ */ jsxs6("div", { className: "mt-3 flex flex-wrap gap-2", children: [
|
|
2077
|
+
profile.extends && /* @__PURE__ */ jsxs6(Badge2, { variant: "outline", className: "text-xs", children: [
|
|
1975
2078
|
"extends ",
|
|
1976
2079
|
profile.extends
|
|
1977
2080
|
] }),
|
|
1978
|
-
profile.model && /* @__PURE__ */
|
|
2081
|
+
profile.model && /* @__PURE__ */ jsx6(Badge2, { variant: "outline", className: "text-xs", children: profile.model.split("/").pop() })
|
|
1979
2082
|
] }),
|
|
1980
|
-
profile.metrics && profile.metrics.total_runs > 0 && /* @__PURE__ */
|
|
1981
|
-
/* @__PURE__ */
|
|
2083
|
+
profile.metrics && profile.metrics.total_runs > 0 && /* @__PURE__ */ jsxs6("div", { className: "mt-3 flex gap-4 border-border border-t pt-3 text-muted-foreground text-xs", children: [
|
|
2084
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1982
2085
|
profile.metrics.total_runs,
|
|
1983
2086
|
" runs"
|
|
1984
2087
|
] }),
|
|
1985
|
-
/* @__PURE__ */
|
|
2088
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1986
2089
|
profile.metrics.success_rate.toFixed(0),
|
|
1987
2090
|
"% success"
|
|
1988
2091
|
] }),
|
|
1989
|
-
/* @__PURE__ */
|
|
2092
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1990
2093
|
"~",
|
|
1991
2094
|
(profile.metrics.avg_duration_ms / 1e3).toFixed(1),
|
|
1992
2095
|
"s avg"
|
|
@@ -2005,7 +2108,7 @@ function ProfileFormDialog({
|
|
|
2005
2108
|
onSuccess
|
|
2006
2109
|
}) {
|
|
2007
2110
|
const isEditing = !!profile?.id;
|
|
2008
|
-
const [formData, setFormData] =
|
|
2111
|
+
const [formData, setFormData] = React5.useState({
|
|
2009
2112
|
name: "",
|
|
2010
2113
|
description: "",
|
|
2011
2114
|
extends: "",
|
|
@@ -2015,9 +2118,9 @@ function ProfileFormDialog({
|
|
|
2015
2118
|
tags: [],
|
|
2016
2119
|
is_public: false
|
|
2017
2120
|
});
|
|
2018
|
-
const [saving, setSaving] =
|
|
2019
|
-
const [error, setError] =
|
|
2020
|
-
|
|
2121
|
+
const [saving, setSaving] = React5.useState(false);
|
|
2122
|
+
const [error, setError] = React5.useState(null);
|
|
2123
|
+
React5.useEffect(() => {
|
|
2021
2124
|
if (profile) {
|
|
2022
2125
|
setFormData({
|
|
2023
2126
|
name: profile.name,
|
|
@@ -2073,19 +2176,19 @@ function ProfileFormDialog({
|
|
|
2073
2176
|
setSaving(false);
|
|
2074
2177
|
}
|
|
2075
2178
|
};
|
|
2076
|
-
return /* @__PURE__ */
|
|
2077
|
-
/* @__PURE__ */
|
|
2078
|
-
/* @__PURE__ */
|
|
2079
|
-
/* @__PURE__ */
|
|
2179
|
+
return /* @__PURE__ */ jsx6(Dialog2, { open, onOpenChange: (o) => !o && onClose(), children: /* @__PURE__ */ jsxs6(DialogContent2, { className: "max-w-2xl", children: [
|
|
2180
|
+
/* @__PURE__ */ jsxs6(DialogHeader2, { children: [
|
|
2181
|
+
/* @__PURE__ */ jsx6(DialogTitle2, { children: isEditing ? "Edit Profile" : "Create Profile" }),
|
|
2182
|
+
/* @__PURE__ */ jsx6(DialogDescription2, { children: isEditing ? "Update your custom profile configuration" : "Create a new profile to customize agent behavior" })
|
|
2080
2183
|
] }),
|
|
2081
|
-
/* @__PURE__ */
|
|
2082
|
-
error && /* @__PURE__ */
|
|
2083
|
-
/* @__PURE__ */
|
|
2084
|
-
/* @__PURE__ */
|
|
2184
|
+
/* @__PURE__ */ jsxs6("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
2185
|
+
error && /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 rounded-lg border border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] p-3 text-[var(--surface-danger-text)] text-sm", children: [
|
|
2186
|
+
/* @__PURE__ */ jsx6(AlertCircle, { className: "h-4 w-4" }),
|
|
2187
|
+
/* @__PURE__ */ jsx6("span", { children: error })
|
|
2085
2188
|
] }),
|
|
2086
|
-
/* @__PURE__ */
|
|
2087
|
-
/* @__PURE__ */
|
|
2088
|
-
/* @__PURE__ */
|
|
2189
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2190
|
+
/* @__PURE__ */ jsx6("label", { className: "mb-1 block font-medium text-sm", children: "Name *" }),
|
|
2191
|
+
/* @__PURE__ */ jsx6(
|
|
2089
2192
|
Input2,
|
|
2090
2193
|
{
|
|
2091
2194
|
value: formData.name,
|
|
@@ -2097,9 +2200,9 @@ function ProfileFormDialog({
|
|
|
2097
2200
|
}
|
|
2098
2201
|
)
|
|
2099
2202
|
] }),
|
|
2100
|
-
/* @__PURE__ */
|
|
2101
|
-
/* @__PURE__ */
|
|
2102
|
-
/* @__PURE__ */
|
|
2203
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2204
|
+
/* @__PURE__ */ jsx6("label", { className: "mb-1 block font-medium text-sm", children: "Description" }),
|
|
2205
|
+
/* @__PURE__ */ jsx6(
|
|
2103
2206
|
Input2,
|
|
2104
2207
|
{
|
|
2105
2208
|
value: formData.description,
|
|
@@ -2108,17 +2211,17 @@ function ProfileFormDialog({
|
|
|
2108
2211
|
}
|
|
2109
2212
|
)
|
|
2110
2213
|
] }),
|
|
2111
|
-
/* @__PURE__ */
|
|
2112
|
-
/* @__PURE__ */
|
|
2113
|
-
/* @__PURE__ */
|
|
2214
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2215
|
+
/* @__PURE__ */ jsx6("label", { className: "mb-1 block font-medium text-sm", children: "Extends (base profile)" }),
|
|
2216
|
+
/* @__PURE__ */ jsxs6(
|
|
2114
2217
|
"select",
|
|
2115
2218
|
{
|
|
2116
2219
|
value: formData.extends,
|
|
2117
2220
|
onChange: (e) => setFormData((d) => ({ ...d, extends: e.target.value })),
|
|
2118
2221
|
className: "w-full rounded-md border border-border bg-background px-3 py-2 text-sm",
|
|
2119
2222
|
children: [
|
|
2120
|
-
/* @__PURE__ */
|
|
2121
|
-
builtinProfiles.map((p) => /* @__PURE__ */
|
|
2223
|
+
/* @__PURE__ */ jsx6("option", { value: "", children: "None (start from scratch)" }),
|
|
2224
|
+
builtinProfiles.map((p) => /* @__PURE__ */ jsxs6("option", { value: p.name, children: [
|
|
2122
2225
|
p.name,
|
|
2123
2226
|
" - ",
|
|
2124
2227
|
p.description ?? "Built-in profile"
|
|
@@ -2127,9 +2230,9 @@ function ProfileFormDialog({
|
|
|
2127
2230
|
}
|
|
2128
2231
|
)
|
|
2129
2232
|
] }),
|
|
2130
|
-
/* @__PURE__ */
|
|
2131
|
-
/* @__PURE__ */
|
|
2132
|
-
/* @__PURE__ */
|
|
2233
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2234
|
+
/* @__PURE__ */ jsx6("label", { className: "mb-1 block font-medium text-sm", children: "Model" }),
|
|
2235
|
+
/* @__PURE__ */ jsx6(
|
|
2133
2236
|
Input2,
|
|
2134
2237
|
{
|
|
2135
2238
|
value: formData.model,
|
|
@@ -2137,11 +2240,11 @@ function ProfileFormDialog({
|
|
|
2137
2240
|
placeholder: "anthropic/claude-sonnet-4"
|
|
2138
2241
|
}
|
|
2139
2242
|
),
|
|
2140
|
-
/* @__PURE__ */
|
|
2243
|
+
/* @__PURE__ */ jsx6("p", { className: "mt-1 text-muted-foreground text-xs", children: "Format: provider/model-id (e.g., anthropic/claude-sonnet-4)" })
|
|
2141
2244
|
] }),
|
|
2142
|
-
/* @__PURE__ */
|
|
2143
|
-
/* @__PURE__ */
|
|
2144
|
-
/* @__PURE__ */
|
|
2245
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2246
|
+
/* @__PURE__ */ jsx6("label", { className: "mb-1 block font-medium text-sm", children: "System Prompt" }),
|
|
2247
|
+
/* @__PURE__ */ jsx6(
|
|
2145
2248
|
"textarea",
|
|
2146
2249
|
{
|
|
2147
2250
|
value: formData.system_prompt,
|
|
@@ -2152,9 +2255,9 @@ function ProfileFormDialog({
|
|
|
2152
2255
|
}
|
|
2153
2256
|
)
|
|
2154
2257
|
] }),
|
|
2155
|
-
/* @__PURE__ */
|
|
2156
|
-
/* @__PURE__ */
|
|
2157
|
-
/* @__PURE__ */
|
|
2258
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2259
|
+
/* @__PURE__ */ jsx6("label", { className: "mb-1 block font-medium text-sm", children: "Tags" }),
|
|
2260
|
+
/* @__PURE__ */ jsx6(
|
|
2158
2261
|
Input2,
|
|
2159
2262
|
{
|
|
2160
2263
|
value: formData.tags?.join(", "),
|
|
@@ -2165,10 +2268,10 @@ function ProfileFormDialog({
|
|
|
2165
2268
|
placeholder: "trading, aggressive, experimental"
|
|
2166
2269
|
}
|
|
2167
2270
|
),
|
|
2168
|
-
/* @__PURE__ */
|
|
2271
|
+
/* @__PURE__ */ jsx6("p", { className: "mt-1 text-muted-foreground text-xs", children: "Comma-separated tags for organization" })
|
|
2169
2272
|
] }),
|
|
2170
|
-
/* @__PURE__ */
|
|
2171
|
-
/* @__PURE__ */
|
|
2273
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
2274
|
+
/* @__PURE__ */ jsx6(
|
|
2172
2275
|
"input",
|
|
2173
2276
|
{
|
|
2174
2277
|
type: "checkbox",
|
|
@@ -2178,12 +2281,12 @@ function ProfileFormDialog({
|
|
|
2178
2281
|
className: "rounded border-border"
|
|
2179
2282
|
}
|
|
2180
2283
|
),
|
|
2181
|
-
/* @__PURE__ */
|
|
2284
|
+
/* @__PURE__ */ jsx6("label", { htmlFor: "is_public", className: "text-sm", children: "Make this profile public (visible to other users)" })
|
|
2182
2285
|
] }),
|
|
2183
|
-
/* @__PURE__ */
|
|
2184
|
-
/* @__PURE__ */
|
|
2185
|
-
/* @__PURE__ */
|
|
2186
|
-
saving && /* @__PURE__ */
|
|
2286
|
+
/* @__PURE__ */ jsxs6(DialogFooter2, { children: [
|
|
2287
|
+
/* @__PURE__ */ jsx6(Button2, { type: "button", variant: "outline", onClick: onClose, children: "Cancel" }),
|
|
2288
|
+
/* @__PURE__ */ jsxs6(Button2, { type: "submit", disabled: saving || !formData.name, children: [
|
|
2289
|
+
saving && /* @__PURE__ */ jsx6(Loader23, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
2187
2290
|
isEditing ? "Save Changes" : "Create Profile"
|
|
2188
2291
|
] })
|
|
2189
2292
|
] })
|
|
@@ -2196,8 +2299,8 @@ function DeleteProfileDialog({
|
|
|
2196
2299
|
apiClient,
|
|
2197
2300
|
onSuccess
|
|
2198
2301
|
}) {
|
|
2199
|
-
const [deleting, setDeleting] =
|
|
2200
|
-
const [error, setError] =
|
|
2302
|
+
const [deleting, setDeleting] = React5.useState(false);
|
|
2303
|
+
const [error, setError] = React5.useState(null);
|
|
2201
2304
|
const handleDelete = async () => {
|
|
2202
2305
|
if (!profile) return;
|
|
2203
2306
|
setError(null);
|
|
@@ -2211,34 +2314,34 @@ function DeleteProfileDialog({
|
|
|
2211
2314
|
setDeleting(false);
|
|
2212
2315
|
}
|
|
2213
2316
|
};
|
|
2214
|
-
return /* @__PURE__ */
|
|
2215
|
-
/* @__PURE__ */
|
|
2216
|
-
/* @__PURE__ */
|
|
2217
|
-
/* @__PURE__ */
|
|
2317
|
+
return /* @__PURE__ */ jsx6(Dialog2, { open: !!profile, onOpenChange: (o) => !o && onClose(), children: /* @__PURE__ */ jsxs6(DialogContent2, { children: [
|
|
2318
|
+
/* @__PURE__ */ jsxs6(DialogHeader2, { children: [
|
|
2319
|
+
/* @__PURE__ */ jsx6(DialogTitle2, { children: "Delete Profile" }),
|
|
2320
|
+
/* @__PURE__ */ jsxs6(DialogDescription2, { children: [
|
|
2218
2321
|
'Are you sure you want to delete "',
|
|
2219
2322
|
profile?.name,
|
|
2220
2323
|
'"? This action cannot be undone.'
|
|
2221
2324
|
] })
|
|
2222
2325
|
] }),
|
|
2223
|
-
error && /* @__PURE__ */
|
|
2224
|
-
/* @__PURE__ */
|
|
2225
|
-
/* @__PURE__ */
|
|
2326
|
+
error && /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 rounded-lg border border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] p-3 text-[var(--surface-danger-text)] text-sm", children: [
|
|
2327
|
+
/* @__PURE__ */ jsx6(AlertCircle, { className: "h-4 w-4" }),
|
|
2328
|
+
/* @__PURE__ */ jsx6("span", { children: error })
|
|
2226
2329
|
] }),
|
|
2227
|
-
profile?.metrics && profile.metrics.total_runs > 0 && /* @__PURE__ */
|
|
2330
|
+
profile?.metrics && profile.metrics.total_runs > 0 && /* @__PURE__ */ jsxs6("div", { className: "rounded-lg border border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)] p-3 text-sm text-[var(--surface-warning-text)]", children: [
|
|
2228
2331
|
"This profile has ",
|
|
2229
2332
|
profile.metrics.total_runs,
|
|
2230
2333
|
" recorded runs. Deleting it will lose all performance metrics."
|
|
2231
2334
|
] }),
|
|
2232
|
-
/* @__PURE__ */
|
|
2233
|
-
/* @__PURE__ */
|
|
2234
|
-
/* @__PURE__ */
|
|
2335
|
+
/* @__PURE__ */ jsxs6(DialogFooter2, { children: [
|
|
2336
|
+
/* @__PURE__ */ jsx6(Button2, { variant: "outline", onClick: onClose, children: "Cancel" }),
|
|
2337
|
+
/* @__PURE__ */ jsxs6(
|
|
2235
2338
|
Button2,
|
|
2236
2339
|
{
|
|
2237
2340
|
variant: "destructive",
|
|
2238
2341
|
onClick: handleDelete,
|
|
2239
2342
|
disabled: deleting,
|
|
2240
2343
|
children: [
|
|
2241
|
-
deleting && /* @__PURE__ */
|
|
2344
|
+
deleting && /* @__PURE__ */ jsx6(Loader23, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
2242
2345
|
"Delete Profile"
|
|
2243
2346
|
]
|
|
2244
2347
|
}
|
|
@@ -2253,35 +2356,35 @@ function ProfileDetailDialog({
|
|
|
2253
2356
|
onDuplicate
|
|
2254
2357
|
}) {
|
|
2255
2358
|
if (!profile) return null;
|
|
2256
|
-
return /* @__PURE__ */
|
|
2257
|
-
/* @__PURE__ */
|
|
2258
|
-
/* @__PURE__ */
|
|
2259
|
-
/* @__PURE__ */
|
|
2260
|
-
profile.is_builtin && /* @__PURE__ */
|
|
2261
|
-
profile.is_public && !profile.is_builtin && /* @__PURE__ */
|
|
2359
|
+
return /* @__PURE__ */ jsx6(Dialog2, { open: !!profile, onOpenChange: (o) => !o && onClose(), children: /* @__PURE__ */ jsxs6(DialogContent2, { className: "max-w-2xl", children: [
|
|
2360
|
+
/* @__PURE__ */ jsxs6(DialogHeader2, { children: [
|
|
2361
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
2362
|
+
/* @__PURE__ */ jsx6(DialogTitle2, { children: profile.name }),
|
|
2363
|
+
profile.is_builtin && /* @__PURE__ */ jsx6(Badge2, { variant: "secondary", className: "border-0", children: "Built-in" }),
|
|
2364
|
+
profile.is_public && !profile.is_builtin && /* @__PURE__ */ jsx6(Badge2, { className: "border border-[var(--surface-info-border)] bg-[var(--surface-info-bg)] text-[var(--surface-info-text)]", children: "Public" })
|
|
2262
2365
|
] }),
|
|
2263
|
-
profile.description && /* @__PURE__ */
|
|
2366
|
+
profile.description && /* @__PURE__ */ jsx6(DialogDescription2, { children: profile.description })
|
|
2264
2367
|
] }),
|
|
2265
|
-
/* @__PURE__ */
|
|
2266
|
-
/* @__PURE__ */
|
|
2267
|
-
profile.extends && /* @__PURE__ */
|
|
2268
|
-
/* @__PURE__ */
|
|
2269
|
-
/* @__PURE__ */
|
|
2368
|
+
/* @__PURE__ */ jsxs6("div", { className: "space-y-4", children: [
|
|
2369
|
+
/* @__PURE__ */ jsxs6("div", { className: "grid gap-4 sm:grid-cols-2", children: [
|
|
2370
|
+
profile.extends && /* @__PURE__ */ jsxs6("div", { children: [
|
|
2371
|
+
/* @__PURE__ */ jsx6("label", { className: "font-medium text-muted-foreground text-xs", children: "Extends" }),
|
|
2372
|
+
/* @__PURE__ */ jsx6("p", { className: "text-sm", children: profile.extends })
|
|
2270
2373
|
] }),
|
|
2271
|
-
profile.model && /* @__PURE__ */
|
|
2272
|
-
/* @__PURE__ */
|
|
2273
|
-
/* @__PURE__ */
|
|
2374
|
+
profile.model && /* @__PURE__ */ jsxs6("div", { children: [
|
|
2375
|
+
/* @__PURE__ */ jsx6("label", { className: "font-medium text-muted-foreground text-xs", children: "Model" }),
|
|
2376
|
+
/* @__PURE__ */ jsx6("p", { className: "text-sm", children: profile.model })
|
|
2274
2377
|
] })
|
|
2275
2378
|
] }),
|
|
2276
|
-
profile.tags && profile.tags.length > 0 && /* @__PURE__ */
|
|
2277
|
-
/* @__PURE__ */
|
|
2278
|
-
/* @__PURE__ */
|
|
2379
|
+
profile.tags && profile.tags.length > 0 && /* @__PURE__ */ jsxs6("div", { children: [
|
|
2380
|
+
/* @__PURE__ */ jsx6("label", { className: "font-medium text-muted-foreground text-xs", children: "Tags" }),
|
|
2381
|
+
/* @__PURE__ */ jsx6("div", { className: "mt-1 flex flex-wrap gap-1", children: profile.tags.map((tag) => /* @__PURE__ */ jsx6(Badge2, { variant: "outline", className: "text-xs", children: tag }, tag)) })
|
|
2279
2382
|
] }),
|
|
2280
|
-
profile.system_prompt && /* @__PURE__ */
|
|
2281
|
-
/* @__PURE__ */
|
|
2282
|
-
/* @__PURE__ */
|
|
2283
|
-
/* @__PURE__ */
|
|
2284
|
-
/* @__PURE__ */
|
|
2383
|
+
profile.system_prompt && /* @__PURE__ */ jsxs6("div", { children: [
|
|
2384
|
+
/* @__PURE__ */ jsx6("label", { className: "font-medium text-muted-foreground text-xs", children: "System Prompt" }),
|
|
2385
|
+
/* @__PURE__ */ jsxs6("div", { className: "relative mt-1", children: [
|
|
2386
|
+
/* @__PURE__ */ jsx6("pre", { className: "max-h-48 overflow-auto rounded-lg bg-muted p-3 font-mono text-sm", children: profile.system_prompt }),
|
|
2387
|
+
/* @__PURE__ */ jsx6(
|
|
2285
2388
|
Button2,
|
|
2286
2389
|
{
|
|
2287
2390
|
variant: "ghost",
|
|
@@ -2289,54 +2392,54 @@ function ProfileDetailDialog({
|
|
|
2289
2392
|
className: "absolute top-2 right-2",
|
|
2290
2393
|
onClick: () => navigator.clipboard.writeText(profile.system_prompt),
|
|
2291
2394
|
"aria-label": "Copy system prompt",
|
|
2292
|
-
children: /* @__PURE__ */
|
|
2395
|
+
children: /* @__PURE__ */ jsx6(Copy, { className: "h-4 w-4" })
|
|
2293
2396
|
}
|
|
2294
2397
|
)
|
|
2295
2398
|
] })
|
|
2296
2399
|
] }),
|
|
2297
|
-
profile.instructions && profile.instructions.length > 0 && /* @__PURE__ */
|
|
2298
|
-
/* @__PURE__ */
|
|
2299
|
-
/* @__PURE__ */
|
|
2300
|
-
/* @__PURE__ */
|
|
2400
|
+
profile.instructions && profile.instructions.length > 0 && /* @__PURE__ */ jsxs6("div", { children: [
|
|
2401
|
+
/* @__PURE__ */ jsx6("label", { className: "font-medium text-muted-foreground text-xs", children: "Instructions" }),
|
|
2402
|
+
/* @__PURE__ */ jsx6("ul", { className: "mt-1 space-y-1", children: profile.instructions.map((inst, i) => /* @__PURE__ */ jsxs6("li", { className: "flex items-start gap-2 text-sm", children: [
|
|
2403
|
+
/* @__PURE__ */ jsx6(ChevronRight, { className: "mt-0.5 h-4 w-4 text-muted-foreground" }),
|
|
2301
2404
|
inst
|
|
2302
2405
|
] }, i)) })
|
|
2303
2406
|
] }),
|
|
2304
|
-
profile.metrics && profile.metrics.total_runs > 0 && /* @__PURE__ */
|
|
2305
|
-
/* @__PURE__ */
|
|
2306
|
-
/* @__PURE__ */
|
|
2307
|
-
/* @__PURE__ */
|
|
2308
|
-
/* @__PURE__ */
|
|
2309
|
-
/* @__PURE__ */
|
|
2407
|
+
profile.metrics && profile.metrics.total_runs > 0 && /* @__PURE__ */ jsxs6("div", { className: "rounded-lg border border-border p-4", children: [
|
|
2408
|
+
/* @__PURE__ */ jsx6("label", { className: "font-medium text-muted-foreground text-xs", children: "Performance Metrics" }),
|
|
2409
|
+
/* @__PURE__ */ jsxs6("div", { className: "mt-2 grid grid-cols-2 gap-4 sm:grid-cols-4", children: [
|
|
2410
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2411
|
+
/* @__PURE__ */ jsx6("p", { className: "font-medium text-2xl", children: profile.metrics.total_runs }),
|
|
2412
|
+
/* @__PURE__ */ jsx6("p", { className: "text-muted-foreground text-xs", children: "Total Runs" })
|
|
2310
2413
|
] }),
|
|
2311
|
-
/* @__PURE__ */
|
|
2312
|
-
/* @__PURE__ */
|
|
2414
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2415
|
+
/* @__PURE__ */ jsxs6("p", { className: "font-medium text-2xl", children: [
|
|
2313
2416
|
profile.metrics.success_rate.toFixed(0),
|
|
2314
2417
|
"%"
|
|
2315
2418
|
] }),
|
|
2316
|
-
/* @__PURE__ */
|
|
2419
|
+
/* @__PURE__ */ jsx6("p", { className: "text-muted-foreground text-xs", children: "Success Rate" })
|
|
2317
2420
|
] }),
|
|
2318
|
-
/* @__PURE__ */
|
|
2319
|
-
/* @__PURE__ */
|
|
2421
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2422
|
+
/* @__PURE__ */ jsxs6("p", { className: "font-medium text-2xl", children: [
|
|
2320
2423
|
(profile.metrics.avg_duration_ms / 1e3).toFixed(1),
|
|
2321
2424
|
"s"
|
|
2322
2425
|
] }),
|
|
2323
|
-
/* @__PURE__ */
|
|
2426
|
+
/* @__PURE__ */ jsx6("p", { className: "text-muted-foreground text-xs", children: "Avg Duration" })
|
|
2324
2427
|
] }),
|
|
2325
|
-
profile.metrics.avg_tokens_used && /* @__PURE__ */
|
|
2326
|
-
/* @__PURE__ */
|
|
2327
|
-
/* @__PURE__ */
|
|
2428
|
+
profile.metrics.avg_tokens_used && /* @__PURE__ */ jsxs6("div", { children: [
|
|
2429
|
+
/* @__PURE__ */ jsx6("p", { className: "font-medium text-2xl", children: profile.metrics.avg_tokens_used.toLocaleString() }),
|
|
2430
|
+
/* @__PURE__ */ jsx6("p", { className: "text-muted-foreground text-xs", children: "Avg Tokens" })
|
|
2328
2431
|
] })
|
|
2329
2432
|
] })
|
|
2330
2433
|
] })
|
|
2331
2434
|
] }),
|
|
2332
|
-
/* @__PURE__ */
|
|
2333
|
-
/* @__PURE__ */
|
|
2334
|
-
onDuplicate && /* @__PURE__ */
|
|
2335
|
-
/* @__PURE__ */
|
|
2435
|
+
/* @__PURE__ */ jsxs6(DialogFooter2, { children: [
|
|
2436
|
+
/* @__PURE__ */ jsx6(Button2, { variant: "outline", onClick: onClose, children: "Close" }),
|
|
2437
|
+
onDuplicate && /* @__PURE__ */ jsxs6(Button2, { variant: "outline", onClick: onDuplicate, children: [
|
|
2438
|
+
/* @__PURE__ */ jsx6(Copy, { className: "mr-2 h-4 w-4" }),
|
|
2336
2439
|
"Duplicate"
|
|
2337
2440
|
] }),
|
|
2338
|
-
onEdit && /* @__PURE__ */
|
|
2339
|
-
/* @__PURE__ */
|
|
2441
|
+
onEdit && /* @__PURE__ */ jsxs6(Button2, { onClick: onEdit, children: [
|
|
2442
|
+
/* @__PURE__ */ jsx6(Edit2, { className: "mr-2 h-4 w-4" }),
|
|
2340
2443
|
"Edit"
|
|
2341
2444
|
] })
|
|
2342
2445
|
] })
|
|
@@ -2344,33 +2447,104 @@ function ProfileDetailDialog({
|
|
|
2344
2447
|
}
|
|
2345
2448
|
|
|
2346
2449
|
// src/pages/secrets-page.tsx
|
|
2347
|
-
import * as
|
|
2348
|
-
import { Lock, Plus as Plus3, Trash2 as Trash23, Eye, EyeOff, AlertCircle as AlertCircle2, Key, Shield, CheckCircle, Users, ArrowRight } from "lucide-react";
|
|
2450
|
+
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";
|
|
2349
2452
|
import {
|
|
2350
|
-
Dialog as
|
|
2351
|
-
DialogContent as
|
|
2352
|
-
DialogDescription as
|
|
2353
|
-
DialogFooter as
|
|
2354
|
-
DialogHeader as
|
|
2355
|
-
DialogTitle as
|
|
2453
|
+
Dialog as Dialog3,
|
|
2454
|
+
DialogContent as DialogContent3,
|
|
2455
|
+
DialogDescription as DialogDescription3,
|
|
2456
|
+
DialogFooter as DialogFooter3,
|
|
2457
|
+
DialogHeader as DialogHeader3,
|
|
2458
|
+
DialogTitle as DialogTitle3
|
|
2356
2459
|
} from "@tangle-network/ui/primitives";
|
|
2357
|
-
|
|
2460
|
+
|
|
2461
|
+
// src/pages/env-importer.ts
|
|
2462
|
+
var NORMALIZE_RE = /[^A-Z0-9_]/g;
|
|
2463
|
+
function normalizeKey(rawKey) {
|
|
2464
|
+
return rawKey.toUpperCase().replace(NORMALIZE_RE, "_");
|
|
2465
|
+
}
|
|
2466
|
+
function stripMatchingQuotes(value) {
|
|
2467
|
+
if (value.length >= 2) {
|
|
2468
|
+
const quote = value[0];
|
|
2469
|
+
if ((quote === '"' || quote === "'") && value[value.length - 1] === quote) {
|
|
2470
|
+
const inner = value.slice(1, -1);
|
|
2471
|
+
if (!inner.includes(quote)) {
|
|
2472
|
+
return inner;
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
return value;
|
|
2477
|
+
}
|
|
2478
|
+
function parseEnvText(text) {
|
|
2479
|
+
const rows = [];
|
|
2480
|
+
const errors = [];
|
|
2481
|
+
const lines = text.split(/\r?\n/);
|
|
2482
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2483
|
+
const lineNumber = i + 1;
|
|
2484
|
+
const rawLine = lines[i];
|
|
2485
|
+
const trimmed = rawLine.trim();
|
|
2486
|
+
if (trimmed === "" || trimmed.startsWith("#")) continue;
|
|
2487
|
+
let rest = trimmed;
|
|
2488
|
+
const exportMatch = /^export\s+/.exec(rest);
|
|
2489
|
+
if (exportMatch) rest = rest.slice(exportMatch[0].length);
|
|
2490
|
+
const eqIdx = rest.indexOf("=");
|
|
2491
|
+
if (eqIdx === -1) {
|
|
2492
|
+
errors.push({ lineNumber, message: "Missing '=' separator", rawLine });
|
|
2493
|
+
continue;
|
|
2494
|
+
}
|
|
2495
|
+
const rawKey = rest.slice(0, eqIdx).trim();
|
|
2496
|
+
const rawValue = rest.slice(eqIdx + 1).trim();
|
|
2497
|
+
if (rawKey === "") {
|
|
2498
|
+
errors.push({ lineNumber, message: "Missing key before '='", rawLine });
|
|
2499
|
+
continue;
|
|
2500
|
+
}
|
|
2501
|
+
const key = normalizeKey(rawKey);
|
|
2502
|
+
if (!/[A-Z0-9]/.test(key)) {
|
|
2503
|
+
errors.push({
|
|
2504
|
+
lineNumber,
|
|
2505
|
+
message: "Key has no valid characters (letters or digits)",
|
|
2506
|
+
rawLine
|
|
2507
|
+
});
|
|
2508
|
+
continue;
|
|
2509
|
+
}
|
|
2510
|
+
rows.push({
|
|
2511
|
+
key,
|
|
2512
|
+
rawKey,
|
|
2513
|
+
value: stripMatchingQuotes(rawValue),
|
|
2514
|
+
lineNumber
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
return { rows, errors };
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
// src/pages/secrets-page.tsx
|
|
2521
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2522
|
+
var MAX_IMPORT_FILE_BYTES = 256 * 1024;
|
|
2358
2523
|
function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
2359
|
-
const [secrets, setSecrets] =
|
|
2360
|
-
const [loading, setLoading] =
|
|
2361
|
-
const [error, setError] =
|
|
2362
|
-
const [isCreateOpen, setIsCreateOpen] =
|
|
2363
|
-
const [newName, setNewName] =
|
|
2364
|
-
const [newValue, setNewValue] =
|
|
2365
|
-
const [showValue, setShowValue] =
|
|
2366
|
-
const [isCreating, setIsCreating] =
|
|
2367
|
-
const [createError, setCreateError] =
|
|
2368
|
-
const [deleteTarget, setDeleteTarget] =
|
|
2369
|
-
const [isDeleting, setIsDeleting] =
|
|
2370
|
-
const
|
|
2524
|
+
const [secrets, setSecrets] = React6.useState([]);
|
|
2525
|
+
const [loading, setLoading] = React6.useState(true);
|
|
2526
|
+
const [error, setError] = React6.useState(null);
|
|
2527
|
+
const [isCreateOpen, setIsCreateOpen] = React6.useState(false);
|
|
2528
|
+
const [newName, setNewName] = React6.useState("");
|
|
2529
|
+
const [newValue, setNewValue] = React6.useState("");
|
|
2530
|
+
const [showValue, setShowValue] = React6.useState(false);
|
|
2531
|
+
const [isCreating, setIsCreating] = React6.useState(false);
|
|
2532
|
+
const [createError, setCreateError] = React6.useState(null);
|
|
2533
|
+
const [deleteTarget, setDeleteTarget] = React6.useState(null);
|
|
2534
|
+
const [isDeleting, setIsDeleting] = React6.useState(false);
|
|
2535
|
+
const [isImportOpen, setIsImportOpen] = React6.useState(false);
|
|
2536
|
+
const [importText, setImportText] = React6.useState("");
|
|
2537
|
+
const [importResult, setImportResult] = React6.useState(null);
|
|
2538
|
+
const [rowStatus, setRowStatus] = React6.useState([]);
|
|
2539
|
+
const [rowMessages, setRowMessages] = React6.useState([]);
|
|
2540
|
+
const [isImportSaving, setIsImportSaving] = React6.useState(false);
|
|
2541
|
+
const [showImportValues, setShowImportValues] = React6.useState(false);
|
|
2542
|
+
const [importFileError, setImportFileError] = React6.useState(null);
|
|
2543
|
+
const fileInputRef = React6.useRef(null);
|
|
2544
|
+
const apiRef = React6.useRef(apiClient);
|
|
2371
2545
|
apiRef.current = apiClient;
|
|
2372
|
-
const loadGenRef =
|
|
2373
|
-
const loadSecrets =
|
|
2546
|
+
const loadGenRef = React6.useRef(0);
|
|
2547
|
+
const loadSecrets = React6.useCallback(async (showSpinner = true) => {
|
|
2374
2548
|
const gen = ++loadGenRef.current;
|
|
2375
2549
|
try {
|
|
2376
2550
|
if (showSpinner) setLoading(true);
|
|
@@ -2385,7 +2559,7 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2385
2559
|
if (gen === loadGenRef.current) setLoading(false);
|
|
2386
2560
|
}
|
|
2387
2561
|
}, []);
|
|
2388
|
-
|
|
2562
|
+
React6.useEffect(() => {
|
|
2389
2563
|
loadSecrets();
|
|
2390
2564
|
}, [loadSecrets]);
|
|
2391
2565
|
const handleCreate = async () => {
|
|
@@ -2417,6 +2591,100 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2417
2591
|
setIsDeleting(false);
|
|
2418
2592
|
}
|
|
2419
2593
|
};
|
|
2594
|
+
const resetImportState = () => {
|
|
2595
|
+
setImportText("");
|
|
2596
|
+
setImportResult(null);
|
|
2597
|
+
setRowStatus([]);
|
|
2598
|
+
setRowMessages([]);
|
|
2599
|
+
setShowImportValues(false);
|
|
2600
|
+
setImportFileError(null);
|
|
2601
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
2602
|
+
};
|
|
2603
|
+
const runParse = (text) => {
|
|
2604
|
+
const result = parseEnvText(text);
|
|
2605
|
+
setImportResult(result);
|
|
2606
|
+
setRowStatus(new Array(result.rows.length).fill("idle"));
|
|
2607
|
+
setRowMessages(new Array(result.rows.length).fill(""));
|
|
2608
|
+
};
|
|
2609
|
+
const handleParse = () => {
|
|
2610
|
+
runParse(importText);
|
|
2611
|
+
};
|
|
2612
|
+
const handleImportFile = async (file) => {
|
|
2613
|
+
if (!file) return;
|
|
2614
|
+
setImportFileError(null);
|
|
2615
|
+
if (file.size > MAX_IMPORT_FILE_BYTES) {
|
|
2616
|
+
setImportFileError(`File is too large (${Math.round(file.size / 1024)} KiB). Limit is ${MAX_IMPORT_FILE_BYTES / 1024} KiB.`);
|
|
2617
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
2618
|
+
return;
|
|
2619
|
+
}
|
|
2620
|
+
const text = await file.text();
|
|
2621
|
+
setImportText(text);
|
|
2622
|
+
runParse(text);
|
|
2623
|
+
};
|
|
2624
|
+
const updateRowKey = (index, next) => {
|
|
2625
|
+
setImportResult((prev) => {
|
|
2626
|
+
if (!prev) return prev;
|
|
2627
|
+
const rows = prev.rows.slice();
|
|
2628
|
+
rows[index] = { ...rows[index], key: next.toUpperCase().replace(/[^A-Z0-9_]/g, "_") };
|
|
2629
|
+
return { ...prev, rows };
|
|
2630
|
+
});
|
|
2631
|
+
};
|
|
2632
|
+
const updateRowValue = (index, next) => {
|
|
2633
|
+
setImportResult((prev) => {
|
|
2634
|
+
if (!prev) return prev;
|
|
2635
|
+
const rows = prev.rows.slice();
|
|
2636
|
+
rows[index] = { ...rows[index], value: next };
|
|
2637
|
+
return { ...prev, rows };
|
|
2638
|
+
});
|
|
2639
|
+
};
|
|
2640
|
+
const removeImportRow = (index) => {
|
|
2641
|
+
setImportResult((prev) => {
|
|
2642
|
+
if (!prev) return prev;
|
|
2643
|
+
const rows = prev.rows.slice();
|
|
2644
|
+
rows.splice(index, 1);
|
|
2645
|
+
return { ...prev, rows };
|
|
2646
|
+
});
|
|
2647
|
+
setRowStatus((prev) => {
|
|
2648
|
+
const next = prev.slice();
|
|
2649
|
+
next.splice(index, 1);
|
|
2650
|
+
return next;
|
|
2651
|
+
});
|
|
2652
|
+
setRowMessages((prev) => {
|
|
2653
|
+
const next = prev.slice();
|
|
2654
|
+
next.splice(index, 1);
|
|
2655
|
+
return next;
|
|
2656
|
+
});
|
|
2657
|
+
};
|
|
2658
|
+
const importRows = importResult?.rows ?? [];
|
|
2659
|
+
const hasImportErrors = !!(importResult && importResult.errors.length > 0);
|
|
2660
|
+
const importSaveDisabled = isImportSaving || importRows.length === 0 || hasImportErrors || importRows.some((r) => !r.key || !/[A-Z0-9]/.test(r.key) || !r.value.trim());
|
|
2661
|
+
const handleImportSave = async () => {
|
|
2662
|
+
if (!importResult || importSaveDisabled) return;
|
|
2663
|
+
const rows = importResult.rows;
|
|
2664
|
+
setIsImportSaving(true);
|
|
2665
|
+
const statuses = new Array(rows.length).fill("idle");
|
|
2666
|
+
const messages = new Array(rows.length).fill("");
|
|
2667
|
+
try {
|
|
2668
|
+
for (let i = 0; i < rows.length; i++) {
|
|
2669
|
+
try {
|
|
2670
|
+
await apiRef.current.createSecret(rows[i].key, rows[i].value);
|
|
2671
|
+
statuses[i] = "success";
|
|
2672
|
+
} catch (err) {
|
|
2673
|
+
statuses[i] = "error";
|
|
2674
|
+
messages[i] = err instanceof Error ? err.message : "Failed to create secret";
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
setRowStatus(statuses);
|
|
2678
|
+
setRowMessages(messages);
|
|
2679
|
+
await loadSecrets(false);
|
|
2680
|
+
if (statuses.every((s) => s === "success")) {
|
|
2681
|
+
setIsImportOpen(false);
|
|
2682
|
+
resetImportState();
|
|
2683
|
+
}
|
|
2684
|
+
} finally {
|
|
2685
|
+
setIsImportSaving(false);
|
|
2686
|
+
}
|
|
2687
|
+
};
|
|
2420
2688
|
const formatDate = (dateStr) => {
|
|
2421
2689
|
try {
|
|
2422
2690
|
const ts = /^\d+$/.test(dateStr) ? Number(dateStr) : dateStr;
|
|
@@ -2427,36 +2695,50 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2427
2695
|
return dateStr;
|
|
2428
2696
|
}
|
|
2429
2697
|
};
|
|
2430
|
-
return /* @__PURE__ */
|
|
2431
|
-
/* @__PURE__ */
|
|
2432
|
-
/* @__PURE__ */
|
|
2433
|
-
/* @__PURE__ */
|
|
2434
|
-
/* @__PURE__ */
|
|
2698
|
+
return /* @__PURE__ */ jsxs7("div", { className: cn("mx-auto w-full max-w-7xl space-y-8", className), children: [
|
|
2699
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-4 md:flex-row md:items-end md:justify-between", children: [
|
|
2700
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
2701
|
+
/* @__PURE__ */ jsx7("h1", { className: "font-display text-3xl font-extrabold tracking-tight text-foreground", children: "Environment Secrets" }),
|
|
2702
|
+
/* @__PURE__ */ jsx7("p", { className: "mt-1 text-sm text-muted-foreground", children: "Secrets are securely stored and automatically exposed as environment variables across all your sandboxes." })
|
|
2435
2703
|
] }),
|
|
2436
|
-
/* @__PURE__ */
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2704
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-3", children: [
|
|
2705
|
+
/* @__PURE__ */ jsxs7(
|
|
2706
|
+
"button",
|
|
2707
|
+
{
|
|
2708
|
+
type: "button",
|
|
2709
|
+
onClick: () => setIsImportOpen(true),
|
|
2710
|
+
className: "inline-flex items-center gap-2 rounded-lg border border-border bg-card px-4 py-2.5 text-sm font-semibold text-foreground hover:bg-muted transition-colors active:scale-[0.97]",
|
|
2711
|
+
children: [
|
|
2712
|
+
/* @__PURE__ */ jsx7(Upload, { className: "h-4 w-4" }),
|
|
2713
|
+
"Import .env"
|
|
2714
|
+
]
|
|
2715
|
+
}
|
|
2716
|
+
),
|
|
2717
|
+
/* @__PURE__ */ jsxs7(
|
|
2718
|
+
"button",
|
|
2719
|
+
{
|
|
2720
|
+
type: "button",
|
|
2721
|
+
onClick: () => setIsCreateOpen(true),
|
|
2722
|
+
className: "inline-flex items-center gap-2 rounded-lg bg-[var(--btn-primary-bg)] border border-[var(--border-accent,transparent)] px-5 py-2.5 text-sm font-semibold text-[var(--btn-primary-text)] hover:bg-[var(--btn-primary-hover)] transition-colors active:scale-[0.97]",
|
|
2723
|
+
children: [
|
|
2724
|
+
/* @__PURE__ */ jsx7(Plus3, { className: "h-4 w-4" }),
|
|
2725
|
+
"New Secret"
|
|
2726
|
+
]
|
|
2727
|
+
}
|
|
2728
|
+
)
|
|
2729
|
+
] })
|
|
2448
2730
|
] }),
|
|
2449
|
-
teamSecretsHint && /* @__PURE__ */
|
|
2450
|
-
/* @__PURE__ */
|
|
2451
|
-
/* @__PURE__ */
|
|
2452
|
-
/* @__PURE__ */
|
|
2453
|
-
/* @__PURE__ */
|
|
2731
|
+
teamSecretsHint && /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-3 rounded-lg border border-border bg-[var(--accent-surface-soft)]/40 px-4 py-3", children: [
|
|
2732
|
+
/* @__PURE__ */ jsx7(Users, { className: "h-5 w-5 shrink-0 text-[var(--accent-text)]", "aria-hidden": "true" }),
|
|
2733
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex-1 text-sm", children: [
|
|
2734
|
+
/* @__PURE__ */ jsx7("p", { className: "font-semibold text-foreground", children: "Setting up secrets for a team?" }),
|
|
2735
|
+
/* @__PURE__ */ jsxs7("p", { className: "mt-0.5 text-muted-foreground text-xs", children: [
|
|
2454
2736
|
"Secrets here are ",
|
|
2455
|
-
/* @__PURE__ */
|
|
2737
|
+
/* @__PURE__ */ jsx7("strong", { children: "personal" }),
|
|
2456
2738
|
" \u2014 only available in sandboxes you create. To share credentials with teammates, configure them on the team page instead."
|
|
2457
2739
|
] })
|
|
2458
2740
|
] }),
|
|
2459
|
-
/* @__PURE__ */
|
|
2741
|
+
/* @__PURE__ */ jsxs7(
|
|
2460
2742
|
"button",
|
|
2461
2743
|
{
|
|
2462
2744
|
type: "button",
|
|
@@ -2464,24 +2746,24 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2464
2746
|
className: "inline-flex shrink-0 items-center gap-1 rounded-md border border-border bg-card px-3 py-1.5 text-xs font-semibold text-foreground hover:bg-muted transition-colors",
|
|
2465
2747
|
children: [
|
|
2466
2748
|
teamSecretsHint.label ?? "Manage team secrets",
|
|
2467
|
-
/* @__PURE__ */
|
|
2749
|
+
/* @__PURE__ */ jsx7(ArrowRight, { className: "h-3 w-3", "aria-hidden": "true" })
|
|
2468
2750
|
]
|
|
2469
2751
|
}
|
|
2470
2752
|
)
|
|
2471
2753
|
] }),
|
|
2472
|
-
/* @__PURE__ */
|
|
2473
|
-
/* @__PURE__ */
|
|
2474
|
-
/* @__PURE__ */
|
|
2475
|
-
/* @__PURE__ */
|
|
2754
|
+
/* @__PURE__ */ jsxs7("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-4", children: [
|
|
2755
|
+
/* @__PURE__ */ jsxs7("div", { className: "rounded-lg border border-border bg-card p-5 shadow-[var(--shadow-card)]", children: [
|
|
2756
|
+
/* @__PURE__ */ jsx7("p", { className: "text-[10px] font-bold uppercase tracking-widest text-muted-foreground", children: "Total Active Secrets" }),
|
|
2757
|
+
/* @__PURE__ */ jsx7("div", { className: "mt-2 flex items-baseline gap-2", children: /* @__PURE__ */ jsx7("span", { className: "font-display text-2xl font-extrabold text-foreground", children: secrets.length }) })
|
|
2476
2758
|
] }),
|
|
2477
|
-
/* @__PURE__ */
|
|
2478
|
-
/* @__PURE__ */
|
|
2479
|
-
/* @__PURE__ */
|
|
2480
|
-
/* @__PURE__ */
|
|
2481
|
-
/* @__PURE__ */
|
|
2759
|
+
/* @__PURE__ */ jsxs7("div", { className: "rounded-lg border border-border bg-card p-5 shadow-[var(--shadow-card)]", children: [
|
|
2760
|
+
/* @__PURE__ */ jsx7("p", { className: "text-[10px] font-bold uppercase tracking-widest text-muted-foreground", children: "Status" }),
|
|
2761
|
+
/* @__PURE__ */ jsxs7("div", { className: "mt-2 flex items-center gap-2", children: [
|
|
2762
|
+
/* @__PURE__ */ jsx7(CheckCircle, { className: "h-4 w-4 text-[var(--surface-success-text,#047857)]" }),
|
|
2763
|
+
/* @__PURE__ */ jsx7("span", { className: "text-sm font-semibold text-[var(--surface-success-text,#047857)]", children: "Encrypted" })
|
|
2482
2764
|
] })
|
|
2483
2765
|
] }),
|
|
2484
|
-
/* @__PURE__ */
|
|
2766
|
+
/* @__PURE__ */ jsx7(
|
|
2485
2767
|
InfoPanel,
|
|
2486
2768
|
{
|
|
2487
2769
|
className: "md:col-span-2",
|
|
@@ -2491,11 +2773,11 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2491
2773
|
}
|
|
2492
2774
|
)
|
|
2493
2775
|
] }),
|
|
2494
|
-
error && /* @__PURE__ */
|
|
2495
|
-
/* @__PURE__ */
|
|
2496
|
-
/* @__PURE__ */
|
|
2776
|
+
error && /* @__PURE__ */ jsxs7("div", { className: "rounded-lg border border-destructive/30 bg-destructive/10 p-4 flex items-center gap-3", children: [
|
|
2777
|
+
/* @__PURE__ */ jsx7(AlertCircle2, { className: "h-5 w-5 text-destructive shrink-0" }),
|
|
2778
|
+
/* @__PURE__ */ jsx7("p", { className: "text-destructive text-sm font-medium", children: error })
|
|
2497
2779
|
] }),
|
|
2498
|
-
/* @__PURE__ */
|
|
2780
|
+
/* @__PURE__ */ jsx7(Dialog3, { open: isCreateOpen, onOpenChange: (open) => {
|
|
2499
2781
|
if (!open) {
|
|
2500
2782
|
setIsCreateOpen(false);
|
|
2501
2783
|
setNewName("");
|
|
@@ -2503,12 +2785,12 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2503
2785
|
setCreateError(null);
|
|
2504
2786
|
setShowValue(false);
|
|
2505
2787
|
}
|
|
2506
|
-
}, children: /* @__PURE__ */
|
|
2507
|
-
/* @__PURE__ */
|
|
2508
|
-
/* @__PURE__ */
|
|
2509
|
-
/* @__PURE__ */
|
|
2788
|
+
}, children: /* @__PURE__ */ jsxs7(DialogContent3, { className: "max-w-md", children: [
|
|
2789
|
+
/* @__PURE__ */ jsxs7(DialogHeader3, { children: [
|
|
2790
|
+
/* @__PURE__ */ jsx7(DialogTitle3, { children: "Create Secret" }),
|
|
2791
|
+
/* @__PURE__ */ jsx7(DialogDescription3, { children: "Secrets are automatically exposed as environment variables across all your new sandboxes." })
|
|
2510
2792
|
] }),
|
|
2511
|
-
/* @__PURE__ */
|
|
2793
|
+
/* @__PURE__ */ jsxs7(
|
|
2512
2794
|
"form",
|
|
2513
2795
|
{
|
|
2514
2796
|
onSubmit: (e) => {
|
|
@@ -2517,9 +2799,9 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2517
2799
|
},
|
|
2518
2800
|
className: "space-y-4",
|
|
2519
2801
|
children: [
|
|
2520
|
-
/* @__PURE__ */
|
|
2521
|
-
/* @__PURE__ */
|
|
2522
|
-
/* @__PURE__ */
|
|
2802
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
2803
|
+
/* @__PURE__ */ jsx7("label", { htmlFor: "secret-name", className: "block text-xs font-bold uppercase tracking-widest text-muted-foreground mb-2", children: "Name" }),
|
|
2804
|
+
/* @__PURE__ */ jsx7(
|
|
2523
2805
|
"input",
|
|
2524
2806
|
{
|
|
2525
2807
|
id: "secret-name",
|
|
@@ -2533,10 +2815,10 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2533
2815
|
}
|
|
2534
2816
|
)
|
|
2535
2817
|
] }),
|
|
2536
|
-
/* @__PURE__ */
|
|
2537
|
-
/* @__PURE__ */
|
|
2538
|
-
/* @__PURE__ */
|
|
2539
|
-
/* @__PURE__ */
|
|
2818
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
2819
|
+
/* @__PURE__ */ jsx7("label", { htmlFor: "secret-value", className: "block text-xs font-bold uppercase tracking-widest text-muted-foreground mb-2", children: "Value" }),
|
|
2820
|
+
/* @__PURE__ */ jsxs7("div", { className: "relative", children: [
|
|
2821
|
+
/* @__PURE__ */ jsx7(
|
|
2540
2822
|
"input",
|
|
2541
2823
|
{
|
|
2542
2824
|
id: "secret-value",
|
|
@@ -2549,26 +2831,26 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2549
2831
|
className: "w-full rounded-md border border-border bg-card px-3 py-2.5 pr-10 text-sm font-mono text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
|
2550
2832
|
}
|
|
2551
2833
|
),
|
|
2552
|
-
/* @__PURE__ */
|
|
2834
|
+
/* @__PURE__ */ jsx7(
|
|
2553
2835
|
"button",
|
|
2554
2836
|
{
|
|
2555
2837
|
type: "button",
|
|
2556
2838
|
onClick: () => setShowValue(!showValue),
|
|
2557
2839
|
className: "absolute right-2 top-1/2 -translate-y-1/2 p-1 text-muted-foreground hover:text-foreground",
|
|
2558
2840
|
"aria-label": showValue ? "Hide value" : "Show value",
|
|
2559
|
-
children: showValue ? /* @__PURE__ */
|
|
2841
|
+
children: showValue ? /* @__PURE__ */ jsx7(EyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx7(Eye, { className: "h-4 w-4" })
|
|
2560
2842
|
}
|
|
2561
2843
|
)
|
|
2562
2844
|
] }),
|
|
2563
|
-
/* @__PURE__ */
|
|
2845
|
+
/* @__PURE__ */ jsx7("p", { className: "mt-1.5 text-xs text-muted-foreground", children: "This value cannot be retrieved after creation." })
|
|
2564
2846
|
] }),
|
|
2565
|
-
/* @__PURE__ */
|
|
2847
|
+
/* @__PURE__ */ jsx7("button", { type: "submit", className: "hidden", tabIndex: -1, "aria-hidden": "true", children: "Submit" })
|
|
2566
2848
|
]
|
|
2567
2849
|
}
|
|
2568
2850
|
),
|
|
2569
|
-
createError && /* @__PURE__ */
|
|
2570
|
-
/* @__PURE__ */
|
|
2571
|
-
/* @__PURE__ */
|
|
2851
|
+
createError && /* @__PURE__ */ jsx7("p", { className: "mt-3 text-sm text-destructive", children: createError }),
|
|
2852
|
+
/* @__PURE__ */ jsxs7(DialogFooter3, { children: [
|
|
2853
|
+
/* @__PURE__ */ jsx7(
|
|
2572
2854
|
"button",
|
|
2573
2855
|
{
|
|
2574
2856
|
type: "button",
|
|
@@ -2582,7 +2864,7 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2582
2864
|
children: "Cancel"
|
|
2583
2865
|
}
|
|
2584
2866
|
),
|
|
2585
|
-
/* @__PURE__ */
|
|
2867
|
+
/* @__PURE__ */ jsx7(
|
|
2586
2868
|
"button",
|
|
2587
2869
|
{
|
|
2588
2870
|
type: "button",
|
|
@@ -2594,19 +2876,204 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2594
2876
|
)
|
|
2595
2877
|
] })
|
|
2596
2878
|
] }) }),
|
|
2597
|
-
/* @__PURE__ */
|
|
2879
|
+
/* @__PURE__ */ jsx7(Dialog3, { open: isImportOpen, onOpenChange: (open) => {
|
|
2880
|
+
if (!open && !isImportSaving) {
|
|
2881
|
+
setIsImportOpen(false);
|
|
2882
|
+
resetImportState();
|
|
2883
|
+
}
|
|
2884
|
+
}, children: /* @__PURE__ */ jsxs7(DialogContent3, { className: "max-w-2xl", children: [
|
|
2885
|
+
/* @__PURE__ */ jsxs7(DialogHeader3, { children: [
|
|
2886
|
+
/* @__PURE__ */ jsx7(DialogTitle3, { children: "Import Secrets" }),
|
|
2887
|
+
/* @__PURE__ */ jsxs7(DialogDescription3, { children: [
|
|
2888
|
+
"Upload a ",
|
|
2889
|
+
/* @__PURE__ */ jsx7("span", { className: "font-mono", children: ".env" }),
|
|
2890
|
+
" file or paste key-value pairs. Review and edit each row before saving."
|
|
2891
|
+
] })
|
|
2892
|
+
] }),
|
|
2893
|
+
/* @__PURE__ */ jsxs7("div", { className: "space-y-4", children: [
|
|
2894
|
+
/* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
|
|
2895
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
|
|
2896
|
+
/* @__PURE__ */ jsx7(
|
|
2897
|
+
"input",
|
|
2898
|
+
{
|
|
2899
|
+
ref: fileInputRef,
|
|
2900
|
+
type: "file",
|
|
2901
|
+
accept: ".env,.txt,text/plain",
|
|
2902
|
+
"aria-label": "Upload .env file",
|
|
2903
|
+
className: "hidden",
|
|
2904
|
+
onChange: (e) => handleImportFile(e.target.files?.[0] ?? null)
|
|
2905
|
+
}
|
|
2906
|
+
),
|
|
2907
|
+
/* @__PURE__ */ jsxs7(
|
|
2908
|
+
"button",
|
|
2909
|
+
{
|
|
2910
|
+
type: "button",
|
|
2911
|
+
onClick: () => fileInputRef.current?.click(),
|
|
2912
|
+
className: "inline-flex items-center gap-2 rounded-md border border-border bg-card px-3 py-2 text-xs font-semibold text-foreground hover:bg-muted transition-colors",
|
|
2913
|
+
children: [
|
|
2914
|
+
/* @__PURE__ */ jsx7(Upload, { className: "h-3.5 w-3.5" }),
|
|
2915
|
+
"Choose .env file"
|
|
2916
|
+
]
|
|
2917
|
+
}
|
|
2918
|
+
),
|
|
2919
|
+
/* @__PURE__ */ jsx7(
|
|
2920
|
+
"button",
|
|
2921
|
+
{
|
|
2922
|
+
type: "button",
|
|
2923
|
+
onClick: handleParse,
|
|
2924
|
+
disabled: !importText.trim(),
|
|
2925
|
+
className: "rounded-md bg-[var(--btn-primary-bg)] px-3 py-2 text-xs font-bold text-[var(--btn-primary-text)] hover:bg-[var(--btn-primary-hover)] transition-colors disabled:opacity-50",
|
|
2926
|
+
children: "Parse"
|
|
2927
|
+
}
|
|
2928
|
+
)
|
|
2929
|
+
] }),
|
|
2930
|
+
/* @__PURE__ */ jsx7(
|
|
2931
|
+
"textarea",
|
|
2932
|
+
{
|
|
2933
|
+
"aria-label": "Paste .env contents",
|
|
2934
|
+
placeholder: "Paste .env contents, e.g.\nAPI_KEY=abc123\n# comment\nexport DB_URL=postgres://localhost",
|
|
2935
|
+
value: importText,
|
|
2936
|
+
onChange: (e) => setImportText(e.target.value),
|
|
2937
|
+
rows: 6,
|
|
2938
|
+
spellCheck: false,
|
|
2939
|
+
className: "w-full rounded-md border border-border bg-card px-3 py-2 font-mono text-xs text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
|
2940
|
+
}
|
|
2941
|
+
),
|
|
2942
|
+
/* @__PURE__ */ jsxs7("p", { className: "text-[11px] text-muted-foreground", children: [
|
|
2943
|
+
"Lines starting with ",
|
|
2944
|
+
/* @__PURE__ */ jsx7("span", { className: "font-mono", children: "#" }),
|
|
2945
|
+
" are comments. Text after ",
|
|
2946
|
+
/* @__PURE__ */ jsx7("span", { className: "font-mono", children: "#" }),
|
|
2947
|
+
" inside a value is preserved."
|
|
2948
|
+
] }),
|
|
2949
|
+
importFileError && /* @__PURE__ */ jsx7("p", { className: "text-xs text-destructive", role: "alert", children: importFileError })
|
|
2950
|
+
] }),
|
|
2951
|
+
importResult && importResult.errors.length > 0 && /* @__PURE__ */ jsxs7("div", { className: "rounded-md border border-destructive/30 bg-destructive/10 p-3", children: [
|
|
2952
|
+
/* @__PURE__ */ jsxs7("p", { className: "mb-1 text-xs font-bold uppercase tracking-widest text-destructive", children: [
|
|
2953
|
+
importResult.errors.length,
|
|
2954
|
+
" line",
|
|
2955
|
+
importResult.errors.length !== 1 ? "s" : "",
|
|
2956
|
+
" could not be parsed"
|
|
2957
|
+
] }),
|
|
2958
|
+
/* @__PURE__ */ jsx7("ul", { className: "space-y-1", children: importResult.errors.map((err) => /* @__PURE__ */ jsxs7("li", { className: "text-xs text-destructive", role: "alert", children: [
|
|
2959
|
+
"Line ",
|
|
2960
|
+
err.lineNumber,
|
|
2961
|
+
": ",
|
|
2962
|
+
err.message
|
|
2963
|
+
] }, err.lineNumber)) })
|
|
2964
|
+
] }),
|
|
2965
|
+
importResult && importResult.rows.length > 0 && /* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
|
|
2966
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between", children: [
|
|
2967
|
+
/* @__PURE__ */ jsxs7("p", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground", children: [
|
|
2968
|
+
importResult.rows.length,
|
|
2969
|
+
" secret",
|
|
2970
|
+
importResult.rows.length !== 1 ? "s" : "",
|
|
2971
|
+
" ready"
|
|
2972
|
+
] }),
|
|
2973
|
+
/* @__PURE__ */ jsxs7(
|
|
2974
|
+
"button",
|
|
2975
|
+
{
|
|
2976
|
+
type: "button",
|
|
2977
|
+
onClick: () => setShowImportValues((s) => !s),
|
|
2978
|
+
className: "inline-flex items-center gap-1 text-xs font-semibold text-muted-foreground hover:text-foreground",
|
|
2979
|
+
children: [
|
|
2980
|
+
showImportValues ? /* @__PURE__ */ jsx7(EyeOff, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx7(Eye, { className: "h-3.5 w-3.5" }),
|
|
2981
|
+
showImportValues ? "Hide values" : "Show values"
|
|
2982
|
+
]
|
|
2983
|
+
}
|
|
2984
|
+
)
|
|
2985
|
+
] }),
|
|
2986
|
+
/* @__PURE__ */ jsx7("div", { className: "max-h-64 space-y-2 overflow-y-auto", children: importResult.rows.map((row, index) => {
|
|
2987
|
+
const status = rowStatus[index];
|
|
2988
|
+
const message = rowMessages[index];
|
|
2989
|
+
return /* @__PURE__ */ jsxs7("div", { className: "flex items-start gap-2 rounded-md border border-border bg-muted/30 p-2", children: [
|
|
2990
|
+
/* @__PURE__ */ jsx7(
|
|
2991
|
+
"input",
|
|
2992
|
+
{
|
|
2993
|
+
type: "text",
|
|
2994
|
+
"aria-label": `Import row ${index + 1} key`,
|
|
2995
|
+
value: row.key,
|
|
2996
|
+
onChange: (e) => updateRowKey(index, e.target.value),
|
|
2997
|
+
disabled: isImportSaving,
|
|
2998
|
+
className: "w-2/5 rounded border border-border bg-card px-2 py-1.5 font-mono text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:opacity-60"
|
|
2999
|
+
}
|
|
3000
|
+
),
|
|
3001
|
+
/* @__PURE__ */ jsx7(
|
|
3002
|
+
"input",
|
|
3003
|
+
{
|
|
3004
|
+
type: showImportValues ? "text" : "password",
|
|
3005
|
+
"aria-label": `Import row ${index + 1} value`,
|
|
3006
|
+
value: row.value,
|
|
3007
|
+
onChange: (e) => updateRowValue(index, e.target.value),
|
|
3008
|
+
disabled: isImportSaving,
|
|
3009
|
+
className: "w-2/5 rounded border border-border bg-card px-2 py-1.5 font-mono text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:opacity-60"
|
|
3010
|
+
}
|
|
3011
|
+
),
|
|
3012
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex w-1/5 flex-col items-end gap-1", children: [
|
|
3013
|
+
status === "success" && /* @__PURE__ */ jsxs7("span", { className: "inline-flex items-center gap-1 text-xs font-semibold text-[var(--surface-success-text,#047857)]", children: [
|
|
3014
|
+
/* @__PURE__ */ jsx7(CheckCircle, { className: "h-3.5 w-3.5" }),
|
|
3015
|
+
" Saved"
|
|
3016
|
+
] }),
|
|
3017
|
+
status === "error" && /* @__PURE__ */ jsx7("span", { className: "text-right text-xs font-semibold text-destructive", title: message, children: message || "Failed" }),
|
|
3018
|
+
/* @__PURE__ */ jsxs7(
|
|
3019
|
+
"button",
|
|
3020
|
+
{
|
|
3021
|
+
type: "button",
|
|
3022
|
+
onClick: () => removeImportRow(index),
|
|
3023
|
+
disabled: isImportSaving,
|
|
3024
|
+
"aria-label": `Remove import row ${index + 1}`,
|
|
3025
|
+
className: "inline-flex items-center gap-1 text-xs font-semibold text-muted-foreground hover:text-destructive disabled:opacity-50 disabled:pointer-events-none",
|
|
3026
|
+
children: [
|
|
3027
|
+
/* @__PURE__ */ jsx7(Trash23, { className: "h-3.5 w-3.5" }),
|
|
3028
|
+
" Remove"
|
|
3029
|
+
]
|
|
3030
|
+
}
|
|
3031
|
+
)
|
|
3032
|
+
] })
|
|
3033
|
+
] }, `${row.lineNumber}-${index}`);
|
|
3034
|
+
}) })
|
|
3035
|
+
] }),
|
|
3036
|
+
importResult && importResult.rows.length === 0 && importResult.errors.length === 0 && /* @__PURE__ */ jsx7("p", { className: "text-xs text-muted-foreground", children: "No secrets found. Add at least one KEY=value line." })
|
|
3037
|
+
] }),
|
|
3038
|
+
/* @__PURE__ */ jsxs7(DialogFooter3, { children: [
|
|
3039
|
+
/* @__PURE__ */ jsx7(
|
|
3040
|
+
"button",
|
|
3041
|
+
{
|
|
3042
|
+
type: "button",
|
|
3043
|
+
onClick: () => {
|
|
3044
|
+
setIsImportOpen(false);
|
|
3045
|
+
resetImportState();
|
|
3046
|
+
},
|
|
3047
|
+
disabled: isImportSaving,
|
|
3048
|
+
className: "rounded-md border border-border bg-card px-4 py-2 text-sm font-medium text-foreground hover:bg-muted transition-colors disabled:opacity-50 disabled:pointer-events-none",
|
|
3049
|
+
children: "Cancel"
|
|
3050
|
+
}
|
|
3051
|
+
),
|
|
3052
|
+
/* @__PURE__ */ jsx7(
|
|
3053
|
+
"button",
|
|
3054
|
+
{
|
|
3055
|
+
type: "button",
|
|
3056
|
+
onClick: handleImportSave,
|
|
3057
|
+
disabled: importSaveDisabled,
|
|
3058
|
+
className: "rounded-md bg-[var(--btn-primary-bg)] px-4 py-2 text-sm font-bold text-[var(--btn-primary-text)] hover:bg-[var(--btn-primary-hover)] transition-colors disabled:opacity-50 active:scale-[0.97]",
|
|
3059
|
+
children: isImportSaving ? "Importing..." : importRows.length > 0 ? `Import ${importRows.length} secret${importRows.length === 1 ? "" : "s"}` : "Import secrets"
|
|
3060
|
+
}
|
|
3061
|
+
)
|
|
3062
|
+
] })
|
|
3063
|
+
] }) }),
|
|
3064
|
+
/* @__PURE__ */ jsx7(Dialog3, { open: !!deleteTarget, onOpenChange: (open) => {
|
|
2598
3065
|
if (!open) setDeleteTarget(null);
|
|
2599
|
-
}, children: /* @__PURE__ */
|
|
2600
|
-
/* @__PURE__ */
|
|
2601
|
-
/* @__PURE__ */
|
|
2602
|
-
/* @__PURE__ */
|
|
3066
|
+
}, children: /* @__PURE__ */ jsxs7(DialogContent3, { className: "max-w-sm", children: [
|
|
3067
|
+
/* @__PURE__ */ jsxs7(DialogHeader3, { children: [
|
|
3068
|
+
/* @__PURE__ */ jsx7(DialogTitle3, { children: "Delete Secret?" }),
|
|
3069
|
+
/* @__PURE__ */ jsxs7(DialogDescription3, { children: [
|
|
2603
3070
|
"This will permanently delete ",
|
|
2604
|
-
/* @__PURE__ */
|
|
3071
|
+
/* @__PURE__ */ jsx7("span", { className: "font-mono font-bold text-foreground", children: deleteTarget }),
|
|
2605
3072
|
". Sandboxes using this secret will lose access to it."
|
|
2606
3073
|
] })
|
|
2607
3074
|
] }),
|
|
2608
|
-
/* @__PURE__ */
|
|
2609
|
-
/* @__PURE__ */
|
|
3075
|
+
/* @__PURE__ */ jsxs7(DialogFooter3, { children: [
|
|
3076
|
+
/* @__PURE__ */ jsx7(
|
|
2610
3077
|
"button",
|
|
2611
3078
|
{
|
|
2612
3079
|
type: "button",
|
|
@@ -2615,7 +3082,7 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2615
3082
|
children: "Cancel"
|
|
2616
3083
|
}
|
|
2617
3084
|
),
|
|
2618
|
-
/* @__PURE__ */
|
|
3085
|
+
/* @__PURE__ */ jsx7(
|
|
2619
3086
|
"button",
|
|
2620
3087
|
{
|
|
2621
3088
|
type: "button",
|
|
@@ -2627,20 +3094,20 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2627
3094
|
)
|
|
2628
3095
|
] })
|
|
2629
3096
|
] }) }),
|
|
2630
|
-
/* @__PURE__ */
|
|
2631
|
-
/* @__PURE__ */
|
|
2632
|
-
/* @__PURE__ */
|
|
2633
|
-
/* @__PURE__ */
|
|
3097
|
+
/* @__PURE__ */ jsxs7("div", { className: "overflow-hidden rounded-lg border border-border bg-card shadow-[var(--shadow-card)]", children: [
|
|
3098
|
+
/* @__PURE__ */ jsxs7("div", { className: "border-b border-border px-6 py-4 flex items-center justify-between", children: [
|
|
3099
|
+
/* @__PURE__ */ jsx7("div", { className: "flex gap-6", children: /* @__PURE__ */ jsx7("button", { type: "button", className: "text-xs font-bold uppercase tracking-widest text-foreground border-b-2 border-foreground pb-1", children: "All Secrets" }) }),
|
|
3100
|
+
/* @__PURE__ */ jsxs7("span", { className: "text-xs text-muted-foreground font-mono", children: [
|
|
2634
3101
|
secrets.length,
|
|
2635
3102
|
" secret",
|
|
2636
3103
|
secrets.length !== 1 ? "s" : ""
|
|
2637
3104
|
] })
|
|
2638
3105
|
] }),
|
|
2639
|
-
loading ? /* @__PURE__ */
|
|
2640
|
-
/* @__PURE__ */
|
|
2641
|
-
/* @__PURE__ */
|
|
2642
|
-
/* @__PURE__ */
|
|
2643
|
-
/* @__PURE__ */
|
|
3106
|
+
loading ? /* @__PURE__ */ jsx7("div", { className: "flex items-center justify-center py-16", children: /* @__PURE__ */ jsx7("div", { className: "h-6 w-6 animate-spin rounded-full border-2 border-muted-foreground border-t-transparent" }) }) : secrets.length === 0 ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [
|
|
3107
|
+
/* @__PURE__ */ jsx7(Lock, { className: "h-10 w-10 text-muted-foreground mb-4" }),
|
|
3108
|
+
/* @__PURE__ */ jsx7("h3", { className: "text-lg font-semibold text-foreground", children: "No secrets yet" }),
|
|
3109
|
+
/* @__PURE__ */ jsx7("p", { className: "mt-1 text-sm text-muted-foreground max-w-sm", children: "Create a secret to inject into your sandboxes." }),
|
|
3110
|
+
/* @__PURE__ */ jsxs7(
|
|
2644
3111
|
"button",
|
|
2645
3112
|
{
|
|
2646
3113
|
type: "button",
|
|
@@ -2648,52 +3115,52 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2648
3115
|
"aria-label": "Create your first secret",
|
|
2649
3116
|
className: "mt-6 inline-flex items-center gap-2 rounded-md bg-[var(--btn-primary-bg)] px-4 py-2 text-sm font-semibold text-[var(--btn-primary-text)] hover:bg-[var(--btn-primary-hover)] transition-colors active:scale-[0.97]",
|
|
2650
3117
|
children: [
|
|
2651
|
-
/* @__PURE__ */
|
|
3118
|
+
/* @__PURE__ */ jsx7(Plus3, { className: "h-4 w-4" }),
|
|
2652
3119
|
"New Secret"
|
|
2653
3120
|
]
|
|
2654
3121
|
}
|
|
2655
3122
|
)
|
|
2656
|
-
] }) : /* @__PURE__ */
|
|
2657
|
-
/* @__PURE__ */
|
|
2658
|
-
/* @__PURE__ */
|
|
2659
|
-
/* @__PURE__ */
|
|
2660
|
-
/* @__PURE__ */
|
|
2661
|
-
/* @__PURE__ */
|
|
3123
|
+
] }) : /* @__PURE__ */ jsxs7("table", { className: "w-full text-left border-collapse", children: [
|
|
3124
|
+
/* @__PURE__ */ jsx7("thead", { children: /* @__PURE__ */ jsxs7("tr", { className: "bg-muted/30 border-b border-border", children: [
|
|
3125
|
+
/* @__PURE__ */ jsx7("th", { className: "px-6 py-4 text-[10px] font-bold uppercase tracking-widest text-muted-foreground", children: "Secret Name" }),
|
|
3126
|
+
/* @__PURE__ */ jsx7("th", { className: "px-6 py-4 text-[10px] font-bold uppercase tracking-widest text-muted-foreground", children: "Encrypted Value" }),
|
|
3127
|
+
/* @__PURE__ */ jsx7("th", { className: "px-6 py-4 text-[10px] font-bold uppercase tracking-widest text-muted-foreground text-right", children: "Created" }),
|
|
3128
|
+
/* @__PURE__ */ jsx7("th", { className: "px-6 py-4 w-12" })
|
|
2662
3129
|
] }) }),
|
|
2663
|
-
/* @__PURE__ */
|
|
2664
|
-
/* @__PURE__ */
|
|
2665
|
-
/* @__PURE__ */
|
|
2666
|
-
/* @__PURE__ */
|
|
3130
|
+
/* @__PURE__ */ jsx7("tbody", { className: "divide-y divide-border", children: secrets.map((secret) => /* @__PURE__ */ jsxs7("tr", { className: "hover:bg-muted/20 transition-colors", children: [
|
|
3131
|
+
/* @__PURE__ */ jsx7("td", { className: "px-6 py-4", children: /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-3", children: [
|
|
3132
|
+
/* @__PURE__ */ jsx7(Key, { className: "h-4 w-4 text-muted-foreground" }),
|
|
3133
|
+
/* @__PURE__ */ jsx7("span", { className: "text-sm font-bold font-mono text-foreground", children: secret.name })
|
|
2667
3134
|
] }) }),
|
|
2668
|
-
/* @__PURE__ */
|
|
2669
|
-
/* @__PURE__ */
|
|
2670
|
-
/* @__PURE__ */
|
|
3135
|
+
/* @__PURE__ */ jsx7("td", { className: "px-6 py-4", children: /* @__PURE__ */ jsx7("code", { className: "text-xs font-mono text-muted-foreground bg-muted px-2 py-1 rounded", children: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }) }),
|
|
3136
|
+
/* @__PURE__ */ jsx7("td", { className: "px-6 py-4 text-right", children: /* @__PURE__ */ jsx7("span", { className: "text-xs text-muted-foreground", children: formatDate(secret.createdAt) }) }),
|
|
3137
|
+
/* @__PURE__ */ jsx7("td", { className: "px-6 py-4", children: /* @__PURE__ */ jsx7(
|
|
2671
3138
|
"button",
|
|
2672
3139
|
{
|
|
2673
3140
|
type: "button",
|
|
2674
3141
|
onClick: () => setDeleteTarget(secret.name),
|
|
2675
3142
|
className: "p-1.5 rounded-md text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-colors",
|
|
2676
3143
|
"aria-label": `Delete ${secret.name}`,
|
|
2677
|
-
children: /* @__PURE__ */
|
|
3144
|
+
children: /* @__PURE__ */ jsx7(Trash23, { className: "h-4 w-4" })
|
|
2678
3145
|
}
|
|
2679
3146
|
) })
|
|
2680
3147
|
] }, secret.name)) })
|
|
2681
3148
|
] })
|
|
2682
3149
|
] }),
|
|
2683
|
-
/* @__PURE__ */
|
|
2684
|
-
/* @__PURE__ */
|
|
2685
|
-
/* @__PURE__ */
|
|
2686
|
-
/* @__PURE__ */
|
|
2687
|
-
/* @__PURE__ */
|
|
3150
|
+
/* @__PURE__ */ jsxs7("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", children: [
|
|
3151
|
+
/* @__PURE__ */ jsxs7("div", { className: "rounded-lg border border-border bg-card p-6 shadow-[var(--shadow-card)]", children: [
|
|
3152
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-3 mb-3", children: [
|
|
3153
|
+
/* @__PURE__ */ jsx7("div", { className: "flex h-9 w-9 items-center justify-center rounded-md bg-[var(--brand-primary,hsl(var(--primary)))] text-[var(--btn-primary-text)]", children: /* @__PURE__ */ jsx7(Shield, { className: "h-5 w-5" }) }),
|
|
3154
|
+
/* @__PURE__ */ jsx7("h3", { className: "text-sm font-bold text-foreground", children: "Encryption Standard" })
|
|
2688
3155
|
] }),
|
|
2689
|
-
/* @__PURE__ */
|
|
3156
|
+
/* @__PURE__ */ jsx7("p", { className: "text-sm text-muted-foreground leading-relaxed", children: "Your secrets are encrypted using AES-256-GCM at rest and TLS 1.3 in transit. Hardware Security Modules manage all root keys." })
|
|
2690
3157
|
] }),
|
|
2691
|
-
/* @__PURE__ */
|
|
2692
|
-
/* @__PURE__ */
|
|
2693
|
-
/* @__PURE__ */
|
|
2694
|
-
/* @__PURE__ */
|
|
3158
|
+
/* @__PURE__ */ jsxs7("div", { className: "rounded-lg border border-border bg-card p-6 shadow-[var(--shadow-card)]", children: [
|
|
3159
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-3 mb-3", children: [
|
|
3160
|
+
/* @__PURE__ */ jsx7("div", { className: "flex h-9 w-9 items-center justify-center rounded-md bg-[var(--brand-primary,hsl(var(--primary)))] text-[var(--btn-primary-text)]", children: /* @__PURE__ */ jsx7(Lock, { className: "h-5 w-5" }) }),
|
|
3161
|
+
/* @__PURE__ */ jsx7("h3", { className: "text-sm font-bold text-foreground", children: "Access Policy" })
|
|
2695
3162
|
] }),
|
|
2696
|
-
/* @__PURE__ */
|
|
3163
|
+
/* @__PURE__ */ jsx7("p", { className: "text-sm text-muted-foreground leading-relaxed", children: "Secrets are injected at sandbox creation time and are never exposed in logs, API responses, or container metadata." })
|
|
2697
3164
|
] })
|
|
2698
3165
|
] })
|
|
2699
3166
|
] });
|
|
@@ -2702,18 +3169,18 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2702
3169
|
// src/pages/templates-page.tsx
|
|
2703
3170
|
import { Layers as Layers2 } from "lucide-react";
|
|
2704
3171
|
import { Skeleton as Skeleton3 } from "@tangle-network/ui/primitives";
|
|
2705
|
-
import { jsx as
|
|
3172
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2706
3173
|
function TemplatesPage({ templates, loading = false, onUseTemplate, className }) {
|
|
2707
|
-
return /* @__PURE__ */
|
|
2708
|
-
/* @__PURE__ */
|
|
2709
|
-
/* @__PURE__ */
|
|
2710
|
-
/* @__PURE__ */
|
|
3174
|
+
return /* @__PURE__ */ jsxs8("div", { className: cn("space-y-8", className), children: [
|
|
3175
|
+
/* @__PURE__ */ jsxs8("div", { children: [
|
|
3176
|
+
/* @__PURE__ */ jsx8("h1", { className: "font-bold text-3xl text-foreground", children: "Templates" }),
|
|
3177
|
+
/* @__PURE__ */ jsx8("p", { className: "mt-1 text-muted-foreground", children: "Pre-configured environments to get started quickly" })
|
|
2711
3178
|
] }),
|
|
2712
|
-
loading || !templates ? /* @__PURE__ */
|
|
2713
|
-
/* @__PURE__ */
|
|
2714
|
-
/* @__PURE__ */
|
|
2715
|
-
/* @__PURE__ */
|
|
2716
|
-
] }) : /* @__PURE__ */
|
|
3179
|
+
loading || !templates ? /* @__PURE__ */ jsx8("div", { className: "grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsx8(Skeleton3, { className: "h-56 rounded-2xl" }, i)) }) : templates.length === 0 ? /* @__PURE__ */ jsxs8("div", { className: "rounded-2xl border border-border bg-card p-16 text-center", children: [
|
|
3180
|
+
/* @__PURE__ */ jsx8(Layers2, { className: "mx-auto mb-3 h-10 w-10 text-muted-foreground" }),
|
|
3181
|
+
/* @__PURE__ */ jsx8("p", { className: "text-sm font-medium text-foreground mb-1", children: "No templates available" }),
|
|
3182
|
+
/* @__PURE__ */ jsx8("p", { className: "text-sm text-muted-foreground", children: "Check back later for pre-configured environments." })
|
|
3183
|
+
] }) : /* @__PURE__ */ jsx8("div", { className: "grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3", children: templates.map((template) => /* @__PURE__ */ jsx8(
|
|
2717
3184
|
TemplateCard,
|
|
2718
3185
|
{
|
|
2719
3186
|
template,
|
|
@@ -2725,7 +3192,7 @@ function TemplatesPage({ templates, loading = false, onUseTemplate, className })
|
|
|
2725
3192
|
}
|
|
2726
3193
|
|
|
2727
3194
|
// src/pages/startup-scripts-page.tsx
|
|
2728
|
-
import * as
|
|
3195
|
+
import * as React7 from "react";
|
|
2729
3196
|
import {
|
|
2730
3197
|
Play,
|
|
2731
3198
|
Plus as Plus4,
|
|
@@ -2746,14 +3213,14 @@ import {
|
|
|
2746
3213
|
Layers as Layers3
|
|
2747
3214
|
} from "lucide-react";
|
|
2748
3215
|
import {
|
|
2749
|
-
Dialog as
|
|
2750
|
-
DialogContent as
|
|
2751
|
-
DialogDescription as
|
|
2752
|
-
DialogFooter as
|
|
2753
|
-
DialogHeader as
|
|
2754
|
-
DialogTitle as
|
|
3216
|
+
Dialog as Dialog4,
|
|
3217
|
+
DialogContent as DialogContent4,
|
|
3218
|
+
DialogDescription as DialogDescription4,
|
|
3219
|
+
DialogFooter as DialogFooter4,
|
|
3220
|
+
DialogHeader as DialogHeader4,
|
|
3221
|
+
DialogTitle as DialogTitle4
|
|
2755
3222
|
} from "@tangle-network/ui/primitives";
|
|
2756
|
-
import { jsx as
|
|
3223
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2757
3224
|
var SCRIPT_TYPE_META = {
|
|
2758
3225
|
bash: {
|
|
2759
3226
|
label: "Bash",
|
|
@@ -2922,26 +3389,26 @@ function makeDefaultFormData(scriptType = "bash") {
|
|
|
2922
3389
|
};
|
|
2923
3390
|
}
|
|
2924
3391
|
function StartupScriptsPage({ apiClient, className }) {
|
|
2925
|
-
const [scripts, setScripts] =
|
|
2926
|
-
const [secrets, setSecrets] =
|
|
2927
|
-
const [environments, setEnvironments] =
|
|
2928
|
-
const [loading, setLoading] =
|
|
2929
|
-
const [error, setError] =
|
|
2930
|
-
const [isDialogOpen, setIsDialogOpen] =
|
|
2931
|
-
const [dialogStep, setDialogStep] =
|
|
2932
|
-
const [transitionDir, setTransitionDir] =
|
|
2933
|
-
const [stepKey, setStepKey] =
|
|
2934
|
-
const [editingScript, setEditingScript] =
|
|
2935
|
-
const [formData, setFormData] =
|
|
2936
|
-
const [isSaving, setIsSaving] =
|
|
2937
|
-
const [formError, setFormError] =
|
|
2938
|
-
const [showConditions, setShowConditions] =
|
|
2939
|
-
const [deleteTarget, setDeleteTarget] =
|
|
2940
|
-
const [isDeleting, setIsDeleting] =
|
|
2941
|
-
const apiRef =
|
|
3392
|
+
const [scripts, setScripts] = React7.useState([]);
|
|
3393
|
+
const [secrets, setSecrets] = React7.useState([]);
|
|
3394
|
+
const [environments, setEnvironments] = React7.useState([]);
|
|
3395
|
+
const [loading, setLoading] = React7.useState(true);
|
|
3396
|
+
const [error, setError] = React7.useState(null);
|
|
3397
|
+
const [isDialogOpen, setIsDialogOpen] = React7.useState(false);
|
|
3398
|
+
const [dialogStep, setDialogStep] = React7.useState("picker");
|
|
3399
|
+
const [transitionDir, setTransitionDir] = React7.useState("forward");
|
|
3400
|
+
const [stepKey, setStepKey] = React7.useState(0);
|
|
3401
|
+
const [editingScript, setEditingScript] = React7.useState(null);
|
|
3402
|
+
const [formData, setFormData] = React7.useState(makeDefaultFormData());
|
|
3403
|
+
const [isSaving, setIsSaving] = React7.useState(false);
|
|
3404
|
+
const [formError, setFormError] = React7.useState(null);
|
|
3405
|
+
const [showConditions, setShowConditions] = React7.useState(false);
|
|
3406
|
+
const [deleteTarget, setDeleteTarget] = React7.useState(null);
|
|
3407
|
+
const [isDeleting, setIsDeleting] = React7.useState(false);
|
|
3408
|
+
const apiRef = React7.useRef(apiClient);
|
|
2942
3409
|
apiRef.current = apiClient;
|
|
2943
|
-
const loadGenRef =
|
|
2944
|
-
const loadData =
|
|
3410
|
+
const loadGenRef = React7.useRef(0);
|
|
3411
|
+
const loadData = React7.useCallback(async (showSpinner = true) => {
|
|
2945
3412
|
const gen = ++loadGenRef.current;
|
|
2946
3413
|
try {
|
|
2947
3414
|
if (showSpinner) setLoading(true);
|
|
@@ -2962,7 +3429,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
2962
3429
|
if (gen === loadGenRef.current) setLoading(false);
|
|
2963
3430
|
}
|
|
2964
3431
|
}, []);
|
|
2965
|
-
|
|
3432
|
+
React7.useEffect(() => {
|
|
2966
3433
|
loadData();
|
|
2967
3434
|
}, [loadData]);
|
|
2968
3435
|
const openCreate = () => {
|
|
@@ -3075,41 +3542,41 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3075
3542
|
}));
|
|
3076
3543
|
};
|
|
3077
3544
|
const activeCount = scripts.filter((s) => s.enabled).length;
|
|
3078
|
-
return /* @__PURE__ */
|
|
3079
|
-
/* @__PURE__ */
|
|
3080
|
-
/* @__PURE__ */
|
|
3081
|
-
/* @__PURE__ */
|
|
3082
|
-
/* @__PURE__ */
|
|
3545
|
+
return /* @__PURE__ */ jsxs9("div", { className: cn("mx-auto w-full max-w-7xl space-y-6", className), children: [
|
|
3546
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-4 md:flex-row md:items-end md:justify-between", children: [
|
|
3547
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3548
|
+
/* @__PURE__ */ jsx9("h1", { className: "font-display text-3xl font-extrabold tracking-tight text-foreground", children: "Startup Scripts" }),
|
|
3549
|
+
/* @__PURE__ */ jsx9("p", { className: "mt-1 text-sm text-muted-foreground", children: "Define scripts that run automatically when your sandboxes start. Scripts can access your encrypted secrets." })
|
|
3083
3550
|
] }),
|
|
3084
|
-
/* @__PURE__ */
|
|
3551
|
+
/* @__PURE__ */ jsxs9(
|
|
3085
3552
|
"button",
|
|
3086
3553
|
{
|
|
3087
3554
|
type: "button",
|
|
3088
3555
|
onClick: openCreate,
|
|
3089
3556
|
className: "inline-flex items-center gap-2 rounded-lg bg-[var(--btn-primary-bg)] px-4 py-2.5 text-sm font-bold text-[var(--btn-primary-text)] shadow-sm transition-colors hover:bg-[var(--btn-primary-hover)]",
|
|
3090
3557
|
children: [
|
|
3091
|
-
/* @__PURE__ */
|
|
3558
|
+
/* @__PURE__ */ jsx9(Plus4, { className: "h-4 w-4" }),
|
|
3092
3559
|
"New Script"
|
|
3093
3560
|
]
|
|
3094
3561
|
}
|
|
3095
3562
|
)
|
|
3096
3563
|
] }),
|
|
3097
|
-
/* @__PURE__ */
|
|
3098
|
-
/* @__PURE__ */
|
|
3099
|
-
/* @__PURE__ */
|
|
3100
|
-
/* @__PURE__ */
|
|
3564
|
+
/* @__PURE__ */ jsxs9("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-4", children: [
|
|
3565
|
+
/* @__PURE__ */ jsxs9("div", { className: "rounded-lg border border-border bg-card p-5 shadow-[var(--shadow-card)]", children: [
|
|
3566
|
+
/* @__PURE__ */ jsx9("p", { className: "text-[10px] font-bold uppercase tracking-widest text-muted-foreground", children: "Total Scripts" }),
|
|
3567
|
+
/* @__PURE__ */ jsx9("div", { className: "mt-2 flex items-baseline gap-2", children: /* @__PURE__ */ jsx9("span", { className: "font-display text-2xl font-extrabold text-foreground", children: scripts.length }) })
|
|
3101
3568
|
] }),
|
|
3102
|
-
/* @__PURE__ */
|
|
3103
|
-
/* @__PURE__ */
|
|
3104
|
-
/* @__PURE__ */
|
|
3105
|
-
/* @__PURE__ */
|
|
3106
|
-
/* @__PURE__ */
|
|
3569
|
+
/* @__PURE__ */ jsxs9("div", { className: "rounded-lg border border-border bg-card p-5 shadow-[var(--shadow-card)]", children: [
|
|
3570
|
+
/* @__PURE__ */ jsx9("p", { className: "text-[10px] font-bold uppercase tracking-widest text-muted-foreground", children: "Active" }),
|
|
3571
|
+
/* @__PURE__ */ jsxs9("div", { className: "mt-2 flex items-baseline gap-2", children: [
|
|
3572
|
+
/* @__PURE__ */ jsx9("span", { className: "font-display text-2xl font-extrabold text-foreground", children: activeCount }),
|
|
3573
|
+
/* @__PURE__ */ jsxs9("span", { className: "text-xs text-muted-foreground", children: [
|
|
3107
3574
|
"of ",
|
|
3108
3575
|
scripts.length
|
|
3109
3576
|
] })
|
|
3110
3577
|
] })
|
|
3111
3578
|
] }),
|
|
3112
|
-
/* @__PURE__ */
|
|
3579
|
+
/* @__PURE__ */ jsx9(
|
|
3113
3580
|
InfoPanel,
|
|
3114
3581
|
{
|
|
3115
3582
|
className: "md:col-span-2",
|
|
@@ -3119,12 +3586,12 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3119
3586
|
}
|
|
3120
3587
|
)
|
|
3121
3588
|
] }),
|
|
3122
|
-
error && /* @__PURE__ */
|
|
3123
|
-
/* @__PURE__ */
|
|
3124
|
-
/* @__PURE__ */
|
|
3589
|
+
error && /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-3 rounded-lg border border-destructive/30 bg-destructive/10 p-4", children: [
|
|
3590
|
+
/* @__PURE__ */ jsx9(AlertCircle3, { className: "h-5 w-5 shrink-0 text-destructive" }),
|
|
3591
|
+
/* @__PURE__ */ jsx9("p", { className: "text-sm font-medium text-destructive", children: error })
|
|
3125
3592
|
] }),
|
|
3126
|
-
/* @__PURE__ */
|
|
3127
|
-
dialogStep === "picker" && /* @__PURE__ */
|
|
3593
|
+
/* @__PURE__ */ jsx9(Dialog4, { open: isDialogOpen, onOpenChange: setIsDialogOpen, children: /* @__PURE__ */ jsxs9(DialogContent4, { className: "max-w-2xl max-h-[90vh] overflow-y-auto", children: [
|
|
3594
|
+
dialogStep === "picker" && /* @__PURE__ */ jsxs9(
|
|
3128
3595
|
"div",
|
|
3129
3596
|
{
|
|
3130
3597
|
className: cn(
|
|
@@ -3132,14 +3599,14 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3132
3599
|
transitionDir === "back" ? "slide-in-from-left-4" : "slide-in-from-right-4"
|
|
3133
3600
|
),
|
|
3134
3601
|
children: [
|
|
3135
|
-
/* @__PURE__ */
|
|
3136
|
-
/* @__PURE__ */
|
|
3137
|
-
/* @__PURE__ */
|
|
3602
|
+
/* @__PURE__ */ jsxs9(DialogHeader4, { children: [
|
|
3603
|
+
/* @__PURE__ */ jsx9(DialogTitle4, { children: "New Startup Script" }),
|
|
3604
|
+
/* @__PURE__ */ jsx9(DialogDescription4, { children: "Start from a template or create a blank script." })
|
|
3138
3605
|
] }),
|
|
3139
|
-
/* @__PURE__ */
|
|
3140
|
-
/* @__PURE__ */
|
|
3141
|
-
/* @__PURE__ */
|
|
3142
|
-
/* @__PURE__ */
|
|
3606
|
+
/* @__PURE__ */ jsxs9("div", { className: "space-y-4 py-2", children: [
|
|
3607
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3608
|
+
/* @__PURE__ */ jsx9("p", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground mb-2", children: "Blank Script" }),
|
|
3609
|
+
/* @__PURE__ */ jsx9("div", { className: "flex flex-wrap gap-2", children: Object.entries(SCRIPT_TYPE_META).map(([type, meta]) => /* @__PURE__ */ jsx9(
|
|
3143
3610
|
"button",
|
|
3144
3611
|
{
|
|
3145
3612
|
type: "button",
|
|
@@ -3150,24 +3617,24 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3150
3617
|
type
|
|
3151
3618
|
)) })
|
|
3152
3619
|
] }),
|
|
3153
|
-
/* @__PURE__ */
|
|
3154
|
-
/* @__PURE__ */
|
|
3155
|
-
/* @__PURE__ */
|
|
3620
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3621
|
+
/* @__PURE__ */ jsx9("p", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground mb-2", children: "Templates" }),
|
|
3622
|
+
/* @__PURE__ */ jsx9("div", { className: "space-y-2", children: SCRIPT_TEMPLATES.map((tmpl) => /* @__PURE__ */ jsxs9(
|
|
3156
3623
|
"button",
|
|
3157
3624
|
{
|
|
3158
3625
|
type: "button",
|
|
3159
3626
|
onClick: () => openFromTemplate(tmpl),
|
|
3160
3627
|
className: "w-full text-left rounded-lg border border-border bg-card p-4 hover:border-primary/30 hover:bg-muted/30 transition-colors group",
|
|
3161
3628
|
children: [
|
|
3162
|
-
/* @__PURE__ */
|
|
3163
|
-
/* @__PURE__ */
|
|
3164
|
-
/* @__PURE__ */
|
|
3165
|
-
/* @__PURE__ */
|
|
3629
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between", children: [
|
|
3630
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3631
|
+
/* @__PURE__ */ jsx9("h4", { className: "text-sm font-bold text-foreground group-hover:text-primary transition-colors", children: tmpl.name }),
|
|
3632
|
+
/* @__PURE__ */ jsx9("p", { className: "mt-0.5 text-xs text-muted-foreground", children: tmpl.description })
|
|
3166
3633
|
] }),
|
|
3167
|
-
/* @__PURE__ */
|
|
3634
|
+
/* @__PURE__ */ jsx9("span", { className: "text-[10px] font-mono text-muted-foreground bg-muted rounded px-1.5 py-0.5", children: SCRIPT_TYPE_META[tmpl.scriptType].label })
|
|
3168
3635
|
] }),
|
|
3169
|
-
tmpl.injectSecrets.length > 0 && /* @__PURE__ */
|
|
3170
|
-
/* @__PURE__ */
|
|
3636
|
+
tmpl.injectSecrets.length > 0 && /* @__PURE__ */ jsx9("div", { className: "mt-2 flex flex-wrap gap-1", children: tmpl.injectSecrets.map((s) => /* @__PURE__ */ jsxs9("span", { className: "inline-flex items-center gap-0.5 rounded-full bg-muted px-2 py-0.5 text-[10px] text-muted-foreground", children: [
|
|
3637
|
+
/* @__PURE__ */ jsx9(Lock2, { className: "h-2.5 w-2.5" }),
|
|
3171
3638
|
s
|
|
3172
3639
|
] }, s)) })
|
|
3173
3640
|
]
|
|
@@ -3180,7 +3647,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3180
3647
|
},
|
|
3181
3648
|
`picker-${stepKey}`
|
|
3182
3649
|
),
|
|
3183
|
-
dialogStep === "form" && /* @__PURE__ */
|
|
3650
|
+
dialogStep === "form" && /* @__PURE__ */ jsxs9(
|
|
3184
3651
|
"div",
|
|
3185
3652
|
{
|
|
3186
3653
|
className: cn(
|
|
@@ -3188,14 +3655,14 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3188
3655
|
transitionDir === "forward" ? "slide-in-from-right-4" : "slide-in-from-left-4"
|
|
3189
3656
|
),
|
|
3190
3657
|
children: [
|
|
3191
|
-
/* @__PURE__ */
|
|
3192
|
-
/* @__PURE__ */
|
|
3193
|
-
/* @__PURE__ */
|
|
3658
|
+
/* @__PURE__ */ jsxs9(DialogHeader4, { children: [
|
|
3659
|
+
/* @__PURE__ */ jsx9(DialogTitle4, { children: editingScript ? "Edit Script" : "Create Startup Script" }),
|
|
3660
|
+
/* @__PURE__ */ jsx9(DialogDescription4, { children: editingScript ? "Modify your startup script configuration." : "Define a shell script that runs when sandboxes start. Scripts execute before the AI agent." })
|
|
3194
3661
|
] }),
|
|
3195
|
-
/* @__PURE__ */
|
|
3196
|
-
/* @__PURE__ */
|
|
3197
|
-
/* @__PURE__ */
|
|
3198
|
-
/* @__PURE__ */
|
|
3662
|
+
/* @__PURE__ */ jsxs9("div", { className: "space-y-5 py-2", children: [
|
|
3663
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3664
|
+
/* @__PURE__ */ jsx9("label", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground", children: "Name" }),
|
|
3665
|
+
/* @__PURE__ */ jsx9(
|
|
3199
3666
|
"input",
|
|
3200
3667
|
{
|
|
3201
3668
|
type: "text",
|
|
@@ -3207,9 +3674,9 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3207
3674
|
}
|
|
3208
3675
|
)
|
|
3209
3676
|
] }),
|
|
3210
|
-
/* @__PURE__ */
|
|
3211
|
-
/* @__PURE__ */
|
|
3212
|
-
/* @__PURE__ */
|
|
3677
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3678
|
+
/* @__PURE__ */ jsx9("label", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground", children: "Description" }),
|
|
3679
|
+
/* @__PURE__ */ jsx9(
|
|
3213
3680
|
"input",
|
|
3214
3681
|
{
|
|
3215
3682
|
type: "text",
|
|
@@ -3221,9 +3688,9 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3221
3688
|
}
|
|
3222
3689
|
)
|
|
3223
3690
|
] }),
|
|
3224
|
-
/* @__PURE__ */
|
|
3225
|
-
/* @__PURE__ */
|
|
3226
|
-
/* @__PURE__ */
|
|
3691
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3692
|
+
/* @__PURE__ */ jsx9("label", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground", children: "Language" }),
|
|
3693
|
+
/* @__PURE__ */ jsx9("div", { className: "mt-1.5 flex flex-wrap gap-2", children: Object.entries(SCRIPT_TYPE_META).map(([type, meta]) => /* @__PURE__ */ jsx9(
|
|
3227
3694
|
"button",
|
|
3228
3695
|
{
|
|
3229
3696
|
type: "button",
|
|
@@ -3245,9 +3712,9 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3245
3712
|
type
|
|
3246
3713
|
)) })
|
|
3247
3714
|
] }),
|
|
3248
|
-
/* @__PURE__ */
|
|
3249
|
-
/* @__PURE__ */
|
|
3250
|
-
/* @__PURE__ */
|
|
3715
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3716
|
+
/* @__PURE__ */ jsx9("label", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground", children: "Script" }),
|
|
3717
|
+
/* @__PURE__ */ jsx9(
|
|
3251
3718
|
"textarea",
|
|
3252
3719
|
{
|
|
3253
3720
|
value: formData.content,
|
|
@@ -3257,19 +3724,19 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3257
3724
|
className: "mt-1.5 w-full rounded-lg border border-border bg-[var(--depth-1,hsl(var(--muted)))] px-4 py-3 font-mono text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/30 resize-y"
|
|
3258
3725
|
}
|
|
3259
3726
|
),
|
|
3260
|
-
/* @__PURE__ */
|
|
3727
|
+
/* @__PURE__ */ jsxs9("p", { className: "mt-1 text-xs text-muted-foreground", children: [
|
|
3261
3728
|
SCRIPT_TYPE_META[formData.scriptType].label,
|
|
3262
3729
|
" script. Injected secrets are available as environment variables (e.g. ",
|
|
3263
|
-
/* @__PURE__ */
|
|
3730
|
+
/* @__PURE__ */ jsx9("code", { className: "text-primary", children: "$GITHUB_TOKEN" }),
|
|
3264
3731
|
")."
|
|
3265
3732
|
] })
|
|
3266
3733
|
] }),
|
|
3267
|
-
secrets.length > 0 && /* @__PURE__ */
|
|
3268
|
-
/* @__PURE__ */
|
|
3269
|
-
/* @__PURE__ */
|
|
3270
|
-
/* @__PURE__ */
|
|
3734
|
+
secrets.length > 0 && /* @__PURE__ */ jsxs9("div", { children: [
|
|
3735
|
+
/* @__PURE__ */ jsx9("label", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground", children: "Inject Secrets" }),
|
|
3736
|
+
/* @__PURE__ */ jsx9("p", { className: "mt-0.5 text-xs text-muted-foreground", children: "Select secrets to make available as environment variables." }),
|
|
3737
|
+
/* @__PURE__ */ jsx9("div", { className: "mt-2 flex flex-wrap gap-2", children: secrets.map((secret) => {
|
|
3271
3738
|
const selected = formData.injectSecrets.includes(secret.name);
|
|
3272
|
-
return /* @__PURE__ */
|
|
3739
|
+
return /* @__PURE__ */ jsxs9(
|
|
3273
3740
|
"button",
|
|
3274
3741
|
{
|
|
3275
3742
|
type: "button",
|
|
@@ -3279,7 +3746,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3279
3746
|
selected ? "bg-primary/10 border-primary/30 text-primary" : "bg-muted border-border text-muted-foreground hover:border-primary/20"
|
|
3280
3747
|
),
|
|
3281
3748
|
children: [
|
|
3282
|
-
/* @__PURE__ */
|
|
3749
|
+
/* @__PURE__ */ jsx9(Lock2, { className: "h-3 w-3" }),
|
|
3283
3750
|
secret.name
|
|
3284
3751
|
]
|
|
3285
3752
|
},
|
|
@@ -3287,29 +3754,29 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3287
3754
|
);
|
|
3288
3755
|
}) })
|
|
3289
3756
|
] }),
|
|
3290
|
-
/* @__PURE__ */
|
|
3291
|
-
/* @__PURE__ */
|
|
3757
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3758
|
+
/* @__PURE__ */ jsxs9(
|
|
3292
3759
|
"button",
|
|
3293
3760
|
{
|
|
3294
3761
|
type: "button",
|
|
3295
3762
|
onClick: () => setShowConditions(!showConditions),
|
|
3296
3763
|
className: "flex items-center gap-2 text-xs font-bold uppercase tracking-widest text-muted-foreground hover:text-foreground transition-colors",
|
|
3297
3764
|
children: [
|
|
3298
|
-
showConditions ? /* @__PURE__ */
|
|
3765
|
+
showConditions ? /* @__PURE__ */ jsx9(ChevronUp, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx9(ChevronDown2, { className: "h-3.5 w-3.5" }),
|
|
3299
3766
|
"Conditions & Execution"
|
|
3300
3767
|
]
|
|
3301
3768
|
}
|
|
3302
3769
|
),
|
|
3303
|
-
showConditions && /* @__PURE__ */
|
|
3304
|
-
/* @__PURE__ */
|
|
3305
|
-
/* @__PURE__ */
|
|
3306
|
-
/* @__PURE__ */
|
|
3770
|
+
showConditions && /* @__PURE__ */ jsxs9("div", { className: "mt-3 space-y-4 rounded-lg border border-border bg-muted/30 p-4", children: [
|
|
3771
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3772
|
+
/* @__PURE__ */ jsxs9("label", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground flex items-center gap-1.5", children: [
|
|
3773
|
+
/* @__PURE__ */ jsx9(Layers3, { className: "h-3.5 w-3.5" }),
|
|
3307
3774
|
"Environments"
|
|
3308
3775
|
] }),
|
|
3309
|
-
/* @__PURE__ */
|
|
3310
|
-
environments.length > 0 && /* @__PURE__ */
|
|
3776
|
+
/* @__PURE__ */ jsx9("p", { className: "mt-0.5 text-xs text-muted-foreground", children: environments.length > 0 ? "Only run for these environments. Leave empty to run for all." : "No templates configured. Script will run for all environments." }),
|
|
3777
|
+
environments.length > 0 && /* @__PURE__ */ jsx9("div", { className: "mt-2 flex flex-wrap gap-2", children: environments.map((env) => {
|
|
3311
3778
|
const selected = formData.environments.includes(env.id);
|
|
3312
|
-
return /* @__PURE__ */
|
|
3779
|
+
return /* @__PURE__ */ jsx9(
|
|
3313
3780
|
"button",
|
|
3314
3781
|
{
|
|
3315
3782
|
type: "button",
|
|
@@ -3324,13 +3791,13 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3324
3791
|
);
|
|
3325
3792
|
}) })
|
|
3326
3793
|
] }),
|
|
3327
|
-
/* @__PURE__ */
|
|
3328
|
-
/* @__PURE__ */
|
|
3329
|
-
/* @__PURE__ */
|
|
3330
|
-
/* @__PURE__ */
|
|
3794
|
+
/* @__PURE__ */ jsxs9("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
3795
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3796
|
+
/* @__PURE__ */ jsxs9("label", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground flex items-center gap-1.5", children: [
|
|
3797
|
+
/* @__PURE__ */ jsx9(Cpu2, { className: "h-3.5 w-3.5" }),
|
|
3331
3798
|
"Min CPU Cores"
|
|
3332
3799
|
] }),
|
|
3333
|
-
/* @__PURE__ */
|
|
3800
|
+
/* @__PURE__ */ jsx9(
|
|
3334
3801
|
"input",
|
|
3335
3802
|
{
|
|
3336
3803
|
type: "number",
|
|
@@ -3346,12 +3813,12 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3346
3813
|
}
|
|
3347
3814
|
)
|
|
3348
3815
|
] }),
|
|
3349
|
-
/* @__PURE__ */
|
|
3350
|
-
/* @__PURE__ */
|
|
3351
|
-
/* @__PURE__ */
|
|
3816
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3817
|
+
/* @__PURE__ */ jsxs9("label", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground flex items-center gap-1.5", children: [
|
|
3818
|
+
/* @__PURE__ */ jsx9(MemoryStick, { className: "h-3.5 w-3.5" }),
|
|
3352
3819
|
"Min RAM (GB)"
|
|
3353
3820
|
] }),
|
|
3354
|
-
/* @__PURE__ */
|
|
3821
|
+
/* @__PURE__ */ jsx9(
|
|
3355
3822
|
"input",
|
|
3356
3823
|
{
|
|
3357
3824
|
type: "number",
|
|
@@ -3368,13 +3835,13 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3368
3835
|
)
|
|
3369
3836
|
] })
|
|
3370
3837
|
] }),
|
|
3371
|
-
/* @__PURE__ */
|
|
3372
|
-
/* @__PURE__ */
|
|
3373
|
-
/* @__PURE__ */
|
|
3374
|
-
/* @__PURE__ */
|
|
3838
|
+
/* @__PURE__ */ jsxs9("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
3839
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3840
|
+
/* @__PURE__ */ jsxs9("label", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground flex items-center gap-1.5", children: [
|
|
3841
|
+
/* @__PURE__ */ jsx9(GripVertical, { className: "h-3.5 w-3.5" }),
|
|
3375
3842
|
"Run Order"
|
|
3376
3843
|
] }),
|
|
3377
|
-
/* @__PURE__ */
|
|
3844
|
+
/* @__PURE__ */ jsx9(
|
|
3378
3845
|
"input",
|
|
3379
3846
|
{
|
|
3380
3847
|
type: "number",
|
|
@@ -3385,14 +3852,14 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3385
3852
|
className: "mt-1.5 w-full rounded-lg border border-border bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/30"
|
|
3386
3853
|
}
|
|
3387
3854
|
),
|
|
3388
|
-
/* @__PURE__ */
|
|
3855
|
+
/* @__PURE__ */ jsx9("p", { className: "mt-1 text-xs text-muted-foreground", children: "Lower runs first" })
|
|
3389
3856
|
] }),
|
|
3390
|
-
/* @__PURE__ */
|
|
3391
|
-
/* @__PURE__ */
|
|
3392
|
-
/* @__PURE__ */
|
|
3857
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3858
|
+
/* @__PURE__ */ jsxs9("label", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground flex items-center gap-1.5", children: [
|
|
3859
|
+
/* @__PURE__ */ jsx9(Clock, { className: "h-3.5 w-3.5" }),
|
|
3393
3860
|
"Timeout (seconds)"
|
|
3394
3861
|
] }),
|
|
3395
|
-
/* @__PURE__ */
|
|
3862
|
+
/* @__PURE__ */ jsx9(
|
|
3396
3863
|
"input",
|
|
3397
3864
|
{
|
|
3398
3865
|
type: "number",
|
|
@@ -3405,13 +3872,13 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3405
3872
|
)
|
|
3406
3873
|
] })
|
|
3407
3874
|
] }),
|
|
3408
|
-
/* @__PURE__ */
|
|
3409
|
-
/* @__PURE__ */
|
|
3410
|
-
/* @__PURE__ */
|
|
3411
|
-
/* @__PURE__ */
|
|
3412
|
-
/* @__PURE__ */
|
|
3875
|
+
/* @__PURE__ */ jsxs9("div", { className: "space-y-3", children: [
|
|
3876
|
+
/* @__PURE__ */ jsxs9("label", { className: "flex items-center justify-between cursor-pointer", children: [
|
|
3877
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3878
|
+
/* @__PURE__ */ jsx9("span", { className: "text-sm font-medium text-foreground", children: "Continue on failure" }),
|
|
3879
|
+
/* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: "If script fails, continue starting the sandbox" })
|
|
3413
3880
|
] }),
|
|
3414
|
-
/* @__PURE__ */
|
|
3881
|
+
/* @__PURE__ */ jsx9(
|
|
3415
3882
|
"button",
|
|
3416
3883
|
{
|
|
3417
3884
|
type: "button",
|
|
@@ -3420,7 +3887,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3420
3887
|
"relative h-6 w-11 rounded-full transition-colors",
|
|
3421
3888
|
formData.continueOnFailure ? "bg-primary" : "bg-border"
|
|
3422
3889
|
),
|
|
3423
|
-
children: /* @__PURE__ */
|
|
3890
|
+
children: /* @__PURE__ */ jsx9(
|
|
3424
3891
|
"span",
|
|
3425
3892
|
{
|
|
3426
3893
|
className: cn(
|
|
@@ -3432,12 +3899,12 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3432
3899
|
}
|
|
3433
3900
|
)
|
|
3434
3901
|
] }),
|
|
3435
|
-
/* @__PURE__ */
|
|
3436
|
-
/* @__PURE__ */
|
|
3437
|
-
/* @__PURE__ */
|
|
3438
|
-
/* @__PURE__ */
|
|
3902
|
+
/* @__PURE__ */ jsxs9("label", { className: "flex items-center justify-between cursor-pointer", children: [
|
|
3903
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3904
|
+
/* @__PURE__ */ jsx9("span", { className: "text-sm font-medium text-foreground", children: "Run as root" }),
|
|
3905
|
+
/* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: "Execute with root privileges instead of the agent user" })
|
|
3439
3906
|
] }),
|
|
3440
|
-
/* @__PURE__ */
|
|
3907
|
+
/* @__PURE__ */ jsx9(
|
|
3441
3908
|
"button",
|
|
3442
3909
|
{
|
|
3443
3910
|
type: "button",
|
|
@@ -3446,7 +3913,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3446
3913
|
"relative h-6 w-11 rounded-full transition-colors",
|
|
3447
3914
|
formData.runAsRoot ? "bg-primary" : "bg-border"
|
|
3448
3915
|
),
|
|
3449
|
-
children: /* @__PURE__ */
|
|
3916
|
+
children: /* @__PURE__ */ jsx9(
|
|
3450
3917
|
"span",
|
|
3451
3918
|
{
|
|
3452
3919
|
className: cn(
|
|
@@ -3461,26 +3928,26 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3461
3928
|
] })
|
|
3462
3929
|
] })
|
|
3463
3930
|
] }),
|
|
3464
|
-
formError && /* @__PURE__ */
|
|
3465
|
-
/* @__PURE__ */
|
|
3466
|
-
/* @__PURE__ */
|
|
3931
|
+
formError && /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 rounded-lg border border-destructive/30 bg-destructive/10 p-3", children: [
|
|
3932
|
+
/* @__PURE__ */ jsx9(AlertCircle3, { className: "h-4 w-4 text-destructive" }),
|
|
3933
|
+
/* @__PURE__ */ jsx9("p", { className: "text-sm text-destructive", children: formError })
|
|
3467
3934
|
] })
|
|
3468
3935
|
] }),
|
|
3469
|
-
/* @__PURE__ */
|
|
3470
|
-
/* @__PURE__ */
|
|
3936
|
+
/* @__PURE__ */ jsxs9(DialogFooter4, { className: "flex items-center justify-between sm:justify-between", children: [
|
|
3937
|
+
/* @__PURE__ */ jsx9("div", { children: !editingScript && /* @__PURE__ */ jsxs9(
|
|
3471
3938
|
"button",
|
|
3472
3939
|
{
|
|
3473
3940
|
type: "button",
|
|
3474
3941
|
onClick: () => goToStep("picker"),
|
|
3475
3942
|
className: "inline-flex items-center gap-1.5 rounded-lg border border-border px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
|
|
3476
3943
|
children: [
|
|
3477
|
-
/* @__PURE__ */
|
|
3944
|
+
/* @__PURE__ */ jsx9("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx9("path", { d: "m15 18-6-6 6-6" }) }),
|
|
3478
3945
|
"Back"
|
|
3479
3946
|
]
|
|
3480
3947
|
}
|
|
3481
3948
|
) }),
|
|
3482
|
-
/* @__PURE__ */
|
|
3483
|
-
/* @__PURE__ */
|
|
3949
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
3950
|
+
/* @__PURE__ */ jsx9(
|
|
3484
3951
|
"button",
|
|
3485
3952
|
{
|
|
3486
3953
|
type: "button",
|
|
@@ -3489,7 +3956,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3489
3956
|
children: "Cancel"
|
|
3490
3957
|
}
|
|
3491
3958
|
),
|
|
3492
|
-
/* @__PURE__ */
|
|
3959
|
+
/* @__PURE__ */ jsx9(
|
|
3493
3960
|
"button",
|
|
3494
3961
|
{
|
|
3495
3962
|
type: "button",
|
|
@@ -3506,17 +3973,17 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3506
3973
|
`form-${stepKey}`
|
|
3507
3974
|
)
|
|
3508
3975
|
] }) }),
|
|
3509
|
-
/* @__PURE__ */
|
|
3510
|
-
/* @__PURE__ */
|
|
3511
|
-
/* @__PURE__ */
|
|
3512
|
-
/* @__PURE__ */
|
|
3976
|
+
/* @__PURE__ */ jsx9(Dialog4, { open: !!deleteTarget, onOpenChange: () => setDeleteTarget(null), children: /* @__PURE__ */ jsxs9(DialogContent4, { className: "max-w-md", children: [
|
|
3977
|
+
/* @__PURE__ */ jsxs9(DialogHeader4, { children: [
|
|
3978
|
+
/* @__PURE__ */ jsx9(DialogTitle4, { children: "Delete Startup Script" }),
|
|
3979
|
+
/* @__PURE__ */ jsxs9(DialogDescription4, { children: [
|
|
3513
3980
|
"Are you sure you want to delete \u201C",
|
|
3514
3981
|
deleteTarget?.name,
|
|
3515
3982
|
"\u201D? This action cannot be undone."
|
|
3516
3983
|
] })
|
|
3517
3984
|
] }),
|
|
3518
|
-
/* @__PURE__ */
|
|
3519
|
-
/* @__PURE__ */
|
|
3985
|
+
/* @__PURE__ */ jsxs9(DialogFooter4, { children: [
|
|
3986
|
+
/* @__PURE__ */ jsx9(
|
|
3520
3987
|
"button",
|
|
3521
3988
|
{
|
|
3522
3989
|
type: "button",
|
|
@@ -3525,7 +3992,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3525
3992
|
children: "Cancel"
|
|
3526
3993
|
}
|
|
3527
3994
|
),
|
|
3528
|
-
/* @__PURE__ */
|
|
3995
|
+
/* @__PURE__ */ jsx9(
|
|
3529
3996
|
"button",
|
|
3530
3997
|
{
|
|
3531
3998
|
type: "button",
|
|
@@ -3537,20 +4004,20 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3537
4004
|
)
|
|
3538
4005
|
] })
|
|
3539
4006
|
] }) }),
|
|
3540
|
-
/* @__PURE__ */
|
|
3541
|
-
/* @__PURE__ */
|
|
3542
|
-
/* @__PURE__ */
|
|
3543
|
-
/* @__PURE__ */
|
|
4007
|
+
/* @__PURE__ */ jsxs9("div", { className: "overflow-hidden rounded-lg border border-border bg-card shadow-[var(--shadow-card)]", children: [
|
|
4008
|
+
/* @__PURE__ */ jsxs9("div", { className: "border-b border-border px-6 py-4 flex items-center justify-between", children: [
|
|
4009
|
+
/* @__PURE__ */ jsx9("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx9("button", { className: "text-xs font-bold uppercase tracking-widest text-foreground", children: "All Scripts" }) }),
|
|
4010
|
+
/* @__PURE__ */ jsxs9("span", { className: "text-xs text-muted-foreground font-mono", children: [
|
|
3544
4011
|
scripts.length,
|
|
3545
4012
|
" script",
|
|
3546
4013
|
scripts.length !== 1 ? "s" : ""
|
|
3547
4014
|
] })
|
|
3548
4015
|
] }),
|
|
3549
|
-
loading ? /* @__PURE__ */
|
|
3550
|
-
/* @__PURE__ */
|
|
3551
|
-
/* @__PURE__ */
|
|
3552
|
-
/* @__PURE__ */
|
|
3553
|
-
/* @__PURE__ */
|
|
4016
|
+
loading ? /* @__PURE__ */ jsx9("div", { className: "flex items-center justify-center py-16", children: /* @__PURE__ */ jsx9("div", { className: "h-6 w-6 animate-spin rounded-full border-2 border-primary border-t-transparent" }) }) : scripts.length === 0 ? /* @__PURE__ */ jsxs9("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [
|
|
4017
|
+
/* @__PURE__ */ jsx9(Terminal, { className: "h-10 w-10 text-muted-foreground mb-4" }),
|
|
4018
|
+
/* @__PURE__ */ jsx9("h3", { className: "text-lg font-semibold text-foreground", children: "No startup scripts yet" }),
|
|
4019
|
+
/* @__PURE__ */ jsx9("p", { className: "mt-1 text-sm text-muted-foreground max-w-sm", children: "Create a script to run automatically when your sandboxes start." }),
|
|
4020
|
+
/* @__PURE__ */ jsxs9(
|
|
3554
4021
|
"button",
|
|
3555
4022
|
{
|
|
3556
4023
|
type: "button",
|
|
@@ -3558,12 +4025,12 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3558
4025
|
"aria-label": "Create your first startup script",
|
|
3559
4026
|
className: "mt-4 inline-flex items-center gap-2 rounded-lg bg-[var(--btn-primary-bg)] px-4 py-2.5 text-sm font-bold text-[var(--btn-primary-text)] shadow-sm transition-colors hover:bg-[var(--btn-primary-hover)]",
|
|
3560
4027
|
children: [
|
|
3561
|
-
/* @__PURE__ */
|
|
4028
|
+
/* @__PURE__ */ jsx9(Plus4, { className: "h-4 w-4" }),
|
|
3562
4029
|
"New Script"
|
|
3563
4030
|
]
|
|
3564
4031
|
}
|
|
3565
4032
|
)
|
|
3566
|
-
] }) : /* @__PURE__ */
|
|
4033
|
+
] }) : /* @__PURE__ */ jsx9("div", { className: "divide-y divide-border", children: scripts.map((script) => /* @__PURE__ */ jsxs9(
|
|
3567
4034
|
"div",
|
|
3568
4035
|
{
|
|
3569
4036
|
className: cn(
|
|
@@ -3571,7 +4038,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3571
4038
|
!script.enabled && "opacity-60"
|
|
3572
4039
|
),
|
|
3573
4040
|
children: [
|
|
3574
|
-
/* @__PURE__ */
|
|
4041
|
+
/* @__PURE__ */ jsx9(
|
|
3575
4042
|
"button",
|
|
3576
4043
|
{
|
|
3577
4044
|
type: "button",
|
|
@@ -3581,53 +4048,53 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3581
4048
|
"flex h-8 w-8 shrink-0 items-center justify-center rounded-full transition-colors",
|
|
3582
4049
|
script.enabled ? "bg-[var(--surface-success-bg,hsl(142 76% 90%))] text-[var(--surface-success-text,hsl(142 76% 36%))]" : "bg-muted text-muted-foreground"
|
|
3583
4050
|
),
|
|
3584
|
-
children: script.enabled ? /* @__PURE__ */
|
|
4051
|
+
children: script.enabled ? /* @__PURE__ */ jsx9(Power, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx9(PowerOff, { className: "h-4 w-4" })
|
|
3585
4052
|
}
|
|
3586
4053
|
),
|
|
3587
|
-
/* @__PURE__ */
|
|
3588
|
-
/* @__PURE__ */
|
|
3589
|
-
/* @__PURE__ */
|
|
3590
|
-
/* @__PURE__ */
|
|
3591
|
-
script.runOrder !== 100 && /* @__PURE__ */
|
|
4054
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex-1 min-w-0", children: [
|
|
4055
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
4056
|
+
/* @__PURE__ */ jsx9("h4", { className: "text-sm font-bold text-foreground truncate", children: script.name }),
|
|
4057
|
+
/* @__PURE__ */ jsx9("span", { className: "text-[10px] font-mono text-muted-foreground bg-muted rounded px-1.5 py-0.5", children: SCRIPT_TYPE_META[script.scriptType ?? "bash"].label }),
|
|
4058
|
+
script.runOrder !== 100 && /* @__PURE__ */ jsxs9("span", { className: "text-[10px] font-mono text-muted-foreground bg-muted rounded px-1.5 py-0.5", children: [
|
|
3592
4059
|
"#",
|
|
3593
4060
|
script.runOrder
|
|
3594
4061
|
] })
|
|
3595
4062
|
] }),
|
|
3596
|
-
script.description && /* @__PURE__ */
|
|
3597
|
-
/* @__PURE__ */
|
|
3598
|
-
script.environments.map((env) => /* @__PURE__ */
|
|
3599
|
-
script.injectSecrets.map((s) => /* @__PURE__ */
|
|
3600
|
-
/* @__PURE__ */
|
|
4063
|
+
script.description && /* @__PURE__ */ jsx9("p", { className: "mt-0.5 text-xs text-muted-foreground truncate", children: script.description }),
|
|
4064
|
+
/* @__PURE__ */ jsxs9("div", { className: "mt-1.5 flex flex-wrap gap-1.5", children: [
|
|
4065
|
+
script.environments.map((env) => /* @__PURE__ */ jsx9("span", { className: "rounded-full bg-primary/10 px-2 py-0.5 text-[10px] font-medium text-primary", children: env }, env)),
|
|
4066
|
+
script.injectSecrets.map((s) => /* @__PURE__ */ jsxs9("span", { className: "rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground flex items-center gap-0.5", children: [
|
|
4067
|
+
/* @__PURE__ */ jsx9(Lock2, { className: "h-2.5 w-2.5" }),
|
|
3601
4068
|
s
|
|
3602
4069
|
] }, s)),
|
|
3603
|
-
script.continueOnFailure && /* @__PURE__ */
|
|
3604
|
-
script.runAsRoot && /* @__PURE__ */
|
|
4070
|
+
script.continueOnFailure && /* @__PURE__ */ jsx9("span", { className: "rounded-full bg-amber-500/10 px-2 py-0.5 text-[10px] font-medium text-amber-600", children: "soft fail" }),
|
|
4071
|
+
script.runAsRoot && /* @__PURE__ */ jsx9("span", { className: "rounded-full bg-destructive/10 px-2 py-0.5 text-[10px] font-medium text-destructive", children: "root" })
|
|
3605
4072
|
] })
|
|
3606
4073
|
] }),
|
|
3607
|
-
/* @__PURE__ */
|
|
3608
|
-
/* @__PURE__ */
|
|
4074
|
+
/* @__PURE__ */ jsxs9("div", { className: "hidden md:flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
4075
|
+
/* @__PURE__ */ jsx9(Clock, { className: "h-3.5 w-3.5" }),
|
|
3609
4076
|
script.timeoutSeconds,
|
|
3610
4077
|
"s"
|
|
3611
4078
|
] }),
|
|
3612
|
-
/* @__PURE__ */
|
|
3613
|
-
/* @__PURE__ */
|
|
4079
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1 sm:opacity-0 sm:group-hover:opacity-100 sm:focus-within:opacity-100 transition-opacity", children: [
|
|
4080
|
+
/* @__PURE__ */ jsx9(
|
|
3614
4081
|
"button",
|
|
3615
4082
|
{
|
|
3616
4083
|
type: "button",
|
|
3617
4084
|
onClick: () => openEdit(script),
|
|
3618
4085
|
className: "rounded-md p-2 text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
|
|
3619
4086
|
"aria-label": `Edit ${script.name}`,
|
|
3620
|
-
children: /* @__PURE__ */
|
|
4087
|
+
children: /* @__PURE__ */ jsx9(Pencil, { className: "h-4 w-4" })
|
|
3621
4088
|
}
|
|
3622
4089
|
),
|
|
3623
|
-
/* @__PURE__ */
|
|
4090
|
+
/* @__PURE__ */ jsx9(
|
|
3624
4091
|
"button",
|
|
3625
4092
|
{
|
|
3626
4093
|
type: "button",
|
|
3627
4094
|
onClick: () => setDeleteTarget(script),
|
|
3628
4095
|
className: "rounded-md p-2 text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-colors",
|
|
3629
4096
|
"aria-label": `Delete ${script.name}`,
|
|
3630
|
-
children: /* @__PURE__ */
|
|
4097
|
+
children: /* @__PURE__ */ jsx9(Trash24, { className: "h-4 w-4" })
|
|
3631
4098
|
}
|
|
3632
4099
|
)
|
|
3633
4100
|
] })
|
|
@@ -3636,20 +4103,20 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3636
4103
|
script.id
|
|
3637
4104
|
)) })
|
|
3638
4105
|
] }),
|
|
3639
|
-
/* @__PURE__ */
|
|
3640
|
-
/* @__PURE__ */
|
|
3641
|
-
/* @__PURE__ */
|
|
3642
|
-
/* @__PURE__ */
|
|
3643
|
-
/* @__PURE__ */
|
|
4106
|
+
/* @__PURE__ */ jsxs9("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", children: [
|
|
4107
|
+
/* @__PURE__ */ jsxs9("div", { className: "rounded-lg border border-border bg-card p-6 shadow-[var(--shadow-card)]", children: [
|
|
4108
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-3 mb-3", children: [
|
|
4109
|
+
/* @__PURE__ */ jsx9("div", { className: "flex h-9 w-9 items-center justify-center rounded-md bg-[var(--brand-primary,hsl(var(--primary)))] text-[var(--btn-primary-text)]", children: /* @__PURE__ */ jsx9(Play, { className: "h-5 w-5" }) }),
|
|
4110
|
+
/* @__PURE__ */ jsx9("h3", { className: "text-sm font-bold text-foreground", children: "How Scripts Run" })
|
|
3644
4111
|
] }),
|
|
3645
|
-
/* @__PURE__ */
|
|
4112
|
+
/* @__PURE__ */ jsx9("p", { className: "text-sm text-muted-foreground", children: 'Scripts execute in order after the container starts but before the AI agent. They run as bash scripts with full access to mounted tools (Nix profile) and workspace. Failed scripts abort sandbox creation unless "continue on failure" is enabled.' })
|
|
3646
4113
|
] }),
|
|
3647
|
-
/* @__PURE__ */
|
|
3648
|
-
/* @__PURE__ */
|
|
3649
|
-
/* @__PURE__ */
|
|
3650
|
-
/* @__PURE__ */
|
|
4114
|
+
/* @__PURE__ */ jsxs9("div", { className: "rounded-lg border border-border bg-card p-6 shadow-[var(--shadow-card)]", children: [
|
|
4115
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-3 mb-3", children: [
|
|
4116
|
+
/* @__PURE__ */ jsx9("div", { className: "flex h-9 w-9 items-center justify-center rounded-md bg-[var(--brand-primary,hsl(var(--primary)))] text-[var(--btn-primary-text)]", children: /* @__PURE__ */ jsx9(Shield2, { className: "h-5 w-5" }) }),
|
|
4117
|
+
/* @__PURE__ */ jsx9("h3", { className: "text-sm font-bold text-foreground", children: "Security & Secrets" })
|
|
3651
4118
|
] }),
|
|
3652
|
-
/* @__PURE__ */
|
|
4119
|
+
/* @__PURE__ */ jsx9("p", { className: "text-sm text-muted-foreground", children: "Selected secrets are injected as environment variables at execution time. Secret values are never stored in the script itself \u2014 they are decrypted and injected only when the sandbox starts. Scripts can use conditions to restrict execution to specific environments or resource tiers." })
|
|
3653
4120
|
] })
|
|
3654
4121
|
] })
|
|
3655
4122
|
] });
|