@growthub/cli 0.12.2 → 0.13.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/sandbox-run/route.js +50 -25
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/ApiRegistryActionCard.jsx +141 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/ApiRegistryReviewModal.jsx +38 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/DataModelShell.jsx +556 -248
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationGraphCanvas.jsx +242 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationGraphEmptyCanvas.jsx +52 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationNodeConfigPanel.jsx +1203 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationRunTracePanel.jsx +163 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxOrchestrationEditorPanel.jsx +190 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxToolConfirmModal.jsx +64 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxToolDraftPanel.jsx +376 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/dm-shared.jsx +8 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/page.jsx +6 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +2897 -934
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/page.jsx +10 -7
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/views/[viewId]/page.jsx +206 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/WorkflowSurface.jsx +906 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/page.jsx +12 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-builder.jsx +493 -28
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-rail.jsx +1363 -8
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/data-model/field-contracts.js +1 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/nav-workflows.js +54 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph-runner.js +322 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph.js +734 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-trace.js +73 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-sidecar-routing.js +24 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +13 -4
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-helper-apply.js +96 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-schema.js +122 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse sandbox row lastResponse / source-record run entries for trace viewer UI.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { redactSecretsFromText } from "./orchestration-graph.js";
|
|
6
|
+
|
|
7
|
+
function safeParseJson(text) {
|
|
8
|
+
const raw = String(text || "").trim();
|
|
9
|
+
if (!raw) return null;
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(raw);
|
|
12
|
+
} catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function parseSandboxRunTrace(lastResponse) {
|
|
18
|
+
const parsed = safeParseJson(lastResponse);
|
|
19
|
+
if (!parsed || typeof parsed !== "object") {
|
|
20
|
+
return {
|
|
21
|
+
status: "",
|
|
22
|
+
runId: "",
|
|
23
|
+
exitCode: null,
|
|
24
|
+
durationMs: null,
|
|
25
|
+
runtime: "",
|
|
26
|
+
adapter: "",
|
|
27
|
+
runLocality: "",
|
|
28
|
+
error: "",
|
|
29
|
+
stdout: "",
|
|
30
|
+
stderr: "",
|
|
31
|
+
output: "",
|
|
32
|
+
ranAt: "",
|
|
33
|
+
envRefsResolved: [],
|
|
34
|
+
envRefsMissing: []
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const outputRaw = parsed.output ?? parsed.normalizedOutput ?? parsed.response;
|
|
38
|
+
return {
|
|
39
|
+
status: parsed.status || (parsed.exitCode === 0 && !parsed.error ? "connected" : parsed.error ? "failed" : ""),
|
|
40
|
+
runId: String(parsed.runId || "").trim(),
|
|
41
|
+
exitCode: parsed.exitCode ?? null,
|
|
42
|
+
durationMs: parsed.durationMs ?? null,
|
|
43
|
+
runtime: String(parsed.runtime || "").trim(),
|
|
44
|
+
adapter: String(parsed.adapter || "").trim(),
|
|
45
|
+
runLocality: String(parsed.runLocality || "").trim(),
|
|
46
|
+
error: redactSecretsFromText(parsed.error || ""),
|
|
47
|
+
stdout: redactSecretsFromText(typeof parsed.stdout === "string" ? parsed.stdout : JSON.stringify(parsed.stdout ?? "", null, 2)),
|
|
48
|
+
stderr: redactSecretsFromText(parsed.stderr || ""),
|
|
49
|
+
output: redactSecretsFromText(
|
|
50
|
+
typeof outputRaw === "string" ? outputRaw : JSON.stringify(outputRaw ?? "", null, 2)
|
|
51
|
+
),
|
|
52
|
+
ranAt: String(parsed.ranAt || "").trim(),
|
|
53
|
+
envRefsResolved: Array.isArray(parsed.envRefsResolved) ? parsed.envRefsResolved : [],
|
|
54
|
+
envRefsMissing: Array.isArray(parsed.envRefsMissing) ? parsed.envRefsMissing : []
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function normalizeRunRecord(record) {
|
|
59
|
+
if (!record || typeof record !== "object") return null;
|
|
60
|
+
return {
|
|
61
|
+
runId: String(record.runId || "").trim(),
|
|
62
|
+
ranAt: String(record.ranAt || "").trim(),
|
|
63
|
+
exitCode: record.exitCode ?? null,
|
|
64
|
+
durationMs: record.durationMs ?? null,
|
|
65
|
+
error: redactSecretsFromText(record.error || ""),
|
|
66
|
+
stdout: redactSecretsFromText(typeof record.stdout === "string" ? record.stdout : ""),
|
|
67
|
+
stderr: redactSecretsFromText(record.stderr || ""),
|
|
68
|
+
lifecycleStatus: String(record.lifecycleStatus || "").trim(),
|
|
69
|
+
version: String(record.version || "").trim()
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { parseSandboxRunTrace, normalizeRunRecord, safeParseJson };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure routing for connector menu → node + config tab (sidecar UX contract).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
function resolveConnectorAction({ from, to, action }) {
|
|
6
|
+
const result = { nodeId: "input", tab: "node" };
|
|
7
|
+
if (action === "filter") {
|
|
8
|
+
if (to === "transform" || from === "api-request") {
|
|
9
|
+
result.nodeId = "transform";
|
|
10
|
+
} else {
|
|
11
|
+
result.nodeId = "input";
|
|
12
|
+
}
|
|
13
|
+
result.tab = "filters";
|
|
14
|
+
} else if (action === "map") {
|
|
15
|
+
result.nodeId = "transform";
|
|
16
|
+
result.tab = "node";
|
|
17
|
+
} else if (action === "preview") {
|
|
18
|
+
result.nodeId = "result";
|
|
19
|
+
result.tab = "preview";
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { resolveConnectorAction };
|
|
@@ -289,12 +289,19 @@ function deriveManualObjectTable(object) {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
// Helper-owned hidden objects — system-managed, never surfaced in the
|
|
292
|
-
// user-facing Data Model picker / object list / dynamic title.
|
|
293
|
-
//
|
|
294
|
-
//
|
|
295
|
-
//
|
|
292
|
+
// user-facing Data Model picker / object list / dynamic title.
|
|
293
|
+
//
|
|
294
|
+
// - `workspace-helper-sandbox` backs the helper's local-intelligence
|
|
295
|
+
// sandbox primitive (helper-tuned instructions live there); users
|
|
296
|
+
// interact with it only through the helper Setup tab.
|
|
297
|
+
// - `nav-folders` backs the Custom Folders Navigation module rendered
|
|
298
|
+
// in the workspace rail (between the tab toggles and the Home / Chat
|
|
299
|
+
// body). Users create, rename, drag, and add items entirely from the
|
|
300
|
+
// rail; the row-level structure is never exposed in the Data Model
|
|
301
|
+
// admin surface so the core governed business objects stay clean.
|
|
296
302
|
const HIDDEN_HELPER_OBJECT_IDS = new Set([
|
|
297
303
|
"workspace-helper-sandbox",
|
|
304
|
+
"nav-folders",
|
|
298
305
|
]);
|
|
299
306
|
|
|
300
307
|
function listWorkspaceDataModelTables(workspaceConfig) {
|
|
@@ -724,6 +731,8 @@ const OBJECT_TYPE_PRESETS = {
|
|
|
724
731
|
"lastRunId",
|
|
725
732
|
"lastSourceId",
|
|
726
733
|
"lastResponse",
|
|
734
|
+
"orchestrationGraph",
|
|
735
|
+
"description",
|
|
727
736
|
"resolverTemplateId",
|
|
728
737
|
"connectorKind",
|
|
729
738
|
"executionLane"
|
|
@@ -461,6 +461,92 @@ function nextThreadId() {
|
|
|
461
461
|
return `thr_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
462
462
|
}
|
|
463
463
|
|
|
464
|
+
/**
|
|
465
|
+
* Custom Folders Navigation — governed end-user organization layer.
|
|
466
|
+
*
|
|
467
|
+
* Same well-known custom-typed Data Model object pattern as
|
|
468
|
+
* `helper-threads`: one object (id = "nav-folders") whose `rows[]` carry
|
|
469
|
+
* the user's folder structure. Each row is a folder. Folder items
|
|
470
|
+
* (dashboard links, lightweight views of governed objects) are nested
|
|
471
|
+
* inside the row as a JSON-serialisable `items[]` array.
|
|
472
|
+
*
|
|
473
|
+
* Persists through the existing PATCH allowlist on `/api/workspace`
|
|
474
|
+
* (`dataModel`), is round-trip validated by `validateWorkspaceConfig`,
|
|
475
|
+
* is hidden from the user-facing Data Model picker via
|
|
476
|
+
* `HIDDEN_HELPER_OBJECT_IDS` in `lib/workspace-data-model.js`, and is
|
|
477
|
+
* fully backwards compatible — if the object is missing the rail simply
|
|
478
|
+
* shows zero folders and the user can add one with the `+` button.
|
|
479
|
+
*
|
|
480
|
+
* Row shape (validated in `lib/workspace-schema.js`):
|
|
481
|
+
*
|
|
482
|
+
* {
|
|
483
|
+
* id: "fld_…",
|
|
484
|
+
* name: "Sales Pipeline",
|
|
485
|
+
* order: 0,
|
|
486
|
+
* collapsed: false,
|
|
487
|
+
* items: [
|
|
488
|
+
* { id: "item_…", type: "dashboard", refId: "dash-abc",
|
|
489
|
+
* label: "Revenue Overview" },
|
|
490
|
+
* { id: "item_…", type: "view", objectId: "prospects",
|
|
491
|
+
* label: "Active Prospects",
|
|
492
|
+
* viewConfig: { columns: [...], filters: [...], sort: {...} } }
|
|
493
|
+
* ]
|
|
494
|
+
* }
|
|
495
|
+
*/
|
|
496
|
+
|
|
497
|
+
const NAV_FOLDERS_OBJECT_ID = "nav-folders";
|
|
498
|
+
const NAV_FOLDERS_LABEL = "Custom Folders";
|
|
499
|
+
const NAV_FOLDER_NAME_MAX = 60;
|
|
500
|
+
const NAV_ITEM_LABEL_MAX = 80;
|
|
501
|
+
const NAV_ITEM_TYPES = new Set(["dashboard", "view"]);
|
|
502
|
+
|
|
503
|
+
function ensureNavFoldersObject(config) {
|
|
504
|
+
const dm = config?.dataModel && typeof config.dataModel === "object" ? config.dataModel : {};
|
|
505
|
+
const objects = Array.isArray(dm.objects) ? dm.objects.slice() : [];
|
|
506
|
+
const idx = objects.findIndex((o) => o?.id === NAV_FOLDERS_OBJECT_ID);
|
|
507
|
+
if (idx >= 0) {
|
|
508
|
+
const existing = objects[idx];
|
|
509
|
+
if (!Array.isArray(existing.rows)) {
|
|
510
|
+
objects[idx] = { ...existing, rows: [] };
|
|
511
|
+
}
|
|
512
|
+
return { ...config, dataModel: { ...dm, objects } };
|
|
513
|
+
}
|
|
514
|
+
const seeded = {
|
|
515
|
+
id: NAV_FOLDERS_OBJECT_ID,
|
|
516
|
+
label: NAV_FOLDERS_LABEL,
|
|
517
|
+
source: NAV_FOLDERS_LABEL,
|
|
518
|
+
objectType: "custom",
|
|
519
|
+
icon: "Folder",
|
|
520
|
+
columns: ["name", "order", "collapsed", "items"],
|
|
521
|
+
rows: [],
|
|
522
|
+
binding: { mode: "manual", source: NAV_FOLDERS_LABEL },
|
|
523
|
+
};
|
|
524
|
+
return { ...config, dataModel: { ...dm, objects: [...objects, seeded] } };
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function nextNavFolderId() {
|
|
528
|
+
return `fld_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function nextNavItemId() {
|
|
532
|
+
return `item_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function getNavFolderRows(config) {
|
|
536
|
+
const obj = (config?.dataModel?.objects || []).find((o) => o?.id === NAV_FOLDERS_OBJECT_ID);
|
|
537
|
+
return Array.isArray(obj?.rows) ? obj.rows : [];
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
function writeNavFolderRows(config, rows) {
|
|
541
|
+
const withObject = ensureNavFoldersObject(config);
|
|
542
|
+
const dm = withObject.dataModel;
|
|
543
|
+
const objects = dm.objects.slice();
|
|
544
|
+
const idx = objects.findIndex((o) => o?.id === NAV_FOLDERS_OBJECT_ID);
|
|
545
|
+
if (idx === -1) return withObject;
|
|
546
|
+
objects[idx] = { ...objects[idx], rows: rows.map((row, i) => ({ ...row, order: i })) };
|
|
547
|
+
return { ...withObject, dataModel: { ...dm, objects } };
|
|
548
|
+
}
|
|
549
|
+
|
|
464
550
|
export {
|
|
465
551
|
applyProposalToConfig,
|
|
466
552
|
validateProposalForApply,
|
|
@@ -470,4 +556,14 @@ export {
|
|
|
470
556
|
nextThreadId,
|
|
471
557
|
HELPER_THREADS_OBJECT_ID,
|
|
472
558
|
ALLOWED_PATCH_FIELDS,
|
|
559
|
+
NAV_FOLDERS_OBJECT_ID,
|
|
560
|
+
NAV_FOLDERS_LABEL,
|
|
561
|
+
NAV_FOLDER_NAME_MAX,
|
|
562
|
+
NAV_ITEM_LABEL_MAX,
|
|
563
|
+
NAV_ITEM_TYPES,
|
|
564
|
+
ensureNavFoldersObject,
|
|
565
|
+
nextNavFolderId,
|
|
566
|
+
nextNavItemId,
|
|
567
|
+
getNavFolderRows,
|
|
568
|
+
writeNavFolderRows,
|
|
473
569
|
};
|
|
@@ -963,6 +963,11 @@ function validateSandboxEnvironmentRow(row, path, errors) {
|
|
|
963
963
|
errors.push(`${path}.intelligenceAdapterMode must be one of ${INTELLIGENCE_ADAPTER_MODES.join(", ")}`);
|
|
964
964
|
}
|
|
965
965
|
}
|
|
966
|
+
if (row.orchestrationGraph !== undefined && row.orchestrationGraph !== null && row.orchestrationGraph !== "") {
|
|
967
|
+
if (typeof row.orchestrationGraph !== "string" && (typeof row.orchestrationGraph !== "object" || Array.isArray(row.orchestrationGraph))) {
|
|
968
|
+
errors.push(`${path}.orchestrationGraph must be a JSON string or plain object`);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
966
971
|
if (row.envRefs !== undefined && typeof row.envRefs !== "string" && !Array.isArray(row.envRefs)) {
|
|
967
972
|
errors.push(`${path}.envRefs must be a comma-separated string or array of env-ref slugs (never values)`);
|
|
968
973
|
}
|
|
@@ -1000,6 +1005,116 @@ function validateSandboxEnvironmentRow(row, path, errors) {
|
|
|
1000
1005
|
}
|
|
1001
1006
|
}
|
|
1002
1007
|
|
|
1008
|
+
const NAV_FOLDERS_OBJECT_ID = "nav-folders";
|
|
1009
|
+
const NAV_FOLDER_NAME_MAX = 60;
|
|
1010
|
+
const NAV_ITEM_LABEL_MAX = 80;
|
|
1011
|
+
const NAV_ITEM_TYPES = ["dashboard", "view", "workflow"];
|
|
1012
|
+
|
|
1013
|
+
function validateNavFolderRow(row, path, errors) {
|
|
1014
|
+
if (!isPlainObject(row)) return;
|
|
1015
|
+
if (typeof row.id !== "string" || !row.id.trim()) {
|
|
1016
|
+
errors.push(`${path}.id must be a non-empty string`);
|
|
1017
|
+
}
|
|
1018
|
+
if (typeof row.name !== "string" || !row.name.trim()) {
|
|
1019
|
+
errors.push(`${path}.name must be a non-empty string`);
|
|
1020
|
+
} else if (row.name.length > NAV_FOLDER_NAME_MAX) {
|
|
1021
|
+
errors.push(`${path}.name must be ${NAV_FOLDER_NAME_MAX} characters or fewer`);
|
|
1022
|
+
}
|
|
1023
|
+
if (row.order !== undefined && !isFiniteInt(row.order)) {
|
|
1024
|
+
errors.push(`${path}.order must be a finite integer when present`);
|
|
1025
|
+
}
|
|
1026
|
+
if (row.collapsed !== undefined && typeof row.collapsed !== "boolean") {
|
|
1027
|
+
errors.push(`${path}.collapsed must be a boolean when present`);
|
|
1028
|
+
}
|
|
1029
|
+
if (row.icon !== undefined && typeof row.icon !== "string") {
|
|
1030
|
+
errors.push(`${path}.icon must be a string when present`);
|
|
1031
|
+
}
|
|
1032
|
+
if (row.color !== undefined && typeof row.color !== "string") {
|
|
1033
|
+
errors.push(`${path}.color must be a string when present`);
|
|
1034
|
+
}
|
|
1035
|
+
if (row.iconBg !== undefined && typeof row.iconBg !== "string") {
|
|
1036
|
+
errors.push(`${path}.iconBg must be a string when present`);
|
|
1037
|
+
}
|
|
1038
|
+
if (row.items === undefined) return;
|
|
1039
|
+
if (!Array.isArray(row.items)) {
|
|
1040
|
+
errors.push(`${path}.items must be an array`);
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
const seenItemIds = new Set();
|
|
1044
|
+
row.items.forEach((item, index) => {
|
|
1045
|
+
const ipfx = `${path}.items[${index}]`;
|
|
1046
|
+
if (!isPlainObject(item)) {
|
|
1047
|
+
errors.push(`${ipfx} must be a plain object`);
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
if (typeof item.id !== "string" || !item.id.trim()) {
|
|
1051
|
+
errors.push(`${ipfx}.id must be a non-empty string`);
|
|
1052
|
+
} else if (seenItemIds.has(item.id)) {
|
|
1053
|
+
errors.push(`${ipfx}.id duplicates an earlier item id in this folder`);
|
|
1054
|
+
} else {
|
|
1055
|
+
seenItemIds.add(item.id);
|
|
1056
|
+
}
|
|
1057
|
+
if (!NAV_ITEM_TYPES.includes(item.type)) {
|
|
1058
|
+
errors.push(`${ipfx}.type must be one of ${NAV_ITEM_TYPES.join(", ")}`);
|
|
1059
|
+
}
|
|
1060
|
+
if (item.label !== undefined) {
|
|
1061
|
+
if (typeof item.label !== "string") {
|
|
1062
|
+
errors.push(`${ipfx}.label must be a string when present`);
|
|
1063
|
+
} else if (item.label.length > NAV_ITEM_LABEL_MAX) {
|
|
1064
|
+
errors.push(`${ipfx}.label must be ${NAV_ITEM_LABEL_MAX} characters or fewer`);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
if (item.icon !== undefined && typeof item.icon !== "string") {
|
|
1068
|
+
errors.push(`${ipfx}.icon must be a string when present`);
|
|
1069
|
+
}
|
|
1070
|
+
if (item.color !== undefined && typeof item.color !== "string") {
|
|
1071
|
+
errors.push(`${ipfx}.color must be a string when present`);
|
|
1072
|
+
}
|
|
1073
|
+
if (item.iconBg !== undefined && typeof item.iconBg !== "string") {
|
|
1074
|
+
errors.push(`${ipfx}.iconBg must be a string when present`);
|
|
1075
|
+
}
|
|
1076
|
+
if (item.type === "dashboard") {
|
|
1077
|
+
if (typeof item.refId !== "string" || !item.refId.trim()) {
|
|
1078
|
+
errors.push(`${ipfx}.refId must be a non-empty string for dashboard items`);
|
|
1079
|
+
}
|
|
1080
|
+
} else if (item.type === "view") {
|
|
1081
|
+
if (typeof item.objectId !== "string" || !item.objectId.trim()) {
|
|
1082
|
+
errors.push(`${ipfx}.objectId must be a non-empty string for view items`);
|
|
1083
|
+
}
|
|
1084
|
+
if (item.viewConfig !== undefined) {
|
|
1085
|
+
if (!isPlainObject(item.viewConfig)) {
|
|
1086
|
+
errors.push(`${ipfx}.viewConfig must be a plain object when present`);
|
|
1087
|
+
} else {
|
|
1088
|
+
if (item.viewConfig.columns !== undefined) {
|
|
1089
|
+
validateStringArray(item.viewConfig.columns, `${ipfx}.viewConfig.columns`, errors);
|
|
1090
|
+
}
|
|
1091
|
+
if (item.viewConfig.filters !== undefined && !Array.isArray(item.viewConfig.filters)) {
|
|
1092
|
+
errors.push(`${ipfx}.viewConfig.filters must be an array when present`);
|
|
1093
|
+
}
|
|
1094
|
+
if (item.viewConfig.sort !== undefined && !isPlainObject(item.viewConfig.sort)) {
|
|
1095
|
+
errors.push(`${ipfx}.viewConfig.sort must be a plain object when present`);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
} else if (item.type === "workflow") {
|
|
1100
|
+
if (typeof item.objectId !== "string" || !item.objectId.trim()) {
|
|
1101
|
+
errors.push(`${ipfx}.objectId must be a non-empty string for workflow items`);
|
|
1102
|
+
}
|
|
1103
|
+
if (typeof item.rowId !== "string" || !item.rowId.trim()) {
|
|
1104
|
+
errors.push(`${ipfx}.rowId must be a non-empty string for workflow items`);
|
|
1105
|
+
}
|
|
1106
|
+
if (item.fieldName !== undefined) {
|
|
1107
|
+
if (typeof item.fieldName !== "string" || !item.fieldName.trim()) {
|
|
1108
|
+
errors.push(`${ipfx}.fieldName must be a non-empty string when present`);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
if (item.orchestrationGraph !== undefined) {
|
|
1112
|
+
errors.push(`${ipfx} must not embed orchestrationGraph — workflow items are shortcuts only`);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1003
1118
|
function validateDataModelConfig(dataModel, errors) {
|
|
1004
1119
|
if (dataModel === undefined) return;
|
|
1005
1120
|
if (!isPlainObject(dataModel)) {
|
|
@@ -1040,6 +1155,9 @@ function validateDataModelConfig(dataModel, errors) {
|
|
|
1040
1155
|
if (object.objectType === "sandbox-environment") {
|
|
1041
1156
|
validateSandboxEnvironmentRow(row, `${prefix}.rows[${rowIndex}]`, errors);
|
|
1042
1157
|
}
|
|
1158
|
+
if (object.id === NAV_FOLDERS_OBJECT_ID) {
|
|
1159
|
+
validateNavFolderRow(row, `${prefix}.rows[${rowIndex}]`, errors);
|
|
1160
|
+
}
|
|
1043
1161
|
});
|
|
1044
1162
|
}
|
|
1045
1163
|
validateStaticDataBinding(object.binding, `${prefix}.binding`, errors);
|
|
@@ -1316,6 +1434,10 @@ export {
|
|
|
1316
1434
|
DEFAULT_SANDBOX_ADAPTER,
|
|
1317
1435
|
SANDBOX_DEFAULT_TIMEOUT_MS,
|
|
1318
1436
|
SANDBOX_MAX_TIMEOUT_MS,
|
|
1437
|
+
NAV_FOLDERS_OBJECT_ID,
|
|
1438
|
+
NAV_FOLDER_NAME_MAX,
|
|
1439
|
+
NAV_ITEM_LABEL_MAX,
|
|
1440
|
+
NAV_ITEM_TYPES,
|
|
1319
1441
|
NORMALIZED_OBJECT_FIELD_IDS,
|
|
1320
1442
|
SAMPLE_DATA_BINDINGS,
|
|
1321
1443
|
SAMPLE_VIEW_ROWS,
|
|
@@ -115,6 +115,7 @@
|
|
|
115
115
|
"apps/workspace/app/data-model/page.jsx",
|
|
116
116
|
"apps/workspace/app/data-model/components/DataModelShell.jsx",
|
|
117
117
|
"apps/workspace/app/data-model/components/HelperSidecar.jsx",
|
|
118
|
+
"apps/workspace/app/views/[viewId]/page.jsx",
|
|
118
119
|
"apps/workspace/lib/adapters/payments/index.js",
|
|
119
120
|
"apps/workspace/lib/adapters/persistence/index.js",
|
|
120
121
|
"apps/workspace/lib/adapters/persistence/postgres.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@growthub/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "CLI control plane for Growthub Local and Agent Workspace as Code: export, fork, inspect, operate, sync, and optionally activate governed AI workspaces.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|