@tangle-network/sandbox-ui 0.10.2 → 0.10.4
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-2XCOGNZP.js → chunk-XQF6LQDV.js} +180 -121
- package/dist/dashboard.d.ts +1 -1
- package/dist/dashboard.js +3 -1
- package/dist/globals.css +16 -20
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -1
- package/dist/pages.d.ts +38 -2
- package/dist/pages.js +668 -250
- package/dist/styles.css +16 -20
- package/dist/{variant-list-BNwUOSgz.d.ts → variant-list-DHP2OXFE.d.ts} +21 -5
- package/package.json +1 -1
package/dist/pages.js
CHANGED
|
@@ -298,16 +298,65 @@ function BillingPage({
|
|
|
298
298
|
|
|
299
299
|
// src/pages/provisioning-wizard.tsx
|
|
300
300
|
import * as React2 from "react";
|
|
301
|
-
import {
|
|
301
|
+
import {
|
|
302
|
+
ArrowLeft,
|
|
303
|
+
Layers,
|
|
304
|
+
Cpu,
|
|
305
|
+
Bot,
|
|
306
|
+
Info,
|
|
307
|
+
Loader2,
|
|
308
|
+
Settings,
|
|
309
|
+
Plus,
|
|
310
|
+
Trash2,
|
|
311
|
+
Check
|
|
312
|
+
} from "lucide-react";
|
|
302
313
|
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
303
|
-
var VALID_DRIVERS = /* @__PURE__ */ new Set([
|
|
314
|
+
var VALID_DRIVERS = /* @__PURE__ */ new Set([
|
|
315
|
+
"docker",
|
|
316
|
+
"firecracker",
|
|
317
|
+
"tangle"
|
|
318
|
+
]);
|
|
319
|
+
var DEFAULT_MODEL_OPTIONS = [
|
|
320
|
+
{ value: "claude-sonnet", label: "Claude Sonnet 4.6 (Highly Capable)" }
|
|
321
|
+
];
|
|
322
|
+
var DEFAULT_MODEL_TIER = DEFAULT_MODEL_OPTIONS[0]?.value ?? "claude-sonnet";
|
|
304
323
|
var STACK_DISPLAY = {
|
|
305
|
-
universal: {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
324
|
+
universal: {
|
|
325
|
+
name: "Default",
|
|
326
|
+
abbr: "D",
|
|
327
|
+
color: "violet",
|
|
328
|
+
textClass: "text-[var(--surface-violet-text)]"
|
|
329
|
+
},
|
|
330
|
+
ethereum: {
|
|
331
|
+
name: "Ethereum",
|
|
332
|
+
abbr: "\u039E",
|
|
333
|
+
color: "blue",
|
|
334
|
+
textClass: "text-[var(--surface-info-text)]"
|
|
335
|
+
},
|
|
336
|
+
solana: {
|
|
337
|
+
name: "Solana",
|
|
338
|
+
abbr: "S",
|
|
339
|
+
color: "green",
|
|
340
|
+
textClass: "text-[var(--surface-success-text)]"
|
|
341
|
+
},
|
|
342
|
+
tangle: {
|
|
343
|
+
name: "Tangle",
|
|
344
|
+
abbr: "T",
|
|
345
|
+
color: "purple",
|
|
346
|
+
textClass: "text-[var(--surface-violet-text)]"
|
|
347
|
+
},
|
|
348
|
+
"ai-sdk": {
|
|
349
|
+
name: "AI SDK",
|
|
350
|
+
abbr: "AI",
|
|
351
|
+
color: "teal",
|
|
352
|
+
textClass: "text-[var(--surface-teal-text)]"
|
|
353
|
+
},
|
|
354
|
+
rust: {
|
|
355
|
+
name: "Rust",
|
|
356
|
+
abbr: "Rs",
|
|
357
|
+
color: "orange",
|
|
358
|
+
textClass: "text-[var(--surface-orange-text)]"
|
|
359
|
+
}
|
|
311
360
|
};
|
|
312
361
|
function resolveEnvironment(env) {
|
|
313
362
|
if (env.id.startsWith("template:")) {
|
|
@@ -334,9 +383,27 @@ function resolveEnvironment(env) {
|
|
|
334
383
|
};
|
|
335
384
|
}
|
|
336
385
|
var defaultEnvironments = [
|
|
337
|
-
{
|
|
338
|
-
|
|
339
|
-
|
|
386
|
+
{
|
|
387
|
+
id: "node",
|
|
388
|
+
name: "Node.js",
|
|
389
|
+
description: "v20.x LTS with optimized runtime for asynchronous event-driven agents.",
|
|
390
|
+
icon: /* @__PURE__ */ jsx2("span", { className: "text-[var(--code-success)] text-2xl font-bold", children: "N" }),
|
|
391
|
+
color: "green"
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
id: "python",
|
|
395
|
+
name: "Python",
|
|
396
|
+
description: "v3.11 pre-installed with PyTorch and common data science libraries.",
|
|
397
|
+
icon: /* @__PURE__ */ jsx2("span", { className: "text-sky-400 text-2xl font-bold", children: "Py" }),
|
|
398
|
+
color: "blue"
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
id: "ubuntu",
|
|
402
|
+
name: "Ubuntu",
|
|
403
|
+
description: "Full 22.04 LTS terminal access for custom containerized workloads.",
|
|
404
|
+
icon: /* @__PURE__ */ jsx2("span", { className: "text-orange-400 text-2xl font-bold", children: "U" }),
|
|
405
|
+
color: "orange"
|
|
406
|
+
}
|
|
340
407
|
];
|
|
341
408
|
var CPU_MIN = 0.5;
|
|
342
409
|
var CPU_MAX = 8;
|
|
@@ -344,9 +411,35 @@ var RAM_MIN = 2;
|
|
|
344
411
|
var RAM_MAX = 32;
|
|
345
412
|
var STORAGE_MIN = 20;
|
|
346
413
|
var STORAGE_MAX = 512;
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
414
|
+
var DEFAULT_PRICING_RATES = {
|
|
415
|
+
cpuPerHr: 0.045,
|
|
416
|
+
ramPerGbHr: 5e-3,
|
|
417
|
+
diskPerGbHr: 11e-4,
|
|
418
|
+
minChargePerHr: void 0
|
|
419
|
+
};
|
|
420
|
+
function formatPerSecondValue(hourlyValue) {
|
|
421
|
+
return (hourlyValue / 3600).toFixed(8);
|
|
422
|
+
}
|
|
423
|
+
var RAW_PRESETS = [
|
|
424
|
+
{ name: "Lightweight", cpu: 2, ram: 4, storage: 50 },
|
|
425
|
+
{ name: "Standard", cpu: 4, ram: 16, storage: 128 },
|
|
426
|
+
{ name: "Performance", cpu: 8, ram: 32, storage: 256 }
|
|
427
|
+
];
|
|
428
|
+
function computeHourlyCost(cpu, ram, storage, rates) {
|
|
429
|
+
const compute = cpu * rates.cpuPerHr;
|
|
430
|
+
const memory = ram * rates.ramPerGbHr;
|
|
431
|
+
const storageCost = storage * rates.diskPerGbHr;
|
|
432
|
+
const lineSum = compute + memory + storageCost;
|
|
433
|
+
const floor = rates.minChargePerHr ?? 0;
|
|
434
|
+
return {
|
|
435
|
+
compute,
|
|
436
|
+
memory,
|
|
437
|
+
storage: storageCost,
|
|
438
|
+
lineSum,
|
|
439
|
+
floor,
|
|
440
|
+
floorApplies: floor > lineSum,
|
|
441
|
+
total: Math.max(floor, lineSum)
|
|
442
|
+
};
|
|
350
443
|
}
|
|
351
444
|
function ProvisioningWizard({
|
|
352
445
|
environments: environmentsProp,
|
|
@@ -359,13 +452,27 @@ function ProvisioningWizard({
|
|
|
359
452
|
defaultConfig,
|
|
360
453
|
skipToReview,
|
|
361
454
|
onLoadStartupScripts,
|
|
362
|
-
resourceLimits
|
|
455
|
+
resourceLimits,
|
|
456
|
+
modelOptions,
|
|
457
|
+
pricingRates,
|
|
458
|
+
planTiers
|
|
363
459
|
}) {
|
|
364
|
-
const cpuMax = Math.max(
|
|
365
|
-
|
|
366
|
-
|
|
460
|
+
const cpuMax = Math.max(
|
|
461
|
+
CPU_MIN,
|
|
462
|
+
Math.min(resourceLimits?.cpuMax ?? CPU_MAX, CPU_MAX)
|
|
463
|
+
);
|
|
464
|
+
const ramMax = Math.max(
|
|
465
|
+
RAM_MIN,
|
|
466
|
+
Math.min(resourceLimits?.ramMaxGB ?? RAM_MAX, RAM_MAX)
|
|
467
|
+
);
|
|
468
|
+
const storageMax = Math.max(
|
|
469
|
+
STORAGE_MIN,
|
|
470
|
+
Math.min(resourceLimits?.storageMaxGB ?? STORAGE_MAX, STORAGE_MAX)
|
|
471
|
+
);
|
|
367
472
|
const dc = defaultConfig;
|
|
368
|
-
const [envList, setEnvList] = React2.useState(
|
|
473
|
+
const [envList, setEnvList] = React2.useState(
|
|
474
|
+
environmentsProp ?? defaultEnvironments
|
|
475
|
+
);
|
|
369
476
|
const onLoadEnvironmentsRef = React2.useRef(onLoadEnvironments);
|
|
370
477
|
onLoadEnvironmentsRef.current = onLoadEnvironments;
|
|
371
478
|
React2.useEffect(() => {
|
|
@@ -374,7 +481,10 @@ function ProvisioningWizard({
|
|
|
374
481
|
onLoadEnvironmentsRef.current().then((entries) => {
|
|
375
482
|
if (!cancelled) setEnvList(entries.map(resolveEnvironment));
|
|
376
483
|
}).catch((err) => {
|
|
377
|
-
if (!cancelled)
|
|
484
|
+
if (!cancelled)
|
|
485
|
+
setLoadError(
|
|
486
|
+
err instanceof Error ? err.message : "Failed to load environments"
|
|
487
|
+
);
|
|
378
488
|
});
|
|
379
489
|
} else if (environmentsProp) {
|
|
380
490
|
setEnvList(environmentsProp);
|
|
@@ -385,30 +495,54 @@ function ProvisioningWizard({
|
|
|
385
495
|
}, [environmentsProp]);
|
|
386
496
|
const environments = envList;
|
|
387
497
|
const effectiveDefault = dc?.environment ?? defaultEnvironment;
|
|
388
|
-
const [selectedEnv, setSelectedEnv] = React2.useState(
|
|
498
|
+
const [selectedEnv, setSelectedEnv] = React2.useState(
|
|
499
|
+
effectiveDefault ?? environments[0]?.id ?? ""
|
|
500
|
+
);
|
|
389
501
|
React2.useEffect(() => {
|
|
390
502
|
if (effectiveDefault && envList.some((e) => e.id === effectiveDefault)) {
|
|
391
503
|
setSelectedEnv(effectiveDefault);
|
|
392
504
|
}
|
|
393
505
|
}, [envList, effectiveDefault]);
|
|
394
|
-
const [cpuCores, setCpuCores] = React2.useState(
|
|
506
|
+
const [cpuCores, setCpuCores] = React2.useState(
|
|
507
|
+
Math.min(dc?.cpuCores ?? 4, cpuMax)
|
|
508
|
+
);
|
|
395
509
|
const [ramGB, setRamGB] = React2.useState(Math.min(dc?.ramGB ?? 16, ramMax));
|
|
396
|
-
const [storageGB, setStorageGB] = React2.useState(
|
|
510
|
+
const [storageGB, setStorageGB] = React2.useState(
|
|
511
|
+
Math.min(dc?.storageGB ?? 128, storageMax)
|
|
512
|
+
);
|
|
397
513
|
React2.useEffect(() => {
|
|
398
514
|
setCpuCores((prev) => Math.min(prev, cpuMax));
|
|
399
515
|
setRamGB((prev) => Math.min(prev, ramMax));
|
|
400
516
|
setStorageGB((prev) => Math.min(prev, storageMax));
|
|
401
517
|
}, [cpuMax, ramMax, storageMax]);
|
|
402
|
-
const [modelTier, setModelTier] = React2.useState(
|
|
403
|
-
|
|
518
|
+
const [modelTier, setModelTier] = React2.useState(
|
|
519
|
+
dc?.modelTier ?? DEFAULT_MODEL_TIER
|
|
520
|
+
);
|
|
521
|
+
const [systemPrompt, setSystemPrompt] = React2.useState(
|
|
522
|
+
dc?.systemPrompt ?? ""
|
|
523
|
+
);
|
|
524
|
+
React2.useEffect(() => {
|
|
525
|
+
const options = modelOptions ?? DEFAULT_MODEL_OPTIONS;
|
|
526
|
+
if (options.length === 0) return;
|
|
527
|
+
const currentOption = options.find((o) => o.value === modelTier);
|
|
528
|
+
if (!currentOption || currentOption.disabled) {
|
|
529
|
+
const firstAvailable = options.find((o) => !o.disabled);
|
|
530
|
+
if (firstAvailable && firstAvailable.value !== modelTier) {
|
|
531
|
+
setModelTier(firstAvailable.value);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}, [modelOptions, modelTier]);
|
|
404
535
|
const [name, setName] = React2.useState(dc?.name ?? "");
|
|
405
536
|
const [gitUrl, setGitUrl] = React2.useState(dc?.gitUrl ?? "");
|
|
406
537
|
const [envVars, setEnvVars] = React2.useState(dc?.envVars ?? [{ key: "", value: "" }]);
|
|
407
538
|
const [driver, setDriver] = React2.useState(dc?.driver ?? "docker");
|
|
408
539
|
const [bare, setBare] = React2.useState(dc?.bare ?? false);
|
|
409
|
-
const [startupScriptIds, setStartupScriptIds] = React2.useState(
|
|
540
|
+
const [startupScriptIds, setStartupScriptIds] = React2.useState(
|
|
541
|
+
dc?.startupScriptIds ?? []
|
|
542
|
+
);
|
|
410
543
|
const [availableScripts, setAvailableScripts] = React2.useState([]);
|
|
411
544
|
const [activePreset, setActivePreset] = React2.useState(null);
|
|
545
|
+
const [pricingView, setPricingView] = React2.useState("hourly");
|
|
412
546
|
const [showAdvanced, setShowAdvanced] = React2.useState(false);
|
|
413
547
|
const [loadError, setLoadError] = React2.useState(null);
|
|
414
548
|
const onLoadStartupScriptsRef = React2.useRef(onLoadStartupScripts);
|
|
@@ -419,7 +553,10 @@ function ProvisioningWizard({
|
|
|
419
553
|
onLoadStartupScriptsRef.current().then((scripts) => {
|
|
420
554
|
if (!cancelled) setAvailableScripts(scripts);
|
|
421
555
|
}).catch((err) => {
|
|
422
|
-
if (!cancelled)
|
|
556
|
+
if (!cancelled)
|
|
557
|
+
setLoadError(
|
|
558
|
+
err instanceof Error ? err.message : "Failed to load startup scripts"
|
|
559
|
+
);
|
|
423
560
|
});
|
|
424
561
|
}
|
|
425
562
|
return () => {
|
|
@@ -427,7 +564,9 @@ function ProvisioningWizard({
|
|
|
427
564
|
};
|
|
428
565
|
}, []);
|
|
429
566
|
const isMultistep = variant === "multistep";
|
|
430
|
-
const [currentStep, setCurrentStep] = React2.useState(
|
|
567
|
+
const [currentStep, setCurrentStep] = React2.useState(
|
|
568
|
+
skipToReview && dc && isMultistep ? 3 : 1
|
|
569
|
+
);
|
|
431
570
|
const [isDeploying, setIsDeploying] = React2.useState(false);
|
|
432
571
|
const [deployError, setDeployError] = React2.useState(null);
|
|
433
572
|
const handleDeploy = async () => {
|
|
@@ -435,8 +574,25 @@ function ProvisioningWizard({
|
|
|
435
574
|
setIsDeploying(true);
|
|
436
575
|
setDeployError(null);
|
|
437
576
|
try {
|
|
438
|
-
const validScriptIds = new Set(
|
|
439
|
-
|
|
577
|
+
const validScriptIds = new Set(
|
|
578
|
+
availableScripts.filter((s) => s.enabled).map((s) => s.id)
|
|
579
|
+
);
|
|
580
|
+
await onSubmit({
|
|
581
|
+
environment: selectedEnv,
|
|
582
|
+
cpuCores,
|
|
583
|
+
ramGB,
|
|
584
|
+
storageGB,
|
|
585
|
+
modelTier,
|
|
586
|
+
systemPrompt,
|
|
587
|
+
name,
|
|
588
|
+
gitUrl,
|
|
589
|
+
envVars: envVars.filter((e) => e.key.trim() !== ""),
|
|
590
|
+
driver,
|
|
591
|
+
bare,
|
|
592
|
+
startupScriptIds: startupScriptIds.filter(
|
|
593
|
+
(id) => validScriptIds.has(id)
|
|
594
|
+
)
|
|
595
|
+
});
|
|
440
596
|
} catch (err) {
|
|
441
597
|
setDeployError(err instanceof Error ? err.message : "Deployment failed");
|
|
442
598
|
} finally {
|
|
@@ -449,15 +605,73 @@ function ProvisioningWizard({
|
|
|
449
605
|
setStorageGB(Math.min(storage, storageMax));
|
|
450
606
|
setActivePreset(name2);
|
|
451
607
|
};
|
|
452
|
-
const presets =
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
608
|
+
const presets = RAW_PRESETS.map((p) => {
|
|
609
|
+
const locked = p.cpu > cpuMax || p.ram > ramMax || p.storage > storageMax;
|
|
610
|
+
let unlockLabel;
|
|
611
|
+
if (locked && planTiers && planTiers.length > 0) {
|
|
612
|
+
const unlocking = planTiers.find(
|
|
613
|
+
(t) => p.cpu <= t.cpuMax && p.ram <= t.ramMaxGB && p.storage <= t.storageMaxGB
|
|
614
|
+
);
|
|
615
|
+
unlockLabel = unlocking?.label;
|
|
616
|
+
}
|
|
617
|
+
return {
|
|
618
|
+
...p,
|
|
619
|
+
fits: !locked,
|
|
620
|
+
locked,
|
|
621
|
+
unlockLabel: unlockLabel ?? "Pro"
|
|
622
|
+
};
|
|
623
|
+
});
|
|
624
|
+
const didInitPresetFromDcRef = React2.useRef(false);
|
|
625
|
+
const lastLimitsRef = React2.useRef(null);
|
|
626
|
+
React2.useEffect(() => {
|
|
627
|
+
const limitsUnchanged = lastLimitsRef.current !== null && lastLimitsRef.current.cpu === cpuMax && lastLimitsRef.current.ram === ramMax && lastLimitsRef.current.storage === storageMax;
|
|
628
|
+
if (limitsUnchanged) return;
|
|
629
|
+
lastLimitsRef.current = { cpu: cpuMax, ram: ramMax, storage: storageMax };
|
|
630
|
+
if (dc && !didInitPresetFromDcRef.current) {
|
|
631
|
+
didInitPresetFromDcRef.current = true;
|
|
632
|
+
const matching = RAW_PRESETS.find(
|
|
633
|
+
(p) => p.cpu === dc.cpuCores && p.ram === dc.ramGB && p.storage === dc.storageGB
|
|
634
|
+
);
|
|
635
|
+
if (matching) setActivePreset(matching.name);
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
const largestFitting = [...RAW_PRESETS].reverse().find(
|
|
639
|
+
(p) => p.cpu <= cpuMax && p.ram <= ramMax && p.storage <= storageMax
|
|
640
|
+
);
|
|
641
|
+
if (largestFitting) {
|
|
642
|
+
applyPreset(
|
|
643
|
+
largestFitting.name,
|
|
644
|
+
largestFitting.cpu,
|
|
645
|
+
largestFitting.ram,
|
|
646
|
+
largestFitting.storage
|
|
647
|
+
);
|
|
648
|
+
} else {
|
|
649
|
+
setActivePreset(null);
|
|
650
|
+
}
|
|
651
|
+
}, [cpuMax, ramMax, storageMax, dc]);
|
|
652
|
+
const effectivePricingRates = pricingRates ?? DEFAULT_PRICING_RATES;
|
|
653
|
+
const hourlyCostBreakdown = computeHourlyCost(
|
|
654
|
+
cpuCores,
|
|
655
|
+
ramGB,
|
|
656
|
+
storageGB,
|
|
657
|
+
effectivePricingRates
|
|
658
|
+
);
|
|
659
|
+
const hourCost = hourlyCostBreakdown.total.toFixed(2);
|
|
660
|
+
const displayValue = pricingView === "hourly" ? hourCost : formatPerSecondValue(hourlyCostBreakdown.total);
|
|
661
|
+
const pricingSuffix = pricingView === "hourly" ? "/ hour" : "/ sec";
|
|
662
|
+
const rateSuffix = pricingView === "hourly" ? "/h" : "/s";
|
|
663
|
+
const fmtRate = (v) => pricingView === "hourly" ? v.toFixed(2) : formatPerSecondValue(v);
|
|
458
664
|
return /* @__PURE__ */ jsxs2("div", { className: cn("max-w-6xl mx-auto flex flex-col", className), children: [
|
|
459
665
|
/* @__PURE__ */ jsxs2("div", { className: "mb-6 flex items-center gap-4 shrink-0", children: [
|
|
460
|
-
onBack && /* @__PURE__ */ jsx2(
|
|
666
|
+
onBack && /* @__PURE__ */ jsx2(
|
|
667
|
+
"button",
|
|
668
|
+
{
|
|
669
|
+
type: "button",
|
|
670
|
+
onClick: onBack,
|
|
671
|
+
className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-border hover:bg-muted/50 transition-colors text-foreground",
|
|
672
|
+
children: /* @__PURE__ */ jsx2(ArrowLeft, { className: "h-5 w-5" })
|
|
673
|
+
}
|
|
674
|
+
),
|
|
461
675
|
/* @__PURE__ */ jsxs2("div", { children: [
|
|
462
676
|
/* @__PURE__ */ jsx2("h1", { className: "text-3xl font-extrabold tracking-tight text-foreground mb-1", children: "Sandbox Provisioning" }),
|
|
463
677
|
/* @__PURE__ */ jsx2("p", { className: "text-muted-foreground text-sm", children: "Select your stack, allocate resources, and configure your agent." })
|
|
@@ -466,16 +680,39 @@ function ProvisioningWizard({
|
|
|
466
680
|
/* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-12 gap-6 flex-1 min-h-0", children: [
|
|
467
681
|
/* @__PURE__ */ jsxs2("div", { className: "col-span-12 xl:col-span-8 flex flex-col min-h-0", children: [
|
|
468
682
|
isMultistep && /* @__PURE__ */ jsx2("div", { className: "flex items-center gap-2 mb-4 bg-card border border-border p-3 rounded-2xl mx-auto max-w-2xl justify-between shrink-0", children: [1, 2, 3].map((s) => /* @__PURE__ */ jsxs2("div", { className: "flex items-center", children: [
|
|
469
|
-
/* @__PURE__ */ jsx2(
|
|
470
|
-
"
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
683
|
+
/* @__PURE__ */ jsx2(
|
|
684
|
+
"div",
|
|
685
|
+
{
|
|
686
|
+
className: cn(
|
|
687
|
+
"w-7 h-7 rounded-full flex items-center justify-center font-bold text-xs shrink-0 transition-all duration-200",
|
|
688
|
+
currentStep === s ? "bg-primary text-primary-foreground ring-2 ring-primary/30 ring-offset-2 ring-offset-card shadow-sm" : currentStep > s ? "bg-primary text-primary-foreground" : "bg-muted border border-border text-muted-foreground"
|
|
689
|
+
),
|
|
690
|
+
children: currentStep > s ? /* @__PURE__ */ jsx2(Check, { className: "h-3.5 w-3.5" }) : s
|
|
691
|
+
}
|
|
692
|
+
),
|
|
693
|
+
/* @__PURE__ */ jsxs2(
|
|
694
|
+
"span",
|
|
695
|
+
{
|
|
696
|
+
className: cn(
|
|
697
|
+
"ml-2 sm:ml-3 font-bold text-sm tracking-tight hidden sm:inline transition-colors duration-200",
|
|
698
|
+
currentStep === s ? "text-foreground" : currentStep > s ? "text-primary" : "text-muted-foreground"
|
|
699
|
+
),
|
|
700
|
+
children: [
|
|
701
|
+
s === 1 && "Environment",
|
|
702
|
+
s === 2 && "Resources",
|
|
703
|
+
s === 3 && "AI Agent"
|
|
704
|
+
]
|
|
705
|
+
}
|
|
706
|
+
),
|
|
707
|
+
s < 3 && /* @__PURE__ */ jsx2(
|
|
708
|
+
"div",
|
|
709
|
+
{
|
|
710
|
+
className: cn(
|
|
711
|
+
"w-4 sm:w-8 h-0.5 mx-2 sm:mx-4 rounded-full transition-colors duration-300",
|
|
712
|
+
currentStep > s ? "bg-primary" : "bg-border"
|
|
713
|
+
)
|
|
714
|
+
}
|
|
715
|
+
)
|
|
479
716
|
] }, s)) }),
|
|
480
717
|
dc && isMultistep && /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between bg-card border border-border rounded-2xl px-4 py-3 shrink-0", children: [
|
|
481
718
|
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 text-sm", children: [
|
|
@@ -492,7 +729,11 @@ function ProvisioningWizard({
|
|
|
492
729
|
setCpuCores(Math.min(4, cpuMax));
|
|
493
730
|
setRamGB(Math.min(16, ramMax));
|
|
494
731
|
setStorageGB(Math.min(128, storageMax));
|
|
495
|
-
|
|
732
|
+
const resetOptions = modelOptions ?? DEFAULT_MODEL_OPTIONS;
|
|
733
|
+
const firstAvailable = resetOptions.find(
|
|
734
|
+
(o) => !o.disabled
|
|
735
|
+
);
|
|
736
|
+
setModelTier(firstAvailable?.value ?? DEFAULT_MODEL_TIER);
|
|
496
737
|
setSystemPrompt("");
|
|
497
738
|
setName("");
|
|
498
739
|
setGitUrl("");
|
|
@@ -501,6 +742,7 @@ function ProvisioningWizard({
|
|
|
501
742
|
setBare(false);
|
|
502
743
|
setStartupScriptIds([]);
|
|
503
744
|
setActivePreset(null);
|
|
745
|
+
setPricingView("hourly");
|
|
504
746
|
},
|
|
505
747
|
className: "text-xs font-bold text-primary hover:text-primary/70 transition-colors",
|
|
506
748
|
children: "Start from scratch"
|
|
@@ -530,10 +772,16 @@ function ProvisioningWizard({
|
|
|
530
772
|
selectedEnv === env.id && /* @__PURE__ */ jsx2("div", { className: "absolute inset-0 bg-gradient-to-br from-primary/8 to-transparent pointer-events-none" }),
|
|
531
773
|
/* @__PURE__ */ jsxs2("div", { className: "flex justify-between items-start mb-3 relative z-10", children: [
|
|
532
774
|
/* @__PURE__ */ jsx2("div", { className: "w-10 h-10 rounded-full flex items-center justify-center bg-muted/50 border border-border shadow-inner", children: env.icon }),
|
|
533
|
-
/* @__PURE__ */ jsx2(
|
|
534
|
-
"
|
|
535
|
-
|
|
536
|
-
|
|
775
|
+
/* @__PURE__ */ jsx2(
|
|
776
|
+
"div",
|
|
777
|
+
{
|
|
778
|
+
className: cn(
|
|
779
|
+
"w-5 h-5 rounded-full border-2 flex items-center justify-center transition-all duration-200",
|
|
780
|
+
selectedEnv === env.id ? "border-primary bg-primary" : "border-border group-hover:border-primary/40"
|
|
781
|
+
),
|
|
782
|
+
children: selectedEnv === env.id && /* @__PURE__ */ jsx2(Check, { className: "h-3 w-3 text-primary-foreground animate-in zoom-in duration-200" })
|
|
783
|
+
}
|
|
784
|
+
)
|
|
537
785
|
] }),
|
|
538
786
|
/* @__PURE__ */ jsx2("h3", { className: "font-bold text-sm mb-0.5 text-foreground relative z-10", children: env.name }),
|
|
539
787
|
/* @__PURE__ */ jsx2("p", { className: "text-xs text-muted-foreground leading-relaxed relative z-10", children: env.description })
|
|
@@ -550,59 +798,110 @@ function ProvisioningWizard({
|
|
|
550
798
|
/* @__PURE__ */ jsxs2("div", { className: "mb-6", children: [
|
|
551
799
|
/* @__PURE__ */ jsx2("label", { className: "block font-label text-xs font-bold uppercase tracking-widest text-muted-foreground mb-3", children: "Compute Presets" }),
|
|
552
800
|
/* @__PURE__ */ jsx2("div", { className: "grid grid-cols-3 gap-3", children: presets.map((p) => {
|
|
553
|
-
const active = activePreset === p.name;
|
|
554
|
-
return /* @__PURE__ */ jsxs2(
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
p.
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
801
|
+
const active = activePreset === p.name && !p.locked;
|
|
802
|
+
return /* @__PURE__ */ jsxs2(
|
|
803
|
+
"button",
|
|
804
|
+
{
|
|
805
|
+
type: "button",
|
|
806
|
+
onClick: () => !p.locked && applyPreset(p.name, p.cpu, p.ram, p.storage),
|
|
807
|
+
disabled: p.locked,
|
|
808
|
+
className: cn(
|
|
809
|
+
"p-3 rounded-[14px] transition-all duration-200 text-center group border relative",
|
|
810
|
+
active ? "bg-primary/5 border-primary ring-1 ring-primary/20 shadow-sm" : p.locked ? "bg-muted/30 border-border opacity-60 cursor-not-allowed" : "bg-card border-border hover:border-primary/30 hover:shadow-sm active:scale-[0.97]"
|
|
811
|
+
),
|
|
812
|
+
children: [
|
|
813
|
+
p.locked && /* @__PURE__ */ jsx2("div", { className: "absolute -top-1.5 -right-1.5 bg-primary text-primary-foreground text-[9px] font-bold px-1.5 py-0.5 rounded-full uppercase tracking-wider", children: p.unlockLabel }),
|
|
814
|
+
/* @__PURE__ */ jsx2(
|
|
815
|
+
"div",
|
|
816
|
+
{
|
|
817
|
+
className: cn(
|
|
818
|
+
"font-bold text-sm transition-colors duration-200",
|
|
819
|
+
active ? "text-primary" : p.locked ? "text-muted-foreground" : "text-foreground"
|
|
820
|
+
),
|
|
821
|
+
children: p.name
|
|
822
|
+
}
|
|
823
|
+
),
|
|
824
|
+
/* @__PURE__ */ jsxs2("div", { className: "text-xs text-muted-foreground mt-0.5 font-mono", children: [
|
|
825
|
+
p.cpu,
|
|
826
|
+
" vCPU",
|
|
827
|
+
p.cpu === 1 ? "" : "s",
|
|
828
|
+
" / ",
|
|
829
|
+
p.ram,
|
|
830
|
+
"GB /",
|
|
831
|
+
" ",
|
|
832
|
+
p.storage,
|
|
833
|
+
"GB"
|
|
834
|
+
] })
|
|
835
|
+
]
|
|
836
|
+
},
|
|
837
|
+
p.name
|
|
838
|
+
);
|
|
565
839
|
}) })
|
|
566
840
|
] }),
|
|
567
841
|
/* @__PURE__ */ jsx2("div", { className: "space-y-6", children: [
|
|
568
|
-
{
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
842
|
+
{
|
|
843
|
+
label: "Compute Cores (CPU)",
|
|
844
|
+
value: cpuCores,
|
|
845
|
+
setter: setCpuCores,
|
|
846
|
+
min: CPU_MIN,
|
|
847
|
+
max: cpuMax,
|
|
848
|
+
step: 0.5,
|
|
849
|
+
unit: "vCPU"
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
label: "Memory (RAM)",
|
|
853
|
+
value: ramGB,
|
|
854
|
+
setter: setRamGB,
|
|
855
|
+
min: RAM_MIN,
|
|
856
|
+
max: ramMax,
|
|
857
|
+
step: 1,
|
|
858
|
+
unit: "GB"
|
|
859
|
+
},
|
|
860
|
+
{
|
|
861
|
+
label: "Ephemeral Storage",
|
|
862
|
+
value: storageGB,
|
|
863
|
+
setter: setStorageGB,
|
|
864
|
+
min: STORAGE_MIN,
|
|
865
|
+
max: storageMax,
|
|
866
|
+
step: 8,
|
|
867
|
+
unit: "GB"
|
|
868
|
+
}
|
|
869
|
+
].map(
|
|
870
|
+
({ label, value, setter, min, max, step: s, unit }) => {
|
|
871
|
+
const displayUnit = unit === "vCPU" ? `${value} vCPU${value === 1 ? "" : "s"}` : `${value}${unit}`;
|
|
872
|
+
return /* @__PURE__ */ jsxs2("div", { children: [
|
|
873
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex justify-between items-end border-b border-border pb-1.5 mb-2", children: [
|
|
874
|
+
/* @__PURE__ */ jsx2("label", { className: "font-label text-xs font-bold uppercase tracking-widest text-muted-foreground", children: label }),
|
|
875
|
+
/* @__PURE__ */ jsx2("span", { className: "text-xl font-bold text-foreground tracking-tight", children: displayUnit })
|
|
876
|
+
] }),
|
|
877
|
+
/* @__PURE__ */ jsx2(
|
|
878
|
+
"input",
|
|
879
|
+
{
|
|
880
|
+
type: "range",
|
|
881
|
+
min,
|
|
882
|
+
max,
|
|
883
|
+
step: s,
|
|
884
|
+
value,
|
|
885
|
+
onChange: (e) => {
|
|
886
|
+
setter(+e.target.value);
|
|
887
|
+
setActivePreset(null);
|
|
888
|
+
},
|
|
889
|
+
className: "w-full h-2 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-2 [&::-moz-range-track]:bg-border [&::-moz-range-track]:rounded-full [&::-moz-range-track]:h-2 [&::-webkit-slider-thumb]:bg-primary [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:-mt-[6px] [&::-webkit-slider-thumb]:shadow-md [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-primary-foreground [&::-webkit-slider-thumb]:transition-transform [&::-webkit-slider-thumb]:hover:scale-110"
|
|
890
|
+
}
|
|
891
|
+
),
|
|
892
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-[10px] font-mono text-muted-foreground/60 mt-1", children: [
|
|
893
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
894
|
+
min,
|
|
895
|
+
unit === "vCPU" ? min === 1 ? " vCPU" : " vCPUs" : unit
|
|
896
|
+
] }),
|
|
897
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
898
|
+
max,
|
|
899
|
+
unit === "vCPU" ? max === 1 ? " vCPU" : " vCPUs" : unit
|
|
900
|
+
] })
|
|
901
|
+
] })
|
|
902
|
+
] }, label);
|
|
903
|
+
}
|
|
904
|
+
) })
|
|
606
905
|
] }) }),
|
|
607
906
|
(!isMultistep || currentStep === 3) && /* @__PURE__ */ jsx2(React2.Fragment, { children: /* @__PURE__ */ jsxs2("section", { className: "bg-card border border-border rounded-[24px] p-6 shadow-2xl relative overflow-hidden animate-in fade-in slide-in-from-bottom-4 duration-300", children: [
|
|
608
907
|
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3 mb-5", children: [
|
|
@@ -612,19 +911,28 @@ function ProvisioningWizard({
|
|
|
612
911
|
/* @__PURE__ */ jsxs2("div", { className: "space-y-5", children: [
|
|
613
912
|
/* @__PURE__ */ jsxs2("div", { children: [
|
|
614
913
|
/* @__PURE__ */ jsx2("label", { className: "block font-label text-xs font-bold uppercase tracking-widest text-muted-foreground mb-2", children: "Model Engine" }),
|
|
615
|
-
/* @__PURE__ */
|
|
914
|
+
/* @__PURE__ */ jsx2(
|
|
616
915
|
"select",
|
|
617
916
|
{
|
|
618
917
|
value: modelTier,
|
|
619
918
|
onChange: (e) => setModelTier(e.target.value),
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
/* @__PURE__ */ jsx2(
|
|
624
|
-
|
|
625
|
-
|
|
919
|
+
disabled: modelOptions && modelOptions.filter((o) => !o.disabled).length === 0,
|
|
920
|
+
className: "w-full bg-card border border-border rounded-xl h-12 px-4 font-bold text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent appearance-none disabled:opacity-50 disabled:cursor-not-allowed",
|
|
921
|
+
children: (modelOptions ?? DEFAULT_MODEL_OPTIONS).map(
|
|
922
|
+
(option) => /* @__PURE__ */ jsx2(
|
|
923
|
+
"option",
|
|
924
|
+
{
|
|
925
|
+
value: option.value,
|
|
926
|
+
disabled: option.disabled,
|
|
927
|
+
className: "bg-gray-900",
|
|
928
|
+
children: option.label
|
|
929
|
+
},
|
|
930
|
+
option.value
|
|
931
|
+
)
|
|
932
|
+
)
|
|
626
933
|
}
|
|
627
|
-
)
|
|
934
|
+
),
|
|
935
|
+
modelOptions && modelOptions.length > 0 && modelOptions.every((o) => o.disabled) && /* @__PURE__ */ jsx2("p", { className: "text-xs text-muted-foreground mt-2", children: "All model options are currently disabled. Please upgrade your plan or contact support." })
|
|
628
936
|
] }),
|
|
629
937
|
/* @__PURE__ */ jsxs2("div", { children: [
|
|
630
938
|
/* @__PURE__ */ jsx2("label", { className: "block font-label text-xs font-bold uppercase tracking-widest text-muted-foreground mb-2", children: "Core Directives (System Prompt)" }),
|
|
@@ -675,12 +983,22 @@ function ProvisioningWizard({
|
|
|
675
983
|
{
|
|
676
984
|
value: driver,
|
|
677
985
|
onChange: (e) => {
|
|
678
|
-
if (VALID_DRIVERS.has(e.target.value))
|
|
986
|
+
if (VALID_DRIVERS.has(e.target.value))
|
|
987
|
+
setDriver(
|
|
988
|
+
e.target.value
|
|
989
|
+
);
|
|
679
990
|
},
|
|
680
991
|
className: "w-full bg-card border border-border rounded-xl h-12 px-4 font-bold text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent appearance-none",
|
|
681
992
|
children: [
|
|
682
993
|
/* @__PURE__ */ jsx2("option", { value: "docker", className: "bg-gray-900", children: "Docker container (Default)" }),
|
|
683
|
-
/* @__PURE__ */ jsx2(
|
|
994
|
+
/* @__PURE__ */ jsx2(
|
|
995
|
+
"option",
|
|
996
|
+
{
|
|
997
|
+
value: "firecracker",
|
|
998
|
+
className: "bg-gray-900",
|
|
999
|
+
children: "Firecracker microVM (Secure)"
|
|
1000
|
+
}
|
|
1001
|
+
),
|
|
684
1002
|
/* @__PURE__ */ jsx2("option", { value: "tangle", className: "bg-gray-900", children: "Tangle Distributed Node" })
|
|
685
1003
|
]
|
|
686
1004
|
}
|
|
@@ -703,10 +1021,21 @@ function ProvisioningWizard({
|
|
|
703
1021
|
/* @__PURE__ */ jsxs2("div", { children: [
|
|
704
1022
|
/* @__PURE__ */ jsxs2("div", { className: "flex justify-between items-center mb-2", children: [
|
|
705
1023
|
/* @__PURE__ */ jsx2("label", { className: "block font-label text-xs font-bold uppercase tracking-widest text-muted-foreground", children: "Environment Variables" }),
|
|
706
|
-
/* @__PURE__ */ jsxs2(
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
1024
|
+
/* @__PURE__ */ jsxs2(
|
|
1025
|
+
"button",
|
|
1026
|
+
{
|
|
1027
|
+
type: "button",
|
|
1028
|
+
onClick: () => setEnvVars([
|
|
1029
|
+
...envVars,
|
|
1030
|
+
{ key: "", value: "" }
|
|
1031
|
+
]),
|
|
1032
|
+
className: "flex items-center gap-1 text-xs text-primary hover:text-primary/70 transition-colors font-bold",
|
|
1033
|
+
children: [
|
|
1034
|
+
/* @__PURE__ */ jsx2(Plus, { className: "h-3 w-3" }),
|
|
1035
|
+
" Add Var"
|
|
1036
|
+
]
|
|
1037
|
+
}
|
|
1038
|
+
)
|
|
710
1039
|
] }),
|
|
711
1040
|
/* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
|
|
712
1041
|
envVars.map((env, i) => /* @__PURE__ */ jsxs2("div", { className: "flex gap-2", children: [
|
|
@@ -715,7 +1044,11 @@ function ProvisioningWizard({
|
|
|
715
1044
|
{
|
|
716
1045
|
type: "text",
|
|
717
1046
|
value: env.key,
|
|
718
|
-
onChange: (e) => setEnvVars(
|
|
1047
|
+
onChange: (e) => setEnvVars(
|
|
1048
|
+
envVars.map(
|
|
1049
|
+
(v, idx) => idx === i ? { ...v, key: e.target.value } : v
|
|
1050
|
+
)
|
|
1051
|
+
),
|
|
719
1052
|
className: "flex-1 bg-card border border-border rounded-xl h-10 px-3 font-mono text-sm text-foreground focus:outline-none focus:ring-1 focus:ring-primary placeholder:text-muted-foreground",
|
|
720
1053
|
placeholder: "API_KEY"
|
|
721
1054
|
}
|
|
@@ -725,12 +1058,26 @@ function ProvisioningWizard({
|
|
|
725
1058
|
{
|
|
726
1059
|
type: "password",
|
|
727
1060
|
value: env.value,
|
|
728
|
-
onChange: (e) => setEnvVars(
|
|
1061
|
+
onChange: (e) => setEnvVars(
|
|
1062
|
+
envVars.map(
|
|
1063
|
+
(v, idx) => idx === i ? { ...v, value: e.target.value } : v
|
|
1064
|
+
)
|
|
1065
|
+
),
|
|
729
1066
|
className: "flex-[2] bg-card border border-border rounded-xl h-10 px-3 font-mono text-sm text-foreground focus:outline-none focus:ring-1 focus:ring-primary placeholder:text-muted-foreground",
|
|
730
1067
|
placeholder: "sk-xxxxxxxxxxx"
|
|
731
1068
|
}
|
|
732
1069
|
),
|
|
733
|
-
/* @__PURE__ */ jsx2(
|
|
1070
|
+
/* @__PURE__ */ jsx2(
|
|
1071
|
+
"button",
|
|
1072
|
+
{
|
|
1073
|
+
type: "button",
|
|
1074
|
+
onClick: () => setEnvVars(
|
|
1075
|
+
envVars.filter((_, idx) => idx !== i)
|
|
1076
|
+
),
|
|
1077
|
+
className: "h-10 w-10 flex items-center justify-center shrink-0 rounded-xl bg-card border border-border text-red-400 hover:bg-red-500/10 hover:border-red-500/30 transition-colors",
|
|
1078
|
+
children: /* @__PURE__ */ jsx2(Trash2, { className: "h-4 w-4" })
|
|
1079
|
+
}
|
|
1080
|
+
)
|
|
734
1081
|
] }, i)),
|
|
735
1082
|
envVars.length === 0 && /* @__PURE__ */ jsx2("div", { className: "text-center p-3 bg-card border border-border rounded-xl text-muted-foreground/60 text-sm italic", children: "No environment variables set" })
|
|
736
1083
|
] })
|
|
@@ -738,36 +1085,82 @@ function ProvisioningWizard({
|
|
|
738
1085
|
availableScripts.length > 0 && /* @__PURE__ */ jsxs2("div", { children: [
|
|
739
1086
|
/* @__PURE__ */ jsx2("div", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground mb-2", children: "Startup Scripts" }),
|
|
740
1087
|
/* @__PURE__ */ jsx2("div", { className: "space-y-2", children: availableScripts.filter((s) => s.enabled).map((script) => {
|
|
741
|
-
const selected = startupScriptIds.includes(
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
1088
|
+
const selected = startupScriptIds.includes(
|
|
1089
|
+
script.id
|
|
1090
|
+
);
|
|
1091
|
+
return /* @__PURE__ */ jsxs2(
|
|
1092
|
+
"label",
|
|
1093
|
+
{
|
|
1094
|
+
className: "flex items-start gap-3 cursor-pointer group rounded-lg border border-border p-3 transition-colors hover:border-primary/30",
|
|
1095
|
+
children: [
|
|
1096
|
+
/* @__PURE__ */ jsx2(
|
|
1097
|
+
"input",
|
|
1098
|
+
{
|
|
1099
|
+
type: "checkbox",
|
|
1100
|
+
checked: selected,
|
|
1101
|
+
onChange: () => setStartupScriptIds(
|
|
1102
|
+
(prev) => selected ? prev.filter(
|
|
1103
|
+
(id) => id !== script.id
|
|
1104
|
+
) : [...prev, script.id]
|
|
1105
|
+
),
|
|
1106
|
+
className: "mt-0.5 h-4 w-4 rounded border-border text-primary focus:ring-primary/30"
|
|
1107
|
+
}
|
|
750
1108
|
),
|
|
751
|
-
className: "
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
1109
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex-1 min-w-0", children: [
|
|
1110
|
+
/* @__PURE__ */ jsx2("div", { className: "text-sm font-medium text-foreground group-hover:text-primary transition-colors", children: script.name }),
|
|
1111
|
+
script.description && /* @__PURE__ */ jsx2("div", { className: "text-xs text-muted-foreground mt-0.5", children: script.description }),
|
|
1112
|
+
script.injectSecrets.length > 0 && /* @__PURE__ */ jsx2("div", { className: "flex flex-wrap gap-1 mt-1.5", children: script.injectSecrets.map((s) => /* @__PURE__ */ jsxs2(
|
|
1113
|
+
"span",
|
|
1114
|
+
{
|
|
1115
|
+
className: "inline-flex items-center gap-0.5 rounded-full bg-muted px-2 py-0.5 text-[10px] text-muted-foreground",
|
|
1116
|
+
children: [
|
|
1117
|
+
/* @__PURE__ */ jsxs2(
|
|
1118
|
+
"svg",
|
|
1119
|
+
{
|
|
1120
|
+
className: "h-2.5 w-2.5",
|
|
1121
|
+
viewBox: "0 0 24 24",
|
|
1122
|
+
fill: "none",
|
|
1123
|
+
stroke: "currentColor",
|
|
1124
|
+
strokeWidth: "2",
|
|
1125
|
+
children: [
|
|
1126
|
+
/* @__PURE__ */ jsx2(
|
|
1127
|
+
"rect",
|
|
1128
|
+
{
|
|
1129
|
+
x: "3",
|
|
1130
|
+
y: "11",
|
|
1131
|
+
width: "18",
|
|
1132
|
+
height: "11",
|
|
1133
|
+
rx: "2",
|
|
1134
|
+
ry: "2"
|
|
1135
|
+
}
|
|
1136
|
+
),
|
|
1137
|
+
/* @__PURE__ */ jsx2("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })
|
|
1138
|
+
]
|
|
1139
|
+
}
|
|
1140
|
+
),
|
|
1141
|
+
s
|
|
1142
|
+
]
|
|
1143
|
+
},
|
|
1144
|
+
s
|
|
1145
|
+
)) })
|
|
1146
|
+
] })
|
|
1147
|
+
]
|
|
1148
|
+
},
|
|
1149
|
+
script.id
|
|
1150
|
+
);
|
|
766
1151
|
}) })
|
|
767
1152
|
] }),
|
|
768
1153
|
/* @__PURE__ */ jsx2("div", { className: "pt-2 border-t border-border", children: /* @__PURE__ */ jsxs2("label", { className: "flex items-center gap-3 cursor-pointer group", children: [
|
|
769
1154
|
/* @__PURE__ */ jsxs2("div", { className: "relative flex items-center justify-center shrink-0", children: [
|
|
770
|
-
/* @__PURE__ */ jsx2(
|
|
1155
|
+
/* @__PURE__ */ jsx2(
|
|
1156
|
+
"input",
|
|
1157
|
+
{
|
|
1158
|
+
type: "checkbox",
|
|
1159
|
+
className: "sr-only peer",
|
|
1160
|
+
checked: bare,
|
|
1161
|
+
onChange: (e) => setBare(e.target.checked)
|
|
1162
|
+
}
|
|
1163
|
+
),
|
|
771
1164
|
/* @__PURE__ */ jsx2("div", { className: "w-10 h-6 bg-muted peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary hover:bg-muted/80 transition-colors" })
|
|
772
1165
|
] }),
|
|
773
1166
|
/* @__PURE__ */ jsxs2("div", { children: [
|
|
@@ -782,93 +1175,97 @@ function ProvisioningWizard({
|
|
|
782
1175
|
] })
|
|
783
1176
|
] }),
|
|
784
1177
|
/* @__PURE__ */ jsxs2("div", { className: "col-span-12 xl:col-span-4 sticky top-4 space-y-4", children: [
|
|
785
|
-
/* @__PURE__ */ jsxs2("div", { className: "bg-card border border-primary/15 rounded-[24px] overflow-hidden shadow-2xl relative", children: [
|
|
786
|
-
/* @__PURE__ */ jsx2("div", { className: "absolute inset-0 bg-[radial-gradient(circle_at_top,rgba(173,163,255,0.05)_0,transparent_100%)] pointer-events-none" }),
|
|
787
|
-
/* @__PURE__ */ jsxs2("div", { className: "bg-muted/50 border-b border-border px-4 py-3 flex items-center gap-3", children: [
|
|
788
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex gap-2", children: [
|
|
789
|
-
/* @__PURE__ */ jsx2("div", { className: "h-3 w-3 rounded-full bg-[#ff5f56]/80" }),
|
|
790
|
-
/* @__PURE__ */ jsx2("div", { className: "h-3 w-3 rounded-full bg-[#ffbd2e]/80" }),
|
|
791
|
-
/* @__PURE__ */ jsx2("div", { className: "h-3 w-3 rounded-full bg-[#27c93f]/80" })
|
|
792
|
-
] }),
|
|
793
|
-
/* @__PURE__ */ jsx2("div", { className: "font-mono text-[10px] text-muted-foreground uppercase tracking-widest ml-2 border-l border-border pl-3", children: "deploy_sequence.sh" })
|
|
794
|
-
] }),
|
|
795
|
-
/* @__PURE__ */ jsxs2("div", { className: "p-5 font-mono text-xs space-y-3 min-h-[240px] relative z-10 text-[13px]", children: [
|
|
796
|
-
/* @__PURE__ */ jsxs2("div", { className: "text-green-400", children: [
|
|
797
|
-
"root@tangle:~# ",
|
|
798
|
-
/* @__PURE__ */ jsx2("span", { className: "text-foreground/80", children: "tangle-cli provision --new" })
|
|
799
|
-
] }),
|
|
800
|
-
/* @__PURE__ */ jsx2("div", { className: "text-muted-foreground/70", children: "Initializing deployment handshake..." }),
|
|
801
|
-
/* @__PURE__ */ jsxs2("div", { className: "text-foreground/70", children: [
|
|
802
|
-
/* @__PURE__ */ jsx2("span", { className: "text-primary mr-2", children: "\u2713" }),
|
|
803
|
-
" Bound Platform: ",
|
|
804
|
-
/* @__PURE__ */ jsx2("span", { className: "text-foreground font-bold animate-in fade-in duration-300", children: environments.find((e) => e.id === selectedEnv)?.name ?? "Node.js" }, `env-${selectedEnv}`)
|
|
805
|
-
] }),
|
|
806
|
-
/* @__PURE__ */ jsxs2("div", { className: "text-foreground/70", children: [
|
|
807
|
-
/* @__PURE__ */ jsx2("span", { className: "text-primary mr-2", children: "\u2713" }),
|
|
808
|
-
" Allocation CPU: ",
|
|
809
|
-
/* @__PURE__ */ jsxs2("span", { className: "text-foreground font-bold animate-in fade-in duration-300", children: [
|
|
810
|
-
cpuCores,
|
|
811
|
-
" Cores"
|
|
812
|
-
] }, `cpu-${cpuCores}`)
|
|
813
|
-
] }),
|
|
814
|
-
/* @__PURE__ */ jsxs2("div", { className: "text-foreground/70", children: [
|
|
815
|
-
/* @__PURE__ */ jsx2("span", { className: "text-primary mr-2", children: "\u2713" }),
|
|
816
|
-
" Allocation RAM: ",
|
|
817
|
-
/* @__PURE__ */ jsxs2("span", { className: "text-foreground font-bold animate-in fade-in duration-300", children: [
|
|
818
|
-
ramGB,
|
|
819
|
-
"GB"
|
|
820
|
-
] }, `ram-${ramGB}`)
|
|
821
|
-
] }),
|
|
822
|
-
/* @__PURE__ */ jsxs2("div", { className: "text-foreground/70", children: [
|
|
823
|
-
/* @__PURE__ */ jsx2("span", { className: "text-primary mr-2", children: "\u2713" }),
|
|
824
|
-
" Mounted Storage: ",
|
|
825
|
-
/* @__PURE__ */ jsxs2("span", { className: "text-foreground font-bold animate-in fade-in duration-300", children: [
|
|
826
|
-
storageGB,
|
|
827
|
-
"GB NVMe"
|
|
828
|
-
] }, `disk-${storageGB}`)
|
|
829
|
-
] }),
|
|
830
|
-
/* @__PURE__ */ jsxs2("div", { className: "pt-3 flex items-center gap-3", children: [
|
|
831
|
-
/* @__PURE__ */ jsx2("div", { className: "w-2 h-4 bg-primary animate-pulse" }),
|
|
832
|
-
/* @__PURE__ */ jsx2("span", { className: "text-muted-foreground", children: "Awaiting user confirmation..." })
|
|
833
|
-
] })
|
|
834
|
-
] })
|
|
835
|
-
] }),
|
|
836
1178
|
/* @__PURE__ */ jsxs2("div", { className: "p-6 rounded-[24px] bg-card border border-primary/15 relative overflow-hidden", children: [
|
|
837
1179
|
/* @__PURE__ */ jsx2("div", { className: "hidden" }),
|
|
838
1180
|
/* @__PURE__ */ jsxs2("div", { className: "flex justify-between items-center mb-4 relative z-10", children: [
|
|
839
1181
|
/* @__PURE__ */ jsx2("span", { className: "font-label text-xs font-bold uppercase tracking-widest text-muted-foreground", children: "Run Cost" }),
|
|
840
|
-
/* @__PURE__ */
|
|
1182
|
+
/* @__PURE__ */ jsxs2(
|
|
1183
|
+
"div",
|
|
1184
|
+
{
|
|
1185
|
+
role: "group",
|
|
1186
|
+
"aria-label": "Pricing view",
|
|
1187
|
+
className: "inline-flex items-center rounded-full border border-border bg-muted/50 p-0.5",
|
|
1188
|
+
children: [
|
|
1189
|
+
/* @__PURE__ */ jsx2(
|
|
1190
|
+
"button",
|
|
1191
|
+
{
|
|
1192
|
+
type: "button",
|
|
1193
|
+
"aria-pressed": pricingView === "hourly",
|
|
1194
|
+
onClick: () => setPricingView("hourly"),
|
|
1195
|
+
className: cn(
|
|
1196
|
+
"rounded-full px-2.5 py-0.5 text-[10px] font-bold transition-all",
|
|
1197
|
+
pricingView === "hourly" ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
|
|
1198
|
+
),
|
|
1199
|
+
children: "Per Hour"
|
|
1200
|
+
}
|
|
1201
|
+
),
|
|
1202
|
+
/* @__PURE__ */ jsx2(
|
|
1203
|
+
"button",
|
|
1204
|
+
{
|
|
1205
|
+
type: "button",
|
|
1206
|
+
"aria-pressed": pricingView === "perSecond",
|
|
1207
|
+
onClick: () => setPricingView("perSecond"),
|
|
1208
|
+
className: cn(
|
|
1209
|
+
"rounded-full px-2.5 py-0.5 text-[10px] font-bold transition-all",
|
|
1210
|
+
pricingView === "perSecond" ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
|
|
1211
|
+
),
|
|
1212
|
+
children: "Per Second"
|
|
1213
|
+
}
|
|
1214
|
+
)
|
|
1215
|
+
]
|
|
1216
|
+
}
|
|
1217
|
+
)
|
|
841
1218
|
] }),
|
|
842
1219
|
/* @__PURE__ */ jsxs2("div", { className: "flex items-baseline gap-2 mb-5 relative z-10", children: [
|
|
843
|
-
/* @__PURE__ */ jsxs2(
|
|
844
|
-
"
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
1220
|
+
/* @__PURE__ */ jsxs2(
|
|
1221
|
+
"span",
|
|
1222
|
+
{
|
|
1223
|
+
className: cn(
|
|
1224
|
+
"font-black text-foreground tracking-tighter animate-in fade-in duration-200",
|
|
1225
|
+
pricingView === "hourly" ? "text-4xl" : "text-2xl"
|
|
1226
|
+
),
|
|
1227
|
+
children: [
|
|
1228
|
+
"$",
|
|
1229
|
+
displayValue
|
|
1230
|
+
]
|
|
1231
|
+
},
|
|
1232
|
+
pricingView
|
|
1233
|
+
),
|
|
1234
|
+
/* @__PURE__ */ jsx2("span", { className: "text-muted-foreground text-sm font-bold", children: pricingSuffix })
|
|
848
1235
|
] }),
|
|
849
1236
|
/* @__PURE__ */ jsxs2("div", { className: "space-y-2 relative z-10 bg-card border border-border rounded-xl p-3", children: [
|
|
850
1237
|
/* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-xs font-mono tracking-widest text-muted-foreground", children: [
|
|
851
1238
|
/* @__PURE__ */ jsx2("span", { children: "COMPUTE" }),
|
|
852
1239
|
/* @__PURE__ */ jsxs2("span", { className: "text-foreground", children: [
|
|
853
1240
|
"$",
|
|
854
|
-
(
|
|
855
|
-
|
|
1241
|
+
fmtRate(hourlyCostBreakdown.compute),
|
|
1242
|
+
rateSuffix
|
|
856
1243
|
] })
|
|
857
1244
|
] }),
|
|
858
1245
|
/* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-xs font-mono tracking-widest text-muted-foreground", children: [
|
|
859
1246
|
/* @__PURE__ */ jsx2("span", { children: "MEMORY" }),
|
|
860
1247
|
/* @__PURE__ */ jsxs2("span", { className: "text-foreground/80", children: [
|
|
861
1248
|
"$",
|
|
862
|
-
(
|
|
863
|
-
|
|
1249
|
+
fmtRate(hourlyCostBreakdown.memory),
|
|
1250
|
+
rateSuffix
|
|
864
1251
|
] })
|
|
865
1252
|
] }),
|
|
866
1253
|
/* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-xs font-mono tracking-widest text-muted-foreground", children: [
|
|
867
1254
|
/* @__PURE__ */ jsx2("span", { children: "STORAGE" }),
|
|
868
1255
|
/* @__PURE__ */ jsxs2("span", { className: "text-foreground/80", children: [
|
|
869
1256
|
"$",
|
|
870
|
-
(
|
|
871
|
-
|
|
1257
|
+
fmtRate(hourlyCostBreakdown.storage),
|
|
1258
|
+
rateSuffix
|
|
1259
|
+
] })
|
|
1260
|
+
] }),
|
|
1261
|
+
hourlyCostBreakdown.floorApplies && /* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-xs font-mono tracking-widest text-primary border-t border-border pt-2", children: [
|
|
1262
|
+
/* @__PURE__ */ jsx2("span", { children: "MIN CHARGE" }),
|
|
1263
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
1264
|
+
"$",
|
|
1265
|
+
fmtRate(
|
|
1266
|
+
hourlyCostBreakdown.floor - hourlyCostBreakdown.lineSum
|
|
1267
|
+
),
|
|
1268
|
+
rateSuffix
|
|
872
1269
|
] })
|
|
873
1270
|
] })
|
|
874
1271
|
] })
|
|
@@ -885,7 +1282,8 @@ function ProvisioningWizard({
|
|
|
885
1282
|
onClick: () => setCurrentStep((s) => s + 1),
|
|
886
1283
|
className: "w-full relative overflow-hidden h-12 bg-primary text-primary-foreground font-extrabold text-sm rounded-2xl hover:brightness-110 transition-all active:scale-[0.98] shadow-md",
|
|
887
1284
|
children: [
|
|
888
|
-
"Continue to
|
|
1285
|
+
"Continue to",
|
|
1286
|
+
" ",
|
|
889
1287
|
currentStep === 1 ? "Resources" : "Agent Config"
|
|
890
1288
|
]
|
|
891
1289
|
}
|
|
@@ -1839,46 +2237,64 @@ function SecretsPage({ apiClient, className }) {
|
|
|
1839
2237
|
/* @__PURE__ */ jsx5(DialogTitle, { children: "Create Secret" }),
|
|
1840
2238
|
/* @__PURE__ */ jsx5(DialogDescription, { children: "Secrets are automatically exposed as environment variables across all your new sandboxes." })
|
|
1841
2239
|
] }),
|
|
1842
|
-
/* @__PURE__ */ jsxs5(
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
2240
|
+
/* @__PURE__ */ jsxs5(
|
|
2241
|
+
"form",
|
|
2242
|
+
{
|
|
2243
|
+
onSubmit: (e) => {
|
|
2244
|
+
e.preventDefault();
|
|
2245
|
+
if (newName.trim() && newValue.trim() && !isCreating) handleCreate();
|
|
2246
|
+
},
|
|
2247
|
+
className: "space-y-4",
|
|
2248
|
+
children: [
|
|
2249
|
+
/* @__PURE__ */ jsxs5("div", { children: [
|
|
2250
|
+
/* @__PURE__ */ jsx5("label", { htmlFor: "secret-name", className: "block text-xs font-bold uppercase tracking-widest text-muted-foreground mb-2", children: "Name" }),
|
|
2251
|
+
/* @__PURE__ */ jsx5(
|
|
2252
|
+
"input",
|
|
2253
|
+
{
|
|
2254
|
+
id: "secret-name",
|
|
2255
|
+
name: "secret-name",
|
|
2256
|
+
type: "text",
|
|
2257
|
+
value: newName,
|
|
2258
|
+
onChange: (e) => setNewName(e.target.value.toUpperCase().replace(/[^A-Z0-9_]/g, "_")),
|
|
2259
|
+
placeholder: "MY_SECRET_KEY",
|
|
2260
|
+
autoComplete: "off",
|
|
2261
|
+
className: "w-full rounded-md border border-border bg-card px-3 py-2.5 text-sm font-mono text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
|
2262
|
+
}
|
|
2263
|
+
)
|
|
2264
|
+
] }),
|
|
2265
|
+
/* @__PURE__ */ jsxs5("div", { children: [
|
|
2266
|
+
/* @__PURE__ */ jsx5("label", { htmlFor: "secret-value", className: "block text-xs font-bold uppercase tracking-widest text-muted-foreground mb-2", children: "Value" }),
|
|
2267
|
+
/* @__PURE__ */ jsxs5("div", { className: "relative", children: [
|
|
2268
|
+
/* @__PURE__ */ jsx5(
|
|
2269
|
+
"input",
|
|
2270
|
+
{
|
|
2271
|
+
id: "secret-value",
|
|
2272
|
+
name: "secret-value",
|
|
2273
|
+
type: showValue ? "text" : "password",
|
|
2274
|
+
value: newValue,
|
|
2275
|
+
onChange: (e) => setNewValue(e.target.value),
|
|
2276
|
+
placeholder: "Enter secret value...",
|
|
2277
|
+
autoComplete: "new-password",
|
|
2278
|
+
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"
|
|
2279
|
+
}
|
|
2280
|
+
),
|
|
2281
|
+
/* @__PURE__ */ jsx5(
|
|
2282
|
+
"button",
|
|
2283
|
+
{
|
|
2284
|
+
type: "button",
|
|
2285
|
+
onClick: () => setShowValue(!showValue),
|
|
2286
|
+
className: "absolute right-2 top-1/2 -translate-y-1/2 p-1 text-muted-foreground hover:text-foreground",
|
|
2287
|
+
"aria-label": showValue ? "Hide value" : "Show value",
|
|
2288
|
+
children: showValue ? /* @__PURE__ */ jsx5(EyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx5(Eye, { className: "h-4 w-4" })
|
|
2289
|
+
}
|
|
2290
|
+
)
|
|
2291
|
+
] }),
|
|
2292
|
+
/* @__PURE__ */ jsx5("p", { className: "mt-1.5 text-xs text-muted-foreground", children: "This value cannot be retrieved after creation." })
|
|
2293
|
+
] }),
|
|
2294
|
+
/* @__PURE__ */ jsx5("button", { type: "submit", className: "hidden", tabIndex: -1, "aria-hidden": "true", children: "Submit" })
|
|
2295
|
+
]
|
|
2296
|
+
}
|
|
2297
|
+
),
|
|
1882
2298
|
createError && /* @__PURE__ */ jsx5("p", { className: "mt-3 text-sm text-destructive", children: createError }),
|
|
1883
2299
|
/* @__PURE__ */ jsxs5(DialogFooter, { children: [
|
|
1884
2300
|
/* @__PURE__ */ jsx5(
|
|
@@ -1958,10 +2374,11 @@ function SecretsPage({ apiClient, className }) {
|
|
|
1958
2374
|
{
|
|
1959
2375
|
type: "button",
|
|
1960
2376
|
onClick: () => setIsCreateOpen(true),
|
|
2377
|
+
"aria-label": "Create your first secret",
|
|
1961
2378
|
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]",
|
|
1962
2379
|
children: [
|
|
1963
2380
|
/* @__PURE__ */ jsx5(Plus3, { className: "h-4 w-4" }),
|
|
1964
|
-
"
|
|
2381
|
+
"New Secret"
|
|
1965
2382
|
]
|
|
1966
2383
|
}
|
|
1967
2384
|
)
|
|
@@ -2858,10 +3275,11 @@ function StartupScriptsPage({ apiClient, className }) {
|
|
|
2858
3275
|
{
|
|
2859
3276
|
type: "button",
|
|
2860
3277
|
onClick: openCreate,
|
|
3278
|
+
"aria-label": "Create your first startup script",
|
|
2861
3279
|
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)]",
|
|
2862
3280
|
children: [
|
|
2863
3281
|
/* @__PURE__ */ jsx7(Plus4, { className: "h-4 w-4" }),
|
|
2864
|
-
"
|
|
3282
|
+
"New Script"
|
|
2865
3283
|
]
|
|
2866
3284
|
}
|
|
2867
3285
|
)
|