basic scan working and renders results

This commit is contained in:
Mary Hipp 2024-02-22 11:50:16 -05:00 committed by psychedelicious
parent a022aaf258
commit 5b66baa3ec
6 changed files with 143 additions and 3 deletions

View File

@ -7,7 +7,7 @@ import { useCallback, useMemo } from 'react';
import { RiSparklingFill } from 'react-icons/ri'; import { RiSparklingFill } from 'react-icons/ri';
import { useGetModelImportsQuery, usePruneModelImportsMutation } from 'services/api/endpoints/models'; import { useGetModelImportsQuery, usePruneModelImportsMutation } from 'services/api/endpoints/models';
import { ImportQueueModel } from '../ImportQueueModel'; import { ImportQueueModel } from './ImportQueueModel';
export const ImportQueue = () => { export const ImportQueue = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();

View File

@ -0,0 +1,5 @@
import { ScanModelsForm } from './ScanModelsForm';
export const ScanModels = () => {
return <ScanModelsForm />;
};

View File

@ -0,0 +1,54 @@
import { Flex, FormControl, FormLabel, Input, Button, FormErrorMessage, Divider } from '@invoke-ai/ui-library';
import { ChangeEventHandler, useCallback, useState } from 'react';
import { useLazyScanModelsQuery } from '../../../../../services/api/endpoints/models';
import { useTranslation } from 'react-i18next';
import { ScanModelsResults } from './ScanModelsResults';
export const ScanModelsForm = () => {
const [scanPath, setScanPath] = useState('');
const [errorMessage, setErrorMessage] = useState('');
const [results, setResults] = useState<string[] | undefined>();
const { t } = useTranslation();
const [_scanModels, { isLoading }] = useLazyScanModelsQuery();
const handleSubmitScan = useCallback(async () => {
_scanModels({ scan_path: scanPath })
.unwrap()
.then((result) => {
setResults(result);
})
.catch((error) => {
if (error) {
setErrorMessage(error.data.detail);
}
});
}, [scanPath]);
const handleSetScanPath: ChangeEventHandler<HTMLInputElement> = useCallback((e) => {
setScanPath(e.target.value);
setErrorMessage('');
}, []);
return (
<>
<FormControl isInvalid={!!errorMessage.length} w="full">
<Flex flexDir="column" w="full">
<Flex gap={2} alignItems="flex-end" justifyContent="space-between">
<Flex direction="column" w="full">
<FormLabel>{t('common.folder')}</FormLabel>
<Input value={scanPath} onChange={handleSetScanPath} />
</Flex>
<Button onClick={handleSubmitScan} isLoading={isLoading} isDisabled={scanPath.length === 0}>
{t('modelManager.scanFolder')}
</Button>
</Flex>
{!!errorMessage.length && <FormErrorMessage>{errorMessage}</FormErrorMessage>}
</Flex>
</FormControl>
{results && <ScanModelsResults results={results} />}
</>
);
};

View File

@ -0,0 +1,77 @@
import {
Text,
Flex,
Heading,
IconButton,
Input,
InputGroup,
InputRightElement,
Divider,
Box,
} from '@invoke-ai/ui-library';
import { t } from 'i18next';
import { ChangeEventHandler, useCallback, useMemo, useState } from 'react';
import { PiXBold } from 'react-icons/pi';
export const ScanModelsResults = ({ results }: { results: string[] }) => {
const [searchTerm, setSearchTerm] = useState('');
const [filteredResults, setFilteredResults] = useState(results);
const handleSearch: ChangeEventHandler<HTMLInputElement> = useCallback(
(e) => {
setSearchTerm(e.target.value);
setFilteredResults(
results.filter((result) => {
const modelName = result.split('\\').slice(-1)[0];
return modelName?.includes(e.target.value);
})
);
},
[results]
);
const clearSearch = useCallback(() => {
setSearchTerm('');
}, []);
return (
<>
<Divider mt={4} />
<Flex flexDir="column" gap={2} mt={4}>
<Flex justifyContent="space-between" alignItems="center" mb={4}>
<Heading fontSize="md" as="h4">
Scan Results
</Heading>
<InputGroup maxW="300px" size="xs">
<Input
placeholder={t('modelManager.search')}
value={searchTerm || ''}
data-testid="board-search-input"
onChange={handleSearch}
size="xs"
/>
{!!searchTerm?.length && (
<InputRightElement h="full" pe={2}>
<IconButton
size="sm"
variant="link"
aria-label={t('boards.clearSearch')}
icon={<PiXBold />}
onClick={clearSearch}
/>
</InputRightElement>
)}
</InputGroup>
</Flex>
{filteredResults.map((result) => (
<Flex key={result} fontSize="sm" flexDir="column">
<Text fontWeight="semibold">{result.split('\\').slice(-1)[0]}</Text>
<Text variant="subtext">{result}</Text>
</Flex>
))}
</Flex>
</>
);
};

View File

@ -2,6 +2,7 @@ import { Box, Divider, Heading, Tab, TabList, TabPanel, TabPanels, Tabs } from '
import { ImportQueue } from './AddModelPanel/ImportQueue'; import { ImportQueue } from './AddModelPanel/ImportQueue';
import { SimpleImport } from './AddModelPanel/SimpleImport'; import { SimpleImport } from './AddModelPanel/SimpleImport';
import { ScanModels } from './AddModelPanel/ScanModels/ScanModels';
export const ImportModels = () => { export const ImportModels = () => {
return ( return (
@ -9,7 +10,7 @@ export const ImportModels = () => {
<Box w="full" p={4}> <Box w="full" p={4}>
<Heading fontSize="xl">Add Model</Heading> <Heading fontSize="xl">Add Model</Heading>
</Box> </Box>
<Box layerStyle="second" borderRadius="base" w="full" h="100vh"> <Box layerStyle="second" borderRadius="base" w="full">
<Tabs variant="collapse"> <Tabs variant="collapse">
<TabList> <TabList>
<Tab>Simple</Tab> <Tab>Simple</Tab>
@ -21,7 +22,9 @@ export const ImportModels = () => {
<SimpleImport /> <SimpleImport />
</TabPanel> </TabPanel>
<TabPanel>Advanced Import Placeholder</TabPanel> <TabPanel>Advanced Import Placeholder</TabPanel>
<TabPanel>Scan Models Placeholder</TabPanel> <TabPanel>
<ScanModels />
</TabPanel>
</TabPanels> </TabPanels>
</Tabs> </Tabs>

View File

@ -349,6 +349,7 @@ export const {
useMergeMainModelsMutation, useMergeMainModelsMutation,
useSyncModelsMutation, useSyncModelsMutation,
useScanModelsQuery, useScanModelsQuery,
useLazyScanModelsQuery,
useGetCheckpointConfigsQuery, useGetCheckpointConfigsQuery,
useGetModelImportsQuery, useGetModelImportsQuery,
useGetModelMetadataQuery, useGetModelMetadataQuery,