feat(ui): change reset button to menu

This commit is contained in:
psychedelicious
2025-02-21 07:56:49 +10:00
parent e2bdbfe721
commit 34d988063f
5 changed files with 61 additions and 15 deletions

View File

@@ -1709,7 +1709,8 @@
"delete": "Delete",
"openLibrary": "Open Library",
"builder": {
"resetForm": "Reset Form",
"deleteAllElements": "Delete All Form Elements",
"resetAllNodeFields": "Reset All Node Fields",
"builder": "Form Builder",
"layout": "Layout",
"row": "Row",

View File

@@ -1,31 +1,24 @@
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { Button, ButtonGroup, Flex, Spacer } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useAppSelector } from 'app/store/storeHooks';
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
import { firefoxDndFix } from 'features/dnd/util';
import { FormElementComponent } from 'features/nodes/components/sidePanel/builder/ContainerElementComponent';
import { buildFormElementDndData, useBuilderDndMonitor } from 'features/nodes/components/sidePanel/builder/dnd-hooks';
import { formReset, selectFormRootElementId } from 'features/nodes/store/workflowSlice';
import { WorkflowBuilderEditMenu } from 'features/nodes/components/sidePanel/builder/WorkflowBuilderMenu';
import { selectFormRootElementId } from 'features/nodes/store/workflowSlice';
import type { FormElement } from 'features/nodes/types/workflow';
import { buildContainer, buildDivider, buildHeading, buildText } from 'features/nodes/types/workflow';
import { startCase } from 'lodash-es';
import type { RefObject } from 'react';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { PiArrowCounterClockwiseBold } from 'react-icons/pi';
import { memo, useEffect, useRef, useState } from 'react';
import { assert } from 'tsafe';
export const WorkflowBuilder = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const rootElementId = useAppSelector(selectFormRootElementId);
useBuilderDndMonitor();
const resetForm = useCallback(() => {
dispatch(formReset());
}, [dispatch]);
return (
<Flex justifyContent="center" w="full" h="full">
<Flex flexDir="column" w="full" maxW="768px" gap={2}>
@@ -35,9 +28,7 @@ export const WorkflowBuilder = memo(() => {
<AddFormElementDndButton type="heading" />
<AddFormElementDndButton type="text" />
<Spacer />
<Button onClick={resetForm} variant="ghost" leftIcon={<PiArrowCounterClockwiseBold />}>
{t('workflows.builder.resetForm')}
</Button>
<WorkflowBuilderEditMenu />
</ButtonGroup>
<ScrollableContent>
<Flex>

View File

@@ -0,0 +1,30 @@
import { IconButton, Menu, MenuButton, MenuItem, MenuList } from '@invoke-ai/ui-library';
import { useAppStore } from 'app/store/nanostores/store';
import { useResetAllNodeFields } from 'features/nodes/components/sidePanel/builder/use-reset-all-node-fields';
import { formReset } from 'features/nodes/store/workflowSlice';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { PiArrowCounterClockwiseBold, PiDotsThreeBold, PiTrashBold } from 'react-icons/pi';
export const WorkflowBuilderEditMenu = memo(() => {
const { t } = useTranslation();
const store = useAppStore();
const resetAllNodeFields = useResetAllNodeFields();
const deleteAllElements = useCallback(() => {
store.dispatch(formReset());
}, [store]);
return (
<Menu placement="bottom-end">
<MenuButton as={IconButton} icon={<PiDotsThreeBold />} variant="ghost" />
<MenuList>
<MenuItem icon={<PiArrowCounterClockwiseBold />} onClick={resetAllNodeFields}>
{t('workflows.builder.resetAllNodeFields')}
</MenuItem>
<MenuItem isDestructive icon={<PiTrashBold />} onClick={deleteAllElements}>
{t('workflows.builder.deleteAllElements')}
</MenuItem>
</MenuList>
</Menu>
);
});
WorkflowBuilderEditMenu.displayName = 'WorkflowBuilderEditMenu';

View File

@@ -0,0 +1,20 @@
import { useAppStore } from 'app/store/nanostores/store';
import { fieldValueReset } from 'features/nodes/store/nodesSlice';
import { selectFormInitialValues, selectNodeFieldElements } from 'features/nodes/store/workflowSlice';
import { useCallback } from 'react';
export const useResetAllNodeFields = () => {
const store = useAppStore();
const resetAllNodeValuesToDefaults = useCallback(() => {
const allInitialValues = selectFormInitialValues(store.getState());
const nodeFieldElements = selectNodeFieldElements(store.getState());
for (const element of nodeFieldElements) {
if (!(element.id in allInitialValues)) {
continue;
}
const { nodeId, fieldName } = element.data.fieldIdentifier;
store.dispatch(fieldValueReset({ nodeId, fieldName, value: allInitialValues[element.id] }));
}
}, [store]);
return resetAllNodeValuesToDefaults;
};

View File

@@ -369,6 +369,10 @@ export const selectIsFormEmpty = createWorkflowSelector((workflow) => {
}
return rootElement.data.children.length === 0;
});
export const selectFormInitialValues = createWorkflowSelector((workflow) => workflow.formFieldInitialValues);
export const selectNodeFieldElements = createWorkflowSelector((workflow) =>
Object.values(workflow.form.elements).filter(isNodeFieldElement)
);
const buildSelectElement = (id: string) => createWorkflowSelector((workflow) => workflow.form?.elements[id]);
export const useElement = (id: string): FormElement | undefined => {
const selector = useMemo(() => buildSelectElement(id), [id]);