Compare commits

...

3 Commits

Author SHA1 Message Date
psychedelicious
793165fa6b use buildUseBoolean 2024-09-19 07:09:48 +10:00
Mary Hipp
8629ff24a1 fix(ui): update studio destination options and get them all working with new tab and store values 2024-09-18 10:48:59 -04:00
Mary Hipp
6e67642d11 feat(ui): update workflow library modal to use nanostore to track open/close 2024-09-18 10:48:39 -04:00
10 changed files with 90 additions and 40 deletions

View File

@@ -1,4 +1,6 @@
import { Box, useGlobalModifiersInit } from '@invoke-ai/ui-library';
import type { StudioDestination } from 'app/hooks/useHandleStudioDestination';
import { useHandleStudioDestination } from 'app/hooks/useHandleStudioDestination';
import { useSyncQueueStatus } from 'app/hooks/useSyncQueueStatus';
import { useLogger } from 'app/logging/useLogger';
import { appStarted } from 'app/store/middleware/listenerMiddleware/listeners/appStarted';
@@ -21,8 +23,6 @@ import RefreshAfterResetModal from 'features/system/components/SettingsModal/Ref
import { configChanged } from 'features/system/store/configSlice';
import { selectLanguage } from 'features/system/store/systemSelectors';
import { AppContent } from 'features/ui/components/AppContent';
import { setActiveTab } from 'features/ui/store/uiSlice';
import type { TabName } from 'features/ui/store/uiTypes';
import { useGetAndLoadLibraryWorkflow } from 'features/workflowLibrary/hooks/useGetAndLoadLibraryWorkflow';
import { AnimatePresence } from 'framer-motion';
import i18n from 'i18n';
@@ -45,7 +45,7 @@ interface Props {
};
selectedWorkflowId?: string;
selectedStylePresetId?: string;
destination?: TabName;
studioDestination?: StudioDestination;
}
const App = ({
@@ -53,7 +53,7 @@ const App = ({
selectedImage,
selectedWorkflowId,
selectedStylePresetId,
destination,
studioDestination,
}: Props) => {
const language = useAppSelector(selectLanguage);
const logger = useLogger('system');
@@ -66,6 +66,8 @@ const App = ({
useGlobalHotkeys();
useGetOpenAPISchemaQuery();
const handleStudioDestination = useHandleStudioDestination();
const { dropzone, isHandlingUpload, setIsHandlingUpload } = useFullscreenDropzone();
const handleReset = useCallback(() => {
@@ -100,10 +102,10 @@ const App = ({
}, [dispatch, selectedStylePresetId]);
useEffect(() => {
if (destination) {
dispatch(setActiveTab(destination));
if (studioDestination) {
handleStudioDestination(studioDestination);
}
}, [dispatch, destination]);
}, [handleStudioDestination, studioDestination]);
useEffect(() => {
dispatch(appStarted());

View File

@@ -1,6 +1,7 @@
import 'i18n';
import type { Middleware } from '@reduxjs/toolkit';
import type { StudioDestination } from 'app/hooks/useHandleStudioDestination';
import { $authToken } from 'app/store/nanostores/authToken';
import { $baseUrl } from 'app/store/nanostores/baseUrl';
import { $customNavComponent } from 'app/store/nanostores/customNavComponent';
@@ -18,7 +19,6 @@ import type { PartialAppConfig } from 'app/types/invokeai';
import Loading from 'common/components/Loading/Loading';
import AppDndContext from 'features/dnd/components/AppDndContext';
import type { WorkflowCategory } from 'features/nodes/types/workflow';
import type { TabName } from 'features/ui/store/uiTypes';
import type { PropsWithChildren, ReactNode } from 'react';
import React, { lazy, memo, useEffect, useMemo } from 'react';
import { Provider } from 'react-redux';
@@ -46,7 +46,7 @@ interface Props extends PropsWithChildren {
};
selectedWorkflowId?: string;
selectedStylePresetId?: string;
destination?: TabName;
studioDestination?: StudioDestination;
customStarUi?: CustomStarUi;
socketOptions?: Partial<ManagerOptions & SocketOptions>;
isDebugging?: boolean;
@@ -68,7 +68,7 @@ const InvokeAIUI = ({
selectedImage,
selectedWorkflowId,
selectedStylePresetId,
destination,
studioDestination,
customStarUi,
socketOptions,
isDebugging = false,
@@ -230,7 +230,7 @@ const InvokeAIUI = ({
selectedImage={selectedImage}
selectedWorkflowId={selectedWorkflowId}
selectedStylePresetId={selectedStylePresetId}
destination={destination}
studioDestination={studioDestination}
/>
</AppDndContext>
</ThemeLocaleProvider>

View File

@@ -0,0 +1,58 @@
import { useAppDispatch } from 'app/store/storeHooks';
import { settingsSendToCanvasChanged } from 'features/controlLayers/store/canvasSettingsSlice';
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
import { $isMenuOpen } from 'features/stylePresets/store/isMenuOpen';
import { setActiveTab } from 'features/ui/store/uiSlice';
import { useWorkflowLibraryModal } from 'features/workflowLibrary/store/isWorkflowLibraryModalOpen';
import { useCallback } from 'react';
export type StudioDestination =
| 'generation'
| 'canvas'
| 'workflows'
| 'upscaling'
| 'viewAllWorkflows'
| 'viewAllStylePresets';
export const useHandleStudioDestination = () => {
const dispatch = useAppDispatch();
const imageViewer = useImageViewer();
const workflowLibraryModal = useWorkflowLibraryModal();
const handleStudioDestination = useCallback(
(destination: StudioDestination) => {
switch (destination) {
case 'generation':
dispatch(setActiveTab('canvas'));
dispatch(settingsSendToCanvasChanged(false));
imageViewer.open();
break;
case 'canvas':
dispatch(setActiveTab('canvas'));
dispatch(settingsSendToCanvasChanged(true));
imageViewer.close();
break;
case 'workflows':
dispatch(setActiveTab('workflows'));
break;
case 'upscaling':
dispatch(setActiveTab('upscaling'));
break;
case 'viewAllWorkflows':
dispatch(setActiveTab('workflows'));
workflowLibraryModal.setTrue();
break;
case 'viewAllStylePresets':
dispatch(setActiveTab('canvas'));
$isMenuOpen.set(true);
break;
default:
dispatch(setActiveTab('canvas'));
break;
}
},
[dispatch, imageViewer, workflowLibraryModal]
);
return handleStudioDestination;
};

View File

@@ -1,6 +1,6 @@
import { Button } from '@invoke-ai/ui-library';
import { useWorkflowLibraryModalContext } from 'features/workflowLibrary/context/useWorkflowLibraryModalContext';
import { useLoadWorkflowFromFile } from 'features/workflowLibrary/hooks/useLoadWorkflowFromFile';
import { useWorkflowLibraryModal } from 'features/workflowLibrary/store/isWorkflowLibraryModalOpen';
import { memo, useCallback, useRef } from 'react';
import { useDropzone } from 'react-dropzone';
import { useTranslation } from 'react-i18next';
@@ -9,9 +9,9 @@ import { PiUploadSimpleBold } from 'react-icons/pi';
const UploadWorkflowButton = () => {
const { t } = useTranslation();
const resetRef = useRef<() => void>(null);
const { onClose } = useWorkflowLibraryModalContext();
const loadWorkflowFromFile = useLoadWorkflowFromFile({ resetRef, onSuccess: onClose });
const workflowLibraryModal = useWorkflowLibraryModal();
const loadWorkflowFromFile = useLoadWorkflowFromFile({ resetRef, onSuccess: workflowLibraryModal.setFalse });
const onDropAccepted = useCallback(
(files: File[]) => {
if (!files[0]) {

View File

@@ -1,5 +1,5 @@
import { IconButton, useDisclosure } from '@invoke-ai/ui-library';
import { WorkflowLibraryModalContext } from 'features/workflowLibrary/context/WorkflowLibraryModalContext';
import { IconButton } from '@invoke-ai/ui-library';
import { useWorkflowLibraryModal } from 'features/workflowLibrary/store/isWorkflowLibraryModalOpen';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiFolderOpenBold } from 'react-icons/pi';
@@ -8,19 +8,19 @@ import WorkflowLibraryModal from './WorkflowLibraryModal';
const WorkflowLibraryButton = () => {
const { t } = useTranslation();
const disclosure = useDisclosure();
const workflowLibraryModal = useWorkflowLibraryModal();
return (
<WorkflowLibraryModalContext.Provider value={disclosure}>
<>
<IconButton
aria-label={t('workflows.workflowLibrary')}
tooltip={t('workflows.workflowLibrary')}
icon={<PiFolderOpenBold />}
onClick={disclosure.onOpen}
onClick={workflowLibraryModal.setTrue}
pointerEvents="auto"
/>
<WorkflowLibraryModal />
</WorkflowLibraryModalContext.Provider>
</>
);
};

View File

@@ -3,9 +3,9 @@ import { EMPTY_OBJECT } from 'app/store/constants';
import { useAppSelector } from 'app/store/storeHooks';
import dateFormat, { masks } from 'dateformat';
import { selectWorkflowId } from 'features/nodes/store/workflowSlice';
import { useWorkflowLibraryModalContext } from 'features/workflowLibrary/context/useWorkflowLibraryModalContext';
import { useDeleteLibraryWorkflow } from 'features/workflowLibrary/hooks/useDeleteLibraryWorkflow';
import { useGetAndLoadLibraryWorkflow } from 'features/workflowLibrary/hooks/useGetAndLoadLibraryWorkflow';
import { useWorkflowLibraryModal } from 'features/workflowLibrary/store/isWorkflowLibraryModalOpen';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import type { WorkflowRecordListItemDTO } from 'services/api/types';
@@ -17,9 +17,9 @@ type Props = {
const WorkflowLibraryListItem = ({ workflowDTO }: Props) => {
const { t } = useTranslation();
const workflowId = useAppSelector(selectWorkflowId);
const { onClose } = useWorkflowLibraryModalContext();
const workflowLibraryModal = useWorkflowLibraryModal();
const { deleteWorkflow, deleteWorkflowResult } = useDeleteLibraryWorkflow(EMPTY_OBJECT);
const { getAndLoadWorkflow, getAndLoadWorkflowResult } = useGetAndLoadLibraryWorkflow({ onSuccess: onClose });
const { getAndLoadWorkflow, getAndLoadWorkflowResult } = useGetAndLoadLibraryWorkflow({ onSuccess: workflowLibraryModal.setFalse });
const handleDeleteWorkflow = useCallback(() => {
deleteWorkflow(workflowDTO.workflow_id);

View File

@@ -8,15 +8,16 @@ import {
ModalOverlay,
} from '@invoke-ai/ui-library';
import WorkflowLibraryContent from 'features/workflowLibrary/components/WorkflowLibraryContent';
import { useWorkflowLibraryModalContext } from 'features/workflowLibrary/context/useWorkflowLibraryModalContext';
import { useWorkflowLibraryModal } from 'features/workflowLibrary/store/isWorkflowLibraryModalOpen';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
const WorkflowLibraryModal = () => {
const { t } = useTranslation();
const { isOpen, onClose } = useWorkflowLibraryModalContext();
const workflowLibraryModal = useWorkflowLibraryModal();
return (
<Modal isOpen={isOpen} onClose={onClose} isCentered useInert={false}>
<Modal isOpen={workflowLibraryModal.isTrue} onClose={workflowLibraryModal.setFalse} isCentered useInert={false}>
<ModalOverlay />
<ModalContent w="80%" h="80%" minW="unset" minH="unset" maxW="1200px" maxH="664px">
<ModalHeader>{t('workflows.workflowLibrary')}</ModalHeader>

View File

@@ -1,4 +0,0 @@
import type { UseDisclosureReturn } from '@invoke-ai/ui-library';
import { createContext } from 'react';
export const WorkflowLibraryModalContext = createContext<UseDisclosureReturn | null>(null);

View File

@@ -1,10 +0,0 @@
import { WorkflowLibraryModalContext } from 'features/workflowLibrary/context/WorkflowLibraryModalContext';
import { useContext } from 'react';
export const useWorkflowLibraryModalContext = () => {
const context = useContext(WorkflowLibraryModalContext);
if (!context) {
throw new Error('useWorkflowLibraryContext must be used within a WorkflowLibraryContext.Provider');
}
return context;
};

View File

@@ -0,0 +1,3 @@
import { buildUseBoolean } from 'common/hooks/useBoolean';
export const [useWorkflowLibraryModal] = buildUseBoolean(false);