From 50fec41aba87dcbfffcc8ada56014a96c4e0e46f Mon Sep 17 00:00:00 2001 From: Sean Edmunds Date: Fri, 21 Mar 2025 11:05:01 -0500 Subject: [PATCH] Search Provider settings updates --- .../Search/DebouncedSearchProvider.tsx | 169 ++++++++++++ .../Search/SearchProviderSettingsItem.tsx | 26 ++ .../components/Search/SearchProviders.tsx | 246 ++++++++++++++++-- .../settings/components/WoL/WolClients.tsx | 14 +- 4 files changed, 426 insertions(+), 29 deletions(-) create mode 100644 src/pages/settings/components/Search/DebouncedSearchProvider.tsx create mode 100644 src/pages/settings/components/Search/SearchProviderSettingsItem.tsx diff --git a/src/pages/settings/components/Search/DebouncedSearchProvider.tsx b/src/pages/settings/components/Search/DebouncedSearchProvider.tsx new file mode 100644 index 0000000..e27e195 --- /dev/null +++ b/src/pages/settings/components/Search/DebouncedSearchProvider.tsx @@ -0,0 +1,169 @@ +import { + ActionIcon, + Button, + Card, + Group, + Modal, + Stack, + Text, + TextInput, + Tooltip, +} from '@mantine/core'; +import { useDebouncedValue, useDisclosure } from '@mantine/hooks'; +import { IconTrash } from '@tabler/icons-react'; +import { useCommonHooks, useMutationAPI } from 'hooks'; +import { useEffect, useState } from 'react'; +import { cardClasses, modalClasses, textInputClasses } from 'styles'; + +function DebouncedSearchProvider({ searchProvider, handleDelete }: any) { + const { theme } = useCommonHooks(); + const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); + const { mutateAsync } = useMutationAPI(); + + const [provider, setProvider] = useState(searchProvider); + const [update, setUpdate] = useState({}); + const [debounced] = useDebouncedValue(update, 1000); + + useEffect(() => { + if (Object.keys(debounced).length) { + mutateAsync({ method: 'PATCH', endpoint: 'api/providers', body: debounced }); + } + }, [debounced]); + + useEffect(() => { + if (update !== provider && Object.keys(update).length) { + setProvider(update); + } + }, [update]); + + return ( + + { + closeModal(); + }} + style={{ + '--color-text-pri': theme.primaryColor, + '--color-text-acc': theme.accentColor, + '--color-background': theme.backgroundColor, + '--color-border': theme.borderColor, + '--color-search-background': theme.searchColor, + '--image-background': `url(${theme.backgroundImage})`, + }} + closeOnEscape + closeOnClickOutside + > + + + + Delete Client + + + + + Are you sure you want to delete this Search Provider? + {`"${provider.name}"`} + This action cannot be undone! + + + + + + + + + + { + openModal(); + }} + > + + + + + + { + setUpdate({ + ...provider, + name: event.target.value, + }); + }} + /> + { + setUpdate({ + ...provider, + prefix: event.target.value, + }); + }} + /> + + { + setUpdate({ + ...provider, + url: event.target.value, + }); + }} + /> + + + ); +} + +export default DebouncedSearchProvider; diff --git a/src/pages/settings/components/Search/SearchProviderSettingsItem.tsx b/src/pages/settings/components/Search/SearchProviderSettingsItem.tsx new file mode 100644 index 0000000..72c93ff --- /dev/null +++ b/src/pages/settings/components/Search/SearchProviderSettingsItem.tsx @@ -0,0 +1,26 @@ +import { Card, Stack, Text } from '@mantine/core'; +import HintItem from 'components/HelpModal/HintItem'; +import { cardClasses } from 'styles'; + +function SearchProviderSettingsItem({ provider }: any) { + return ( + + + + + {provider.url} + + + + ); +} + +export default SearchProviderSettingsItem; diff --git a/src/pages/settings/components/Search/SearchProviders.tsx b/src/pages/settings/components/Search/SearchProviders.tsx index 56f3546..5d3d9ff 100644 --- a/src/pages/settings/components/Search/SearchProviders.tsx +++ b/src/pages/settings/components/Search/SearchProviders.tsx @@ -1,8 +1,31 @@ -import { Stack, Text } from '@mantine/core'; -import { DataTable, SearchProviderColumns } from 'components'; -import { useQueryAPI } from 'hooks'; +import { + ActionIcon, + Box, + Button, + Divider, + Grid, + GridCol, + Group, + Highlight, + Modal, + Popover, + Stack, + Text, + TextInput, +} from '@mantine/core'; +import { useDebouncedValue, useDisclosure } from '@mantine/hooks'; +import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks'; import { useEffect, useState } from 'react'; -import { textClasses } from 'styles'; +import { FiHelpCircle, FiPlus } from 'react-icons/fi'; +import { + actionIconClasses, + buttonClasses, + modalClasses, + textClasses, + textInputClasses, +} from 'styles'; +import DebouncedSearchProvider from './DebouncedSearchProvider'; +import SearchProviderSettingsItem from './SearchProviderSettingsItem'; const SearchProviderSettings = () => { const endpoint = 'api/providers'; @@ -15,26 +38,213 @@ const SearchProviderSettings = () => { endpoint: endpoint, }); const [providerData, setProviderData] = useState([]); - + const { theme } = useCommonHooks(); + const { mutateAsync } = useMutationAPI(); + const [newProvider, setNewProvider] = useState({}); + const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); + const [searchValue, setSearchValue] = useState(''); + const [debouncedSearch] = useDebouncedValue(searchValue, 500); + const handleDelete = (application: any) => { + mutateAsync({ method: 'DELETE', endpoint: endpoint, body: application }); + }; useEffect(() => { if (providers && providersIsFetched) { - setProviderData(providers); + setProviderData( + providers.filter((a: any) => + a.name.toLowerCase().includes(debouncedSearch.toLowerCase()), + ), + ); } - }, [providers, providersIsFetched]); + }, [providers, providersIsFetched, debouncedSearch]); return ( - - Search Providers - - + { + closeModal(); + }} + style={{ + '--color-text-pri': theme.primaryColor, + '--color-text-acc': theme.accentColor, + '--color-background': theme.backgroundColor, + '--color-border': theme.borderColor, + '--color-search-background': theme.searchColor, + '--image-background': `url(${theme.backgroundImage})`, + }} + closeOnEscape + closeOnClickOutside + > + + + + Add a new application + + + + + + + { + setNewProvider({ + ...newProvider, + name: event.target.value, + }); + }} + /> + { + setNewProvider({ + ...newProvider, + prefix: event.target.value, + }); + }} + /> + + { + setNewProvider({ + ...newProvider, + url: event.target.value, + }); + }} + /> + + + + + + + + + + + + + Search Providers + + + + + + + + + + + {'Search providers and shortcuts can be configured here.'} + + + {'Providers can be used in the search bar.'} + + + + + + { + setSearchValue(event.target.value); + }} + /> + + + + {providerData?.map((provider: any) => ( + + + + { + e.stopPropagation(); + }} + > + + + + + + + + + ))} + + ); }; diff --git a/src/pages/settings/components/WoL/WolClients.tsx b/src/pages/settings/components/WoL/WolClients.tsx index 77a3082..d3a3ce9 100644 --- a/src/pages/settings/components/WoL/WolClients.tsx +++ b/src/pages/settings/components/WoL/WolClients.tsx @@ -29,23 +29,15 @@ import WolClientSettingsItem from './WolClientSettingsItem'; const WolClientSettings = () => { const endpoint = 'api/wolClients'; - const { - data: wolClientsData, - isFetched: wolClientsIsFetched, - isFetching: wolClientsIsFetching, - isLoading: wolClientsIsLoading, - } = useQueryAPI({ + const { data: wolClientsData, isFetched: wolClientsIsFetched } = useQueryAPI({ endpoint: endpoint, }); const [wolClients, setWolClients] = useState([]); const { mutateAsync } = useMutationAPI(); const { theme } = useCommonHooks(); const [newWolClient, setNewWolClient] = useState({ - name: '', - url: '', - icon: '', - baseUrl: '', - filterName: '', + hostname: '', + macAddress: '', }); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const [searchValue, setSearchValue] = useState('');