mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
workflow tab (#5680)
* new workflow tab UI - still using shared state with workflow editor tab * polish workflow details * remove workflow tab, add edit/view mode to workflow slice and get that working to switch between within editor tab * UI updates for view/edit mode * cleanup * add warning to view mode * lint * start with isTouched false * working on styling mode toggle * more UX iteration * lint * cleanup * save original field values to state, add indicator if they have been changed and give user choice to reset * lint * fix import and commit translation * dont switch to view mode when loading a workflow * warns before clearing editor * use folder icon * fix(ui): track do not erase value when resetting field value - When adding an exposed field, we need to add it to originalExposedFieldValues - When removing an exposed field, we need to remove it from originalExposedFieldValues - add `useFieldValue` and `useOriginalFieldValue` hooks to encapsulate related logic * feat(ui): use IconButton for workflow view/edit button * feat(ui): change icon for new workflow It was the same as the workflow tab icon, confusing bc you think it's going to somehow take you to the tab. * feat(ui): use render props for NewWorkflowConfirmationAlertDialog There was a lot of potentially sensitive logic shared between the new workflow button and menu items. Also, two instances of ConfirmationAlertDialog. Using a render prop deduplicates the logic & components * fix(ui): do not mark workflow touched when loading workflow This was occurring because the `nodesChanged` action is called by reactflow when loading a workflow. Specifically, it calculates and sets the node dimensions as it loads. The existing logic set `isTouched` whenever this action was called. The changes reactflow emits have types, and we can use the change types and data to determine if a change should result in the workflow being marked as touched. * chore(ui): lint * chore(ui): lint * delete empty file --------- Co-authored-by: Mary Hipp <maryhipp@Marys-MacBook-Air.local> Co-authored-by: psychedelicious <4822129+psychedelicious@users.noreply.github.com>
This commit is contained in:
@ -0,0 +1,28 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useFieldValue } from 'features/nodes/hooks/useFieldValue';
|
||||
import { fieldValueReset } from 'features/nodes/store/nodesSlice';
|
||||
import { selectWorkflowSlice } from 'features/nodes/store/workflowSlice';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
export const useFieldOriginalValue = (nodeId: string, fieldName: string) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const selectOriginalExposedFieldValues = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
selectWorkflowSlice,
|
||||
(workflow) =>
|
||||
workflow.originalExposedFieldValues.find((v) => v.nodeId === nodeId && v.fieldName === fieldName)?.value
|
||||
),
|
||||
[nodeId, fieldName]
|
||||
);
|
||||
const originalValue = useAppSelector(selectOriginalExposedFieldValues);
|
||||
const value = useFieldValue(nodeId, fieldName);
|
||||
const isValueChanged = useMemo(() => !isEqual(value, originalValue), [value, originalValue]);
|
||||
const onReset = useCallback(() => {
|
||||
dispatch(fieldValueReset({ nodeId, fieldName, value: originalValue }));
|
||||
}, [dispatch, fieldName, nodeId, originalValue]);
|
||||
|
||||
return { originalValue, isValueChanged, onReset };
|
||||
};
|
@ -0,0 +1,23 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useFieldValue = (nodeId: string, fieldName: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(selectNodesSlice, (nodes) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
return node?.data.inputs[fieldName]?.value;
|
||||
}),
|
||||
[fieldName, nodeId]
|
||||
);
|
||||
|
||||
const value = useAppSelector(selector);
|
||||
|
||||
return value;
|
||||
};
|
Reference in New Issue
Block a user