diff --git a/packages/dashboard/app/components/WorkflowNodeEditor.css b/packages/dashboard/app/components/WorkflowNodeEditor.css
index 2d100a4964..0a4c759d38 100644
--- a/packages/dashboard/app/components/WorkflowNodeEditor.css
+++ b/packages/dashboard/app/components/WorkflowNodeEditor.css
@@ -80,12 +80,76 @@
display: flex;
flex-direction: column;
gap: var(--space-xs);
- width: 220px;
+ width: 300px;
padding: var(--space-sm);
border-right: 1px solid var(--border);
overflow-y: auto;
}
+/* U12: columns + fields authoring sections moved into the left sidebar, below
+ the workflow list. Each is a collapsible disclosure whose toggle button is the
+ section header; the panels' own internal
is suppressed to avoid a double
+ header. */
+.wf-sidebar-panels {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-xs);
+ margin-top: var(--space-sm);
+ padding-top: var(--space-sm);
+ border-top: 1px solid var(--border);
+}
+
+.wf-sidebar-section {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-xs);
+}
+
+.wf-sidebar-section-toggle {
+ display: flex;
+ align-items: center;
+ gap: var(--space-xs);
+ width: 100%;
+ padding: var(--space-xs) var(--space-sm);
+ background: transparent;
+ border: none;
+ border-radius: var(--radius-sm);
+ color: var(--text);
+ font-size: 0.7rem;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
+ cursor: pointer;
+}
+
+.wf-sidebar-section-toggle:hover {
+ background: var(--bg-secondary);
+}
+
+/* When nested in the sidebar disclosure, the panels are stacked full-width
+ blocks rather than side columns: drop the dedicated width/border and let them
+ flow inside the sidebar's own scroll. */
+.wf-sidebar-section .wf-column-panel,
+.wf-sidebar-section .wf-fields-panel {
+ width: auto;
+ min-width: 0;
+ padding: 0 var(--space-xs) var(--space-xs);
+ border-left: none;
+ overflow-y: visible;
+}
+
+/* The disclosure toggle is the visible section header; hide the panels' own
+ title heading to avoid a duplicate. The Add button (also in the header) stays. */
+.wf-sidebar-section .wf-column-panel-header h3,
+.wf-sidebar-section .wf-fields-panel-header h3 {
+ display: none;
+}
+
+.wf-sidebar-section .wf-column-panel-header,
+.wf-sidebar-section .wf-fields-panel-header {
+ justify-content: flex-end;
+}
+
.wf-editor-new {
display: inline-flex;
align-items: center;
diff --git a/packages/dashboard/app/components/WorkflowNodeEditor.tsx b/packages/dashboard/app/components/WorkflowNodeEditor.tsx
index 5273a104d3..545a040fc0 100644
--- a/packages/dashboard/app/components/WorkflowNodeEditor.tsx
+++ b/packages/dashboard/app/components/WorkflowNodeEditor.tsx
@@ -668,6 +668,40 @@ function InnerEditor({
});
const [templateFilter, setTemplateFilter] = useState("");
const [templateConflict, setTemplateConflict] = useState(null);
+
+ // U12: the columns/fields authoring panels live in the left sidebar (below the
+ // workflow list) as collapsible disclosure sections. Each section's collapsed
+ // state persists in localStorage; default expanded.
+ const columnsCollapsedStorageKey = "fusion:wf-sidebar-columns-collapsed";
+ const fieldsCollapsedStorageKey = "fusion:wf-sidebar-fields-collapsed";
+ const [columnsCollapsed, setColumnsCollapsed] = useState(() => {
+ try {
+ return localStorage.getItem(columnsCollapsedStorageKey) === "1";
+ } catch {
+ return false;
+ }
+ });
+ const [fieldsCollapsed, setFieldsCollapsed] = useState(() => {
+ try {
+ return localStorage.getItem(fieldsCollapsedStorageKey) === "1";
+ } catch {
+ return false;
+ }
+ });
+ useEffect(() => {
+ try {
+ localStorage.setItem(columnsCollapsedStorageKey, columnsCollapsed ? "1" : "0");
+ } catch {
+ // localStorage unavailable (private mode / SSR): non-fatal.
+ }
+ }, [columnsCollapsed]);
+ useEffect(() => {
+ try {
+ localStorage.setItem(fieldsCollapsedStorageKey, fieldsCollapsed ? "1" : "0");
+ } catch {
+ // localStorage unavailable (private mode / SSR): non-fatal.
+ }
+ }, [fieldsCollapsed]);
// Wrapper around so keyboard deletion can return focus to the
// canvas container (R6) instead of leaving it on a now-removed node.
const canvasRef = useRef(null);
@@ -1873,6 +1907,59 @@ function InnerEditor({
))}
)}
+
+ {/* U12: columns + fields authoring panels, below the workflow list,
+ each as a collapsible disclosure section. Only shown when a
+ workflow is active (read-only gating preserved via isBuiltin). The
+ disclosure button serves as the section header; the panels' own
+ internal is suppressed via CSS to avoid a double header. */}
+ {activeWorkflow && (
+
+
+
+ {!columnsCollapsed && (
+
+ )}
+
+
+
+
+ {!fieldsCollapsed && (
+
+ )}
+
+
+ )}
@@ -2336,26 +2423,6 @@ function InnerEditor({
)}
- {activeWorkflow && (
-
- )}
-
- {activeWorkflow && (
-
- )}
-
{selectedNode && selectedNode.data.kind !== "start" && selectedNode.data.kind !== "end" && (