diff --git a/src/components/SettingsHeader.tsx b/src/components/SettingsHeader.tsx index 8a2b00e..eece85c 100644 --- a/src/components/SettingsHeader.tsx +++ b/src/components/SettingsHeader.tsx @@ -3,6 +3,7 @@ import { Button, Group, Highlight, + Menu, Popover, Stack, Switch, @@ -10,7 +11,8 @@ import { } from '@mantine/core'; import { useCommonHooks } from 'hooks'; import { useState } from 'react'; -import { FiHelpCircle, FiLoader, FiPlus, FiX } from 'react-icons/fi'; +import { FaSort } from 'react-icons/fa'; +import { FiHelpCircle, FiPlus, FiX } from 'react-icons/fi'; import { actionIconClasses, buttonClasses, @@ -31,6 +33,8 @@ export function SettingsHeader({ searchPlaceholder, isLoading, setIsLoading, + sortBy, + setSortBy, }: { setDragging: undefined | ((dragging: boolean) => void); openModal: undefined | (() => void); @@ -45,6 +49,8 @@ export function SettingsHeader({ searchPlaceholder: string | undefined; isLoading: boolean; setIsLoading: (isLoading: boolean) => void; + sortBy: string; + setSortBy: undefined | ((sortBy: string) => void); }) { const { isMobile, theme } = useCommonHooks(); const [disabled, setDisabled] = useState(false); @@ -123,50 +129,141 @@ export function SettingsHeader({ )} {searchValue !== undefined && ( - setIsLoading(true)} - onChange={(value: any) => { - setSearchValue(value); - }} - style={{ - zIndex: 100, - }} - styles={ - theme.textShadowsEnabled - ? { - label: { boxShadow: '2px 2px var(--mantine-color-border-0)' }, - } - : undefined - } - rightSection={ - isLoading ? ( - - - - ) : ( - searchValue && ( + > + setIsLoading(true)} + onChange={(value: any) => { + setSearchValue(value); + }} + style={{ + zIndex: 100, + }} + styles={ + theme.textShadowsEnabled + ? { + label: { boxShadow: '2px 2px var(--mantine-color-border-0)' }, + } + : undefined + } + rightSection={ + isLoading ? ( setSearchValue('')} - > - - + /> + ) : ( + searchValue && ( + setSearchValue('')} + > + + + ) ) - ) - } - /> + } + /> + {setSortBy !== undefined && ( + + + + + + + + Sort By + { + setSortBy('A>Z'); + }} + style={{ + color: + sortBy === 'A>Z' + ? 'var(--mantine-color-background-0)' + : 'var(--mantine-color-primary-0)', + backgroundColor: + sortBy === 'A>Z' ? 'var(--mantine-color-primary-0)' : undefined, + }} + > + {'A>Z'} + + { + setSortBy('Z>A'); + }} + style={{ + color: + sortBy === 'Z>A' + ? 'var(--mantine-color-background-0)' + : 'var(--mantine-color-primary-0)', + backgroundColor: + sortBy === 'Z>A' ? 'var(--mantine-color-primary-0)' : undefined, + }} + > + {'Z>A'} + + { + setSortBy('Newest'); + }} + style={{ + color: + sortBy === 'Newest' + ? 'var(--mantine-color-background-0)' + : 'var(--mantine-color-primary-0)', + backgroundColor: + sortBy === 'Newest' ? 'var(--mantine-color-primary-0)' : undefined, + }} + > + {'Newest'} + + { + setSortBy('Oldest'); + }} + style={{ + color: + sortBy === 'Oldest' + ? 'var(--mantine-color-background-0)' + : 'var(--mantine-color-primary-0)', + backgroundColor: + sortBy === 'Oldest' ? 'var(--mantine-color-primary-0)' : undefined, + }} + > + {'Oldest'} + + { + setSortBy('Custom'); + }} + style={{ + color: + sortBy === 'Custom' + ? 'var(--mantine-color-background-0)' + : 'var(--mantine-color-primary-0)', + backgroundColor: + sortBy === 'Custom' ? 'var(--mantine-color-primary-0)' : undefined, + }} + > + {'Custom'} + + + + )} + )} {setDragging && ( (''); const [debouncedSearch] = useDebouncedValue(searchValue, 500); const form = useForm({ @@ -54,19 +56,41 @@ export function Applications() { const { data: applicationData, isFetching: applicationDataIsFetching } = useQueryAPI({ endpoint: appsEndpoint, }); - const applications: Application[] = - applicationData - ?.filter( - (a: Application) => - a.name.toLowerCase().includes((debouncedSearch as string).toLowerCase()) || - a.url.toLowerCase().includes((debouncedSearch as string).toLowerCase()) || - a.baseUrl.toLowerCase().includes((debouncedSearch as string).toLowerCase()), - ) - .sort((a: Application, b: Application) => (a.index > b.index ? 1 : -1)) || []; + const applications: Application[] = applicationData + ?.filter( + (a: Application) => + a.name.toLowerCase().includes((debouncedSearch as string).toLowerCase()) || + a.url.toLowerCase().includes((debouncedSearch as string).toLowerCase()) || + a.baseUrl.toLowerCase().includes((debouncedSearch as string).toLowerCase()), + ) + .sort((a: Application, b: Application) => { + if (!dragging) { + switch (sortBy) { + case 'A>Z': + return a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase() ? 1 : -1; + case 'Z>A': + return a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase() ? 1 : -1; + case 'Newest': + if (a.id && b.id) { + return a.id < b.id ? 1 : -1; + } + return -1; + case 'Oldest': + if (a.id && b.id) { + return a.id > b.id ? 1 : -1; + } + return -1; + case 'Custom': + return a.index > b.index ? 1 : -1; + default: + return 0; + } + } + return a.index > b.index ? 1 : -1; + }); const [applicationList, setApplicationList] = useState([]); const { isMobile, reorder, theme } = useCommonHooks(); const { mutateAsync } = useMutationAPI(); - const [dragging, setDragging] = useState(false); const [isOpen, setIsOpen] = useState(false); const [isLoading, setIsLoading] = useState(false); @@ -104,7 +128,7 @@ export function Applications() { useEffect(() => { if (applicationList.length > 0 && applicationList !== applications) { - mutateAsync({ + void mutateAsync({ method: 'PATCH', endpoint: appsOrderEndpoint, body: applicationList, @@ -114,7 +138,7 @@ export function Applications() { return ( 0 ? setDragging : undefined} + setDragging={applications?.length > 0 ? setDragging : undefined} openModal={openModal} title={'Applications'} tooltip={{ @@ -140,6 +164,8 @@ export function Applications() { searchPlaceholder={'Search Applications...'} isLoading={isLoading} setIsLoading={setIsLoading} + sortBy={sortBy} + setSortBy={setSortBy} /> {modalOpened && ( { - mutateAsync({ + void mutateAsync({ method: 'POST', endpoint: appsEndpoint, body: { ...values, - index: applications.length, + index: applications?.length, }, }); handleClose(); @@ -318,7 +344,7 @@ export function Applications() { size: 'xl', }} /> - {applications.length > 0 ? ( + {applications?.length > 0 ? ( {(provided) => ( { if (groupList.length > 0 && groupList !== groups) { - mutateAsync({ + void mutateAsync({ method: 'PATCH', endpoint: 'api/bookmarkCategoryOrder', body: groupList, @@ -129,7 +129,7 @@ export function Bookmarks() { body={
{ - mutateAsync({ + void mutateAsync({ method: 'POST', endpoint: categoriesEndpoint, body: { @@ -221,6 +221,8 @@ export function Bookmarks() { searchPlaceholder={'Search Bookmarks...'} isLoading={isLoading} setIsLoading={setIsLoading} + sortBy={''} + setSortBy={undefined} /> {dragging ? ( diff --git a/src/pages/settings/components/GuacamoleClients/GuacamoleClients.tsx b/src/pages/settings/components/GuacamoleClients/GuacamoleClients.tsx index c8e3e45..019e750 100644 --- a/src/pages/settings/components/GuacamoleClients/GuacamoleClients.tsx +++ b/src/pages/settings/components/GuacamoleClients/GuacamoleClients.tsx @@ -80,7 +80,7 @@ export function GuacamoleClients() { body={ { - mutateAsync({ + void mutateAsync({ method: 'POST', endpoint: endpoint, body: { ...values, enabled: 1 }, @@ -210,6 +210,8 @@ export function GuacamoleClients() { searchPlaceholder={'Search Clients...'} isLoading={isLoading} setIsLoading={setIsLoading} + sortBy={''} + setSortBy={undefined} /> { if (Object.keys(debounced).length) { - mutateAsync({ method: 'PATCH', endpoint: endpoint, body: debounced }); + void mutateAsync({ method: 'PATCH', endpoint: endpoint, body: debounced }); } }, [debounced]); @@ -82,6 +82,8 @@ export function Messages() { searchPlaceholder={'Search Messages...'} isLoading={isLoading} setIsLoading={setIsLoading} + sortBy={''} + setSortBy={undefined} /> {modalOpened && ( { - mutateAsync({ + void mutateAsync({ method: 'POST', endpoint: endpoint, body: { message: values.message }, diff --git a/src/pages/settings/components/Personalization/Personalization.tsx b/src/pages/settings/components/Personalization/Personalization.tsx index d7b81bd..42cb6b5 100644 --- a/src/pages/settings/components/Personalization/Personalization.tsx +++ b/src/pages/settings/components/Personalization/Personalization.tsx @@ -37,7 +37,7 @@ export function Personalization() { const { isMobile, theme } = useCommonHooks(); useEffect(() => { if (debounced && Object.keys(debounced).length) { - mutateAsync({ method: 'PATCH', endpoint: endpoint, body: debounced }); + void mutateAsync({ method: 'PATCH', endpoint: endpoint, body: debounced }); setUpdate(undefined); } }, [debounced]); @@ -87,6 +87,8 @@ export function Personalization() { searchPlaceholder={undefined} isLoading={false} setIsLoading={() => {}} + sortBy={''} + setSortBy={undefined} /> { - mutateAsync({ + void mutateAsync({ method: 'POST', endpoint: endpoint, body: values, @@ -281,6 +281,8 @@ export function SearchProviders() { searchPlaceholder={'Search Providers...'} isLoading={isLoading} setIsLoading={setIsLoading} + sortBy={''} + setSortBy={undefined} /> { - mutateAsync({ + void mutateAsync({ method: 'POST', endpoint: endpoint, body: values, @@ -151,6 +151,8 @@ export function WolClients() { searchPlaceholder={'Search Clients...'} isLoading={isLoading} setIsLoading={setIsLoading} + sortBy={''} + setSortBy={undefined} />