mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'main' into feat/install_docs_update
This commit is contained in:
commit
c003967eaa
@ -14,10 +14,12 @@ import { $openAPISchemaUrl } from 'app/store/nanostores/openAPISchemaUrl';
|
|||||||
import { $projectId } from 'app/store/nanostores/projectId';
|
import { $projectId } from 'app/store/nanostores/projectId';
|
||||||
import { $queueId, DEFAULT_QUEUE_ID } from 'app/store/nanostores/queueId';
|
import { $queueId, DEFAULT_QUEUE_ID } from 'app/store/nanostores/queueId';
|
||||||
import { $store } from 'app/store/nanostores/store';
|
import { $store } from 'app/store/nanostores/store';
|
||||||
|
import { $workflowCategories } from 'app/store/nanostores/workflowCategories';
|
||||||
import { createStore } from 'app/store/store';
|
import { createStore } from 'app/store/store';
|
||||||
import type { PartialAppConfig } from 'app/types/invokeai';
|
import type { PartialAppConfig } from 'app/types/invokeai';
|
||||||
import Loading from 'common/components/Loading/Loading';
|
import Loading from 'common/components/Loading/Loading';
|
||||||
import AppDndContext from 'features/dnd/components/AppDndContext';
|
import AppDndContext from 'features/dnd/components/AppDndContext';
|
||||||
|
import type { WorkflowCategory } from 'features/nodes/types/workflow';
|
||||||
import type { PropsWithChildren, ReactNode } from 'react';
|
import type { PropsWithChildren, ReactNode } from 'react';
|
||||||
import React, { lazy, memo, useEffect, useMemo } from 'react';
|
import React, { lazy, memo, useEffect, useMemo } from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
@ -45,6 +47,7 @@ interface Props extends PropsWithChildren {
|
|||||||
socketOptions?: Partial<ManagerOptions & SocketOptions>;
|
socketOptions?: Partial<ManagerOptions & SocketOptions>;
|
||||||
isDebugging?: boolean;
|
isDebugging?: boolean;
|
||||||
logo?: ReactNode;
|
logo?: ReactNode;
|
||||||
|
workflowCategories?: WorkflowCategory[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const InvokeAIUI = ({
|
const InvokeAIUI = ({
|
||||||
@ -62,6 +65,7 @@ const InvokeAIUI = ({
|
|||||||
socketOptions,
|
socketOptions,
|
||||||
isDebugging = false,
|
isDebugging = false,
|
||||||
logo,
|
logo,
|
||||||
|
workflowCategories,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// configure API client token
|
// configure API client token
|
||||||
@ -156,6 +160,16 @@ const InvokeAIUI = ({
|
|||||||
};
|
};
|
||||||
}, [logo]);
|
}, [logo]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (workflowCategories) {
|
||||||
|
$workflowCategories.set(workflowCategories);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
$workflowCategories.set([]);
|
||||||
|
};
|
||||||
|
}, [workflowCategories]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socketOptions) {
|
if (socketOptions) {
|
||||||
$socketOptions.set(socketOptions);
|
$socketOptions.set(socketOptions);
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
import type { WorkflowCategory } from 'features/nodes/types/workflow';
|
||||||
|
import { atom } from 'nanostores';
|
||||||
|
|
||||||
|
export const $workflowCategories = atom<WorkflowCategory[]>([
|
||||||
|
'user',
|
||||||
|
'default',
|
||||||
|
]);
|
@ -11,10 +11,10 @@ import {
|
|||||||
Input,
|
Input,
|
||||||
InputGroup,
|
InputGroup,
|
||||||
InputRightElement,
|
InputRightElement,
|
||||||
Spacer,
|
|
||||||
} from '@invoke-ai/ui';
|
} from '@invoke-ai/ui';
|
||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { $projectId } from 'app/store/nanostores/projectId';
|
import { $projectId } from 'app/store/nanostores/projectId';
|
||||||
|
import { $workflowCategories } from 'app/store/nanostores/workflowCategories';
|
||||||
import {
|
import {
|
||||||
IAINoContentFallback,
|
IAINoContentFallback,
|
||||||
IAINoContentFallbackWithSpinner,
|
IAINoContentFallbackWithSpinner,
|
||||||
@ -58,10 +58,13 @@ const DIRECTION_OPTIONS: ComboboxOption[] = [
|
|||||||
|
|
||||||
const WorkflowLibraryList = () => {
|
const WorkflowLibraryList = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [category, setCategory] = useState<WorkflowCategory>('user');
|
const workflowCategories = useStore($workflowCategories);
|
||||||
|
const [selectedCategory, setSelectedCategory] =
|
||||||
|
useState<WorkflowCategory>('user');
|
||||||
const [page, setPage] = useState(0);
|
const [page, setPage] = useState(0);
|
||||||
const [query, setQuery] = useState('');
|
const [query, setQuery] = useState('');
|
||||||
const projectId = useStore($projectId);
|
const projectId = useStore($projectId);
|
||||||
|
|
||||||
const orderByOptions = useMemo(() => {
|
const orderByOptions = useMemo(() => {
|
||||||
return projectId
|
return projectId
|
||||||
? ORDER_BY_OPTIONS.filter((option) => option.value !== 'opened_at')
|
? ORDER_BY_OPTIONS.filter((option) => option.value !== 'opened_at')
|
||||||
@ -75,13 +78,13 @@ const WorkflowLibraryList = () => {
|
|||||||
const [debouncedQuery] = useDebounce(query, 500);
|
const [debouncedQuery] = useDebounce(query, 500);
|
||||||
|
|
||||||
const queryArg = useMemo<Parameters<typeof useListWorkflowsQuery>[0]>(() => {
|
const queryArg = useMemo<Parameters<typeof useListWorkflowsQuery>[0]>(() => {
|
||||||
if (category !== 'default') {
|
if (selectedCategory !== 'default') {
|
||||||
return {
|
return {
|
||||||
page,
|
page,
|
||||||
per_page: PER_PAGE,
|
per_page: PER_PAGE,
|
||||||
order_by,
|
order_by,
|
||||||
direction,
|
direction,
|
||||||
category,
|
category: selectedCategory,
|
||||||
query: debouncedQuery,
|
query: debouncedQuery,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -90,10 +93,10 @@ const WorkflowLibraryList = () => {
|
|||||||
per_page: PER_PAGE,
|
per_page: PER_PAGE,
|
||||||
order_by: 'name' as const,
|
order_by: 'name' as const,
|
||||||
direction: 'ASC' as const,
|
direction: 'ASC' as const,
|
||||||
category,
|
category: selectedCategory,
|
||||||
query: debouncedQuery,
|
query: debouncedQuery,
|
||||||
};
|
};
|
||||||
}, [category, debouncedQuery, direction, order_by, page]);
|
}, [selectedCategory, debouncedQuery, direction, order_by, page]);
|
||||||
|
|
||||||
const { data, isLoading, isError, isFetching } =
|
const { data, isLoading, isError, isFetching } =
|
||||||
useListWorkflowsQuery(queryArg);
|
useListWorkflowsQuery(queryArg);
|
||||||
@ -154,43 +157,43 @@ const WorkflowLibraryList = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleSetCategory = useCallback((category: WorkflowCategory) => {
|
const handleSetCategory = useCallback((category: WorkflowCategory) => {
|
||||||
setCategory(category);
|
setSelectedCategory(category);
|
||||||
setPage(0);
|
setPage(0);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Flex gap={4} alignItems="center" h={10} flexShrink={0} flexGrow={0}>
|
<Flex
|
||||||
<ButtonGroup>
|
gap={4}
|
||||||
<Button
|
alignItems="center"
|
||||||
variant={category === 'user' ? undefined : 'ghost'}
|
h={16}
|
||||||
onClick={handleSetCategory.bind(null, 'user')}
|
flexShrink={0}
|
||||||
isChecked={category === 'user'}
|
flexGrow={0}
|
||||||
>
|
justifyContent="space-between"
|
||||||
{t('workflows.userWorkflows')}
|
>
|
||||||
</Button>
|
<ButtonGroup alignSelf="flex-end">
|
||||||
{projectId ? (
|
{workflowCategories.map((category) => (
|
||||||
<Button
|
<Button
|
||||||
variant={category === 'project' ? undefined : 'ghost'}
|
key={category}
|
||||||
onClick={handleSetCategory.bind(null, 'project')}
|
variant={selectedCategory === category ? undefined : 'ghost'}
|
||||||
isChecked={category === 'project'}
|
onClick={handleSetCategory.bind(null, category)}
|
||||||
|
isChecked={selectedCategory === category}
|
||||||
>
|
>
|
||||||
{t('workflows.projectWorkflows')}
|
{t(`workflows.${category}Workflows`)}
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
))}
|
||||||
<Button
|
|
||||||
variant={category === 'default' ? undefined : 'ghost'}
|
|
||||||
onClick={handleSetCategory.bind(null, 'default')}
|
|
||||||
isChecked={category === 'default'}
|
|
||||||
>
|
|
||||||
{t('workflows.defaultWorkflows')}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
<Spacer />
|
{selectedCategory !== 'default' && (
|
||||||
{category !== 'default' && (
|
|
||||||
<>
|
<>
|
||||||
<FormControl isDisabled={isFetching} w={64} minW={56}>
|
<FormControl
|
||||||
|
isDisabled={isFetching}
|
||||||
|
sx={{
|
||||||
|
flexDir: 'column',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
gap: 1,
|
||||||
|
maxW: 56,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<FormLabel>{t('common.orderBy')}</FormLabel>
|
<FormLabel>{t('common.orderBy')}</FormLabel>
|
||||||
<Combobox
|
<Combobox
|
||||||
value={valueOrderBy}
|
value={valueOrderBy}
|
||||||
@ -198,7 +201,15 @@ const WorkflowLibraryList = () => {
|
|||||||
onChange={onChangeOrderBy}
|
onChange={onChangeOrderBy}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl isDisabled={isFetching} w={64} minW={56}>
|
<FormControl
|
||||||
|
isDisabled={isFetching}
|
||||||
|
sx={{
|
||||||
|
flexDir: 'column',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
gap: 1,
|
||||||
|
maxW: 56,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<FormLabel>{t('common.direction')}</FormLabel>
|
<FormLabel>{t('common.direction')}</FormLabel>
|
||||||
<Combobox
|
<Combobox
|
||||||
value={valueDirection}
|
value={valueDirection}
|
||||||
@ -208,7 +219,7 @@ const WorkflowLibraryList = () => {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<InputGroup w="20rem">
|
<InputGroup w="20rem" alignSelf="flex-end">
|
||||||
<Input
|
<Input
|
||||||
placeholder={t('workflows.searchWorkflows')}
|
placeholder={t('workflows.searchWorkflows')}
|
||||||
value={query}
|
value={query}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user