From 895356701f9083b663c050330d5b98406ee6ab59 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Sun, 30 Oct 2022 20:21:31 -0700 Subject: [PATCH] Update server list --- .../servers/components/edit-server-form.tsx | 12 +- .../servers/components/server-list-item.tsx | 246 ++++++++++++------ .../servers/components/server-list.tsx | 37 +-- .../mutations/use-disable-server-folder.ts | 2 +- .../mutations/use-enable-server-folder.ts | 2 +- .../servers/mutations/use-full-scan.ts | 39 +++ .../servers/mutations/use-quick-scan.ts | 39 +++ .../servers/mutations/use-update-server.ts | 17 +- .../servers/queries/use-server-list.ts | 76 ++---- 9 files changed, 283 insertions(+), 187 deletions(-) create mode 100644 src/renderer/features/servers/mutations/use-full-scan.ts create mode 100644 src/renderer/features/servers/mutations/use-quick-scan.ts diff --git a/src/renderer/features/servers/components/edit-server-form.tsx b/src/renderer/features/servers/components/edit-server-form.tsx index 1df5f7c45..bc78bdab6 100644 --- a/src/renderer/features/servers/components/edit-server-form.tsx +++ b/src/renderer/features/servers/components/edit-server-form.tsx @@ -3,7 +3,7 @@ import { useForm } from '@mantine/form'; import { useTranslation } from 'react-i18next'; import { RiInformationLine } from 'react-icons/ri'; import { Server, ServerType } from '@/renderer/api/types'; -import { Button, PasswordInput, TextInput } from '@/renderer/components'; +import { Button, PasswordInput, TextInput, toast } from '@/renderer/components'; import { useUpdateServer } from '@/renderer/features/servers/mutations/use-update-server'; interface EditServerFormProps { @@ -40,7 +40,15 @@ export const EditServerForm = ({ server, onCancel }: EditServerFormProps) => { }, query: { serverId: server.id }, }, - { onSuccess: onCancel } + { + onSuccess: (data) => { + toast.show({ + message: `Server "${data.data.name}" updated`, + type: 'success', + }); + onCancel(); + }, + } ); }); diff --git a/src/renderer/features/servers/components/server-list-item.tsx b/src/renderer/features/servers/components/server-list-item.tsx index 489dc323d..3beef848c 100644 --- a/src/renderer/features/servers/components/server-list-item.tsx +++ b/src/renderer/features/servers/components/server-list-item.tsx @@ -1,8 +1,11 @@ -import { Stack, Group } from '@mantine/core'; +import { useMemo } from 'react'; +import { Stack, Group, Divider } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; +import { useQueryClient } from '@tanstack/react-query'; import { RiDeleteBin2Fill, RiEdit2Fill } from 'react-icons/ri'; -import { Server } from '@/renderer/api/types'; -import { Button, Text } from '@/renderer/components'; +import { queryKeys } from '@/renderer/api/query-keys'; +import { Server, TaskType } from '@/renderer/api/types'; +import { Button, Switch, Text, toast } from '@/renderer/components'; import { AddServerCredentialForm } from '@/renderer/features/servers/components/add-server-credential-form'; import { AddServerUrlForm } from '@/renderer/features/servers/components/add-server-url-form'; import { EditServerForm } from '@/renderer/features/servers/components/edit-server-form'; @@ -12,25 +15,77 @@ import { useDisableServerFolder } from '@/renderer/features/servers/mutations/us import { useDisableServerUrl } from '@/renderer/features/servers/mutations/use-disable-server-url'; import { useEnableServerFolder } from '@/renderer/features/servers/mutations/use-enable-server-folder'; import { useEnableServerUrl } from '@/renderer/features/servers/mutations/use-enable-server-url'; +import { useFullScan } from '@/renderer/features/servers/mutations/use-full-scan'; +import { useQuickScan } from '@/renderer/features/servers/mutations/use-quick-scan'; +import { useUpdateServer } from '@/renderer/features/servers/mutations/use-update-server'; import { usePermissions } from '@/renderer/features/shared'; +import { useTaskList } from '@/renderer/features/tasks'; import { useAuthStore } from '@/renderer/store'; +import { Font } from '@/renderer/styles'; interface ServerListItemProps { server: Server; } export const ServerListItem = ({ server }: ServerListItemProps) => { + const queryClient = useQueryClient(); const [edit, editHandlers] = useDisclosure(false); const [addUrl, addUrlHandlers] = useDisclosure(false); const [addCredential, addCredentialHandlers] = useDisclosure(false); const permissions = usePermissions(); + const updateServer = useUpdateServer(); const enableServerUrl = useEnableServerUrl(); const disableServerUrl = useDisableServerUrl(); const deleteServerUrl = useDeleteServerUrl(); const enableServerFolder = useEnableServerFolder(); const disableServerFolder = useDisableServerFolder(); - const serverCredentials = useAuthStore((state) => state.serverCredentials); + const fullScan = useFullScan(); + const quickScan = useQuickScan(); + const { data: tasks } = useTaskList(); + + const isRunningTask = useMemo(() => { + return tasks?.data.some( + (task) => + task.server?.id === server.id && + (task.type === TaskType.FULL_SCAN || task.type === TaskType.QUICK_SCAN) + ); + }, [server.id, tasks?.data]); + + const serverCredentials = useAuthStore( + (state) => state.serverCredentials + ).filter((credential) => credential.serverId === server.id); + + const handleFullScan = () => { + fullScan.mutate( + { body: {}, query: { serverId: server.id } }, + { + onSuccess: () => { + toast.show({ message: 'Full scan started', type: 'info' }); + queryClient.invalidateQueries(queryKeys.tasks.root); + }, + } + ); + }; + + const handleQuickScan = () => { + quickScan.mutate( + { body: {}, query: { serverId: server.id } }, + { + onSuccess: () => { + toast.show({ message: 'Quick scan started', type: 'info' }); + queryClient.invalidateQueries(queryKeys.tasks.root); + }, + } + ); + }; + + const toggleRequiredCredential = (e: boolean) => { + updateServer.mutate({ + body: { noCredential: e, type: server.type }, + query: { serverId: server.id }, + }); + }; const enableServerCredential = useAuthStore( (state) => state.enableServerCredential @@ -87,8 +142,33 @@ export const ServerListItem = ({ server }: ServerListItemProps) => { return ( <> - - + + + Server details + + + + + + } + > {edit ? ( { {server.serverFolders?.map((folder) => ( - + + {folder.name} - {folder.name} - - - {permissions.deleteServerFolder && ( )} + + handleToggleFolder(folder.id, !e.currentTarget.checked) + } + /> ))} - - {addUrl ? ( - addUrlHandlers.close()} - /> - ) : ( - <> - - {server.serverUrls?.map((serverUrl) => ( - - {serverUrl.url} - - - {permissions.deleteServerUrl && ( - - )} - - - ))} - - {permissions.createServerUrl && ( - - )} - - )} - {addCredential ? ( { {credential.username} - {permissions.deleteServerCredential && ( )} + + handleToggleCredential( + credential.id, + !e.currentTarget.checked + ) + } + /> ))} @@ -251,7 +271,67 @@ export const ServerListItem = ({ server }: ServerListItemProps) => { )} + + {addUrl ? ( + addUrlHandlers.close()} + /> + ) : ( + <> + + {server.serverUrls?.map((serverUrl) => ( + + {serverUrl.url} + + {permissions.deleteServerUrl && ( + + )} + + handleToggleUrl( + serverUrl.id, + !e.currentTarget.checked + ) + } + /> + + + ))} + + {permissions.createServerUrl && ( + + )} + + )} + + + + Require user credentials + + toggleRequiredCredential(e.currentTarget.checked) + } + /> + + {permissions.deleteServer && ( - - diff --git a/src/renderer/features/servers/mutations/use-disable-server-folder.ts b/src/renderer/features/servers/mutations/use-disable-server-folder.ts index 607d03474..774b4c21e 100644 --- a/src/renderer/features/servers/mutations/use-disable-server-folder.ts +++ b/src/renderer/features/servers/mutations/use-disable-server-folder.ts @@ -47,7 +47,7 @@ export const useDisableServerFolder = () => { return { previous }; }, onSettled: () => { - queryClient.invalidateQueries(queryKeys.servers.list()); + queryClient.invalidateQueries(queryKeys.servers.root); }, }); diff --git a/src/renderer/features/servers/mutations/use-enable-server-folder.ts b/src/renderer/features/servers/mutations/use-enable-server-folder.ts index 477adf3d5..b45184311 100644 --- a/src/renderer/features/servers/mutations/use-enable-server-folder.ts +++ b/src/renderer/features/servers/mutations/use-enable-server-folder.ts @@ -47,7 +47,7 @@ export const useEnableServerFolder = () => { return { previous }; }, onSettled: () => { - queryClient.invalidateQueries(queryKeys.servers.list()); + queryClient.invalidateQueries(queryKeys.servers.root); }, }); diff --git a/src/renderer/features/servers/mutations/use-full-scan.ts b/src/renderer/features/servers/mutations/use-full-scan.ts new file mode 100644 index 000000000..cbffa0a1c --- /dev/null +++ b/src/renderer/features/servers/mutations/use-full-scan.ts @@ -0,0 +1,39 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { AxiosError } from 'axios'; +import { api } from '@/renderer/api'; +import { queryKeys } from '@/renderer/api/query-keys'; +import { ServerListResponse } from '@/renderer/api/servers.api'; +import { ApiError, NullResponse } from '@/renderer/api/types'; + +export const useFullScan = () => { + const queryClient = useQueryClient(); + + const mutation = useMutation< + NullResponse, + AxiosError, + { + body: { serverFolderId?: string[] }; + query: { serverId: string }; + }, + { previous: ServerListResponse | undefined } + >({ + mutationFn: ({ body, query }) => api.servers.fullScan({ body, query }), + onError: (_err, _variables, context) => { + if (!context?.previous) return; + queryClient.setQueryData(queryKeys.servers.list(), context.previous); + }, + onMutate: async () => { + const queryKey = queryKeys.servers.list(); + + await queryClient.cancelQueries(queryKey); + const previous = queryClient.getQueryData(queryKey); + + return { previous }; + }, + onSuccess: () => { + queryClient.invalidateQueries(queryKeys.servers.list()); + }, + }); + + return mutation; +}; diff --git a/src/renderer/features/servers/mutations/use-quick-scan.ts b/src/renderer/features/servers/mutations/use-quick-scan.ts new file mode 100644 index 000000000..a3bf6c207 --- /dev/null +++ b/src/renderer/features/servers/mutations/use-quick-scan.ts @@ -0,0 +1,39 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { AxiosError } from 'axios'; +import { api } from '@/renderer/api'; +import { queryKeys } from '@/renderer/api/query-keys'; +import { ServerListResponse } from '@/renderer/api/servers.api'; +import { ApiError, NullResponse } from '@/renderer/api/types'; + +export const useQuickScan = () => { + const queryClient = useQueryClient(); + + const mutation = useMutation< + NullResponse, + AxiosError, + { + body: { serverFolderId?: string[] }; + query: { serverId: string }; + }, + { previous: ServerListResponse | undefined } + >({ + mutationFn: ({ body, query }) => api.servers.quickScan({ body, query }), + onError: (_err, _variables, context) => { + if (!context?.previous) return; + queryClient.setQueryData(queryKeys.servers.list(), context.previous); + }, + onMutate: async () => { + const queryKey = queryKeys.servers.list(); + + await queryClient.cancelQueries(queryKey); + const previous = queryClient.getQueryData(queryKey); + + return { previous }; + }, + onSettled: () => { + queryClient.invalidateQueries(queryKeys.servers.list()); + }, + }); + + return mutation; +}; diff --git a/src/renderer/features/servers/mutations/use-update-server.ts b/src/renderer/features/servers/mutations/use-update-server.ts index a47dd25af..b7e881432 100644 --- a/src/renderer/features/servers/mutations/use-update-server.ts +++ b/src/renderer/features/servers/mutations/use-update-server.ts @@ -39,10 +39,16 @@ export const useUpdateServer = () => { if (!previous) return undefined; const data = previous.data.map((server) => { if (server.id === variables.query.serverId) { + if (variables.body.name || variables.body.username) { + return { + ...server, + name: variables.body.name, + username: variables.body?.username, + }; + } return { ...server, - name: variables.body.name, - username: variables.body.username, + noCredential: variables.body.noCredential, }; } @@ -56,13 +62,6 @@ export const useUpdateServer = () => { onSettled: () => { queryClient.invalidateQueries(queryKeys.servers.list()); }, - onSuccess: (data) => { - toast.show({ - message: `Server "${data.data.name}" updated`, - type: 'success', - }); - queryClient.invalidateQueries(queryKeys.servers.list()); - }, }); return mutation; diff --git a/src/renderer/features/servers/queries/use-server-list.ts b/src/renderer/features/servers/queries/use-server-list.ts index 549bcddab..f67c41c16 100644 --- a/src/renderer/features/servers/queries/use-server-list.ts +++ b/src/renderer/features/servers/queries/use-server-list.ts @@ -3,65 +3,29 @@ import { api } from '@/renderer/api'; import { queryKeys } from '@/renderer/api/query-keys'; import { ServerListResponse } from '@/renderer/api/servers.api'; import { QueryOptions } from '@/renderer/lib/react-query'; +import { useAuthStore } from '@/renderer/store'; -export const useServerList = (options?: QueryOptions) => { - // return useQuery({ - // // onSuccess: (servers) => { - // // const { serverUrl } = JSON.parse( - // // localStorage.getItem('authentication') || '{}' - // // ); - // // const storedServersKey = `servers_${md5(serverUrl)}`; - // // const serversFromLocalStorage = localStorage.getItem(storedServersKey); - // // // If a custom account/token is set for a server, use that instead of the default one - // // if (serversFromLocalStorage) { - // // const existingServers = JSON.parse(serversFromLocalStorage); - // // // The 'locked' property determines whether or not to skip updating the server auth - // // const skipped = existingServers.filter( - // // (server: ServerFolderAuth) => server.locked - // // ); - // // const store = servers?.data?.flatMap((server) => - // // server.serverFolders?.map((serverFolder: ServerFolder) => { - // // if (skipped.includes(serverFolder.id)) { - // // return existingServers.find( - // // (s: ServerFolderAuth) => s.id === serverFolder.id - // // ); - // // } - // // return { - // // id: serverFolder.id, - // // locked: false, - // // serverId: server.id, - // // token: server.token, - // // type: server.type, - // // url: server.url, - // // userId: server.remoteUserId, - // // username: server.username, - // // }; - // // }) - // // ); - // // return localStorage.setItem(storedServersKey, JSON.stringify(store)); - // // } - // // const store = servers?.data?.flatMap((server) => - // // server.serverFolders?.map((serverFolder: ServerFolder) => ({ - // // id: serverFolder.id, - // // locked: false, - // // serverId: server.id, - // // token: server.token, - // // type: server.type, - // // url: server.url, - // // userId: server.remoteUserId, - // // username: server.username, - // // })) - // // ); - // // return localStorage.setItem(storedServersKey, JSON.stringify(store)); - // // }, - // queryFn: () => api.servers.getServerList(), - // queryKey: queryKeys.server.list, - // ...options, - // }); +export const useServerList = ( + params?: { enabled?: boolean }, + options?: QueryOptions +) => { + const currentServer = useAuthStore((state) => state.currentServer); + const setCurrentServer = useAuthStore((state) => state.setCurrentServer); return useQuery({ - queryFn: () => api.servers.getServerList(), - queryKey: queryKeys.servers.list(), + onSuccess: (data) => { + const currentServerFromList = data.data.find( + (server) => server.id === currentServer?.id + ); + + if (!currentServerFromList) { + return setCurrentServer(null); + } + + return setCurrentServer(currentServerFromList); + }, + queryFn: () => api.servers.getServerList(params), + queryKey: queryKeys.servers.list(params), ...options, }); };