@tangle-network/sandbox-ui 0.24.1 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-76TCOY2R.js → chunk-LDETDX7W.js} +9 -1
- package/dist/dashboard.d.ts +6 -0
- package/dist/dashboard.js +1 -1
- package/dist/globals.css +12 -10
- package/dist/index.js +1 -1
- package/dist/pages.d.ts +25 -2
- package/dist/pages.js +1302 -839
- 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
|
|
@@ -462,19 +468,177 @@ function BillingPage({
|
|
|
462
468
|
}
|
|
463
469
|
|
|
464
470
|
// src/pages/provisioning-wizard.tsx
|
|
465
|
-
import * as
|
|
471
|
+
import * as React3 from "react";
|
|
466
472
|
import {
|
|
467
473
|
ArrowLeft,
|
|
468
474
|
Layers,
|
|
469
475
|
Cpu,
|
|
470
476
|
Info,
|
|
471
|
-
Loader2,
|
|
477
|
+
Loader2 as Loader22,
|
|
472
478
|
Settings,
|
|
473
479
|
Plus,
|
|
474
480
|
Trash2,
|
|
475
481
|
Check
|
|
476
482
|
} from "lucide-react";
|
|
477
|
-
|
|
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";
|
|
478
642
|
var VALID_DRIVERS = /* @__PURE__ */ new Set([
|
|
479
643
|
"docker",
|
|
480
644
|
"firecracker",
|
|
@@ -527,7 +691,7 @@ function resolveEnvironment(env) {
|
|
|
527
691
|
id: env.id,
|
|
528
692
|
name: templateName,
|
|
529
693
|
description: env.description ?? "User template from snapshot",
|
|
530
|
-
icon: /* @__PURE__ */
|
|
694
|
+
icon: /* @__PURE__ */ jsx4("span", { className: "text-[var(--surface-success-text)] text-2xl font-bold", children: "T" }),
|
|
531
695
|
color: "green"
|
|
532
696
|
};
|
|
533
697
|
}
|
|
@@ -540,7 +704,7 @@ function resolveEnvironment(env) {
|
|
|
540
704
|
id: env.id,
|
|
541
705
|
name,
|
|
542
706
|
description: env.description ?? `${name} development environment`,
|
|
543
|
-
icon: /* @__PURE__ */
|
|
707
|
+
icon: /* @__PURE__ */ jsx4("span", { className: `${textClass} text-2xl font-bold`, children: abbr }),
|
|
544
708
|
color
|
|
545
709
|
};
|
|
546
710
|
}
|
|
@@ -549,21 +713,21 @@ var defaultEnvironments = [
|
|
|
549
713
|
id: "node",
|
|
550
714
|
name: "Node.js",
|
|
551
715
|
description: "v20.x LTS with optimized runtime for asynchronous event-driven agents.",
|
|
552
|
-
icon: /* @__PURE__ */
|
|
716
|
+
icon: /* @__PURE__ */ jsx4("span", { className: "text-[var(--code-success)] text-2xl font-bold", children: "N" }),
|
|
553
717
|
color: "green"
|
|
554
718
|
},
|
|
555
719
|
{
|
|
556
720
|
id: "python",
|
|
557
721
|
name: "Python",
|
|
558
722
|
description: "v3.11 pre-installed with PyTorch and common data science libraries.",
|
|
559
|
-
icon: /* @__PURE__ */
|
|
723
|
+
icon: /* @__PURE__ */ jsx4("span", { className: "text-sky-400 text-2xl font-bold", children: "Py" }),
|
|
560
724
|
color: "blue"
|
|
561
725
|
},
|
|
562
726
|
{
|
|
563
727
|
id: "ubuntu",
|
|
564
728
|
name: "Ubuntu",
|
|
565
729
|
description: "Full 22.04 LTS terminal access for custom containerized workloads.",
|
|
566
|
-
icon: /* @__PURE__ */
|
|
730
|
+
icon: /* @__PURE__ */ jsx4("span", { className: "text-orange-400 text-2xl font-bold", children: "U" }),
|
|
567
731
|
color: "orange"
|
|
568
732
|
}
|
|
569
733
|
];
|
|
@@ -634,47 +798,79 @@ function computeHourlyCost(cpu, ram, storage, rates) {
|
|
|
634
798
|
}
|
|
635
799
|
function SshAccessStep({ config }) {
|
|
636
800
|
const keys = config.keys ?? [];
|
|
801
|
+
const canAddKey = typeof config.onCreateKey === "function";
|
|
802
|
+
const [isAddKeyOpen, setIsAddKeyOpen] = React3.useState(false);
|
|
637
803
|
const inlineKeyCount = config.inlinePublicKeys.split(/\r?\n/).map((key) => key.trim()).filter(Boolean).length;
|
|
638
804
|
const totalKeyCount = config.selectedKeyIds.length + inlineKeyCount;
|
|
639
|
-
return /* @__PURE__ */
|
|
640
|
-
/* @__PURE__ */
|
|
641
|
-
/* @__PURE__ */
|
|
642
|
-
/* @__PURE__ */
|
|
643
|
-
/* @__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." })
|
|
644
810
|
] }),
|
|
645
|
-
/* @__PURE__ */
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
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
|
+
] })
|
|
649
830
|
] })
|
|
650
831
|
] }),
|
|
651
|
-
keys.length > 0 && /* @__PURE__ */
|
|
832
|
+
keys.length > 0 && /* @__PURE__ */ jsx4("div", { className: "grid gap-2 sm:grid-cols-2", children: keys.map((key) => {
|
|
652
833
|
const selected = config.selectedKeyIds.includes(key.id);
|
|
653
|
-
return /* @__PURE__ */
|
|
654
|
-
|
|
834
|
+
return /* @__PURE__ */ jsx4(
|
|
835
|
+
"button",
|
|
655
836
|
{
|
|
656
837
|
type: "button",
|
|
657
|
-
variant: selected ? "sandbox" : "outline",
|
|
658
|
-
className: "h-auto justify-start p-3 text-left",
|
|
659
838
|
"aria-pressed": selected,
|
|
660
839
|
onClick: () => {
|
|
661
840
|
config.onSelectedKeyIdsChange(
|
|
662
841
|
selected ? config.selectedKeyIds.filter((id) => id !== key.id) : [...config.selectedKeyIds, key.id]
|
|
663
842
|
);
|
|
664
843
|
},
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
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
|
+
)
|
|
672
868
|
] })
|
|
673
869
|
},
|
|
674
870
|
key.id
|
|
675
871
|
);
|
|
676
872
|
}) }),
|
|
677
|
-
/* @__PURE__ */
|
|
873
|
+
/* @__PURE__ */ jsx4(
|
|
678
874
|
Textarea,
|
|
679
875
|
{
|
|
680
876
|
className: "min-h-24 font-mono text-xs",
|
|
@@ -682,6 +878,18 @@ function SshAccessStep({ config }) {
|
|
|
682
878
|
value: config.inlinePublicKeys,
|
|
683
879
|
onChange: (event) => config.onInlinePublicKeysChange(event.target.value)
|
|
684
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
|
+
}
|
|
685
893
|
)
|
|
686
894
|
] });
|
|
687
895
|
}
|
|
@@ -691,10 +899,8 @@ function ProvisioningWizard({
|
|
|
691
899
|
onSubmit,
|
|
692
900
|
onBack,
|
|
693
901
|
className,
|
|
694
|
-
variant = "flat",
|
|
695
902
|
defaultEnvironment,
|
|
696
903
|
defaultConfig,
|
|
697
|
-
skipToReview,
|
|
698
904
|
onLoadStartupScripts,
|
|
699
905
|
resourceLimits,
|
|
700
906
|
sshAccess,
|
|
@@ -717,17 +923,17 @@ function ProvisioningWizard({
|
|
|
717
923
|
const ramStep = alignSliderStep(RAM_MIN, ramMax, RAM_STEP);
|
|
718
924
|
const storageStep = alignSliderStep(STORAGE_MIN, storageMax, STORAGE_STEP);
|
|
719
925
|
const dc = defaultConfig;
|
|
720
|
-
const [envList, setEnvList] =
|
|
926
|
+
const [envList, setEnvList] = React3.useState(() => {
|
|
721
927
|
if (environmentsProp) return environmentsProp;
|
|
722
928
|
if (onLoadEnvironments) return [];
|
|
723
929
|
return defaultEnvironments;
|
|
724
930
|
});
|
|
725
|
-
const [isLoadingEnvironments, setIsLoadingEnvironments] =
|
|
931
|
+
const [isLoadingEnvironments, setIsLoadingEnvironments] = React3.useState(
|
|
726
932
|
() => !environmentsProp && !!onLoadEnvironments
|
|
727
933
|
);
|
|
728
|
-
const onLoadEnvironmentsRef =
|
|
934
|
+
const onLoadEnvironmentsRef = React3.useRef(onLoadEnvironments);
|
|
729
935
|
onLoadEnvironmentsRef.current = onLoadEnvironments;
|
|
730
|
-
|
|
936
|
+
React3.useEffect(() => {
|
|
731
937
|
let cancelled = false;
|
|
732
938
|
if (onLoadEnvironmentsRef.current) {
|
|
733
939
|
setIsLoadingEnvironments(true);
|
|
@@ -753,10 +959,10 @@ function ProvisioningWizard({
|
|
|
753
959
|
}, [environmentsProp]);
|
|
754
960
|
const environments = envList;
|
|
755
961
|
const effectiveDefault = dc?.environment ?? defaultEnvironment;
|
|
756
|
-
const [selectedEnv, setSelectedEnv] =
|
|
962
|
+
const [selectedEnv, setSelectedEnv] = React3.useState(
|
|
757
963
|
effectiveDefault ?? environments[0]?.id ?? ""
|
|
758
964
|
);
|
|
759
|
-
|
|
965
|
+
React3.useEffect(() => {
|
|
760
966
|
if (envList.length === 0) return;
|
|
761
967
|
if (effectiveDefault && envList.some((e) => e.id === effectiveDefault)) {
|
|
762
968
|
setSelectedEnv(effectiveDefault);
|
|
@@ -767,38 +973,38 @@ function ProvisioningWizard({
|
|
|
767
973
|
return envList[0]?.id ?? "";
|
|
768
974
|
});
|
|
769
975
|
}, [envList, effectiveDefault]);
|
|
770
|
-
const [cpuCores, setCpuCores] =
|
|
976
|
+
const [cpuCores, setCpuCores] = React3.useState(
|
|
771
977
|
snapSliderValue(dc?.cpuCores ?? 4, CPU_MIN, cpuMax, cpuStep)
|
|
772
978
|
);
|
|
773
|
-
const [ramGB, setRamGB] =
|
|
979
|
+
const [ramGB, setRamGB] = React3.useState(
|
|
774
980
|
snapSliderValue(dc?.ramGB ?? 16, RAM_MIN, ramMax, ramStep)
|
|
775
981
|
);
|
|
776
|
-
const [storageGB, setStorageGB] =
|
|
982
|
+
const [storageGB, setStorageGB] = React3.useState(
|
|
777
983
|
snapSliderValue(dc?.storageGB ?? 128, STORAGE_MIN, storageMax, storageStep)
|
|
778
984
|
);
|
|
779
|
-
|
|
985
|
+
React3.useEffect(() => {
|
|
780
986
|
setCpuCores((prev) => snapSliderValue(prev, CPU_MIN, cpuMax, cpuStep));
|
|
781
987
|
setRamGB((prev) => snapSliderValue(prev, RAM_MIN, ramMax, ramStep));
|
|
782
988
|
setStorageGB(
|
|
783
989
|
(prev) => snapSliderValue(prev, STORAGE_MIN, storageMax, storageStep)
|
|
784
990
|
);
|
|
785
991
|
}, [cpuMax, ramMax, storageMax, cpuStep, ramStep, storageStep]);
|
|
786
|
-
const [name, setName] =
|
|
787
|
-
const [gitUrl, setGitUrl] =
|
|
788
|
-
const [envVars, setEnvVars] =
|
|
789
|
-
const [driver, setDriver] =
|
|
790
|
-
const [bare, setBare] =
|
|
791
|
-
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(
|
|
792
998
|
dc?.startupScriptIds ?? []
|
|
793
999
|
);
|
|
794
|
-
const [availableScripts, setAvailableScripts] =
|
|
795
|
-
const [activePreset, setActivePreset] =
|
|
796
|
-
const [pricingView, setPricingView] =
|
|
797
|
-
const [showAdvanced, setShowAdvanced] =
|
|
798
|
-
const [loadError, setLoadError] =
|
|
799
|
-
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);
|
|
800
1006
|
onLoadStartupScriptsRef.current = onLoadStartupScripts;
|
|
801
|
-
|
|
1007
|
+
React3.useEffect(() => {
|
|
802
1008
|
let cancelled = false;
|
|
803
1009
|
if (onLoadStartupScriptsRef.current) {
|
|
804
1010
|
onLoadStartupScriptsRef.current().then((scripts) => {
|
|
@@ -814,14 +1020,8 @@ function ProvisioningWizard({
|
|
|
814
1020
|
cancelled = true;
|
|
815
1021
|
};
|
|
816
1022
|
}, []);
|
|
817
|
-
const
|
|
818
|
-
const
|
|
819
|
-
const finalStep = stepLabels.length;
|
|
820
|
-
const [currentStep, setCurrentStep] = React2.useState(
|
|
821
|
-
skipToReview && dc && isMultistep ? finalStep : 1
|
|
822
|
-
);
|
|
823
|
-
const [isDeploying, setIsDeploying] = React2.useState(false);
|
|
824
|
-
const [deployError, setDeployError] = React2.useState(null);
|
|
1023
|
+
const [isDeploying, setIsDeploying] = React3.useState(false);
|
|
1024
|
+
const [deployError, setDeployError] = React3.useState(null);
|
|
825
1025
|
const handleDeploy = async () => {
|
|
826
1026
|
if (!onSubmit) return;
|
|
827
1027
|
setIsDeploying(true);
|
|
@@ -872,9 +1072,9 @@ function ProvisioningWizard({
|
|
|
872
1072
|
unlockLabel: unlockLabel ?? "Pro"
|
|
873
1073
|
};
|
|
874
1074
|
});
|
|
875
|
-
const didInitPresetFromDcRef =
|
|
876
|
-
const lastLimitsRef =
|
|
877
|
-
|
|
1075
|
+
const didInitPresetFromDcRef = React3.useRef(false);
|
|
1076
|
+
const lastLimitsRef = React3.useRef(null);
|
|
1077
|
+
React3.useEffect(() => {
|
|
878
1078
|
const limitsUnchanged = lastLimitsRef.current !== null && lastLimitsRef.current.cpu === cpuMax && lastLimitsRef.current.ram === ramMax && lastLimitsRef.current.storage === storageMax;
|
|
879
1079
|
if (limitsUnchanged) return;
|
|
880
1080
|
lastLimitsRef.current = { cpu: cpuMax, ram: ramMax, storage: storageMax };
|
|
@@ -912,9 +1112,9 @@ function ProvisioningWizard({
|
|
|
912
1112
|
const pricingSuffix = pricingView === "hourly" ? "/ hour" : "/ sec";
|
|
913
1113
|
const rateSuffix = pricingView === "hourly" ? "/h" : "/s";
|
|
914
1114
|
const fmtRate = (v) => pricingView === "hourly" ? v.toFixed(2) : formatPerSecondValue(v);
|
|
915
|
-
return /* @__PURE__ */
|
|
916
|
-
/* @__PURE__ */
|
|
917
|
-
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(
|
|
918
1118
|
Button,
|
|
919
1119
|
{
|
|
920
1120
|
type: "button",
|
|
@@ -922,109 +1122,43 @@ function ProvisioningWizard({
|
|
|
922
1122
|
size: "icon",
|
|
923
1123
|
onClick: onBack,
|
|
924
1124
|
className: "h-9 w-9 shrink-0",
|
|
925
|
-
children: /* @__PURE__ */
|
|
1125
|
+
children: /* @__PURE__ */ jsx4(ArrowLeft, { className: "h-4 w-4" })
|
|
926
1126
|
}
|
|
927
1127
|
),
|
|
928
|
-
/* @__PURE__ */
|
|
929
|
-
/* @__PURE__ */
|
|
930
|
-
/* @__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." })
|
|
931
1131
|
] })
|
|
932
1132
|
] }),
|
|
933
|
-
/* @__PURE__ */
|
|
934
|
-
/* @__PURE__ */
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
/* @__PURE__ */ jsx3(
|
|
939
|
-
"div",
|
|
940
|
-
{
|
|
941
|
-
className: cn(
|
|
942
|
-
"h-6 w-6 rounded-full flex items-center justify-center font-semibold text-xs shrink-0 transition-colors duration-200",
|
|
943
|
-
currentStep >= s ? "bg-primary text-primary-foreground" : "bg-muted border border-border text-muted-foreground"
|
|
944
|
-
),
|
|
945
|
-
children: currentStep > s ? /* @__PURE__ */ jsx3(Check, { className: "h-3 w-3" }) : s
|
|
946
|
-
}
|
|
947
|
-
),
|
|
948
|
-
/* @__PURE__ */ jsx3(
|
|
949
|
-
"span",
|
|
950
|
-
{
|
|
951
|
-
className: cn(
|
|
952
|
-
"ml-2 font-medium text-sm hidden sm:inline transition-colors duration-200",
|
|
953
|
-
currentStep === s ? "text-foreground" : currentStep > s ? "text-primary" : "text-muted-foreground"
|
|
954
|
-
),
|
|
955
|
-
children: label
|
|
956
|
-
}
|
|
957
|
-
),
|
|
958
|
-
s < finalStep && /* @__PURE__ */ jsx3(
|
|
959
|
-
"div",
|
|
960
|
-
{
|
|
961
|
-
className: cn(
|
|
962
|
-
"w-4 sm:w-8 h-px mx-2 sm:mx-3 transition-colors duration-300",
|
|
963
|
-
currentStep > s ? "bg-primary" : "bg-border"
|
|
964
|
-
)
|
|
965
|
-
}
|
|
966
|
-
)
|
|
967
|
-
] }, s);
|
|
968
|
-
}) }),
|
|
969
|
-
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: [
|
|
970
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 text-sm", children: [
|
|
971
|
-
/* @__PURE__ */ jsx3(Info, { className: "h-4 w-4 text-primary shrink-0" }),
|
|
972
|
-
/* @__PURE__ */ jsx3("span", { className: "text-muted-foreground", children: "Pre-configured from template." })
|
|
973
|
-
] }),
|
|
974
|
-
/* @__PURE__ */ jsx3(
|
|
975
|
-
Button,
|
|
976
|
-
{
|
|
977
|
-
type: "button",
|
|
978
|
-
variant: "link",
|
|
979
|
-
onClick: () => {
|
|
980
|
-
setCurrentStep(1);
|
|
981
|
-
setSelectedEnv(environments[0]?.id ?? "");
|
|
982
|
-
setCpuCores(snapSliderValue(4, CPU_MIN, cpuMax, cpuStep));
|
|
983
|
-
setRamGB(snapSliderValue(16, RAM_MIN, ramMax, ramStep));
|
|
984
|
-
setStorageGB(
|
|
985
|
-
snapSliderValue(128, STORAGE_MIN, storageMax, storageStep)
|
|
986
|
-
);
|
|
987
|
-
setName("");
|
|
988
|
-
setGitUrl("");
|
|
989
|
-
setEnvVars([{ key: "", value: "" }]);
|
|
990
|
-
setDriver("docker");
|
|
991
|
-
setBare(false);
|
|
992
|
-
setStartupScriptIds([]);
|
|
993
|
-
setActivePreset(null);
|
|
994
|
-
setPricingView("hourly");
|
|
995
|
-
},
|
|
996
|
-
className: "h-auto p-0 text-xs",
|
|
997
|
-
children: "Start from scratch"
|
|
998
|
-
}
|
|
999
|
-
)
|
|
1000
|
-
] }),
|
|
1001
|
-
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: [
|
|
1002
|
-
/* @__PURE__ */ jsx3(Info, { className: "h-4 w-4 text-destructive shrink-0" }),
|
|
1003
|
-
/* @__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 })
|
|
1004
1138
|
] }),
|
|
1005
|
-
/* @__PURE__ */
|
|
1006
|
-
|
|
1007
|
-
/* @__PURE__ */
|
|
1008
|
-
/* @__PURE__ */
|
|
1009
|
-
/* @__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" })
|
|
1010
1144
|
] }),
|
|
1011
|
-
/* @__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(
|
|
1012
1146
|
"div",
|
|
1013
1147
|
{
|
|
1014
1148
|
className: "p-3.5 rounded-lg border border-border bg-card/50 animate-pulse",
|
|
1015
1149
|
"aria-hidden": "true",
|
|
1016
1150
|
children: [
|
|
1017
|
-
/* @__PURE__ */
|
|
1018
|
-
/* @__PURE__ */
|
|
1019
|
-
/* @__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" })
|
|
1020
1154
|
] }),
|
|
1021
|
-
/* @__PURE__ */
|
|
1022
|
-
/* @__PURE__ */
|
|
1023
|
-
/* @__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" })
|
|
1024
1158
|
]
|
|
1025
1159
|
},
|
|
1026
1160
|
`env-skeleton-${i}`
|
|
1027
|
-
)) : environments.map((env) => /* @__PURE__ */
|
|
1161
|
+
)) : environments.map((env) => /* @__PURE__ */ jsxs4(
|
|
1028
1162
|
"button",
|
|
1029
1163
|
{
|
|
1030
1164
|
type: "button",
|
|
@@ -1034,36 +1168,36 @@ function ProvisioningWizard({
|
|
|
1034
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]"
|
|
1035
1169
|
),
|
|
1036
1170
|
children: [
|
|
1037
|
-
/* @__PURE__ */
|
|
1038
|
-
/* @__PURE__ */
|
|
1039
|
-
/* @__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(
|
|
1040
1174
|
"div",
|
|
1041
1175
|
{
|
|
1042
1176
|
className: cn(
|
|
1043
1177
|
"w-4 h-4 rounded-full border-2 flex items-center justify-center transition-colors duration-200",
|
|
1044
1178
|
selectedEnv === env.id ? "border-primary bg-primary" : "border-border group-hover:border-primary/40"
|
|
1045
1179
|
),
|
|
1046
|
-
children: selectedEnv === env.id && /* @__PURE__ */
|
|
1180
|
+
children: selectedEnv === env.id && /* @__PURE__ */ jsx4(Check, { className: "h-2.5 w-2.5 text-primary-foreground" })
|
|
1047
1181
|
}
|
|
1048
1182
|
)
|
|
1049
1183
|
] }),
|
|
1050
|
-
/* @__PURE__ */
|
|
1051
|
-
/* @__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 })
|
|
1052
1186
|
]
|
|
1053
1187
|
},
|
|
1054
1188
|
env.id
|
|
1055
1189
|
)) })
|
|
1056
|
-
] })
|
|
1057
|
-
|
|
1058
|
-
/* @__PURE__ */
|
|
1059
|
-
/* @__PURE__ */
|
|
1060
|
-
/* @__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" })
|
|
1061
1195
|
] }),
|
|
1062
|
-
/* @__PURE__ */
|
|
1063
|
-
/* @__PURE__ */
|
|
1064
|
-
/* @__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) => {
|
|
1065
1199
|
const active = activePreset === p.name && !p.locked;
|
|
1066
|
-
return /* @__PURE__ */
|
|
1200
|
+
return /* @__PURE__ */ jsxs4(
|
|
1067
1201
|
"button",
|
|
1068
1202
|
{
|
|
1069
1203
|
type: "button",
|
|
@@ -1074,8 +1208,8 @@ function ProvisioningWizard({
|
|
|
1074
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]"
|
|
1075
1209
|
),
|
|
1076
1210
|
children: [
|
|
1077
|
-
p.locked && /* @__PURE__ */
|
|
1078
|
-
/* @__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(
|
|
1079
1213
|
"div",
|
|
1080
1214
|
{
|
|
1081
1215
|
className: cn(
|
|
@@ -1085,7 +1219,7 @@ function ProvisioningWizard({
|
|
|
1085
1219
|
children: p.name
|
|
1086
1220
|
}
|
|
1087
1221
|
),
|
|
1088
|
-
/* @__PURE__ */
|
|
1222
|
+
/* @__PURE__ */ jsxs4("div", { className: "text-xs text-muted-foreground mt-0.5 font-mono", children: [
|
|
1089
1223
|
p.cpu,
|
|
1090
1224
|
" vCPU",
|
|
1091
1225
|
p.cpu === 1 ? "" : "s",
|
|
@@ -1102,7 +1236,7 @@ function ProvisioningWizard({
|
|
|
1102
1236
|
);
|
|
1103
1237
|
}) })
|
|
1104
1238
|
] }),
|
|
1105
|
-
/* @__PURE__ */
|
|
1239
|
+
/* @__PURE__ */ jsx4("div", { className: "space-y-4", children: [
|
|
1106
1240
|
{
|
|
1107
1241
|
label: "Compute Cores (CPU)",
|
|
1108
1242
|
value: cpuCores,
|
|
@@ -1133,12 +1267,12 @@ function ProvisioningWizard({
|
|
|
1133
1267
|
].map(
|
|
1134
1268
|
({ label, value, setter, min, max, step: s, unit }) => {
|
|
1135
1269
|
const displayUnit = unit === "vCPU" ? `${value} vCPU${value === 1 ? "" : "s"}` : `${value}${unit}`;
|
|
1136
|
-
return /* @__PURE__ */
|
|
1137
|
-
/* @__PURE__ */
|
|
1138
|
-
/* @__PURE__ */
|
|
1139
|
-
/* @__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 })
|
|
1140
1274
|
] }),
|
|
1141
|
-
/* @__PURE__ */
|
|
1275
|
+
/* @__PURE__ */ jsx4(
|
|
1142
1276
|
"input",
|
|
1143
1277
|
{
|
|
1144
1278
|
type: "range",
|
|
@@ -1153,12 +1287,12 @@ function ProvisioningWizard({
|
|
|
1153
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"
|
|
1154
1288
|
}
|
|
1155
1289
|
),
|
|
1156
|
-
/* @__PURE__ */
|
|
1157
|
-
/* @__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: [
|
|
1158
1292
|
min,
|
|
1159
1293
|
unit === "vCPU" ? min === 1 ? " vCPU" : " vCPUs" : unit
|
|
1160
1294
|
] }),
|
|
1161
|
-
/* @__PURE__ */
|
|
1295
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
1162
1296
|
max,
|
|
1163
1297
|
unit === "vCPU" ? max === 1 ? " vCPU" : " vCPUs" : unit
|
|
1164
1298
|
] })
|
|
@@ -1166,25 +1300,25 @@ function ProvisioningWizard({
|
|
|
1166
1300
|
] }, label);
|
|
1167
1301
|
}
|
|
1168
1302
|
) })
|
|
1169
|
-
] })
|
|
1170
|
-
|
|
1171
|
-
/* @__PURE__ */
|
|
1303
|
+
] }),
|
|
1304
|
+
/* @__PURE__ */ jsx4("section", { className: SECTION_CARD_CLASS, children: /* @__PURE__ */ jsxs4("div", { children: [
|
|
1305
|
+
/* @__PURE__ */ jsxs4(
|
|
1172
1306
|
"button",
|
|
1173
1307
|
{
|
|
1174
1308
|
type: "button",
|
|
1175
1309
|
onClick: () => setShowAdvanced(!showAdvanced),
|
|
1176
1310
|
className: "flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors text-sm font-medium focus:outline-none",
|
|
1177
1311
|
children: [
|
|
1178
|
-
/* @__PURE__ */
|
|
1312
|
+
/* @__PURE__ */ jsx4(Settings, { className: "w-4 h-4" }),
|
|
1179
1313
|
showAdvanced ? "Hide Advanced Options" : "Show Advanced Options"
|
|
1180
1314
|
]
|
|
1181
1315
|
}
|
|
1182
1316
|
),
|
|
1183
|
-
showAdvanced && /* @__PURE__ */
|
|
1184
|
-
/* @__PURE__ */
|
|
1185
|
-
/* @__PURE__ */
|
|
1186
|
-
/* @__PURE__ */
|
|
1187
|
-
/* @__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(
|
|
1188
1322
|
Input,
|
|
1189
1323
|
{
|
|
1190
1324
|
type: "text",
|
|
@@ -1196,9 +1330,9 @@ function ProvisioningWizard({
|
|
|
1196
1330
|
}
|
|
1197
1331
|
)
|
|
1198
1332
|
] }),
|
|
1199
|
-
/* @__PURE__ */
|
|
1200
|
-
/* @__PURE__ */
|
|
1201
|
-
/* @__PURE__ */
|
|
1333
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1334
|
+
/* @__PURE__ */ jsx4("label", { className: cn(FIELD_LABEL_CLASS, "mb-1.5"), children: "Virtualization Driver" }),
|
|
1335
|
+
/* @__PURE__ */ jsxs4(
|
|
1202
1336
|
"select",
|
|
1203
1337
|
{
|
|
1204
1338
|
value: driver,
|
|
@@ -1210,8 +1344,8 @@ function ProvisioningWizard({
|
|
|
1210
1344
|
},
|
|
1211
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",
|
|
1212
1346
|
children: [
|
|
1213
|
-
/* @__PURE__ */
|
|
1214
|
-
/* @__PURE__ */
|
|
1347
|
+
/* @__PURE__ */ jsx4("option", { value: "docker", className: "bg-gray-900", children: "Docker container (Default)" }),
|
|
1348
|
+
/* @__PURE__ */ jsx4(
|
|
1215
1349
|
"option",
|
|
1216
1350
|
{
|
|
1217
1351
|
value: "firecracker",
|
|
@@ -1219,15 +1353,15 @@ function ProvisioningWizard({
|
|
|
1219
1353
|
children: "Firecracker microVM (Secure)"
|
|
1220
1354
|
}
|
|
1221
1355
|
),
|
|
1222
|
-
/* @__PURE__ */
|
|
1356
|
+
/* @__PURE__ */ jsx4("option", { value: "tangle", className: "bg-gray-900", children: "Tangle Distributed Node" })
|
|
1223
1357
|
]
|
|
1224
1358
|
}
|
|
1225
1359
|
)
|
|
1226
1360
|
] })
|
|
1227
1361
|
] }),
|
|
1228
|
-
/* @__PURE__ */
|
|
1229
|
-
/* @__PURE__ */
|
|
1230
|
-
/* @__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(
|
|
1231
1365
|
Input,
|
|
1232
1366
|
{
|
|
1233
1367
|
type: "text",
|
|
@@ -1238,10 +1372,10 @@ function ProvisioningWizard({
|
|
|
1238
1372
|
}
|
|
1239
1373
|
)
|
|
1240
1374
|
] }),
|
|
1241
|
-
/* @__PURE__ */
|
|
1242
|
-
/* @__PURE__ */
|
|
1243
|
-
/* @__PURE__ */
|
|
1244
|
-
/* @__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(
|
|
1245
1379
|
"button",
|
|
1246
1380
|
{
|
|
1247
1381
|
type: "button",
|
|
@@ -1251,15 +1385,15 @@ function ProvisioningWizard({
|
|
|
1251
1385
|
]),
|
|
1252
1386
|
className: "flex items-center gap-1 text-xs text-primary hover:text-primary/70 transition-colors font-medium",
|
|
1253
1387
|
children: [
|
|
1254
|
-
/* @__PURE__ */
|
|
1388
|
+
/* @__PURE__ */ jsx4(Plus, { className: "h-3 w-3" }),
|
|
1255
1389
|
" Add Var"
|
|
1256
1390
|
]
|
|
1257
1391
|
}
|
|
1258
1392
|
)
|
|
1259
1393
|
] }),
|
|
1260
|
-
/* @__PURE__ */
|
|
1261
|
-
envVars.map((env, i) => /* @__PURE__ */
|
|
1262
|
-
/* @__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(
|
|
1263
1397
|
Input,
|
|
1264
1398
|
{
|
|
1265
1399
|
type: "text",
|
|
@@ -1273,7 +1407,7 @@ function ProvisioningWizard({
|
|
|
1273
1407
|
placeholder: "API_KEY"
|
|
1274
1408
|
}
|
|
1275
1409
|
),
|
|
1276
|
-
/* @__PURE__ */
|
|
1410
|
+
/* @__PURE__ */ jsx4(
|
|
1277
1411
|
Input,
|
|
1278
1412
|
{
|
|
1279
1413
|
type: "password",
|
|
@@ -1287,7 +1421,7 @@ function ProvisioningWizard({
|
|
|
1287
1421
|
placeholder: "sk-xxxxxxxxxxx"
|
|
1288
1422
|
}
|
|
1289
1423
|
),
|
|
1290
|
-
/* @__PURE__ */
|
|
1424
|
+
/* @__PURE__ */ jsx4(
|
|
1291
1425
|
Button,
|
|
1292
1426
|
{
|
|
1293
1427
|
type: "button",
|
|
@@ -1297,25 +1431,25 @@ function ProvisioningWizard({
|
|
|
1297
1431
|
envVars.filter((_, idx) => idx !== i)
|
|
1298
1432
|
),
|
|
1299
1433
|
className: "h-9 w-9 shrink-0 text-destructive hover:bg-destructive/10 hover:border-destructive/30",
|
|
1300
|
-
children: /* @__PURE__ */
|
|
1434
|
+
children: /* @__PURE__ */ jsx4(Trash2, { className: "h-4 w-4" })
|
|
1301
1435
|
}
|
|
1302
1436
|
)
|
|
1303
1437
|
] }, i)),
|
|
1304
|
-
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" })
|
|
1305
1439
|
] })
|
|
1306
1440
|
] }),
|
|
1307
|
-
availableScripts.length > 0 && /* @__PURE__ */
|
|
1308
|
-
/* @__PURE__ */
|
|
1309
|
-
/* @__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) => {
|
|
1310
1444
|
const selected = startupScriptIds.includes(
|
|
1311
1445
|
script.id
|
|
1312
1446
|
);
|
|
1313
|
-
return /* @__PURE__ */
|
|
1447
|
+
return /* @__PURE__ */ jsxs4(
|
|
1314
1448
|
"label",
|
|
1315
1449
|
{
|
|
1316
1450
|
className: "flex items-start gap-3 cursor-pointer group rounded-lg border border-border p-3 transition-colors hover:border-primary/30",
|
|
1317
1451
|
children: [
|
|
1318
|
-
/* @__PURE__ */
|
|
1452
|
+
/* @__PURE__ */ jsx4(
|
|
1319
1453
|
"input",
|
|
1320
1454
|
{
|
|
1321
1455
|
type: "checkbox",
|
|
@@ -1328,15 +1462,15 @@ function ProvisioningWizard({
|
|
|
1328
1462
|
className: "mt-0.5 h-4 w-4 rounded border-border text-primary focus:ring-primary/30"
|
|
1329
1463
|
}
|
|
1330
1464
|
),
|
|
1331
|
-
/* @__PURE__ */
|
|
1332
|
-
/* @__PURE__ */
|
|
1333
|
-
script.description && /* @__PURE__ */
|
|
1334
|
-
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(
|
|
1335
1469
|
"span",
|
|
1336
1470
|
{
|
|
1337
1471
|
className: "inline-flex items-center gap-0.5 rounded-full bg-muted px-2 py-0.5 text-[10px] text-muted-foreground",
|
|
1338
1472
|
children: [
|
|
1339
|
-
/* @__PURE__ */
|
|
1473
|
+
/* @__PURE__ */ jsxs4(
|
|
1340
1474
|
"svg",
|
|
1341
1475
|
{
|
|
1342
1476
|
className: "h-2.5 w-2.5",
|
|
@@ -1345,7 +1479,7 @@ function ProvisioningWizard({
|
|
|
1345
1479
|
stroke: "currentColor",
|
|
1346
1480
|
strokeWidth: "2",
|
|
1347
1481
|
children: [
|
|
1348
|
-
/* @__PURE__ */
|
|
1482
|
+
/* @__PURE__ */ jsx4(
|
|
1349
1483
|
"rect",
|
|
1350
1484
|
{
|
|
1351
1485
|
x: "3",
|
|
@@ -1356,7 +1490,7 @@ function ProvisioningWizard({
|
|
|
1356
1490
|
ry: "2"
|
|
1357
1491
|
}
|
|
1358
1492
|
),
|
|
1359
|
-
/* @__PURE__ */
|
|
1493
|
+
/* @__PURE__ */ jsx4("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })
|
|
1360
1494
|
]
|
|
1361
1495
|
}
|
|
1362
1496
|
),
|
|
@@ -1372,9 +1506,9 @@ function ProvisioningWizard({
|
|
|
1372
1506
|
);
|
|
1373
1507
|
}) })
|
|
1374
1508
|
] }),
|
|
1375
|
-
/* @__PURE__ */
|
|
1376
|
-
/* @__PURE__ */
|
|
1377
|
-
/* @__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(
|
|
1378
1512
|
"label",
|
|
1379
1513
|
{
|
|
1380
1514
|
htmlFor: "wizard-bare-mode",
|
|
@@ -1382,9 +1516,9 @@ function ProvisioningWizard({
|
|
|
1382
1516
|
children: "Bare Mode"
|
|
1383
1517
|
}
|
|
1384
1518
|
),
|
|
1385
|
-
/* @__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." })
|
|
1386
1520
|
] }),
|
|
1387
|
-
/* @__PURE__ */
|
|
1521
|
+
/* @__PURE__ */ jsx4(
|
|
1388
1522
|
Switch,
|
|
1389
1523
|
{
|
|
1390
1524
|
id: "wizard-bare-mode",
|
|
@@ -1395,28 +1529,28 @@ function ProvisioningWizard({
|
|
|
1395
1529
|
)
|
|
1396
1530
|
] })
|
|
1397
1531
|
] })
|
|
1398
|
-
] }) })
|
|
1399
|
-
sshAccess &&
|
|
1400
|
-
/* @__PURE__ */
|
|
1401
|
-
/* @__PURE__ */
|
|
1402
|
-
/* @__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" })
|
|
1403
1537
|
] }),
|
|
1404
|
-
/* @__PURE__ */
|
|
1405
|
-
] })
|
|
1538
|
+
/* @__PURE__ */ jsx4(SshAccessStep, { config: sshAccess })
|
|
1539
|
+
] })
|
|
1406
1540
|
] })
|
|
1407
1541
|
] }),
|
|
1408
|
-
/* @__PURE__ */
|
|
1409
|
-
/* @__PURE__ */
|
|
1410
|
-
/* @__PURE__ */
|
|
1411
|
-
/* @__PURE__ */
|
|
1412
|
-
/* @__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(
|
|
1413
1547
|
"div",
|
|
1414
1548
|
{
|
|
1415
1549
|
role: "group",
|
|
1416
1550
|
"aria-label": "Pricing view",
|
|
1417
1551
|
className: "inline-flex items-center rounded-md border border-border bg-muted/50 p-0.5",
|
|
1418
1552
|
children: [
|
|
1419
|
-
/* @__PURE__ */
|
|
1553
|
+
/* @__PURE__ */ jsx4(
|
|
1420
1554
|
"button",
|
|
1421
1555
|
{
|
|
1422
1556
|
type: "button",
|
|
@@ -1429,7 +1563,7 @@ function ProvisioningWizard({
|
|
|
1429
1563
|
children: "Per Hour"
|
|
1430
1564
|
}
|
|
1431
1565
|
),
|
|
1432
|
-
/* @__PURE__ */
|
|
1566
|
+
/* @__PURE__ */ jsx4(
|
|
1433
1567
|
"button",
|
|
1434
1568
|
{
|
|
1435
1569
|
type: "button",
|
|
@@ -1446,8 +1580,8 @@ function ProvisioningWizard({
|
|
|
1446
1580
|
}
|
|
1447
1581
|
)
|
|
1448
1582
|
] }),
|
|
1449
|
-
/* @__PURE__ */
|
|
1450
|
-
/* @__PURE__ */
|
|
1583
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-baseline gap-2 mb-4", children: [
|
|
1584
|
+
/* @__PURE__ */ jsxs4(
|
|
1451
1585
|
"span",
|
|
1452
1586
|
{
|
|
1453
1587
|
className: cn(
|
|
@@ -1461,36 +1595,36 @@ function ProvisioningWizard({
|
|
|
1461
1595
|
},
|
|
1462
1596
|
pricingView
|
|
1463
1597
|
),
|
|
1464
|
-
/* @__PURE__ */
|
|
1598
|
+
/* @__PURE__ */ jsx4("span", { className: "text-muted-foreground text-sm", children: pricingSuffix })
|
|
1465
1599
|
] }),
|
|
1466
|
-
/* @__PURE__ */
|
|
1467
|
-
/* @__PURE__ */
|
|
1468
|
-
/* @__PURE__ */
|
|
1469
|
-
/* @__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: [
|
|
1470
1604
|
"$",
|
|
1471
1605
|
fmtRate(hourlyCostBreakdown.compute),
|
|
1472
1606
|
rateSuffix
|
|
1473
1607
|
] })
|
|
1474
1608
|
] }),
|
|
1475
|
-
/* @__PURE__ */
|
|
1476
|
-
/* @__PURE__ */
|
|
1477
|
-
/* @__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: [
|
|
1478
1612
|
"$",
|
|
1479
1613
|
fmtRate(hourlyCostBreakdown.memory),
|
|
1480
1614
|
rateSuffix
|
|
1481
1615
|
] })
|
|
1482
1616
|
] }),
|
|
1483
|
-
/* @__PURE__ */
|
|
1484
|
-
/* @__PURE__ */
|
|
1485
|
-
/* @__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: [
|
|
1486
1620
|
"$",
|
|
1487
1621
|
fmtRate(hourlyCostBreakdown.storage),
|
|
1488
1622
|
rateSuffix
|
|
1489
1623
|
] })
|
|
1490
1624
|
] }),
|
|
1491
|
-
hourlyCostBreakdown.floorApplies && /* @__PURE__ */
|
|
1492
|
-
/* @__PURE__ */
|
|
1493
|
-
/* @__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: [
|
|
1494
1628
|
"$",
|
|
1495
1629
|
fmtRate(
|
|
1496
1630
|
hourlyCostBreakdown.floor - hourlyCostBreakdown.lineSum
|
|
@@ -1500,54 +1634,19 @@ function ProvisioningWizard({
|
|
|
1500
1634
|
] })
|
|
1501
1635
|
] })
|
|
1502
1636
|
] }),
|
|
1503
|
-
deployError && /* @__PURE__ */
|
|
1504
|
-
/* @__PURE__ */
|
|
1505
|
-
/* @__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 })
|
|
1506
1640
|
] }),
|
|
1507
|
-
/* @__PURE__ */
|
|
1508
|
-
currentStep < finalStep ? /* @__PURE__ */ jsxs3(
|
|
1509
|
-
Button,
|
|
1510
|
-
{
|
|
1511
|
-
type: "button",
|
|
1512
|
-
onClick: () => setCurrentStep((s) => s + 1),
|
|
1513
|
-
className: "w-full",
|
|
1514
|
-
children: [
|
|
1515
|
-
"Continue to ",
|
|
1516
|
-
stepLabels[currentStep]
|
|
1517
|
-
]
|
|
1518
|
-
}
|
|
1519
|
-
) : /* @__PURE__ */ jsx3(
|
|
1520
|
-
Button,
|
|
1521
|
-
{
|
|
1522
|
-
type: "button",
|
|
1523
|
-
onClick: handleDeploy,
|
|
1524
|
-
disabled: isDeploying || !selectedEnv,
|
|
1525
|
-
className: "w-full",
|
|
1526
|
-
children: isDeploying ? /* @__PURE__ */ jsxs3("span", { className: "flex items-center justify-center gap-2", children: [
|
|
1527
|
-
/* @__PURE__ */ jsx3(Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
1528
|
-
"Deploying..."
|
|
1529
|
-
] }) : "Deploy Workspace"
|
|
1530
|
-
}
|
|
1531
|
-
),
|
|
1532
|
-
currentStep > 1 && /* @__PURE__ */ jsx3(
|
|
1533
|
-
Button,
|
|
1534
|
-
{
|
|
1535
|
-
type: "button",
|
|
1536
|
-
variant: "secondary",
|
|
1537
|
-
onClick: () => setCurrentStep((s) => s - 1),
|
|
1538
|
-
className: "w-full",
|
|
1539
|
-
children: "Back"
|
|
1540
|
-
}
|
|
1541
|
-
)
|
|
1542
|
-
] }) : /* @__PURE__ */ jsx3(
|
|
1641
|
+
/* @__PURE__ */ jsx4("div", { className: "space-y-2", children: /* @__PURE__ */ jsx4(
|
|
1543
1642
|
Button,
|
|
1544
1643
|
{
|
|
1545
1644
|
type: "button",
|
|
1546
1645
|
onClick: handleDeploy,
|
|
1547
1646
|
disabled: isDeploying || !selectedEnv,
|
|
1548
1647
|
className: "w-full",
|
|
1549
|
-
children: isDeploying ? /* @__PURE__ */
|
|
1550
|
-
/* @__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" }),
|
|
1551
1650
|
"Spinning up environment..."
|
|
1552
1651
|
] }) : "Deploy Workspace"
|
|
1553
1652
|
}
|
|
@@ -1558,10 +1657,10 @@ function ProvisioningWizard({
|
|
|
1558
1657
|
}
|
|
1559
1658
|
|
|
1560
1659
|
// src/pages/pricing-page.tsx
|
|
1561
|
-
import * as
|
|
1660
|
+
import * as React4 from "react";
|
|
1562
1661
|
import { Skeleton as Skeleton2, SkeletonCard as SkeletonCard2 } from "@tangle-network/ui/primitives";
|
|
1563
1662
|
import { ChevronDown } from "lucide-react";
|
|
1564
|
-
import { jsx as
|
|
1663
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1565
1664
|
async function fetchTiersFromApi(apiBasePath) {
|
|
1566
1665
|
const res = await fetch(`${apiBasePath}/v1/billing/tiers`);
|
|
1567
1666
|
if (!res.ok) throw new Error("Failed to fetch pricing tiers");
|
|
@@ -1593,14 +1692,14 @@ function StandalonePricingPage({
|
|
|
1593
1692
|
eyebrow,
|
|
1594
1693
|
className
|
|
1595
1694
|
}) {
|
|
1596
|
-
const [state, setState] =
|
|
1695
|
+
const [state, setState] = React4.useState({
|
|
1597
1696
|
tiers: initialTiers || [],
|
|
1598
1697
|
loading: !initialTiers,
|
|
1599
1698
|
error: null,
|
|
1600
1699
|
billingPeriod: "monthly",
|
|
1601
1700
|
selectingTier: false
|
|
1602
1701
|
});
|
|
1603
|
-
const loadTiers =
|
|
1702
|
+
const loadTiers = React4.useCallback(async () => {
|
|
1604
1703
|
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
1605
1704
|
try {
|
|
1606
1705
|
const tiers = fetchTiers ? await fetchTiers() : await fetchTiersFromApi(apiBasePath);
|
|
@@ -1613,12 +1712,12 @@ function StandalonePricingPage({
|
|
|
1613
1712
|
}));
|
|
1614
1713
|
}
|
|
1615
1714
|
}, [apiBasePath, fetchTiers]);
|
|
1616
|
-
|
|
1715
|
+
React4.useEffect(() => {
|
|
1617
1716
|
if (!initialTiers) {
|
|
1618
1717
|
loadTiers();
|
|
1619
1718
|
}
|
|
1620
1719
|
}, [initialTiers, loadTiers]);
|
|
1621
|
-
const handleSelectTier =
|
|
1720
|
+
const handleSelectTier = React4.useCallback(
|
|
1622
1721
|
async (tierId) => {
|
|
1623
1722
|
if (onSelectTier) {
|
|
1624
1723
|
onSelectTier(tierId, state.billingPeriod);
|
|
@@ -1645,25 +1744,25 @@ function StandalonePricingPage({
|
|
|
1645
1744
|
},
|
|
1646
1745
|
[apiBasePath, state.billingPeriod, onSelectTier]
|
|
1647
1746
|
);
|
|
1648
|
-
return /* @__PURE__ */
|
|
1649
|
-
/* @__PURE__ */
|
|
1650
|
-
eyebrow && /* @__PURE__ */
|
|
1651
|
-
/* @__PURE__ */
|
|
1652
|
-
/* @__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 })
|
|
1653
1752
|
] }),
|
|
1654
|
-
state.loading ? /* @__PURE__ */
|
|
1655
|
-
/* @__PURE__ */
|
|
1656
|
-
/* @__PURE__ */
|
|
1657
|
-
/* @__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" })
|
|
1658
1757
|
] }),
|
|
1659
|
-
/* @__PURE__ */
|
|
1660
|
-
/* @__PURE__ */
|
|
1661
|
-
/* @__PURE__ */
|
|
1662
|
-
/* @__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]" })
|
|
1663
1762
|
] })
|
|
1664
|
-
] }) : state.error ? /* @__PURE__ */
|
|
1665
|
-
/* @__PURE__ */
|
|
1666
|
-
/* @__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(
|
|
1667
1766
|
"button",
|
|
1668
1767
|
{
|
|
1669
1768
|
type: "button",
|
|
@@ -1672,7 +1771,7 @@ function StandalonePricingPage({
|
|
|
1672
1771
|
children: "Try Again"
|
|
1673
1772
|
}
|
|
1674
1773
|
)
|
|
1675
|
-
] }) : /* @__PURE__ */
|
|
1774
|
+
] }) : /* @__PURE__ */ jsx5(
|
|
1676
1775
|
PricingPage,
|
|
1677
1776
|
{
|
|
1678
1777
|
tiers: state.tiers,
|
|
@@ -1683,14 +1782,14 @@ function StandalonePricingPage({
|
|
|
1683
1782
|
loading: state.selectingTier
|
|
1684
1783
|
}
|
|
1685
1784
|
),
|
|
1686
|
-
/* @__PURE__ */
|
|
1687
|
-
/* @__PURE__ */
|
|
1688
|
-
FAQ.map(({ q, a }) => /* @__PURE__ */
|
|
1689
|
-
/* @__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: [
|
|
1690
1789
|
q,
|
|
1691
|
-
/* @__PURE__ */
|
|
1790
|
+
/* @__PURE__ */ jsx5(ChevronDown, { className: "h-4 w-4 text-muted-foreground transition-transform group-open:rotate-180" })
|
|
1692
1791
|
] }),
|
|
1693
|
-
/* @__PURE__ */
|
|
1792
|
+
/* @__PURE__ */ jsx5("div", { className: "px-6 pb-4", children: /* @__PURE__ */ jsx5("p", { className: "text-sm text-muted-foreground leading-relaxed", children: a }) })
|
|
1694
1793
|
] }, q))
|
|
1695
1794
|
] })
|
|
1696
1795
|
] });
|
|
@@ -1702,27 +1801,27 @@ import {
|
|
|
1702
1801
|
ChevronRight,
|
|
1703
1802
|
Copy,
|
|
1704
1803
|
Edit2,
|
|
1705
|
-
Loader2 as
|
|
1804
|
+
Loader2 as Loader23,
|
|
1706
1805
|
Plus as Plus2,
|
|
1707
1806
|
Search,
|
|
1708
1807
|
Settings2,
|
|
1709
1808
|
Trash2 as Trash22
|
|
1710
1809
|
} from "lucide-react";
|
|
1711
|
-
import * as
|
|
1810
|
+
import * as React5 from "react";
|
|
1712
1811
|
import { Button as Button2 } from "@tangle-network/ui/primitives";
|
|
1713
1812
|
import { Badge as Badge2 } from "@tangle-network/ui/primitives";
|
|
1714
1813
|
import { Card } from "@tangle-network/ui/primitives";
|
|
1715
1814
|
import {
|
|
1716
|
-
Dialog,
|
|
1717
|
-
DialogContent,
|
|
1718
|
-
DialogDescription,
|
|
1719
|
-
DialogFooter,
|
|
1720
|
-
DialogHeader,
|
|
1721
|
-
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
|
|
1722
1821
|
} from "@tangle-network/ui/primitives";
|
|
1723
1822
|
import { EmptyState } from "@tangle-network/ui/primitives";
|
|
1724
1823
|
import { Input as Input2 } from "@tangle-network/ui/primitives";
|
|
1725
|
-
import { jsx as
|
|
1824
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1726
1825
|
var TIER_LIMITS = {
|
|
1727
1826
|
free: 3,
|
|
1728
1827
|
starter: 10,
|
|
@@ -1736,24 +1835,24 @@ function ProfilesPage({
|
|
|
1736
1835
|
onCompareClick,
|
|
1737
1836
|
title = "Profiles"
|
|
1738
1837
|
}) {
|
|
1739
|
-
const [builtinProfiles, setBuiltinProfiles] =
|
|
1740
|
-
const [customProfiles, setCustomProfiles] =
|
|
1741
|
-
const [loading, setLoading] =
|
|
1742
|
-
const [error, setError] =
|
|
1743
|
-
const [searchQuery, setSearchQuery] =
|
|
1744
|
-
const [createDialogOpen, setCreateDialogOpen] =
|
|
1745
|
-
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(
|
|
1746
1845
|
null
|
|
1747
1846
|
);
|
|
1748
|
-
const [deletingProfile, setDeletingProfile] =
|
|
1847
|
+
const [deletingProfile, setDeletingProfile] = React5.useState(
|
|
1749
1848
|
null
|
|
1750
1849
|
);
|
|
1751
|
-
const [detailProfile, setDetailProfile] =
|
|
1850
|
+
const [detailProfile, setDetailProfile] = React5.useState(
|
|
1752
1851
|
null
|
|
1753
1852
|
);
|
|
1754
1853
|
const profileLimit = maxProfiles ?? TIER_LIMITS[tier] ?? 3;
|
|
1755
1854
|
const canCreateMore = customProfiles.length < profileLimit;
|
|
1756
|
-
const loadProfiles =
|
|
1855
|
+
const loadProfiles = React5.useCallback(async () => {
|
|
1757
1856
|
try {
|
|
1758
1857
|
setLoading(true);
|
|
1759
1858
|
setError(null);
|
|
@@ -1766,7 +1865,7 @@ function ProfilesPage({
|
|
|
1766
1865
|
setLoading(false);
|
|
1767
1866
|
}
|
|
1768
1867
|
}, [apiClient]);
|
|
1769
|
-
|
|
1868
|
+
React5.useEffect(() => {
|
|
1770
1869
|
loadProfiles();
|
|
1771
1870
|
}, [loadProfiles]);
|
|
1772
1871
|
const filteredBuiltin = builtinProfiles.filter(
|
|
@@ -1775,14 +1874,14 @@ function ProfilesPage({
|
|
|
1775
1874
|
const filteredCustom = customProfiles.filter(
|
|
1776
1875
|
(p) => p.name.toLowerCase().includes(searchQuery.toLowerCase()) || p.description?.toLowerCase().includes(searchQuery.toLowerCase())
|
|
1777
1876
|
);
|
|
1778
|
-
return /* @__PURE__ */
|
|
1779
|
-
/* @__PURE__ */
|
|
1780
|
-
/* @__PURE__ */
|
|
1781
|
-
/* @__PURE__ */
|
|
1782
|
-
/* @__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" })
|
|
1783
1882
|
] }),
|
|
1784
|
-
/* @__PURE__ */
|
|
1785
|
-
onCompareClick && customProfiles.length >= 2 && /* @__PURE__ */
|
|
1883
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3", children: [
|
|
1884
|
+
onCompareClick && customProfiles.length >= 2 && /* @__PURE__ */ jsx6(
|
|
1786
1885
|
Button2,
|
|
1787
1886
|
{
|
|
1788
1887
|
variant: "outline",
|
|
@@ -1790,30 +1889,30 @@ function ProfilesPage({
|
|
|
1790
1889
|
children: "Compare Profiles"
|
|
1791
1890
|
}
|
|
1792
1891
|
),
|
|
1793
|
-
/* @__PURE__ */
|
|
1892
|
+
/* @__PURE__ */ jsxs6(
|
|
1794
1893
|
Button2,
|
|
1795
1894
|
{
|
|
1796
1895
|
onClick: () => setCreateDialogOpen(true),
|
|
1797
1896
|
disabled: !canCreateMore,
|
|
1798
1897
|
children: [
|
|
1799
|
-
/* @__PURE__ */
|
|
1898
|
+
/* @__PURE__ */ jsx6(Plus2, { className: "mr-2 h-4 w-4" }),
|
|
1800
1899
|
"Create Profile"
|
|
1801
1900
|
]
|
|
1802
1901
|
}
|
|
1803
1902
|
)
|
|
1804
1903
|
] })
|
|
1805
1904
|
] }),
|
|
1806
|
-
!canCreateMore && /* @__PURE__ */
|
|
1807
|
-
/* @__PURE__ */
|
|
1808
|
-
/* @__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: [
|
|
1809
1908
|
"You've reached your profile limit (",
|
|
1810
1909
|
profileLimit,
|
|
1811
1910
|
" profiles). Upgrade your plan to create more."
|
|
1812
1911
|
] })
|
|
1813
1912
|
] }),
|
|
1814
|
-
/* @__PURE__ */
|
|
1815
|
-
/* @__PURE__ */
|
|
1816
|
-
/* @__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(
|
|
1817
1916
|
Input2,
|
|
1818
1917
|
{
|
|
1819
1918
|
placeholder: "Search profiles...",
|
|
@@ -1823,33 +1922,33 @@ function ProfilesPage({
|
|
|
1823
1922
|
}
|
|
1824
1923
|
)
|
|
1825
1924
|
] }),
|
|
1826
|
-
error && /* @__PURE__ */
|
|
1827
|
-
/* @__PURE__ */
|
|
1828
|
-
/* @__PURE__ */
|
|
1829
|
-
/* @__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" })
|
|
1830
1929
|
] }),
|
|
1831
|
-
loading && /* @__PURE__ */
|
|
1832
|
-
!loading && /* @__PURE__ */
|
|
1833
|
-
/* @__PURE__ */
|
|
1834
|
-
/* @__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: [
|
|
1835
1934
|
"Your Profiles (",
|
|
1836
1935
|
customProfiles.length,
|
|
1837
1936
|
"/",
|
|
1838
1937
|
profileLimit === Number.POSITIVE_INFINITY ? "inf" : profileLimit,
|
|
1839
1938
|
")"
|
|
1840
1939
|
] }) }),
|
|
1841
|
-
filteredCustom.length === 0 ? /* @__PURE__ */
|
|
1940
|
+
filteredCustom.length === 0 ? /* @__PURE__ */ jsx6(
|
|
1842
1941
|
EmptyState,
|
|
1843
1942
|
{
|
|
1844
|
-
icon: /* @__PURE__ */
|
|
1943
|
+
icon: /* @__PURE__ */ jsx6(Settings2, { className: "h-8 w-8" }),
|
|
1845
1944
|
title: "No custom profiles yet",
|
|
1846
1945
|
description: "Create a profile to customize agent behavior",
|
|
1847
|
-
action: canCreateMore ? /* @__PURE__ */
|
|
1848
|
-
/* @__PURE__ */
|
|
1946
|
+
action: canCreateMore ? /* @__PURE__ */ jsxs6(Button2, { onClick: () => setCreateDialogOpen(true), children: [
|
|
1947
|
+
/* @__PURE__ */ jsx6(Plus2, { className: "mr-2 h-4 w-4" }),
|
|
1849
1948
|
"Create Profile"
|
|
1850
1949
|
] }) : void 0
|
|
1851
1950
|
}
|
|
1852
|
-
) : /* @__PURE__ */
|
|
1951
|
+
) : /* @__PURE__ */ jsx6("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3", children: filteredCustom.map((profile) => /* @__PURE__ */ jsx6(
|
|
1853
1952
|
ProfileCard,
|
|
1854
1953
|
{
|
|
1855
1954
|
profile,
|
|
@@ -1860,13 +1959,13 @@ function ProfilesPage({
|
|
|
1860
1959
|
profile.id
|
|
1861
1960
|
)) })
|
|
1862
1961
|
] }),
|
|
1863
|
-
/* @__PURE__ */
|
|
1864
|
-
/* @__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: [
|
|
1865
1964
|
"Built-in Profiles (",
|
|
1866
1965
|
builtinProfiles.length,
|
|
1867
1966
|
")"
|
|
1868
1967
|
] }) }),
|
|
1869
|
-
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(
|
|
1870
1969
|
ProfileCard,
|
|
1871
1970
|
{
|
|
1872
1971
|
profile,
|
|
@@ -1877,7 +1976,7 @@ function ProfilesPage({
|
|
|
1877
1976
|
)) })
|
|
1878
1977
|
] })
|
|
1879
1978
|
] }),
|
|
1880
|
-
/* @__PURE__ */
|
|
1979
|
+
/* @__PURE__ */ jsx6(
|
|
1881
1980
|
ProfileFormDialog,
|
|
1882
1981
|
{
|
|
1883
1982
|
open: createDialogOpen || !!editingProfile,
|
|
@@ -1895,7 +1994,7 @@ function ProfilesPage({
|
|
|
1895
1994
|
}
|
|
1896
1995
|
}
|
|
1897
1996
|
),
|
|
1898
|
-
/* @__PURE__ */
|
|
1997
|
+
/* @__PURE__ */ jsx6(
|
|
1899
1998
|
DeleteProfileDialog,
|
|
1900
1999
|
{
|
|
1901
2000
|
profile: deletingProfile,
|
|
@@ -1907,7 +2006,7 @@ function ProfilesPage({
|
|
|
1907
2006
|
}
|
|
1908
2007
|
}
|
|
1909
2008
|
),
|
|
1910
|
-
/* @__PURE__ */
|
|
2009
|
+
/* @__PURE__ */ jsx6(
|
|
1911
2010
|
ProfileDetailDialog,
|
|
1912
2011
|
{
|
|
1913
2012
|
profile: detailProfile,
|
|
@@ -1936,61 +2035,61 @@ function ProfileCard({
|
|
|
1936
2035
|
onDelete,
|
|
1937
2036
|
isBuiltin
|
|
1938
2037
|
}) {
|
|
1939
|
-
return /* @__PURE__ */
|
|
2038
|
+
return /* @__PURE__ */ jsxs6(
|
|
1940
2039
|
Card,
|
|
1941
2040
|
{
|
|
1942
2041
|
className: "cursor-pointer p-4 transition-colors hover:border-border/80",
|
|
1943
2042
|
onClick: onView,
|
|
1944
2043
|
children: [
|
|
1945
|
-
/* @__PURE__ */
|
|
1946
|
-
/* @__PURE__ */
|
|
1947
|
-
/* @__PURE__ */
|
|
1948
|
-
/* @__PURE__ */
|
|
1949
|
-
isBuiltin && /* @__PURE__ */
|
|
1950
|
-
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" })
|
|
1951
2050
|
] }),
|
|
1952
|
-
profile.description && /* @__PURE__ */
|
|
2051
|
+
profile.description && /* @__PURE__ */ jsx6("p", { className: "mt-1 line-clamp-2 text-muted-foreground text-sm", children: profile.description })
|
|
1953
2052
|
] }),
|
|
1954
|
-
!isBuiltin && /* @__PURE__ */
|
|
1955
|
-
onEdit && /* @__PURE__ */
|
|
2053
|
+
!isBuiltin && /* @__PURE__ */ jsxs6("div", { className: "flex gap-1", onClick: (e) => e.stopPropagation(), children: [
|
|
2054
|
+
onEdit && /* @__PURE__ */ jsx6(
|
|
1956
2055
|
Button2,
|
|
1957
2056
|
{
|
|
1958
2057
|
variant: "ghost",
|
|
1959
2058
|
size: "icon",
|
|
1960
2059
|
onClick: onEdit,
|
|
1961
2060
|
"aria-label": "Edit profile",
|
|
1962
|
-
children: /* @__PURE__ */
|
|
2061
|
+
children: /* @__PURE__ */ jsx6(Edit2, { className: "h-4 w-4" })
|
|
1963
2062
|
}
|
|
1964
2063
|
),
|
|
1965
|
-
onDelete && /* @__PURE__ */
|
|
2064
|
+
onDelete && /* @__PURE__ */ jsx6(
|
|
1966
2065
|
Button2,
|
|
1967
2066
|
{
|
|
1968
2067
|
variant: "ghost",
|
|
1969
2068
|
size: "icon",
|
|
1970
2069
|
onClick: onDelete,
|
|
1971
2070
|
"aria-label": "Delete profile",
|
|
1972
|
-
children: /* @__PURE__ */
|
|
2071
|
+
children: /* @__PURE__ */ jsx6(Trash22, { className: "h-4 w-4 text-[var(--surface-danger-text)]" })
|
|
1973
2072
|
}
|
|
1974
2073
|
)
|
|
1975
2074
|
] })
|
|
1976
2075
|
] }),
|
|
1977
|
-
/* @__PURE__ */
|
|
1978
|
-
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: [
|
|
1979
2078
|
"extends ",
|
|
1980
2079
|
profile.extends
|
|
1981
2080
|
] }),
|
|
1982
|
-
profile.model && /* @__PURE__ */
|
|
2081
|
+
profile.model && /* @__PURE__ */ jsx6(Badge2, { variant: "outline", className: "text-xs", children: profile.model.split("/").pop() })
|
|
1983
2082
|
] }),
|
|
1984
|
-
profile.metrics && profile.metrics.total_runs > 0 && /* @__PURE__ */
|
|
1985
|
-
/* @__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: [
|
|
1986
2085
|
profile.metrics.total_runs,
|
|
1987
2086
|
" runs"
|
|
1988
2087
|
] }),
|
|
1989
|
-
/* @__PURE__ */
|
|
2088
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1990
2089
|
profile.metrics.success_rate.toFixed(0),
|
|
1991
2090
|
"% success"
|
|
1992
2091
|
] }),
|
|
1993
|
-
/* @__PURE__ */
|
|
2092
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1994
2093
|
"~",
|
|
1995
2094
|
(profile.metrics.avg_duration_ms / 1e3).toFixed(1),
|
|
1996
2095
|
"s avg"
|
|
@@ -2009,7 +2108,7 @@ function ProfileFormDialog({
|
|
|
2009
2108
|
onSuccess
|
|
2010
2109
|
}) {
|
|
2011
2110
|
const isEditing = !!profile?.id;
|
|
2012
|
-
const [formData, setFormData] =
|
|
2111
|
+
const [formData, setFormData] = React5.useState({
|
|
2013
2112
|
name: "",
|
|
2014
2113
|
description: "",
|
|
2015
2114
|
extends: "",
|
|
@@ -2019,9 +2118,9 @@ function ProfileFormDialog({
|
|
|
2019
2118
|
tags: [],
|
|
2020
2119
|
is_public: false
|
|
2021
2120
|
});
|
|
2022
|
-
const [saving, setSaving] =
|
|
2023
|
-
const [error, setError] =
|
|
2024
|
-
|
|
2121
|
+
const [saving, setSaving] = React5.useState(false);
|
|
2122
|
+
const [error, setError] = React5.useState(null);
|
|
2123
|
+
React5.useEffect(() => {
|
|
2025
2124
|
if (profile) {
|
|
2026
2125
|
setFormData({
|
|
2027
2126
|
name: profile.name,
|
|
@@ -2077,19 +2176,19 @@ function ProfileFormDialog({
|
|
|
2077
2176
|
setSaving(false);
|
|
2078
2177
|
}
|
|
2079
2178
|
};
|
|
2080
|
-
return /* @__PURE__ */
|
|
2081
|
-
/* @__PURE__ */
|
|
2082
|
-
/* @__PURE__ */
|
|
2083
|
-
/* @__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" })
|
|
2084
2183
|
] }),
|
|
2085
|
-
/* @__PURE__ */
|
|
2086
|
-
error && /* @__PURE__ */
|
|
2087
|
-
/* @__PURE__ */
|
|
2088
|
-
/* @__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 })
|
|
2089
2188
|
] }),
|
|
2090
|
-
/* @__PURE__ */
|
|
2091
|
-
/* @__PURE__ */
|
|
2092
|
-
/* @__PURE__ */
|
|
2189
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2190
|
+
/* @__PURE__ */ jsx6("label", { className: "mb-1 block font-medium text-sm", children: "Name *" }),
|
|
2191
|
+
/* @__PURE__ */ jsx6(
|
|
2093
2192
|
Input2,
|
|
2094
2193
|
{
|
|
2095
2194
|
value: formData.name,
|
|
@@ -2101,9 +2200,9 @@ function ProfileFormDialog({
|
|
|
2101
2200
|
}
|
|
2102
2201
|
)
|
|
2103
2202
|
] }),
|
|
2104
|
-
/* @__PURE__ */
|
|
2105
|
-
/* @__PURE__ */
|
|
2106
|
-
/* @__PURE__ */
|
|
2203
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2204
|
+
/* @__PURE__ */ jsx6("label", { className: "mb-1 block font-medium text-sm", children: "Description" }),
|
|
2205
|
+
/* @__PURE__ */ jsx6(
|
|
2107
2206
|
Input2,
|
|
2108
2207
|
{
|
|
2109
2208
|
value: formData.description,
|
|
@@ -2112,17 +2211,17 @@ function ProfileFormDialog({
|
|
|
2112
2211
|
}
|
|
2113
2212
|
)
|
|
2114
2213
|
] }),
|
|
2115
|
-
/* @__PURE__ */
|
|
2116
|
-
/* @__PURE__ */
|
|
2117
|
-
/* @__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(
|
|
2118
2217
|
"select",
|
|
2119
2218
|
{
|
|
2120
2219
|
value: formData.extends,
|
|
2121
2220
|
onChange: (e) => setFormData((d) => ({ ...d, extends: e.target.value })),
|
|
2122
2221
|
className: "w-full rounded-md border border-border bg-background px-3 py-2 text-sm",
|
|
2123
2222
|
children: [
|
|
2124
|
-
/* @__PURE__ */
|
|
2125
|
-
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: [
|
|
2126
2225
|
p.name,
|
|
2127
2226
|
" - ",
|
|
2128
2227
|
p.description ?? "Built-in profile"
|
|
@@ -2131,9 +2230,9 @@ function ProfileFormDialog({
|
|
|
2131
2230
|
}
|
|
2132
2231
|
)
|
|
2133
2232
|
] }),
|
|
2134
|
-
/* @__PURE__ */
|
|
2135
|
-
/* @__PURE__ */
|
|
2136
|
-
/* @__PURE__ */
|
|
2233
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2234
|
+
/* @__PURE__ */ jsx6("label", { className: "mb-1 block font-medium text-sm", children: "Model" }),
|
|
2235
|
+
/* @__PURE__ */ jsx6(
|
|
2137
2236
|
Input2,
|
|
2138
2237
|
{
|
|
2139
2238
|
value: formData.model,
|
|
@@ -2141,11 +2240,11 @@ function ProfileFormDialog({
|
|
|
2141
2240
|
placeholder: "anthropic/claude-sonnet-4"
|
|
2142
2241
|
}
|
|
2143
2242
|
),
|
|
2144
|
-
/* @__PURE__ */
|
|
2243
|
+
/* @__PURE__ */ jsx6("p", { className: "mt-1 text-muted-foreground text-xs", children: "Format: provider/model-id (e.g., anthropic/claude-sonnet-4)" })
|
|
2145
2244
|
] }),
|
|
2146
|
-
/* @__PURE__ */
|
|
2147
|
-
/* @__PURE__ */
|
|
2148
|
-
/* @__PURE__ */
|
|
2245
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2246
|
+
/* @__PURE__ */ jsx6("label", { className: "mb-1 block font-medium text-sm", children: "System Prompt" }),
|
|
2247
|
+
/* @__PURE__ */ jsx6(
|
|
2149
2248
|
"textarea",
|
|
2150
2249
|
{
|
|
2151
2250
|
value: formData.system_prompt,
|
|
@@ -2156,9 +2255,9 @@ function ProfileFormDialog({
|
|
|
2156
2255
|
}
|
|
2157
2256
|
)
|
|
2158
2257
|
] }),
|
|
2159
|
-
/* @__PURE__ */
|
|
2160
|
-
/* @__PURE__ */
|
|
2161
|
-
/* @__PURE__ */
|
|
2258
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2259
|
+
/* @__PURE__ */ jsx6("label", { className: "mb-1 block font-medium text-sm", children: "Tags" }),
|
|
2260
|
+
/* @__PURE__ */ jsx6(
|
|
2162
2261
|
Input2,
|
|
2163
2262
|
{
|
|
2164
2263
|
value: formData.tags?.join(", "),
|
|
@@ -2169,10 +2268,10 @@ function ProfileFormDialog({
|
|
|
2169
2268
|
placeholder: "trading, aggressive, experimental"
|
|
2170
2269
|
}
|
|
2171
2270
|
),
|
|
2172
|
-
/* @__PURE__ */
|
|
2271
|
+
/* @__PURE__ */ jsx6("p", { className: "mt-1 text-muted-foreground text-xs", children: "Comma-separated tags for organization" })
|
|
2173
2272
|
] }),
|
|
2174
|
-
/* @__PURE__ */
|
|
2175
|
-
/* @__PURE__ */
|
|
2273
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
2274
|
+
/* @__PURE__ */ jsx6(
|
|
2176
2275
|
"input",
|
|
2177
2276
|
{
|
|
2178
2277
|
type: "checkbox",
|
|
@@ -2182,12 +2281,12 @@ function ProfileFormDialog({
|
|
|
2182
2281
|
className: "rounded border-border"
|
|
2183
2282
|
}
|
|
2184
2283
|
),
|
|
2185
|
-
/* @__PURE__ */
|
|
2284
|
+
/* @__PURE__ */ jsx6("label", { htmlFor: "is_public", className: "text-sm", children: "Make this profile public (visible to other users)" })
|
|
2186
2285
|
] }),
|
|
2187
|
-
/* @__PURE__ */
|
|
2188
|
-
/* @__PURE__ */
|
|
2189
|
-
/* @__PURE__ */
|
|
2190
|
-
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" }),
|
|
2191
2290
|
isEditing ? "Save Changes" : "Create Profile"
|
|
2192
2291
|
] })
|
|
2193
2292
|
] })
|
|
@@ -2200,8 +2299,8 @@ function DeleteProfileDialog({
|
|
|
2200
2299
|
apiClient,
|
|
2201
2300
|
onSuccess
|
|
2202
2301
|
}) {
|
|
2203
|
-
const [deleting, setDeleting] =
|
|
2204
|
-
const [error, setError] =
|
|
2302
|
+
const [deleting, setDeleting] = React5.useState(false);
|
|
2303
|
+
const [error, setError] = React5.useState(null);
|
|
2205
2304
|
const handleDelete = async () => {
|
|
2206
2305
|
if (!profile) return;
|
|
2207
2306
|
setError(null);
|
|
@@ -2215,34 +2314,34 @@ function DeleteProfileDialog({
|
|
|
2215
2314
|
setDeleting(false);
|
|
2216
2315
|
}
|
|
2217
2316
|
};
|
|
2218
|
-
return /* @__PURE__ */
|
|
2219
|
-
/* @__PURE__ */
|
|
2220
|
-
/* @__PURE__ */
|
|
2221
|
-
/* @__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: [
|
|
2222
2321
|
'Are you sure you want to delete "',
|
|
2223
2322
|
profile?.name,
|
|
2224
2323
|
'"? This action cannot be undone.'
|
|
2225
2324
|
] })
|
|
2226
2325
|
] }),
|
|
2227
|
-
error && /* @__PURE__ */
|
|
2228
|
-
/* @__PURE__ */
|
|
2229
|
-
/* @__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 })
|
|
2230
2329
|
] }),
|
|
2231
|
-
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: [
|
|
2232
2331
|
"This profile has ",
|
|
2233
2332
|
profile.metrics.total_runs,
|
|
2234
2333
|
" recorded runs. Deleting it will lose all performance metrics."
|
|
2235
2334
|
] }),
|
|
2236
|
-
/* @__PURE__ */
|
|
2237
|
-
/* @__PURE__ */
|
|
2238
|
-
/* @__PURE__ */
|
|
2335
|
+
/* @__PURE__ */ jsxs6(DialogFooter2, { children: [
|
|
2336
|
+
/* @__PURE__ */ jsx6(Button2, { variant: "outline", onClick: onClose, children: "Cancel" }),
|
|
2337
|
+
/* @__PURE__ */ jsxs6(
|
|
2239
2338
|
Button2,
|
|
2240
2339
|
{
|
|
2241
2340
|
variant: "destructive",
|
|
2242
2341
|
onClick: handleDelete,
|
|
2243
2342
|
disabled: deleting,
|
|
2244
2343
|
children: [
|
|
2245
|
-
deleting && /* @__PURE__ */
|
|
2344
|
+
deleting && /* @__PURE__ */ jsx6(Loader23, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
2246
2345
|
"Delete Profile"
|
|
2247
2346
|
]
|
|
2248
2347
|
}
|
|
@@ -2257,35 +2356,35 @@ function ProfileDetailDialog({
|
|
|
2257
2356
|
onDuplicate
|
|
2258
2357
|
}) {
|
|
2259
2358
|
if (!profile) return null;
|
|
2260
|
-
return /* @__PURE__ */
|
|
2261
|
-
/* @__PURE__ */
|
|
2262
|
-
/* @__PURE__ */
|
|
2263
|
-
/* @__PURE__ */
|
|
2264
|
-
profile.is_builtin && /* @__PURE__ */
|
|
2265
|
-
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" })
|
|
2266
2365
|
] }),
|
|
2267
|
-
profile.description && /* @__PURE__ */
|
|
2366
|
+
profile.description && /* @__PURE__ */ jsx6(DialogDescription2, { children: profile.description })
|
|
2268
2367
|
] }),
|
|
2269
|
-
/* @__PURE__ */
|
|
2270
|
-
/* @__PURE__ */
|
|
2271
|
-
profile.extends && /* @__PURE__ */
|
|
2272
|
-
/* @__PURE__ */
|
|
2273
|
-
/* @__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 })
|
|
2274
2373
|
] }),
|
|
2275
|
-
profile.model && /* @__PURE__ */
|
|
2276
|
-
/* @__PURE__ */
|
|
2277
|
-
/* @__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 })
|
|
2278
2377
|
] })
|
|
2279
2378
|
] }),
|
|
2280
|
-
profile.tags && profile.tags.length > 0 && /* @__PURE__ */
|
|
2281
|
-
/* @__PURE__ */
|
|
2282
|
-
/* @__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)) })
|
|
2283
2382
|
] }),
|
|
2284
|
-
profile.system_prompt && /* @__PURE__ */
|
|
2285
|
-
/* @__PURE__ */
|
|
2286
|
-
/* @__PURE__ */
|
|
2287
|
-
/* @__PURE__ */
|
|
2288
|
-
/* @__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(
|
|
2289
2388
|
Button2,
|
|
2290
2389
|
{
|
|
2291
2390
|
variant: "ghost",
|
|
@@ -2293,54 +2392,54 @@ function ProfileDetailDialog({
|
|
|
2293
2392
|
className: "absolute top-2 right-2",
|
|
2294
2393
|
onClick: () => navigator.clipboard.writeText(profile.system_prompt),
|
|
2295
2394
|
"aria-label": "Copy system prompt",
|
|
2296
|
-
children: /* @__PURE__ */
|
|
2395
|
+
children: /* @__PURE__ */ jsx6(Copy, { className: "h-4 w-4" })
|
|
2297
2396
|
}
|
|
2298
2397
|
)
|
|
2299
2398
|
] })
|
|
2300
2399
|
] }),
|
|
2301
|
-
profile.instructions && profile.instructions.length > 0 && /* @__PURE__ */
|
|
2302
|
-
/* @__PURE__ */
|
|
2303
|
-
/* @__PURE__ */
|
|
2304
|
-
/* @__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" }),
|
|
2305
2404
|
inst
|
|
2306
2405
|
] }, i)) })
|
|
2307
2406
|
] }),
|
|
2308
|
-
profile.metrics && profile.metrics.total_runs > 0 && /* @__PURE__ */
|
|
2309
|
-
/* @__PURE__ */
|
|
2310
|
-
/* @__PURE__ */
|
|
2311
|
-
/* @__PURE__ */
|
|
2312
|
-
/* @__PURE__ */
|
|
2313
|
-
/* @__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" })
|
|
2314
2413
|
] }),
|
|
2315
|
-
/* @__PURE__ */
|
|
2316
|
-
/* @__PURE__ */
|
|
2414
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2415
|
+
/* @__PURE__ */ jsxs6("p", { className: "font-medium text-2xl", children: [
|
|
2317
2416
|
profile.metrics.success_rate.toFixed(0),
|
|
2318
2417
|
"%"
|
|
2319
2418
|
] }),
|
|
2320
|
-
/* @__PURE__ */
|
|
2419
|
+
/* @__PURE__ */ jsx6("p", { className: "text-muted-foreground text-xs", children: "Success Rate" })
|
|
2321
2420
|
] }),
|
|
2322
|
-
/* @__PURE__ */
|
|
2323
|
-
/* @__PURE__ */
|
|
2421
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2422
|
+
/* @__PURE__ */ jsxs6("p", { className: "font-medium text-2xl", children: [
|
|
2324
2423
|
(profile.metrics.avg_duration_ms / 1e3).toFixed(1),
|
|
2325
2424
|
"s"
|
|
2326
2425
|
] }),
|
|
2327
|
-
/* @__PURE__ */
|
|
2426
|
+
/* @__PURE__ */ jsx6("p", { className: "text-muted-foreground text-xs", children: "Avg Duration" })
|
|
2328
2427
|
] }),
|
|
2329
|
-
profile.metrics.avg_tokens_used && /* @__PURE__ */
|
|
2330
|
-
/* @__PURE__ */
|
|
2331
|
-
/* @__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" })
|
|
2332
2431
|
] })
|
|
2333
2432
|
] })
|
|
2334
2433
|
] })
|
|
2335
2434
|
] }),
|
|
2336
|
-
/* @__PURE__ */
|
|
2337
|
-
/* @__PURE__ */
|
|
2338
|
-
onDuplicate && /* @__PURE__ */
|
|
2339
|
-
/* @__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" }),
|
|
2340
2439
|
"Duplicate"
|
|
2341
2440
|
] }),
|
|
2342
|
-
onEdit && /* @__PURE__ */
|
|
2343
|
-
/* @__PURE__ */
|
|
2441
|
+
onEdit && /* @__PURE__ */ jsxs6(Button2, { onClick: onEdit, children: [
|
|
2442
|
+
/* @__PURE__ */ jsx6(Edit2, { className: "mr-2 h-4 w-4" }),
|
|
2344
2443
|
"Edit"
|
|
2345
2444
|
] })
|
|
2346
2445
|
] })
|
|
@@ -2348,33 +2447,104 @@ function ProfileDetailDialog({
|
|
|
2348
2447
|
}
|
|
2349
2448
|
|
|
2350
2449
|
// src/pages/secrets-page.tsx
|
|
2351
|
-
import * as
|
|
2352
|
-
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";
|
|
2353
2452
|
import {
|
|
2354
|
-
Dialog as
|
|
2355
|
-
DialogContent as
|
|
2356
|
-
DialogDescription as
|
|
2357
|
-
DialogFooter as
|
|
2358
|
-
DialogHeader as
|
|
2359
|
-
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
|
|
2360
2459
|
} from "@tangle-network/ui/primitives";
|
|
2361
|
-
|
|
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;
|
|
2362
2523
|
function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
2363
|
-
const [secrets, setSecrets] =
|
|
2364
|
-
const [loading, setLoading] =
|
|
2365
|
-
const [error, setError] =
|
|
2366
|
-
const [isCreateOpen, setIsCreateOpen] =
|
|
2367
|
-
const [newName, setNewName] =
|
|
2368
|
-
const [newValue, setNewValue] =
|
|
2369
|
-
const [showValue, setShowValue] =
|
|
2370
|
-
const [isCreating, setIsCreating] =
|
|
2371
|
-
const [createError, setCreateError] =
|
|
2372
|
-
const [deleteTarget, setDeleteTarget] =
|
|
2373
|
-
const [isDeleting, setIsDeleting] =
|
|
2374
|
-
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);
|
|
2375
2545
|
apiRef.current = apiClient;
|
|
2376
|
-
const loadGenRef =
|
|
2377
|
-
const loadSecrets =
|
|
2546
|
+
const loadGenRef = React6.useRef(0);
|
|
2547
|
+
const loadSecrets = React6.useCallback(async (showSpinner = true) => {
|
|
2378
2548
|
const gen = ++loadGenRef.current;
|
|
2379
2549
|
try {
|
|
2380
2550
|
if (showSpinner) setLoading(true);
|
|
@@ -2389,7 +2559,7 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2389
2559
|
if (gen === loadGenRef.current) setLoading(false);
|
|
2390
2560
|
}
|
|
2391
2561
|
}, []);
|
|
2392
|
-
|
|
2562
|
+
React6.useEffect(() => {
|
|
2393
2563
|
loadSecrets();
|
|
2394
2564
|
}, [loadSecrets]);
|
|
2395
2565
|
const handleCreate = async () => {
|
|
@@ -2421,6 +2591,100 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2421
2591
|
setIsDeleting(false);
|
|
2422
2592
|
}
|
|
2423
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
|
+
};
|
|
2424
2688
|
const formatDate = (dateStr) => {
|
|
2425
2689
|
try {
|
|
2426
2690
|
const ts = /^\d+$/.test(dateStr) ? Number(dateStr) : dateStr;
|
|
@@ -2431,36 +2695,50 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2431
2695
|
return dateStr;
|
|
2432
2696
|
}
|
|
2433
2697
|
};
|
|
2434
|
-
return /* @__PURE__ */
|
|
2435
|
-
/* @__PURE__ */
|
|
2436
|
-
/* @__PURE__ */
|
|
2437
|
-
/* @__PURE__ */
|
|
2438
|
-
/* @__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." })
|
|
2439
2703
|
] }),
|
|
2440
|
-
/* @__PURE__ */
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
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
|
+
] })
|
|
2452
2730
|
] }),
|
|
2453
|
-
teamSecretsHint && /* @__PURE__ */
|
|
2454
|
-
/* @__PURE__ */
|
|
2455
|
-
/* @__PURE__ */
|
|
2456
|
-
/* @__PURE__ */
|
|
2457
|
-
/* @__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: [
|
|
2458
2736
|
"Secrets here are ",
|
|
2459
|
-
/* @__PURE__ */
|
|
2737
|
+
/* @__PURE__ */ jsx7("strong", { children: "personal" }),
|
|
2460
2738
|
" \u2014 only available in sandboxes you create. To share credentials with teammates, configure them on the team page instead."
|
|
2461
2739
|
] })
|
|
2462
2740
|
] }),
|
|
2463
|
-
/* @__PURE__ */
|
|
2741
|
+
/* @__PURE__ */ jsxs7(
|
|
2464
2742
|
"button",
|
|
2465
2743
|
{
|
|
2466
2744
|
type: "button",
|
|
@@ -2468,24 +2746,24 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2468
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",
|
|
2469
2747
|
children: [
|
|
2470
2748
|
teamSecretsHint.label ?? "Manage team secrets",
|
|
2471
|
-
/* @__PURE__ */
|
|
2749
|
+
/* @__PURE__ */ jsx7(ArrowRight, { className: "h-3 w-3", "aria-hidden": "true" })
|
|
2472
2750
|
]
|
|
2473
2751
|
}
|
|
2474
2752
|
)
|
|
2475
2753
|
] }),
|
|
2476
|
-
/* @__PURE__ */
|
|
2477
|
-
/* @__PURE__ */
|
|
2478
|
-
/* @__PURE__ */
|
|
2479
|
-
/* @__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 }) })
|
|
2480
2758
|
] }),
|
|
2481
|
-
/* @__PURE__ */
|
|
2482
|
-
/* @__PURE__ */
|
|
2483
|
-
/* @__PURE__ */
|
|
2484
|
-
/* @__PURE__ */
|
|
2485
|
-
/* @__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" })
|
|
2486
2764
|
] })
|
|
2487
2765
|
] }),
|
|
2488
|
-
/* @__PURE__ */
|
|
2766
|
+
/* @__PURE__ */ jsx7(
|
|
2489
2767
|
InfoPanel,
|
|
2490
2768
|
{
|
|
2491
2769
|
className: "md:col-span-2",
|
|
@@ -2495,11 +2773,11 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2495
2773
|
}
|
|
2496
2774
|
)
|
|
2497
2775
|
] }),
|
|
2498
|
-
error && /* @__PURE__ */
|
|
2499
|
-
/* @__PURE__ */
|
|
2500
|
-
/* @__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 })
|
|
2501
2779
|
] }),
|
|
2502
|
-
/* @__PURE__ */
|
|
2780
|
+
/* @__PURE__ */ jsx7(Dialog3, { open: isCreateOpen, onOpenChange: (open) => {
|
|
2503
2781
|
if (!open) {
|
|
2504
2782
|
setIsCreateOpen(false);
|
|
2505
2783
|
setNewName("");
|
|
@@ -2507,12 +2785,12 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2507
2785
|
setCreateError(null);
|
|
2508
2786
|
setShowValue(false);
|
|
2509
2787
|
}
|
|
2510
|
-
}, children: /* @__PURE__ */
|
|
2511
|
-
/* @__PURE__ */
|
|
2512
|
-
/* @__PURE__ */
|
|
2513
|
-
/* @__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." })
|
|
2514
2792
|
] }),
|
|
2515
|
-
/* @__PURE__ */
|
|
2793
|
+
/* @__PURE__ */ jsxs7(
|
|
2516
2794
|
"form",
|
|
2517
2795
|
{
|
|
2518
2796
|
onSubmit: (e) => {
|
|
@@ -2521,9 +2799,9 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2521
2799
|
},
|
|
2522
2800
|
className: "space-y-4",
|
|
2523
2801
|
children: [
|
|
2524
|
-
/* @__PURE__ */
|
|
2525
|
-
/* @__PURE__ */
|
|
2526
|
-
/* @__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(
|
|
2527
2805
|
"input",
|
|
2528
2806
|
{
|
|
2529
2807
|
id: "secret-name",
|
|
@@ -2537,10 +2815,10 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2537
2815
|
}
|
|
2538
2816
|
)
|
|
2539
2817
|
] }),
|
|
2540
|
-
/* @__PURE__ */
|
|
2541
|
-
/* @__PURE__ */
|
|
2542
|
-
/* @__PURE__ */
|
|
2543
|
-
/* @__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(
|
|
2544
2822
|
"input",
|
|
2545
2823
|
{
|
|
2546
2824
|
id: "secret-value",
|
|
@@ -2553,26 +2831,26 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2553
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"
|
|
2554
2832
|
}
|
|
2555
2833
|
),
|
|
2556
|
-
/* @__PURE__ */
|
|
2834
|
+
/* @__PURE__ */ jsx7(
|
|
2557
2835
|
"button",
|
|
2558
2836
|
{
|
|
2559
2837
|
type: "button",
|
|
2560
2838
|
onClick: () => setShowValue(!showValue),
|
|
2561
2839
|
className: "absolute right-2 top-1/2 -translate-y-1/2 p-1 text-muted-foreground hover:text-foreground",
|
|
2562
2840
|
"aria-label": showValue ? "Hide value" : "Show value",
|
|
2563
|
-
children: showValue ? /* @__PURE__ */
|
|
2841
|
+
children: showValue ? /* @__PURE__ */ jsx7(EyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx7(Eye, { className: "h-4 w-4" })
|
|
2564
2842
|
}
|
|
2565
2843
|
)
|
|
2566
2844
|
] }),
|
|
2567
|
-
/* @__PURE__ */
|
|
2845
|
+
/* @__PURE__ */ jsx7("p", { className: "mt-1.5 text-xs text-muted-foreground", children: "This value cannot be retrieved after creation." })
|
|
2568
2846
|
] }),
|
|
2569
|
-
/* @__PURE__ */
|
|
2847
|
+
/* @__PURE__ */ jsx7("button", { type: "submit", className: "hidden", tabIndex: -1, "aria-hidden": "true", children: "Submit" })
|
|
2570
2848
|
]
|
|
2571
2849
|
}
|
|
2572
2850
|
),
|
|
2573
|
-
createError && /* @__PURE__ */
|
|
2574
|
-
/* @__PURE__ */
|
|
2575
|
-
/* @__PURE__ */
|
|
2851
|
+
createError && /* @__PURE__ */ jsx7("p", { className: "mt-3 text-sm text-destructive", children: createError }),
|
|
2852
|
+
/* @__PURE__ */ jsxs7(DialogFooter3, { children: [
|
|
2853
|
+
/* @__PURE__ */ jsx7(
|
|
2576
2854
|
"button",
|
|
2577
2855
|
{
|
|
2578
2856
|
type: "button",
|
|
@@ -2586,7 +2864,7 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2586
2864
|
children: "Cancel"
|
|
2587
2865
|
}
|
|
2588
2866
|
),
|
|
2589
|
-
/* @__PURE__ */
|
|
2867
|
+
/* @__PURE__ */ jsx7(
|
|
2590
2868
|
"button",
|
|
2591
2869
|
{
|
|
2592
2870
|
type: "button",
|
|
@@ -2598,19 +2876,204 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2598
2876
|
)
|
|
2599
2877
|
] })
|
|
2600
2878
|
] }) }),
|
|
2601
|
-
/* @__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) => {
|
|
2602
3065
|
if (!open) setDeleteTarget(null);
|
|
2603
|
-
}, children: /* @__PURE__ */
|
|
2604
|
-
/* @__PURE__ */
|
|
2605
|
-
/* @__PURE__ */
|
|
2606
|
-
/* @__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: [
|
|
2607
3070
|
"This will permanently delete ",
|
|
2608
|
-
/* @__PURE__ */
|
|
3071
|
+
/* @__PURE__ */ jsx7("span", { className: "font-mono font-bold text-foreground", children: deleteTarget }),
|
|
2609
3072
|
". Sandboxes using this secret will lose access to it."
|
|
2610
3073
|
] })
|
|
2611
3074
|
] }),
|
|
2612
|
-
/* @__PURE__ */
|
|
2613
|
-
/* @__PURE__ */
|
|
3075
|
+
/* @__PURE__ */ jsxs7(DialogFooter3, { children: [
|
|
3076
|
+
/* @__PURE__ */ jsx7(
|
|
2614
3077
|
"button",
|
|
2615
3078
|
{
|
|
2616
3079
|
type: "button",
|
|
@@ -2619,7 +3082,7 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2619
3082
|
children: "Cancel"
|
|
2620
3083
|
}
|
|
2621
3084
|
),
|
|
2622
|
-
/* @__PURE__ */
|
|
3085
|
+
/* @__PURE__ */ jsx7(
|
|
2623
3086
|
"button",
|
|
2624
3087
|
{
|
|
2625
3088
|
type: "button",
|
|
@@ -2631,20 +3094,20 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2631
3094
|
)
|
|
2632
3095
|
] })
|
|
2633
3096
|
] }) }),
|
|
2634
|
-
/* @__PURE__ */
|
|
2635
|
-
/* @__PURE__ */
|
|
2636
|
-
/* @__PURE__ */
|
|
2637
|
-
/* @__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: [
|
|
2638
3101
|
secrets.length,
|
|
2639
3102
|
" secret",
|
|
2640
3103
|
secrets.length !== 1 ? "s" : ""
|
|
2641
3104
|
] })
|
|
2642
3105
|
] }),
|
|
2643
|
-
loading ? /* @__PURE__ */
|
|
2644
|
-
/* @__PURE__ */
|
|
2645
|
-
/* @__PURE__ */
|
|
2646
|
-
/* @__PURE__ */
|
|
2647
|
-
/* @__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(
|
|
2648
3111
|
"button",
|
|
2649
3112
|
{
|
|
2650
3113
|
type: "button",
|
|
@@ -2652,52 +3115,52 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2652
3115
|
"aria-label": "Create your first secret",
|
|
2653
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]",
|
|
2654
3117
|
children: [
|
|
2655
|
-
/* @__PURE__ */
|
|
3118
|
+
/* @__PURE__ */ jsx7(Plus3, { className: "h-4 w-4" }),
|
|
2656
3119
|
"New Secret"
|
|
2657
3120
|
]
|
|
2658
3121
|
}
|
|
2659
3122
|
)
|
|
2660
|
-
] }) : /* @__PURE__ */
|
|
2661
|
-
/* @__PURE__ */
|
|
2662
|
-
/* @__PURE__ */
|
|
2663
|
-
/* @__PURE__ */
|
|
2664
|
-
/* @__PURE__ */
|
|
2665
|
-
/* @__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" })
|
|
2666
3129
|
] }) }),
|
|
2667
|
-
/* @__PURE__ */
|
|
2668
|
-
/* @__PURE__ */
|
|
2669
|
-
/* @__PURE__ */
|
|
2670
|
-
/* @__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 })
|
|
2671
3134
|
] }) }),
|
|
2672
|
-
/* @__PURE__ */
|
|
2673
|
-
/* @__PURE__ */
|
|
2674
|
-
/* @__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(
|
|
2675
3138
|
"button",
|
|
2676
3139
|
{
|
|
2677
3140
|
type: "button",
|
|
2678
3141
|
onClick: () => setDeleteTarget(secret.name),
|
|
2679
3142
|
className: "p-1.5 rounded-md text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-colors",
|
|
2680
3143
|
"aria-label": `Delete ${secret.name}`,
|
|
2681
|
-
children: /* @__PURE__ */
|
|
3144
|
+
children: /* @__PURE__ */ jsx7(Trash23, { className: "h-4 w-4" })
|
|
2682
3145
|
}
|
|
2683
3146
|
) })
|
|
2684
3147
|
] }, secret.name)) })
|
|
2685
3148
|
] })
|
|
2686
3149
|
] }),
|
|
2687
|
-
/* @__PURE__ */
|
|
2688
|
-
/* @__PURE__ */
|
|
2689
|
-
/* @__PURE__ */
|
|
2690
|
-
/* @__PURE__ */
|
|
2691
|
-
/* @__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" })
|
|
2692
3155
|
] }),
|
|
2693
|
-
/* @__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." })
|
|
2694
3157
|
] }),
|
|
2695
|
-
/* @__PURE__ */
|
|
2696
|
-
/* @__PURE__ */
|
|
2697
|
-
/* @__PURE__ */
|
|
2698
|
-
/* @__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" })
|
|
2699
3162
|
] }),
|
|
2700
|
-
/* @__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." })
|
|
2701
3164
|
] })
|
|
2702
3165
|
] })
|
|
2703
3166
|
] });
|
|
@@ -2706,18 +3169,18 @@ function SecretsPage({ apiClient, className, teamSecretsHint }) {
|
|
|
2706
3169
|
// src/pages/templates-page.tsx
|
|
2707
3170
|
import { Layers as Layers2 } from "lucide-react";
|
|
2708
3171
|
import { Skeleton as Skeleton3 } from "@tangle-network/ui/primitives";
|
|
2709
|
-
import { jsx as
|
|
3172
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2710
3173
|
function TemplatesPage({ templates, loading = false, onUseTemplate, className }) {
|
|
2711
|
-
return /* @__PURE__ */
|
|
2712
|
-
/* @__PURE__ */
|
|
2713
|
-
/* @__PURE__ */
|
|
2714
|
-
/* @__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" })
|
|
2715
3178
|
] }),
|
|
2716
|
-
loading || !templates ? /* @__PURE__ */
|
|
2717
|
-
/* @__PURE__ */
|
|
2718
|
-
/* @__PURE__ */
|
|
2719
|
-
/* @__PURE__ */
|
|
2720
|
-
] }) : /* @__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(
|
|
2721
3184
|
TemplateCard,
|
|
2722
3185
|
{
|
|
2723
3186
|
template,
|
|
@@ -2729,7 +3192,7 @@ function TemplatesPage({ templates, loading = false, onUseTemplate, className })
|
|
|
2729
3192
|
}
|
|
2730
3193
|
|
|
2731
3194
|
// src/pages/startup-scripts-page.tsx
|
|
2732
|
-
import * as
|
|
3195
|
+
import * as React7 from "react";
|
|
2733
3196
|
import {
|
|
2734
3197
|
Play,
|
|
2735
3198
|
Plus as Plus4,
|
|
@@ -2750,14 +3213,14 @@ import {
|
|
|
2750
3213
|
Layers as Layers3
|
|
2751
3214
|
} from "lucide-react";
|
|
2752
3215
|
import {
|
|
2753
|
-
Dialog as
|
|
2754
|
-
DialogContent as
|
|
2755
|
-
DialogDescription as
|
|
2756
|
-
DialogFooter as
|
|
2757
|
-
DialogHeader as
|
|
2758
|
-
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
|
|
2759
3222
|
} from "@tangle-network/ui/primitives";
|
|
2760
|
-
import { jsx as
|
|
3223
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2761
3224
|
var SCRIPT_TYPE_META = {
|
|
2762
3225
|
bash: {
|
|
2763
3226
|
label: "Bash",
|
|
@@ -2926,26 +3389,26 @@ function makeDefaultFormData(scriptType = "bash") {
|
|
|
2926
3389
|
};
|
|
2927
3390
|
}
|
|
2928
3391
|
function StartupScriptsPage({ apiClient, className }) {
|
|
2929
|
-
const [scripts, setScripts] =
|
|
2930
|
-
const [secrets, setSecrets] =
|
|
2931
|
-
const [environments, setEnvironments] =
|
|
2932
|
-
const [loading, setLoading] =
|
|
2933
|
-
const [error, setError] =
|
|
2934
|
-
const [isDialogOpen, setIsDialogOpen] =
|
|
2935
|
-
const [dialogStep, setDialogStep] =
|
|
2936
|
-
const [transitionDir, setTransitionDir] =
|
|
2937
|
-
const [stepKey, setStepKey] =
|
|
2938
|
-
const [editingScript, setEditingScript] =
|
|
2939
|
-
const [formData, setFormData] =
|
|
2940
|
-
const [isSaving, setIsSaving] =
|
|
2941
|
-
const [formError, setFormError] =
|
|
2942
|
-
const [showConditions, setShowConditions] =
|
|
2943
|
-
const [deleteTarget, setDeleteTarget] =
|
|
2944
|
-
const [isDeleting, setIsDeleting] =
|
|
2945
|
-
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);
|
|
2946
3409
|
apiRef.current = apiClient;
|
|
2947
|
-
const loadGenRef =
|
|
2948
|
-
const loadData =
|
|
3410
|
+
const loadGenRef = React7.useRef(0);
|
|
3411
|
+
const loadData = React7.useCallback(async (showSpinner = true) => {
|
|
2949
3412
|
const gen = ++loadGenRef.current;
|
|
2950
3413
|
try {
|
|
2951
3414
|
if (showSpinner) setLoading(true);
|
|
@@ -2966,7 +3429,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
2966
3429
|
if (gen === loadGenRef.current) setLoading(false);
|
|
2967
3430
|
}
|
|
2968
3431
|
}, []);
|
|
2969
|
-
|
|
3432
|
+
React7.useEffect(() => {
|
|
2970
3433
|
loadData();
|
|
2971
3434
|
}, [loadData]);
|
|
2972
3435
|
const openCreate = () => {
|
|
@@ -3079,41 +3542,41 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3079
3542
|
}));
|
|
3080
3543
|
};
|
|
3081
3544
|
const activeCount = scripts.filter((s) => s.enabled).length;
|
|
3082
|
-
return /* @__PURE__ */
|
|
3083
|
-
/* @__PURE__ */
|
|
3084
|
-
/* @__PURE__ */
|
|
3085
|
-
/* @__PURE__ */
|
|
3086
|
-
/* @__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." })
|
|
3087
3550
|
] }),
|
|
3088
|
-
/* @__PURE__ */
|
|
3551
|
+
/* @__PURE__ */ jsxs9(
|
|
3089
3552
|
"button",
|
|
3090
3553
|
{
|
|
3091
3554
|
type: "button",
|
|
3092
3555
|
onClick: openCreate,
|
|
3093
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)]",
|
|
3094
3557
|
children: [
|
|
3095
|
-
/* @__PURE__ */
|
|
3558
|
+
/* @__PURE__ */ jsx9(Plus4, { className: "h-4 w-4" }),
|
|
3096
3559
|
"New Script"
|
|
3097
3560
|
]
|
|
3098
3561
|
}
|
|
3099
3562
|
)
|
|
3100
3563
|
] }),
|
|
3101
|
-
/* @__PURE__ */
|
|
3102
|
-
/* @__PURE__ */
|
|
3103
|
-
/* @__PURE__ */
|
|
3104
|
-
/* @__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 }) })
|
|
3105
3568
|
] }),
|
|
3106
|
-
/* @__PURE__ */
|
|
3107
|
-
/* @__PURE__ */
|
|
3108
|
-
/* @__PURE__ */
|
|
3109
|
-
/* @__PURE__ */
|
|
3110
|
-
/* @__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: [
|
|
3111
3574
|
"of ",
|
|
3112
3575
|
scripts.length
|
|
3113
3576
|
] })
|
|
3114
3577
|
] })
|
|
3115
3578
|
] }),
|
|
3116
|
-
/* @__PURE__ */
|
|
3579
|
+
/* @__PURE__ */ jsx9(
|
|
3117
3580
|
InfoPanel,
|
|
3118
3581
|
{
|
|
3119
3582
|
className: "md:col-span-2",
|
|
@@ -3123,12 +3586,12 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3123
3586
|
}
|
|
3124
3587
|
)
|
|
3125
3588
|
] }),
|
|
3126
|
-
error && /* @__PURE__ */
|
|
3127
|
-
/* @__PURE__ */
|
|
3128
|
-
/* @__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 })
|
|
3129
3592
|
] }),
|
|
3130
|
-
/* @__PURE__ */
|
|
3131
|
-
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(
|
|
3132
3595
|
"div",
|
|
3133
3596
|
{
|
|
3134
3597
|
className: cn(
|
|
@@ -3136,14 +3599,14 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3136
3599
|
transitionDir === "back" ? "slide-in-from-left-4" : "slide-in-from-right-4"
|
|
3137
3600
|
),
|
|
3138
3601
|
children: [
|
|
3139
|
-
/* @__PURE__ */
|
|
3140
|
-
/* @__PURE__ */
|
|
3141
|
-
/* @__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." })
|
|
3142
3605
|
] }),
|
|
3143
|
-
/* @__PURE__ */
|
|
3144
|
-
/* @__PURE__ */
|
|
3145
|
-
/* @__PURE__ */
|
|
3146
|
-
/* @__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(
|
|
3147
3610
|
"button",
|
|
3148
3611
|
{
|
|
3149
3612
|
type: "button",
|
|
@@ -3154,24 +3617,24 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3154
3617
|
type
|
|
3155
3618
|
)) })
|
|
3156
3619
|
] }),
|
|
3157
|
-
/* @__PURE__ */
|
|
3158
|
-
/* @__PURE__ */
|
|
3159
|
-
/* @__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(
|
|
3160
3623
|
"button",
|
|
3161
3624
|
{
|
|
3162
3625
|
type: "button",
|
|
3163
3626
|
onClick: () => openFromTemplate(tmpl),
|
|
3164
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",
|
|
3165
3628
|
children: [
|
|
3166
|
-
/* @__PURE__ */
|
|
3167
|
-
/* @__PURE__ */
|
|
3168
|
-
/* @__PURE__ */
|
|
3169
|
-
/* @__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 })
|
|
3170
3633
|
] }),
|
|
3171
|
-
/* @__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 })
|
|
3172
3635
|
] }),
|
|
3173
|
-
tmpl.injectSecrets.length > 0 && /* @__PURE__ */
|
|
3174
|
-
/* @__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" }),
|
|
3175
3638
|
s
|
|
3176
3639
|
] }, s)) })
|
|
3177
3640
|
]
|
|
@@ -3184,7 +3647,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3184
3647
|
},
|
|
3185
3648
|
`picker-${stepKey}`
|
|
3186
3649
|
),
|
|
3187
|
-
dialogStep === "form" && /* @__PURE__ */
|
|
3650
|
+
dialogStep === "form" && /* @__PURE__ */ jsxs9(
|
|
3188
3651
|
"div",
|
|
3189
3652
|
{
|
|
3190
3653
|
className: cn(
|
|
@@ -3192,14 +3655,14 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3192
3655
|
transitionDir === "forward" ? "slide-in-from-right-4" : "slide-in-from-left-4"
|
|
3193
3656
|
),
|
|
3194
3657
|
children: [
|
|
3195
|
-
/* @__PURE__ */
|
|
3196
|
-
/* @__PURE__ */
|
|
3197
|
-
/* @__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." })
|
|
3198
3661
|
] }),
|
|
3199
|
-
/* @__PURE__ */
|
|
3200
|
-
/* @__PURE__ */
|
|
3201
|
-
/* @__PURE__ */
|
|
3202
|
-
/* @__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(
|
|
3203
3666
|
"input",
|
|
3204
3667
|
{
|
|
3205
3668
|
type: "text",
|
|
@@ -3211,9 +3674,9 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3211
3674
|
}
|
|
3212
3675
|
)
|
|
3213
3676
|
] }),
|
|
3214
|
-
/* @__PURE__ */
|
|
3215
|
-
/* @__PURE__ */
|
|
3216
|
-
/* @__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(
|
|
3217
3680
|
"input",
|
|
3218
3681
|
{
|
|
3219
3682
|
type: "text",
|
|
@@ -3225,9 +3688,9 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3225
3688
|
}
|
|
3226
3689
|
)
|
|
3227
3690
|
] }),
|
|
3228
|
-
/* @__PURE__ */
|
|
3229
|
-
/* @__PURE__ */
|
|
3230
|
-
/* @__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(
|
|
3231
3694
|
"button",
|
|
3232
3695
|
{
|
|
3233
3696
|
type: "button",
|
|
@@ -3249,9 +3712,9 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3249
3712
|
type
|
|
3250
3713
|
)) })
|
|
3251
3714
|
] }),
|
|
3252
|
-
/* @__PURE__ */
|
|
3253
|
-
/* @__PURE__ */
|
|
3254
|
-
/* @__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(
|
|
3255
3718
|
"textarea",
|
|
3256
3719
|
{
|
|
3257
3720
|
value: formData.content,
|
|
@@ -3261,19 +3724,19 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3261
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"
|
|
3262
3725
|
}
|
|
3263
3726
|
),
|
|
3264
|
-
/* @__PURE__ */
|
|
3727
|
+
/* @__PURE__ */ jsxs9("p", { className: "mt-1 text-xs text-muted-foreground", children: [
|
|
3265
3728
|
SCRIPT_TYPE_META[formData.scriptType].label,
|
|
3266
3729
|
" script. Injected secrets are available as environment variables (e.g. ",
|
|
3267
|
-
/* @__PURE__ */
|
|
3730
|
+
/* @__PURE__ */ jsx9("code", { className: "text-primary", children: "$GITHUB_TOKEN" }),
|
|
3268
3731
|
")."
|
|
3269
3732
|
] })
|
|
3270
3733
|
] }),
|
|
3271
|
-
secrets.length > 0 && /* @__PURE__ */
|
|
3272
|
-
/* @__PURE__ */
|
|
3273
|
-
/* @__PURE__ */
|
|
3274
|
-
/* @__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) => {
|
|
3275
3738
|
const selected = formData.injectSecrets.includes(secret.name);
|
|
3276
|
-
return /* @__PURE__ */
|
|
3739
|
+
return /* @__PURE__ */ jsxs9(
|
|
3277
3740
|
"button",
|
|
3278
3741
|
{
|
|
3279
3742
|
type: "button",
|
|
@@ -3283,7 +3746,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3283
3746
|
selected ? "bg-primary/10 border-primary/30 text-primary" : "bg-muted border-border text-muted-foreground hover:border-primary/20"
|
|
3284
3747
|
),
|
|
3285
3748
|
children: [
|
|
3286
|
-
/* @__PURE__ */
|
|
3749
|
+
/* @__PURE__ */ jsx9(Lock2, { className: "h-3 w-3" }),
|
|
3287
3750
|
secret.name
|
|
3288
3751
|
]
|
|
3289
3752
|
},
|
|
@@ -3291,29 +3754,29 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3291
3754
|
);
|
|
3292
3755
|
}) })
|
|
3293
3756
|
] }),
|
|
3294
|
-
/* @__PURE__ */
|
|
3295
|
-
/* @__PURE__ */
|
|
3757
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
3758
|
+
/* @__PURE__ */ jsxs9(
|
|
3296
3759
|
"button",
|
|
3297
3760
|
{
|
|
3298
3761
|
type: "button",
|
|
3299
3762
|
onClick: () => setShowConditions(!showConditions),
|
|
3300
3763
|
className: "flex items-center gap-2 text-xs font-bold uppercase tracking-widest text-muted-foreground hover:text-foreground transition-colors",
|
|
3301
3764
|
children: [
|
|
3302
|
-
showConditions ? /* @__PURE__ */
|
|
3765
|
+
showConditions ? /* @__PURE__ */ jsx9(ChevronUp, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx9(ChevronDown2, { className: "h-3.5 w-3.5" }),
|
|
3303
3766
|
"Conditions & Execution"
|
|
3304
3767
|
]
|
|
3305
3768
|
}
|
|
3306
3769
|
),
|
|
3307
|
-
showConditions && /* @__PURE__ */
|
|
3308
|
-
/* @__PURE__ */
|
|
3309
|
-
/* @__PURE__ */
|
|
3310
|
-
/* @__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" }),
|
|
3311
3774
|
"Environments"
|
|
3312
3775
|
] }),
|
|
3313
|
-
/* @__PURE__ */
|
|
3314
|
-
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) => {
|
|
3315
3778
|
const selected = formData.environments.includes(env.id);
|
|
3316
|
-
return /* @__PURE__ */
|
|
3779
|
+
return /* @__PURE__ */ jsx9(
|
|
3317
3780
|
"button",
|
|
3318
3781
|
{
|
|
3319
3782
|
type: "button",
|
|
@@ -3328,13 +3791,13 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3328
3791
|
);
|
|
3329
3792
|
}) })
|
|
3330
3793
|
] }),
|
|
3331
|
-
/* @__PURE__ */
|
|
3332
|
-
/* @__PURE__ */
|
|
3333
|
-
/* @__PURE__ */
|
|
3334
|
-
/* @__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" }),
|
|
3335
3798
|
"Min CPU Cores"
|
|
3336
3799
|
] }),
|
|
3337
|
-
/* @__PURE__ */
|
|
3800
|
+
/* @__PURE__ */ jsx9(
|
|
3338
3801
|
"input",
|
|
3339
3802
|
{
|
|
3340
3803
|
type: "number",
|
|
@@ -3350,12 +3813,12 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3350
3813
|
}
|
|
3351
3814
|
)
|
|
3352
3815
|
] }),
|
|
3353
|
-
/* @__PURE__ */
|
|
3354
|
-
/* @__PURE__ */
|
|
3355
|
-
/* @__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" }),
|
|
3356
3819
|
"Min RAM (GB)"
|
|
3357
3820
|
] }),
|
|
3358
|
-
/* @__PURE__ */
|
|
3821
|
+
/* @__PURE__ */ jsx9(
|
|
3359
3822
|
"input",
|
|
3360
3823
|
{
|
|
3361
3824
|
type: "number",
|
|
@@ -3372,13 +3835,13 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3372
3835
|
)
|
|
3373
3836
|
] })
|
|
3374
3837
|
] }),
|
|
3375
|
-
/* @__PURE__ */
|
|
3376
|
-
/* @__PURE__ */
|
|
3377
|
-
/* @__PURE__ */
|
|
3378
|
-
/* @__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" }),
|
|
3379
3842
|
"Run Order"
|
|
3380
3843
|
] }),
|
|
3381
|
-
/* @__PURE__ */
|
|
3844
|
+
/* @__PURE__ */ jsx9(
|
|
3382
3845
|
"input",
|
|
3383
3846
|
{
|
|
3384
3847
|
type: "number",
|
|
@@ -3389,14 +3852,14 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3389
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"
|
|
3390
3853
|
}
|
|
3391
3854
|
),
|
|
3392
|
-
/* @__PURE__ */
|
|
3855
|
+
/* @__PURE__ */ jsx9("p", { className: "mt-1 text-xs text-muted-foreground", children: "Lower runs first" })
|
|
3393
3856
|
] }),
|
|
3394
|
-
/* @__PURE__ */
|
|
3395
|
-
/* @__PURE__ */
|
|
3396
|
-
/* @__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" }),
|
|
3397
3860
|
"Timeout (seconds)"
|
|
3398
3861
|
] }),
|
|
3399
|
-
/* @__PURE__ */
|
|
3862
|
+
/* @__PURE__ */ jsx9(
|
|
3400
3863
|
"input",
|
|
3401
3864
|
{
|
|
3402
3865
|
type: "number",
|
|
@@ -3409,13 +3872,13 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3409
3872
|
)
|
|
3410
3873
|
] })
|
|
3411
3874
|
] }),
|
|
3412
|
-
/* @__PURE__ */
|
|
3413
|
-
/* @__PURE__ */
|
|
3414
|
-
/* @__PURE__ */
|
|
3415
|
-
/* @__PURE__ */
|
|
3416
|
-
/* @__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" })
|
|
3417
3880
|
] }),
|
|
3418
|
-
/* @__PURE__ */
|
|
3881
|
+
/* @__PURE__ */ jsx9(
|
|
3419
3882
|
"button",
|
|
3420
3883
|
{
|
|
3421
3884
|
type: "button",
|
|
@@ -3424,7 +3887,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3424
3887
|
"relative h-6 w-11 rounded-full transition-colors",
|
|
3425
3888
|
formData.continueOnFailure ? "bg-primary" : "bg-border"
|
|
3426
3889
|
),
|
|
3427
|
-
children: /* @__PURE__ */
|
|
3890
|
+
children: /* @__PURE__ */ jsx9(
|
|
3428
3891
|
"span",
|
|
3429
3892
|
{
|
|
3430
3893
|
className: cn(
|
|
@@ -3436,12 +3899,12 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3436
3899
|
}
|
|
3437
3900
|
)
|
|
3438
3901
|
] }),
|
|
3439
|
-
/* @__PURE__ */
|
|
3440
|
-
/* @__PURE__ */
|
|
3441
|
-
/* @__PURE__ */
|
|
3442
|
-
/* @__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" })
|
|
3443
3906
|
] }),
|
|
3444
|
-
/* @__PURE__ */
|
|
3907
|
+
/* @__PURE__ */ jsx9(
|
|
3445
3908
|
"button",
|
|
3446
3909
|
{
|
|
3447
3910
|
type: "button",
|
|
@@ -3450,7 +3913,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3450
3913
|
"relative h-6 w-11 rounded-full transition-colors",
|
|
3451
3914
|
formData.runAsRoot ? "bg-primary" : "bg-border"
|
|
3452
3915
|
),
|
|
3453
|
-
children: /* @__PURE__ */
|
|
3916
|
+
children: /* @__PURE__ */ jsx9(
|
|
3454
3917
|
"span",
|
|
3455
3918
|
{
|
|
3456
3919
|
className: cn(
|
|
@@ -3465,26 +3928,26 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3465
3928
|
] })
|
|
3466
3929
|
] })
|
|
3467
3930
|
] }),
|
|
3468
|
-
formError && /* @__PURE__ */
|
|
3469
|
-
/* @__PURE__ */
|
|
3470
|
-
/* @__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 })
|
|
3471
3934
|
] })
|
|
3472
3935
|
] }),
|
|
3473
|
-
/* @__PURE__ */
|
|
3474
|
-
/* @__PURE__ */
|
|
3936
|
+
/* @__PURE__ */ jsxs9(DialogFooter4, { className: "flex items-center justify-between sm:justify-between", children: [
|
|
3937
|
+
/* @__PURE__ */ jsx9("div", { children: !editingScript && /* @__PURE__ */ jsxs9(
|
|
3475
3938
|
"button",
|
|
3476
3939
|
{
|
|
3477
3940
|
type: "button",
|
|
3478
3941
|
onClick: () => goToStep("picker"),
|
|
3479
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",
|
|
3480
3943
|
children: [
|
|
3481
|
-
/* @__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" }) }),
|
|
3482
3945
|
"Back"
|
|
3483
3946
|
]
|
|
3484
3947
|
}
|
|
3485
3948
|
) }),
|
|
3486
|
-
/* @__PURE__ */
|
|
3487
|
-
/* @__PURE__ */
|
|
3949
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
3950
|
+
/* @__PURE__ */ jsx9(
|
|
3488
3951
|
"button",
|
|
3489
3952
|
{
|
|
3490
3953
|
type: "button",
|
|
@@ -3493,7 +3956,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3493
3956
|
children: "Cancel"
|
|
3494
3957
|
}
|
|
3495
3958
|
),
|
|
3496
|
-
/* @__PURE__ */
|
|
3959
|
+
/* @__PURE__ */ jsx9(
|
|
3497
3960
|
"button",
|
|
3498
3961
|
{
|
|
3499
3962
|
type: "button",
|
|
@@ -3510,17 +3973,17 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3510
3973
|
`form-${stepKey}`
|
|
3511
3974
|
)
|
|
3512
3975
|
] }) }),
|
|
3513
|
-
/* @__PURE__ */
|
|
3514
|
-
/* @__PURE__ */
|
|
3515
|
-
/* @__PURE__ */
|
|
3516
|
-
/* @__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: [
|
|
3517
3980
|
"Are you sure you want to delete \u201C",
|
|
3518
3981
|
deleteTarget?.name,
|
|
3519
3982
|
"\u201D? This action cannot be undone."
|
|
3520
3983
|
] })
|
|
3521
3984
|
] }),
|
|
3522
|
-
/* @__PURE__ */
|
|
3523
|
-
/* @__PURE__ */
|
|
3985
|
+
/* @__PURE__ */ jsxs9(DialogFooter4, { children: [
|
|
3986
|
+
/* @__PURE__ */ jsx9(
|
|
3524
3987
|
"button",
|
|
3525
3988
|
{
|
|
3526
3989
|
type: "button",
|
|
@@ -3529,7 +3992,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3529
3992
|
children: "Cancel"
|
|
3530
3993
|
}
|
|
3531
3994
|
),
|
|
3532
|
-
/* @__PURE__ */
|
|
3995
|
+
/* @__PURE__ */ jsx9(
|
|
3533
3996
|
"button",
|
|
3534
3997
|
{
|
|
3535
3998
|
type: "button",
|
|
@@ -3541,20 +4004,20 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3541
4004
|
)
|
|
3542
4005
|
] })
|
|
3543
4006
|
] }) }),
|
|
3544
|
-
/* @__PURE__ */
|
|
3545
|
-
/* @__PURE__ */
|
|
3546
|
-
/* @__PURE__ */
|
|
3547
|
-
/* @__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: [
|
|
3548
4011
|
scripts.length,
|
|
3549
4012
|
" script",
|
|
3550
4013
|
scripts.length !== 1 ? "s" : ""
|
|
3551
4014
|
] })
|
|
3552
4015
|
] }),
|
|
3553
|
-
loading ? /* @__PURE__ */
|
|
3554
|
-
/* @__PURE__ */
|
|
3555
|
-
/* @__PURE__ */
|
|
3556
|
-
/* @__PURE__ */
|
|
3557
|
-
/* @__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(
|
|
3558
4021
|
"button",
|
|
3559
4022
|
{
|
|
3560
4023
|
type: "button",
|
|
@@ -3562,12 +4025,12 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3562
4025
|
"aria-label": "Create your first startup script",
|
|
3563
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)]",
|
|
3564
4027
|
children: [
|
|
3565
|
-
/* @__PURE__ */
|
|
4028
|
+
/* @__PURE__ */ jsx9(Plus4, { className: "h-4 w-4" }),
|
|
3566
4029
|
"New Script"
|
|
3567
4030
|
]
|
|
3568
4031
|
}
|
|
3569
4032
|
)
|
|
3570
|
-
] }) : /* @__PURE__ */
|
|
4033
|
+
] }) : /* @__PURE__ */ jsx9("div", { className: "divide-y divide-border", children: scripts.map((script) => /* @__PURE__ */ jsxs9(
|
|
3571
4034
|
"div",
|
|
3572
4035
|
{
|
|
3573
4036
|
className: cn(
|
|
@@ -3575,7 +4038,7 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3575
4038
|
!script.enabled && "opacity-60"
|
|
3576
4039
|
),
|
|
3577
4040
|
children: [
|
|
3578
|
-
/* @__PURE__ */
|
|
4041
|
+
/* @__PURE__ */ jsx9(
|
|
3579
4042
|
"button",
|
|
3580
4043
|
{
|
|
3581
4044
|
type: "button",
|
|
@@ -3585,53 +4048,53 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3585
4048
|
"flex h-8 w-8 shrink-0 items-center justify-center rounded-full transition-colors",
|
|
3586
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"
|
|
3587
4050
|
),
|
|
3588
|
-
children: script.enabled ? /* @__PURE__ */
|
|
4051
|
+
children: script.enabled ? /* @__PURE__ */ jsx9(Power, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx9(PowerOff, { className: "h-4 w-4" })
|
|
3589
4052
|
}
|
|
3590
4053
|
),
|
|
3591
|
-
/* @__PURE__ */
|
|
3592
|
-
/* @__PURE__ */
|
|
3593
|
-
/* @__PURE__ */
|
|
3594
|
-
/* @__PURE__ */
|
|
3595
|
-
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: [
|
|
3596
4059
|
"#",
|
|
3597
4060
|
script.runOrder
|
|
3598
4061
|
] })
|
|
3599
4062
|
] }),
|
|
3600
|
-
script.description && /* @__PURE__ */
|
|
3601
|
-
/* @__PURE__ */
|
|
3602
|
-
script.environments.map((env) => /* @__PURE__ */
|
|
3603
|
-
script.injectSecrets.map((s) => /* @__PURE__ */
|
|
3604
|
-
/* @__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" }),
|
|
3605
4068
|
s
|
|
3606
4069
|
] }, s)),
|
|
3607
|
-
script.continueOnFailure && /* @__PURE__ */
|
|
3608
|
-
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" })
|
|
3609
4072
|
] })
|
|
3610
4073
|
] }),
|
|
3611
|
-
/* @__PURE__ */
|
|
3612
|
-
/* @__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" }),
|
|
3613
4076
|
script.timeoutSeconds,
|
|
3614
4077
|
"s"
|
|
3615
4078
|
] }),
|
|
3616
|
-
/* @__PURE__ */
|
|
3617
|
-
/* @__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(
|
|
3618
4081
|
"button",
|
|
3619
4082
|
{
|
|
3620
4083
|
type: "button",
|
|
3621
4084
|
onClick: () => openEdit(script),
|
|
3622
4085
|
className: "rounded-md p-2 text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
|
|
3623
4086
|
"aria-label": `Edit ${script.name}`,
|
|
3624
|
-
children: /* @__PURE__ */
|
|
4087
|
+
children: /* @__PURE__ */ jsx9(Pencil, { className: "h-4 w-4" })
|
|
3625
4088
|
}
|
|
3626
4089
|
),
|
|
3627
|
-
/* @__PURE__ */
|
|
4090
|
+
/* @__PURE__ */ jsx9(
|
|
3628
4091
|
"button",
|
|
3629
4092
|
{
|
|
3630
4093
|
type: "button",
|
|
3631
4094
|
onClick: () => setDeleteTarget(script),
|
|
3632
4095
|
className: "rounded-md p-2 text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-colors",
|
|
3633
4096
|
"aria-label": `Delete ${script.name}`,
|
|
3634
|
-
children: /* @__PURE__ */
|
|
4097
|
+
children: /* @__PURE__ */ jsx9(Trash24, { className: "h-4 w-4" })
|
|
3635
4098
|
}
|
|
3636
4099
|
)
|
|
3637
4100
|
] })
|
|
@@ -3640,20 +4103,20 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
3640
4103
|
script.id
|
|
3641
4104
|
)) })
|
|
3642
4105
|
] }),
|
|
3643
|
-
/* @__PURE__ */
|
|
3644
|
-
/* @__PURE__ */
|
|
3645
|
-
/* @__PURE__ */
|
|
3646
|
-
/* @__PURE__ */
|
|
3647
|
-
/* @__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" })
|
|
3648
4111
|
] }),
|
|
3649
|
-
/* @__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.' })
|
|
3650
4113
|
] }),
|
|
3651
|
-
/* @__PURE__ */
|
|
3652
|
-
/* @__PURE__ */
|
|
3653
|
-
/* @__PURE__ */
|
|
3654
|
-
/* @__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" })
|
|
3655
4118
|
] }),
|
|
3656
|
-
/* @__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." })
|
|
3657
4120
|
] })
|
|
3658
4121
|
] })
|
|
3659
4122
|
] });
|