feat(ui): add conditionally-enabled workflow publishing ui

This is a squash of a lot of scattered commits that became very difficult to clean up and make individually. Sorry.

Besides the new UI, there are a number of notable changes:
- Publishing logic is disabled in OSS by default. To enable it, provided a `disabledFeatures` prop _without_ "publishWorkflow".
- Enqueuing a workflow is no longer handled in a redux listener. It was  hard to track the state of the enqueue logic in the listener. It is now in a hook. I did not migrate the canvas and upscaling tabs - their enqueue logic is still in the listener.
- When queueing a validation run, the new `useEnqueueWorkflows()` hook will update the payload with the required data for the run.
- Some logic is added to the socket event listeners to handle workflow publish runs completing.
- The workflow library side nav has a new "published" view. It is hidden when the "publishWorkflow" feature is disabled.
- I've added `Safe` and `OrThrow` versions of some workflows hooks. These hooks typically retrieve some data from redux. For example, a node. The `Safe` hooks return the node or null if it cannot be found, while the `OrThrow` hooks return the node or raise if it cannot be found. The `OrThrow` hooks should be used within one of the gate components. These components use the `Safe` hooks and render a fallback if e.g. the node isn't found. This change is required for some of the publish flow UI.
- Add support for locking the workflow editor. When locked, you can pan and zoom but that's it. Currently, it is only locked during publish flow and if a published workflow is opened.
This commit is contained in:
psychedelicious
2025-04-02 16:21:58 +10:00
parent d66fdfde71
commit e4678201cb
101 changed files with 1410 additions and 341 deletions

View File

@@ -5,6 +5,7 @@ import {
formFieldInitialValuesChanged,
workflowCategoryChanged,
workflowIDChanged,
workflowIsPublishedChanged,
workflowNameChanged,
workflowSaved,
} from 'features/nodes/store/workflowSlice';
@@ -65,6 +66,7 @@ export const useCreateLibraryWorkflow = (): CreateLibraryWorkflowReturn => {
meta: { category },
} = data.workflow;
dispatch(workflowIDChanged(id));
dispatch(workflowIsPublishedChanged(false));
dispatch(workflowNameChanged(name));
dispatch(workflowCategoryChanged(category));
dispatch(newWorkflowSaved({ category }));

View File

@@ -1,24 +1,29 @@
import { useAppSelector } from 'app/store/storeHooks';
import { selectWorkflowIsPublished } from 'features/nodes/store/workflowSlice';
import { useBuildWorkflowFast } from 'features/nodes/util/workflow/buildWorkflow';
import { saveWorkflowAs } from 'features/workflowLibrary/components/SaveWorkflowAsDialog';
import { isLibraryWorkflow, useSaveLibraryWorkflow } from 'features/workflowLibrary/hooks/useSaveLibraryWorkflow';
import { useCallback } from 'react';
/**
* Returns a function that saves the current workflow if it's a library workflow, or opens the save dialog.
* Returns a function that saves the current workflow if it's a library workflow, or opens the save as dialog.
*
* Published workflows are always saved as a new workflow.
*/
export const useSaveOrSaveAsWorkflow = () => {
const buildWorkflow = useBuildWorkflowFast();
const isPublished = useAppSelector(selectWorkflowIsPublished);
const { saveWorkflow } = useSaveLibraryWorkflow();
const saveOrSaveAsWorkflow = useCallback(() => {
const workflow = buildWorkflow();
if (isLibraryWorkflow(workflow)) {
if (isLibraryWorkflow(workflow) && !isPublished) {
saveWorkflow(workflow);
} else {
saveWorkflowAs(workflow);
}
}, [buildWorkflow, saveWorkflow]);
}, [buildWorkflow, isPublished, saveWorkflow]);
return saveOrSaveAsWorkflow;
};