fix(oracle-r4): curation contradiction + wizard view enrichment
Oracle round-7 remediation, items 2 + 7:
- flowCuration.NON_BUSINESS_SOURCE_CONTEXTS no longer lists
EA2_DRAFT_PROCESS:process_creation (it's in STARTABLE_SOURCE_CONTEXTS).
Adds CANVAS_AGENT_MEMORY + CANVAS_AGENT_VAULT_ROOT to NON_BUSINESS so
vault docs never leak into hubs / catalogue.
- wizardApi.createView now accepts a fields list and emits proper field
defs (name slug, label, type from {string,number,boolean,textarea}).
- Wizard.handleDataSave rebuilds every step's view with the user's
draft.fields after Generate phase, then rewires the presentation
edges to the new views. Steps now expose real business fields, not a
generic 'Notes' textarea.
This commit is contained in:
@@ -30,10 +30,11 @@ const NON_BUSINESS_SOURCE_CONTEXTS = new Set([
|
|||||||
"CANVAS_CHAT_INBOX",
|
"CANVAS_CHAT_INBOX",
|
||||||
"CANVAS_ATTENDANCE_ROOT",
|
"CANVAS_ATTENDANCE_ROOT",
|
||||||
"CANVAS_ATTENDANCE_SITE",
|
"CANVAS_ATTENDANCE_SITE",
|
||||||
|
"CANVAS_AGENT_MEMORY",
|
||||||
|
"CANVAS_AGENT_VAULT_ROOT",
|
||||||
"CANVAS_SEED_PROCESS",
|
"CANVAS_SEED_PROCESS",
|
||||||
"CANVAS_SEED_STEP",
|
"CANVAS_SEED_STEP",
|
||||||
"EA2_WIZARD_STEP",
|
"EA2_WIZARD_STEP",
|
||||||
"EA2_DRAFT_PROCESS:process_creation",
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const STARTABLE_FLOW_KEYS = new Set<string>([
|
export const STARTABLE_FLOW_KEYS = new Set<string>([
|
||||||
|
|||||||
+13
-7
@@ -139,9 +139,20 @@ export const wizardApi = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
createView(node: { display_name: string }): CreateOp {
|
createView(node: { display_name: string; fields?: { name: string; type: string }[] }): CreateOp {
|
||||||
const slug = node.display_name.toLowerCase().replace(/[^a-z0-9]+/g, "_").slice(0, 30) || "view";
|
const slug = node.display_name.toLowerCase().replace(/[^a-z0-9]+/g, "_").slice(0, 30) || "view";
|
||||||
const name = `${slug}_view_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`;
|
const name = `${slug}_view_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`;
|
||||||
|
const TYPE_MAP: Record<string, string> = { string: "string", number: "number", boolean: "boolean", textarea: "textarea" };
|
||||||
|
const fieldDefs =
|
||||||
|
node.fields && node.fields.length > 0
|
||||||
|
? node.fields
|
||||||
|
.filter((f) => f.name && f.name.trim())
|
||||||
|
.map((f) => {
|
||||||
|
const fieldSlug = f.name.toLowerCase().replace(/[^a-z0-9]+/g, "_").slice(0, 40);
|
||||||
|
const label = f.name.charAt(0).toUpperCase() + f.name.slice(1);
|
||||||
|
return { name: fieldSlug, label, type: TYPE_MAP[f.type] || "string", required: true, description: label };
|
||||||
|
})
|
||||||
|
: [{ name: "notes", label: "Notes", type: "textarea", required: false, description: "Notes for this step" }];
|
||||||
return {
|
return {
|
||||||
op: "create",
|
op: "create",
|
||||||
coll: "view",
|
coll: "view",
|
||||||
@@ -153,12 +164,7 @@ export const wizardApi = {
|
|||||||
description: null,
|
description: null,
|
||||||
source_context: null,
|
source_context: null,
|
||||||
channel: "web",
|
channel: "web",
|
||||||
layout: {
|
layout: { layout: "form", fields: fieldDefs },
|
||||||
layout: "form",
|
|
||||||
fields: [
|
|
||||||
{ name: "notes", label: "Notes", type: "textarea", required: false, description: "Notes" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
actions: [{ label: "Submit", action: "submit" }],
|
actions: [{ label: "Submit", action: "submit" }],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
+15
-3
@@ -144,13 +144,25 @@ export default function Wizard() {
|
|||||||
if (!draft.flowKey || !actor) return;
|
if (!draft.flowKey || !actor) return;
|
||||||
setWorking(true);
|
setWorking(true);
|
||||||
try {
|
try {
|
||||||
// In a real app we'd save proper data models here.
|
|
||||||
// For the spike we just move forward and do a dummy update
|
|
||||||
await wizardApi.updateDraftConfig(draft.flowKey, {
|
await wizardApi.updateDraftConfig(draft.flowKey, {
|
||||||
config: { wizard: { panelState: { fields: draft.fields } } }
|
config: { wizard: { panelState: { fields: draft.fields } } }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (draft.fields.length > 0 && draft.nodes.length > 0) {
|
||||||
|
const replaceOps: BatchOperation[] = draft.nodes.map(n =>
|
||||||
|
wizardApi.ops.createView({ display_name: n.display_name, fields: draft.fields })
|
||||||
|
);
|
||||||
|
const res = await wizardApi.applyBatch(draft.flowKey, replaceOps, actor);
|
||||||
|
const newViewKeys = (res?.result?.ops || []).map((o: any) => o.key);
|
||||||
|
const wireOps: BatchOperation[] = draft.nodes.map((n, i) =>
|
||||||
|
wizardApi.ops.presentationEdge(n._key, newViewKeys[i])
|
||||||
|
);
|
||||||
|
if (wireOps.length) await wizardApi.applyBatch(draft.flowKey, wireOps, actor);
|
||||||
|
updateDraft({ nodes: draft.nodes.map((n, i) => ({ ...n, viewKey: newViewKeys[i] })) });
|
||||||
|
}
|
||||||
|
|
||||||
updateDraft({ step: "Validate" });
|
updateDraft({ step: "Validate" });
|
||||||
pushToast("ok", "Data requirements saved");
|
pushToast("ok", `Saved ${draft.fields.length} fields onto every step's form`);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
pushToast("err", `Save failed: ${err.message}`);
|
pushToast("err", `Save failed: ${err.message}`);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user