From c7b3af3b14fb1bc558dcbc79006d6ba00f1becec Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Aug 2026 18:23:50 +0000 Subject: [PATCH 1/6] feat: let the host hide a subworkflow's Compute tab The job designer renders its own Compute tab, so a job screen offered two things called 'Compute' - the job's, and one per subworkflow - leaving the reader to guess which one the job would actually run with. New hideComputeSubTab prop on Workflow, threaded to Subworkflow through WorkflowDefaultLayout. Default false, so nothing changes for hosts that do not set it. Compute is the last tab, which is what lets it be dropped without renumbering the panels; an active index pointing at it falls back to Overview rather than leaving an empty panel behind. SOF-8023 phase 1.2. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01DK8KomMescJvMQNSEfeRR8 --- src/components/subworkflows/Subworkflow.tsx | 73 ++++++++++++------- src/components/workflows/Workflow.tsx | 9 +++ .../workflows/WorkflowDefaultLayout.tsx | 4 + 3 files changed, 61 insertions(+), 25 deletions(-) diff --git a/src/components/subworkflows/Subworkflow.tsx b/src/components/subworkflows/Subworkflow.tsx index 10118aa..6991be5 100644 --- a/src/components/subworkflows/Subworkflow.tsx +++ b/src/components/subworkflows/Subworkflow.tsx @@ -71,6 +71,13 @@ export type SubworkflowProps = { jobProperties?: WorkflowDesignerProperty[]; activeTabIndex: number; onActiveTabIndexChange: (tabIndex: number) => void; + /** + * Drops this subworkflow's own Compute tab. Set it when the host already + * shows a compute surface of its own — the job designer does, and two places + * called "Compute" on one screen leave the reader guessing which one the job + * will actually run with. + */ + hideComputeSubTab?: boolean; }; export const TAB_NAVIGATION_CONFIG = { @@ -96,6 +103,10 @@ export const TAB_NAVIGATION_CONFIG = { }, } as const; +const COMPUTE_TAB_NAME = TAB_NAVIGATION_CONFIG.compute.itemName; +/** Compute is the last tab, which is what lets it be dropped without renumbering the rest. */ +const COMPUTE_TAB_INDEX = Object.keys(TAB_NAVIGATION_CONFIG).indexOf("compute"); + export function Subworkflow({ subworkflow, onUpdate, @@ -121,6 +132,7 @@ export function Subworkflow({ jobProperties, activeTabIndex, onActiveTabIndexChange, + hideComputeSubTab = false, }: SubworkflowProps) { const { getDefaultComputeConfig } = useWorkflowComponents(); const [unitIndex, setUnitIndex] = useState(0); @@ -312,25 +324,34 @@ export function Subworkflow({ const tabs: WorkflowDesignerTabItem[] = useMemo( () => - Object.values(TAB_NAVIGATION_CONFIG).map((tab, index) => ({ - ...tab, - href: undefined, - onClick: (event) => { - event.preventDefault(); - setTabIndex(index); - }, - })), - [setTabIndex], + Object.values(TAB_NAVIGATION_CONFIG) + .map((tab, index) => ({ + ...tab, + href: undefined, + onClick: (event: React.MouseEvent) => { + event.preventDefault(); + setTabIndex(index); + }, + })) + // Compute is the last entry, so dropping it leaves the remaining + // tabs on the indices their panels are keyed to. + .filter((tab) => !(hideComputeSubTab && tab.itemName === COMPUTE_TAB_NAME)), + [setTabIndex, hideComputeSubTab], ); + // A subworkflow whose Compute tab was open when the host hid it would + // otherwise be left showing an empty panel. + const visibleTabIndex = + hideComputeSubTab && activeTabIndex === COMPUTE_TAB_INDEX ? 0 : activeTabIndex; + return ( - + - - - + {hideComputeSubTab ? null : ( + + + + )} ); diff --git a/src/components/workflows/Workflow.tsx b/src/components/workflows/Workflow.tsx index 3629b23..e8ea87d 100644 --- a/src/components/workflows/Workflow.tsx +++ b/src/components/workflows/Workflow.tsx @@ -93,6 +93,13 @@ export type WorkflowProps = { isDescriptionEditable: boolean; /** Refined job properties for unit modals in job designer; optional elsewhere. */ jobProperties?: WorkflowDesignerProperty[]; + /** + * Hides each subworkflow's own Compute tab. Set it when the host renders a + * compute surface of its own, as the job designer does — otherwise the same + * screen offers two things called "Compute" and the reader has to guess + * which one the job will run with. + */ + hideComputeSubTab?: boolean; }; const noop = (): undefined => undefined; @@ -153,6 +160,7 @@ export function Workflow({ workflowRenderGeneration, isDescriptionEditable, jobProperties, + hideComputeSubTab = false, }: WorkflowProps) { const [unitIndex, setUnitIndex] = useState(0); const [isRelaxationToggled, setIsRelaxationToggled] = useState(false); @@ -462,6 +470,7 @@ export function Workflow({ templates={templates} createMetaProperty={createMetaProperty} jobProperties={jobProperties} + hideComputeSubTab={hideComputeSubTab} subworkflowActiveTabIndexById={subworkflowActiveTabIndexById} onSubworkflowActiveTabIndexChange={onSubworkflowActiveTabIndexChange} /> diff --git a/src/components/workflows/WorkflowDefaultLayout.tsx b/src/components/workflows/WorkflowDefaultLayout.tsx index a97d166..b8c8aa1 100644 --- a/src/components/workflows/WorkflowDefaultLayout.tsx +++ b/src/components/workflows/WorkflowDefaultLayout.tsx @@ -125,6 +125,8 @@ export type WorkflowDefaultLayoutProps = { /** Subworkflow inner tabs (Overview, Important settings, …); owned by {@link Workflow} so remounts of {@link Subworkflow} do not reset them. */ subworkflowActiveTabIndexById: Record; onSubworkflowActiveTabIndexChange: (subworkflowId: string, tabIndex: number) => void; + /** See {@link SubworkflowProps.hideComputeSubTab}. */ + hideComputeSubTab?: boolean; }; export function WorkflowDefaultLayout(props: WorkflowDefaultLayoutProps) { @@ -181,6 +183,7 @@ export function WorkflowDefaultLayout(props: WorkflowDefaultLayoutProps) { jobProperties, subworkflowActiveTabIndexById, onSubworkflowActiveTabIndexChange, + hideComputeSubTab, } = props; const { EntityHeaderComponent, MetadataComponent, HistoryComponent } = useWorkflowComponents(); @@ -301,6 +304,7 @@ export function WorkflowDefaultLayout(props: WorkflowDefaultLayoutProps) { activeTabIndex={ subworkflowActiveTabIndexById[subworkflow.id] ?? 0 } + hideComputeSubTab={hideComputeSubTab} onActiveTabIndexChange={(tabIndex) => onSubworkflowActiveTabIndexChange( subworkflow.id, From ab7696e9ef9becdc5b1e0c8d2e4da1f9e27484e0 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Aug 2026 20:28:59 +0000 Subject: [PATCH 2/6] build: regenerate dist for hideComputeSubTab dist/ is tracked in this repo and the published package ships it. The husky pre-commit hook regenerates and stages it automatically (npm run transpile && git add dist/), but only once hooks are installed - there is no 'prepare: husky install' script here, so a fresh clone commits without it. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01DK8KomMescJvMQNSEfeRR8 --- dist/components/subworkflows/Subworkflow.d.ts | 9 ++++++++- .../subworkflows/Subworkflow.d.ts.map | 2 +- dist/components/subworkflows/Subworkflow.js | 18 ++++++++++++++---- dist/components/workflows/Workflow.d.ts | 9 ++++++++- dist/components/workflows/Workflow.d.ts.map | 2 +- dist/components/workflows/Workflow.js | 4 ++-- .../workflows/WorkflowDefaultLayout.d.ts | 2 ++ .../workflows/WorkflowDefaultLayout.d.ts.map | 2 +- .../workflows/WorkflowDefaultLayout.js | 4 ++-- 9 files changed, 39 insertions(+), 13 deletions(-) diff --git a/dist/components/subworkflows/Subworkflow.d.ts b/dist/components/subworkflows/Subworkflow.d.ts index d646754..67da6ff 100644 --- a/dist/components/subworkflows/Subworkflow.d.ts +++ b/dist/components/subworkflows/Subworkflow.d.ts @@ -27,6 +27,13 @@ export type SubworkflowProps = { jobProperties?: WorkflowDesignerProperty[]; activeTabIndex: number; onActiveTabIndexChange: (tabIndex: number) => void; + /** + * Drops this subworkflow's own Compute tab. Set it when the host already + * shows a compute surface of its own — the job designer does, and two places + * called "Compute" on one screen leave the reader guessing which one the job + * will actually run with. + */ + hideComputeSubTab?: boolean; }; export declare const TAB_NAVIGATION_CONFIG: { readonly overview: { @@ -50,5 +57,5 @@ export declare const TAB_NAVIGATION_CONFIG: { readonly href: "sw-compute"; }; }; -export declare function Subworkflow({ subworkflow, onUpdate, isStandalone, editable, adjustable, metaProperties, onOutputUpdateRequest, isMethodDataLoading, accountUsers, accountUsersIsLoading, currentUser, clusters, materials, materialsIndex, onMaterialSwitch, profile, publicAccount, createMetaProperty, pseudoUploadReduxDialog, unitTypeReduxDialog, className, jobProperties, activeTabIndex, onActiveTabIndexChange, }: SubworkflowProps): React.JSX.Element; +export declare function Subworkflow({ subworkflow, onUpdate, isStandalone, editable, adjustable, metaProperties, onOutputUpdateRequest, isMethodDataLoading, accountUsers, accountUsersIsLoading, currentUser, clusters, materials, materialsIndex, onMaterialSwitch, profile, publicAccount, createMetaProperty, pseudoUploadReduxDialog, unitTypeReduxDialog, className, jobProperties, activeTabIndex, onActiveTabIndexChange, hideComputeSubTab, }: SubworkflowProps): React.JSX.Element; //# sourceMappingURL=Subworkflow.d.ts.map \ No newline at end of file diff --git a/dist/components/subworkflows/Subworkflow.d.ts.map b/dist/components/subworkflows/Subworkflow.d.ts.map index b9b4262..a417646 100644 --- a/dist/components/subworkflows/Subworkflow.d.ts.map +++ b/dist/components/subworkflows/Subworkflow.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"Subworkflow.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/Subworkflow.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAIvF,OAAO,EAEH,KAAK,eAAe,EACpB,WAAW,IAAI,eAAe,EAEjC,MAAM,cAAc,CAAC;AAOtB,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D,OAAO,KAAK,EACR,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,wCAAwC,EACxC,2BAA2B,EAC3B,4BAA4B,EAC5B,kCAAkC,EAClC,uBAAuB,EACvB,wBAAwB,EAExB,oBAAoB,EACvB,MAAM,qBAAqB,CAAC;AAU7B,MAAM,MAAM,gBAAgB,GAAG;IAC3B,WAAW,EAAE,eAAe,CAAC;IAC7B,QAAQ,EAAE,CAAC,WAAW,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,4BAA4B,EAAE,CAAC;IAChD,qBAAqB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACrD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,WAAW,CAAC,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACrC,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAChD,OAAO,EAAE,uBAAuB,CAAC;IACjC,aAAa,EAAE,uBAAuB,CAAC;IACvC,kBAAkB,EAAE,CAChB,QAAQ,EAAE,wCAAwC,KACjD,OAAO,CAAC,kCAAkC,GAAG,SAAS,CAAC,CAAC;IAC7D,uBAAuB,EAAE,2BAA2B,CAAC;IACrD,mBAAmB,EAAE,2BAA2B,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC3C,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACtD,CAAC;AAEF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;CAqBxB,CAAC;AAEX,wBAAgB,WAAW,CAAC,EACxB,WAAW,EACX,QAAQ,EACR,YAAoB,EACpB,QAAe,EACf,UAAkB,EAClB,cAAmB,EACnB,qBAAqB,EACrB,mBAA2B,EAC3B,YAAY,EACZ,qBAAqB,EACrB,WAAW,EACX,QAAa,EACb,SAAc,EACd,cAAc,EACd,gBAAgB,EAChB,OAAO,EACP,aAAa,EACb,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,SAAS,EACT,aAAa,EACb,cAAc,EACd,sBAAsB,GACzB,EAAE,gBAAgB,qBAoUlB"} \ No newline at end of file +{"version":3,"file":"Subworkflow.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/Subworkflow.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAIvF,OAAO,EAEH,KAAK,eAAe,EACpB,WAAW,IAAI,eAAe,EAEjC,MAAM,cAAc,CAAC;AAOtB,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D,OAAO,KAAK,EACR,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,wCAAwC,EACxC,2BAA2B,EAC3B,4BAA4B,EAC5B,kCAAkC,EAClC,uBAAuB,EACvB,wBAAwB,EAExB,oBAAoB,EACvB,MAAM,qBAAqB,CAAC;AAU7B,MAAM,MAAM,gBAAgB,GAAG;IAC3B,WAAW,EAAE,eAAe,CAAC;IAC7B,QAAQ,EAAE,CAAC,WAAW,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,4BAA4B,EAAE,CAAC;IAChD,qBAAqB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACrD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,WAAW,CAAC,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACrC,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAChD,OAAO,EAAE,uBAAuB,CAAC;IACjC,aAAa,EAAE,uBAAuB,CAAC;IACvC,kBAAkB,EAAE,CAChB,QAAQ,EAAE,wCAAwC,KACjD,OAAO,CAAC,kCAAkC,GAAG,SAAS,CAAC,CAAC;IAC7D,uBAAuB,EAAE,2BAA2B,CAAC;IACrD,mBAAmB,EAAE,2BAA2B,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC3C,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;CAqBxB,CAAC;AAMX,wBAAgB,WAAW,CAAC,EACxB,WAAW,EACX,QAAQ,EACR,YAAoB,EACpB,QAAe,EACf,UAAkB,EAClB,cAAmB,EACnB,qBAAqB,EACrB,mBAA2B,EAC3B,YAAY,EACZ,qBAAqB,EACrB,WAAW,EACX,QAAa,EACb,SAAc,EACd,cAAc,EACd,gBAAgB,EAChB,OAAO,EACP,aAAa,EACb,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,SAAS,EACT,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,iBAAyB,GAC5B,EAAE,gBAAgB,qBA+UlB"} \ No newline at end of file diff --git a/dist/components/subworkflows/Subworkflow.js b/dist/components/subworkflows/Subworkflow.js index af2e26e..ba0011b 100644 --- a/dist/components/subworkflows/Subworkflow.js +++ b/dist/components/subworkflows/Subworkflow.js @@ -43,7 +43,10 @@ export const TAB_NAVIGATION_CONFIG = { href: "sw-compute", }, }; -export function Subworkflow({ subworkflow, onUpdate, isStandalone = false, editable = true, adjustable = false, metaProperties = [], onOutputUpdateRequest, isMethodDataLoading = false, accountUsers, accountUsersIsLoading, currentUser, clusters = [], materials = [], materialsIndex, onMaterialSwitch, profile, publicAccount, createMetaProperty, pseudoUploadReduxDialog, unitTypeReduxDialog, className, jobProperties, activeTabIndex, onActiveTabIndexChange, }) { +const COMPUTE_TAB_NAME = TAB_NAVIGATION_CONFIG.compute.itemName; +/** Compute is the last tab, which is what lets it be dropped without renumbering the rest. */ +const COMPUTE_TAB_INDEX = Object.keys(TAB_NAVIGATION_CONFIG).indexOf("compute"); +export function Subworkflow({ subworkflow, onUpdate, isStandalone = false, editable = true, adjustable = false, metaProperties = [], onOutputUpdateRequest, isMethodDataLoading = false, accountUsers, accountUsersIsLoading, currentUser, clusters = [], materials = [], materialsIndex, onMaterialSwitch, profile, publicAccount, createMetaProperty, pseudoUploadReduxDialog, unitTypeReduxDialog, className, jobProperties, activeTabIndex, onActiveTabIndexChange, hideComputeSubTab = false, }) { var _a, _b, _c; const { getDefaultComputeConfig } = useWorkflowComponents(); const [unitIndex, setUnitIndex] = useState(0); @@ -164,13 +167,20 @@ export function Subworkflow({ subworkflow, onUpdate, isStandalone = false, edita version: (_b = subworkflow.application) === null || _b === void 0 ? void 0 : _b.version, build: (_c = subworkflow.application) === null || _c === void 0 ? void 0 : _c.build, }); - const tabs = useMemo(() => Object.values(TAB_NAVIGATION_CONFIG).map((tab, index) => ({ + const tabs = useMemo(() => Object.values(TAB_NAVIGATION_CONFIG) + .map((tab, index) => ({ ...tab, href: undefined, onClick: (event) => { event.preventDefault(); setTabIndex(index); }, - })), [setTabIndex]); - return (_jsxs(Stack, { "data-tid": "subworkflow", height: "100%", className: className, children: [_jsx(TabsMenu, { tabs: tabs, activeTabIndex: activeTabIndex, sx: { fontSize: 12, height: "100%" } }), _jsxs(TabContext, { value: `${activeTabIndex}`, children: [_jsx(TabPanel, { value: "0", id: TAB_NAVIGATION_CONFIG.overview.href, sx: { height: "100%" }, children: _jsxs(Stack, { spacing: 3, height: "100%", children: [_jsx(AccordionComponent, { header: "Details", id: "subworkflow-accordion", sx: { pt: 0 }, children: _jsxs(Stack, { spacing: 2, children: [_jsx(Properties, { subworkflow: subworkflow, onUpdate: onUpdate, editable: editable || adjustable }), _jsx(ApplicationAve, { application: subworkflow.application, onApplicationUpdate: onApplicationUpdate, editable: editable }), subworkflow.modelInstance.isUnknown ? null : (_jsx(Model, { id: "model", model: subworkflow.modelInstance, models: filteredModels, application: subworkflow.application, onUpdate: onModelUpdate, editable: editable })), _jsx(SubworkflowMethodPanel, { subworkflow: subworkflow, editable: editable, adjustable: adjustable, isMethodDataLoading: isMethodDataLoading, isStandalone: isStandalone, materials: materials, profile: profile, onUpdate: onChildSubworkflowInstanceUpdate, pseudoUploadReduxDialog: pseudoUploadReduxDialog, metaProperties: metaProperties, createMetaProperty: createMetaProperty })] }) }), _jsx(UnitsFlowchartContainer, { units: subworkflow.unitsInstances, onUnitAdd: onUnitAdd, isStandalone: isStandalone, editable: editable, adjustable: adjustable, onUnitClone: onUnitClone, onUnitRemove: onUnitRemove, onUnitUpdate: onUnitUpdate, materials: materials, materialsIndex: materialsIndex, onMaterialSwitch: onMaterialSwitch, subworkflow: subworkflow, onOutputUpdateRequest: onOutputUpdateRequest, publicAccount: publicAccount, unitIndex: unitIndex, onUnitSelect: onUnitSelect, unitTypeReduxDialog: unitTypeReduxDialog, jobProperties: jobProperties, UnitModalComponent: UnitModal })] }) }), _jsx(TabPanel, { value: "1", id: TAB_NAVIGATION_CONFIG.importantSettings.href, "data-tab-name": TAB_NAVIGATION_CONFIG.importantSettings.itemName, children: _jsx(ImportantSettings, { id: TAB_NAVIGATION_CONFIG.importantSettings.href, subworkflow: subworkflow, onContextChanged: onImportantSettingsContextChanged }) }), _jsx(TabPanel, { value: "2", children: _jsx(Grid, { container: true, spacing: 2, children: subworkflow.unitsInstances.map((unit, index) => (_jsx(SubworkflowExecutionUnitDetailsRow, { unit: unit, index: index, editable: editable, onUnitResultsChanged: onUnitResultsChanged, onUnitIsDraftChanged: onUnitIsDraftChanged, onUnitMonitorChanged: onUnitMonitorChanged, onUnitPostProcessorChanged: onUnitPostProcessorChanged }, unit.flowchartId))) }) }), _jsx(TabPanel, { value: "3", children: _jsx(WorkflowCompute, { compute: subworkflow.compute, onUpdate: onComputeUpdate, onToggle: onComputeToggle, showAdvancedOptions: new Application(subworkflow.application).hasAdvancedComputeOptions, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: currentUser !== null && currentUser !== void 0 ? currentUser : profile.user.entity, clusters: clusters }) })] })] })); + })) + // Compute is the last entry, so dropping it leaves the remaining + // tabs on the indices their panels are keyed to. + .filter((tab) => !(hideComputeSubTab && tab.itemName === COMPUTE_TAB_NAME)), [setTabIndex, hideComputeSubTab]); + // A subworkflow whose Compute tab was open when the host hid it would + // otherwise be left showing an empty panel. + const visibleTabIndex = hideComputeSubTab && activeTabIndex === COMPUTE_TAB_INDEX ? 0 : activeTabIndex; + return (_jsxs(Stack, { "data-tid": "subworkflow", height: "100%", className: className, children: [_jsx(TabsMenu, { tabs: tabs, activeTabIndex: visibleTabIndex, sx: { fontSize: 12, height: "100%" } }), _jsxs(TabContext, { value: `${visibleTabIndex}`, children: [_jsx(TabPanel, { value: "0", id: TAB_NAVIGATION_CONFIG.overview.href, sx: { height: "100%" }, children: _jsxs(Stack, { spacing: 3, height: "100%", children: [_jsx(AccordionComponent, { header: "Details", id: "subworkflow-accordion", sx: { pt: 0 }, children: _jsxs(Stack, { spacing: 2, children: [_jsx(Properties, { subworkflow: subworkflow, onUpdate: onUpdate, editable: editable || adjustable }), _jsx(ApplicationAve, { application: subworkflow.application, onApplicationUpdate: onApplicationUpdate, editable: editable }), subworkflow.modelInstance.isUnknown ? null : (_jsx(Model, { id: "model", model: subworkflow.modelInstance, models: filteredModels, application: subworkflow.application, onUpdate: onModelUpdate, editable: editable })), _jsx(SubworkflowMethodPanel, { subworkflow: subworkflow, editable: editable, adjustable: adjustable, isMethodDataLoading: isMethodDataLoading, isStandalone: isStandalone, materials: materials, profile: profile, onUpdate: onChildSubworkflowInstanceUpdate, pseudoUploadReduxDialog: pseudoUploadReduxDialog, metaProperties: metaProperties, createMetaProperty: createMetaProperty })] }) }), _jsx(UnitsFlowchartContainer, { units: subworkflow.unitsInstances, onUnitAdd: onUnitAdd, isStandalone: isStandalone, editable: editable, adjustable: adjustable, onUnitClone: onUnitClone, onUnitRemove: onUnitRemove, onUnitUpdate: onUnitUpdate, materials: materials, materialsIndex: materialsIndex, onMaterialSwitch: onMaterialSwitch, subworkflow: subworkflow, onOutputUpdateRequest: onOutputUpdateRequest, publicAccount: publicAccount, unitIndex: unitIndex, onUnitSelect: onUnitSelect, unitTypeReduxDialog: unitTypeReduxDialog, jobProperties: jobProperties, UnitModalComponent: UnitModal })] }) }), _jsx(TabPanel, { value: "1", id: TAB_NAVIGATION_CONFIG.importantSettings.href, "data-tab-name": TAB_NAVIGATION_CONFIG.importantSettings.itemName, children: _jsx(ImportantSettings, { id: TAB_NAVIGATION_CONFIG.importantSettings.href, subworkflow: subworkflow, onContextChanged: onImportantSettingsContextChanged }) }), _jsx(TabPanel, { value: "2", children: _jsx(Grid, { container: true, spacing: 2, children: subworkflow.unitsInstances.map((unit, index) => (_jsx(SubworkflowExecutionUnitDetailsRow, { unit: unit, index: index, editable: editable, onUnitResultsChanged: onUnitResultsChanged, onUnitIsDraftChanged: onUnitIsDraftChanged, onUnitMonitorChanged: onUnitMonitorChanged, onUnitPostProcessorChanged: onUnitPostProcessorChanged }, unit.flowchartId))) }) }), hideComputeSubTab ? null : (_jsx(TabPanel, { value: `${COMPUTE_TAB_INDEX}`, children: _jsx(WorkflowCompute, { compute: subworkflow.compute, onUpdate: onComputeUpdate, onToggle: onComputeToggle, showAdvancedOptions: new Application(subworkflow.application).hasAdvancedComputeOptions, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: currentUser !== null && currentUser !== void 0 ? currentUser : profile.user.entity, clusters: clusters }) }))] })] })); } diff --git a/dist/components/workflows/Workflow.d.ts b/dist/components/workflows/Workflow.d.ts index 98f295d..75385ed 100644 --- a/dist/components/workflows/Workflow.d.ts +++ b/dist/components/workflows/Workflow.d.ts @@ -66,7 +66,14 @@ export type WorkflowProps = { isDescriptionEditable: boolean; /** Refined job properties for unit modals in job designer; optional elsewhere. */ jobProperties?: WorkflowDesignerProperty[]; + /** + * Hides each subworkflow's own Compute tab. Set it when the host renders a + * compute surface of its own, as the job designer does — otherwise the same + * screen offers two things called "Compute" and the reader has to guess + * which one the job will run with. + */ + hideComputeSubTab?: boolean; }; -export declare function Workflow({ workflow, metaProperties, onUpdate, onOutputUpdateRequest, onUpdateTags, extraActions, onSave, onNameUpdate, iconCls, onUnitAdd, onUnitAddSubworkflowFromConfig, onUnitRemove, onUnitUpdate, onSubworkflowUnitUpdate, materials, materialsIndex, jobHasParent, onMaterialSwitch, showHeaderPager, onHeaderPagerUpdate, dialogs, createMetaProperty, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, templates, isStandalone, isHeaderCompact, editable, adjustable, isLoading, showHeader, isMethodDataLoading, materialsSet, isMap, isSetPublicVisible, showMetadata, showHistory, workflowHistory, onIsMultiMaterialChanged, onRender, renderAtJobLevel, workflowRenderGeneration, isDescriptionEditable, jobProperties, }: WorkflowProps): React.JSX.Element; +export declare function Workflow({ workflow, metaProperties, onUpdate, onOutputUpdateRequest, onUpdateTags, extraActions, onSave, onNameUpdate, iconCls, onUnitAdd, onUnitAddSubworkflowFromConfig, onUnitRemove, onUnitUpdate, onSubworkflowUnitUpdate, materials, materialsIndex, jobHasParent, onMaterialSwitch, showHeaderPager, onHeaderPagerUpdate, dialogs, createMetaProperty, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, templates, isStandalone, isHeaderCompact, editable, adjustable, isLoading, showHeader, isMethodDataLoading, materialsSet, isMap, isSetPublicVisible, showMetadata, showHistory, workflowHistory, onIsMultiMaterialChanged, onRender, renderAtJobLevel, workflowRenderGeneration, isDescriptionEditable, jobProperties, hideComputeSubTab, }: WorkflowProps): React.JSX.Element; export {}; //# sourceMappingURL=Workflow.d.ts.map \ No newline at end of file diff --git a/dist/components/workflows/Workflow.d.ts.map b/dist/components/workflows/Workflow.d.ts.map index a698ff5..23fcac2 100644 --- a/dist/components/workflows/Workflow.d.ts.map +++ b/dist/components/workflows/Workflow.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"Workflow.d.ts","sourceRoot":"","sources":["../../../src/components/workflows/Workflow.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"Workflow.d.ts","sourceRoot":"","sources":["../../../src/components/workflows/Workflow.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/components/workflows/Workflow.js b/dist/components/workflows/Workflow.js index 462e5db..0308598 100644 --- a/dist/components/workflows/Workflow.js +++ b/dist/components/workflows/Workflow.js @@ -11,7 +11,7 @@ import { getWorkflowDesignerTabResetKey } from "./workflowDesignerTabState"; const noop = () => undefined; const EMPTY_META_PROPERTIES = []; const noopUnitAddSubworkflowFromConfig = (_config, _prependOrPasteIndex, _unitIndex) => undefined; -export function Workflow({ workflow, metaProperties = EMPTY_META_PROPERTIES, onUpdate = noop, onOutputUpdateRequest, onUpdateTags, extraActions = [], onSave, onNameUpdate, iconCls, onUnitAdd = noop, onUnitAddSubworkflowFromConfig = noopUnitAddSubworkflowFromConfig, onUnitRemove = noop, onUnitUpdate = noop, onSubworkflowUnitUpdate = noop, materials = [], materialsIndex, jobHasParent = false, onMaterialSwitch, showHeaderPager = false, onHeaderPagerUpdate, dialogs, createMetaProperty = async (_property) => undefined, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters = [], templates, isStandalone = false, isHeaderCompact, editable = false, adjustable = false, isLoading = false, showHeader = true, isMethodDataLoading = false, materialsSet, isMap, isSetPublicVisible, showMetadata = true, showHistory = false, workflowHistory = [], onIsMultiMaterialChanged, onRender, renderAtJobLevel = false, workflowRenderGeneration, isDescriptionEditable, jobProperties, }) { +export function Workflow({ workflow, metaProperties = EMPTY_META_PROPERTIES, onUpdate = noop, onOutputUpdateRequest, onUpdateTags, extraActions = [], onSave, onNameUpdate, iconCls, onUnitAdd = noop, onUnitAddSubworkflowFromConfig = noopUnitAddSubworkflowFromConfig, onUnitRemove = noop, onUnitUpdate = noop, onSubworkflowUnitUpdate = noop, materials = [], materialsIndex, jobHasParent = false, onMaterialSwitch, showHeaderPager = false, onHeaderPagerUpdate, dialogs, createMetaProperty = async (_property) => undefined, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters = [], templates, isStandalone = false, isHeaderCompact, editable = false, adjustable = false, isLoading = false, showHeader = true, isMethodDataLoading = false, materialsSet, isMap, isSetPublicVisible, showMetadata = true, showHistory = false, workflowHistory = [], onIsMultiMaterialChanged, onRender, renderAtJobLevel = false, workflowRenderGeneration, isDescriptionEditable, jobProperties, hideComputeSubTab = false, }) { const [unitIndex, setUnitIndex] = useState(0); const [isRelaxationToggled, setIsRelaxationToggled] = useState(false); const [isMultiMaterialToggled, setIsMultiMaterialToggled] = useState(() => Boolean(workflow.isMultiMaterial)); @@ -207,5 +207,5 @@ export function Workflow({ workflow, metaProperties = EMPTY_META_PROPERTIES, onU buttonContent: "Select Workflow Actions", }; }, [getActions]); - return (_jsx(Box, { "data-workflow-render-generation": workflowRenderGeneration, children: _jsx(WorkflowDefaultLayout, { entity: workflow, unitIndex: unitIndex, isMap: isMap, materials: materials, materialsIndex: materialsIndex, materialsSet: materialsSet, jobHasParent: jobHasParent, editable: Boolean(editable), adjustable: Boolean(adjustable), isLoading: isLoading, showHeader: showHeader, isHeaderCompact: isHeaderCompact, isStandalone: isStandalone, isMethodDataLoading: isMethodDataLoading, isSetPublicVisible: isSetPublicVisible, showMetadata: showMetadata, showHistory: showHistory, workflowHistory: workflowHistory, iconCls: iconCls, onNameUpdate: onNameUpdate, onUpdateTags: onUpdateTags, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUnitUpdate: onUnitUpdate, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, onMapWorkflowUpdate: onMapWorkflowUpdate, onUnitSelect: onUnitSelect, onUpdateUnitIndex: onUpdateUnitIndex, handleUnitRemove: handleUnitRemove, onUnitNameUpdate: onUnitNameUpdate, areWorkflowContentExpanded: areWorkflowContentExpanded, toggleExpandWorkflowContent: toggleExpandWorkflowContent, headerStatusCls: headerStatusCls, getPagerProps: getPagerProps, getSaveBtnProps: getSaveBtnProps, getDropdownProps: getDropdownProps, isDescriptionEditable: isDescriptionEditable, onDescriptionUpdate: onDescriptionUpdate, dialogs: dialogs, metaProperties: metaProperties, onMaterialSwitch: onMaterialSwitch, onOutputUpdateRequest: onOutputUpdateRequest, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, profile: profile, publicAccount: publicAccount, clusters: clusters, templates: templates, createMetaProperty: createMetaProperty, jobProperties: jobProperties, subworkflowActiveTabIndexById: subworkflowActiveTabIndexById, onSubworkflowActiveTabIndexChange: onSubworkflowActiveTabIndexChange }) })); + return (_jsx(Box, { "data-workflow-render-generation": workflowRenderGeneration, children: _jsx(WorkflowDefaultLayout, { entity: workflow, unitIndex: unitIndex, isMap: isMap, materials: materials, materialsIndex: materialsIndex, materialsSet: materialsSet, jobHasParent: jobHasParent, editable: Boolean(editable), adjustable: Boolean(adjustable), isLoading: isLoading, showHeader: showHeader, isHeaderCompact: isHeaderCompact, isStandalone: isStandalone, isMethodDataLoading: isMethodDataLoading, isSetPublicVisible: isSetPublicVisible, showMetadata: showMetadata, showHistory: showHistory, workflowHistory: workflowHistory, iconCls: iconCls, onNameUpdate: onNameUpdate, onUpdateTags: onUpdateTags, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUnitUpdate: onUnitUpdate, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, onMapWorkflowUpdate: onMapWorkflowUpdate, onUnitSelect: onUnitSelect, onUpdateUnitIndex: onUpdateUnitIndex, handleUnitRemove: handleUnitRemove, onUnitNameUpdate: onUnitNameUpdate, areWorkflowContentExpanded: areWorkflowContentExpanded, toggleExpandWorkflowContent: toggleExpandWorkflowContent, headerStatusCls: headerStatusCls, getPagerProps: getPagerProps, getSaveBtnProps: getSaveBtnProps, getDropdownProps: getDropdownProps, isDescriptionEditable: isDescriptionEditable, onDescriptionUpdate: onDescriptionUpdate, dialogs: dialogs, metaProperties: metaProperties, onMaterialSwitch: onMaterialSwitch, onOutputUpdateRequest: onOutputUpdateRequest, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, profile: profile, publicAccount: publicAccount, clusters: clusters, templates: templates, createMetaProperty: createMetaProperty, jobProperties: jobProperties, hideComputeSubTab: hideComputeSubTab, subworkflowActiveTabIndexById: subworkflowActiveTabIndexById, onSubworkflowActiveTabIndexChange: onSubworkflowActiveTabIndexChange }) })); } diff --git a/dist/components/workflows/WorkflowDefaultLayout.d.ts b/dist/components/workflows/WorkflowDefaultLayout.d.ts index 254af65..2771098 100644 --- a/dist/components/workflows/WorkflowDefaultLayout.d.ts +++ b/dist/components/workflows/WorkflowDefaultLayout.d.ts @@ -85,6 +85,8 @@ export type WorkflowDefaultLayoutProps = { /** Subworkflow inner tabs (Overview, Important settings, …); owned by {@link Workflow} so remounts of {@link Subworkflow} do not reset them. */ subworkflowActiveTabIndexById: Record; onSubworkflowActiveTabIndexChange: (subworkflowId: string, tabIndex: number) => void; + /** See {@link SubworkflowProps.hideComputeSubTab}. */ + hideComputeSubTab?: boolean; }; export declare function WorkflowDefaultLayout(props: WorkflowDefaultLayoutProps): React.JSX.Element; //# sourceMappingURL=WorkflowDefaultLayout.d.ts.map \ No newline at end of file diff --git a/dist/components/workflows/WorkflowDefaultLayout.d.ts.map b/dist/components/workflows/WorkflowDefaultLayout.d.ts.map index 3ef5ce0..cbc23f3 100644 --- a/dist/components/workflows/WorkflowDefaultLayout.d.ts.map +++ b/dist/components/workflows/WorkflowDefaultLayout.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"WorkflowDefaultLayout.d.ts","sourceRoot":"","sources":["../../../src/components/workflows/WorkflowDefaultLayout.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"WorkflowDefaultLayout.d.ts","sourceRoot":"","sources":["../../../src/components/workflows/WorkflowDefaultLayout.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/components/workflows/WorkflowDefaultLayout.js b/dist/components/workflows/WorkflowDefaultLayout.js index 4a44b3e..00463da 100644 --- a/dist/components/workflows/WorkflowDefaultLayout.js +++ b/dist/components/workflows/WorkflowDefaultLayout.js @@ -17,7 +17,7 @@ import { WorkflowValidationAlert } from "./WorkflowValidationAlert"; const MapWorkflowDesigner = React.lazy(() => import("./Map").then((module) => ({ default: module.MapWorkflowDesigner }))); export function WorkflowDefaultLayout(props) { var _a, _b; - const { entity, unitIndex, isMap, materials, materialsIndex, materialsSet, jobHasParent = false, editable, adjustable, isLoading, showHeader, isHeaderCompact, isStandalone, isMethodDataLoading, isSetPublicVisible, showMetadata, showHistory, workflowHistory, iconCls, onNameUpdate, onUpdateTags, onUnitAdd, onUnitAddSubworkflowFromConfig, onUnitUpdate, onSubworkflowUnitUpdate, onMapWorkflowUpdate, onUnitSelect, onUpdateUnitIndex, handleUnitRemove, onUnitNameUpdate, areWorkflowContentExpanded, toggleExpandWorkflowContent, headerStatusCls, getPagerProps, getSaveBtnProps, getDropdownProps, isDescriptionEditable, onDescriptionUpdate, dialogs, metaProperties, onMaterialSwitch, onOutputUpdateRequest, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, templates, createMetaProperty, jobProperties, subworkflowActiveTabIndexById, onSubworkflowActiveTabIndexChange, } = props; + const { entity, unitIndex, isMap, materials, materialsIndex, materialsSet, jobHasParent = false, editable, adjustable, isLoading, showHeader, isHeaderCompact, isStandalone, isMethodDataLoading, isSetPublicVisible, showMetadata, showHistory, workflowHistory, iconCls, onNameUpdate, onUpdateTags, onUnitAdd, onUnitAddSubworkflowFromConfig, onUnitUpdate, onSubworkflowUnitUpdate, onMapWorkflowUpdate, onUnitSelect, onUpdateUnitIndex, handleUnitRemove, onUnitNameUpdate, areWorkflowContentExpanded, toggleExpandWorkflowContent, headerStatusCls, getPagerProps, getSaveBtnProps, getDropdownProps, isDescriptionEditable, onDescriptionUpdate, dialogs, metaProperties, onMaterialSwitch, onOutputUpdateRequest, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, templates, createMetaProperty, jobProperties, subworkflowActiveTabIndexById, onSubworkflowActiveTabIndexChange, hideComputeSubTab, } = props; const { EntityHeaderComponent, MetadataComponent, HistoryComponent } = useWorkflowComponents(); const unit = entity.unitInstances[unitIndex]; if (!unit) { @@ -40,5 +40,5 @@ export function WorkflowDefaultLayout(props) { }, description: get(entity, "description"), isLoading: isLoading, editable: Boolean(editable), onNameUpdate: onNameUpdate, iconCls: iconCls, id: "workflow-designer-header", pagerProps: getPagerProps(), saveBtnProps: getSaveBtnProps(), dropdownProps: getDropdownProps(), descriptionEditorTitle: "Workflow Description", item: entity, isDescriptionEditable: isDescriptionEditable, onDescriptionUpdate: onDescriptionUpdate })), _jsxs(Grid, { container: true, sx: { backgroundColor: "background.paper" }, children: [_jsx(Grid, { ...leftColumnGridProps, item: true, sx: { borderRight: "1px solid #cecece", backgroundColor: "background.default", - }, children: _jsx(Box, { className: "workflow-flowchart-container", sx: { height: "100%", p: 2 }, children: _jsx(WorkflowUnitsFlowchart, { editable: Boolean(editable), onUnitRemove: handleUnitRemove, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, workflow: entity, activeUnit: unit, onClick: onUnitSelect, isCardContentExpanded: areWorkflowContentExpanded, headerStatusCls: headerStatusCls }) }) }), _jsxs(Grid, { className: "workflow-subworkflow-container", item: true, sx: { display: "flex", flexDirection: "column" }, ...rightColumnGridProps, children: [_jsx(WorkflowValidationAlert, { workflow: entity }), unit.type === UnitType.subworkflow && (_jsxs(_Fragment, { children: [_jsx(SubworkflowHeader, { unit: unit, adjustable: Boolean(adjustable), editable: Boolean(editable), subworkflow: subworkflow, onUnitRemove: handleUnitRemove, headerStatusCls: headerStatusCls, onUnitNameUpdate: onUnitNameUpdate, unitIndex: unitIndex, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUpdateUnitIndex: onUpdateUnitIndex, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, areWorkflowContentExpanded: areWorkflowContentExpanded, toggleExpandWorkflowContent: toggleExpandWorkflowContent, workflow: entity, materials: materials, materialsIndex: materialsIndex, materialsSet: materialsSet, jobHasParent: jobHasParent }), subworkflow ? (_jsx(Subworkflow, { className: "card-body", subworkflow: subworkflow, activeTabIndex: (_b = subworkflowActiveTabIndexById[subworkflow.id]) !== null && _b !== void 0 ? _b : 0, onActiveTabIndexChange: (tabIndex) => onSubworkflowActiveTabIndexChange(subworkflow.id, tabIndex), onUpdate: onSubworkflowUnitUpdate, isStandalone: isStandalone, isMethodDataLoading: isMethodDataLoading, editable: Boolean(editable), adjustable: Boolean(adjustable), onMaterialSwitch: onMaterialSwitch, materials: materials, materialsIndex: materialsIndex, metaProperties: metaProperties, onOutputUpdateRequest: onOutputUpdateRequest, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: profile.user.entity, clusters: clusters, pseudoUploadReduxDialog: pseudoUploadReduxDialog, unitTypeReduxDialog: unitTypeReduxDialog, profile: profile, publicAccount: publicAccount, createMetaProperty: createMetaProperty, jobProperties: jobProperties }, subworkflow.id)) : null] })), unit.type === UnitType.map && (_jsx(React.Suspense, { fallback: null, children: _jsx(MapWorkflowDesigner, { className: "card-body", unit: unit, workflow: mapWorkflow, onUpdate: onUnitUpdate, onWorkflowUpdate: onMapWorkflowUpdate, editable: Boolean(editable), adjustable: Boolean(adjustable), onMaterialSwitch: onMaterialSwitch, materials: materials, materialsIndex: materialsIndex, iconCls: iconCls, onOutputUpdateRequest: onOutputUpdateRequest, parentWorkflow: entity, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: profile.user.entity, publicAccount: publicAccount, profile: profile, clusters: clusters, dialogs: dialogs, templates: templates, isDescriptionEditable: isDescriptionEditable, metaProperties: metaProperties }) })), unit.type === UnitType.error && (_jsx(Box, { className: "card-body", sx: { p: 2 }, children: _jsx(ErrorUnitContent, { unit: unit }) }))] })] }), _jsx(Divider, {}), showMetadata && (_jsx(MetadataComponent, { tags: get(entity, "tags", []), editable: Boolean(editable), isSetPublicVisible: isSetPublicVisible, onUpdateTags: onUpdateTags, publicAccount: publicAccount.entity })), _jsx(Divider, {}), showHistory && _jsx(HistoryComponent, { items: workflowHistory })] }) })); + }, children: _jsx(Box, { className: "workflow-flowchart-container", sx: { height: "100%", p: 2 }, children: _jsx(WorkflowUnitsFlowchart, { editable: Boolean(editable), onUnitRemove: handleUnitRemove, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, workflow: entity, activeUnit: unit, onClick: onUnitSelect, isCardContentExpanded: areWorkflowContentExpanded, headerStatusCls: headerStatusCls }) }) }), _jsxs(Grid, { className: "workflow-subworkflow-container", item: true, sx: { display: "flex", flexDirection: "column" }, ...rightColumnGridProps, children: [_jsx(WorkflowValidationAlert, { workflow: entity }), unit.type === UnitType.subworkflow && (_jsxs(_Fragment, { children: [_jsx(SubworkflowHeader, { unit: unit, adjustable: Boolean(adjustable), editable: Boolean(editable), subworkflow: subworkflow, onUnitRemove: handleUnitRemove, headerStatusCls: headerStatusCls, onUnitNameUpdate: onUnitNameUpdate, unitIndex: unitIndex, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUpdateUnitIndex: onUpdateUnitIndex, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, areWorkflowContentExpanded: areWorkflowContentExpanded, toggleExpandWorkflowContent: toggleExpandWorkflowContent, workflow: entity, materials: materials, materialsIndex: materialsIndex, materialsSet: materialsSet, jobHasParent: jobHasParent }), subworkflow ? (_jsx(Subworkflow, { className: "card-body", subworkflow: subworkflow, activeTabIndex: (_b = subworkflowActiveTabIndexById[subworkflow.id]) !== null && _b !== void 0 ? _b : 0, hideComputeSubTab: hideComputeSubTab, onActiveTabIndexChange: (tabIndex) => onSubworkflowActiveTabIndexChange(subworkflow.id, tabIndex), onUpdate: onSubworkflowUnitUpdate, isStandalone: isStandalone, isMethodDataLoading: isMethodDataLoading, editable: Boolean(editable), adjustable: Boolean(adjustable), onMaterialSwitch: onMaterialSwitch, materials: materials, materialsIndex: materialsIndex, metaProperties: metaProperties, onOutputUpdateRequest: onOutputUpdateRequest, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: profile.user.entity, clusters: clusters, pseudoUploadReduxDialog: pseudoUploadReduxDialog, unitTypeReduxDialog: unitTypeReduxDialog, profile: profile, publicAccount: publicAccount, createMetaProperty: createMetaProperty, jobProperties: jobProperties }, subworkflow.id)) : null] })), unit.type === UnitType.map && (_jsx(React.Suspense, { fallback: null, children: _jsx(MapWorkflowDesigner, { className: "card-body", unit: unit, workflow: mapWorkflow, onUpdate: onUnitUpdate, onWorkflowUpdate: onMapWorkflowUpdate, editable: Boolean(editable), adjustable: Boolean(adjustable), onMaterialSwitch: onMaterialSwitch, materials: materials, materialsIndex: materialsIndex, iconCls: iconCls, onOutputUpdateRequest: onOutputUpdateRequest, parentWorkflow: entity, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: profile.user.entity, publicAccount: publicAccount, profile: profile, clusters: clusters, dialogs: dialogs, templates: templates, isDescriptionEditable: isDescriptionEditable, metaProperties: metaProperties }) })), unit.type === UnitType.error && (_jsx(Box, { className: "card-body", sx: { p: 2 }, children: _jsx(ErrorUnitContent, { unit: unit }) }))] })] }), _jsx(Divider, {}), showMetadata && (_jsx(MetadataComponent, { tags: get(entity, "tags", []), editable: Boolean(editable), isSetPublicVisible: isSetPublicVisible, onUpdateTags: onUpdateTags, publicAccount: publicAccount.entity })), _jsx(Divider, {}), showHistory && _jsx(HistoryComponent, { items: workflowHistory })] }) })); } From a81d8625f9a1214cb0cfbe189f3b003e8e56873c Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Aug 2026 20:58:30 +0000 Subject: [PATCH 3/6] feat: Developer info toggle; hide unit status unless it means something Identifiers and status came back from wove on every card. Both are now opt-in there (mat3ra/wove#11); this is the host side. - Developer info action in the workflow actions dropdown, following the existing showCheckIcon toggle pattern, flips flowchart ids back on for whoever is debugging without them being on show for everyone else. - showUnitStatus prop, default off: in the designer nothing has run, so every unit reports a meaningless 'idle'. The job designer turns it on once a job leaves draft. Both reach wove through WoveDisplayOptionsProvider rather than props: the cards sit behind reactflow node data (UnitsFlowchartContainer -> UnitsFlowchart -> node.data -> UnitNode -> UnitCard), and these are host-level decisions anyway. Covers SOF-8024 portion 1 items 1.1 and 1.5. Note: dist/ here also gains the output for this branch's earlier work (BrillouinZone, UndoSnackbar, the quick wins). That was missing - the husky hook that regenerates dist only fires once hooks are installed, and this repo has no 'prepare: husky install' script - so transpiling sweeps it up. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01DK8KomMescJvMQNSEfeRR8 --- dist/WorkflowDesignerContainer.d.ts | 2 + dist/WorkflowDesignerContainer.d.ts.map | 2 +- dist/WorkflowDesignerContainer.js | 56 ++++- dist/components/common/BrillouinZone.d.ts | 25 ++ dist/components/common/BrillouinZone.d.ts.map | 1 + dist/components/common/BrillouinZone.js | 71 ++++++ dist/components/common/UndoSnackbar.d.ts | 15 ++ dist/components/common/UndoSnackbar.d.ts.map | 1 + dist/components/common/UndoSnackbar.js | 20 ++ .../common/brillouinZoneForProvider.d.ts | 11 + .../common/brillouinZoneForProvider.d.ts.map | 1 + .../common/brillouinZoneForProvider.js | 47 ++++ .../common/brillouinZoneGeometry.d.ts | 37 +++ .../common/brillouinZoneGeometry.d.ts.map | 1 + .../common/brillouinZoneGeometry.js | 233 ++++++++++++++++++ .../subworkflows/ImportantSettings.d.ts.map | 2 +- .../subworkflows/ImportantSettings.js | 7 +- dist/components/subworkflows/Subworkflow.d.ts | 6 +- .../subworkflows/Subworkflow.d.ts.map | 2 +- dist/components/subworkflows/Subworkflow.js | 19 +- .../subworkflows/WorkflowCompute.d.ts.map | 2 +- .../subworkflows/WorkflowCompute.js | 7 +- .../importantSettingsFormUtils.d.ts | 6 +- .../importantSettingsFormUtils.d.ts.map | 2 +- .../importantSettingsFormUtils.js | 30 ++- dist/components/units/UnitModal.js | 2 +- dist/components/workflows/Workflow.d.ts | 11 +- dist/components/workflows/Workflow.d.ts.map | 2 +- dist/components/workflows/Workflow.js | 24 +- dist/standalone/index.js | 15 +- src/components/workflows/Workflow.tsx | 144 ++++++----- 31 files changed, 709 insertions(+), 95 deletions(-) create mode 100644 dist/components/common/BrillouinZone.d.ts create mode 100644 dist/components/common/BrillouinZone.d.ts.map create mode 100644 dist/components/common/BrillouinZone.js create mode 100644 dist/components/common/UndoSnackbar.d.ts create mode 100644 dist/components/common/UndoSnackbar.d.ts.map create mode 100644 dist/components/common/UndoSnackbar.js create mode 100644 dist/components/common/brillouinZoneForProvider.d.ts create mode 100644 dist/components/common/brillouinZoneForProvider.d.ts.map create mode 100644 dist/components/common/brillouinZoneForProvider.js create mode 100644 dist/components/common/brillouinZoneGeometry.d.ts create mode 100644 dist/components/common/brillouinZoneGeometry.d.ts.map create mode 100644 dist/components/common/brillouinZoneGeometry.js diff --git a/dist/WorkflowDesignerContainer.d.ts b/dist/WorkflowDesignerContainer.d.ts index 07fae2b..088276f 100644 --- a/dist/WorkflowDesignerContainer.d.ts +++ b/dist/WorkflowDesignerContainer.d.ts @@ -48,6 +48,8 @@ type WorkflowDesignerContainerBaseProps = { getDefaultComputeConfig: (cluster?: unknown) => Record; generateEntityId: () => string; openDocumentationDialog?: (searchText: string) => void; + /** Fires when unsaved-changes state flips; lets the shell mark Save / guard navigation. */ + onDirtyChange?: (isDirty: boolean) => void; }; export type WorkflowDesignerContainerProps = WorkflowDesignerContainerBaseProps; export default function WorkflowDesignerContainer(containerProps: WorkflowDesignerContainerProps): React.JSX.Element; diff --git a/dist/WorkflowDesignerContainer.d.ts.map b/dist/WorkflowDesignerContainer.d.ts.map index 9c5f3b7..9ba4b36 100644 --- a/dist/WorkflowDesignerContainer.d.ts.map +++ b/dist/WorkflowDesignerContainer.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"WorkflowDesignerContainer.d.ts","sourceRoot":"","sources":["../src/WorkflowDesignerContainer.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"WorkflowDesignerContainer.d.ts","sourceRoot":"","sources":["../src/WorkflowDesignerContainer.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/WorkflowDesignerContainer.js b/dist/WorkflowDesignerContainer.js index d6e19ef..f78e393 100644 --- a/dist/WorkflowDesignerContainer.js +++ b/dist/WorkflowDesignerContainer.js @@ -1,15 +1,16 @@ -import { jsx as _jsx } from "react/jsx-runtime"; +import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { Utils } from "@mat3ra/utils"; import { Subworkflow, Workflow } from "@mat3ra/wode"; import Box from "@mui/material/Box"; import CircularProgress from "@mui/material/CircularProgress"; -import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react"; +import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; +import { UndoSnackbar } from "./components/common/UndoSnackbar"; import { Workflow as WoveWorkflowDesigner } from "./components/workflows/Workflow"; import { WorkflowComponentsContext } from "./WorkflowComponentsContext"; /** Stable empty-array sentinel so the metaProperties useLayoutEffect dep never spuriously fires. */ const EMPTY_META_PROPERTIES = []; export default function WorkflowDesignerContainer(containerProps) { - const { initialWorkflow, defaultMaterial, metaProperties = EMPTY_META_PROPERTIES, editable, showHistory, workflowHistory, isStandalone, adjustable, showHeader, showMetadata, extraActions = [], accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, dialogs, templates, isLoading, saveWorkflow, isDescriptionEditable, EntityHeaderComponent, EntityNameComponent, MetadataComponent, HistoryComponent, SubworkflowFormTitleComponent, PseudoFormComponent, DataGridComponent, BrillouinZoneImageComponent, getDefaultComputeConfig, generateEntityId, } = containerProps; + const { initialWorkflow, defaultMaterial, metaProperties = EMPTY_META_PROPERTIES, editable, showHistory, workflowHistory, isStandalone, adjustable, showHeader, showMetadata, extraActions = [], accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, dialogs, templates, isLoading, saveWorkflow, isDescriptionEditable, EntityHeaderComponent, EntityNameComponent, MetadataComponent, HistoryComponent, SubworkflowFormTitleComponent, PseudoFormComponent, DataGridComponent, BrillouinZoneImageComponent, getDefaultComputeConfig, generateEntityId, onDirtyChange, } = containerProps; const workflowComponents = useMemo(() => ({ EntityHeaderComponent, EntityNameComponent, @@ -43,9 +44,34 @@ export default function WorkflowDesignerContainer(containerProps) { }; }); const [renderGeneration, setRenderGeneration] = useState(0); + const [removeUndoState, setRemoveUndoState] = useState(null); + const [isDirty, setIsDirty] = useState(false); /** Latest workflow for save; avoids stale reads when `onSave` used `setState(prev => …)`. */ const workflowRef = useRef(state.workflow); workflowRef.current = state.workflow; + /** + * Unsaved-changes baseline. Captured after the first `workflow.render()` pass (not from + * `initialWorkflow`) because rendering injects context into units, which would otherwise + * read as an immediate phantom edit. + */ + const dirtyBaselineRef = useRef(null); + const onDirtyChangeRef = useRef(onDirtyChange); + onDirtyChangeRef.current = onDirtyChange; + useEffect(() => { + const currentJson = JSON.stringify(state.workflow.toJSON()); + if (dirtyBaselineRef.current === null) { + dirtyBaselineRef.current = currentJson; + return; + } + const nextDirty = currentJson !== dirtyBaselineRef.current; + setIsDirty((prev) => { + var _a; + if (prev !== nextDirty) { + (_a = onDirtyChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onDirtyChangeRef, nextDirty); + } + return nextDirty; + }); + }, [state.workflow, renderGeneration]); /** * Sole entry point for `workflow.render()` in the workflow designer UI tree. */ @@ -72,6 +98,15 @@ export default function WorkflowDesignerContainer(containerProps) { setState((prev) => ({ ...prev, workflow: nextWorkflow })); }, []); const onSave = useCallback((omitRedirect) => { + // Reset the unsaved-changes baseline optimistically; save errors surface via alerts. + dirtyBaselineRef.current = JSON.stringify(workflowRef.current.toJSON()); + setIsDirty((prev) => { + var _a; + if (prev) { + (_a = onDirtyChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onDirtyChangeRef, false); + } + return false; + }); saveWorkflow({ workflow: workflowRef.current, omitRedirect }).catch(() => { /* errors reported inside saveWorkflow */ }); @@ -125,14 +160,27 @@ export default function WorkflowDesignerContainer(containerProps) { renderWorkflow(); }, [renderWorkflow, generateEntityId]); const onUnitRemove = useCallback((flowchartId) => { + var _a; if (flowchartId == null) { return; } + const { current } = workflowRef; + const removedUnit = current.unitInstances.find((u) => u.flowchartId === flowchartId); + const snapshot = current.toJSON(); setState((prev) => { const workflow = prev.workflow.clone(); workflow.removeUnit(flowchartId); return { ...prev, workflow }; }); + setRemoveUndoState({ + message: `Removed "${(_a = removedUnit === null || removedUnit === void 0 ? void 0 : removedUnit.name) !== null && _a !== void 0 ? _a : "unit"}"`, + onUndo: () => { + const restored = new Workflow(snapshot); + workflowRef.current = restored; + setState((prev) => ({ ...prev, workflow: restored })); + renderWorkflow(); + }, + }); renderWorkflow(); }, [renderWorkflow]); const onUnitUpdate = useCallback((unit) => { @@ -176,5 +224,5 @@ export default function WorkflowDesignerContainer(containerProps) { py: 4, }, children: _jsx(CircularProgress, {}) })); } - return (_jsx(WorkflowComponentsContext.Provider, { value: workflowComponents, children: _jsx(WoveWorkflowDesigner, { workflow: workflow, jobHasParent: Boolean((state.job || {}).parentJob), isSetPublicVisible: state.isSetPublicVisible || false, isLoading: isLoading, materials: materials, showHeader: showHeader, showMetadata: showMetadata, editable: editable, showHistory: showHistory, workflowHistory: workflowHistory, isStandalone: isStandalone, adjustable: adjustable, metaProperties: metaProperties, extraActions: extraActions, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, profile: profile, publicAccount: publicAccount, clusters: clusters, dialogs: dialogs, templates: templates, onUpdate: onUpdate, onSave: onSave, onNameUpdate: onNameUpdate, onUpdateTags: onUpdateTags, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUnitRemove: onUnitRemove, onUnitUpdate: onUnitUpdate, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, onRender: renderWorkflow, workflowRenderGeneration: renderGeneration, isDescriptionEditable: isDescriptionEditable }) })); + return (_jsxs(WorkflowComponentsContext.Provider, { value: workflowComponents, children: [_jsx(UndoSnackbar, { state: removeUndoState, onClose: () => setRemoveUndoState(null) }), _jsx(WoveWorkflowDesigner, { workflow: workflow, isDirty: isDirty, jobHasParent: Boolean((state.job || {}).parentJob), isSetPublicVisible: state.isSetPublicVisible || false, isLoading: isLoading, materials: materials, showHeader: showHeader, showMetadata: showMetadata, editable: editable, showHistory: showHistory, workflowHistory: workflowHistory, isStandalone: isStandalone, adjustable: adjustable, metaProperties: metaProperties, extraActions: extraActions, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, profile: profile, publicAccount: publicAccount, clusters: clusters, dialogs: dialogs, templates: templates, onUpdate: onUpdate, onSave: onSave, onNameUpdate: onNameUpdate, onUpdateTags: onUpdateTags, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUnitRemove: onUnitRemove, onUnitUpdate: onUnitUpdate, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, onRender: renderWorkflow, workflowRenderGeneration: renderGeneration, isDescriptionEditable: isDescriptionEditable })] })); } diff --git a/dist/components/common/BrillouinZone.d.ts b/dist/components/common/BrillouinZone.d.ts new file mode 100644 index 0000000..c0ce69e --- /dev/null +++ b/dist/components/common/BrillouinZone.d.ts @@ -0,0 +1,25 @@ +import React from "react"; +import { type Vector3 } from "./brillouinZoneGeometry"; +export interface BrillouinZoneProps { + /** + * Reciprocal vectors of the material's own lattice + * (`new ReciprocalLattice(material.lattice).reciprocalVectors`). Preferred: exact for this + * material. wove's component contract does not carry them, so the call site supplies them. + */ + reciprocalVectors?: [Vector3, Vector3, Vector3]; + /** Bravais lattice type, e.g. `FCC` — used only when {@link reciprocalVectors} is absent. */ + latticeType?: string; + /** Web-app asset path wove derives from the lattice; used only as a last fallback. */ + imgSrc?: string; + description?: string; +} +/** + * Draws the first Brillouin zone for a lattice type instead of fetching a per-lattice PNG. + * + * Hosts that ship their own artwork keep passing `BrillouinZoneImageComponent`; this is the + * default for everyone else, where `imgSrc` points at an asset that does not exist (see + * {@link computeBrillouinZoneFaces}). Falls back to the image for lattice types it cannot model. + */ +export declare function BrillouinZone({ reciprocalVectors, latticeType, imgSrc, description, }: BrillouinZoneProps): React.JSX.Element; +export default BrillouinZone; +//# sourceMappingURL=BrillouinZone.d.ts.map \ No newline at end of file diff --git a/dist/components/common/BrillouinZone.d.ts.map b/dist/components/common/BrillouinZone.d.ts.map new file mode 100644 index 0000000..448d054 --- /dev/null +++ b/dist/components/common/BrillouinZone.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"BrillouinZone.d.ts","sourceRoot":"","sources":["../../../src/components/common/BrillouinZone.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,EAEH,KAAK,OAAO,EAGf,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,kBAAkB;IAC/B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAChD,6FAA6F;IAC7F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAsED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAC1B,iBAAiB,EACjB,WAAW,EACX,MAAM,EACN,WAAW,GACd,EAAE,kBAAkB,qBA2DpB;AAED,eAAe,aAAa,CAAC"} \ No newline at end of file diff --git a/dist/components/common/BrillouinZone.js b/dist/components/common/BrillouinZone.js new file mode 100644 index 0000000..fc87551 --- /dev/null +++ b/dist/components/common/BrillouinZone.js @@ -0,0 +1,71 @@ +import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; +import Box from "@mui/material/Box"; +import { useTheme } from "@mui/material/styles"; +import Typography from "@mui/material/Typography"; +import { useMemo } from "react"; +import { computeBrillouinZoneFaces, computeBrillouinZoneFacesFromReciprocalVectors, } from "./brillouinZoneGeometry"; +/** Fixed three-quarter view; the zone is a static illustration, not an interactive scene. */ +const VIEW_YAW = Math.PI / 5; +const VIEW_PITCH = Math.PI / 7; +const SIZE = 220; +const PADDING = 12; +function project([x, y, z]) { + const cosYaw = Math.cos(VIEW_YAW); + const sinYaw = Math.sin(VIEW_YAW); + const rotatedX = x * cosYaw + z * sinYaw; + const rotatedZ = -x * sinYaw + z * cosYaw; + const cosPitch = Math.cos(VIEW_PITCH); + const sinPitch = Math.sin(VIEW_PITCH); + const rotatedY = y * cosPitch - rotatedZ * sinPitch; + // SVG's y axis grows downward, hence the negation. + return { x: rotatedX, y: -rotatedY, depth: y * sinPitch + rotatedZ * cosPitch }; +} +function projectFaces(faces) { + const projectedByFace = faces.map((face) => face.vertices.map(project)); + const all = projectedByFace.flat(); + const minX = Math.min(...all.map((p) => p.x)); + const maxX = Math.max(...all.map((p) => p.x)); + const minY = Math.min(...all.map((p) => p.y)); + const maxY = Math.max(...all.map((p) => p.y)); + const span = Math.max(maxX - minX, maxY - minY) || 1; + const scaleFactor = (SIZE - 2 * PADDING) / span; + const offsetX = PADDING + (SIZE - 2 * PADDING - (maxX - minX) * scaleFactor) / 2; + const offsetY = PADDING + (SIZE - 2 * PADDING - (maxY - minY) * scaleFactor) / 2; + return (projectedByFace + .map((projected, index) => { + const points = projected + .map((p) => `${(offsetX + (p.x - minX) * scaleFactor).toFixed(2)},${(offsetY + + (p.y - minY) * scaleFactor).toFixed(2)}`) + .join(" "); + const depth = projected.reduce((sum, p) => sum + p.depth, 0) / (projected.length || 1); + // Lambert-ish shading from a light above and to the viewer's left. + const [nx, ny, nz] = faces[index].normal; + const shade = Math.max(0, nx * -0.3 + ny * 0.55 + nz * 0.78); + return { points, depth, shade }; + }) + // Painter's algorithm: the zone is convex, so far-to-near ordering hides back faces. + .sort((left, right) => left.depth - right.depth)); +} +/** + * Draws the first Brillouin zone for a lattice type instead of fetching a per-lattice PNG. + * + * Hosts that ship their own artwork keep passing `BrillouinZoneImageComponent`; this is the + * default for everyone else, where `imgSrc` points at an asset that does not exist (see + * {@link computeBrillouinZoneFaces}). Falls back to the image for lattice types it cannot model. + */ +export function BrillouinZone({ reciprocalVectors, latticeType, imgSrc, description, }) { + const theme = useTheme(); + const faces = useMemo(() => reciprocalVectors + ? computeBrillouinZoneFacesFromReciprocalVectors(reciprocalVectors) + : computeBrillouinZoneFaces(latticeType !== null && latticeType !== void 0 ? latticeType : ""), [reciprocalVectors, latticeType]); + const projected = useMemo(() => (faces ? projectFaces(faces) : null), [faces]); + if (!projected) { + if (!imgSrc) + return null; + return (_jsx(Box, { className: "brillouin-zone brillouin-zone--image", children: _jsx("img", { src: imgSrc, alt: description || "Brillouin zone", style: { maxWidth: "100%" } }) })); + } + const faceColor = theme.palette.primary.main; + const edgeColor = theme.palette.mode === "dark" ? "#0d1117" : "#ffffff"; + return (_jsxs(Box, { className: "brillouin-zone", "data-tid": "brillouin-zone", sx: { my: 1 }, children: [_jsx("svg", { width: SIZE, height: SIZE, viewBox: `0 0 ${SIZE} ${SIZE}`, role: "img", "aria-label": `First Brillouin zone of a ${latticeType} lattice`, children: projected.map((face) => (_jsx("polygon", { points: face.points, fill: faceColor, fillOpacity: 0.25 + 0.6 * face.shade, stroke: edgeColor, strokeWidth: 1, strokeLinejoin: "round" }, face.points))) }), _jsxs(Typography, { variant: "caption", color: "text.secondary", component: "div", children: ["First Brillouin zone \u2014 ", latticeType, " lattice"] }), description ? (_jsx(Typography, { variant: "caption", color: "text.secondary", component: "div", children: description })) : null] })); +} +export default BrillouinZone; diff --git a/dist/components/common/UndoSnackbar.d.ts b/dist/components/common/UndoSnackbar.d.ts new file mode 100644 index 0000000..69cf600 --- /dev/null +++ b/dist/components/common/UndoSnackbar.d.ts @@ -0,0 +1,15 @@ +import React from "react"; +export type UndoSnackbarState = { + message: string; + onUndo: () => void; +} | null; +/** + * Post-removal "Undo" affordance: the removal is applied immediately and can be reverted + * within {@link AUTO_HIDE_MS}. Rendered by both the workflow-level container (subworkflow + * removals) and {@link Subworkflow} (unit removals). + */ +export declare function UndoSnackbar({ state, onClose, }: { + state: UndoSnackbarState; + onClose: () => void; +}): React.JSX.Element; +//# sourceMappingURL=UndoSnackbar.d.ts.map \ No newline at end of file diff --git a/dist/components/common/UndoSnackbar.d.ts.map b/dist/components/common/UndoSnackbar.d.ts.map new file mode 100644 index 0000000..2ead80c --- /dev/null +++ b/dist/components/common/UndoSnackbar.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"UndoSnackbar.d.ts","sourceRoot":"","sources":["../../../src/components/common/UndoSnackbar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,MAAM,iBAAiB,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,IAAI,CAAC;CACtB,GAAG,IAAI,CAAC;AAIT;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,OAAO,GACV,EAAE;IACC,KAAK,EAAE,iBAAiB,CAAC;IACzB,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB,qBA2BA"} \ No newline at end of file diff --git a/dist/components/common/UndoSnackbar.js b/dist/components/common/UndoSnackbar.js new file mode 100644 index 0000000..c613a2f --- /dev/null +++ b/dist/components/common/UndoSnackbar.js @@ -0,0 +1,20 @@ +import { jsx as _jsx } from "react/jsx-runtime"; +import Button from "@mui/material/Button"; +import Snackbar from "@mui/material/Snackbar"; +const AUTO_HIDE_MS = 10000; +/** + * Post-removal "Undo" affordance: the removal is applied immediately and can be reverted + * within {@link AUTO_HIDE_MS}. Rendered by both the workflow-level container (subworkflow + * removals) and {@link Subworkflow} (unit removals). + */ +export function UndoSnackbar({ state, onClose, }) { + var _a; + return (_jsx(Snackbar, { open: Boolean(state), autoHideDuration: AUTO_HIDE_MS, onClose: (_event, reason) => { + if (reason === "clickaway") + return; + onClose(); + }, message: (_a = state === null || state === void 0 ? void 0 : state.message) !== null && _a !== void 0 ? _a : "", anchorOrigin: { vertical: "bottom", horizontal: "center" }, "data-tid": "undo-snackbar", action: _jsx(Button, { color: "secondary", size: "small", "data-tid": "undo-remove", onClick: () => { + state === null || state === void 0 ? void 0 : state.onUndo(); + onClose(); + }, children: "Undo" }) })); +} diff --git a/dist/components/common/brillouinZoneForProvider.d.ts b/dist/components/common/brillouinZoneForProvider.d.ts new file mode 100644 index 0000000..30be447 --- /dev/null +++ b/dist/components/common/brillouinZoneForProvider.d.ts @@ -0,0 +1,11 @@ +import React from "react"; +import { type BrillouinZoneProps } from "./BrillouinZone"; +/** + * Binds {@link BrillouinZone} to a context provider's own material, so the zone is computed from + * that material's reciprocal lattice rather than from representative ratios for its lattice type. + * + * wove passes only `latticeType`/`imgSrc` to the injected component, but the call site has the + * provider — and therefore the material — in hand. + */ +export declare function brillouinZoneComponentForProvider(provider: unknown): React.ComponentType; +//# sourceMappingURL=brillouinZoneForProvider.d.ts.map \ No newline at end of file diff --git a/dist/components/common/brillouinZoneForProvider.d.ts.map b/dist/components/common/brillouinZoneForProvider.d.ts.map new file mode 100644 index 0000000..18a6fcf --- /dev/null +++ b/dist/components/common/brillouinZoneForProvider.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"brillouinZoneForProvider.d.ts","sourceRoot":"","sources":["../../../src/components/common/brillouinZoneForProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AA8BzE;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAC7C,QAAQ,EAAE,OAAO,GAClB,KAAK,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAgBzC"} \ No newline at end of file diff --git a/dist/components/common/brillouinZoneForProvider.js b/dist/components/common/brillouinZoneForProvider.js new file mode 100644 index 0000000..3ea523c --- /dev/null +++ b/dist/components/common/brillouinZoneForProvider.js @@ -0,0 +1,47 @@ +import { jsx as _jsx } from "react/jsx-runtime"; +import { ReciprocalLattice } from "@mat3ra/made"; +import { BrillouinZone } from "./BrillouinZone"; +function reciprocalVectorsFromProvider(provider) { + var _a; + const lattice = (_a = provider === null || provider === void 0 ? void 0 : provider.material) === null || _a === void 0 ? void 0 : _a.lattice; + if (!lattice) { + return undefined; + } + try { + const vectors = new ReciprocalLattice(lattice).reciprocalVectors; + return (vectors === null || vectors === void 0 ? void 0 : vectors.length) === 3 ? vectors : undefined; + } + catch (_b) { + // Malformed lattice: fall back to the lattice-type approximation inside the component. + return undefined; + } +} +/** + * Component identity must be stable across renders or React remounts the SVG on every keystroke + * in the k-path form; the provider instance is the natural cache key. + */ +const componentByProvider = new WeakMap(); +/** + * Binds {@link BrillouinZone} to a context provider's own material, so the zone is computed from + * that material's reciprocal lattice rather than from representative ratios for its lattice type. + * + * wove passes only `latticeType`/`imgSrc` to the injected component, but the call site has the + * provider — and therefore the material — in hand. + */ +export function brillouinZoneComponentForProvider(provider) { + if (!provider || typeof provider !== "object") { + return BrillouinZone; + } + const cached = componentByProvider.get(provider); + if (cached) { + return cached; + } + const reciprocalVectors = reciprocalVectorsFromProvider(provider); + const component = reciprocalVectors + ? // eslint-disable-next-line react/jsx-props-no-spreading + (props) => _jsx(BrillouinZone, { ...props, reciprocalVectors: reciprocalVectors }) + : BrillouinZone; + component.displayName = "BrillouinZoneForProvider"; + componentByProvider.set(provider, component); + return component; +} diff --git a/dist/components/common/brillouinZoneGeometry.d.ts b/dist/components/common/brillouinZoneGeometry.d.ts new file mode 100644 index 0000000..7d7e88a --- /dev/null +++ b/dist/components/common/brillouinZoneGeometry.d.ts @@ -0,0 +1,37 @@ +/** + * First Brillouin zone geometry — the Wigner-Seitz cell of the reciprocal lattice. + * + * `@mat3ra/wove` renders the zone by pointing an `` at + * `/images/brillouin_zone/.png`, an asset that ships with the web app only: every + * other consumer of the designer (standalone demo, Storybook, embedders) gets a broken image, + * and the absolute path cannot resolve under a non-root deployment base. The lattice type is + * already known at that point, so the zone can be derived instead of fetched. + */ +export type Vector3 = [number, number, number]; +export interface BrillouinZoneFace { + /** Polygon vertices in reciprocal space, ordered counter-clockwise about {@link normal}. */ + vertices: Vector3[]; + /** Outward unit normal — the reciprocal lattice vector whose bisector plane cuts this face. */ + normal: Vector3; +} +/** + * Builds the first Brillouin zone from the reciprocal lattice vectors: the set of points + * closer to the origin than to any other reciprocal lattice point, i.e. the intersection of + * the half-spaces `x·G ≤ |G|²/2`. Vertices are the plane triple-intersections that satisfy + * every other half-space; faces group the vertices lying on each plane. + * + * Prefer this over {@link computeBrillouinZoneFaces}: it is exact for the material at hand, + * where the lattice *type* alone leaves the cell shape underdetermined. Pass + * `new ReciprocalLattice(material.lattice).reciprocalVectors` from `@mat3ra/made`. + */ +export declare function computeBrillouinZoneFacesFromReciprocalVectors(vectors: [Vector3, Vector3, Vector3]): BrillouinZoneFace[] | null; +/** + * Zone for a Bravais lattice *type*, for callers that have no material to hand. + * + * The type alone does not fix the cell: non-cubic systems have c/a and angle freedom, so + * {@link PRIMITIVE_VECTORS_BY_LATTICE_TYPE} stands in representative ratios — the same + * compromise a single canonical image per type makes. Exact for the cubic systems. + */ +export declare function computeBrillouinZoneFaces(latticeType: string): BrillouinZoneFace[] | null; +export declare const SUPPORTED_LATTICE_TYPES: string[]; +//# sourceMappingURL=brillouinZoneGeometry.d.ts.map \ No newline at end of file diff --git a/dist/components/common/brillouinZoneGeometry.d.ts.map b/dist/components/common/brillouinZoneGeometry.d.ts.map new file mode 100644 index 0000000..8aedc88 --- /dev/null +++ b/dist/components/common/brillouinZoneGeometry.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"brillouinZoneGeometry.d.ts","sourceRoot":"","sources":["../../../src/components/common/brillouinZoneGeometry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAC9B,4FAA4F;IAC5F,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,+FAA+F;IAC/F,MAAM,EAAE,OAAO,CAAC;CACnB;AAsJD;;;;;;;;;GASG;AACH,wBAAgB,8CAA8C,CAC1D,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,GACrC,iBAAiB,EAAE,GAAG,IAAI,CAqF5B;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,iBAAiB,EAAE,GAAG,IAAI,CAUzF;AAED,eAAO,MAAM,uBAAuB,UAAiD,CAAC"} \ No newline at end of file diff --git a/dist/components/common/brillouinZoneGeometry.js b/dist/components/common/brillouinZoneGeometry.js new file mode 100644 index 0000000..949f762 --- /dev/null +++ b/dist/components/common/brillouinZoneGeometry.js @@ -0,0 +1,233 @@ +/** + * First Brillouin zone geometry — the Wigner-Seitz cell of the reciprocal lattice. + * + * `@mat3ra/wove` renders the zone by pointing an `` at + * `/images/brillouin_zone/.png`, an asset that ships with the web app only: every + * other consumer of the designer (standalone demo, Storybook, embedders) gets a broken image, + * and the absolute path cannot resolve under a non-root deployment base. The lattice type is + * already known at that point, so the zone can be derived instead of fetched. + */ +const SQRT3_OVER_2 = Math.sqrt(3) / 2; +/** + * Primitive vectors per Bravais lattice type, in units of `a`. Non-cubic types have shape + * degrees of freedom (c/a, angles) that the lattice *type* alone does not fix; those use + * representative ratios, matching what a single canonical image per type also depicts. + */ +const PRIMITIVE_VECTORS_BY_LATTICE_TYPE = { + CUB: [ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1], + ], + FCC: [ + [0, 0.5, 0.5], + [0.5, 0, 0.5], + [0.5, 0.5, 0], + ], + BCC: [ + [-0.5, 0.5, 0.5], + [0.5, -0.5, 0.5], + [0.5, 0.5, -0.5], + ], + TET: [ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1.4], + ], + BCT: [ + [-0.5, 0.5, 0.7], + [0.5, -0.5, 0.7], + [0.5, 0.5, -0.7], + ], + ORC: [ + [1, 0, 0], + [0, 1.3, 0], + [0, 0, 1.7], + ], + ORCF: [ + [0, 0.65, 0.85], + [0.5, 0, 0.85], + [0.5, 0.65, 0], + ], + ORCI: [ + [-0.5, 0.65, 0.85], + [0.5, -0.65, 0.85], + [0.5, 0.65, -0.85], + ], + ORCC: [ + [0.5, -0.65, 0], + [0.5, 0.65, 0], + [0, 0, 1.7], + ], + HEX: [ + [0.5, -SQRT3_OVER_2, 0], + [0.5, SQRT3_OVER_2, 0], + [0, 0, 1.6], + ], + RHL: [ + [0.9, -0.5, 0.3], + [0.9, 0.5, 0.3], + [0.2, 0, 1.05], + ], + MCL: [ + [1, 0, 0], + [0, 1.2, 0], + [0, 0.55, 1.4], + ], + MCLC: [ + [0.5, 0.6, 0], + [-0.5, 0.6, 0], + [0, 0.55, 1.4], + ], + TRI: [ + [1, 0, 0], + [0.25, 1.15, 0], + [0.3, 0.35, 1.3], + ], +}; +function cross(a, b) { + return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]]; +} +function dot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} +function subtract(a, b) { + return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]; +} +function scale(a, factor) { + return [a[0] * factor, a[1] * factor, a[2] * factor]; +} +function length(a) { + return Math.sqrt(dot(a, a)); +} +function normalize(a) { + const magnitude = length(a); + return magnitude === 0 ? [0, 0, 0] : scale(a, 1 / magnitude); +} +/** + * `2π` is omitted: it scales every reciprocal vector equally, and the zone is drawn normalized. + */ +function reciprocalVectors(a1, a2, a3) { + const volume = dot(a1, cross(a2, a3)); + if (Math.abs(volume) < 1e-12) { + return null; + } + return [ + scale(cross(a2, a3), 1 / volume), + scale(cross(a3, a1), 1 / volume), + scale(cross(a1, a2), 1 / volume), + ]; +} +/** Solves `M x = rhs` for 3×3 `M` by Cramer's rule; null when `M` is singular. */ +function solve3x3(rows, rhs) { + const determinant = dot(rows[0], cross(rows[1], rows[2])); + if (Math.abs(determinant) < 1e-9) { + return null; + } + /** Determinant of `rows` with column `index` replaced by `rhs`. */ + const replacedDeterminant = (index) => { + const replaced = rows.map((row, rowIndex) => { + const next = [...row]; + next[index] = rhs[rowIndex]; + return next; + }); + return dot(replaced[0], cross(replaced[1], replaced[2])); + }; + return [ + replacedDeterminant(0) / determinant, + replacedDeterminant(1) / determinant, + replacedDeterminant(2) / determinant, + ]; +} +const TOLERANCE = 1e-7; +/** + * Builds the first Brillouin zone from the reciprocal lattice vectors: the set of points + * closer to the origin than to any other reciprocal lattice point, i.e. the intersection of + * the half-spaces `x·G ≤ |G|²/2`. Vertices are the plane triple-intersections that satisfy + * every other half-space; faces group the vertices lying on each plane. + * + * Prefer this over {@link computeBrillouinZoneFaces}: it is exact for the material at hand, + * where the lattice *type* alone leaves the cell shape underdetermined. Pass + * `new ReciprocalLattice(material.lattice).reciprocalVectors` from `@mat3ra/made`. + */ +export function computeBrillouinZoneFacesFromReciprocalVectors(vectors) { + const [b1, b2, b3] = vectors; + if ([b1, b2, b3].some((vector) => !vector || vector.length !== 3 || vector.some(Number.isNaN))) { + return null; + } + const reciprocalLatticePoints = []; + for (let h = -2; h <= 2; h += 1) { + for (let k = -2; k <= 2; k += 1) { + for (let l = -2; l <= 2; l += 1) { + if (h !== 0 || k !== 0 || l !== 0) { + reciprocalLatticePoints.push([ + h * b1[0] + k * b2[0] + l * b3[0], + h * b1[1] + k * b2[1] + l * b3[1], + h * b1[2] + k * b2[2] + l * b3[2], + ]); + } + } + } + } + // Only the nearest shells can bound the cell; trimming keeps the triple loop small. + const planes = reciprocalLatticePoints + .sort((left, right) => length(left) - length(right)) + .slice(0, 40) + .map((g) => ({ normal: g, offset: dot(g, g) / 2 })); + const isInsideCell = (point) => planes.every((plane) => dot(point, plane.normal) <= plane.offset + TOLERANCE); + const vertices = []; + for (let i = 0; i < planes.length; i += 1) { + for (let j = i + 1; j < planes.length; j += 1) { + for (let k = j + 1; k < planes.length; k += 1) { + const point = solve3x3([planes[i].normal, planes[j].normal, planes[k].normal], [planes[i].offset, planes[j].offset, planes[k].offset]); + const isCellVertex = Boolean(point) && isInsideCell(point); + const isDuplicate = isCellVertex && + vertices.some((existing) => length(subtract(existing, point)) < 1e-6); + if (isCellVertex && !isDuplicate) { + vertices.push(point); + } + } + } + } + if (vertices.length < 4) { + return null; + } + const faces = []; + planes.forEach((plane) => { + const onPlane = vertices.filter((vertex) => Math.abs(dot(vertex, plane.normal) - plane.offset) < 1e-6); + if (onPlane.length < 3) + return; + // Order the polygon by angle around the face normal, in an in-plane basis. + const normal = normalize(plane.normal); + const centroid = scale(onPlane.reduce((sum, v) => [sum[0] + v[0], sum[1] + v[1], sum[2] + v[2]], [0, 0, 0]), 1 / onPlane.length); + const reference = normalize(subtract(onPlane[0], centroid)); + const bitangent = cross(normal, reference); + const ordered = [...onPlane].sort((left, right) => { + const leftOffset = subtract(left, centroid); + const rightOffset = subtract(right, centroid); + return (Math.atan2(dot(leftOffset, bitangent), dot(leftOffset, reference)) - + Math.atan2(dot(rightOffset, bitangent), dot(rightOffset, reference))); + }); + faces.push({ vertices: ordered, normal }); + }); + return faces.length >= 4 ? faces : null; +} +/** + * Zone for a Bravais lattice *type*, for callers that have no material to hand. + * + * The type alone does not fix the cell: non-cubic systems have c/a and angle freedom, so + * {@link PRIMITIVE_VECTORS_BY_LATTICE_TYPE} stands in representative ratios — the same + * compromise a single canonical image per type makes. Exact for the cubic systems. + */ +export function computeBrillouinZoneFaces(latticeType) { + const key = String(latticeType || "") + .toUpperCase() + .split(/[_\-\s]/)[0]; + const primitiveVectors = PRIMITIVE_VECTORS_BY_LATTICE_TYPE[key]; + if (!primitiveVectors) { + return null; + } + const reciprocal = reciprocalVectors(...primitiveVectors); + return reciprocal ? computeBrillouinZoneFacesFromReciprocalVectors(reciprocal) : null; +} +export const SUPPORTED_LATTICE_TYPES = Object.keys(PRIMITIVE_VECTORS_BY_LATTICE_TYPE); diff --git a/dist/components/subworkflows/ImportantSettings.d.ts.map b/dist/components/subworkflows/ImportantSettings.d.ts.map index 7f9aeaa..d5d18c6 100644 --- a/dist/components/subworkflows/ImportantSettings.d.ts.map +++ b/dist/components/subworkflows/ImportantSettings.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"ImportantSettings.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/ImportantSettings.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA+C,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAK7F,OAAO,KAAK,MAAM,OAAO,CAAC;AAc1B,UAAU,sBAAsB;IAC5B,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAChC;AA6LD,wBAAgB,iBAAiB,CAAC,EAC9B,WAAW,EACX,IAAI,EACJ,SAAS,EACT,EAAE,EACF,gBAAgB,GACnB,EAAE,sBAAsB,qBAmBxB"} \ No newline at end of file +{"version":3,"file":"ImportantSettings.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/ImportantSettings.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA+C,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAK7F,OAAO,KAAK,MAAM,OAAO,CAAC;AAe1B,UAAU,sBAAsB;IAC5B,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAChC;AAwMD,wBAAgB,iBAAiB,CAAC,EAC9B,WAAW,EACX,IAAI,EACJ,SAAS,EACT,EAAE,EACF,gBAAgB,GACnB,EAAE,sBAAsB,qBAmBxB"} \ No newline at end of file diff --git a/dist/components/subworkflows/ImportantSettings.js b/dist/components/subworkflows/ImportantSettings.js index 08f5b7a..9639f5b 100644 --- a/dist/components/subworkflows/ImportantSettings.js +++ b/dist/components/subworkflows/ImportantSettings.js @@ -7,6 +7,7 @@ import Typography from "@mui/material/Typography"; import ajv from "@rjsf/validator-ajv8"; import React from "react"; import { useWorkflowComponents } from "../../WorkflowComponentsContext"; +import { brillouinZoneComponentForProvider } from "../common/brillouinZoneForProvider"; import { mergeUiSchemaWithDefaultFieldStyles } from "./importantSettingsFormUtils"; /** * Use schema `type`, not `instanceof`. Job/workflow units are built via Meteor-compiled @@ -26,6 +27,8 @@ function getProviderTitle(provider) { switch (provider.name) { case "boundaryConditions": return "Boundary Conditions"; + case "cutoffs": + return "Planewave Cutoffs"; default: return provider.name; } @@ -36,7 +39,7 @@ function ImportantSettingsForUnit({ unit, unitIndex, onContextChanged, }) { return (_jsxs(Box, { my: 2, className: "important-settings-for-unit ImportantSettingsForUnit", id: unit.flowchartId, "data-tid": unit.name, children: [_jsx(SubworkflowFormTitleComponent, { title: `Unit ${unitIndex}: ${unit.name}` }), _jsx(Box, { ml: 3, children: getUnitImportantSettingsProviders(unit).map((provider, index) => { const title = getProviderTitle(provider); const data = provider.getData(); - return (_jsxs(Box, { className: "ImportantSettingsForUnit-Box", my: 2, "data-form-revision": formRevision, "data-tid": title, children: [_jsx(Typography, { variant: "h6", children: title }), _jsx(ExtraImportantSettingsByContextProvider, { provider: provider, BrillouinZoneImageComponent: BrillouinZoneImageComponent }), _jsx(RJSForm, { schema: provider.jsonSchema, validator: ajv, uiSchema: provider.uiSchema, formData: data, experimental_defaultFormStateBehavior: { + return (_jsxs(Box, { className: "ImportantSettingsForUnit-Box", my: 2, "data-form-revision": formRevision, "data-tid": title, children: [_jsx(Typography, { variant: "h6", children: title }), _jsx(ExtraImportantSettingsByContextProvider, { provider: provider, BrillouinZoneImageComponent: BrillouinZoneImageComponent !== null && BrillouinZoneImageComponent !== void 0 ? BrillouinZoneImageComponent : brillouinZoneComponentForProvider(provider) }), _jsx(RJSForm, { schema: provider.jsonSchema, validator: ajv, uiSchema: provider.uiSchema, formData: data, experimental_defaultFormStateBehavior: { mergeDefaultsIntoFormData: "useDefaultIfFormDataUndefined", }, onChange: ({ formData }) => { const rootSchema = provider.jsonSchema; @@ -85,7 +88,7 @@ function ImportantSettingsForSubworkflow({ subworkflow, onContextChanged, }) { return (_jsxs(Box, { className: "ImportantSettingsForSubworkflow", my: 2, id: subworkflow.id, children: [_jsx(SubworkflowFormTitleComponent, { title: "Settings global to this Subworkflow" }), _jsx(Box, { ml: 3, mt: 2, children: groups.map((group) => { const [{ provider: firstProvider }] = group; const data = firstProvider.getData(); - return (_jsxs(Box, { children: [_jsx(Typography, { variant: "h6", children: getProviderTitle(firstProvider) }), _jsx(RJSForm, { validator: ajv, schema: firstProvider.jsonSchema, uiSchema: mergeUiSchemaWithDefaultFieldStyles(firstProvider.uiSchema), formData: data, + return (_jsxs(Box, { children: [_jsx(Typography, { variant: "h6", children: getProviderTitle(firstProvider) }), _jsx(RJSForm, { validator: ajv, schema: firstProvider.jsonSchema, uiSchema: mergeUiSchemaWithDefaultFieldStyles(firstProvider.uiSchema, firstProvider.name), formData: data, // fields={firstProvider.fields} // widgets={{ CheckboxWidget: Checkbox }} onChange: ({ formData }) => { diff --git a/dist/components/subworkflows/Subworkflow.d.ts b/dist/components/subworkflows/Subworkflow.d.ts index 67da6ff..f4cd71a 100644 --- a/dist/components/subworkflows/Subworkflow.d.ts +++ b/dist/components/subworkflows/Subworkflow.d.ts @@ -37,17 +37,17 @@ export type SubworkflowProps = { }; export declare const TAB_NAVIGATION_CONFIG: { readonly overview: { - readonly itemName: "Overview"; + readonly itemName: "Units"; readonly className: ""; readonly href: "sw-overview"; }; readonly importantSettings: { - readonly itemName: "Important settings"; + readonly itemName: "Settings"; readonly className: ""; readonly href: "sw-important-settings"; }; readonly detailedView: { - readonly itemName: "Detailed view"; + readonly itemName: "Outputs"; readonly className: ""; readonly href: "sw-detailed-view"; }; diff --git a/dist/components/subworkflows/Subworkflow.d.ts.map b/dist/components/subworkflows/Subworkflow.d.ts.map index a417646..48720ae 100644 --- a/dist/components/subworkflows/Subworkflow.d.ts.map +++ b/dist/components/subworkflows/Subworkflow.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"Subworkflow.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/Subworkflow.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAIvF,OAAO,EAEH,KAAK,eAAe,EACpB,WAAW,IAAI,eAAe,EAEjC,MAAM,cAAc,CAAC;AAOtB,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D,OAAO,KAAK,EACR,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,wCAAwC,EACxC,2BAA2B,EAC3B,4BAA4B,EAC5B,kCAAkC,EAClC,uBAAuB,EACvB,wBAAwB,EAExB,oBAAoB,EACvB,MAAM,qBAAqB,CAAC;AAU7B,MAAM,MAAM,gBAAgB,GAAG;IAC3B,WAAW,EAAE,eAAe,CAAC;IAC7B,QAAQ,EAAE,CAAC,WAAW,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,4BAA4B,EAAE,CAAC;IAChD,qBAAqB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACrD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,WAAW,CAAC,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACrC,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAChD,OAAO,EAAE,uBAAuB,CAAC;IACjC,aAAa,EAAE,uBAAuB,CAAC;IACvC,kBAAkB,EAAE,CAChB,QAAQ,EAAE,wCAAwC,KACjD,OAAO,CAAC,kCAAkC,GAAG,SAAS,CAAC,CAAC;IAC7D,uBAAuB,EAAE,2BAA2B,CAAC;IACrD,mBAAmB,EAAE,2BAA2B,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC3C,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;CAqBxB,CAAC;AAMX,wBAAgB,WAAW,CAAC,EACxB,WAAW,EACX,QAAQ,EACR,YAAoB,EACpB,QAAe,EACf,UAAkB,EAClB,cAAmB,EACnB,qBAAqB,EACrB,mBAA2B,EAC3B,YAAY,EACZ,qBAAqB,EACrB,WAAW,EACX,QAAa,EACb,SAAc,EACd,cAAc,EACd,gBAAgB,EAChB,OAAO,EACP,aAAa,EACb,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,SAAS,EACT,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,iBAAyB,GAC5B,EAAE,gBAAgB,qBA+UlB"} \ No newline at end of file +{"version":3,"file":"Subworkflow.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/Subworkflow.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAIvF,OAAO,EAEH,KAAK,eAAe,EACpB,WAAW,IAAI,eAAe,EAEjC,MAAM,cAAc,CAAC;AAOtB,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D,OAAO,KAAK,EACR,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,wCAAwC,EACxC,2BAA2B,EAC3B,4BAA4B,EAC5B,kCAAkC,EAClC,uBAAuB,EACvB,wBAAwB,EAExB,oBAAoB,EACvB,MAAM,qBAAqB,CAAC;AAW7B,MAAM,MAAM,gBAAgB,GAAG;IAC3B,WAAW,EAAE,eAAe,CAAC;IAC7B,QAAQ,EAAE,CAAC,WAAW,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,4BAA4B,EAAE,CAAC;IAChD,qBAAqB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACrD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,WAAW,CAAC,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACrC,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAChD,OAAO,EAAE,uBAAuB,CAAC;IACjC,aAAa,EAAE,uBAAuB,CAAC;IACvC,kBAAkB,EAAE,CAChB,QAAQ,EAAE,wCAAwC,KACjD,OAAO,CAAC,kCAAkC,GAAG,SAAS,CAAC,CAAC;IAC7D,uBAAuB,EAAE,2BAA2B,CAAC;IACrD,mBAAmB,EAAE,2BAA2B,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC3C,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;CAqBxB,CAAC;AAMX,wBAAgB,WAAW,CAAC,EACxB,WAAW,EACX,QAAQ,EACR,YAAoB,EACpB,QAAe,EACf,UAAkB,EAClB,cAAmB,EACnB,qBAAqB,EACrB,mBAA2B,EAC3B,YAAY,EACZ,qBAAqB,EACrB,WAAW,EACX,QAAa,EACb,SAAc,EACd,cAAc,EACd,gBAAgB,EAChB,OAAO,EACP,aAAa,EACb,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,SAAS,EACT,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,iBAAyB,GAC5B,EAAE,gBAAgB,qBAyVlB"} \ No newline at end of file diff --git a/dist/components/subworkflows/Subworkflow.js b/dist/components/subworkflows/Subworkflow.js index ba0011b..7735721 100644 --- a/dist/components/subworkflows/Subworkflow.js +++ b/dist/components/subworkflows/Subworkflow.js @@ -15,6 +15,7 @@ import Grid from "@mui/material/Grid"; import Stack from "@mui/material/Stack"; import { useCallback, useMemo, useState } from "react"; import { useWorkflowComponents } from "../../WorkflowComponentsContext"; +import { UndoSnackbar } from "../common/UndoSnackbar"; import UnitModal from "../units/UnitModal"; import { ImportantSettings } from "./ImportantSettings"; import { SubworkflowExecutionUnitDetailsRow } from "./SubworkflowExecutionUnitDetailsRow"; @@ -23,17 +24,17 @@ import WorkflowCompute from "./WorkflowCompute"; const AccordionComponent = Accordion; export const TAB_NAVIGATION_CONFIG = { overview: { - itemName: "Overview", + itemName: "Units", className: "", href: "sw-overview", }, importantSettings: { - itemName: "Important settings", + itemName: "Settings", className: "", href: "sw-important-settings", }, detailedView: { - itemName: "Detailed view", + itemName: "Outputs", className: "", href: "sw-detailed-view", }, @@ -50,6 +51,7 @@ export function Subworkflow({ subworkflow, onUpdate, isStandalone = false, edita var _a, _b, _c; const { getDefaultComputeConfig } = useWorkflowComponents(); const [unitIndex, setUnitIndex] = useState(0); + const [removeUndoState, setRemoveUndoState] = useState(null); const applyToSubworkflow = useCallback((fn) => { fn(subworkflow); onUpdate(subworkflow.toJSON()); @@ -101,10 +103,17 @@ export function Subworkflow({ subworkflow, onUpdate, isStandalone = false, edita }); }, [applyToSubworkflow]); const onUnitRemove = useCallback((flowchartId) => { + var _a; + const removedUnit = subworkflow.getUnit(flowchartId); + const snapshot = subworkflow.toJSON(); applyToSubworkflow((sw) => { sw.removeUnit(flowchartId); }); - }, [applyToSubworkflow]); + setRemoveUndoState({ + message: `Removed unit "${(_a = removedUnit === null || removedUnit === void 0 ? void 0 : removedUnit.name) !== null && _a !== void 0 ? _a : flowchartId}"`, + onUndo: () => onUpdate(snapshot), + }); + }, [applyToSubworkflow, subworkflow, onUpdate]); const onUnitClone = useCallback((unit, index) => { const { flowchartId: _omitFlowchartId, next: _omitNext, head: _omitHead, ...config } = unit; applyToSubworkflow((sw) => { @@ -182,5 +191,5 @@ export function Subworkflow({ subworkflow, onUpdate, isStandalone = false, edita // A subworkflow whose Compute tab was open when the host hid it would // otherwise be left showing an empty panel. const visibleTabIndex = hideComputeSubTab && activeTabIndex === COMPUTE_TAB_INDEX ? 0 : activeTabIndex; - return (_jsxs(Stack, { "data-tid": "subworkflow", height: "100%", className: className, children: [_jsx(TabsMenu, { tabs: tabs, activeTabIndex: visibleTabIndex, sx: { fontSize: 12, height: "100%" } }), _jsxs(TabContext, { value: `${visibleTabIndex}`, children: [_jsx(TabPanel, { value: "0", id: TAB_NAVIGATION_CONFIG.overview.href, sx: { height: "100%" }, children: _jsxs(Stack, { spacing: 3, height: "100%", children: [_jsx(AccordionComponent, { header: "Details", id: "subworkflow-accordion", sx: { pt: 0 }, children: _jsxs(Stack, { spacing: 2, children: [_jsx(Properties, { subworkflow: subworkflow, onUpdate: onUpdate, editable: editable || adjustable }), _jsx(ApplicationAve, { application: subworkflow.application, onApplicationUpdate: onApplicationUpdate, editable: editable }), subworkflow.modelInstance.isUnknown ? null : (_jsx(Model, { id: "model", model: subworkflow.modelInstance, models: filteredModels, application: subworkflow.application, onUpdate: onModelUpdate, editable: editable })), _jsx(SubworkflowMethodPanel, { subworkflow: subworkflow, editable: editable, adjustable: adjustable, isMethodDataLoading: isMethodDataLoading, isStandalone: isStandalone, materials: materials, profile: profile, onUpdate: onChildSubworkflowInstanceUpdate, pseudoUploadReduxDialog: pseudoUploadReduxDialog, metaProperties: metaProperties, createMetaProperty: createMetaProperty })] }) }), _jsx(UnitsFlowchartContainer, { units: subworkflow.unitsInstances, onUnitAdd: onUnitAdd, isStandalone: isStandalone, editable: editable, adjustable: adjustable, onUnitClone: onUnitClone, onUnitRemove: onUnitRemove, onUnitUpdate: onUnitUpdate, materials: materials, materialsIndex: materialsIndex, onMaterialSwitch: onMaterialSwitch, subworkflow: subworkflow, onOutputUpdateRequest: onOutputUpdateRequest, publicAccount: publicAccount, unitIndex: unitIndex, onUnitSelect: onUnitSelect, unitTypeReduxDialog: unitTypeReduxDialog, jobProperties: jobProperties, UnitModalComponent: UnitModal })] }) }), _jsx(TabPanel, { value: "1", id: TAB_NAVIGATION_CONFIG.importantSettings.href, "data-tab-name": TAB_NAVIGATION_CONFIG.importantSettings.itemName, children: _jsx(ImportantSettings, { id: TAB_NAVIGATION_CONFIG.importantSettings.href, subworkflow: subworkflow, onContextChanged: onImportantSettingsContextChanged }) }), _jsx(TabPanel, { value: "2", children: _jsx(Grid, { container: true, spacing: 2, children: subworkflow.unitsInstances.map((unit, index) => (_jsx(SubworkflowExecutionUnitDetailsRow, { unit: unit, index: index, editable: editable, onUnitResultsChanged: onUnitResultsChanged, onUnitIsDraftChanged: onUnitIsDraftChanged, onUnitMonitorChanged: onUnitMonitorChanged, onUnitPostProcessorChanged: onUnitPostProcessorChanged }, unit.flowchartId))) }) }), hideComputeSubTab ? null : (_jsx(TabPanel, { value: `${COMPUTE_TAB_INDEX}`, children: _jsx(WorkflowCompute, { compute: subworkflow.compute, onUpdate: onComputeUpdate, onToggle: onComputeToggle, showAdvancedOptions: new Application(subworkflow.application).hasAdvancedComputeOptions, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: currentUser !== null && currentUser !== void 0 ? currentUser : profile.user.entity, clusters: clusters }) }))] })] })); + return (_jsxs(Stack, { "data-tid": "subworkflow", height: "100%", className: className, children: [_jsx(UndoSnackbar, { state: removeUndoState, onClose: () => setRemoveUndoState(null) }), _jsx(TabsMenu, { tabs: tabs, activeTabIndex: visibleTabIndex, sx: { fontSize: 12, height: "100%" } }), _jsxs(TabContext, { value: `${visibleTabIndex}`, children: [_jsx(TabPanel, { value: "0", id: TAB_NAVIGATION_CONFIG.overview.href, sx: { height: "100%" }, children: _jsxs(Stack, { spacing: 3, height: "100%", children: [_jsx(UnitsFlowchartContainer, { units: subworkflow.unitsInstances, onUnitAdd: onUnitAdd, isStandalone: isStandalone, editable: editable, adjustable: adjustable, onUnitClone: onUnitClone, onUnitRemove: onUnitRemove, onUnitUpdate: onUnitUpdate, materials: materials, materialsIndex: materialsIndex, onMaterialSwitch: onMaterialSwitch, subworkflow: subworkflow, onOutputUpdateRequest: onOutputUpdateRequest, publicAccount: publicAccount, unitIndex: unitIndex, onUnitSelect: onUnitSelect, unitTypeReduxDialog: unitTypeReduxDialog, jobProperties: jobProperties, UnitModalComponent: UnitModal }), _jsx(AccordionComponent, { header: "Details", id: "subworkflow-accordion", sx: { pt: 0 }, children: _jsxs(Stack, { spacing: 2, children: [_jsx(Properties, { subworkflow: subworkflow, onUpdate: onUpdate, editable: editable || adjustable }), _jsx(ApplicationAve, { application: subworkflow.application, onApplicationUpdate: onApplicationUpdate, editable: editable }), subworkflow.modelInstance.isUnknown ? null : (_jsx(Model, { id: "model", model: subworkflow.modelInstance, models: filteredModels, application: subworkflow.application, onUpdate: onModelUpdate, editable: editable })), _jsx(SubworkflowMethodPanel, { subworkflow: subworkflow, editable: editable, adjustable: adjustable, isMethodDataLoading: isMethodDataLoading, isStandalone: isStandalone, materials: materials, profile: profile, onUpdate: onChildSubworkflowInstanceUpdate, pseudoUploadReduxDialog: pseudoUploadReduxDialog, metaProperties: metaProperties, createMetaProperty: createMetaProperty })] }) })] }) }), _jsx(TabPanel, { value: "1", id: TAB_NAVIGATION_CONFIG.importantSettings.href, "data-tab-name": TAB_NAVIGATION_CONFIG.importantSettings.itemName, children: _jsx(ImportantSettings, { id: TAB_NAVIGATION_CONFIG.importantSettings.href, subworkflow: subworkflow, onContextChanged: onImportantSettingsContextChanged }) }), _jsx(TabPanel, { value: "2", children: _jsx(Grid, { container: true, spacing: 2, children: subworkflow.unitsInstances.map((unit, index) => (_jsx(SubworkflowExecutionUnitDetailsRow, { unit: unit, index: index, editable: editable, onUnitResultsChanged: onUnitResultsChanged, onUnitIsDraftChanged: onUnitIsDraftChanged, onUnitMonitorChanged: onUnitMonitorChanged, onUnitPostProcessorChanged: onUnitPostProcessorChanged }, unit.flowchartId))) }) }), hideComputeSubTab ? null : (_jsx(TabPanel, { value: `${COMPUTE_TAB_INDEX}`, children: _jsx(WorkflowCompute, { compute: subworkflow.compute, onUpdate: onComputeUpdate, onToggle: onComputeToggle, showAdvancedOptions: new Application(subworkflow.application).hasAdvancedComputeOptions, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: currentUser !== null && currentUser !== void 0 ? currentUser : profile.user.entity, clusters: clusters }) }))] })] })); } diff --git a/dist/components/subworkflows/WorkflowCompute.d.ts.map b/dist/components/subworkflows/WorkflowCompute.d.ts.map index e9ce489..6e775fd 100644 --- a/dist/components/subworkflows/WorkflowCompute.d.ts.map +++ b/dist/components/subworkflows/WorkflowCompute.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"WorkflowCompute.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/WorkflowCompute.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EACR,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,EACvB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,oBAAoB,GAAG;IAC/B,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,WAAW,EAAE,wBAAwB,CAAC;IACtC,QAAQ,CAAC,EAAE,uBAAuB,EAAE,CAAC;CACxC,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACpC,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,mBAAmB,EACnB,YAAY,EACZ,qBAAqB,EACrB,WAAW,EACX,QAAa,GAChB,EAAE,oBAAoB,qBAsCtB"} \ No newline at end of file +{"version":3,"file":"WorkflowCompute.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/WorkflowCompute.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EACR,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,EACvB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,oBAAoB,GAAG;IAC/B,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,WAAW,EAAE,wBAAwB,CAAC;IACtC,QAAQ,CAAC,EAAE,uBAAuB,EAAE,CAAC;CACxC,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACpC,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,mBAAmB,EACnB,YAAY,EACZ,qBAAqB,EACrB,WAAW,EACX,QAAa,GAChB,EAAE,oBAAoB,qBA2CtB"} \ No newline at end of file diff --git a/dist/components/subworkflows/WorkflowCompute.js b/dist/components/subworkflows/WorkflowCompute.js index ca1a5e2..0702c27 100644 --- a/dist/components/subworkflows/WorkflowCompute.js +++ b/dist/components/subworkflows/WorkflowCompute.js @@ -2,10 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; /* eslint-disable jsx-a11y/label-has-associated-control */ import { ComputeForm } from "@mat3ra/ive"; import Box from "@mui/material/Box"; -import Checkbox from "@mui/material/Checkbox"; -import FormControlLabel from "@mui/material/FormControlLabel"; +import Stack from "@mui/material/Stack"; +import Switch from "@mui/material/Switch"; +import Typography from "@mui/material/Typography"; export default function WorkflowCompute({ compute, onToggle, onUpdate, showAdvancedOptions, accountUsers, accountUsersIsLoading, currentUser, clusters = [], }) { - return (_jsxs(Box, { children: [_jsx(Box, { children: _jsx(FormControlLabel, { control: _jsx(Checkbox, { "data-tid": "toggle-compute", onChange: (e) => onToggle(e.target.checked), checked: Boolean(compute) }), label: " Run inside a separate job" }) }), Boolean(compute) && (_jsx(ComputeForm, { id: "compute-form-embedded", compute: compute, user: currentUser, onUpdate: onUpdate, clusters: clusters, showHeader: false, showAdvancedOptions: showAdvancedOptions, accountUsers: accountUsers, isAccountUsersLoading: accountUsersIsLoading, gridParams: { + return (_jsxs(Box, { children: [_jsxs(Stack, { direction: "row", spacing: 1.5, alignItems: "flex-start", sx: { mb: 1 }, children: [_jsx(Switch, { "data-tid": "toggle-compute", checked: Boolean(compute), onChange: (e) => onToggle(e.target.checked), inputProps: { "aria-label": "Override compute for this subworkflow" } }), _jsxs(Box, { children: [_jsx(Typography, { variant: "subtitle1", fontWeight: 600, color: "text.primary", children: "Override compute for this subworkflow" }), _jsx(Typography, { variant: "caption", color: "text.secondary", component: "div", children: "Off: jobs use the compute settings chosen at job creation. On: this subworkflow always runs as a separate job with the resources below." })] })] }), Boolean(compute) && (_jsx(ComputeForm, { id: "compute-form-embedded", compute: compute, user: currentUser, onUpdate: onUpdate, clusters: clusters, showHeader: false, showAdvancedOptions: showAdvancedOptions, accountUsers: accountUsers, isAccountUsersLoading: accountUsersIsLoading, gridParams: { left: { xs: 12, }, diff --git a/dist/components/subworkflows/importantSettingsFormUtils.d.ts b/dist/components/subworkflows/importantSettingsFormUtils.d.ts index aff2929..52e36aa 100644 --- a/dist/components/subworkflows/importantSettingsFormUtils.d.ts +++ b/dist/components/subworkflows/importantSettingsFormUtils.d.ts @@ -10,7 +10,9 @@ export type ImportantSettingsFormProvider = T & { }; /** * Shallow-merges default layout into each top-level entry of `uiSchema`, matching - * `JSONSchemaFormMixin#uiSchemaStyled` without mutating the input. + * `JSONSchemaFormMixin#uiSchemaStyled` without mutating the input. The defaults suppress + * per-field labels; fields listed in {@link PROVIDER_FIELD_LABELS} for `providerName` + * re-enable them with an explicit title instead of rendering bare inputs. */ -export declare function mergeUiSchemaWithDefaultFieldStyles(uiSchema: UiSchema): UiSchema; +export declare function mergeUiSchemaWithDefaultFieldStyles(uiSchema: UiSchema, providerName?: string): UiSchema; //# sourceMappingURL=importantSettingsFormUtils.d.ts.map \ No newline at end of file diff --git a/dist/components/subworkflows/importantSettingsFormUtils.d.ts.map b/dist/components/subworkflows/importantSettingsFormUtils.d.ts.map index 5a0f771..ab5cb34 100644 --- a/dist/components/subworkflows/importantSettingsFormUtils.d.ts.map +++ b/dist/components/subworkflows/importantSettingsFormUtils.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"importantSettingsFormUtils.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/importantSettingsFormUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;GAGG;AACH,MAAM,MAAM,6BAA6B,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;CACtB,CAAC;AAmBF;;;GAGG;AACH,wBAAgB,mCAAmC,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAoBhF"} \ No newline at end of file +{"version":3,"file":"importantSettingsFormUtils.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/importantSettingsFormUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;GAGG;AACH,MAAM,MAAM,6BAA6B,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;CACtB,CAAC;AA+BF;;;;;GAKG;AACH,wBAAgB,mCAAmC,CAC/C,QAAQ,EAAE,QAAQ,EAClB,YAAY,CAAC,EAAE,MAAM,GACtB,QAAQ,CAiCV"} \ No newline at end of file diff --git a/dist/components/subworkflows/importantSettingsFormUtils.js b/dist/components/subworkflows/importantSettingsFormUtils.js index 910ad05..e26689e 100644 --- a/dist/components/subworkflows/importantSettingsFormUtils.js +++ b/dist/components/subworkflows/importantSettingsFormUtils.js @@ -14,23 +14,49 @@ function defaultFieldStylesForMerge() { const { classNames: _omitClassNames, ...rest } = raw; return rest; } +/** + * Field labels the wode provider uiSchemas do not carry themselves (SOF-8024, quick win 1.2). + * Keyed by provider `name`, then schema field. Units are engine-specific (Ry for Quantum + * ESPRESSO), which the provider's own description already states, so labels stay unitless. + */ +const PROVIDER_FIELD_LABELS = { + cutoffs: { + wavefunction: "Wavefunction cutoff", + density: "Charge density cutoff", + }, +}; /** * Shallow-merges default layout into each top-level entry of `uiSchema`, matching - * `JSONSchemaFormMixin#uiSchemaStyled` without mutating the input. + * `JSONSchemaFormMixin#uiSchemaStyled` without mutating the input. The defaults suppress + * per-field labels; fields listed in {@link PROVIDER_FIELD_LABELS} for `providerName` + * re-enable them with an explicit title instead of rendering bare inputs. */ -export function mergeUiSchemaWithDefaultFieldStyles(uiSchema) { +export function mergeUiSchemaWithDefaultFieldStyles(uiSchema, providerName) { const defaultFieldStyles = defaultFieldStylesForMerge(); + const fieldLabels = (providerName && PROVIDER_FIELD_LABELS[providerName]) || {}; return Object.fromEntries(Object.keys(uiSchema).map((key) => { const value = uiSchema[key]; if (value === false) { return [key, false]; } if (value && typeof value === "object" && !Array.isArray(value)) { + const label = fieldLabels[key]; + const labelOverrides = label + ? { + "ui:title": label, + "ui:options": { + ...defaultFieldStyles["ui:options"], + label: true, + title: true, + }, + } + : {}; return [ key, { ...value, ...defaultFieldStyles, + ...labelOverrides, }, ]; } diff --git a/dist/components/units/UnitModal.js b/dist/components/units/UnitModal.js index 1cccfa9..2833579 100644 --- a/dist/components/units/UnitModal.js +++ b/dist/components/units/UnitModal.js @@ -25,7 +25,7 @@ export default function UnitModal({ id = "", title = "", className, onClose, uni onUpdate(unit.toJSON()); }; const renderHeaderCustom = () => { - return (_jsxs(_Fragment, { children: [_jsx(DialogTitle, { component: "div", children: _jsxs(Grid, { container: true, children: [_jsxs(Grid, { item: true, container: true, justifyContent: "space-between", children: [_jsx(Grid, { item: true, children: _jsx(Typography, { variant: "h5", children: "Unit settings" }) }), _jsx(Grid, { item: true, children: _jsx(IconButton, { id: `${id}-close-button`, onClick: onClose, children: _jsx(IconByName, { name: "actions.close", fontSize: "small" }) }) })] }), _jsx(Grid, { item: true, xs: 12, children: _jsx(EntityNameComponent, { editable: editable, value: unit.name, subtitle: { type: unit.type }, description: unit.flowchartId, onUpdate: (name) => onNameUpdate(name), icon: ENTITY_ICONS.unit, status: getUnitStatusCls(unit.status), descriptionLabel: "flowchartId" }) })] }) }), _jsx(Divider, {})] })); + return (_jsxs(_Fragment, { children: [_jsx(DialogTitle, { component: "div", children: _jsxs(Grid, { container: true, children: [_jsxs(Grid, { item: true, container: true, justifyContent: "space-between", children: [_jsx(Grid, { item: true, children: _jsx(Typography, { variant: "h5", children: `${unit.name} — ${unit.type} unit` }) }), _jsx(Grid, { item: true, children: _jsx(IconButton, { id: `${id}-close-button`, onClick: onClose, children: _jsx(IconByName, { name: "actions.close", fontSize: "small" }) }) })] }), _jsx(Grid, { item: true, xs: 12, children: _jsx(EntityNameComponent, { editable: editable, value: unit.name, subtitle: { type: unit.type }, onUpdate: (name) => onNameUpdate(name), icon: ENTITY_ICONS.unit, status: getUnitStatusCls(unit.status) }) })] }) }), _jsx(Divider, {})] })); }; return (_jsxs(Dialog, { open: true, id: id, onClose: onClose, renderHeaderCustom: renderHeaderCustom, renderFooterCustom: () => null, title: title, maxWidth: "lg", className: className ? `UnitModal ${className}` : "UnitModal", scrollable: true, fullWidth: true, children: [_jsx(UnitModalContent, { unit: unit, units: units, onUpdate: onUpdate, adjustable: adjustable, editable: editable, isStandalone: isStandalone, onOutputUpdateRequest: onOutputUpdateRequest, materials: materials, materialsIndex: materialsIndex, onMaterialSwitch: onMaterialSwitch, jobProperties: jobProperties }), _jsx(MetadataComponent, { tags: lodash.get(unit, "tags", []), editable: editable, isSetPublicVisible: false, onUpdateTags: (tags) => { unit.tags = tags; diff --git a/dist/components/workflows/Workflow.d.ts b/dist/components/workflows/Workflow.d.ts index 75385ed..0d60bc1 100644 --- a/dist/components/workflows/Workflow.d.ts +++ b/dist/components/workflows/Workflow.d.ts @@ -15,6 +15,8 @@ export type WorkflowProps = { onUpdateTags?: (tags: string[]) => void; extraActions?: DropdownAction[]; onSave?: (omitRedirect: boolean) => void; + /** Unsaved changes exist; surfaces on the Save affordance. */ + isDirty?: boolean; onNameUpdate?: (name: string) => void; iconCls?: string; onUnitAdd?: (unitType: UnitType, prepend?: boolean, unitIndex?: number) => void; @@ -66,6 +68,13 @@ export type WorkflowProps = { isDescriptionEditable: boolean; /** Refined job properties for unit modals in job designer; optional elsewhere. */ jobProperties?: WorkflowDesignerProperty[]; + /** + * Shows unit status on cards and flowchart nodes. Off by default: in the + * designer nothing has run, so every unit reports a meaningless "idle". + * Hosts that render a workflow which is actually executing — the job + * designer, once a job leaves draft — turn it on. + */ + showUnitStatus?: boolean; /** * Hides each subworkflow's own Compute tab. Set it when the host renders a * compute surface of its own, as the job designer does — otherwise the same @@ -74,6 +83,6 @@ export type WorkflowProps = { */ hideComputeSubTab?: boolean; }; -export declare function Workflow({ workflow, metaProperties, onUpdate, onOutputUpdateRequest, onUpdateTags, extraActions, onSave, onNameUpdate, iconCls, onUnitAdd, onUnitAddSubworkflowFromConfig, onUnitRemove, onUnitUpdate, onSubworkflowUnitUpdate, materials, materialsIndex, jobHasParent, onMaterialSwitch, showHeaderPager, onHeaderPagerUpdate, dialogs, createMetaProperty, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, templates, isStandalone, isHeaderCompact, editable, adjustable, isLoading, showHeader, isMethodDataLoading, materialsSet, isMap, isSetPublicVisible, showMetadata, showHistory, workflowHistory, onIsMultiMaterialChanged, onRender, renderAtJobLevel, workflowRenderGeneration, isDescriptionEditable, jobProperties, hideComputeSubTab, }: WorkflowProps): React.JSX.Element; +export declare function Workflow({ workflow, metaProperties, onUpdate, onOutputUpdateRequest, onUpdateTags, extraActions, onSave, isDirty, onNameUpdate, iconCls, onUnitAdd, onUnitAddSubworkflowFromConfig, onUnitRemove, onUnitUpdate, onSubworkflowUnitUpdate, materials, materialsIndex, jobHasParent, onMaterialSwitch, showHeaderPager, onHeaderPagerUpdate, dialogs, createMetaProperty, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, templates, isStandalone, isHeaderCompact, editable, adjustable, isLoading, showHeader, isMethodDataLoading, materialsSet, isMap, isSetPublicVisible, showMetadata, showHistory, workflowHistory, onIsMultiMaterialChanged, onRender, renderAtJobLevel, workflowRenderGeneration, isDescriptionEditable, jobProperties, hideComputeSubTab, showUnitStatus, }: WorkflowProps): React.JSX.Element; export {}; //# sourceMappingURL=Workflow.d.ts.map \ No newline at end of file diff --git a/dist/components/workflows/Workflow.d.ts.map b/dist/components/workflows/Workflow.d.ts.map index 23fcac2..607681d 100644 --- a/dist/components/workflows/Workflow.d.ts.map +++ b/dist/components/workflows/Workflow.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"Workflow.d.ts","sourceRoot":"","sources":["../../../src/components/workflows/Workflow.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"Workflow.d.ts","sourceRoot":"","sources":["../../../src/components/workflows/Workflow.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/components/workflows/Workflow.js b/dist/components/workflows/Workflow.js index 0308598..b4165ee 100644 --- a/dist/components/workflows/Workflow.js +++ b/dist/components/workflows/Workflow.js @@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime"; import IconByName from "@mat3ra/cove/dist/mui/components/icon"; import { Workflow as WodeWorkflow } from "@mat3ra/wode"; import { UnitType } from "@mat3ra/wode/dist/js/enums"; -import { getUnitStatusCls, getWorkflowStatusCls } from "@mat3ra/wove"; +import { getUnitStatusCls, getWorkflowStatusCls, WoveDisplayOptionsProvider } from "@mat3ra/wove"; import Box from "@mui/material/Box"; import findIndex from "lodash/findIndex"; import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react"; @@ -11,8 +11,10 @@ import { getWorkflowDesignerTabResetKey } from "./workflowDesignerTabState"; const noop = () => undefined; const EMPTY_META_PROPERTIES = []; const noopUnitAddSubworkflowFromConfig = (_config, _prependOrPasteIndex, _unitIndex) => undefined; -export function Workflow({ workflow, metaProperties = EMPTY_META_PROPERTIES, onUpdate = noop, onOutputUpdateRequest, onUpdateTags, extraActions = [], onSave, onNameUpdate, iconCls, onUnitAdd = noop, onUnitAddSubworkflowFromConfig = noopUnitAddSubworkflowFromConfig, onUnitRemove = noop, onUnitUpdate = noop, onSubworkflowUnitUpdate = noop, materials = [], materialsIndex, jobHasParent = false, onMaterialSwitch, showHeaderPager = false, onHeaderPagerUpdate, dialogs, createMetaProperty = async (_property) => undefined, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters = [], templates, isStandalone = false, isHeaderCompact, editable = false, adjustable = false, isLoading = false, showHeader = true, isMethodDataLoading = false, materialsSet, isMap, isSetPublicVisible, showMetadata = true, showHistory = false, workflowHistory = [], onIsMultiMaterialChanged, onRender, renderAtJobLevel = false, workflowRenderGeneration, isDescriptionEditable, jobProperties, hideComputeSubTab = false, }) { +export function Workflow({ workflow, metaProperties = EMPTY_META_PROPERTIES, onUpdate = noop, onOutputUpdateRequest, onUpdateTags, extraActions = [], onSave, isDirty = false, onNameUpdate, iconCls, onUnitAdd = noop, onUnitAddSubworkflowFromConfig = noopUnitAddSubworkflowFromConfig, onUnitRemove = noop, onUnitUpdate = noop, onSubworkflowUnitUpdate = noop, materials = [], materialsIndex, jobHasParent = false, onMaterialSwitch, showHeaderPager = false, onHeaderPagerUpdate, dialogs, createMetaProperty = async (_property) => undefined, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters = [], templates, isStandalone = false, isHeaderCompact, editable = false, adjustable = false, isLoading = false, showHeader = true, isMethodDataLoading = false, materialsSet, isMap, isSetPublicVisible, showMetadata = true, showHistory = false, workflowHistory = [], onIsMultiMaterialChanged, onRender, renderAtJobLevel = false, workflowRenderGeneration, isDescriptionEditable, jobProperties, hideComputeSubTab = false, showUnitStatus = false, }) { const [unitIndex, setUnitIndex] = useState(0); + // Identifiers are noise for the person reading a workflow; opt-in per session. + const [showDeveloperInfo, setShowDeveloperInfo] = useState(false); const [isRelaxationToggled, setIsRelaxationToggled] = useState(false); const [isMultiMaterialToggled, setIsMultiMaterialToggled] = useState(() => Boolean(workflow.isMultiMaterial)); const [areWorkflowContentExpanded, setAreWorkflowContentExpanded] = useState(false); @@ -169,6 +171,18 @@ export function Workflow({ workflow, metaProperties = EMPTY_META_PROPERTIES, onU showCheckIcon: isMultiMaterialToggled, id: "toggle-multi-material", }, + { + // Identifiers are hidden by default; this is how someone + // debugging gets them back without them being on show for + // everyone else. + isShown: true, + content: "Developer info", + onClick: (_action, _event) => { + setShowDeveloperInfo((isShown) => !isShown); + }, + showCheckIcon: showDeveloperInfo, + id: "toggle-developer-info", + }, ]; }, [ adjustable, @@ -177,6 +191,7 @@ export function Workflow({ workflow, metaProperties = EMPTY_META_PROPERTIES, onU isRelaxationToggled, toggleIsMultiMaterial, toggleRelaxation, + showDeveloperInfo, ]); const getActions = useCallback(() => { return [...getDefaultActions(), ...extraActions]; @@ -194,11 +209,12 @@ export function Workflow({ workflow, metaProperties = EMPTY_META_PROPERTIES, onU return { isShown: Boolean(editable && isStandalone), isLoading, + isDirty, onSave: (omitRedirect) => { onSave === null || onSave === void 0 ? void 0 : onSave(omitRedirect !== null && omitRedirect !== void 0 ? omitRedirect : false); }, }; - }, [editable, isLoading, isStandalone, onSave]); + }, [editable, isLoading, isStandalone, onSave, isDirty]); const getDropdownProps = useCallback(() => { return { isShown: true, @@ -207,5 +223,5 @@ export function Workflow({ workflow, metaProperties = EMPTY_META_PROPERTIES, onU buttonContent: "Select Workflow Actions", }; }, [getActions]); - return (_jsx(Box, { "data-workflow-render-generation": workflowRenderGeneration, children: _jsx(WorkflowDefaultLayout, { entity: workflow, unitIndex: unitIndex, isMap: isMap, materials: materials, materialsIndex: materialsIndex, materialsSet: materialsSet, jobHasParent: jobHasParent, editable: Boolean(editable), adjustable: Boolean(adjustable), isLoading: isLoading, showHeader: showHeader, isHeaderCompact: isHeaderCompact, isStandalone: isStandalone, isMethodDataLoading: isMethodDataLoading, isSetPublicVisible: isSetPublicVisible, showMetadata: showMetadata, showHistory: showHistory, workflowHistory: workflowHistory, iconCls: iconCls, onNameUpdate: onNameUpdate, onUpdateTags: onUpdateTags, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUnitUpdate: onUnitUpdate, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, onMapWorkflowUpdate: onMapWorkflowUpdate, onUnitSelect: onUnitSelect, onUpdateUnitIndex: onUpdateUnitIndex, handleUnitRemove: handleUnitRemove, onUnitNameUpdate: onUnitNameUpdate, areWorkflowContentExpanded: areWorkflowContentExpanded, toggleExpandWorkflowContent: toggleExpandWorkflowContent, headerStatusCls: headerStatusCls, getPagerProps: getPagerProps, getSaveBtnProps: getSaveBtnProps, getDropdownProps: getDropdownProps, isDescriptionEditable: isDescriptionEditable, onDescriptionUpdate: onDescriptionUpdate, dialogs: dialogs, metaProperties: metaProperties, onMaterialSwitch: onMaterialSwitch, onOutputUpdateRequest: onOutputUpdateRequest, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, profile: profile, publicAccount: publicAccount, clusters: clusters, templates: templates, createMetaProperty: createMetaProperty, jobProperties: jobProperties, hideComputeSubTab: hideComputeSubTab, subworkflowActiveTabIndexById: subworkflowActiveTabIndexById, onSubworkflowActiveTabIndexChange: onSubworkflowActiveTabIndexChange }) })); + return (_jsx(WoveDisplayOptionsProvider, { showDeveloperInfo: showDeveloperInfo, showStatus: showUnitStatus, children: _jsx(Box, { "data-workflow-render-generation": workflowRenderGeneration, children: _jsx(WorkflowDefaultLayout, { entity: workflow, unitIndex: unitIndex, isMap: isMap, materials: materials, materialsIndex: materialsIndex, materialsSet: materialsSet, jobHasParent: jobHasParent, editable: Boolean(editable), adjustable: Boolean(adjustable), isLoading: isLoading, showHeader: showHeader, isHeaderCompact: isHeaderCompact, isStandalone: isStandalone, isMethodDataLoading: isMethodDataLoading, isSetPublicVisible: isSetPublicVisible, showMetadata: showMetadata, showHistory: showHistory, workflowHistory: workflowHistory, iconCls: iconCls, onNameUpdate: onNameUpdate, onUpdateTags: onUpdateTags, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUnitUpdate: onUnitUpdate, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, onMapWorkflowUpdate: onMapWorkflowUpdate, onUnitSelect: onUnitSelect, onUpdateUnitIndex: onUpdateUnitIndex, handleUnitRemove: handleUnitRemove, onUnitNameUpdate: onUnitNameUpdate, areWorkflowContentExpanded: areWorkflowContentExpanded, toggleExpandWorkflowContent: toggleExpandWorkflowContent, headerStatusCls: headerStatusCls, getPagerProps: getPagerProps, getSaveBtnProps: getSaveBtnProps, getDropdownProps: getDropdownProps, isDescriptionEditable: isDescriptionEditable, onDescriptionUpdate: onDescriptionUpdate, dialogs: dialogs, metaProperties: metaProperties, onMaterialSwitch: onMaterialSwitch, onOutputUpdateRequest: onOutputUpdateRequest, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, profile: profile, publicAccount: publicAccount, clusters: clusters, templates: templates, createMetaProperty: createMetaProperty, jobProperties: jobProperties, hideComputeSubTab: hideComputeSubTab, subworkflowActiveTabIndexById: subworkflowActiveTabIndexById, onSubworkflowActiveTabIndexChange: onSubworkflowActiveTabIndexChange }) }) })); } diff --git a/dist/standalone/index.js b/dist/standalone/index.js index 22e6954..c5bb726 100644 --- a/dist/standalone/index.js +++ b/dist/standalone/index.js @@ -107,6 +107,7 @@ function App() { return siIndex >= 0 ? siIndex : 0; }); const selectedMaterial = allMaterials[materialIndex]; + const [isDirty, setIsDirty] = useState(false); // Re-key the designer when either selection changes so it re-mounts cleanly const designerKey = `${workflowIndex}-${materialIndex}`; const handleSave = useCallback(async () => { @@ -128,13 +129,19 @@ function App() { WebkitTextFillColor: "transparent", mr: 2, flexShrink: 0, - }, children: "Workflow Designer" }), _jsxs(FormControl, { size: "small", sx: { minWidth: 300 }, children: [_jsx(InputLabel, { id: "workflow-select-label", children: "Workflow" }), _jsx(Select, { labelId: "workflow-select-label", id: "workflow-select", value: workflowIndex, label: "Workflow", onChange: (e) => setWorkflowIndex(Number(e.target.value)), children: allWorkflowJsons.map((wf, i) => { + }, children: "Workflow Designer" }), _jsxs(FormControl, { size: "small", sx: { minWidth: 300 }, children: [_jsx(InputLabel, { id: "workflow-select-label", children: "Workflow" }), _jsx(Select, { labelId: "workflow-select-label", id: "workflow-select", value: workflowIndex, label: "Workflow", onChange: (e) => { + setWorkflowIndex(Number(e.target.value)); + setIsDirty(false); + }, children: allWorkflowJsons.map((wf, i) => { var _a; return (_jsx(MenuItem, { value: i, children: (_a = wf === null || wf === void 0 ? void 0 : wf.name) !== null && _a !== void 0 ? _a : `Workflow ${i + 1}` }, i)); - }) })] }), appName && (_jsx(Chip, { label: appName, size: "small", variant: "outlined", color: "primary" })), _jsx(Divider, { orientation: "vertical", flexItem: true }), _jsxs(FormControl, { size: "small", sx: { minWidth: 260 }, children: [_jsx(InputLabel, { id: "material-select-label", children: "Material" }), _jsx(Select, { labelId: "material-select-label", id: "material-select", value: materialIndex, label: "Material", onChange: (e) => setMaterialIndex(Number(e.target.value)), children: allMaterials.map((mat, i) => { + }) })] }), appName && (_jsx(Chip, { label: appName, size: "small", variant: "outlined", color: "primary" })), _jsx(Divider, { orientation: "vertical", flexItem: true }), _jsxs(FormControl, { size: "small", sx: { minWidth: 260 }, children: [_jsx(InputLabel, { id: "material-select-label", children: "Material" }), _jsx(Select, { labelId: "material-select-label", id: "material-select", value: materialIndex, label: "Material", onChange: (e) => { + setMaterialIndex(Number(e.target.value)); + setIsDirty(false); + }, children: allMaterials.map((mat, i) => { var _a, _b; return (_jsx(MenuItem, { value: i, children: (_b = (_a = mat === null || mat === void 0 ? void 0 : mat.name) !== null && _a !== void 0 ? _a : mat === null || mat === void 0 ? void 0 : mat.formula) !== null && _b !== void 0 ? _b : `Material ${i + 1}` }, i)); - }) })] }), _jsx(Chip, { label: `${allWorkflowJsons.length} workflows · ${allMaterials.length} materials`, size: "small", variant: "outlined", color: "secondary", sx: { ml: "auto" } })] }) }), _jsx(Box, { sx: { height: "calc(100vh - 72px)", overflow: "auto" }, children: _jsx(WorkflowDesignerContainer, { initialWorkflow: wodeWorkflow, defaultMaterial: selectedMaterial, editable: true, showHistory: false, workflowHistory: { list: [], loading: false }, isStandalone: true, adjustable: true, showHeader: true, showMetadata: false, accountUsers: [], accountUsersIsLoading: false, profile: { + }) })] }), isDirty && (_jsx(Chip, { label: "\u25CF Unsaved changes", size: "small", variant: "outlined", color: "warning", "data-tid": "dirty-indicator" })), _jsx(Chip, { label: `${allWorkflowJsons.length} workflows · ${allMaterials.length} materials`, size: "small", variant: "outlined", color: "secondary", sx: { ml: "auto" } })] }) }), _jsx(Box, { sx: { height: "calc(100vh - 72px)", overflow: "auto" }, children: _jsx(WorkflowDesignerContainer, { initialWorkflow: wodeWorkflow, defaultMaterial: selectedMaterial, editable: true, showHistory: false, workflowHistory: { list: [], loading: false }, isStandalone: true, adjustable: true, showHeader: true, showMetadata: false, accountUsers: [], accountUsersIsLoading: false, profile: { user: { entity: { id: "1" } }, account: { entity: { id: "1" } }, personalAccount: { entity: { id: "1" } }, @@ -147,7 +154,7 @@ function App() { nodes: 1, queue: "D", timeLimit: "01:00:00", - }), generateEntityId: () => crypto.randomUUID(), openDocumentationDialog: undefined }, designerKey) })] })); + }), generateEntityId: () => crypto.randomUUID(), openDocumentationDialog: undefined, onDirtyChange: setIsDirty }, designerKey) })] })); } // --------------------------------------------------------------------------- // Mount diff --git a/src/components/workflows/Workflow.tsx b/src/components/workflows/Workflow.tsx index 403843f..1ea8d63 100644 --- a/src/components/workflows/Workflow.tsx +++ b/src/components/workflows/Workflow.tsx @@ -5,7 +5,7 @@ import type { Template } from "@mat3ra/ade"; import { type MaterialsSet, type OrderedMaterial, Workflow as WodeWorkflow } from "@mat3ra/wode"; import { UnitType } from "@mat3ra/wode/dist/js/enums"; import type { AnyWorkflowUnit } from "@mat3ra/wode/dist/js/units/factory"; -import { getUnitStatusCls, getWorkflowStatusCls } from "@mat3ra/wove"; +import { getUnitStatusCls, getWorkflowStatusCls, WoveDisplayOptionsProvider } from "@mat3ra/wove"; import Box from "@mui/material/Box"; import findIndex from "lodash/findIndex"; import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react"; @@ -95,6 +95,13 @@ export type WorkflowProps = { isDescriptionEditable: boolean; /** Refined job properties for unit modals in job designer; optional elsewhere. */ jobProperties?: WorkflowDesignerProperty[]; + /** + * Shows unit status on cards and flowchart nodes. Off by default: in the + * designer nothing has run, so every unit reports a meaningless "idle". + * Hosts that render a workflow which is actually executing — the job + * designer, once a job leaves draft — turn it on. + */ + showUnitStatus?: boolean; /** * Hides each subworkflow's own Compute tab. Set it when the host renders a * compute surface of its own, as the job designer does — otherwise the same @@ -164,8 +171,11 @@ export function Workflow({ isDescriptionEditable, jobProperties, hideComputeSubTab = false, + showUnitStatus = false, }: WorkflowProps) { const [unitIndex, setUnitIndex] = useState(0); + // Identifiers are noise for the person reading a workflow; opt-in per session. + const [showDeveloperInfo, setShowDeveloperInfo] = useState(false); const [isRelaxationToggled, setIsRelaxationToggled] = useState(false); const [isMultiMaterialToggled, setIsMultiMaterialToggled] = useState(() => Boolean(workflow.isMultiMaterial), @@ -377,6 +387,18 @@ export function Workflow({ showCheckIcon: isMultiMaterialToggled, id: "toggle-multi-material", }, + { + // Identifiers are hidden by default; this is how someone + // debugging gets them back without them being on show for + // everyone else. + isShown: true, + content: "Developer info", + onClick: (_action, _event) => { + setShowDeveloperInfo((isShown) => !isShown); + }, + showCheckIcon: showDeveloperInfo, + id: "toggle-developer-info", + }, ]; }, [ adjustable, @@ -385,6 +407,7 @@ export function Workflow({ isRelaxationToggled, toggleIsMultiMaterial, toggleRelaxation, + showDeveloperInfo, ]); const getActions = useCallback(() => { @@ -422,62 +445,67 @@ export function Workflow({ }, [getActions]); return ( - - - + + + + + ); } From bdcc73a07c1f1b0b993ac74e6cdedaab4f636a59 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Aug 2026 21:45:54 +0000 Subject: [PATCH 4/6] chore: arm the pre-commit hook so dist stays in sync The hook that regenerates dist has never run: husky was not a dependency and no prepare script installed it, so a fresh clone had .husky/pre-commit sitting inert. That is why several packages landed src changes with a stale or entirely missing dist - including new modules whose emitted code imported files that were never built. Adds husky + 'prepare: husky install' (matching cove, the one repo where this works), and drops 'npx lint-staged' from the hook: lint-staged is neither a dependency nor configured here, so arming the hook with that line would have failed and blocked every commit. Linting is enforced in CI regardless. Verified in ive: staging only a src file produced a commit that included the regenerated dist output. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01DK8KomMescJvMQNSEfeRR8 --- .husky/pre-commit | 5 ++++- package.json | 44 +++++++++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 76031ec..5325f24 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,6 +1,9 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -npx lint-staged +# dist/ is tracked and shipped ("files": ["/dist", "/src"]), so a src change +# committed without it leaves consumers on the old code - and a brand-new module +# is worse than stale, since its dist file is absent entirely and the emitted +# code imports something that does not exist. npm run transpile git add dist/ diff --git a/package.json b/package.json index 541fae8..3b52693 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "scripts": { "build": "tsc && npm run copy-css", "copy-css": "mkdir -p dist/stylesheets && cp src/stylesheets/* dist/stylesheets/ 2>/dev/null || true", + "prepare": "husky install", "transpile": "tsc", "test": "node --import tsx --test tests/*.tests.ts", "lint": "eslint src tests && prettier --check src tests", @@ -52,21 +53,22 @@ }, "license": "Apache-2.0", "devDependencies": { - "@mat3ra/cove": "2026.7.18-4", - "@mat3ra/wave.js": "2026.7.18-1", + "@exabyte-io/eslint-config": "^2025.1.15-0", "@mat3ra/ade": "2026.5.29-0", + "@mat3ra/ave": "2026.7.21-0", "@mat3ra/code": "2026.5.27-0", + "@mat3ra/cove": "2026.7.18-4", "@mat3ra/esse": "2026.7.14-0", + "@mat3ra/ive": "2026.7.18-0", "@mat3ra/mode": "2026.6.3-0", + "@mat3ra/move": "2026.7.18-1", + "@mat3ra/prove": "2026.7.18-0", "@mat3ra/standata": "2026.7.13-0", "@mat3ra/tsconfig": "^2024.6.3-0", + "@mat3ra/utils": "2026.7.9-0", + "@mat3ra/wave.js": "2026.7.18-1", "@mat3ra/wode": "2026.7.9-0", - "@mat3ra/ave": "2026.7.21-0", - "@mat3ra/ive": "2026.7.18-0", - "@mat3ra/move": "2026.7.18-1", - "@mat3ra/prove": "2026.7.18-0", "@mat3ra/wove": "2026.7.21-0", - "@mat3ra/utils": "2026.7.9-0", "@mui/icons-material": "^5.11.9", "@mui/lab": "^5.0.0-alpha.120", "@mui/material": "^5.11.9", @@ -77,21 +79,9 @@ "@types/node": "^20.11.30", "@types/react": "^17.0.2", "@types/react-dom": "^17.0.2", - "@vitejs/plugin-react": "^4.3.4", - "lodash": "^4.17.4", - "mathjs": "^5.10.3", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "reactflow": "^11.7.2", - "tsx": "^4.22.4", - "typescript": "^5.6.6", - "underscore": "^1.8.3", - "underscore.string": "^3.3.4", - "vite": "^6.0.7", - "vite-plugin-node-polyfills": "^0.25.0", - "@exabyte-io/eslint-config": "^2025.1.15-0", "@typescript-eslint/eslint-plugin": "^5.9.1", "@typescript-eslint/parser": "^5.9.1", + "@vitejs/plugin-react": "^4.3.4", "babel-eslint": "^10.1.0", "eslint": "^7.32.0", "eslint-config-airbnb": "^19.0.2", @@ -107,6 +97,18 @@ "eslint-plugin-react": "^7.30.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-simple-import-sort": "^7.0.0", - "prettier": "2.5.1" + "husky": "^7.0.4", + "lodash": "^4.17.4", + "mathjs": "^5.10.3", + "prettier": "2.5.1", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "reactflow": "^11.7.2", + "tsx": "^4.22.4", + "typescript": "^5.6.6", + "underscore": "^1.8.3", + "underscore.string": "^3.3.4", + "vite": "^6.0.7", + "vite-plugin-node-polyfills": "^0.25.0" } } From fbc29d021507a6138768afd87e5701804c36f07f Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Aug 2026 03:47:14 +0000 Subject: [PATCH 5/6] feat: unit inspector drawer, and let the designer inherit its host's theme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 3.3. **Unit inspector (D3).** Adjusting a unit meant leaving the flowchart for the Settings tab, finding that unit among all the others, changing it, and coming back to see what it did — a bounce between three tabs for one edit, with the diagram that gives the change its meaning off screen throughout. Clicking a unit now opens its settings beside the flowchart, which keeps it selected. The panel reuses ImportantSettingsForUnit, so it is the same form the Settings tab shows, scoped to one unit. A plain MUI Drawer rather than cove's ResizableDrawer: that one is anchored to the bottom and resizes on height only, and generalising it to two axes is a change to a shared component with its own consumers. The width handle here is a few lines and puts none of them at risk. **Theme parity (D4).** WorkflowDefaultLayout pinned the whole designer to `oldLightMaterialUITheme`. That is why a dark host framed a white canvas: the shell was dark and this subtree never was. `useHostTheme` skips the override and inherits. Both are opt-in, defaulting off, so the tabs and the light designer are untouched until a host asks for otherwise. **Also fixed: the unit test suite never ran.** Tests import the package by its own name (`@mat3ra/workflow-designer/src/...`), which resolves neither by self-reference — `tests/package.json` names that directory a different package — nor through node_modules. All 16 tests failed on main with "is not a function". One tsconfig `paths` entry fixes it; 16/16 now pass. Unrelated to the rest of this commit, but a repo whose suite is dead cannot review the rest of it. Verified in the demo: clicking a unit card opens the drawer titled "cp · Unit 1 · execution" carrying that unit's dynamics parameters; closing works; with the toggle off no drawer appears. Under the demo's dark theme the flowchart pane is now #0d1117 with white control glyphs (needs the matching wove change). Refs SOF-8023. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01DK8KomMescJvMQNSEfeRR8 --- .husky/post-checkout | 3 + .husky/post-commit | 3 + .husky/post-merge | 3 + .husky/pre-push | 3 + dist/WorkflowDesignerContainer.d.ts | 4 + dist/WorkflowDesignerContainer.d.ts.map | 2 +- dist/WorkflowDesignerContainer.js | 4 +- .../subworkflows/ImportantSettings.d.ts | 8 +- .../subworkflows/ImportantSettings.d.ts.map | 2 +- .../subworkflows/ImportantSettings.js | 2 +- dist/components/subworkflows/Subworkflow.d.ts | 11 +- .../subworkflows/Subworkflow.d.ts.map | 2 +- dist/components/subworkflows/Subworkflow.js | 21 +- .../subworkflows/UnitInspectorDrawer.d.ts | 26 ++ .../subworkflows/UnitInspectorDrawer.d.ts.map | 1 + .../subworkflows/UnitInspectorDrawer.js | 72 ++++ dist/components/workflows/Workflow.d.ts | 6 +- dist/components/workflows/Workflow.d.ts.map | 2 +- dist/components/workflows/Workflow.js | 4 +- .../workflows/WorkflowDefaultLayout.d.ts | 11 + .../workflows/WorkflowDefaultLayout.d.ts.map | 2 +- .../workflows/WorkflowDefaultLayout.js | 15 +- dist/standalone/index.js | 6 +- src/WorkflowDesignerContainer.tsx | 8 + .../subworkflows/ImportantSettings.tsx | 2 +- src/components/subworkflows/Subworkflow.tsx | 29 +- .../subworkflows/UnitInspectorDrawer.tsx | 143 ++++++++ src/components/workflows/Workflow.tsx | 8 + .../workflows/WorkflowDefaultLayout.tsx | 315 +++++++++--------- src/standalone/index.tsx | 14 +- tsconfig.json | 3 + 31 files changed, 553 insertions(+), 182 deletions(-) create mode 100755 .husky/post-checkout create mode 100755 .husky/post-commit create mode 100755 .husky/post-merge create mode 100755 .husky/pre-push create mode 100644 dist/components/subworkflows/UnitInspectorDrawer.d.ts create mode 100644 dist/components/subworkflows/UnitInspectorDrawer.d.ts.map create mode 100644 dist/components/subworkflows/UnitInspectorDrawer.js create mode 100644 src/components/subworkflows/UnitInspectorDrawer.tsx diff --git a/.husky/post-checkout b/.husky/post-checkout new file mode 100755 index 0000000..ca7fcb4 --- /dev/null +++ b/.husky/post-checkout @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'post-checkout' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks').\n"; exit 2; } +git lfs post-checkout "$@" diff --git a/.husky/post-commit b/.husky/post-commit new file mode 100755 index 0000000..52b339c --- /dev/null +++ b/.husky/post-commit @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'post-commit' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks').\n"; exit 2; } +git lfs post-commit "$@" diff --git a/.husky/post-merge b/.husky/post-merge new file mode 100755 index 0000000..a912e66 --- /dev/null +++ b/.husky/post-merge @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'post-merge' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks').\n"; exit 2; } +git lfs post-merge "$@" diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 0000000..0f0089b --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'pre-push' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks').\n"; exit 2; } +git lfs pre-push "$@" diff --git a/dist/WorkflowDesignerContainer.d.ts b/dist/WorkflowDesignerContainer.d.ts index 088276f..afe2c27 100644 --- a/dist/WorkflowDesignerContainer.d.ts +++ b/dist/WorkflowDesignerContainer.d.ts @@ -50,6 +50,10 @@ type WorkflowDesignerContainerBaseProps = { openDocumentationDialog?: (searchText: string) => void; /** Fires when unsaved-changes state flips; lets the shell mark Save / guard navigation. */ onDirtyChange?: (isDirty: boolean) => void; + /** See {@link SubworkflowProps.useUnitInspector}. */ + useUnitInspector?: boolean; + /** See {@link WorkflowDefaultLayoutProps.useHostTheme}. */ + useHostTheme?: boolean; }; export type WorkflowDesignerContainerProps = WorkflowDesignerContainerBaseProps; export default function WorkflowDesignerContainer(containerProps: WorkflowDesignerContainerProps): React.JSX.Element; diff --git a/dist/WorkflowDesignerContainer.d.ts.map b/dist/WorkflowDesignerContainer.d.ts.map index 9ba4b36..064629c 100644 --- a/dist/WorkflowDesignerContainer.d.ts.map +++ b/dist/WorkflowDesignerContainer.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"WorkflowDesignerContainer.d.ts","sourceRoot":"","sources":["../src/WorkflowDesignerContainer.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"WorkflowDesignerContainer.d.ts","sourceRoot":"","sources":["../src/WorkflowDesignerContainer.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/WorkflowDesignerContainer.js b/dist/WorkflowDesignerContainer.js index f78e393..dc643a0 100644 --- a/dist/WorkflowDesignerContainer.js +++ b/dist/WorkflowDesignerContainer.js @@ -10,7 +10,7 @@ import { WorkflowComponentsContext } from "./WorkflowComponentsContext"; /** Stable empty-array sentinel so the metaProperties useLayoutEffect dep never spuriously fires. */ const EMPTY_META_PROPERTIES = []; export default function WorkflowDesignerContainer(containerProps) { - const { initialWorkflow, defaultMaterial, metaProperties = EMPTY_META_PROPERTIES, editable, showHistory, workflowHistory, isStandalone, adjustable, showHeader, showMetadata, extraActions = [], accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, dialogs, templates, isLoading, saveWorkflow, isDescriptionEditable, EntityHeaderComponent, EntityNameComponent, MetadataComponent, HistoryComponent, SubworkflowFormTitleComponent, PseudoFormComponent, DataGridComponent, BrillouinZoneImageComponent, getDefaultComputeConfig, generateEntityId, onDirtyChange, } = containerProps; + const { initialWorkflow, defaultMaterial, metaProperties = EMPTY_META_PROPERTIES, editable, showHistory, workflowHistory, isStandalone, adjustable, showHeader, showMetadata, extraActions = [], accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, dialogs, templates, isLoading, saveWorkflow, isDescriptionEditable, EntityHeaderComponent, EntityNameComponent, MetadataComponent, HistoryComponent, SubworkflowFormTitleComponent, PseudoFormComponent, DataGridComponent, BrillouinZoneImageComponent, getDefaultComputeConfig, generateEntityId, onDirtyChange, useUnitInspector, useHostTheme, } = containerProps; const workflowComponents = useMemo(() => ({ EntityHeaderComponent, EntityNameComponent, @@ -224,5 +224,5 @@ export default function WorkflowDesignerContainer(containerProps) { py: 4, }, children: _jsx(CircularProgress, {}) })); } - return (_jsxs(WorkflowComponentsContext.Provider, { value: workflowComponents, children: [_jsx(UndoSnackbar, { state: removeUndoState, onClose: () => setRemoveUndoState(null) }), _jsx(WoveWorkflowDesigner, { workflow: workflow, isDirty: isDirty, jobHasParent: Boolean((state.job || {}).parentJob), isSetPublicVisible: state.isSetPublicVisible || false, isLoading: isLoading, materials: materials, showHeader: showHeader, showMetadata: showMetadata, editable: editable, showHistory: showHistory, workflowHistory: workflowHistory, isStandalone: isStandalone, adjustable: adjustable, metaProperties: metaProperties, extraActions: extraActions, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, profile: profile, publicAccount: publicAccount, clusters: clusters, dialogs: dialogs, templates: templates, onUpdate: onUpdate, onSave: onSave, onNameUpdate: onNameUpdate, onUpdateTags: onUpdateTags, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUnitRemove: onUnitRemove, onUnitUpdate: onUnitUpdate, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, onRender: renderWorkflow, workflowRenderGeneration: renderGeneration, isDescriptionEditable: isDescriptionEditable })] })); + return (_jsxs(WorkflowComponentsContext.Provider, { value: workflowComponents, children: [_jsx(UndoSnackbar, { state: removeUndoState, onClose: () => setRemoveUndoState(null) }), _jsx(WoveWorkflowDesigner, { useUnitInspector: useUnitInspector, useHostTheme: useHostTheme, workflow: workflow, isDirty: isDirty, jobHasParent: Boolean((state.job || {}).parentJob), isSetPublicVisible: state.isSetPublicVisible || false, isLoading: isLoading, materials: materials, showHeader: showHeader, showMetadata: showMetadata, editable: editable, showHistory: showHistory, workflowHistory: workflowHistory, isStandalone: isStandalone, adjustable: adjustable, metaProperties: metaProperties, extraActions: extraActions, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, profile: profile, publicAccount: publicAccount, clusters: clusters, dialogs: dialogs, templates: templates, onUpdate: onUpdate, onSave: onSave, onNameUpdate: onNameUpdate, onUpdateTags: onUpdateTags, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUnitRemove: onUnitRemove, onUnitUpdate: onUnitUpdate, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, onRender: renderWorkflow, workflowRenderGeneration: renderGeneration, isDescriptionEditable: isDescriptionEditable })] })); } diff --git a/dist/components/subworkflows/ImportantSettings.d.ts b/dist/components/subworkflows/ImportantSettings.d.ts index c5a76a3..8042d70 100644 --- a/dist/components/subworkflows/ImportantSettings.d.ts +++ b/dist/components/subworkflows/ImportantSettings.d.ts @@ -1,4 +1,4 @@ -import { type Subworkflow } from "@mat3ra/wode"; +import { type ExecutionUnit, type Subworkflow } from "@mat3ra/wode"; import React from "react"; interface ImportantSettingsProps { subworkflow: Subworkflow; @@ -7,6 +7,12 @@ interface ImportantSettingsProps { id?: string; onContextChanged: () => void; } +interface ImportantSettingsForUnitProps { + unit: ExecutionUnit; + unitIndex: number; + onContextChanged: () => void; +} +export declare function ImportantSettingsForUnit({ unit, unitIndex, onContextChanged, }: ImportantSettingsForUnitProps): React.JSX.Element; export declare function ImportantSettings({ subworkflow, role, className, id, onContextChanged, }: ImportantSettingsProps): React.JSX.Element; export {}; //# sourceMappingURL=ImportantSettings.d.ts.map \ No newline at end of file diff --git a/dist/components/subworkflows/ImportantSettings.d.ts.map b/dist/components/subworkflows/ImportantSettings.d.ts.map index d5d18c6..30d6124 100644 --- a/dist/components/subworkflows/ImportantSettings.d.ts.map +++ b/dist/components/subworkflows/ImportantSettings.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"ImportantSettings.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/ImportantSettings.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA+C,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAK7F,OAAO,KAAK,MAAM,OAAO,CAAC;AAe1B,UAAU,sBAAsB;IAC5B,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAChC;AAwMD,wBAAgB,iBAAiB,CAAC,EAC9B,WAAW,EACX,IAAI,EACJ,SAAS,EACT,EAAE,EACF,gBAAgB,GACnB,EAAE,sBAAsB,qBAmBxB"} \ No newline at end of file +{"version":3,"file":"ImportantSettings.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/ImportantSettings.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA2B,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAK7F,OAAO,KAAK,MAAM,OAAO,CAAC;AAe1B,UAAU,sBAAsB;IAC5B,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAChC;AAqBD,UAAU,6BAA6B;IACnC,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAChC;AAED,wBAAgB,wBAAwB,CAAC,EACrC,IAAI,EACJ,SAAS,EACT,gBAAgB,GACnB,EAAE,6BAA6B,qBAoE/B;AAqGD,wBAAgB,iBAAiB,CAAC,EAC9B,WAAW,EACX,IAAI,EACJ,SAAS,EACT,EAAE,EACF,gBAAgB,GACnB,EAAE,sBAAsB,qBAmBxB"} \ No newline at end of file diff --git a/dist/components/subworkflows/ImportantSettings.js b/dist/components/subworkflows/ImportantSettings.js index 9639f5b..b92372e 100644 --- a/dist/components/subworkflows/ImportantSettings.js +++ b/dist/components/subworkflows/ImportantSettings.js @@ -33,7 +33,7 @@ function getProviderTitle(provider) { return provider.name; } } -function ImportantSettingsForUnit({ unit, unitIndex, onContextChanged, }) { +export function ImportantSettingsForUnit({ unit, unitIndex, onContextChanged, }) { const [formRevision, setFormRevision] = React.useState(0); const { SubworkflowFormTitleComponent, BrillouinZoneImageComponent } = useWorkflowComponents(); return (_jsxs(Box, { my: 2, className: "important-settings-for-unit ImportantSettingsForUnit", id: unit.flowchartId, "data-tid": unit.name, children: [_jsx(SubworkflowFormTitleComponent, { title: `Unit ${unitIndex}: ${unit.name}` }), _jsx(Box, { ml: 3, children: getUnitImportantSettingsProviders(unit).map((provider, index) => { diff --git a/dist/components/subworkflows/Subworkflow.d.ts b/dist/components/subworkflows/Subworkflow.d.ts index f4cd71a..88a0ef8 100644 --- a/dist/components/subworkflows/Subworkflow.d.ts +++ b/dist/components/subworkflows/Subworkflow.d.ts @@ -34,6 +34,15 @@ export type SubworkflowProps = { * will actually run with. */ hideComputeSubTab?: boolean; + /** + * Clicking a unit in the flowchart opens its settings in a side drawer, + * instead of the reader leaving for the Settings tab and finding that unit + * among all the others. + * + * Opt-in per host: the tabs stay exactly as they are, so a host with tests or + * documentation against them is unaffected until it flips this. + */ + useUnitInspector?: boolean; }; export declare const TAB_NAVIGATION_CONFIG: { readonly overview: { @@ -57,5 +66,5 @@ export declare const TAB_NAVIGATION_CONFIG: { readonly href: "sw-compute"; }; }; -export declare function Subworkflow({ subworkflow, onUpdate, isStandalone, editable, adjustable, metaProperties, onOutputUpdateRequest, isMethodDataLoading, accountUsers, accountUsersIsLoading, currentUser, clusters, materials, materialsIndex, onMaterialSwitch, profile, publicAccount, createMetaProperty, pseudoUploadReduxDialog, unitTypeReduxDialog, className, jobProperties, activeTabIndex, onActiveTabIndexChange, hideComputeSubTab, }: SubworkflowProps): React.JSX.Element; +export declare function Subworkflow({ subworkflow, onUpdate, isStandalone, editable, adjustable, metaProperties, onOutputUpdateRequest, isMethodDataLoading, accountUsers, accountUsersIsLoading, currentUser, clusters, materials, materialsIndex, onMaterialSwitch, profile, publicAccount, createMetaProperty, pseudoUploadReduxDialog, unitTypeReduxDialog, className, jobProperties, activeTabIndex, onActiveTabIndexChange, useUnitInspector, hideComputeSubTab, }: SubworkflowProps): React.JSX.Element; //# sourceMappingURL=Subworkflow.d.ts.map \ No newline at end of file diff --git a/dist/components/subworkflows/Subworkflow.d.ts.map b/dist/components/subworkflows/Subworkflow.d.ts.map index 48720ae..9df9d9e 100644 --- a/dist/components/subworkflows/Subworkflow.d.ts.map +++ b/dist/components/subworkflows/Subworkflow.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"Subworkflow.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/Subworkflow.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAIvF,OAAO,EAEH,KAAK,eAAe,EACpB,WAAW,IAAI,eAAe,EAEjC,MAAM,cAAc,CAAC;AAOtB,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D,OAAO,KAAK,EACR,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,wCAAwC,EACxC,2BAA2B,EAC3B,4BAA4B,EAC5B,kCAAkC,EAClC,uBAAuB,EACvB,wBAAwB,EAExB,oBAAoB,EACvB,MAAM,qBAAqB,CAAC;AAW7B,MAAM,MAAM,gBAAgB,GAAG;IAC3B,WAAW,EAAE,eAAe,CAAC;IAC7B,QAAQ,EAAE,CAAC,WAAW,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,4BAA4B,EAAE,CAAC;IAChD,qBAAqB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACrD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,WAAW,CAAC,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACrC,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAChD,OAAO,EAAE,uBAAuB,CAAC;IACjC,aAAa,EAAE,uBAAuB,CAAC;IACvC,kBAAkB,EAAE,CAChB,QAAQ,EAAE,wCAAwC,KACjD,OAAO,CAAC,kCAAkC,GAAG,SAAS,CAAC,CAAC;IAC7D,uBAAuB,EAAE,2BAA2B,CAAC;IACrD,mBAAmB,EAAE,2BAA2B,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC3C,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;CAqBxB,CAAC;AAMX,wBAAgB,WAAW,CAAC,EACxB,WAAW,EACX,QAAQ,EACR,YAAoB,EACpB,QAAe,EACf,UAAkB,EAClB,cAAmB,EACnB,qBAAqB,EACrB,mBAA2B,EAC3B,YAAY,EACZ,qBAAqB,EACrB,WAAW,EACX,QAAa,EACb,SAAc,EACd,cAAc,EACd,gBAAgB,EAChB,OAAO,EACP,aAAa,EACb,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,SAAS,EACT,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,iBAAyB,GAC5B,EAAE,gBAAgB,qBAyVlB"} \ No newline at end of file +{"version":3,"file":"Subworkflow.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/Subworkflow.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAIvF,OAAO,EAEH,KAAK,eAAe,EACpB,WAAW,IAAI,eAAe,EAEjC,MAAM,cAAc,CAAC;AAOtB,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D,OAAO,KAAK,EACR,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,wCAAwC,EACxC,2BAA2B,EAC3B,4BAA4B,EAC5B,kCAAkC,EAClC,uBAAuB,EACvB,wBAAwB,EAExB,oBAAoB,EACvB,MAAM,qBAAqB,CAAC;AAY7B,MAAM,MAAM,gBAAgB,GAAG;IAC3B,WAAW,EAAE,eAAe,CAAC;IAC7B,QAAQ,EAAE,CAAC,WAAW,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,4BAA4B,EAAE,CAAC;IAChD,qBAAqB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACrD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,WAAW,CAAC,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACrC,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAChD,OAAO,EAAE,uBAAuB,CAAC;IACjC,aAAa,EAAE,uBAAuB,CAAC;IACvC,kBAAkB,EAAE,CAChB,QAAQ,EAAE,wCAAwC,KACjD,OAAO,CAAC,kCAAkC,GAAG,SAAS,CAAC,CAAC;IAC7D,uBAAuB,EAAE,2BAA2B,CAAC;IACrD,mBAAmB,EAAE,2BAA2B,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC3C,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;;OAOG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;CAqBxB,CAAC;AAMX,wBAAgB,WAAW,CAAC,EACxB,WAAW,EACX,QAAQ,EACR,YAAoB,EACpB,QAAe,EACf,UAAkB,EAClB,cAAmB,EACnB,qBAAqB,EACrB,mBAA2B,EAC3B,YAAY,EACZ,qBAAqB,EACrB,WAAW,EACX,QAAa,EACb,SAAc,EACd,cAAc,EACd,gBAAgB,EAChB,OAAO,EACP,aAAa,EACb,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,SAAS,EACT,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,gBAAwB,EACxB,iBAAyB,GAC5B,EAAE,gBAAgB,qBAyWlB"} \ No newline at end of file diff --git a/dist/components/subworkflows/Subworkflow.js b/dist/components/subworkflows/Subworkflow.js index 7735721..ecd6eb3 100644 --- a/dist/components/subworkflows/Subworkflow.js +++ b/dist/components/subworkflows/Subworkflow.js @@ -17,6 +17,7 @@ import { useCallback, useMemo, useState } from "react"; import { useWorkflowComponents } from "../../WorkflowComponentsContext"; import { UndoSnackbar } from "../common/UndoSnackbar"; import UnitModal from "../units/UnitModal"; +import UnitInspectorDrawer from "./UnitInspectorDrawer"; import { ImportantSettings } from "./ImportantSettings"; import { SubworkflowExecutionUnitDetailsRow } from "./SubworkflowExecutionUnitDetailsRow"; import { SubworkflowMethodPanel } from "./SubworkflowMethodPanel"; @@ -47,8 +48,8 @@ export const TAB_NAVIGATION_CONFIG = { const COMPUTE_TAB_NAME = TAB_NAVIGATION_CONFIG.compute.itemName; /** Compute is the last tab, which is what lets it be dropped without renumbering the rest. */ const COMPUTE_TAB_INDEX = Object.keys(TAB_NAVIGATION_CONFIG).indexOf("compute"); -export function Subworkflow({ subworkflow, onUpdate, isStandalone = false, editable = true, adjustable = false, metaProperties = [], onOutputUpdateRequest, isMethodDataLoading = false, accountUsers, accountUsersIsLoading, currentUser, clusters = [], materials = [], materialsIndex, onMaterialSwitch, profile, publicAccount, createMetaProperty, pseudoUploadReduxDialog, unitTypeReduxDialog, className, jobProperties, activeTabIndex, onActiveTabIndexChange, hideComputeSubTab = false, }) { - var _a, _b, _c; +export function Subworkflow({ subworkflow, onUpdate, isStandalone = false, editable = true, adjustable = false, metaProperties = [], onOutputUpdateRequest, isMethodDataLoading = false, accountUsers, accountUsersIsLoading, currentUser, clusters = [], materials = [], materialsIndex, onMaterialSwitch, profile, publicAccount, createMetaProperty, pseudoUploadReduxDialog, unitTypeReduxDialog, className, jobProperties, activeTabIndex, onActiveTabIndexChange, useUnitInspector = false, hideComputeSubTab = false, }) { + var _a, _b, _c, _d; const { getDefaultComputeConfig } = useWorkflowComponents(); const [unitIndex, setUnitIndex] = useState(0); const [removeUndoState, setRemoveUndoState] = useState(null); @@ -160,21 +161,27 @@ export function Subworkflow({ subworkflow, onUpdate, isStandalone = false, edita unit.togglePostProcessor(safeMakeObject(postProcessor), enabled); }); }, [applyToSubworkflow]); + const [isInspectorOpen, setIsInspectorOpen] = useState(false); const onUnitSelect = useCallback((unit) => { const index = subworkflow.units.findIndex((u) => u.flowchartId === unit.flowchartId); if (index > -1) { setUnitIndex((prev) => (index !== prev ? index : prev)); + if (useUnitInspector) + setIsInspectorOpen(true); } - }, [subworkflow.units]); + }, [subworkflow.units, useUnitInspector]); + // The selected index survives units being added or removed; the drawer must + // not go on showing settings for a unit that is no longer there. + const inspectedUnit = isInspectorOpen && useUnitInspector ? (_a = subworkflow.unitsInstances[unitIndex]) !== null && _a !== void 0 ? _a : null : null; const setTabIndex = useCallback((index) => { onActiveTabIndexChange(index); }, [onActiveTabIndexChange]); const categorizedModelList = new ModelStandata().getAll(); const filteredModels = new ApplicationModelStandata().findByApplicationParameters({ modelList: categorizedModelList, - name: (_a = subworkflow.application) === null || _a === void 0 ? void 0 : _a.name, - version: (_b = subworkflow.application) === null || _b === void 0 ? void 0 : _b.version, - build: (_c = subworkflow.application) === null || _c === void 0 ? void 0 : _c.build, + name: (_b = subworkflow.application) === null || _b === void 0 ? void 0 : _b.name, + version: (_c = subworkflow.application) === null || _c === void 0 ? void 0 : _c.version, + build: (_d = subworkflow.application) === null || _d === void 0 ? void 0 : _d.build, }); const tabs = useMemo(() => Object.values(TAB_NAVIGATION_CONFIG) .map((tab, index) => ({ @@ -191,5 +198,5 @@ export function Subworkflow({ subworkflow, onUpdate, isStandalone = false, edita // A subworkflow whose Compute tab was open when the host hid it would // otherwise be left showing an empty panel. const visibleTabIndex = hideComputeSubTab && activeTabIndex === COMPUTE_TAB_INDEX ? 0 : activeTabIndex; - return (_jsxs(Stack, { "data-tid": "subworkflow", height: "100%", className: className, children: [_jsx(UndoSnackbar, { state: removeUndoState, onClose: () => setRemoveUndoState(null) }), _jsx(TabsMenu, { tabs: tabs, activeTabIndex: visibleTabIndex, sx: { fontSize: 12, height: "100%" } }), _jsxs(TabContext, { value: `${visibleTabIndex}`, children: [_jsx(TabPanel, { value: "0", id: TAB_NAVIGATION_CONFIG.overview.href, sx: { height: "100%" }, children: _jsxs(Stack, { spacing: 3, height: "100%", children: [_jsx(UnitsFlowchartContainer, { units: subworkflow.unitsInstances, onUnitAdd: onUnitAdd, isStandalone: isStandalone, editable: editable, adjustable: adjustable, onUnitClone: onUnitClone, onUnitRemove: onUnitRemove, onUnitUpdate: onUnitUpdate, materials: materials, materialsIndex: materialsIndex, onMaterialSwitch: onMaterialSwitch, subworkflow: subworkflow, onOutputUpdateRequest: onOutputUpdateRequest, publicAccount: publicAccount, unitIndex: unitIndex, onUnitSelect: onUnitSelect, unitTypeReduxDialog: unitTypeReduxDialog, jobProperties: jobProperties, UnitModalComponent: UnitModal }), _jsx(AccordionComponent, { header: "Details", id: "subworkflow-accordion", sx: { pt: 0 }, children: _jsxs(Stack, { spacing: 2, children: [_jsx(Properties, { subworkflow: subworkflow, onUpdate: onUpdate, editable: editable || adjustable }), _jsx(ApplicationAve, { application: subworkflow.application, onApplicationUpdate: onApplicationUpdate, editable: editable }), subworkflow.modelInstance.isUnknown ? null : (_jsx(Model, { id: "model", model: subworkflow.modelInstance, models: filteredModels, application: subworkflow.application, onUpdate: onModelUpdate, editable: editable })), _jsx(SubworkflowMethodPanel, { subworkflow: subworkflow, editable: editable, adjustable: adjustable, isMethodDataLoading: isMethodDataLoading, isStandalone: isStandalone, materials: materials, profile: profile, onUpdate: onChildSubworkflowInstanceUpdate, pseudoUploadReduxDialog: pseudoUploadReduxDialog, metaProperties: metaProperties, createMetaProperty: createMetaProperty })] }) })] }) }), _jsx(TabPanel, { value: "1", id: TAB_NAVIGATION_CONFIG.importantSettings.href, "data-tab-name": TAB_NAVIGATION_CONFIG.importantSettings.itemName, children: _jsx(ImportantSettings, { id: TAB_NAVIGATION_CONFIG.importantSettings.href, subworkflow: subworkflow, onContextChanged: onImportantSettingsContextChanged }) }), _jsx(TabPanel, { value: "2", children: _jsx(Grid, { container: true, spacing: 2, children: subworkflow.unitsInstances.map((unit, index) => (_jsx(SubworkflowExecutionUnitDetailsRow, { unit: unit, index: index, editable: editable, onUnitResultsChanged: onUnitResultsChanged, onUnitIsDraftChanged: onUnitIsDraftChanged, onUnitMonitorChanged: onUnitMonitorChanged, onUnitPostProcessorChanged: onUnitPostProcessorChanged }, unit.flowchartId))) }) }), hideComputeSubTab ? null : (_jsx(TabPanel, { value: `${COMPUTE_TAB_INDEX}`, children: _jsx(WorkflowCompute, { compute: subworkflow.compute, onUpdate: onComputeUpdate, onToggle: onComputeToggle, showAdvancedOptions: new Application(subworkflow.application).hasAdvancedComputeOptions, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: currentUser !== null && currentUser !== void 0 ? currentUser : profile.user.entity, clusters: clusters }) }))] })] })); + return (_jsxs(Stack, { "data-tid": "subworkflow", height: "100%", className: className, children: [_jsx(UndoSnackbar, { state: removeUndoState, onClose: () => setRemoveUndoState(null) }), useUnitInspector ? (_jsx(UnitInspectorDrawer, { unit: inspectedUnit, unitIndex: unitIndex, onClose: () => setIsInspectorOpen(false), onContextChanged: onImportantSettingsContextChanged })) : null, _jsx(TabsMenu, { tabs: tabs, activeTabIndex: visibleTabIndex, sx: { fontSize: 12, height: "100%" } }), _jsxs(TabContext, { value: `${visibleTabIndex}`, children: [_jsx(TabPanel, { value: "0", id: TAB_NAVIGATION_CONFIG.overview.href, sx: { height: "100%" }, children: _jsxs(Stack, { spacing: 3, height: "100%", children: [_jsx(UnitsFlowchartContainer, { units: subworkflow.unitsInstances, onUnitAdd: onUnitAdd, isStandalone: isStandalone, editable: editable, adjustable: adjustable, onUnitClone: onUnitClone, onUnitRemove: onUnitRemove, onUnitUpdate: onUnitUpdate, materials: materials, materialsIndex: materialsIndex, onMaterialSwitch: onMaterialSwitch, subworkflow: subworkflow, onOutputUpdateRequest: onOutputUpdateRequest, publicAccount: publicAccount, unitIndex: unitIndex, onUnitSelect: onUnitSelect, unitTypeReduxDialog: unitTypeReduxDialog, jobProperties: jobProperties, UnitModalComponent: UnitModal }), _jsx(AccordionComponent, { header: "Details", id: "subworkflow-accordion", sx: { pt: 0 }, children: _jsxs(Stack, { spacing: 2, children: [_jsx(Properties, { subworkflow: subworkflow, onUpdate: onUpdate, editable: editable || adjustable }), _jsx(ApplicationAve, { application: subworkflow.application, onApplicationUpdate: onApplicationUpdate, editable: editable }), subworkflow.modelInstance.isUnknown ? null : (_jsx(Model, { id: "model", model: subworkflow.modelInstance, models: filteredModels, application: subworkflow.application, onUpdate: onModelUpdate, editable: editable })), _jsx(SubworkflowMethodPanel, { subworkflow: subworkflow, editable: editable, adjustable: adjustable, isMethodDataLoading: isMethodDataLoading, isStandalone: isStandalone, materials: materials, profile: profile, onUpdate: onChildSubworkflowInstanceUpdate, pseudoUploadReduxDialog: pseudoUploadReduxDialog, metaProperties: metaProperties, createMetaProperty: createMetaProperty })] }) })] }) }), _jsx(TabPanel, { value: "1", id: TAB_NAVIGATION_CONFIG.importantSettings.href, "data-tab-name": TAB_NAVIGATION_CONFIG.importantSettings.itemName, children: _jsx(ImportantSettings, { id: TAB_NAVIGATION_CONFIG.importantSettings.href, subworkflow: subworkflow, onContextChanged: onImportantSettingsContextChanged }) }), _jsx(TabPanel, { value: "2", children: _jsx(Grid, { container: true, spacing: 2, children: subworkflow.unitsInstances.map((unit, index) => (_jsx(SubworkflowExecutionUnitDetailsRow, { unit: unit, index: index, editable: editable, onUnitResultsChanged: onUnitResultsChanged, onUnitIsDraftChanged: onUnitIsDraftChanged, onUnitMonitorChanged: onUnitMonitorChanged, onUnitPostProcessorChanged: onUnitPostProcessorChanged }, unit.flowchartId))) }) }), hideComputeSubTab ? null : (_jsx(TabPanel, { value: `${COMPUTE_TAB_INDEX}`, children: _jsx(WorkflowCompute, { compute: subworkflow.compute, onUpdate: onComputeUpdate, onToggle: onComputeToggle, showAdvancedOptions: new Application(subworkflow.application).hasAdvancedComputeOptions, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: currentUser !== null && currentUser !== void 0 ? currentUser : profile.user.entity, clusters: clusters }) }))] })] })); } diff --git a/dist/components/subworkflows/UnitInspectorDrawer.d.ts b/dist/components/subworkflows/UnitInspectorDrawer.d.ts new file mode 100644 index 0000000..55704cf --- /dev/null +++ b/dist/components/subworkflows/UnitInspectorDrawer.d.ts @@ -0,0 +1,26 @@ +import { type AnySubworkflowUnit } from "@mat3ra/wode"; +import React from "react"; +export interface UnitInspectorDrawerProps { + /** The unit to inspect. `null` closes the drawer. */ + unit: AnySubworkflowUnit | null; + unitIndex: number; + onClose: () => void; + onContextChanged: () => void; + id?: string; +} +/** + * One unit's settings, beside the flowchart that selects it. + * + * Adjusting a unit used to mean leaving the flowchart for the Settings tab, + * finding that unit among all the others, changing it, and coming back to see + * what it did — a bounce between three tabs for one edit, with the diagram that + * gives the change its meaning off screen the whole time. Here the unit stays + * selected in the flowchart while its settings are open next to it. + * + * A plain MUI `Drawer` rather than cove's `ResizableDrawer`: that one is anchored + * to the bottom and resizes on height only, and generalising it to two axes is a + * change to a shared component with its own consumers. The width handle here is + * a few lines and does not put them at risk. + */ +export default function UnitInspectorDrawer({ unit, unitIndex, onClose, onContextChanged, id, }: UnitInspectorDrawerProps): React.JSX.Element; +//# sourceMappingURL=UnitInspectorDrawer.d.ts.map \ No newline at end of file diff --git a/dist/components/subworkflows/UnitInspectorDrawer.d.ts.map b/dist/components/subworkflows/UnitInspectorDrawer.d.ts.map new file mode 100644 index 0000000..3c669b2 --- /dev/null +++ b/dist/components/subworkflows/UnitInspectorDrawer.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"UnitInspectorDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/subworkflows/UnitInspectorDrawer.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,kBAAkB,EAAsB,MAAM,cAAc,CAAC;AAM3E,OAAO,KAAK,MAAM,OAAO,CAAC;AAS1B,MAAM,WAAW,wBAAwB;IACrC,qDAAqD;IACrD,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,EAAE,CAAC,EAAE,MAAM,CAAC;CACf;AAQD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,EACxC,IAAI,EACJ,SAAS,EACT,OAAO,EACP,gBAAgB,EAChB,EAA4B,GAC/B,EAAE,wBAAwB,qBA2F1B"} \ No newline at end of file diff --git a/dist/components/subworkflows/UnitInspectorDrawer.js b/dist/components/subworkflows/UnitInspectorDrawer.js new file mode 100644 index 0000000..952e051 --- /dev/null +++ b/dist/components/subworkflows/UnitInspectorDrawer.js @@ -0,0 +1,72 @@ +import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; +import IconByName from "@mat3ra/cove/dist/mui/components/icon/IconByName"; +import Box from "@mui/material/Box"; +import Drawer from "@mui/material/Drawer"; +import IconButton from "@mui/material/IconButton"; +import Stack from "@mui/material/Stack"; +import Typography from "@mui/material/Typography"; +import React from "react"; +import { ImportantSettingsForUnit } from "./ImportantSettings"; +/** Width bounds for the drag handle. Narrower than this and the forms stop fitting. */ +const MIN_WIDTH = 320; +const MAX_WIDTH = 900; +const DEFAULT_WIDTH = 460; +function isExecutionUnit(unit) { + // Schema `type`, not `instanceof`: units may come from a second compiled copy + // of `@mat3ra/wode` (see the note in ImportantSettings). + return unit.type === "execution"; +} +/** + * One unit's settings, beside the flowchart that selects it. + * + * Adjusting a unit used to mean leaving the flowchart for the Settings tab, + * finding that unit among all the others, changing it, and coming back to see + * what it did — a bounce between three tabs for one edit, with the diagram that + * gives the change its meaning off screen the whole time. Here the unit stays + * selected in the flowchart while its settings are open next to it. + * + * A plain MUI `Drawer` rather than cove's `ResizableDrawer`: that one is anchored + * to the bottom and resizes on height only, and generalising it to two axes is a + * change to a shared component with its own consumers. The width handle here is + * a few lines and does not put them at risk. + */ +export default function UnitInspectorDrawer({ unit, unitIndex, onClose, onContextChanged, id = "unit-inspector-drawer", }) { + var _a; + const [width, setWidth] = React.useState(DEFAULT_WIDTH); + const isResizing = React.useRef(false); + React.useEffect(() => { + const resize = (event) => { + if (!isResizing.current) + return; + // The drawer is anchored right, so its width is the distance from the + // pointer to the right edge of the window. + const next = window.innerWidth - event.clientX; + setWidth(Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, next))); + }; + const stop = () => { + isResizing.current = false; + }; + document.addEventListener("mousemove", resize); + document.addEventListener("mouseup", stop); + return () => { + document.removeEventListener("mousemove", resize); + document.removeEventListener("mouseup", stop); + }; + }, []); + return (_jsxs(Drawer, { id: id, anchor: "right", open: Boolean(unit), onClose: onClose, + // Persistent would leave the flowchart squeezed; temporary keeps the + // diagram at full width and lets Escape and a backdrop click close it. + variant: "temporary", PaperProps: { sx: { width, maxWidth: "100vw" } }, children: [_jsx(Box, { role: "separator", "aria-orientation": "vertical", "aria-label": "Resize the inspector", onMouseDown: () => { + isResizing.current = true; + }, sx: { + position: "absolute", + left: 0, + top: 0, + bottom: 0, + width: 6, + cursor: "col-resize", + "&:hover": { bgcolor: "action.hover" }, + } }), _jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, sx: { p: 2, pl: 3, borderBottom: "1px solid", borderColor: "divider" }, children: [_jsxs(Box, { sx: { flexGrow: 1, minWidth: 0 }, children: [_jsx(Typography, { variant: "subtitle2", noWrap: true, children: (_a = unit === null || unit === void 0 ? void 0 : unit.name) !== null && _a !== void 0 ? _a : "Unit" }), _jsxs(Typography, { variant: "caption", color: "text.secondary", children: ["Unit ", unitIndex + 1, (unit === null || unit === void 0 ? void 0 : unit.type) ? ` · ${unit.type}` : ""] })] }), _jsx(IconButton, { size: "small", onClick: onClose, "aria-label": "Close the inspector", children: _jsx(IconByName, { name: "actions.close", fontSize: "small" }) })] }), _jsx(Box, { sx: { overflowY: "auto", px: 3, pb: 3 }, children: unit && isExecutionUnit(unit) ? (_jsx(ImportantSettingsForUnit, { unit: unit, unitIndex: unitIndex, onContextChanged: onContextChanged })) : (_jsx(Typography, { variant: "body2", color: "text.secondary", sx: { pt: 2 }, children: unit + ? `A ${unit.type} unit has no important settings to adjust.` + : "Select a unit in the flowchart." })) })] })); +} diff --git a/dist/components/workflows/Workflow.d.ts b/dist/components/workflows/Workflow.d.ts index 0d60bc1..59d0704 100644 --- a/dist/components/workflows/Workflow.d.ts +++ b/dist/components/workflows/Workflow.d.ts @@ -82,7 +82,11 @@ export type WorkflowProps = { * which one the job will run with. */ hideComputeSubTab?: boolean; + /** See {@link SubworkflowProps.useUnitInspector}. */ + useUnitInspector?: boolean; + /** See {@link WorkflowDefaultLayoutProps.useHostTheme}. */ + useHostTheme?: boolean; }; -export declare function Workflow({ workflow, metaProperties, onUpdate, onOutputUpdateRequest, onUpdateTags, extraActions, onSave, isDirty, onNameUpdate, iconCls, onUnitAdd, onUnitAddSubworkflowFromConfig, onUnitRemove, onUnitUpdate, onSubworkflowUnitUpdate, materials, materialsIndex, jobHasParent, onMaterialSwitch, showHeaderPager, onHeaderPagerUpdate, dialogs, createMetaProperty, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, templates, isStandalone, isHeaderCompact, editable, adjustable, isLoading, showHeader, isMethodDataLoading, materialsSet, isMap, isSetPublicVisible, showMetadata, showHistory, workflowHistory, onIsMultiMaterialChanged, onRender, renderAtJobLevel, workflowRenderGeneration, isDescriptionEditable, jobProperties, hideComputeSubTab, showUnitStatus, }: WorkflowProps): React.JSX.Element; +export declare function Workflow({ workflow, metaProperties, onUpdate, onOutputUpdateRequest, onUpdateTags, extraActions, onSave, isDirty, onNameUpdate, iconCls, onUnitAdd, onUnitAddSubworkflowFromConfig, onUnitRemove, onUnitUpdate, onSubworkflowUnitUpdate, materials, materialsIndex, jobHasParent, onMaterialSwitch, showHeaderPager, onHeaderPagerUpdate, dialogs, createMetaProperty, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, templates, isStandalone, isHeaderCompact, editable, adjustable, isLoading, showHeader, isMethodDataLoading, materialsSet, isMap, isSetPublicVisible, showMetadata, showHistory, workflowHistory, onIsMultiMaterialChanged, onRender, renderAtJobLevel, workflowRenderGeneration, isDescriptionEditable, jobProperties, hideComputeSubTab, useUnitInspector, useHostTheme, showUnitStatus, }: WorkflowProps): React.JSX.Element; export {}; //# sourceMappingURL=Workflow.d.ts.map \ No newline at end of file diff --git a/dist/components/workflows/Workflow.d.ts.map b/dist/components/workflows/Workflow.d.ts.map index 607681d..895d911 100644 --- a/dist/components/workflows/Workflow.d.ts.map +++ b/dist/components/workflows/Workflow.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"Workflow.d.ts","sourceRoot":"","sources":["../../../src/components/workflows/Workflow.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"Workflow.d.ts","sourceRoot":"","sources":["../../../src/components/workflows/Workflow.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/components/workflows/Workflow.js b/dist/components/workflows/Workflow.js index b4165ee..1169afd 100644 --- a/dist/components/workflows/Workflow.js +++ b/dist/components/workflows/Workflow.js @@ -11,7 +11,7 @@ import { getWorkflowDesignerTabResetKey } from "./workflowDesignerTabState"; const noop = () => undefined; const EMPTY_META_PROPERTIES = []; const noopUnitAddSubworkflowFromConfig = (_config, _prependOrPasteIndex, _unitIndex) => undefined; -export function Workflow({ workflow, metaProperties = EMPTY_META_PROPERTIES, onUpdate = noop, onOutputUpdateRequest, onUpdateTags, extraActions = [], onSave, isDirty = false, onNameUpdate, iconCls, onUnitAdd = noop, onUnitAddSubworkflowFromConfig = noopUnitAddSubworkflowFromConfig, onUnitRemove = noop, onUnitUpdate = noop, onSubworkflowUnitUpdate = noop, materials = [], materialsIndex, jobHasParent = false, onMaterialSwitch, showHeaderPager = false, onHeaderPagerUpdate, dialogs, createMetaProperty = async (_property) => undefined, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters = [], templates, isStandalone = false, isHeaderCompact, editable = false, adjustable = false, isLoading = false, showHeader = true, isMethodDataLoading = false, materialsSet, isMap, isSetPublicVisible, showMetadata = true, showHistory = false, workflowHistory = [], onIsMultiMaterialChanged, onRender, renderAtJobLevel = false, workflowRenderGeneration, isDescriptionEditable, jobProperties, hideComputeSubTab = false, showUnitStatus = false, }) { +export function Workflow({ workflow, metaProperties = EMPTY_META_PROPERTIES, onUpdate = noop, onOutputUpdateRequest, onUpdateTags, extraActions = [], onSave, isDirty = false, onNameUpdate, iconCls, onUnitAdd = noop, onUnitAddSubworkflowFromConfig = noopUnitAddSubworkflowFromConfig, onUnitRemove = noop, onUnitUpdate = noop, onSubworkflowUnitUpdate = noop, materials = [], materialsIndex, jobHasParent = false, onMaterialSwitch, showHeaderPager = false, onHeaderPagerUpdate, dialogs, createMetaProperty = async (_property) => undefined, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters = [], templates, isStandalone = false, isHeaderCompact, editable = false, adjustable = false, isLoading = false, showHeader = true, isMethodDataLoading = false, materialsSet, isMap, isSetPublicVisible, showMetadata = true, showHistory = false, workflowHistory = [], onIsMultiMaterialChanged, onRender, renderAtJobLevel = false, workflowRenderGeneration, isDescriptionEditable, jobProperties, hideComputeSubTab = false, useUnitInspector = false, useHostTheme = false, showUnitStatus = false, }) { const [unitIndex, setUnitIndex] = useState(0); // Identifiers are noise for the person reading a workflow; opt-in per session. const [showDeveloperInfo, setShowDeveloperInfo] = useState(false); @@ -223,5 +223,5 @@ export function Workflow({ workflow, metaProperties = EMPTY_META_PROPERTIES, onU buttonContent: "Select Workflow Actions", }; }, [getActions]); - return (_jsx(WoveDisplayOptionsProvider, { showDeveloperInfo: showDeveloperInfo, showStatus: showUnitStatus, children: _jsx(Box, { "data-workflow-render-generation": workflowRenderGeneration, children: _jsx(WorkflowDefaultLayout, { entity: workflow, unitIndex: unitIndex, isMap: isMap, materials: materials, materialsIndex: materialsIndex, materialsSet: materialsSet, jobHasParent: jobHasParent, editable: Boolean(editable), adjustable: Boolean(adjustable), isLoading: isLoading, showHeader: showHeader, isHeaderCompact: isHeaderCompact, isStandalone: isStandalone, isMethodDataLoading: isMethodDataLoading, isSetPublicVisible: isSetPublicVisible, showMetadata: showMetadata, showHistory: showHistory, workflowHistory: workflowHistory, iconCls: iconCls, onNameUpdate: onNameUpdate, onUpdateTags: onUpdateTags, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUnitUpdate: onUnitUpdate, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, onMapWorkflowUpdate: onMapWorkflowUpdate, onUnitSelect: onUnitSelect, onUpdateUnitIndex: onUpdateUnitIndex, handleUnitRemove: handleUnitRemove, onUnitNameUpdate: onUnitNameUpdate, areWorkflowContentExpanded: areWorkflowContentExpanded, toggleExpandWorkflowContent: toggleExpandWorkflowContent, headerStatusCls: headerStatusCls, getPagerProps: getPagerProps, getSaveBtnProps: getSaveBtnProps, getDropdownProps: getDropdownProps, isDescriptionEditable: isDescriptionEditable, onDescriptionUpdate: onDescriptionUpdate, dialogs: dialogs, metaProperties: metaProperties, onMaterialSwitch: onMaterialSwitch, onOutputUpdateRequest: onOutputUpdateRequest, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, profile: profile, publicAccount: publicAccount, clusters: clusters, templates: templates, createMetaProperty: createMetaProperty, jobProperties: jobProperties, hideComputeSubTab: hideComputeSubTab, subworkflowActiveTabIndexById: subworkflowActiveTabIndexById, onSubworkflowActiveTabIndexChange: onSubworkflowActiveTabIndexChange }) }) })); + return (_jsx(WoveDisplayOptionsProvider, { showDeveloperInfo: showDeveloperInfo, showStatus: showUnitStatus, children: _jsx(Box, { "data-workflow-render-generation": workflowRenderGeneration, children: _jsx(WorkflowDefaultLayout, { entity: workflow, unitIndex: unitIndex, isMap: isMap, materials: materials, materialsIndex: materialsIndex, materialsSet: materialsSet, jobHasParent: jobHasParent, editable: Boolean(editable), adjustable: Boolean(adjustable), isLoading: isLoading, showHeader: showHeader, isHeaderCompact: isHeaderCompact, isStandalone: isStandalone, isMethodDataLoading: isMethodDataLoading, isSetPublicVisible: isSetPublicVisible, showMetadata: showMetadata, showHistory: showHistory, workflowHistory: workflowHistory, iconCls: iconCls, onNameUpdate: onNameUpdate, onUpdateTags: onUpdateTags, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUnitUpdate: onUnitUpdate, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, onMapWorkflowUpdate: onMapWorkflowUpdate, onUnitSelect: onUnitSelect, onUpdateUnitIndex: onUpdateUnitIndex, handleUnitRemove: handleUnitRemove, onUnitNameUpdate: onUnitNameUpdate, areWorkflowContentExpanded: areWorkflowContentExpanded, toggleExpandWorkflowContent: toggleExpandWorkflowContent, headerStatusCls: headerStatusCls, getPagerProps: getPagerProps, getSaveBtnProps: getSaveBtnProps, getDropdownProps: getDropdownProps, isDescriptionEditable: isDescriptionEditable, onDescriptionUpdate: onDescriptionUpdate, dialogs: dialogs, metaProperties: metaProperties, onMaterialSwitch: onMaterialSwitch, onOutputUpdateRequest: onOutputUpdateRequest, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, profile: profile, publicAccount: publicAccount, clusters: clusters, templates: templates, createMetaProperty: createMetaProperty, jobProperties: jobProperties, hideComputeSubTab: hideComputeSubTab, useUnitInspector: useUnitInspector, useHostTheme: useHostTheme, subworkflowActiveTabIndexById: subworkflowActiveTabIndexById, onSubworkflowActiveTabIndexChange: onSubworkflowActiveTabIndexChange }) }) })); } diff --git a/dist/components/workflows/WorkflowDefaultLayout.d.ts b/dist/components/workflows/WorkflowDefaultLayout.d.ts index 2771098..39c3eb1 100644 --- a/dist/components/workflows/WorkflowDefaultLayout.d.ts +++ b/dist/components/workflows/WorkflowDefaultLayout.d.ts @@ -87,6 +87,17 @@ export type WorkflowDefaultLayoutProps = { onSubworkflowActiveTabIndexChange: (subworkflowId: string, tabIndex: number) => void; /** See {@link SubworkflowProps.hideComputeSubTab}. */ hideComputeSubTab?: boolean; + /** See {@link SubworkflowProps.useUnitInspector}. */ + useUnitInspector?: boolean; + /** + * Renders under the host's theme instead of forcing cove's old light one. + * + * The designer has always pinned itself to `oldLightMaterialUITheme`, which + * is why a dark host frames a white canvas: the shell is dark, and this + * subtree is not. Opt-in, because hosts that expect the light designer today + * would otherwise be restyled without asking. + */ + useHostTheme?: boolean; }; export declare function WorkflowDefaultLayout(props: WorkflowDefaultLayoutProps): React.JSX.Element; //# sourceMappingURL=WorkflowDefaultLayout.d.ts.map \ No newline at end of file diff --git a/dist/components/workflows/WorkflowDefaultLayout.d.ts.map b/dist/components/workflows/WorkflowDefaultLayout.d.ts.map index cbc23f3..812eb38 100644 --- a/dist/components/workflows/WorkflowDefaultLayout.d.ts.map +++ b/dist/components/workflows/WorkflowDefaultLayout.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"WorkflowDefaultLayout.d.ts","sourceRoot":"","sources":["../../../src/components/workflows/WorkflowDefaultLayout.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"WorkflowDefaultLayout.d.ts","sourceRoot":"","sources":["../../../src/components/workflows/WorkflowDefaultLayout.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/components/workflows/WorkflowDefaultLayout.js b/dist/components/workflows/WorkflowDefaultLayout.js index 00463da..1faaf9b 100644 --- a/dist/components/workflows/WorkflowDefaultLayout.js +++ b/dist/components/workflows/WorkflowDefaultLayout.js @@ -17,7 +17,7 @@ import { WorkflowValidationAlert } from "./WorkflowValidationAlert"; const MapWorkflowDesigner = React.lazy(() => import("./Map").then((module) => ({ default: module.MapWorkflowDesigner }))); export function WorkflowDefaultLayout(props) { var _a, _b; - const { entity, unitIndex, isMap, materials, materialsIndex, materialsSet, jobHasParent = false, editable, adjustable, isLoading, showHeader, isHeaderCompact, isStandalone, isMethodDataLoading, isSetPublicVisible, showMetadata, showHistory, workflowHistory, iconCls, onNameUpdate, onUpdateTags, onUnitAdd, onUnitAddSubworkflowFromConfig, onUnitUpdate, onSubworkflowUnitUpdate, onMapWorkflowUpdate, onUnitSelect, onUpdateUnitIndex, handleUnitRemove, onUnitNameUpdate, areWorkflowContentExpanded, toggleExpandWorkflowContent, headerStatusCls, getPagerProps, getSaveBtnProps, getDropdownProps, isDescriptionEditable, onDescriptionUpdate, dialogs, metaProperties, onMaterialSwitch, onOutputUpdateRequest, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, templates, createMetaProperty, jobProperties, subworkflowActiveTabIndexById, onSubworkflowActiveTabIndexChange, hideComputeSubTab, } = props; + const { entity, unitIndex, isMap, materials, materialsIndex, materialsSet, jobHasParent = false, editable, adjustable, isLoading, showHeader, isHeaderCompact, isStandalone, isMethodDataLoading, isSetPublicVisible, showMetadata, showHistory, workflowHistory, iconCls, onNameUpdate, onUpdateTags, onUnitAdd, onUnitAddSubworkflowFromConfig, onUnitUpdate, onSubworkflowUnitUpdate, onMapWorkflowUpdate, onUnitSelect, onUpdateUnitIndex, handleUnitRemove, onUnitNameUpdate, areWorkflowContentExpanded, toggleExpandWorkflowContent, headerStatusCls, getPagerProps, getSaveBtnProps, getDropdownProps, isDescriptionEditable, onDescriptionUpdate, dialogs, metaProperties, onMaterialSwitch, onOutputUpdateRequest, accountUsers, accountUsersIsLoading, profile, publicAccount, clusters, templates, createMetaProperty, jobProperties, subworkflowActiveTabIndexById, onSubworkflowActiveTabIndexChange, hideComputeSubTab, useUnitInspector, useHostTheme = false, } = props; const { EntityHeaderComponent, MetadataComponent, HistoryComponent } = useWorkflowComponents(); const unit = entity.unitInstances[unitIndex]; if (!unit) { @@ -35,10 +35,11 @@ export function WorkflowDefaultLayout(props) { const leftColumnGridProps = isMap ? { md: 12, lg: true } : { md: 12, lg: 4 }; const rightColumnGridProps = isMap ? { md: 12, lg: true } : { md: 12, lg: 8 }; const { pseudoUploadReduxDialog, unitTypeReduxDialog } = dialogs; - return (_jsx(ThemeProvider, { theme: oldLightMaterialUITheme, children: _jsxs("div", { className: "workflow-with-name-and-metadata", children: [showHeader && (_jsx(EntityHeaderComponent, { isCompact: isHeaderCompact, icon: ENTITY_ICONS.workflow, name: String((_a = entity.name) !== null && _a !== void 0 ? _a : ""), subtitle: { - applications: entity.usedApplicationNames.join(", "), - }, description: get(entity, "description"), isLoading: isLoading, editable: Boolean(editable), onNameUpdate: onNameUpdate, iconCls: iconCls, id: "workflow-designer-header", pagerProps: getPagerProps(), saveBtnProps: getSaveBtnProps(), dropdownProps: getDropdownProps(), descriptionEditorTitle: "Workflow Description", item: entity, isDescriptionEditable: isDescriptionEditable, onDescriptionUpdate: onDescriptionUpdate })), _jsxs(Grid, { container: true, sx: { backgroundColor: "background.paper" }, children: [_jsx(Grid, { ...leftColumnGridProps, item: true, sx: { - borderRight: "1px solid #cecece", - backgroundColor: "background.default", - }, children: _jsx(Box, { className: "workflow-flowchart-container", sx: { height: "100%", p: 2 }, children: _jsx(WorkflowUnitsFlowchart, { editable: Boolean(editable), onUnitRemove: handleUnitRemove, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, workflow: entity, activeUnit: unit, onClick: onUnitSelect, isCardContentExpanded: areWorkflowContentExpanded, headerStatusCls: headerStatusCls }) }) }), _jsxs(Grid, { className: "workflow-subworkflow-container", item: true, sx: { display: "flex", flexDirection: "column" }, ...rightColumnGridProps, children: [_jsx(WorkflowValidationAlert, { workflow: entity }), unit.type === UnitType.subworkflow && (_jsxs(_Fragment, { children: [_jsx(SubworkflowHeader, { unit: unit, adjustable: Boolean(adjustable), editable: Boolean(editable), subworkflow: subworkflow, onUnitRemove: handleUnitRemove, headerStatusCls: headerStatusCls, onUnitNameUpdate: onUnitNameUpdate, unitIndex: unitIndex, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUpdateUnitIndex: onUpdateUnitIndex, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, areWorkflowContentExpanded: areWorkflowContentExpanded, toggleExpandWorkflowContent: toggleExpandWorkflowContent, workflow: entity, materials: materials, materialsIndex: materialsIndex, materialsSet: materialsSet, jobHasParent: jobHasParent }), subworkflow ? (_jsx(Subworkflow, { className: "card-body", subworkflow: subworkflow, activeTabIndex: (_b = subworkflowActiveTabIndexById[subworkflow.id]) !== null && _b !== void 0 ? _b : 0, hideComputeSubTab: hideComputeSubTab, onActiveTabIndexChange: (tabIndex) => onSubworkflowActiveTabIndexChange(subworkflow.id, tabIndex), onUpdate: onSubworkflowUnitUpdate, isStandalone: isStandalone, isMethodDataLoading: isMethodDataLoading, editable: Boolean(editable), adjustable: Boolean(adjustable), onMaterialSwitch: onMaterialSwitch, materials: materials, materialsIndex: materialsIndex, metaProperties: metaProperties, onOutputUpdateRequest: onOutputUpdateRequest, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: profile.user.entity, clusters: clusters, pseudoUploadReduxDialog: pseudoUploadReduxDialog, unitTypeReduxDialog: unitTypeReduxDialog, profile: profile, publicAccount: publicAccount, createMetaProperty: createMetaProperty, jobProperties: jobProperties }, subworkflow.id)) : null] })), unit.type === UnitType.map && (_jsx(React.Suspense, { fallback: null, children: _jsx(MapWorkflowDesigner, { className: "card-body", unit: unit, workflow: mapWorkflow, onUpdate: onUnitUpdate, onWorkflowUpdate: onMapWorkflowUpdate, editable: Boolean(editable), adjustable: Boolean(adjustable), onMaterialSwitch: onMaterialSwitch, materials: materials, materialsIndex: materialsIndex, iconCls: iconCls, onOutputUpdateRequest: onOutputUpdateRequest, parentWorkflow: entity, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: profile.user.entity, publicAccount: publicAccount, profile: profile, clusters: clusters, dialogs: dialogs, templates: templates, isDescriptionEditable: isDescriptionEditable, metaProperties: metaProperties }) })), unit.type === UnitType.error && (_jsx(Box, { className: "card-body", sx: { p: 2 }, children: _jsx(ErrorUnitContent, { unit: unit }) }))] })] }), _jsx(Divider, {}), showMetadata && (_jsx(MetadataComponent, { tags: get(entity, "tags", []), editable: Boolean(editable), isSetPublicVisible: isSetPublicVisible, onUpdateTags: onUpdateTags, publicAccount: publicAccount.entity })), _jsx(Divider, {}), showHistory && _jsx(HistoryComponent, { items: workflowHistory })] }) })); + const content = (_jsxs("div", { className: "workflow-with-name-and-metadata", children: [showHeader && (_jsx(EntityHeaderComponent, { isCompact: isHeaderCompact, icon: ENTITY_ICONS.workflow, name: String((_a = entity.name) !== null && _a !== void 0 ? _a : ""), subtitle: { + applications: entity.usedApplicationNames.join(", "), + }, description: get(entity, "description"), isLoading: isLoading, editable: Boolean(editable), onNameUpdate: onNameUpdate, iconCls: iconCls, id: "workflow-designer-header", pagerProps: getPagerProps(), saveBtnProps: getSaveBtnProps(), dropdownProps: getDropdownProps(), descriptionEditorTitle: "Workflow Description", item: entity, isDescriptionEditable: isDescriptionEditable, onDescriptionUpdate: onDescriptionUpdate })), _jsxs(Grid, { container: true, sx: { backgroundColor: "background.paper" }, children: [_jsx(Grid, { ...leftColumnGridProps, item: true, sx: { + borderRight: "1px solid #cecece", + backgroundColor: "background.default", + }, children: _jsx(Box, { className: "workflow-flowchart-container", sx: { height: "100%", p: 2 }, children: _jsx(WorkflowUnitsFlowchart, { editable: Boolean(editable), onUnitRemove: handleUnitRemove, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, workflow: entity, activeUnit: unit, onClick: onUnitSelect, isCardContentExpanded: areWorkflowContentExpanded, headerStatusCls: headerStatusCls }) }) }), _jsxs(Grid, { className: "workflow-subworkflow-container", item: true, sx: { display: "flex", flexDirection: "column" }, ...rightColumnGridProps, children: [_jsx(WorkflowValidationAlert, { workflow: entity }), unit.type === UnitType.subworkflow && (_jsxs(_Fragment, { children: [_jsx(SubworkflowHeader, { unit: unit, adjustable: Boolean(adjustable), editable: Boolean(editable), subworkflow: subworkflow, onUnitRemove: handleUnitRemove, headerStatusCls: headerStatusCls, onUnitNameUpdate: onUnitNameUpdate, unitIndex: unitIndex, onUnitAdd: onUnitAdd, onUnitAddSubworkflowFromConfig: onUnitAddSubworkflowFromConfig, onUpdateUnitIndex: onUpdateUnitIndex, onSubworkflowUnitUpdate: onSubworkflowUnitUpdate, areWorkflowContentExpanded: areWorkflowContentExpanded, toggleExpandWorkflowContent: toggleExpandWorkflowContent, workflow: entity, materials: materials, materialsIndex: materialsIndex, materialsSet: materialsSet, jobHasParent: jobHasParent }), subworkflow ? (_jsx(Subworkflow, { className: "card-body", subworkflow: subworkflow, activeTabIndex: (_b = subworkflowActiveTabIndexById[subworkflow.id]) !== null && _b !== void 0 ? _b : 0, hideComputeSubTab: hideComputeSubTab, useUnitInspector: useUnitInspector, onActiveTabIndexChange: (tabIndex) => onSubworkflowActiveTabIndexChange(subworkflow.id, tabIndex), onUpdate: onSubworkflowUnitUpdate, isStandalone: isStandalone, isMethodDataLoading: isMethodDataLoading, editable: Boolean(editable), adjustable: Boolean(adjustable), onMaterialSwitch: onMaterialSwitch, materials: materials, materialsIndex: materialsIndex, metaProperties: metaProperties, onOutputUpdateRequest: onOutputUpdateRequest, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: profile.user.entity, clusters: clusters, pseudoUploadReduxDialog: pseudoUploadReduxDialog, unitTypeReduxDialog: unitTypeReduxDialog, profile: profile, publicAccount: publicAccount, createMetaProperty: createMetaProperty, jobProperties: jobProperties }, subworkflow.id)) : null] })), unit.type === UnitType.map && (_jsx(React.Suspense, { fallback: null, children: _jsx(MapWorkflowDesigner, { className: "card-body", unit: unit, workflow: mapWorkflow, onUpdate: onUnitUpdate, onWorkflowUpdate: onMapWorkflowUpdate, editable: Boolean(editable), adjustable: Boolean(adjustable), onMaterialSwitch: onMaterialSwitch, materials: materials, materialsIndex: materialsIndex, iconCls: iconCls, onOutputUpdateRequest: onOutputUpdateRequest, parentWorkflow: entity, accountUsers: accountUsers, accountUsersIsLoading: accountUsersIsLoading, currentUser: profile.user.entity, publicAccount: publicAccount, profile: profile, clusters: clusters, dialogs: dialogs, templates: templates, isDescriptionEditable: isDescriptionEditable, metaProperties: metaProperties }) })), unit.type === UnitType.error && (_jsx(Box, { className: "card-body", sx: { p: 2 }, children: _jsx(ErrorUnitContent, { unit: unit }) }))] })] }), _jsx(Divider, {}), showMetadata && (_jsx(MetadataComponent, { tags: get(entity, "tags", []), editable: Boolean(editable), isSetPublicVisible: isSetPublicVisible, onUpdateTags: onUpdateTags, publicAccount: publicAccount.entity })), _jsx(Divider, {}), showHistory && _jsx(HistoryComponent, { items: workflowHistory })] })); + return useHostTheme ? (content) : (_jsx(ThemeProvider, { theme: oldLightMaterialUITheme, children: content })); } diff --git a/dist/standalone/index.js b/dist/standalone/index.js index c5bb726..4d27998 100644 --- a/dist/standalone/index.js +++ b/dist/standalone/index.js @@ -108,6 +108,8 @@ function App() { }); const selectedMaterial = allMaterials[materialIndex]; const [isDirty, setIsDirty] = useState(false); + // Phase 3.3 surface, opt-in: the demo is where it gets reviewed before a host flips it on. + const [useUnitInspector, setUseUnitInspector] = useState(true); // Re-key the designer when either selection changes so it re-mounts cleanly const designerKey = `${workflowIndex}-${materialIndex}`; const handleSave = useCallback(async () => { @@ -141,7 +143,7 @@ function App() { }, children: allMaterials.map((mat, i) => { var _a, _b; return (_jsx(MenuItem, { value: i, children: (_b = (_a = mat === null || mat === void 0 ? void 0 : mat.name) !== null && _a !== void 0 ? _a : mat === null || mat === void 0 ? void 0 : mat.formula) !== null && _b !== void 0 ? _b : `Material ${i + 1}` }, i)); - }) })] }), isDirty && (_jsx(Chip, { label: "\u25CF Unsaved changes", size: "small", variant: "outlined", color: "warning", "data-tid": "dirty-indicator" })), _jsx(Chip, { label: `${allWorkflowJsons.length} workflows · ${allMaterials.length} materials`, size: "small", variant: "outlined", color: "secondary", sx: { ml: "auto" } })] }) }), _jsx(Box, { sx: { height: "calc(100vh - 72px)", overflow: "auto" }, children: _jsx(WorkflowDesignerContainer, { initialWorkflow: wodeWorkflow, defaultMaterial: selectedMaterial, editable: true, showHistory: false, workflowHistory: { list: [], loading: false }, isStandalone: true, adjustable: true, showHeader: true, showMetadata: false, accountUsers: [], accountUsersIsLoading: false, profile: { + }) })] }), isDirty && (_jsx(Chip, { label: "\u25CF Unsaved changes", size: "small", variant: "outlined", color: "warning", "data-tid": "dirty-indicator" })), _jsx(Chip, { label: useUnitInspector ? "Unit inspector: on" : "Unit inspector: off", size: "small", variant: useUnitInspector ? "filled" : "outlined", color: "primary", onClick: () => setUseUnitInspector((on) => !on), "data-tid": "unit-inspector-toggle" }), _jsx(Chip, { label: `${allWorkflowJsons.length} workflows · ${allMaterials.length} materials`, size: "small", variant: "outlined", color: "secondary", sx: { ml: "auto" } })] }) }), _jsx(Box, { sx: { height: "calc(100vh - 72px)", overflow: "auto" }, children: _jsx(WorkflowDesignerContainer, { useUnitInspector: useUnitInspector, useHostTheme: true, initialWorkflow: wodeWorkflow, defaultMaterial: selectedMaterial, editable: true, showHistory: false, workflowHistory: { list: [], loading: false }, isStandalone: true, adjustable: true, showHeader: true, showMetadata: false, accountUsers: [], accountUsersIsLoading: false, profile: { user: { entity: { id: "1" } }, account: { entity: { id: "1" } }, personalAccount: { entity: { id: "1" } }, @@ -154,7 +156,7 @@ function App() { nodes: 1, queue: "D", timeLimit: "01:00:00", - }), generateEntityId: () => crypto.randomUUID(), openDocumentationDialog: undefined, onDirtyChange: setIsDirty }, designerKey) })] })); + }), generateEntityId: () => crypto.randomUUID(), openDocumentationDialog: undefined, onDirtyChange: setIsDirty }, `${designerKey}-${useUnitInspector}`) })] })); } // --------------------------------------------------------------------------- // Mount diff --git a/src/WorkflowDesignerContainer.tsx b/src/WorkflowDesignerContainer.tsx index 517f864..14b506c 100644 --- a/src/WorkflowDesignerContainer.tsx +++ b/src/WorkflowDesignerContainer.tsx @@ -69,6 +69,10 @@ type WorkflowDesignerContainerBaseProps = { openDocumentationDialog?: (searchText: string) => void; /** Fires when unsaved-changes state flips; lets the shell mark Save / guard navigation. */ onDirtyChange?: (isDirty: boolean) => void; + /** See {@link SubworkflowProps.useUnitInspector}. */ + useUnitInspector?: boolean; + /** See {@link WorkflowDefaultLayoutProps.useHostTheme}. */ + useHostTheme?: boolean; }; export type WorkflowDesignerContainerProps = WorkflowDesignerContainerBaseProps; @@ -121,6 +125,8 @@ export default function WorkflowDesignerContainer(containerProps: WorkflowDesign getDefaultComputeConfig, generateEntityId, onDirtyChange, + useUnitInspector, + useHostTheme, } = containerProps; const workflowComponents: WorkflowComponents = useMemo( @@ -394,6 +400,8 @@ export default function WorkflowDesignerContainer(containerProps: WorkflowDesign setRemoveUndoState(null)} /> void; } -function ImportantSettingsForUnit({ +export function ImportantSettingsForUnit({ unit, unitIndex, onContextChanged, diff --git a/src/components/subworkflows/Subworkflow.tsx b/src/components/subworkflows/Subworkflow.tsx index 9bed7f0..cf03ae3 100644 --- a/src/components/subworkflows/Subworkflow.tsx +++ b/src/components/subworkflows/Subworkflow.tsx @@ -38,6 +38,7 @@ import type { import { useWorkflowComponents } from "../../WorkflowComponentsContext"; import { UndoSnackbar, type UndoSnackbarState } from "../common/UndoSnackbar"; import UnitModal from "../units/UnitModal"; +import UnitInspectorDrawer from "./UnitInspectorDrawer"; import { ImportantSettings } from "./ImportantSettings"; import { SubworkflowExecutionUnitDetailsRow } from "./SubworkflowExecutionUnitDetailsRow"; import { SubworkflowMethodPanel } from "./SubworkflowMethodPanel"; @@ -79,6 +80,15 @@ export type SubworkflowProps = { * will actually run with. */ hideComputeSubTab?: boolean; + /** + * Clicking a unit in the flowchart opens its settings in a side drawer, + * instead of the reader leaving for the Settings tab and finding that unit + * among all the others. + * + * Opt-in per host: the tabs stay exactly as they are, so a host with tests or + * documentation against them is unaffected until it flips this. + */ + useUnitInspector?: boolean; }; export const TAB_NAVIGATION_CONFIG = { @@ -133,6 +143,7 @@ export function Subworkflow({ jobProperties, activeTabIndex, onActiveTabIndexChange, + useUnitInspector = false, hideComputeSubTab = false, }: SubworkflowProps) { const { getDefaultComputeConfig } = useWorkflowComponents(); @@ -305,16 +316,24 @@ export function Subworkflow({ [applyToSubworkflow], ); + const [isInspectorOpen, setIsInspectorOpen] = useState(false); + const onUnitSelect = useCallback( (unit: { flowchartId: string }) => { const index = subworkflow.units.findIndex((u) => u.flowchartId === unit.flowchartId); if (index > -1) { setUnitIndex((prev) => (index !== prev ? index : prev)); + if (useUnitInspector) setIsInspectorOpen(true); } }, - [subworkflow.units], + [subworkflow.units, useUnitInspector], ); + // The selected index survives units being added or removed; the drawer must + // not go on showing settings for a unit that is no longer there. + const inspectedUnit = + isInspectorOpen && useUnitInspector ? subworkflow.unitsInstances[unitIndex] ?? null : null; + const setTabIndex = useCallback( (index: number) => { onActiveTabIndexChange(index); @@ -355,6 +374,14 @@ export function Subworkflow({ return ( setRemoveUndoState(null)} /> + {useUnitInspector ? ( + setIsInspectorOpen(false)} + onContextChanged={onImportantSettingsContextChanged} + /> + ) : null} void; + onContextChanged: () => void; + id?: string; +} + +function isExecutionUnit(unit: AnySubworkflowUnit): unit is ExecutionUnit { + // Schema `type`, not `instanceof`: units may come from a second compiled copy + // of `@mat3ra/wode` (see the note in ImportantSettings). + return unit.type === "execution"; +} + +/** + * One unit's settings, beside the flowchart that selects it. + * + * Adjusting a unit used to mean leaving the flowchart for the Settings tab, + * finding that unit among all the others, changing it, and coming back to see + * what it did — a bounce between three tabs for one edit, with the diagram that + * gives the change its meaning off screen the whole time. Here the unit stays + * selected in the flowchart while its settings are open next to it. + * + * A plain MUI `Drawer` rather than cove's `ResizableDrawer`: that one is anchored + * to the bottom and resizes on height only, and generalising it to two axes is a + * change to a shared component with its own consumers. The width handle here is + * a few lines and does not put them at risk. + */ +export default function UnitInspectorDrawer({ + unit, + unitIndex, + onClose, + onContextChanged, + id = "unit-inspector-drawer", +}: UnitInspectorDrawerProps) { + const [width, setWidth] = React.useState(DEFAULT_WIDTH); + const isResizing = React.useRef(false); + + React.useEffect(() => { + const resize = (event: MouseEvent) => { + if (!isResizing.current) return; + // The drawer is anchored right, so its width is the distance from the + // pointer to the right edge of the window. + const next = window.innerWidth - event.clientX; + setWidth(Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, next))); + }; + const stop = () => { + isResizing.current = false; + }; + + document.addEventListener("mousemove", resize); + document.addEventListener("mouseup", stop); + + return () => { + document.removeEventListener("mousemove", resize); + document.removeEventListener("mouseup", stop); + }; + }, []); + + return ( + + { + isResizing.current = true; + }} + sx={{ + position: "absolute", + left: 0, + top: 0, + bottom: 0, + width: 6, + cursor: "col-resize", + "&:hover": { bgcolor: "action.hover" }, + }} + /> + + + + + {unit?.name ?? "Unit"} + + + Unit {unitIndex + 1} + {unit?.type ? ` · ${unit.type}` : ""} + + + + + + + + + {unit && isExecutionUnit(unit) ? ( + + ) : ( + + {unit + ? `A ${unit.type} unit has no important settings to adjust.` + : "Select a unit in the flowchart."} + + )} + + + ); +} diff --git a/src/components/workflows/Workflow.tsx b/src/components/workflows/Workflow.tsx index 1ea8d63..e6a5b08 100644 --- a/src/components/workflows/Workflow.tsx +++ b/src/components/workflows/Workflow.tsx @@ -109,6 +109,10 @@ export type WorkflowProps = { * which one the job will run with. */ hideComputeSubTab?: boolean; + /** See {@link SubworkflowProps.useUnitInspector}. */ + useUnitInspector?: boolean; + /** See {@link WorkflowDefaultLayoutProps.useHostTheme}. */ + useHostTheme?: boolean; }; const noop = (): undefined => undefined; @@ -171,6 +175,8 @@ export function Workflow({ isDescriptionEditable, jobProperties, hideComputeSubTab = false, + useUnitInspector = false, + useHostTheme = false, showUnitStatus = false, }: WorkflowProps) { const [unitIndex, setUnitIndex] = useState(0); @@ -502,6 +508,8 @@ export function Workflow({ createMetaProperty={createMetaProperty} jobProperties={jobProperties} hideComputeSubTab={hideComputeSubTab} + useUnitInspector={useUnitInspector} + useHostTheme={useHostTheme} subworkflowActiveTabIndexById={subworkflowActiveTabIndexById} onSubworkflowActiveTabIndexChange={onSubworkflowActiveTabIndexChange} /> diff --git a/src/components/workflows/WorkflowDefaultLayout.tsx b/src/components/workflows/WorkflowDefaultLayout.tsx index b8c8aa1..5ce886a 100644 --- a/src/components/workflows/WorkflowDefaultLayout.tsx +++ b/src/components/workflows/WorkflowDefaultLayout.tsx @@ -127,6 +127,17 @@ export type WorkflowDefaultLayoutProps = { onSubworkflowActiveTabIndexChange: (subworkflowId: string, tabIndex: number) => void; /** See {@link SubworkflowProps.hideComputeSubTab}. */ hideComputeSubTab?: boolean; + /** See {@link SubworkflowProps.useUnitInspector}. */ + useUnitInspector?: boolean; + /** + * Renders under the host's theme instead of forcing cove's old light one. + * + * The designer has always pinned itself to `oldLightMaterialUITheme`, which + * is why a dark host frames a white canvas: the shell is dark, and this + * subtree is not. Opt-in, because hosts that expect the light designer today + * would otherwise be restyled without asking. + */ + useHostTheme?: boolean; }; export function WorkflowDefaultLayout(props: WorkflowDefaultLayoutProps) { @@ -184,6 +195,8 @@ export function WorkflowDefaultLayout(props: WorkflowDefaultLayoutProps) { subworkflowActiveTabIndexById, onSubworkflowActiveTabIndexChange, hideComputeSubTab, + useUnitInspector, + useHostTheme = false, } = props; const { EntityHeaderComponent, MetadataComponent, HistoryComponent } = useWorkflowComponents(); @@ -211,179 +224,181 @@ export function WorkflowDefaultLayout(props: WorkflowDefaultLayoutProps) { const { pseudoUploadReduxDialog, unitTypeReduxDialog } = dialogs; - return ( - -
- {showHeader && ( - - )} + const content = ( +
+ {showHeader && ( + + )} - - - - + + + + + + + + {unit.type === UnitType.subworkflow && ( + <> + - - - - - {unit.type === UnitType.subworkflow && ( - <> - - {/* + {/* key={subworkflow.id} remounts when the user picks another flowchart branch. Inner tab index is held on {@link Workflow} (not Subworkflow) so job.render() remounts do not reset Important settings, while leaving the job Workflow tab unmounts Workflow and returns to Overview on the next visit. */} - {subworkflow ? ( - - onSubworkflowActiveTabIndexChange( - subworkflow.id, - tabIndex, - ) - } - onUpdate={onSubworkflowUnitUpdate} - isStandalone={isStandalone} - isMethodDataLoading={isMethodDataLoading} - editable={Boolean(editable)} - adjustable={Boolean(adjustable)} - onMaterialSwitch={onMaterialSwitch} - materials={materials} - materialsIndex={materialsIndex} - metaProperties={metaProperties} - onOutputUpdateRequest={onOutputUpdateRequest} - accountUsers={accountUsers} - accountUsersIsLoading={accountUsersIsLoading} - currentUser={profile.user.entity} - clusters={clusters} - pseudoUploadReduxDialog={pseudoUploadReduxDialog} - unitTypeReduxDialog={unitTypeReduxDialog} - profile={profile} - publicAccount={publicAccount} - createMetaProperty={createMetaProperty} - jobProperties={jobProperties} - /> - ) : null} - - )} - {unit.type === UnitType.map && ( - - + onSubworkflowActiveTabIndexChange(subworkflow.id, tabIndex) + } + onUpdate={onSubworkflowUnitUpdate} + isStandalone={isStandalone} + isMethodDataLoading={isMethodDataLoading} editable={Boolean(editable)} adjustable={Boolean(adjustable)} onMaterialSwitch={onMaterialSwitch} materials={materials} materialsIndex={materialsIndex} - iconCls={iconCls} + metaProperties={metaProperties} onOutputUpdateRequest={onOutputUpdateRequest} - parentWorkflow={entity} accountUsers={accountUsers} accountUsersIsLoading={accountUsersIsLoading} currentUser={profile.user.entity} - publicAccount={publicAccount} - profile={profile} clusters={clusters} - dialogs={dialogs} - templates={templates} - isDescriptionEditable={isDescriptionEditable} - metaProperties={metaProperties} + pseudoUploadReduxDialog={pseudoUploadReduxDialog} + unitTypeReduxDialog={unitTypeReduxDialog} + profile={profile} + publicAccount={publicAccount} + createMetaProperty={createMetaProperty} + jobProperties={jobProperties} /> - - )} - {unit.type === UnitType.error && ( - - - - )} - + ) : null} + + )} + {unit.type === UnitType.map && ( + + + + )} + {unit.type === UnitType.error && ( + + + + )} - - {showMetadata && ( - - )} - - {showHistory && } -
- + + + {showMetadata && ( + + )} + + {showHistory && } +
+ ); + + return useHostTheme ? ( + content + ) : ( + {content} ); } diff --git a/src/standalone/index.tsx b/src/standalone/index.tsx index f34505d..f3f864c 100644 --- a/src/standalone/index.tsx +++ b/src/standalone/index.tsx @@ -136,6 +136,8 @@ function App() { ); const selectedMaterial = allMaterials[materialIndex]; const [isDirty, setIsDirty] = useState(false); + // Phase 3.3 surface, opt-in: the demo is where it gets reviewed before a host flips it on. + const [useUnitInspector, setUseUnitInspector] = useState(true); // Re-key the designer when either selection changes so it re-mounts cleanly const designerKey = `${workflowIndex}-${materialIndex}`; @@ -238,6 +240,14 @@ function App() { data-tid="dirty-indicator" /> )} + setUseUnitInspector((on) => !on)} + data-tid="unit-inspector-toggle" + /> Date: Mon, 17 Aug 2026 03:47:51 +0000 Subject: [PATCH 6/6] chore: drop git-lfs hooks that were committed by accident MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `git lfs install` writes its hooks into whatever `core.hooksPath` points at, which husky sets to `.husky/` — so four LFS hooks landed in the previous commit from a local environment rather than from this repo. They are not harmless noise: each exits 2 when `git-lfs` is absent, so anyone without it installed would find `git push` and `git checkout` failing in a repo that does not use LFS at all. Only `.husky/pre-commit` belongs here, as in the sibling packages. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01DK8KomMescJvMQNSEfeRR8 --- .husky/post-checkout | 3 --- .husky/post-commit | 3 --- .husky/post-merge | 3 --- .husky/pre-push | 3 --- 4 files changed, 12 deletions(-) delete mode 100755 .husky/post-checkout delete mode 100755 .husky/post-commit delete mode 100755 .husky/post-merge delete mode 100755 .husky/pre-push diff --git a/.husky/post-checkout b/.husky/post-checkout deleted file mode 100755 index ca7fcb4..0000000 --- a/.husky/post-checkout +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'post-checkout' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks').\n"; exit 2; } -git lfs post-checkout "$@" diff --git a/.husky/post-commit b/.husky/post-commit deleted file mode 100755 index 52b339c..0000000 --- a/.husky/post-commit +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'post-commit' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks').\n"; exit 2; } -git lfs post-commit "$@" diff --git a/.husky/post-merge b/.husky/post-merge deleted file mode 100755 index a912e66..0000000 --- a/.husky/post-merge +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'post-merge' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks').\n"; exit 2; } -git lfs post-merge "$@" diff --git a/.husky/pre-push b/.husky/pre-push deleted file mode 100755 index 0f0089b..0000000 --- a/.husky/pre-push +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'pre-push' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks').\n"; exit 2; } -git lfs pre-push "$@"