add option for custom star ui (#4530)

Co-authored-by: Mary Hipp <maryhipp@Marys-MacBook-Air.local>
This commit is contained in:
Mary Hipp Rogers 2023-09-13 16:48:10 -04:00 committed by GitHub
parent 0f0366f1f3
commit d989c7fa34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 71 additions and 13 deletions

View File

@ -18,6 +18,8 @@ import { usePreselectedImage } from '../../features/parameters/hooks/usePreselec
import AppErrorBoundaryFallback from './AppErrorBoundaryFallback'; import AppErrorBoundaryFallback from './AppErrorBoundaryFallback';
import GlobalHotkeys from './GlobalHotkeys'; import GlobalHotkeys from './GlobalHotkeys';
import Toaster from './Toaster'; import Toaster from './Toaster';
import { CustomStarUi } from '../../features/ui/store/uiTypes';
import { setCustomStarUi } from '../../features/ui/store/uiSlice';
const DEFAULT_CONFIG = {}; const DEFAULT_CONFIG = {};
@ -28,12 +30,14 @@ interface Props {
imageName: string; imageName: string;
action: 'sendToImg2Img' | 'sendToCanvas' | 'useAllParameters'; action: 'sendToImg2Img' | 'sendToCanvas' | 'useAllParameters';
}; };
customStarUi?: CustomStarUi;
} }
const App = ({ const App = ({
config = DEFAULT_CONFIG, config = DEFAULT_CONFIG,
headerComponent, headerComponent,
selectedImage, selectedImage,
customStarUi,
}: Props) => { }: Props) => {
const language = useAppSelector(languageSelector); const language = useAppSelector(languageSelector);
@ -57,6 +61,12 @@ const App = ({
} }
}, [dispatch, config, logger]); }, [dispatch, config, logger]);
useEffect(() => {
if (customStarUi) {
dispatch(setCustomStarUi(customStarUi));
}
}, [customStarUi, dispatch]);
useEffect(() => { useEffect(() => {
dispatch(appStarted()); dispatch(appStarted());
}, [dispatch]); }, [dispatch]);

View File

@ -15,6 +15,7 @@ import { socketMiddleware } from 'services/events/middleware';
import Loading from '../../common/components/Loading/Loading'; import Loading from '../../common/components/Loading/Loading';
import '../../i18n'; import '../../i18n';
import AppDndContext from '../../features/dnd/components/AppDndContext'; import AppDndContext from '../../features/dnd/components/AppDndContext';
import { CustomStarUi } from '../../features/ui/store/uiTypes';
const App = lazy(() => import('./App')); const App = lazy(() => import('./App'));
const ThemeLocaleProvider = lazy(() => import('./ThemeLocaleProvider')); const ThemeLocaleProvider = lazy(() => import('./ThemeLocaleProvider'));
@ -30,6 +31,7 @@ interface Props extends PropsWithChildren {
imageName: string; imageName: string;
action: 'sendToImg2Img' | 'sendToCanvas' | 'useAllParameters'; action: 'sendToImg2Img' | 'sendToCanvas' | 'useAllParameters';
}; };
customStarUi?: CustomStarUi;
} }
const InvokeAIUI = ({ const InvokeAIUI = ({
@ -40,6 +42,7 @@ const InvokeAIUI = ({
middleware, middleware,
projectId, projectId,
selectedImage, selectedImage,
customStarUi,
}: Props) => { }: Props) => {
useEffect(() => { useEffect(() => {
// configure API client token // configure API client token
@ -90,6 +93,7 @@ const InvokeAIUI = ({
config={config} config={config}
headerComponent={headerComponent} headerComponent={headerComponent}
selectedImage={selectedImage} selectedImage={selectedImage}
customStarUi={customStarUi}
/> />
</AppDndContext> </AppDndContext>
</ThemeLocaleProvider> </ThemeLocaleProvider>

View File

@ -12,10 +12,12 @@ import {
useStarImagesMutation, useStarImagesMutation,
useUnstarImagesMutation, useUnstarImagesMutation,
} from '../../../../services/api/endpoints/images'; } from '../../../../services/api/endpoints/images';
import { uiSelector } from '../../../ui/store/uiSelectors';
const MultipleSelectionMenuItems = () => { const MultipleSelectionMenuItems = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const selection = useAppSelector((state) => state.gallery.selection); const selection = useAppSelector((state) => state.gallery.selection);
const { customStarUi } = useAppSelector(uiSelector);
const [starImages] = useStarImagesMutation(); const [starImages] = useStarImagesMutation();
const [unstarImages] = useUnstarImagesMutation(); const [unstarImages] = useUnstarImagesMutation();
@ -49,15 +51,18 @@ const MultipleSelectionMenuItems = () => {
<> <>
{areAllStarred && ( {areAllStarred && (
<MenuItem <MenuItem
icon={<MdStarBorder />} icon={customStarUi ? customStarUi.on.icon : <MdStarBorder />}
onClickCapture={handleUnstarSelection} onClickCapture={handleUnstarSelection}
> >
Unstar All {customStarUi ? customStarUi.off.text : `Unstar All`}
</MenuItem> </MenuItem>
)} )}
{(areAllUnstarred || (!areAllStarred && !areAllUnstarred)) && ( {(areAllUnstarred || (!areAllStarred && !areAllUnstarred)) && (
<MenuItem icon={<MdStar />} onClickCapture={handleStarSelection}> <MenuItem
Star All icon={customStarUi ? customStarUi.on.icon : <MdStar />}
onClickCapture={handleStarSelection}
>
{customStarUi ? customStarUi.on.text : `Star All`}
</MenuItem> </MenuItem>
)} )}
<MenuItem icon={<FaFolder />} onClickCapture={handleChangeBoard}> <MenuItem icon={<FaFolder />} onClickCapture={handleChangeBoard}>

View File

@ -35,6 +35,7 @@ import { ImageDTO } from 'services/api/types';
import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions'; import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions';
import { workflowLoadRequested } from 'features/nodes/store/actions'; import { workflowLoadRequested } from 'features/nodes/store/actions';
import { configSelector } from '../../../system/store/configSelectors'; import { configSelector } from '../../../system/store/configSelectors';
import { uiSelector } from '../../../ui/store/uiSelectors';
type SingleSelectionMenuItemsProps = { type SingleSelectionMenuItemsProps = {
imageDTO: ImageDTO; imageDTO: ImageDTO;
@ -50,6 +51,7 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
const isCanvasEnabled = useFeatureStatus('unifiedCanvas').isFeatureEnabled; const isCanvasEnabled = useFeatureStatus('unifiedCanvas').isFeatureEnabled;
const { shouldFetchMetadataFromApi } = useAppSelector(configSelector); const { shouldFetchMetadataFromApi } = useAppSelector(configSelector);
const { customStarUi } = useAppSelector(uiSelector);
const { metadata, workflow, isLoading } = useGetImageMetadataFromFileQuery( const { metadata, workflow, isLoading } = useGetImageMetadataFromFileQuery(
{ image: imageDTO, shouldFetchMetadataFromApi }, { image: imageDTO, shouldFetchMetadataFromApi },
@ -225,12 +227,18 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
Change Board Change Board
</MenuItem> </MenuItem>
{imageDTO.starred ? ( {imageDTO.starred ? (
<MenuItem icon={<MdStar />} onClickCapture={handleUnstarImage}> <MenuItem
Unstar Image icon={customStarUi ? customStarUi.off.icon : <MdStar />}
onClickCapture={handleUnstarImage}
>
{customStarUi ? customStarUi.off.text : `Unstar Image`}
</MenuItem> </MenuItem>
) : ( ) : (
<MenuItem icon={<MdStarBorder />} onClickCapture={handleStarImage}> <MenuItem
Star Image icon={customStarUi ? customStarUi.on.icon : <MdStarBorder />}
onClickCapture={handleStarImage}
>
{customStarUi ? customStarUi.on.text : `Star Image`}
</MenuItem> </MenuItem>
)} )}
<MenuItem <MenuItem

View File

@ -18,6 +18,7 @@ import {
useUnstarImagesMutation, useUnstarImagesMutation,
} from 'services/api/endpoints/images'; } from 'services/api/endpoints/images';
import IAIDndImageIcon from '../../../../common/components/IAIDndImageIcon'; import IAIDndImageIcon from '../../../../common/components/IAIDndImageIcon';
import { uiSelector } from '../../../ui/store/uiSelectors';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
interface HoverableImageProps { interface HoverableImageProps {
@ -34,6 +35,8 @@ const GalleryImage = (props: HoverableImageProps) => {
const { handleClick, isSelected, selection, selectionCount } = const { handleClick, isSelected, selection, selectionCount } =
useMultiselect(imageDTO); useMultiselect(imageDTO);
const { customStarUi } = useAppSelector(uiSelector);
const handleDelete = useCallback( const handleDelete = useCallback(
(e: MouseEvent<HTMLButtonElement>) => { (e: MouseEvent<HTMLButtonElement>) => {
e.stopPropagation(); e.stopPropagation();
@ -91,12 +94,22 @@ const GalleryImage = (props: HoverableImageProps) => {
const starIcon = useMemo(() => { const starIcon = useMemo(() => {
if (imageDTO?.starred) { if (imageDTO?.starred) {
return <MdStar size="20" />; return customStarUi ? customStarUi.on.icon : <MdStar size="20" />;
} }
if (!imageDTO?.starred && isHovered) { if (!imageDTO?.starred && isHovered) {
return <MdStarBorder size="20" />; return customStarUi ? customStarUi.off.icon : <MdStarBorder size="20" />;
} }
}, [imageDTO?.starred, isHovered]); }, [imageDTO?.starred, isHovered, customStarUi]);
const starTooltip = useMemo(() => {
if (imageDTO?.starred) {
return customStarUi ? customStarUi.off.text : 'Unstar';
}
if (!imageDTO?.starred) {
return customStarUi ? customStarUi.on.text : 'Star';
}
return '';
}, [imageDTO?.starred, customStarUi]);
if (!imageDTO) { if (!imageDTO) {
return <IAIFillSkeleton />; return <IAIFillSkeleton />;
@ -131,7 +144,7 @@ const GalleryImage = (props: HoverableImageProps) => {
<IAIDndImageIcon <IAIDndImageIcon
onClick={toggleStarredState} onClick={toggleStarredState}
icon={starIcon} icon={starIcon}
tooltip={imageDTO.starred ? 'Unstar' : 'Star'} tooltip={starTooltip}
/> />
{isHovered && shift && ( {isHovered && shift && (

View File

@ -4,7 +4,7 @@ import { initialImageChanged } from 'features/parameters/store/generationSlice';
import { SchedulerParam } from 'features/parameters/types/parameterSchemas'; import { SchedulerParam } from 'features/parameters/types/parameterSchemas';
import { setActiveTabReducer } from './extraReducers'; import { setActiveTabReducer } from './extraReducers';
import { InvokeTabName } from './tabMap'; import { InvokeTabName } from './tabMap';
import { UIState } from './uiTypes'; import { CustomStarUi, UIState } from './uiTypes';
export const initialUIState: UIState = { export const initialUIState: UIState = {
activeTab: 0, activeTab: 0,
@ -19,6 +19,7 @@ export const initialUIState: UIState = {
favoriteSchedulers: [], favoriteSchedulers: [],
globalContextMenuCloseTrigger: 0, globalContextMenuCloseTrigger: 0,
panels: {}, panels: {},
customStarUi: undefined,
}; };
export const uiSlice = createSlice({ export const uiSlice = createSlice({
@ -70,6 +71,9 @@ export const uiSlice = createSlice({
) => { ) => {
state.panels[action.payload.name] = action.payload.value; state.panels[action.payload.name] = action.payload.value;
}, },
setCustomStarUi: (state, action: PayloadAction<CustomStarUi>) => {
state.customStarUi = action.payload;
},
}, },
extraReducers(builder) { extraReducers(builder) {
builder.addCase(initialImageChanged, (state) => { builder.addCase(initialImageChanged, (state) => {
@ -91,6 +95,7 @@ export const {
setShouldAutoChangeDimensions, setShouldAutoChangeDimensions,
contextMenusClosed, contextMenusClosed,
panelsChanged, panelsChanged,
setCustomStarUi,
} = uiSlice.actions; } = uiSlice.actions;
export default uiSlice.reducer; export default uiSlice.reducer;

View File

@ -1,3 +1,4 @@
import { MenuItemProps } from '@chakra-ui/react';
import { SchedulerParam } from 'features/parameters/types/parameterSchemas'; import { SchedulerParam } from 'features/parameters/types/parameterSchemas';
export type Coordinates = { export type Coordinates = {
@ -12,6 +13,17 @@ export type Dimensions = {
export type Rect = Coordinates & Dimensions; export type Rect = Coordinates & Dimensions;
export type CustomStarUi = {
on: {
icon: MenuItemProps['icon'];
text: string;
};
off: {
icon: MenuItemProps['icon'];
text: string;
};
};
export interface UIState { export interface UIState {
activeTab: number; activeTab: number;
shouldShowImageDetails: boolean; shouldShowImageDetails: boolean;
@ -25,4 +37,5 @@ export interface UIState {
favoriteSchedulers: SchedulerParam[]; favoriteSchedulers: SchedulerParam[];
globalContextMenuCloseTrigger: number; globalContextMenuCloseTrigger: number;
panels: Record<string, string>; panels: Record<string, string>;
customStarUi?: CustomStarUi;
} }