diff --git a/src/hooks/useAPI.tsx b/src/hooks/useAPI.tsx index 0a5e350..010e1e0 100644 --- a/src/hooks/useAPI.tsx +++ b/src/hooks/useAPI.tsx @@ -139,8 +139,6 @@ export function useMutationAPI() { queryClient.refetchQueries({ queryKey: ['GET', 'api/providers/default'] }); endpoint === 'api/personalData' && queryClient.refetchQueries({ queryKey: ['GET', 'api/personalData'] }); - queryClient.refetchQueries({ queryKey: ['GET', 'api/wolEnabled'] }); - queryClient.refetchQueries({ queryKey: ['GET', 'api/guacamoleEnabled'] }); }, }); } diff --git a/src/pages/homepage/components/Applications/Applications.tsx b/src/pages/homepage/components/Applications/Applications.tsx index ae6abe1..5776f65 100644 --- a/src/pages/homepage/components/Applications/Applications.tsx +++ b/src/pages/homepage/components/Applications/Applications.tsx @@ -9,7 +9,7 @@ function Applications({ contentType }: { contentType: string[] }) { endpoint: 'api/enabledApplications', }); const { appSort, appDensity, appScale, theme, textShadowStyle } = useCommonHooks(); - const applications = applicationData + const applications: Application[] = applicationData ?.sort((a: Application, b: Application) => { switch (appSort) { case 'A>Z': diff --git a/src/pages/homepage/components/Bookmarks/Bookmarks.tsx b/src/pages/homepage/components/Bookmarks/Bookmarks.tsx index 99cb7d8..cdca2d1 100644 --- a/src/pages/homepage/components/Bookmarks/Bookmarks.tsx +++ b/src/pages/homepage/components/Bookmarks/Bookmarks.tsx @@ -13,12 +13,12 @@ function Bookmarks({ contentType }: { contentType: string[] }) { }); const { bookmarkSort, bookmarkDensity, bookmarkScale, theme, textShadowStyle } = useCommonHooks(); - const groupList = groupData?.map((category: BookmarkGroup) => { + const groupList: BookmarkGroup[] = groupData?.map((category: BookmarkGroup) => { return category; }); - const bookmarks = bookmarkData || []; - const groups = groupList - ?.sort((a: BookmarkGroup, b: BookmarkGroup) => { + const bookmarks: Bookmark[] = bookmarkData || []; + const groups: BookmarkGroup[] = groupList + ?.toSorted((a: BookmarkGroup, b: BookmarkGroup) => { switch (bookmarkSort) { case 'A>Z': return a.categoryName.toLocaleLowerCase() > b.categoryName.toLocaleLowerCase() diff --git a/src/pages/homepage/components/Search/Search.tsx b/src/pages/homepage/components/Search/Search.tsx index 97a9543..5a69ca9 100644 --- a/src/pages/homepage/components/Search/Search.tsx +++ b/src/pages/homepage/components/Search/Search.tsx @@ -28,7 +28,7 @@ import type { import RecommendedApplications from './components/RecommendedApplications'; import RecommendedBookmarks from './components/RecommendedBookmarks'; import RecommendedClients from './components/RecommendedClients'; -import SearchSelectItem from './components/SearchSelectItem'; +import RenderItem from './components/RenderItem'; export default function Search({ current, @@ -47,9 +47,6 @@ export default function Search({ position: string; personal: PersonalData; }) { - const { ref, height } = useElementSize(); - const allIcons: any = { ...fa6, ...vsc, ...si }; - const searchEndpoint = 'api/searchHistory'; const { isMobile, urlPattern, @@ -72,6 +69,12 @@ export default function Search({ defaultProviderIcon, setDefaultProviderIcon, } = useCommonHooks(); + const { ref, height } = useElementSize(); + const { mutateAsync } = useMutationAPI(); + const allIcons: any = { ...fa6, ...vsc, ...si }; + const Icon = allIcons[providerIcon]; + const searchEndpoint = 'api/searchHistory'; + const { data: applicationData } = useQueryAPI({ endpoint: 'api/enabledApplications', }); @@ -94,8 +97,14 @@ export default function Search({ const { data: historyData, isFetched: historyDataIsFetched } = useQueryAPI({ endpoint: searchEndpoint, }); + const applications: Application[] = applicationData || []; - const filteredApplications = applications?.filter((app: Application) => + const providers: Provider[] = providerData || []; + const guacamoleHost: string = guacamoleHostData?.[0]?.guacamoleHost; + const guacamoleClients: GuacamoleClient[] = guacamoleClientData || []; + const searchHistory: SearchHistoryItem[] = historyData || []; + + const filteredApplications: Application[] = applications?.filter((app: Application) => app.name.toLowerCase().includes((searchValue as string).substring(1).toLowerCase()), ); const bookmarks: Bookmark[] = @@ -114,26 +123,23 @@ export default function Search({ bookmark.enabled === 1 && bookmark.name.toLowerCase().includes((searchValue as string).toLowerCase()), ) || []; - const providers = providerData || []; - const guacamoleHost = guacamoleHostData?.[0]?.guacamoleHost; - const guacamoleClients = guacamoleClientData || []; - const filteredGuacamoleClients = + + const filteredGuacamoleClients: GuacamoleClient[] = guacamoleClients.filter((client: GuacamoleClient) => client.clientName .toLowerCase() .includes((searchValue as string).substring(1).toLowerCase()), ) || []; - const searchHistory = historyData || []; + const [filteredHistory, setFilteredHistory] = useState([]); - const { mutateAsync } = useMutationAPI(); - const [providerModalOpened, { open: openProviderModal, close: closeProviderModal }] = - useDisclosure(false); - const [dropdownOpened, { open: openDropdown, close: closeDropdown }] = useDisclosure(); - const [listIndex, setListIndex] = useState(-1); const [placeholderValue, setPlaceholderValue] = useState(''); + const [listIndex, setListIndex] = useState(-1); const [value, setValue] = useState(0); const [historyMultiplier, setHistoryMultiplier] = useState(1); - const Icon = allIcons[providerIcon]; + + const [dropdownOpened, { open: openDropdown, close: closeDropdown }] = useDisclosure(); + const [providerModalOpened, { open: openProviderModal, close: closeProviderModal }] = + useDisclosure(false); const handleResetSearch = () => { setSearchValue(''); @@ -143,21 +149,6 @@ export default function Search({ setProviderURL(defaultProviderURL); }; - const handleSearchHistoryItem = ({ option }: { option: SearchHistoryItem }) => { - const url = - providerData.find((provider: Provider) => provider.prefix === option.prefix)?.url ?? - defaultProviderURL; - open(`${url}${option.searchTerm}`, '_self'); - }; - - const handleAppLaunchItem = ({ option }: { option: any }) => { - const validUrl = - option.url.startsWith('http://') || option.url.startsWith('https://') - ? option.url - : `http://${option.url}`; - open(validUrl, '_self'); - }; - const handleGuacamoleClientLaunchItem = ({ option }: { option: any }) => { const validUrl = `${guacamoleHost}/#/client/${option.clientIdentifier}`; open(validUrl, '_self'); @@ -324,7 +315,7 @@ export default function Search({ setProviderPrefix('/g'); setProviderIcon('FaGoogle'); } else if (item.target.value.startsWith('/')) { - const provider = providers?.find( + const provider: Provider | undefined = providers?.find( (p: Provider) => p.prefix === item.target.value.split(' ')[0], ); setProviderLabel(provider?.name ?? 'Invalid Search'); @@ -434,112 +425,6 @@ export default function Search({ return historyOptions; }; - const renderItem: any = (item: any) => { - const Icon = item.option.prefix - ? allIcons[ - item.option.prefix === '/g' - ? 'FaGoogle' - : (providers.find((p: Provider) => p.prefix === item.option.prefix)?.icon ?? - '') - ] - : item.option.icon - ? allIcons[item.option.icon] - : item.option.type && item.option.type === 'SSH' - ? allIcons.FaTerminal - : item.option.type === 'RDP' - ? allIcons.FaComputer - : allIcons.FaDesktop; - return (searchValue as string).startsWith('!') ? ( - { - e.preventDefault(); - e.stopPropagation(); - handleAppLaunchItem(item); - }} - > - - Launch - - {Icon && ( - - )} - - {item.option.name} - - - ) : (searchValue as string).startsWith('>') && personal.enableGuacamole === 1 ? ( - { - e.preventDefault(); - e.stopPropagation(); - handleGuacamoleClientLaunchItem(item); - }} - > - - Connect to - - - - {item.option.name || item.option.clientName || 'Invalid connection'} - - - ) : item.option.value === 'load' ? ( - { - e.preventDefault(); - e.stopPropagation(); - setHistoryMultiplier((prev: number) => prev + 1); - }} - > - - {item.option.label} - - - ) : ( - - ); - }; - useEffect(() => { if (historyData && historyDataIsFetched) { if (filteredHistory.length === 0) { @@ -580,6 +465,7 @@ export default function Search({ setDefaultProviderIcon(defaultProviderData[0]?.icon ?? 'FaGoogle'); } }, [defaultProviderData, defaultProviderDataIsFetched]); + return ( <> {dropdownOpened && } @@ -647,7 +533,19 @@ export default function Search({ bg: 'transparent', }} scrollAreaProps={{ viewportRef: ref }} - renderOption={(item: any) => renderItem(item)} + renderOption={(item: any) => ( + + )} onFocus={() => { if (searchValue !== '') { openDropdown(); @@ -703,17 +601,22 @@ export default function Search({ - - + {bookmarks.length > 0 && ( + + )} + {personal.enableGuacamole === 1 && + filteredGuacamoleClients.length > 0 && ( + + )} >; + personal: PersonalData; + handleGuacamoleClientLaunchItem: ({ option }: { option: any }) => void; + setHistoryMultiplier: React.Dispatch>; + searchEndpoint: string; +}) { + const { defaultProviderURL } = useCommonHooks(); + const handleSearchHistoryItem = ({ option }: { option: SearchHistoryItem }) => { + const url = + providers.find((provider: Provider) => provider.prefix === option.prefix)?.url ?? + defaultProviderURL; + open(`${url}${option.searchTerm}`, '_self'); + }; + + const handleAppLaunchItem = ({ option }: { option: any }) => { + const validUrl = + option.url.startsWith('http://') || option.url.startsWith('https://') + ? option.url + : `http://${option.url}`; + open(validUrl, '_self'); + }; + const Icon = item.option.prefix + ? allIcons[ + item.option.prefix === '/g' + ? 'FaGoogle' + : (providers.find((p: Provider) => p.prefix === item.option.prefix)?.icon ?? '') + ] + : item.option.icon + ? allIcons[item.option.icon] + : item.option.type && item.option.type === 'SSH' + ? allIcons.FaTerminal + : item.option.type === 'RDP' + ? allIcons.FaComputer + : allIcons.FaDesktop; + return (searchValue as string).startsWith('!') ? ( + { + e.preventDefault(); + e.stopPropagation(); + handleAppLaunchItem(item); + }} + > + + Launch + + {Icon && ( + + )} + + {item.option.name} + + + ) : (searchValue as string).startsWith('>') && personal.enableGuacamole === 1 ? ( + { + e.preventDefault(); + e.stopPropagation(); + handleGuacamoleClientLaunchItem(item); + }} + > + + Connect to + + + + {item.option.name || item.option.clientName || 'Invalid connection'} + + + ) : item.option.value === 'load' ? ( + { + e.preventDefault(); + e.stopPropagation(); + setHistoryMultiplier((prev: number) => prev + 1); + }} + > + + {item.option.label} + + + ) : ( + + ); +} diff --git a/src/pages/homepage/components/SettingsButton/SettingsButton.tsx b/src/pages/homepage/components/SettingsButton/SettingsButton.tsx index 67a298d..e77ed2f 100644 --- a/src/pages/homepage/components/SettingsButton/SettingsButton.tsx +++ b/src/pages/homepage/components/SettingsButton/SettingsButton.tsx @@ -19,7 +19,7 @@ function SettingsButton() { const { data: wolEnabledData, isFetched: wolEnabledDataIsFetched } = useQueryAPI({ endpoint: 'api/wolEnabled', }); - const wolClients = wolClientData || []; + const wolClients: WolClient[] = wolClientData || []; const [enabled, setEnabled] = useState(0); const { mutateAsync } = useMutationAPI(); const [categories, setCategories] = useState([{ value: 'All', label: 'All' }]); diff --git a/src/pages/settings/components/Bookmarks/Bookmarks.tsx b/src/pages/settings/components/Bookmarks/Bookmarks.tsx index 8084302..7d3bcd2 100644 --- a/src/pages/settings/components/Bookmarks/Bookmarks.tsx +++ b/src/pages/settings/components/Bookmarks/Bookmarks.tsx @@ -36,7 +36,7 @@ const BookmarkSettings = () => { const { data: bookmarkData, isFetching: bookmarkDataIsFetching } = useQueryAPI({ endpoint: bookmarksEndpoint, }); - const bookmarks = bookmarkData || []; + const bookmarks: Bookmark[] = bookmarkData || []; const categoriesEndpoint = 'api/bookmarkCategories'; const { data: groupData, isFetched: groupsIsFetched } = useQueryAPI({ endpoint: categoriesEndpoint, @@ -50,7 +50,7 @@ const BookmarkSettings = () => { const [debouncedGroupSearch] = useDebouncedValue(searchValue, 500); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const [isLoading, setIsLoading] = useState(false); - const foundBookmarkGroups = [ + const foundBookmarkGroups: BookmarkGroup[] = [ ...new Set( bookmarks .filter( @@ -68,7 +68,7 @@ const BookmarkSettings = () => { ), ), ]; - const foundGroups = groupData.filter((a: BookmarkGroup) => + const foundGroups: BookmarkGroup[] = groupData.filter((a: BookmarkGroup) => a.categoryName.toLowerCase().includes((debouncedGroupSearch as string).toLowerCase()), ); const handleClose = () => { diff --git a/src/pages/settings/components/GuacamoleClients/GuacamoleClients.tsx b/src/pages/settings/components/GuacamoleClients/GuacamoleClients.tsx index 2211e30..fe66c82 100644 --- a/src/pages/settings/components/GuacamoleClients/GuacamoleClients.tsx +++ b/src/pages/settings/components/GuacamoleClients/GuacamoleClients.tsx @@ -46,7 +46,7 @@ const GuacamoleClients = () => { useQueryAPI({ endpoint: endpoint, }); - const guacamoleClients = + const guacamoleClients: GuacamoleClient[] = guacamoleClientsData.filter( (a: GuacamoleClient) => a.clientName.toLowerCase().includes((debouncedSearch as string).toLowerCase()) || diff --git a/src/pages/settings/components/Messages/Messages.tsx b/src/pages/settings/components/Messages/Messages.tsx index f1d9f41..5158118 100644 --- a/src/pages/settings/components/Messages/Messages.tsx +++ b/src/pages/settings/components/Messages/Messages.tsx @@ -33,7 +33,7 @@ const MessageSettings = () => { const [debouncedSearch] = useDebouncedValue(searchValue, 500); const { isMobile, theme } = useCommonHooks(); const { mutateAsync } = useMutationAPI(); - const messages = + const messages: Message[] = messageData?.filter((m: Message) => m.message.toLowerCase().includes((debouncedSearch as string).toLowerCase()), ) || []; diff --git a/src/pages/settings/components/Search/SearchProviders.tsx b/src/pages/settings/components/Search/SearchProviders.tsx index a3d69da..c7934f7 100644 --- a/src/pages/settings/components/Search/SearchProviders.tsx +++ b/src/pages/settings/components/Search/SearchProviders.tsx @@ -36,12 +36,14 @@ import SearchProviderSettingsItem from './SearchProviderSettingsItem'; const SearchProviderSettings = () => { const allIcons: any = { ...fa6, ...vsc, ...si }; - const defaultProvider = { + const defaultProvider: Provider = { id: undefined, name: '', url: '', prefix: '', default: 0, + enabled: 1, + icon: null, }; const form = useForm({ initialValues: defaultProvider, @@ -57,7 +59,7 @@ const SearchProviderSettings = () => { }); const [searchValue, setSearchValue] = useState(''); const [debouncedSearch] = useDebouncedValue(searchValue, 500); - const providers = + const providers: Provider[] = providerData .filter( (a: Provider) =>