Skip to content

Commit 4eeb3dd

Browse files
Copilotlstein
andcommitted
Add expandable file list to orphaned models dialog
Co-authored-by: lstein <111189+lstein@users.noreply.github.com>
1 parent f96f421 commit 4eeb3dd

File tree

1 file changed

+54
-9
lines changed

1 file changed

+54
-9
lines changed

invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/SyncModelsDialog.tsx

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import {
22
Button,
33
Checkbox,
4+
Collapse,
45
Flex,
56
Heading,
7+
IconButton,
68
Modal,
79
ModalBody,
810
ModalCloseButton,
@@ -16,6 +18,7 @@ import {
1618
} from '@invoke-ai/ui-library';
1719
import { memo, useCallback, useEffect, useState } from 'react';
1820
import { useTranslation } from 'react-i18next';
21+
import { PiCaretDownBold, PiCaretRightBold } from 'react-icons/pi';
1922
import { useDeleteOrphanedModelsMutation, useGetOrphanedModelsQuery } from 'services/api/endpoints/models';
2023

2124
type OrphanedModel = {
@@ -38,6 +41,7 @@ export const SyncModelsDialog = memo(({ isOpen, onClose }: SyncModelsDialogProps
3841

3942
const [selectedModels, setSelectedModels] = useState<Set<string>>(new Set());
4043
const [selectAll, setSelectAll] = useState(true);
44+
const [expandedModels, setExpandedModels] = useState<Set<string>>(new Set());
4145

4246
// Initialize selected models when data loads
4347
useEffect(() => {
@@ -85,6 +89,18 @@ export const SyncModelsDialog = memo(({ isOpen, onClose }: SyncModelsDialogProps
8589
}
8690
}, [selectAll, orphanedModels]);
8791

92+
const handleToggleExpanded = useCallback((path: string) => {
93+
setExpandedModels((prev) => {
94+
const next = new Set(prev);
95+
if (next.has(path)) {
96+
next.delete(path);
97+
} else {
98+
next.add(path);
99+
}
100+
return next;
101+
});
102+
}, []);
103+
88104
const handleDelete = useCallback(async () => {
89105
try {
90106
const result = await deleteOrphanedModels({ paths: Array.from(selectedModels) }).unwrap();
@@ -202,19 +218,48 @@ export const SyncModelsDialog = memo(({ isOpen, onClose }: SyncModelsDialogProps
202218
bg="base.750"
203219
>
204220
<Flex justifyContent="space-between" alignItems="center">
205-
<Checkbox
206-
isChecked={selectedModels.has(model.path)}
207-
onChange={() => handleToggleModel(model.path)}
208-
>
209-
<Text fontWeight="semibold">{model.path}</Text>
210-
</Checkbox>
221+
<Flex alignItems="center" gap={2} flex={1}>
222+
<IconButton
223+
aria-label={expandedModels.has(model.path) ? 'Collapse' : 'Expand'}
224+
icon={expandedModels.has(model.path) ? <PiCaretDownBold /> : <PiCaretRightBold />}
225+
size="xs"
226+
variant="ghost"
227+
onClick={() => handleToggleExpanded(model.path)}
228+
/>
229+
<Checkbox
230+
isChecked={selectedModels.has(model.path)}
231+
onChange={() => handleToggleModel(model.path)}
232+
>
233+
<Text fontWeight="semibold">{model.path}</Text>
234+
</Checkbox>
235+
</Flex>
211236
<Text fontSize="sm" color="base.400">
212237
{formatSize(model.size_bytes)}
213238
</Text>
214239
</Flex>
215-
<Text fontSize="sm" color="base.400">
216-
{t('modelManager.filesCount', { count: model.files.length })}
217-
</Text>
240+
<Flex justifyContent="space-between" alignItems="center">
241+
<Text fontSize="sm" color="base.400">
242+
{t('modelManager.filesCount', { count: model.files.length })}
243+
</Text>
244+
</Flex>
245+
<Collapse in={expandedModels.has(model.path)}>
246+
<Flex
247+
flexDir="column"
248+
gap={1}
249+
mt={2}
250+
p={2}
251+
bg="base.800"
252+
borderRadius="md"
253+
maxH="200px"
254+
overflowY="auto"
255+
>
256+
{model.files.map((file) => (
257+
<Text key={file} fontSize="xs" color="base.300" fontFamily="mono">
258+
{file}
259+
</Text>
260+
))}
261+
</Flex>
262+
</Collapse>
218263
</Flex>
219264
))}
220265
</Flex>

0 commit comments

Comments
 (0)