@growthub/cli 0.13.2 → 0.13.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/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/refresh-sources/route.js +24 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/route.js +14 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/login/route.js +74 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/logout/route.js +67 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/status/route.js +77 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-run/route.js +48 -3
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/DataModelShell.jsx +123 -27
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationNodeConfigPanel.jsx +136 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationRunTracePanel.jsx +713 -92
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxAgentAuthPanel.jsx +224 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxRunPanel.jsx +32 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +514 -9
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/page.jsx +8 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/integrations/page.jsx +10 -7
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/RunSetupPanel.jsx +261 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/WorkflowSurface.jsx +72 -7
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-builder.jsx +766 -138
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-rail.jsx +91 -14
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/docs/sandbox-environment-primitive.md +35 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph-runner.js +15 -3
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-console.js +384 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-inputs.js +323 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-trace.js +32 -3
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth-eligibility.js +50 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth-redaction.js +64 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth.js +629 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-host-catalog.js +168 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-chart-values.js +542 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +164 -7
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-helper.js +11 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-schema.js +111 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +9 -0
- package/package.json +1 -1
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
Mail,
|
|
29
29
|
Maximize2,
|
|
30
30
|
MoreHorizontal,
|
|
31
|
+
Play,
|
|
31
32
|
Plus,
|
|
32
33
|
Pencil,
|
|
33
34
|
Search,
|
|
@@ -67,6 +68,8 @@ import {
|
|
|
67
68
|
} from "@/lib/workspace-data-model";
|
|
68
69
|
import { ReferencePicker } from "./ReferencePicker.jsx";
|
|
69
70
|
import { SandboxRunPanel } from "./SandboxRunPanel.jsx";
|
|
71
|
+
import { SandboxAgentAuthPanel } from "./SandboxAgentAuthPanel.jsx";
|
|
72
|
+
import { isSandboxLocalAgentHost } from "@/lib/sandbox-agent-auth-eligibility";
|
|
70
73
|
import { StatusPill } from "./StatusPill.jsx";
|
|
71
74
|
import { SegmentedToggle, ToggleField } from "./ToggleField.jsx";
|
|
72
75
|
import { SourceTestPanel } from "./SourceTestPanel.jsx";
|
|
@@ -135,6 +138,15 @@ const OBJECT_TYPE_DEFS = [
|
|
|
135
138
|
// ─── Lane / badge meta (objectTypeBadge from dm-shared) ────────────────────────
|
|
136
139
|
|
|
137
140
|
const SANDBOX_RUNTIME_OPTIONS = ["python", "node", "bash"];
|
|
141
|
+
const EMPTY_FIELD_SETTING_LIST = Object.freeze([]);
|
|
142
|
+
const EMPTY_AGENT_AUTH_PATCH = {
|
|
143
|
+
agentAuthStatus: "",
|
|
144
|
+
agentAuthProvider: "",
|
|
145
|
+
agentAuthLastChecked: "",
|
|
146
|
+
agentAuthLastExitCode: "",
|
|
147
|
+
agentAuthLastMessage: "",
|
|
148
|
+
agentAuthLastLoginUrl: ""
|
|
149
|
+
};
|
|
138
150
|
const FIELD_TYPE_CHOICES = [
|
|
139
151
|
{ value: "text", label: "Text", icon: "Type", sample: "Field name" },
|
|
140
152
|
{ value: "number", label: "Number", icon: "Hash", sample: "Amount" },
|
|
@@ -618,10 +630,17 @@ function SandboxRecordFields({
|
|
|
618
630
|
));
|
|
619
631
|
}
|
|
620
632
|
|
|
633
|
+
function withClearedAgentAuth(fields) {
|
|
634
|
+
return { ...fields, ...EMPTY_AGENT_AUTH_PATCH };
|
|
635
|
+
}
|
|
636
|
+
|
|
621
637
|
function setRunLocality(next) {
|
|
622
638
|
const fields = { runLocality: next };
|
|
623
639
|
if (next === "serverless" && ["local-agent-host", "local-intelligence"].includes(String(draft.adapter || "").trim())) {
|
|
624
640
|
fields.adapter = "local-process";
|
|
641
|
+
fields.agentHost = "";
|
|
642
|
+
patchFields(withClearedAgentAuth(fields));
|
|
643
|
+
return;
|
|
625
644
|
}
|
|
626
645
|
patchFields(fields);
|
|
627
646
|
}
|
|
@@ -708,7 +727,10 @@ function SandboxRecordFields({
|
|
|
708
727
|
value={String(draft.adapter || "local-process").trim() || "local-process"}
|
|
709
728
|
disabled={!table.mutable || saving}
|
|
710
729
|
options={sandboxAdapters.length === 0 ? [{ value: "local-process", label: "local-process" }] : sandboxAdapters.map((a) => ({ value: a.id, label: a.label }))}
|
|
711
|
-
onChange={(nextValue) => patchFields({
|
|
730
|
+
onChange={(nextValue) => patchFields(withClearedAgentAuth({
|
|
731
|
+
adapter: nextValue,
|
|
732
|
+
agentHost: nextValue === "local-agent-host" ? draft.agentHost || "" : ""
|
|
733
|
+
}))}
|
|
712
734
|
/>
|
|
713
735
|
</label>
|
|
714
736
|
|
|
@@ -720,7 +742,7 @@ function SandboxRecordFields({
|
|
|
720
742
|
disabled={!table.mutable || saving}
|
|
721
743
|
placeholder="Select host..."
|
|
722
744
|
options={(selectedAdapterMeta?.hostCatalog || []).map((h) => ({ value: h.slug, label: h.label }))}
|
|
723
|
-
onChange={(nextValue) => patchFields({ agentHost: nextValue })}
|
|
745
|
+
onChange={(nextValue) => patchFields(withClearedAgentAuth({ agentHost: nextValue }))}
|
|
724
746
|
/>
|
|
725
747
|
</label>
|
|
726
748
|
)}
|
|
@@ -990,21 +1012,27 @@ function DataModelRecordDrawer({
|
|
|
990
1012
|
const [sidecarMode, setSidecarMode] = useState(null);
|
|
991
1013
|
const [traceField, setTraceField] = useState(null);
|
|
992
1014
|
const [traceRunId, setTraceRunId] = useState("");
|
|
1015
|
+
const drawerKeyRef = useRef("");
|
|
993
1016
|
|
|
994
1017
|
useEffect(() => {
|
|
1018
|
+
const drawerKey = `${table.id || table.objectId || table.source}:${rowIndex}:${row?.Name || row?.id || ""}`;
|
|
1019
|
+
const sameDrawerRecord = drawerKeyRef.current === drawerKey;
|
|
1020
|
+
drawerKeyRef.current = drawerKey;
|
|
995
1021
|
setDraft(row || {});
|
|
996
|
-
setEditMode(false);
|
|
997
1022
|
setPendingColumns(table.columns || []);
|
|
998
1023
|
setPendingHidden(table.fieldSettings?.hidden || []);
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1024
|
+
if (!sameDrawerRecord) {
|
|
1025
|
+
setEditMode(false);
|
|
1026
|
+
setTestMessage("");
|
|
1027
|
+
setSandboxMessage("");
|
|
1028
|
+
setSandboxHistory([]);
|
|
1029
|
+
setSandboxHistoryMessage("");
|
|
1030
|
+
setExpandedJson(null);
|
|
1031
|
+
setSandboxToolFlow(null);
|
|
1032
|
+
setSandboxToolDraft({});
|
|
1033
|
+
setCreatedSandboxMeta(null);
|
|
1034
|
+
setCreatedSandboxTestMessage("");
|
|
1035
|
+
}
|
|
1008
1036
|
if (initialSidecar?.mode === "graph") {
|
|
1009
1037
|
setSidecarMode("graph");
|
|
1010
1038
|
setTraceField(null);
|
|
@@ -1013,12 +1041,12 @@ function DataModelRecordDrawer({
|
|
|
1013
1041
|
setSidecarMode("trace");
|
|
1014
1042
|
setTraceField(initialSidecar.field || "lastResponse");
|
|
1015
1043
|
setTraceRunId(String(initialSidecar.runId || row?.lastRunId || "").trim());
|
|
1016
|
-
} else {
|
|
1044
|
+
} else if (!sameDrawerRecord) {
|
|
1017
1045
|
setSidecarMode(null);
|
|
1018
1046
|
setTraceField(null);
|
|
1019
1047
|
setTraceRunId("");
|
|
1020
1048
|
}
|
|
1021
|
-
}, [row, rowIndex, initialSidecar]);
|
|
1049
|
+
}, [row, rowIndex, initialSidecar, table.id, table.objectId, table.source, table.columns, table.fieldSettings?.hidden]);
|
|
1022
1050
|
|
|
1023
1051
|
if (rowIndex === null || rowIndex === undefined || !row) return null;
|
|
1024
1052
|
|
|
@@ -1371,6 +1399,17 @@ function DataModelRecordDrawer({
|
|
|
1371
1399
|
<h2>{draft.Name || draft.integrationId || draft.id || `Row ${rowIndex + 1}`}</h2>
|
|
1372
1400
|
</div>
|
|
1373
1401
|
<div className="dm-record-drawer-actions">
|
|
1402
|
+
{isSandbox && sidecarMode !== "graph" && sidecarMode !== "trace" && (
|
|
1403
|
+
<button
|
|
1404
|
+
type="button"
|
|
1405
|
+
className="dm-btn-primary-sm dm-record-head-run"
|
|
1406
|
+
disabled={sandboxRunning || saving || !String(draft.Name || "").trim()}
|
|
1407
|
+
onClick={runSandbox}
|
|
1408
|
+
>
|
|
1409
|
+
<Play size={13} aria-hidden />
|
|
1410
|
+
{sandboxRunning ? "Running…" : "Run sandbox"}
|
|
1411
|
+
</button>
|
|
1412
|
+
)}
|
|
1374
1413
|
{!isSandbox && sandboxToolFlow !== "draft" && (
|
|
1375
1414
|
<button type="button" className="dm-sidebar-close" onClick={() => setEditMode((current) => !current)} aria-label="Toggle edit mode">
|
|
1376
1415
|
<Pencil size={16} />
|
|
@@ -1450,7 +1489,7 @@ function DataModelRecordDrawer({
|
|
|
1450
1489
|
onConfirm={createSandboxToolFromRegistry}
|
|
1451
1490
|
onCancel={() => setSandboxToolFlow("draft")}
|
|
1452
1491
|
/>
|
|
1453
|
-
{isSandbox && sidecarMode !== "graph" && sidecarMode !== "trace" && (
|
|
1492
|
+
{isSandbox && sidecarMode !== "graph" && sidecarMode !== "trace" && sandboxMessage && (
|
|
1454
1493
|
<SandboxRunPanel
|
|
1455
1494
|
status={draft.status}
|
|
1456
1495
|
sandboxRunning={sandboxRunning}
|
|
@@ -1458,6 +1497,21 @@ function DataModelRecordDrawer({
|
|
|
1458
1497
|
disabled={saving}
|
|
1459
1498
|
canRun={Boolean(String(draft.Name || "").trim())}
|
|
1460
1499
|
onRun={runSandbox}
|
|
1500
|
+
agentAuthStatus={draft.agentAuthStatus}
|
|
1501
|
+
agentAuthHint={
|
|
1502
|
+
isSandboxLocalAgentHost(draft) && ["stale", "missing"].includes(String(draft.agentAuthStatus || ""))
|
|
1503
|
+
? "Agent auth may be stale — open the auth panel above."
|
|
1504
|
+
: null
|
|
1505
|
+
}
|
|
1506
|
+
/>
|
|
1507
|
+
)}
|
|
1508
|
+
{isSandbox && sidecarMode !== "graph" && sidecarMode !== "trace" && isSandboxLocalAgentHost(draft) && (
|
|
1509
|
+
<SandboxAgentAuthPanel
|
|
1510
|
+
objectId={table.objectId}
|
|
1511
|
+
rowName={String(draft.Name || "").trim()}
|
|
1512
|
+
draft={draft}
|
|
1513
|
+
disabled={saving || sandboxRunning}
|
|
1514
|
+
onPatchDraft={(patch) => setDraft((current) => ({ ...current, ...patch }))}
|
|
1461
1515
|
/>
|
|
1462
1516
|
)}
|
|
1463
1517
|
{isSandbox && sidecarMode === "graph" && (
|
|
@@ -1596,9 +1650,12 @@ function DataModelTableSurface({
|
|
|
1596
1650
|
focusSandboxRowName,
|
|
1597
1651
|
onFocusSandboxRowConsumed,
|
|
1598
1652
|
onFocusSandboxRow,
|
|
1653
|
+
selectedRecordIndex,
|
|
1654
|
+
onSelectedRecordIndexChange,
|
|
1599
1655
|
}) {
|
|
1600
1656
|
const router = useRouter();
|
|
1601
1657
|
const [selectedRow, setSelectedRow] = useState(null);
|
|
1658
|
+
const [localSelectedOriginalIndex, setLocalSelectedOriginalIndex] = useState(null);
|
|
1602
1659
|
const [initialSidecar, setInitialSidecar] = useState(null);
|
|
1603
1660
|
const [fieldName, setFieldName] = useState("");
|
|
1604
1661
|
const [fieldType, setFieldType] = useState("text");
|
|
@@ -1616,10 +1673,17 @@ function DataModelTableSurface({
|
|
|
1616
1673
|
const [pageSize, setPageSize] = useState(15);
|
|
1617
1674
|
const [pageIndex, setPageIndex] = useState(0);
|
|
1618
1675
|
const fieldInputRef = useRef(null);
|
|
1676
|
+
const selectedOriginalIndex = selectedRecordIndex ?? localSelectedOriginalIndex;
|
|
1677
|
+
|
|
1678
|
+
function selectOriginalIndex(index) {
|
|
1679
|
+
setLocalSelectedOriginalIndex(index);
|
|
1680
|
+
onSelectedRecordIndexChange?.(index);
|
|
1681
|
+
}
|
|
1619
1682
|
|
|
1620
1683
|
useEffect(() => { if (addingField) fieldInputRef.current?.focus(); }, [addingField]);
|
|
1621
1684
|
useEffect(() => {
|
|
1622
1685
|
setSelectedRow(null);
|
|
1686
|
+
selectOriginalIndex(null);
|
|
1623
1687
|
setSelectedRows(new Set());
|
|
1624
1688
|
setConfirmDeleteSelection(false);
|
|
1625
1689
|
setLastSelectedRowIndex(null);
|
|
@@ -1633,7 +1697,15 @@ function DataModelTableSurface({
|
|
|
1633
1697
|
setFilterDraft({ fieldId: table.columns[0] || "", operator: "eq", value: "" });
|
|
1634
1698
|
}, [table.id, table.columns]);
|
|
1635
1699
|
|
|
1636
|
-
const settings =
|
|
1700
|
+
const settings = useMemo(() => {
|
|
1701
|
+
const fieldSettings = table.fieldSettings || {};
|
|
1702
|
+
return {
|
|
1703
|
+
hidden: Array.isArray(fieldSettings.hidden) ? fieldSettings.hidden : EMPTY_FIELD_SETTING_LIST,
|
|
1704
|
+
order: Array.isArray(fieldSettings.order) ? fieldSettings.order : (table.columns || EMPTY_FIELD_SETTING_LIST),
|
|
1705
|
+
sort: Array.isArray(fieldSettings.sort) ? fieldSettings.sort : EMPTY_FIELD_SETTING_LIST,
|
|
1706
|
+
filter: fieldSettings.filter || null
|
|
1707
|
+
};
|
|
1708
|
+
}, [table.fieldSettings, table.columns]);
|
|
1637
1709
|
const orderedColumns = useMemo(() => mergeColumnOrder(settings.order, table.columns), [settings.order, table.columns]);
|
|
1638
1710
|
const visibleColumns = useMemo(() => orderedColumns.filter((column) => !settings.hidden.includes(column)), [orderedColumns, settings.hidden]);
|
|
1639
1711
|
const rowEntries = useMemo(() => {
|
|
@@ -1669,7 +1741,8 @@ function DataModelTableSurface({
|
|
|
1669
1741
|
if (visibleIndex < 0) return;
|
|
1670
1742
|
const pageForRow = Math.floor(visibleIndex / pageSize);
|
|
1671
1743
|
setPageIndex(pageForRow);
|
|
1672
|
-
setSelectedRow(visibleIndex
|
|
1744
|
+
setSelectedRow(visibleIndex);
|
|
1745
|
+
selectOriginalIndex(originalIndex);
|
|
1673
1746
|
onFocusSandboxRowConsumed?.();
|
|
1674
1747
|
}, [focusSandboxRowName, table.id, table.objectType, table.rows, rowEntries, pageSize, onFocusSandboxRowConsumed]);
|
|
1675
1748
|
|
|
@@ -1847,11 +1920,14 @@ function DataModelTableSurface({
|
|
|
1847
1920
|
const rowIndexes = Array.from(selectedRows).sort((a, b) => b - a);
|
|
1848
1921
|
onSave((config) => rowIndexes.reduce((nextConfig, rowIndex) => deleteTableRow(nextConfig, table, rowIndex), config));
|
|
1849
1922
|
setSelectedRow(null);
|
|
1923
|
+
selectOriginalIndex(null);
|
|
1850
1924
|
setConfirmDeleteSelection(false);
|
|
1851
1925
|
clearRowSelection();
|
|
1852
1926
|
}
|
|
1853
1927
|
|
|
1854
|
-
const selectedEntry =
|
|
1928
|
+
const selectedEntry = selectedOriginalIndex === null
|
|
1929
|
+
? (selectedRow === null ? null : rowEntries[selectedRow])
|
|
1930
|
+
: rowEntries.find((entry) => entry.originalIndex === selectedOriginalIndex) || null;
|
|
1855
1931
|
const selectedRecord = selectedEntry?.row || null;
|
|
1856
1932
|
|
|
1857
1933
|
return (
|
|
@@ -2035,7 +2111,14 @@ function DataModelTableSurface({
|
|
|
2035
2111
|
const visibleIndex = pageStart + rowIndex;
|
|
2036
2112
|
const displayIndex = visibleIndex + 1;
|
|
2037
2113
|
return (
|
|
2038
|
-
<tr
|
|
2114
|
+
<tr
|
|
2115
|
+
key={`${originalIndex}:${visibleIndex}`}
|
|
2116
|
+
className={`${selectedOriginalIndex === originalIndex ? "selected" : ""}${selectedRows.has(originalIndex) ? " multi-selected" : ""}`}
|
|
2117
|
+
onClick={() => {
|
|
2118
|
+
setSelectedRow(visibleIndex);
|
|
2119
|
+
selectOriginalIndex(originalIndex);
|
|
2120
|
+
}}
|
|
2121
|
+
>
|
|
2039
2122
|
<td className="dm-db-rownum">
|
|
2040
2123
|
{table.mutable ? (
|
|
2041
2124
|
<button type="button" className="dm-row-select" aria-label={selectedRows.has(originalIndex) ? `Deselect row ${displayIndex}` : `Select row ${displayIndex}`} aria-pressed={selectedRows.has(originalIndex)} onClick={(event) => { event.stopPropagation(); toggleRowSelection(originalIndex, visibleIndex, event); }}>
|
|
@@ -2087,11 +2170,12 @@ function DataModelTableSurface({
|
|
|
2087
2170
|
if (column === "orchestrationGraph" || column === "orchestrationConfig") {
|
|
2088
2171
|
openSandboxGraph(column, row);
|
|
2089
2172
|
return;
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2173
|
+
}
|
|
2174
|
+
const sidecar = sandboxSidecarForColumn(column, row);
|
|
2175
|
+
setSelectedRow(visibleIndex);
|
|
2176
|
+
selectOriginalIndex(originalIndex);
|
|
2177
|
+
setInitialSidecar(sidecar);
|
|
2178
|
+
}}
|
|
2095
2179
|
>
|
|
2096
2180
|
{column === "orchestrationGraph" || column === "orchestrationConfig"
|
|
2097
2181
|
? (getOrchestrationGraphUiState(row?.[column]) === "populated" ? "Edit graph" : "Start graph")
|
|
@@ -2139,9 +2223,9 @@ function DataModelTableSurface({
|
|
|
2139
2223
|
tables={tables}
|
|
2140
2224
|
workspaceConfig={workspaceConfig}
|
|
2141
2225
|
rowIndex={selectedEntry?.originalIndex ?? null}
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2226
|
+
row={selectedRecord}
|
|
2227
|
+
saving={saving}
|
|
2228
|
+
onClose={() => { setSelectedRow(null); selectOriginalIndex(null); setInitialSidecar(null); }}
|
|
2145
2229
|
onSave={onSave}
|
|
2146
2230
|
onFocusSandboxRow={onFocusSandboxRow}
|
|
2147
2231
|
initialSidecar={initialSidecar}
|
|
@@ -2449,6 +2533,7 @@ export default function DataModelShell() {
|
|
|
2449
2533
|
const [helperInitialThread, setHelperInitialThread] = useState(null);
|
|
2450
2534
|
const [commandPaletteOpen, setCommandPaletteOpen] = useState(false);
|
|
2451
2535
|
const [focusSandboxRowName, setFocusSandboxRowName] = useState(null);
|
|
2536
|
+
const [selectedRecordByTable, setSelectedRecordByTable] = useState({});
|
|
2452
2537
|
const pendingPatchRef = useRef({});
|
|
2453
2538
|
const saveTimerRef = useRef(null);
|
|
2454
2539
|
|
|
@@ -2540,6 +2625,9 @@ export default function DataModelShell() {
|
|
|
2540
2625
|
);
|
|
2541
2626
|
|
|
2542
2627
|
const selectedTable = tables.find((t) => t.source === selectedSource) || tables[0] || null;
|
|
2628
|
+
const selectedTableKey = selectedTable
|
|
2629
|
+
? String(selectedTable.objectId || selectedTable.id || selectedTable.source || "")
|
|
2630
|
+
: "";
|
|
2543
2631
|
|
|
2544
2632
|
const focusSandboxEnvironmentRow = useCallback(({ rowName, deferOpen = false } = {}) => {
|
|
2545
2633
|
const wanted = String(rowName || "").trim();
|
|
@@ -2903,6 +2991,14 @@ export default function DataModelShell() {
|
|
|
2903
2991
|
focusSandboxRowName={focusSandboxRowName}
|
|
2904
2992
|
onFocusSandboxRowConsumed={() => setFocusSandboxRowName(null)}
|
|
2905
2993
|
onFocusSandboxRow={focusSandboxEnvironmentRow}
|
|
2994
|
+
selectedRecordIndex={selectedTableKey ? selectedRecordByTable[selectedTableKey] ?? null : null}
|
|
2995
|
+
onSelectedRecordIndexChange={(index) => {
|
|
2996
|
+
if (!selectedTableKey) return;
|
|
2997
|
+
setSelectedRecordByTable((current) => ({
|
|
2998
|
+
...current,
|
|
2999
|
+
[selectedTableKey]: index
|
|
3000
|
+
}));
|
|
3001
|
+
}}
|
|
2906
3002
|
/>
|
|
2907
3003
|
</section>
|
|
2908
3004
|
)
|
|
@@ -7,10 +7,33 @@ import {
|
|
|
7
7
|
FILTER_OPERATORS,
|
|
8
8
|
isApiRegistryTestSuccessful
|
|
9
9
|
} from "@/lib/orchestration-graph";
|
|
10
|
+
import { SandboxAgentAuthPanel } from "./SandboxAgentAuthPanel.jsx";
|
|
11
|
+
import { isSandboxLocalAgentHost } from "@/lib/sandbox-agent-auth-eligibility";
|
|
12
|
+
import { HOST_AUTH_CATALOG } from "@/lib/sandbox-agent-host-catalog";
|
|
10
13
|
|
|
11
14
|
const HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
12
15
|
const MODEL_OPTIONS = ["Claude Opus 4.6", "Claude Sonnet 4.5", "GPT-5.2", "Local agent host"];
|
|
13
16
|
const OUTPUT_TYPES = ["Text", "Number", "Boolean", "JSON", "Record ID"];
|
|
17
|
+
const LOCAL_AGENT_ADAPTERS = [
|
|
18
|
+
{ value: "local-process", label: "Local process" },
|
|
19
|
+
{ value: "local-agent-host", label: "Local agent host" },
|
|
20
|
+
{ value: "local-intelligence", label: "Local intelligence" }
|
|
21
|
+
];
|
|
22
|
+
const EMPTY_AGENT_AUTH_PATCH = {
|
|
23
|
+
agentAuthStatus: "",
|
|
24
|
+
agentAuthProvider: "",
|
|
25
|
+
agentAuthLastChecked: "",
|
|
26
|
+
agentAuthLastExitCode: "",
|
|
27
|
+
agentAuthLastMessage: "",
|
|
28
|
+
agentAuthLastLoginUrl: ""
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function getAgentHostOptions() {
|
|
32
|
+
return Object.entries(HOST_AUTH_CATALOG || {}).map(([slug, host]) => ({
|
|
33
|
+
value: slug,
|
|
34
|
+
label: host?.label || slug
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
14
37
|
function normalizeTags(tags) {
|
|
15
38
|
return Array.from(new Set((Array.isArray(tags) ? tags : [])
|
|
16
39
|
.map((tag) => String(tag || "").trim().toLowerCase())
|
|
@@ -378,6 +401,107 @@ function VersionDeltaControls({ node, config, sandboxRow, onChange, disabled })
|
|
|
378
401
|
);
|
|
379
402
|
}
|
|
380
403
|
|
|
404
|
+
function LocalAgentHostControls({
|
|
405
|
+
sandboxRow,
|
|
406
|
+
objectId,
|
|
407
|
+
rowName,
|
|
408
|
+
disabled,
|
|
409
|
+
onSandboxRowPatch
|
|
410
|
+
}) {
|
|
411
|
+
const row = sandboxRow && typeof sandboxRow === "object" ? sandboxRow : {};
|
|
412
|
+
const runLocality = String(row.runLocality || "local").trim().toLowerCase() === "serverless" ? "serverless" : "local";
|
|
413
|
+
const adapter = String(row.adapter || "local-process").trim() || "local-process";
|
|
414
|
+
const agentHost = String(row.agentHost || "").trim();
|
|
415
|
+
const hostOptions = getAgentHostOptions();
|
|
416
|
+
const canPatch = typeof onSandboxRowPatch === "function";
|
|
417
|
+
|
|
418
|
+
function patch(fields) {
|
|
419
|
+
onSandboxRowPatch?.(fields);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function patchWithClearedAgentAuth(fields) {
|
|
423
|
+
patch({ ...fields, ...EMPTY_AGENT_AUTH_PATCH });
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return (
|
|
427
|
+
<div className="dm-orchestration-config__section dm-workflow-agent-runtime">
|
|
428
|
+
<span>Local agent runtime</span>
|
|
429
|
+
<div className="dm-sandbox-locality-toggle" role="group" aria-label="Run locality">
|
|
430
|
+
{["local", "serverless"].map((mode) => (
|
|
431
|
+
<button
|
|
432
|
+
key={mode}
|
|
433
|
+
type="button"
|
|
434
|
+
className={runLocality === mode ? "is-active" : ""}
|
|
435
|
+
disabled={disabled || !canPatch}
|
|
436
|
+
onClick={() => {
|
|
437
|
+
const fields = { runLocality: mode };
|
|
438
|
+
if (mode === "serverless" && ["local-agent-host", "local-intelligence"].includes(adapter)) {
|
|
439
|
+
fields.adapter = "local-process";
|
|
440
|
+
fields.agentHost = "";
|
|
441
|
+
patchWithClearedAgentAuth(fields);
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
patch(fields);
|
|
445
|
+
}}
|
|
446
|
+
>
|
|
447
|
+
{mode === "local" ? "Local" : "Serverless"}
|
|
448
|
+
</button>
|
|
449
|
+
))}
|
|
450
|
+
</div>
|
|
451
|
+
<p className="dm-orchestration-config__hint">
|
|
452
|
+
Same runtime fields as the Data Model sandbox sidecar. Local agent host uses the Paperclip thin adapter on this machine.
|
|
453
|
+
</p>
|
|
454
|
+
{runLocality === "serverless" && (
|
|
455
|
+
<p className="dm-orchestration-config__hint">
|
|
456
|
+
Serverless delegates execution to the configured scheduler/API Registry row; local CLI auth is not used.
|
|
457
|
+
</p>
|
|
458
|
+
)}
|
|
459
|
+
<label className="dm-orchestration-config__field">
|
|
460
|
+
<span>Execution adapter</span>
|
|
461
|
+
<select
|
|
462
|
+
value={adapter}
|
|
463
|
+
disabled={disabled || !canPatch}
|
|
464
|
+
onChange={(event) => {
|
|
465
|
+
const nextAdapter = event.target.value;
|
|
466
|
+
patchWithClearedAgentAuth({
|
|
467
|
+
adapter: nextAdapter,
|
|
468
|
+
agentHost: nextAdapter === "local-agent-host" ? (agentHost || "claude_local") : ""
|
|
469
|
+
});
|
|
470
|
+
}}
|
|
471
|
+
>
|
|
472
|
+
{LOCAL_AGENT_ADAPTERS.map((item) => (
|
|
473
|
+
<option key={item.value} value={item.value}>{item.label}</option>
|
|
474
|
+
))}
|
|
475
|
+
</select>
|
|
476
|
+
</label>
|
|
477
|
+
{runLocality === "local" && adapter === "local-agent-host" && (
|
|
478
|
+
<label className="dm-orchestration-config__field">
|
|
479
|
+
<span>Agent host (Paperclip)</span>
|
|
480
|
+
<select
|
|
481
|
+
value={agentHost}
|
|
482
|
+
disabled={disabled || !canPatch}
|
|
483
|
+
onChange={(event) => patchWithClearedAgentAuth({ agentHost: event.target.value })}
|
|
484
|
+
>
|
|
485
|
+
<option value="">Select host...</option>
|
|
486
|
+
{hostOptions.map((item) => (
|
|
487
|
+
<option key={item.value} value={item.value}>{item.label}</option>
|
|
488
|
+
))}
|
|
489
|
+
</select>
|
|
490
|
+
</label>
|
|
491
|
+
)}
|
|
492
|
+
{runLocality === "local" && adapter === "local-agent-host" && isSandboxLocalAgentHost(row) && (
|
|
493
|
+
<SandboxAgentAuthPanel
|
|
494
|
+
objectId={objectId}
|
|
495
|
+
rowName={rowName}
|
|
496
|
+
draft={row}
|
|
497
|
+
disabled={disabled || !canPatch}
|
|
498
|
+
onPatchDraft={patch}
|
|
499
|
+
/>
|
|
500
|
+
)}
|
|
501
|
+
</div>
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
|
|
381
505
|
export function OrchestrationNodeConfigPanel({
|
|
382
506
|
node,
|
|
383
507
|
onConfigChange,
|
|
@@ -386,6 +510,9 @@ export function OrchestrationNodeConfigPanel({
|
|
|
386
510
|
registryRow,
|
|
387
511
|
workspaceConfig,
|
|
388
512
|
sandboxRow,
|
|
513
|
+
objectId,
|
|
514
|
+
rowName,
|
|
515
|
+
onSandboxRowPatch,
|
|
389
516
|
activeTab: controlledTab,
|
|
390
517
|
onTabChange
|
|
391
518
|
}) {
|
|
@@ -778,6 +905,15 @@ export function OrchestrationNodeConfigPanel({
|
|
|
778
905
|
{MODEL_OPTIONS.map((model) => <option key={model} value={model}>{model}</option>)}
|
|
779
906
|
</select>
|
|
780
907
|
</label>
|
|
908
|
+
{(config.model || MODEL_OPTIONS[0]) === "Local agent host" && (
|
|
909
|
+
<LocalAgentHostControls
|
|
910
|
+
sandboxRow={sandboxRow}
|
|
911
|
+
objectId={objectId}
|
|
912
|
+
rowName={rowName}
|
|
913
|
+
disabled={disabled}
|
|
914
|
+
onSandboxRowPatch={onSandboxRowPatch}
|
|
915
|
+
/>
|
|
916
|
+
)}
|
|
781
917
|
<label className="dm-orchestration-config__field">
|
|
782
918
|
<span>Input prompt</span>
|
|
783
919
|
<textarea
|