Skip to content

Commit 2d1eedc

Browse files
feat(ui): on first load, if the selected library view has no workflows, switch to the first view that has workflows
1 parent 79f4472 commit 2d1eedc

File tree

6 files changed

+245
-174
lines changed

6 files changed

+245
-174
lines changed

invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowLibrary/WorkflowLibraryModal.tsx

Lines changed: 102 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,18 @@ import {
88
ModalHeader,
99
ModalOverlay,
1010
} from '@invoke-ai/ui-library';
11+
import { useStore } from '@nanostores/react';
12+
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
13+
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
1114
import { useWorkflowLibraryModal } from 'features/nodes/store/workflowLibraryModal';
12-
import { memo } from 'react';
15+
import {
16+
$workflowLibraryCategoriesOptions,
17+
selectWorkflowLibraryView,
18+
workflowLibraryViewChanged,
19+
} from 'features/nodes/store/workflowLibrarySlice';
20+
import { memo, useEffect, useMemo, useState } from 'react';
1321
import { useTranslation } from 'react-i18next';
22+
import { useGetCountsByCategoryQuery } from 'services/api/endpoints/workflows';
1423

1524
import { WorkflowLibrarySideNav } from './WorkflowLibrarySideNav';
1625
import { WorkflowLibraryTopNav } from './WorkflowLibraryTopNav';
@@ -19,6 +28,7 @@ import { WorkflowList } from './WorkflowList';
1928
export const WorkflowLibraryModal = memo(() => {
2029
const { t } = useTranslation();
2130
const workflowLibraryModal = useWorkflowLibraryModal();
31+
const didSync = useSyncInitialWorkflowLibraryCategories();
2232
return (
2333
<Modal isOpen={workflowLibraryModal.isOpen} onClose={workflowLibraryModal.close} isCentered>
2434
<ModalOverlay />
@@ -31,18 +41,102 @@ export const WorkflowLibraryModal = memo(() => {
3141
<ModalHeader>{t('workflows.workflowLibrary')}</ModalHeader>
3242
<ModalCloseButton />
3343
<ModalBody pb={6}>
34-
<Flex gap={4} h="100%">
35-
<WorkflowLibrarySideNav />
36-
<Divider orientation="vertical" />
37-
<Flex flexDir="column" flex={1} gap={4}>
38-
<WorkflowLibraryTopNav />
39-
<WorkflowList />
44+
{didSync && (
45+
<Flex gap={4} h="100%">
46+
<WorkflowLibrarySideNav />
47+
<Divider orientation="vertical" />
48+
<Flex flexDir="column" flex={1} gap={4}>
49+
<WorkflowLibraryTopNav />
50+
<WorkflowList />
51+
</Flex>
4052
</Flex>
41-
</Flex>
53+
)}
54+
{!didSync && <IAINoContentFallback label={t('workflows.loading')} icon={null} />}
4255
</ModalBody>
4356
</ModalContent>
4457
</Modal>
4558
);
4659
});
4760

4861
WorkflowLibraryModal.displayName = 'WorkflowLibraryModal';
62+
63+
/**
64+
* On first app load, if the user's selected view has no workflows, switches to the next available view.
65+
*/
66+
const useSyncInitialWorkflowLibraryCategories = () => {
67+
const dispatch = useAppDispatch();
68+
const view = useAppSelector(selectWorkflowLibraryView);
69+
const categoryOptions = useStore($workflowLibraryCategoriesOptions);
70+
const [didSync, setDidSync] = useState(false);
71+
const recentWorkflowsCountQueryArg = useMemo(
72+
() =>
73+
({
74+
categories: ['user', 'project', 'default'],
75+
has_been_opened: true,
76+
}) satisfies Parameters<typeof useGetCountsByCategoryQuery>[0],
77+
[]
78+
);
79+
const yourWorkflowsCountQueryArg = useMemo(
80+
() =>
81+
({
82+
categories: ['user', 'project'],
83+
}) satisfies Parameters<typeof useGetCountsByCategoryQuery>[0],
84+
[]
85+
);
86+
const queryOptions = useMemo(
87+
() =>
88+
({
89+
selectFromResult: ({ data, isLoading }) => {
90+
if (!data) {
91+
return { count: 0, isLoading: true };
92+
}
93+
return {
94+
count: Object.values(data).reduce((acc, count) => acc + count, 0),
95+
isLoading,
96+
};
97+
},
98+
}) satisfies Parameters<typeof useGetCountsByCategoryQuery>[1],
99+
[]
100+
);
101+
102+
const { count: recentWorkflowsCount, isLoading: isLoadingRecentWorkflowsCount } = useGetCountsByCategoryQuery(
103+
recentWorkflowsCountQueryArg,
104+
queryOptions
105+
);
106+
const { count: yourWorkflowsCount, isLoading: isLoadingYourWorkflowsCount } = useGetCountsByCategoryQuery(
107+
yourWorkflowsCountQueryArg,
108+
queryOptions
109+
);
110+
111+
useEffect(() => {
112+
if (didSync || isLoadingRecentWorkflowsCount || isLoadingYourWorkflowsCount) {
113+
return;
114+
}
115+
// If the user's selected view has no workflows, switch to the next available view
116+
if (recentWorkflowsCount === 0 && view === 'recent') {
117+
if (yourWorkflowsCount > 0) {
118+
dispatch(workflowLibraryViewChanged('yours'));
119+
} else {
120+
dispatch(workflowLibraryViewChanged('defaults'));
121+
}
122+
} else if (yourWorkflowsCount === 0 && (view === 'yours' || view === 'shared' || view === 'private')) {
123+
if (recentWorkflowsCount > 0) {
124+
dispatch(workflowLibraryViewChanged('recent'));
125+
} else {
126+
dispatch(workflowLibraryViewChanged('defaults'));
127+
}
128+
}
129+
setDidSync(true);
130+
}, [
131+
categoryOptions,
132+
didSync,
133+
dispatch,
134+
isLoadingRecentWorkflowsCount,
135+
isLoadingYourWorkflowsCount,
136+
recentWorkflowsCount,
137+
view,
138+
yourWorkflowsCount,
139+
]);
140+
141+
return didSync;
142+
};

0 commit comments

Comments
 (0)