feat(ui): rename tab identifiers

- "txt2img" -> "generation"
- "unifiedCanvas" -> "canvas"
- "modelManager" -> "models"
- "nodes" -> "workflows"
- Add UI slice migration setting the active tab to "generation"
This commit is contained in:
psychedelicious 2024-05-03 06:52:15 +10:00 committed by Kent Keirsey
parent 7c1f1076b4
commit 0f7fdabe9b
36 changed files with 80 additions and 77 deletions

View File

@ -20,8 +20,7 @@ export type LoggerNamespace =
| 'models'
| 'config'
| 'canvas'
| 'txt2img'
| 'img2img'
| 'generation'
| 'nodes'
| 'system'
| 'socketio'

View File

@ -30,7 +30,7 @@ import type { ImageDTO } from 'services/api/types';
export const addEnqueueRequestedCanvasListener = (startAppListening: AppStartListening) => {
startAppListening({
predicate: (action): action is ReturnType<typeof enqueueRequested> =>
enqueueRequested.match(action) && action.payload.tabName === 'unifiedCanvas',
enqueueRequested.match(action) && action.payload.tabName === 'canvas',
effect: async (action, { getState, dispatch }) => {
const log = logger('queue');
const { prepend } = action.payload;

View File

@ -8,7 +8,7 @@ import { queueApi } from 'services/api/endpoints/queue';
export const addEnqueueRequestedLinear = (startAppListening: AppStartListening) => {
startAppListening({
predicate: (action): action is ReturnType<typeof enqueueRequested> =>
enqueueRequested.match(action) && action.payload.tabName === 'txt2img',
enqueueRequested.match(action) && action.payload.tabName === 'generation',
effect: async (action, { getState, dispatch }) => {
const state = getState();
const model = state.generation.model;

View File

@ -8,7 +8,7 @@ import type { BatchConfig } from 'services/api/types';
export const addEnqueueRequestedNodes = (startAppListening: AppStartListening) => {
startAppListening({
predicate: (action): action is ReturnType<typeof enqueueRequested> =>
enqueueRequested.match(action) && action.payload.tabName === 'nodes',
enqueueRequested.match(action) && action.payload.tabName === 'workflows',
effect: async (action, { getState, dispatch }) => {
const state = getState();
const { nodes, edges } = state.nodes;

View File

@ -17,7 +17,7 @@ const accept: Accept = {
const selectPostUploadAction = createMemoizedSelector(activeTabNameSelector, (activeTabName) => {
let postUploadAction: PostUploadAction = { type: 'TOAST' };
if (activeTabName === 'unifiedCanvas') {
if (activeTabName === 'canvas') {
postUploadAction = { type: 'SET_CANVAS_INITIAL_IMAGE' };
}

View File

@ -67,7 +67,7 @@ export const useGlobalHotkeys = () => {
useHotkeys(
'1',
() => {
dispatch(setActiveTab('txt2img'));
dispatch(setActiveTab('generation'));
},
[dispatch]
);
@ -75,7 +75,7 @@ export const useGlobalHotkeys = () => {
useHotkeys(
'2',
() => {
dispatch(setActiveTab('unifiedCanvas'));
dispatch(setActiveTab('canvas'));
},
[dispatch]
);
@ -83,7 +83,7 @@ export const useGlobalHotkeys = () => {
useHotkeys(
'3',
() => {
dispatch(setActiveTab('nodes'));
dispatch(setActiveTab('workflows'));
},
[dispatch]
);
@ -92,7 +92,7 @@ export const useGlobalHotkeys = () => {
'4',
() => {
if (isModelManagerEnabled) {
dispatch(setActiveTab('modelManager'));
dispatch(setActiveTab('models'));
}
},
[dispatch, isModelManagerEnabled]

View File

@ -40,7 +40,7 @@ const selector = createMemoizedSelector(
reasons.push(i18n.t('parameters.invoke.systemDisconnected'));
}
if (activeTabName === 'nodes') {
if (activeTabName === 'workflows') {
if (nodes.shouldValidateGraph) {
if (!nodes.nodes.length) {
reasons.push(i18n.t('parameters.invoke.noNodesInGraph'));
@ -93,8 +93,8 @@ const selector = createMemoizedSelector(
reasons.push(i18n.t('parameters.invoke.noModelSelected'));
}
if (activeTabName === 'txt2img') {
// Handling for Control Layers - only exists on txt2img tab now
if (activeTabName === 'generation') {
// Handling for generation tab
controlLayers.present.layers
.filter((l) => l.isEnabled)
.flatMap((l) => {

View File

@ -75,7 +75,7 @@ const useInpaintingCanvasHotkeys = () => {
const onKeyDown = useCallback(
(e: KeyboardEvent) => {
if (e.repeat || e.key !== ' ' || isInteractiveTarget(e.target) || activeTabName !== 'unifiedCanvas') {
if (e.repeat || e.key !== ' ' || isInteractiveTarget(e.target) || activeTabName !== 'canvas') {
return;
}
if ($toolStash.get() || $tool.get() === 'move') {
@ -90,7 +90,7 @@ const useInpaintingCanvasHotkeys = () => {
);
const onKeyUp = useCallback(
(e: KeyboardEvent) => {
if (e.repeat || e.key !== ' ' || isInteractiveTarget(e.target) || activeTabName !== 'unifiedCanvas') {
if (e.repeat || e.key !== ' ' || isInteractiveTarget(e.target) || activeTabName !== 'canvas') {
return;
}
if (!$toolStash.get() || $tool.get() !== 'move') {

View File

@ -76,7 +76,7 @@ const ControlAdapterConfig = (props: { id: string; number: number }) => {
<Box minW={0} w="full" transitionProperty="common" transitionDuration="0.1s">
<ParamControlAdapterModel id={id} />
</Box>
{activeTabName === 'unifiedCanvas' && <ControlNetCanvasImageImports id={id} />}
{activeTabName === 'canvas' && <ControlNetCanvasImageImports id={id} />}
<IconButton
size="sm"
tooltip={t('controlnet.duplicate')}

View File

@ -93,7 +93,7 @@ const ControlAdapterImagePreview = ({ isSmall, id }: Props) => {
return;
}
if (activeTabName === 'unifiedCanvas') {
if (activeTabName === 'canvas') {
dispatch(setBoundingBoxDimensions({ width: controlImage.width, height: controlImage.height }, optimalDimension));
} else {
const options = { updateAspectRatio: true, clamp: true };

View File

@ -80,7 +80,7 @@ export const ControlAdapterImagePreview = memo(
return;
}
if (activeTabName === 'unifiedCanvas') {
if (activeTabName === 'canvas') {
dispatch(
setBoundingBoxDimensions({ width: controlImage.width, height: controlImage.height }, optimalDimension)
);

View File

@ -46,7 +46,7 @@ export const IPAdapterImagePreview = memo(
return;
}
if (activeTabName === 'unifiedCanvas') {
if (activeTabName === 'canvas') {
dispatch(
setBoundingBoxDimensions({ width: controlImage.width, height: controlImage.height }, optimalDimension)
);

View File

@ -43,7 +43,7 @@ export const InitialImagePreview = memo(({ image, onChangeImage, droppableData,
return;
}
if (activeTabName === 'unifiedCanvas') {
if (activeTabName === 'canvas') {
dispatch(setBoundingBoxDimensions({ width: imageDTO.width, height: imageDTO.height }, optimalDimension));
} else {
const options = { updateAspectRatio: true, clamp: true };

View File

@ -7,7 +7,7 @@ import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { useCallback } from 'react';
const selectZoom = createSelector([selectNodesSlice, activeTabNameSelector], (nodes, activeTabName) =>
activeTabName === 'nodes' ? nodes.viewport.zoom : 1
activeTabName === 'workflows' ? nodes.viewport.zoom : 1
);
/**

View File

@ -45,7 +45,7 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const toaster = useAppToaster();
const isCanvasEnabled = useFeatureStatus('unifiedCanvas');
const isCanvasEnabled = useFeatureStatus('canvas');
const customStarUi = useStore($customStarUI);
const { downloadImage } = useDownloadImage();
@ -78,7 +78,7 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
const handleSendToCanvas = useCallback(() => {
dispatch(sentImageToCanvas());
flushSync(() => {
dispatch(setActiveTab('unifiedCanvas'));
dispatch(setActiveTab('canvas'));
});
dispatch(setInitialCanvasImage(imageDTO, optimalDimension));

View File

@ -52,12 +52,12 @@ const ImageMetadataActions = (props: Props) => {
<MetadataItem metadata={metadata} handlers={handlers.refinerStart} />
<MetadataItem metadata={metadata} handlers={handlers.refinerSteps} />
<MetadataLoRAs metadata={metadata} />
{activeTabName !== 'txt2img' && <MetadataControlNets metadata={metadata} />}
{activeTabName !== 'txt2img' && <MetadataT2IAdapters metadata={metadata} />}
{activeTabName !== 'txt2img' && <MetadataIPAdapters metadata={metadata} />}
{activeTabName === 'txt2img' && <MetadataControlNetsV2 metadata={metadata} />}
{activeTabName === 'txt2img' && <MetadataT2IAdaptersV2 metadata={metadata} />}
{activeTabName === 'txt2img' && <MetadataIPAdaptersV2 metadata={metadata} />}
{activeTabName !== 'generation' && <MetadataControlNets metadata={metadata} />}
{activeTabName !== 'generation' && <MetadataT2IAdapters metadata={metadata} />}
{activeTabName !== 'generation' && <MetadataIPAdapters metadata={metadata} />}
{activeTabName === 'generation' && <MetadataControlNetsV2 metadata={metadata} />}
{activeTabName === 'generation' && <MetadataT2IAdaptersV2 metadata={metadata} />}
{activeTabName === 'generation' && <MetadataIPAdaptersV2 metadata={metadata} />}
</>
);
};

View File

@ -11,11 +11,11 @@ import { useTranslation } from 'react-i18next';
import { PiArrowLeftBold } from 'react-icons/pi';
const TAB_NAME_TO_TKEY: Record<InvokeTabName, string> = {
txt2img: 'common.txt2img',
unifiedCanvas: 'common.unifiedCanvas',
nodes: 'common.nodes',
modelManager: 'modelManager.modelManager',
queue: 'queue.queue',
generation: 'ui.tabs.generation',
canvas: 'ui.tabs.canvas',
workflows: 'ui.tabs.workflows',
models: 'ui.tabs.models',
queue: 'ui.tabs.queue',
};
export const ImageViewer = memo(() => {

View File

@ -14,7 +14,7 @@ export const useGalleryHotkeys = () => {
const isStaging = useAppSelector(isStagingSelector);
// block navigation on Unified Canvas tab when staging new images
const canNavigateGallery = useMemo(() => {
return activeTabName !== 'unifiedCanvas' || !isStaging;
return activeTabName !== 'canvas' || !isStaging;
}, [activeTabName, isStaging]);
const {

View File

@ -43,12 +43,12 @@ export const useImageActions = (image_name?: string) => {
}, [metadata]);
const recallAll = useCallback(() => {
parseAndRecallAllMetadata(metadata, activeTabName === 'txt2img');
parseAndRecallAllMetadata(metadata, activeTabName === 'generation');
}, [activeTabName, metadata]);
const remix = useCallback(() => {
// Recalls all metadata parameters except seed
parseAndRecallAllMetadata(metadata, activeTabName === 'txt2img', ['seed']);
parseAndRecallAllMetadata(metadata, activeTabName === 'generation', ['seed']);
}, [activeTabName, metadata]);
const recallSeed = useCallback(() => {

View File

@ -39,7 +39,7 @@ const ToastDescription = () => {
const toast = useToast();
const onClick = useCallback(() => {
dispatch(setActiveTab('modelManager'));
dispatch(setActiveTab('models'));
toast.close(TOAST_ID);
}, [dispatch, toast]);

View File

@ -31,9 +31,9 @@ export const addControlNetToLinearGraph = async (
}
);
// The txt2img tab has special handling - its control adapters are set up in the Control Layers graph helper.
// The generation tab has special handling - its control adapters are set up in the Control Layers graph helper.
const activeTabName = activeTabNameSelector(state);
assert(activeTabName !== 'txt2img', 'Tried to use addControlNetToLinearGraph on txt2img tab');
assert(activeTabName !== 'generation', 'Tried to use addControlNetToLinearGraph on generation tab');
if (controlNets.length) {
// Even though denoise_latents' control input is collection or scalar, keep it simple and always use a collect

View File

@ -106,7 +106,7 @@ export const addHrfToGraph = (state: RootState, graph: NonNullableGraph): void =
if (!state.hrf.hrfEnabled || state.config.disabledSDFeatures.includes('hrf')) {
return;
}
const log = logger('txt2img');
const log = logger('generation');
const { vae, seamlessXAxis, seamlessYAxis } = state.generation;
const { hrfStrength, hrfEnabled, hrfMethod } = state.hrf;

View File

@ -20,9 +20,9 @@ export const addIPAdapterToLinearGraph = async (
graph: NonNullableGraph,
baseNodeId: string
): Promise<void> => {
// The txt2img tab has special handling - its control adapters are set up in the Control Layers graph helper.
// The generation tab has special handling - its control adapters are set up in the Control Layers graph helper.
const activeTabName = activeTabNameSelector(state);
assert(activeTabName !== 'txt2img', 'Tried to use addT2IAdaptersToLinearGraph on txt2img tab');
assert(activeTabName !== 'generation', 'Tried to use addT2IAdaptersToLinearGraph on generation tab');
const ipAdapters = selectValidIPAdapters(state.controlAdapters).filter(({ model, controlImage, isEnabled }) => {
const hasModel = Boolean(model);

View File

@ -20,9 +20,9 @@ export const addT2IAdaptersToLinearGraph = async (
graph: NonNullableGraph,
baseNodeId: string
): Promise<void> => {
// The txt2img tab has special handling - its control adapters are set up in the Control Layers graph helper.
// The generation tab has special handling - its control adapters are set up in the Control Layers graph helper.
const activeTabName = activeTabNameSelector(state);
assert(activeTabName !== 'txt2img', 'Tried to use addT2IAdaptersToLinearGraph on txt2img tab');
assert(activeTabName !== 'generation', 'Tried to use addT2IAdaptersToLinearGraph on generation tab');
const t2iAdapters = selectValidT2IAdapters(state.controlAdapters).filter(
({ model, processedControlImage, processorType, controlImage, isEnabled }) => {

View File

@ -31,7 +31,7 @@ export const getSDXLStylePrompts = (state: RootState): { positiveStylePrompt: st
*/
export const getIsIntermediate = (state: RootState) => {
const activeTabName = activeTabNameSelector(state);
if (activeTabName === 'unifiedCanvas') {
if (activeTabName === 'canvas') {
return !state.canvas.shouldAutoSave;
}
return false;

View File

@ -10,10 +10,10 @@ export const NavigateToModelManagerButton = memo((props: Omit<IconButtonProps, '
const { t } = useTranslation();
const dispatch = useAppDispatch();
const disabledTabs = useAppSelector((s) => s.config.disabledTabs);
const shouldShowButton = useMemo(() => !disabledTabs.includes('modelManager'), [disabledTabs]);
const shouldShowButton = useMemo(() => !disabledTabs.includes('models'), [disabledTabs]);
const handleClick = useCallback(() => {
dispatch(setActiveTab('modelManager'));
dispatch(setActiveTab('models'));
}, [dispatch]);
if (!shouldShowButton) {

View File

@ -25,7 +25,7 @@ export const usePreselectedImage = (selectedImage?: {
const handleSendToCanvas = useCallback(() => {
if (selectedImageDto) {
dispatch(setInitialCanvasImage(selectedImageDto, optimalDimension));
dispatch(setActiveTab('unifiedCanvas'));
dispatch(setActiveTab('canvas'));
toaster({
title: t('toast.sentToUnifiedCanvas'),
status: 'info',

View File

@ -31,7 +31,7 @@ const selector = createMemoizedSelector(
const badges: string[] = [];
const isSDXL = model?.base === 'sdxl';
if (activeTabName === 'unifiedCanvas') {
if (activeTabName === 'canvas') {
const {
aspectRatio,
boundingBoxDimensions: { width, height },
@ -85,7 +85,7 @@ export const ImageSettingsAccordion = memo(() => {
onToggle={onToggleAccordion}
>
<Flex px={4} pt={4} w="full" h="full" flexDir="column" data-testid="image-settings-accordion">
{activeTabName === 'unifiedCanvas' ? <ImageSizeCanvas /> : <ImageSizeLinear />}
{activeTabName === 'canvas' ? <ImageSizeCanvas /> : <ImageSizeLinear />}
<Expander label={t('accordions.advanced.options')} isOpen={isOpenExpander} onToggle={onToggleExpander}>
<Flex gap={4} pb={4} flexDir="column">
<Flex gap={4} alignItems="center">
@ -93,9 +93,9 @@ export const ImageSettingsAccordion = memo(() => {
<ParamSeedShuffle />
<ParamSeedRandomize />
</Flex>
{activeTabName === 'unifiedCanvas' && <ImageToImageStrength />}
{activeTabName === 'txt2img' && !isSDXL && <HrfSettings />}
{activeTabName === 'unifiedCanvas' && (
{activeTabName === 'canvas' && <ImageToImageStrength />}
{activeTabName === 'generation' && !isSDXL && <HrfSettings />}
{activeTabName === 'canvas' && (
<>
<ParamScaleBeforeProcessing />
<FormControlGroup formLabelProps={scalingLabelProps}>

View File

@ -50,7 +50,7 @@ export const ImageSizeLinear = memo(() => {
aspectRatioState={aspectRatioState}
heightComponent={<ParamHeight />}
widthComponent={<ParamWidth />}
previewComponent={tab === 'txt2img' ? <AspectRatioCanvasPreview /> : <AspectRatioIconPreview />}
previewComponent={tab === 'generation' ? <AspectRatioCanvasPreview /> : <AspectRatioIconPreview />}
onChangeAspectRatioState={onChangeAspectRatioState}
onChangeWidth={onChangeWidth}
onChangeHeight={onChangeHeight}

View File

@ -44,26 +44,26 @@ type TabData = {
};
const TAB_DATA: Record<InvokeTabName, TabData> = {
txt2img: {
id: 'txt2img',
generation: {
id: 'generation',
translationKey: 'ui.tabs.generation',
icon: <RiInputMethodLine />,
content: <TextToImageTab />,
},
unifiedCanvas: {
id: 'unifiedCanvas',
canvas: {
id: 'canvas',
translationKey: 'ui.tabs.canvas',
icon: <RiBrushLine />,
content: <UnifiedCanvasTab />,
},
nodes: {
id: 'nodes',
workflows: {
id: 'workflows',
translationKey: 'ui.tabs.workflows',
icon: <PiFlowArrowBold />,
content: <NodesTab />,
},
modelManager: {
id: 'modelManager',
models: {
id: 'models',
translationKey: 'ui.tabs.models',
icon: <RiBox2Line />,
content: <ModelManagerTab />,
@ -80,8 +80,8 @@ const enabledTabsSelector = createMemoizedSelector(selectConfigSlice, (config) =
TAB_NUMBER_MAP.map((tabName) => TAB_DATA[tabName]).filter((tab) => !config.disabledTabs.includes(tab.id))
);
const NO_GALLERY_PANEL_TABS: InvokeTabName[] = ['modelManager', 'queue'];
const NO_OPTIONS_PANEL_TABS: InvokeTabName[] = ['modelManager', 'queue'];
const NO_GALLERY_PANEL_TABS: InvokeTabName[] = ['models', 'queue'];
const NO_OPTIONS_PANEL_TABS: InvokeTabName[] = ['models', 'queue'];
const panelStyles: CSSProperties = { height: '100%', width: '100%' };
const GALLERY_MIN_SIZE_PX = 310;
const GALLERY_MIN_SIZE_PCT = 20;
@ -291,10 +291,10 @@ export default memo(InvokeTabs);
const ParametersPanelComponent = memo(() => {
const activeTabName = useAppSelector(activeTabNameSelector);
if (activeTabName === 'nodes') {
if (activeTabName === 'workflows') {
return <NodeEditorPanelGroup />;
}
if (activeTabName === 'txt2img') {
if (activeTabName === 'generation') {
return <ParametersPanelTextToImage />;
}
return <ParametersPanel />;

View File

@ -34,8 +34,8 @@ const ParametersPanel = () => {
{isSDXL ? <SDXLPrompts /> : <Prompts />}
<ImageSettingsAccordion />
<GenerationSettingsAccordion />
{activeTabName !== 'txt2img' && <ControlSettingsAccordion />}
{activeTabName === 'unifiedCanvas' && <CompositingSettingsAccordion />}
{activeTabName !== 'generation' && <ControlSettingsAccordion />}
{activeTabName === 'canvas' && <CompositingSettingsAccordion />}
{isSDXL && <RefinerSettingsAccordion />}
<AdvancedSettingsAccordion />
</Flex>

View File

@ -48,8 +48,8 @@ const ParametersPanelTextToImage = () => {
<Flex gap={2} flexDirection="column" h="full" w="full">
<ImageSettingsAccordion />
<GenerationSettingsAccordion />
{activeTabName !== 'txt2img' && <ControlSettingsAccordion />}
{activeTabName === 'unifiedCanvas' && <CompositingSettingsAccordion />}
{activeTabName !== 'generation' && <ControlSettingsAccordion />}
{activeTabName === 'canvas' && <CompositingSettingsAccordion />}
{isSDXL && <RefinerSettingsAccordion />}
<AdvancedSettingsAccordion />
</Flex>

View File

@ -1,3 +1,3 @@
export const TAB_NUMBER_MAP = ['txt2img', 'unifiedCanvas', 'nodes', 'modelManager', 'queue'] as const;
export const TAB_NUMBER_MAP = ['generation', 'canvas', 'workflows', 'models', 'queue'] as const;
export type InvokeTabName = (typeof TAB_NUMBER_MAP)[number];

View File

@ -11,7 +11,7 @@ export const activeTabNameSelector = createSelector(
* Previously `activeTab` was an integer, but now it's a string.
* Default to first tab in case user has integer.
*/
(ui) => (isString(ui.activeTab) ? ui.activeTab : 'txt2img')
(ui) => (isString(ui.activeTab) ? ui.activeTab : 'generation')
);
export const activeTabIndexSelector = createSelector(selectUiSlice, selectConfigSlice, (ui, config) => {

View File

@ -7,8 +7,8 @@ import type { InvokeTabName } from './tabMap';
import type { UIState } from './uiTypes';
const initialUIState: UIState = {
_version: 1,
activeTab: 'txt2img',
_version: 2,
activeTab: 'generation',
shouldShowImageDetails: false,
shouldShowProgressInViewer: true,
panels: {},
@ -43,7 +43,7 @@ export const uiSlice = createSlice({
},
extraReducers(builder) {
builder.addCase(workflowLoadRequested, (state) => {
state.activeTab = 'nodes';
state.activeTab = 'workflows';
});
},
});
@ -64,6 +64,10 @@ const migrateUIState = (state: any): any => {
if (!('_version' in state)) {
state._version = 1;
}
if (state._version === 1) {
state.activeTab = 'generation';
state._version = 2;
}
return state;
};

View File

@ -4,7 +4,7 @@ export interface UIState {
/**
* Slice schema version.
*/
_version: 1;
_version: 2;
/**
* The currently active tab.
*/