@growthub/cli 0.13.9 → 0.14.1
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/env-status/route.js +31 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/helper/apply/route.js +227 -5
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/helper/query/route.js +1 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-run/route.js +70 -9
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/components/WorkspaceActivationPanel.jsx +17 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/components/WorkspaceHelperSetupModal.jsx +6 -3
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/AgentSwarmPanel.jsx +61 -35
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/ApiRegistryCreationCockpit.jsx +200 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/DataModelShell.jsx +414 -9
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/HelperSidecar.jsx +339 -77
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationGraphCanvas.jsx +81 -10
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationNodeConfigPanel.jsx +70 -85
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/ReferencePicker.jsx +2 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SidecarExpandView.jsx +37 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SwarmRunCockpit.jsx +625 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/helper-commands.js +150 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +229 -9
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/WorkflowSurface.jsx +224 -14
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/resolver-loader.js +2 -4
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/sandboxes/default-local-agent-host.js +139 -4
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/sandboxes/default-local-intelligence.js +4 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/api-registry-creation-flow.js +317 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/api-response-profile.js +207 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/creation-error-recovery.js +103 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/env-status.js +100 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-agent-swarm.js +246 -4
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph.js +69 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-console.js +411 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-serverless-flow.js +215 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/server-resolver-write.js +67 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/serverless-upgrade.js +89 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-activation.js +11 -4
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +8 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-helper.js +30 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-metadata-store.js +8 -6
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-resolver-proposal.js +200 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-swarm-proposal.js +551 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/package.json +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useMemo } from "react";
|
|
4
|
-
import { Plus, Trash2 } from "lucide-react";
|
|
4
|
+
import { Check, Plus, Trash2 } from "lucide-react";
|
|
5
5
|
import { HOST_AUTH_CATALOG } from "@/lib/sandbox-agent-host-catalog";
|
|
6
6
|
|
|
7
7
|
function getHostOptions() {
|
|
@@ -11,31 +11,63 @@ function getHostOptions() {
|
|
|
11
11
|
}));
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
function
|
|
14
|
+
function nodeSandboxRecordRef(objectId, rowName, nodeId) {
|
|
15
|
+
return {
|
|
16
|
+
objectId: String(objectId || "").trim(),
|
|
17
|
+
rowName: String(rowName || "").trim(),
|
|
18
|
+
nodeId: String(nodeId || "").trim()
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function withRecordRef(patch, objectId, rowName, nodeId) {
|
|
23
|
+
return {
|
|
24
|
+
...patch,
|
|
25
|
+
sandboxRecordRef: nodeSandboxRecordRef(objectId, rowName, nodeId)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function WorkflowCheckbox({ checked, disabled, onChange, children, title }) {
|
|
30
|
+
return (
|
|
31
|
+
<label className="dm-orchestration-config__field dm-orchestration-config__field-inline dm-workflow-check" title={title}>
|
|
32
|
+
<input
|
|
33
|
+
type="checkbox"
|
|
34
|
+
checked={checked}
|
|
35
|
+
disabled={disabled}
|
|
36
|
+
onChange={(event) => onChange?.(event.target.checked)}
|
|
37
|
+
/>
|
|
38
|
+
<span className="dm-workflow-check__box" aria-hidden="true">
|
|
39
|
+
{checked ? <Check size={13} strokeWidth={2.4} /> : null}
|
|
40
|
+
</span>
|
|
41
|
+
<span>{children}</span>
|
|
42
|
+
</label>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function patchOrchestrator(graph, patch, objectId, rowName) {
|
|
15
47
|
const nodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
16
48
|
return {
|
|
17
49
|
...graph,
|
|
18
50
|
nodes: nodes.map((node) =>
|
|
19
51
|
node?.type === "thinAdapter"
|
|
20
|
-
? { ...node, config: { ...(node.config || {}), ...patch } }
|
|
52
|
+
? { ...node, config: { ...(node.config || {}), ...withRecordRef(patch, objectId, rowName, node.id) } }
|
|
21
53
|
: node
|
|
22
54
|
)
|
|
23
55
|
};
|
|
24
56
|
}
|
|
25
57
|
|
|
26
|
-
function patchSynthesis(graph, patch) {
|
|
58
|
+
function patchSynthesis(graph, patch, objectId, rowName) {
|
|
27
59
|
const nodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
28
60
|
return {
|
|
29
61
|
...graph,
|
|
30
62
|
nodes: nodes.map((node) =>
|
|
31
63
|
node?.type === "tool-result"
|
|
32
|
-
? { ...node, config: { ...(node.config || {}), ...patch } }
|
|
64
|
+
? { ...node, config: { ...(node.config || {}), ...withRecordRef(patch, objectId, rowName, node.id) } }
|
|
33
65
|
: node
|
|
34
66
|
)
|
|
35
67
|
};
|
|
36
68
|
}
|
|
37
69
|
|
|
38
|
-
function patchSubagent(graph, nodeId, patch) {
|
|
70
|
+
function patchSubagent(graph, nodeId, patch, objectId, rowName) {
|
|
39
71
|
const nodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
40
72
|
return {
|
|
41
73
|
...graph,
|
|
@@ -44,7 +76,7 @@ function patchSubagent(graph, nodeId, patch) {
|
|
|
44
76
|
? {
|
|
45
77
|
...node,
|
|
46
78
|
label: patch.role != null ? String(patch.role) : node.label,
|
|
47
|
-
config: { ...(node.config || {}), ...patch }
|
|
79
|
+
config: { ...(node.config || {}), ...withRecordRef(patch, objectId, rowName, node.id) }
|
|
48
80
|
}
|
|
49
81
|
: node
|
|
50
82
|
)
|
|
@@ -107,7 +139,7 @@ function patchSwarmConfig(graph, patch) {
|
|
|
107
139
|
return { ...graph, swarm: { ...base, ...patch } };
|
|
108
140
|
}
|
|
109
141
|
|
|
110
|
-
export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
142
|
+
export function AgentSwarmPanel({ graph, objectId, rowName, onGraphChange, disabled }) {
|
|
111
143
|
const hostOptions = useMemo(getHostOptions, []);
|
|
112
144
|
if (!graph || typeof graph !== "object") return null;
|
|
113
145
|
|
|
@@ -133,7 +165,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
133
165
|
rows={3}
|
|
134
166
|
value={orchestrator?.config?.prompt || ""}
|
|
135
167
|
disabled={disabled || !orchestrator}
|
|
136
|
-
onChange={(e) => patchGraph((g) => patchOrchestrator(g, { prompt: e.target.value }))}
|
|
168
|
+
onChange={(e) => patchGraph((g) => patchOrchestrator(g, { prompt: e.target.value }, objectId, rowName))}
|
|
137
169
|
/>
|
|
138
170
|
</label>
|
|
139
171
|
</div>
|
|
@@ -163,7 +195,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
163
195
|
placeholder="Role"
|
|
164
196
|
value={cfg.role || node.label || ""}
|
|
165
197
|
disabled={disabled}
|
|
166
|
-
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { role: e.target.value }))}
|
|
198
|
+
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { role: e.target.value }, objectId, rowName))}
|
|
167
199
|
/>
|
|
168
200
|
<button
|
|
169
201
|
type="button"
|
|
@@ -181,7 +213,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
181
213
|
placeholder="One-sentence charter"
|
|
182
214
|
value={cfg.description || ""}
|
|
183
215
|
disabled={disabled}
|
|
184
|
-
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { description: e.target.value }))}
|
|
216
|
+
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { description: e.target.value }, objectId, rowName))}
|
|
185
217
|
/>
|
|
186
218
|
</label>
|
|
187
219
|
<label className="dm-orchestration-config__field">
|
|
@@ -190,7 +222,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
190
222
|
rows={2}
|
|
191
223
|
value={cfg.taskPrompt || ""}
|
|
192
224
|
disabled={disabled}
|
|
193
|
-
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { taskPrompt: e.target.value }))}
|
|
225
|
+
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { taskPrompt: e.target.value }, objectId, rowName))}
|
|
194
226
|
/>
|
|
195
227
|
</label>
|
|
196
228
|
<label className="dm-orchestration-config__field">
|
|
@@ -201,7 +233,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
201
233
|
disabled={disabled}
|
|
202
234
|
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, {
|
|
203
235
|
tools: e.target.value.split(",").map((t) => t.trim()).filter(Boolean)
|
|
204
|
-
}))}
|
|
236
|
+
}, objectId, rowName))}
|
|
205
237
|
/>
|
|
206
238
|
</label>
|
|
207
239
|
<label className="dm-orchestration-config__field">
|
|
@@ -212,7 +244,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
212
244
|
placeholder="0 = inherit"
|
|
213
245
|
value={cfg.maxTokens || 0}
|
|
214
246
|
disabled={disabled}
|
|
215
|
-
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { maxTokens: Math.max(0, Number(e.target.value) || 0) }))}
|
|
247
|
+
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { maxTokens: Math.max(0, Number(e.target.value) || 0) }, objectId, rowName))}
|
|
216
248
|
/>
|
|
217
249
|
</label>
|
|
218
250
|
<label className="dm-orchestration-config__field">
|
|
@@ -220,7 +252,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
220
252
|
<select
|
|
221
253
|
value={cfg.agentHost || ""}
|
|
222
254
|
disabled={disabled}
|
|
223
|
-
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { agentHost: e.target.value }))}
|
|
255
|
+
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { agentHost: e.target.value }, objectId, rowName))}
|
|
224
256
|
>
|
|
225
257
|
<option value="">Inherit</option>
|
|
226
258
|
{hostOptions.map((opt) => (
|
|
@@ -228,27 +260,21 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
228
260
|
))}
|
|
229
261
|
</select>
|
|
230
262
|
</label>
|
|
231
|
-
<
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
className="dm-orchestration-config__field dm-orchestration-config__field-inline"
|
|
263
|
+
<WorkflowCheckbox
|
|
264
|
+
checked={cfg.required !== false}
|
|
265
|
+
disabled={disabled}
|
|
266
|
+
onChange={(checked) => patchGraph((g) => patchSubagent(g, node.id, { required: checked }, objectId, rowName))}
|
|
267
|
+
>
|
|
268
|
+
Required
|
|
269
|
+
</WorkflowCheckbox>
|
|
270
|
+
<WorkflowCheckbox
|
|
271
|
+
checked={cfg.networkAccess === true}
|
|
272
|
+
disabled={disabled}
|
|
242
273
|
title="Network is granted only when both this and the row's networkAllow are on."
|
|
274
|
+
onChange={(checked) => patchGraph((g) => patchSubagent(g, node.id, { networkAccess: checked }, objectId, rowName))}
|
|
243
275
|
>
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
checked={cfg.networkAccess === true}
|
|
247
|
-
disabled={disabled}
|
|
248
|
-
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { networkAccess: e.target.checked }))}
|
|
249
|
-
/>
|
|
250
|
-
<span>Network</span>
|
|
251
|
-
</label>
|
|
276
|
+
Network
|
|
277
|
+
</WorkflowCheckbox>
|
|
252
278
|
</div>
|
|
253
279
|
);
|
|
254
280
|
})}
|
|
@@ -315,7 +341,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
315
341
|
rows={2}
|
|
316
342
|
value={synthesis?.config?.outcomePrompt || ""}
|
|
317
343
|
disabled={disabled}
|
|
318
|
-
onChange={(e) => patchGraph((g) => patchSynthesis(g, { outcomePrompt: e.target.value }))}
|
|
344
|
+
onChange={(e) => patchGraph((g) => patchSynthesis(g, { outcomePrompt: e.target.value }, objectId, rowName))}
|
|
319
345
|
/>
|
|
320
346
|
</label>
|
|
321
347
|
</div>
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ApiRegistryCreationCockpit — the governed creation interface for one API,
|
|
7
|
+
* rendered inside the existing api-registry record drawer (DataModelShell).
|
|
8
|
+
*
|
|
9
|
+
* Renders the ordered journey from `deriveApiRegistryCreationState`
|
|
10
|
+
* (lib/api-registry-creation-flow.js) plus, once the API is tested, the response
|
|
11
|
+
* Shape analysis (`profileApiResponse` / `recommendResolver`) and a receipts log
|
|
12
|
+
* of real actions. Every actionable step's button calls back into the drawer's
|
|
13
|
+
* existing governed handlers via `onAction(action)` — status, the highlighted
|
|
14
|
+
* "next" step, the activation score, and which buttons are live all come from
|
|
15
|
+
* derivation/real responses, never guessed.
|
|
16
|
+
*
|
|
17
|
+
* Visual language is the workspace's own: the `.dm-db-status` chip and `dm-btn-*`
|
|
18
|
+
* buttons. No invented colors, no new primitive.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const STEP_STATUS = {
|
|
22
|
+
complete: { mod: "ok", label: "Done" },
|
|
23
|
+
active: { mod: "warn", label: "Next" },
|
|
24
|
+
pending: { mod: "", label: "Pending" },
|
|
25
|
+
blocked: { mod: "", label: "Blocked" },
|
|
26
|
+
optional: { mod: "", label: "Optional" },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const RESOLVER_LEVEL = {
|
|
30
|
+
optional: { mod: "", label: "Resolver optional" },
|
|
31
|
+
recommended: { mod: "warn", label: "Resolver recommended" },
|
|
32
|
+
required: { mod: "bad", label: "Resolver required" },
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function StatusChip({ mod, children, className = "" }) {
|
|
36
|
+
return (
|
|
37
|
+
<span className={`dm-db-status${mod ? ` ${mod}` : ""}${className ? ` ${className}` : ""}`}>
|
|
38
|
+
<span />
|
|
39
|
+
{children}
|
|
40
|
+
</span>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function ApiRegistryCreationCockpit({
|
|
45
|
+
state,
|
|
46
|
+
onAction,
|
|
47
|
+
busyAction = "",
|
|
48
|
+
disabled = false,
|
|
49
|
+
profile = null,
|
|
50
|
+
resolverRec = null,
|
|
51
|
+
receipts = [],
|
|
52
|
+
dataSourcePreview = null,
|
|
53
|
+
eyebrow = "Governed creation",
|
|
54
|
+
defaultCollapsed = false,
|
|
55
|
+
hideWhenComplete = false,
|
|
56
|
+
onCollapsedChange,
|
|
57
|
+
}) {
|
|
58
|
+
const [collapsed, setCollapsed] = useState(defaultCollapsed);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
setCollapsed(defaultCollapsed || Boolean(hideWhenComplete && state?.complete));
|
|
61
|
+
}, [defaultCollapsed, hideWhenComplete, state?.complete, state?.integrationId]);
|
|
62
|
+
if (!state || !Array.isArray(state.steps)) return null;
|
|
63
|
+
if (hideWhenComplete && state.complete) return null;
|
|
64
|
+
const candidates = profile?.candidates || {};
|
|
65
|
+
const candidateEntries = Object.entries(candidates).filter(([, v]) => v);
|
|
66
|
+
const previewRow = dataSourcePreview?.row || null;
|
|
67
|
+
const toggleCollapsed = () => {
|
|
68
|
+
const next = !collapsed;
|
|
69
|
+
setCollapsed(next);
|
|
70
|
+
onCollapsedChange?.(next);
|
|
71
|
+
};
|
|
72
|
+
const runAction = (action) => {
|
|
73
|
+
if (action?.id === "edit") {
|
|
74
|
+
setCollapsed(true);
|
|
75
|
+
onCollapsedChange?.(true);
|
|
76
|
+
}
|
|
77
|
+
onAction?.(action);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<section className={`dm-api-action-card dm-cockpit${collapsed ? " is-collapsed" : ""}`} aria-label="API creation journey">
|
|
82
|
+
<button
|
|
83
|
+
type="button"
|
|
84
|
+
className="dm-cockpit-head"
|
|
85
|
+
aria-expanded={!collapsed}
|
|
86
|
+
onClick={toggleCollapsed}
|
|
87
|
+
>
|
|
88
|
+
<div className="dm-api-action-card-body">
|
|
89
|
+
<p className="dm-api-action-card-eyebrow">{eyebrow} · {state.score}% activated</p>
|
|
90
|
+
<h3>{state.headline}</h3>
|
|
91
|
+
</div>
|
|
92
|
+
<span className="dm-cockpit-count">{state.completedCount}/{state.totalCount}</span>
|
|
93
|
+
</button>
|
|
94
|
+
|
|
95
|
+
{!collapsed && <ol className="dm-cockpit-steps">
|
|
96
|
+
{state.steps.map((step) => {
|
|
97
|
+
const meta = STEP_STATUS[step.status] || STEP_STATUS.pending;
|
|
98
|
+
const isNext = step.id === state.nextStepId;
|
|
99
|
+
const action = step.action;
|
|
100
|
+
const isBusy = action && busyAction === `${step.id}:${action.id}`;
|
|
101
|
+
return (
|
|
102
|
+
<li
|
|
103
|
+
key={step.id}
|
|
104
|
+
className={`dm-cockpit-step${isNext ? " dm-cockpit-step-next" : ""}${step.status === "blocked" ? " dm-cockpit-step-muted" : ""}`}
|
|
105
|
+
>
|
|
106
|
+
<StatusChip mod={meta.mod} className="dm-cockpit-step-chip">{meta.label}</StatusChip>
|
|
107
|
+
<div className="dm-cockpit-step-body">
|
|
108
|
+
<p className="dm-cockpit-step-label">{step.label}</p>
|
|
109
|
+
<p className="dm-cockpit-step-desc">{step.description}</p>
|
|
110
|
+
{step.hint ? <p className="dm-cockpit-step-hint">{step.hint}</p> : null}
|
|
111
|
+
</div>
|
|
112
|
+
{action ? (
|
|
113
|
+
<button
|
|
114
|
+
type="button"
|
|
115
|
+
className={isNext ? "dm-btn-primary-sm" : "dm-btn-outline"}
|
|
116
|
+
disabled={disabled || Boolean(busyAction)}
|
|
117
|
+
onClick={() => runAction(action)}
|
|
118
|
+
>
|
|
119
|
+
{isBusy ? "Working…" : action.label}
|
|
120
|
+
</button>
|
|
121
|
+
) : null}
|
|
122
|
+
</li>
|
|
123
|
+
);
|
|
124
|
+
})}
|
|
125
|
+
</ol>}
|
|
126
|
+
|
|
127
|
+
{!collapsed && profile && profile.parsed ? (
|
|
128
|
+
<div className="dm-cockpit-shape">
|
|
129
|
+
<div className="dm-cockpit-shape-head">
|
|
130
|
+
<p className="dm-api-action-card-eyebrow">Response shape</p>
|
|
131
|
+
{resolverRec ? (
|
|
132
|
+
<StatusChip mod={(RESOLVER_LEVEL[resolverRec.level] || RESOLVER_LEVEL.optional).mod}>
|
|
133
|
+
{(RESOLVER_LEVEL[resolverRec.level] || RESOLVER_LEVEL.optional).label}
|
|
134
|
+
</StatusChip>
|
|
135
|
+
) : null}
|
|
136
|
+
</div>
|
|
137
|
+
<p className="dm-cockpit-step-desc">
|
|
138
|
+
{profile.usable
|
|
139
|
+
? `${profile.recordCount} record${profile.recordCount === 1 ? "" : "s"}${profile.arrayPath ? ` at "${profile.arrayPath}"` : " (top-level)"} · entity "${profile.suggestedEntityType}".`
|
|
140
|
+
: "No record array detected in the response."}
|
|
141
|
+
</p>
|
|
142
|
+
{resolverRec ? <p className="dm-cockpit-step-hint">{resolverRec.reason}</p> : null}
|
|
143
|
+
{candidateEntries.length ? (
|
|
144
|
+
<div className="dm-cockpit-fields">
|
|
145
|
+
{candidateEntries.map(([role, name]) => (
|
|
146
|
+
<span key={role} className="dm-cockpit-field"><b>{role}</b>{name}</span>
|
|
147
|
+
))}
|
|
148
|
+
</div>
|
|
149
|
+
) : null}
|
|
150
|
+
{profile.hasPagination ? (
|
|
151
|
+
<p className="dm-cockpit-step-hint">Pagination keys present — a resolver is needed to fetch every page.</p>
|
|
152
|
+
) : null}
|
|
153
|
+
</div>
|
|
154
|
+
) : null}
|
|
155
|
+
|
|
156
|
+
{!collapsed && previewRow ? (
|
|
157
|
+
<div className="dm-cockpit-shape">
|
|
158
|
+
<p className="dm-api-action-card-eyebrow">Data Source preview</p>
|
|
159
|
+
<p className="dm-cockpit-step-desc">
|
|
160
|
+
Create will add a live-backed Data Source object that references this API by <code>registryId</code> and writes records to the source-records sidecar. Nothing fetches until you Refresh.
|
|
161
|
+
</p>
|
|
162
|
+
<div className="dm-cockpit-fields">
|
|
163
|
+
<span className="dm-cockpit-field"><b>name</b>{previewRow.Name}</span>
|
|
164
|
+
<span className="dm-cockpit-field"><b>sourceId</b>{previewRow.sourceId}</span>
|
|
165
|
+
<span className="dm-cockpit-field"><b>storage</b>{previewRow.sourceStorage}</span>
|
|
166
|
+
<span className="dm-cockpit-field"><b>entity</b>{previewRow.entityType}</span>
|
|
167
|
+
<span className="dm-cockpit-field"><b>registryId</b>{previewRow.registryId}</span>
|
|
168
|
+
{previewRow.authRef ? <span className="dm-cockpit-field"><b>authRef</b>{previewRow.authRef}</span> : null}
|
|
169
|
+
</div>
|
|
170
|
+
{Array.isArray(dataSourcePreview.fields) && dataSourcePreview.fields.length ? (
|
|
171
|
+
<>
|
|
172
|
+
<p className="dm-cockpit-step-hint">Detected fields it will carry:</p>
|
|
173
|
+
<div className="dm-cockpit-fields">
|
|
174
|
+
{dataSourcePreview.fields.slice(0, 10).map((f) => (
|
|
175
|
+
<span key={f.name} className="dm-cockpit-field"><b>{f.role || f.type}</b>{f.name}</span>
|
|
176
|
+
))}
|
|
177
|
+
</div>
|
|
178
|
+
</>
|
|
179
|
+
) : null}
|
|
180
|
+
</div>
|
|
181
|
+
) : null}
|
|
182
|
+
|
|
183
|
+
{!collapsed && Array.isArray(receipts) && receipts.length ? (
|
|
184
|
+
<div className="dm-cockpit-receipts">
|
|
185
|
+
<p className="dm-api-action-card-eyebrow">Receipts</p>
|
|
186
|
+
<ul>
|
|
187
|
+
{receipts.slice(0, 6).map((r, i) => (
|
|
188
|
+
<li key={`${r.at}-${i}`} className="dm-cockpit-receipt">
|
|
189
|
+
<StatusChip mod={r.ok ? "ok" : "bad"} className="dm-cockpit-receipt-chip">{r.kind}</StatusChip>
|
|
190
|
+
<span className="dm-cockpit-receipt-text">{r.detail}</span>
|
|
191
|
+
</li>
|
|
192
|
+
))}
|
|
193
|
+
</ul>
|
|
194
|
+
</div>
|
|
195
|
+
) : null}
|
|
196
|
+
</section>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export default ApiRegistryCreationCockpit;
|