diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 19a2c9972e..93367181cf 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -305,6 +305,7 @@ "go": "Go", "image": "image", "imagesTab": "Images you’ve created and saved within Invoke.", + "imagesSettings": "Gallery Images Settings", "jump": "Jump", "loading": "Loading", "newestFirst": "Newest First", diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsListSortControls.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsListSortControls.tsx new file mode 100644 index 0000000000..431e0e8271 --- /dev/null +++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsListSortControls.tsx @@ -0,0 +1,88 @@ +import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui-library'; +import { + Combobox, + Flex, + FormControl, + FormLabel, +} from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { useCallback, useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { z } from 'zod'; +import { boardsListOrderByChanged, boardsListOrderDirChanged } from '../../store/gallerySlice'; +import { selectBoardsListOrderBy, selectBoardsListOrderDir } from '../../store/gallerySelectors'; + +const zOrderBy = z.enum(['created_at', 'board_name']); +type OrderBy = z.infer; +const isOrderBy = (v: unknown): v is OrderBy => zOrderBy.safeParse(v).success; + +const zDirection = z.enum(['ASC', 'DESC']); +type Direction = z.infer; +const isDirection = (v: unknown): v is Direction => zDirection.safeParse(v).success; + +export const BoardsListSortControls = () => { + const { t } = useTranslation(); + + const orderBy = useAppSelector(selectBoardsListOrderBy); + const direction = useAppSelector(selectBoardsListOrderDir); + + const ORDER_BY_OPTIONS: ComboboxOption[] = useMemo( + () => [ + { value: 'created_at', label: t('workflows.created') }, + { value: 'board_name', label: t('workflows.name') }, + ], + [t] + ); + + const DIRECTION_OPTIONS: ComboboxOption[] = useMemo( + () => [ + { value: 'ASC', label: t('workflows.ascending') }, + { value: 'DESC', label: t('workflows.descending') }, + ], + [t] + ); + + const dispatch = useAppDispatch(); + + const onChangeOrderBy = useCallback( + (v) => { + if (!isOrderBy(v?.value) || v.value === orderBy) { + return; + } + dispatch(boardsListOrderByChanged(v.value)); + }, + [orderBy, dispatch] + ); + const valueOrderBy = useMemo(() => { + const orderByValue = ORDER_BY_OPTIONS.find((o) => o.value === orderBy) || ORDER_BY_OPTIONS[0]; + console.log({orderByValue}) + return orderByValue + }, [orderBy, ORDER_BY_OPTIONS]); + + const onChangeDirection = useCallback( + (v) => { + if (!isDirection(v?.value) || v.value === direction) { + return; + } + dispatch(boardsListOrderDirChanged(v.value)); + }, + [direction, dispatch] + ); + const valueDirection = useMemo( + () => DIRECTION_OPTIONS.find((o) => o.value === direction), + [direction, DIRECTION_OPTIONS] + ); + + return ( + + + {t('common.orderBy')} + + + + {t('common.direction')} + + + + ); +}; diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsSettingsPopover.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsSettingsPopover.tsx index c748973495..8c1f9cc44f 100644 --- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsSettingsPopover.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsSettingsPopover.tsx @@ -1,10 +1,11 @@ -import { Flex, IconButton, Popover, PopoverBody, PopoverContent, PopoverTrigger } from '@invoke-ai/ui-library'; +import { Box, Divider, Flex, IconButton, Popover, PopoverBody, PopoverContent, PopoverTrigger } from '@invoke-ai/ui-library'; import BoardAutoAddSelect from 'features/gallery/components/Boards/BoardAutoAddSelect'; import AutoAssignBoardCheckbox from 'features/gallery/components/GallerySettingsPopover/AutoAssignBoardCheckbox'; import ShowArchivedBoardsCheckbox from 'features/gallery/components/GallerySettingsPopover/ShowArchivedBoardsCheckbox'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import { PiGearSixFill } from 'react-icons/pi'; +import { BoardsListSortControls } from './BoardsListSortControls'; const BoardsSettingsPopover = () => { const { t } = useTranslation(); @@ -27,6 +28,9 @@ const BoardsSettingsPopover = () => { + + + diff --git a/invokeai/frontend/web/src/features/gallery/components/GallerySettingsPopover/GallerySettingsPopover.tsx b/invokeai/frontend/web/src/features/gallery/components/GallerySettingsPopover/GallerySettingsPopover.tsx index d0529e77ce..a5d0861486 100644 --- a/invokeai/frontend/web/src/features/gallery/components/GallerySettingsPopover/GallerySettingsPopover.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/GallerySettingsPopover/GallerySettingsPopover.tsx @@ -18,8 +18,9 @@ const GallerySettingsPopover = () => { size="sm" variant="link" alignSelf="stretch" - aria-label={t('gallery.gallerySettings')} + aria-label={t('gallery.imagesSettings')} icon={} + tooltip={t('gallery.imagesSettings')} />