mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
(ui) update so that default list does not sort
This commit is contained in:
committed by
psychedelicious
parent
a28cabdf97
commit
ed88b096f3
@@ -1,19 +1,55 @@
|
||||
import { Button, Collapse, Flex, Icon, Text } from '@invoke-ai/ui-library';
|
||||
import { Button, Collapse, Flex, Icon, Spinner, Text } from '@invoke-ai/ui-library';
|
||||
import { EMPTY_ARRAY } from 'app/store/constants';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import { useCategorySections } from 'features/nodes/hooks/useCategorySections';
|
||||
import { selectWorkflowSearchTerm } from 'features/nodes/store/workflowSlice';
|
||||
import {
|
||||
selectWorkflowOrderBy,
|
||||
selectWorkflowOrderDirection,
|
||||
selectWorkflowSearchTerm,
|
||||
} from 'features/nodes/store/workflowSlice';
|
||||
import type { WorkflowCategory } from 'features/nodes/types/workflow';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiCaretDownBold } from 'react-icons/pi';
|
||||
import type { WorkflowRecordListItemDTO } from 'services/api/types';
|
||||
import { useListWorkflowsQuery } from 'services/api/endpoints/workflows';
|
||||
|
||||
import { WorkflowListItem } from './WorkflowListItem';
|
||||
|
||||
export const WorkflowList = ({ title, data }: { title: string; data: WorkflowRecordListItemDTO[] }) => {
|
||||
const { t } = useTranslation();
|
||||
export const WorkflowList = ({ category }: { category: WorkflowCategory }) => {
|
||||
const searchTerm = useAppSelector(selectWorkflowSearchTerm);
|
||||
const orderBy = useAppSelector(selectWorkflowOrderBy);
|
||||
const direction = useAppSelector(selectWorkflowOrderDirection);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { isOpen, onToggle } = useCategorySections(title);
|
||||
const queryArg = useMemo<Parameters<typeof useListWorkflowsQuery>[0]>(() => {
|
||||
if (category !== 'default') {
|
||||
return {
|
||||
order_by: orderBy,
|
||||
direction,
|
||||
category: category,
|
||||
};
|
||||
}
|
||||
return {
|
||||
order_by: 'name' as const,
|
||||
direction: 'ASC' as const,
|
||||
category: category,
|
||||
};
|
||||
}, [category, direction, orderBy]);
|
||||
|
||||
const { data, isLoading } = useListWorkflowsQuery(queryArg, {
|
||||
selectFromResult: ({ data, isLoading }) => {
|
||||
const filteredData =
|
||||
data?.items.filter((workflow) => workflow.name.toLowerCase().includes(searchTerm.toLowerCase())) || EMPTY_ARRAY;
|
||||
|
||||
return {
|
||||
data: filteredData,
|
||||
isLoading,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const { isOpen, onToggle } = useCategorySections(category);
|
||||
|
||||
return (
|
||||
<Flex flexDir="column">
|
||||
@@ -21,12 +57,16 @@ export const WorkflowList = ({ title, data }: { title: string; data: WorkflowRec
|
||||
<Flex gap={2} alignItems="center">
|
||||
<Icon boxSize={4} as={PiCaretDownBold} transform={isOpen ? undefined : 'rotate(-90deg)'} fill="base.500" />
|
||||
<Text fontSize="sm" fontWeight="semibold" userSelect="none" color="base.500">
|
||||
{title}
|
||||
{t(`workflows.${category}Workflows`)}
|
||||
</Text>
|
||||
</Flex>
|
||||
</Button>
|
||||
<Collapse in={isOpen}>
|
||||
{data.length ? (
|
||||
{isLoading ? (
|
||||
<Flex alignItems="center" justifyContent="center" p={20}>
|
||||
<Spinner />
|
||||
</Flex>
|
||||
) : data.length ? (
|
||||
data.map((workflow) => <WorkflowListItem workflow={workflow} key={workflow.workflow_id} />)
|
||||
) : (
|
||||
<IAINoContentFallback
|
||||
|
||||
@@ -1,88 +1,28 @@
|
||||
import { Flex, Spinner } from '@invoke-ai/ui-library';
|
||||
import { Flex } from '@invoke-ai/ui-library';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { EMPTY_ARRAY } from 'app/store/constants';
|
||||
import { $workflowCategories } from 'app/store/nanostores/workflowCategories';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectWorkflowOrderBy,
|
||||
selectWorkflowOrderDirection,
|
||||
selectWorkflowSearchTerm,
|
||||
} from 'features/nodes/store/workflowSlice';
|
||||
import UploadWorkflowButton from 'features/workflowLibrary/components/UploadWorkflowButton';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useListWorkflowsQuery } from 'services/api/endpoints/workflows';
|
||||
import type { WorkflowRecordListItemDTO } from 'services/api/types';
|
||||
|
||||
import { WorkflowList } from './WorkflowList';
|
||||
import WorkflowSearch from './WorkflowSearch';
|
||||
import { WorkflowSortControl } from './WorkflowSortControl';
|
||||
|
||||
export const WorkflowListMenu = () => {
|
||||
const searchTerm = useAppSelector(selectWorkflowSearchTerm);
|
||||
const orderBy = useAppSelector(selectWorkflowOrderBy);
|
||||
const direction = useAppSelector(selectWorkflowOrderDirection);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { data, isLoading } = useListWorkflowsQuery(
|
||||
{ order_by: orderBy, direction },
|
||||
{
|
||||
selectFromResult: ({ data, isLoading }) => {
|
||||
const filteredData =
|
||||
data?.items.filter((workflow) => workflow.name.toLowerCase().includes(searchTerm.toLowerCase())) ||
|
||||
EMPTY_ARRAY;
|
||||
|
||||
const groupedData = filteredData.reduce(
|
||||
(
|
||||
acc: {
|
||||
default: WorkflowRecordListItemDTO[];
|
||||
project: WorkflowRecordListItemDTO[];
|
||||
user: WorkflowRecordListItemDTO[];
|
||||
},
|
||||
workflow
|
||||
) => {
|
||||
if (workflow.category === 'default') {
|
||||
acc.default.push(workflow);
|
||||
} else if (workflow.category === 'project') {
|
||||
acc.project.push(workflow);
|
||||
} else {
|
||||
acc.user.push(workflow);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ default: [], project: [], user: [] }
|
||||
);
|
||||
|
||||
return {
|
||||
data: groupedData,
|
||||
isLoading,
|
||||
};
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const workflowCategories = useStore($workflowCategories);
|
||||
|
||||
return (
|
||||
<Flex flexDir="column" gap={2} padding={3} layerStyle="second" borderRadius="base">
|
||||
<Flex alignItems="center" gap={2} w="full" justifyContent="space-between">
|
||||
<WorkflowSearch />
|
||||
<Flex>
|
||||
<WorkflowSortControl />
|
||||
<UploadWorkflowButton />
|
||||
</Flex>
|
||||
|
||||
<WorkflowSortControl />
|
||||
|
||||
<UploadWorkflowButton />
|
||||
</Flex>
|
||||
|
||||
{isLoading ? (
|
||||
<Flex alignItems="center" justifyContent="center" p={20}>
|
||||
<Spinner />
|
||||
</Flex>
|
||||
) : (
|
||||
<>
|
||||
{workflowCategories.map((category) => (
|
||||
<WorkflowList key={category} title={t(`workflows.${category}Workflows`)} data={data[category]} />
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{workflowCategories.map((category) => (
|
||||
<WorkflowList key={category} category={category} />
|
||||
))}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
Tooltip,
|
||||
useDisclosure,
|
||||
} from '@invoke-ai/ui-library';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { $projectId } from 'app/store/nanostores/projectId';
|
||||
@@ -91,31 +92,39 @@ export const WorkflowSortControl = () => {
|
||||
[direction, DIRECTION_OPTIONS]
|
||||
);
|
||||
|
||||
const { isOpen, onToggle, onClose } = useDisclosure();
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger>
|
||||
<Tooltip label={`Sorting by ${valueOrderBy?.label} ${valueDirection?.label}`}>
|
||||
<IconButton
|
||||
aria-label="Sort Workflow Librar"
|
||||
icon={direction === 'ASC' ? <PiSortAscendingBold /> : <PiSortDescendingBold />}
|
||||
variant="ghost"
|
||||
/>
|
||||
</Tooltip>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<PopoverBody>
|
||||
<Flex flexDir="column" gap={4}>
|
||||
<FormControl orientation="horizontal" gap={1}>
|
||||
<FormLabel>{t('common.orderBy')}</FormLabel>
|
||||
<Combobox value={valueOrderBy} options={orderByOptions} onChange={onChangeOrderBy} />
|
||||
</FormControl>
|
||||
<FormControl orientation="horizontal" gap={1}>
|
||||
<FormLabel>{t('common.direction')}</FormLabel>
|
||||
<Combobox value={valueDirection} options={DIRECTION_OPTIONS} onChange={onChangeDirection} />
|
||||
</FormControl>
|
||||
</Flex>
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<>
|
||||
<Tooltip label={`Sorting by ${valueOrderBy?.label} ${valueDirection?.label}`}>
|
||||
<IconButton
|
||||
aria-label="Sort Workflow Librar"
|
||||
icon={direction === 'ASC' ? <PiSortAscendingBold /> : <PiSortDescendingBold />}
|
||||
variant="ghost"
|
||||
onClick={onToggle}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Popover placement="bottom" isOpen={isOpen} onClose={onClose} returnFocusOnClose={false} closeOnBlur={false}>
|
||||
<PopoverTrigger>
|
||||
<Flex></Flex>
|
||||
</PopoverTrigger>
|
||||
|
||||
<PopoverContent>
|
||||
<PopoverBody>
|
||||
<Flex flexDir="column" gap={4}>
|
||||
<FormControl orientation="horizontal" gap={1}>
|
||||
<FormLabel>{t('common.orderBy')}</FormLabel>
|
||||
<Combobox value={valueOrderBy} options={orderByOptions} onChange={onChangeOrderBy} />
|
||||
</FormControl>
|
||||
<FormControl orientation="horizontal" gap={1}>
|
||||
<FormLabel>{t('common.direction')}</FormLabel>
|
||||
<Combobox value={valueDirection} options={DIRECTION_OPTIONS} onChange={onChangeDirection} />
|
||||
</FormControl>
|
||||
</Flex>
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user