diff --git a/resources/scripts/components/server/backups/BackupContainer.tsx b/resources/scripts/components/server/backups/BackupContainer.tsx index dee9342c9..d00f29996 100644 --- a/resources/scripts/components/server/backups/BackupContainer.tsx +++ b/resources/scripts/components/server/backups/BackupContainer.tsx @@ -44,6 +44,9 @@ export default () => { {backups.map((backup, index) => setBackups( + s => ([ ...s.map(b => b.uuid === data.uuid ? data : b) ]), + )} className={index !== (backups.length - 1) ? 'mb-2' : undefined} />)} @@ -51,7 +54,7 @@ export default () => {
setBackups(s => [...s, backup])} + onBackupGenerated={backup => setBackups(s => [ ...s, backup ])} />
diff --git a/resources/scripts/components/server/backups/BackupRow.tsx b/resources/scripts/components/server/backups/BackupRow.tsx index d28e487e6..570fec644 100644 --- a/resources/scripts/components/server/backups/BackupRow.tsx +++ b/resources/scripts/components/server/backups/BackupRow.tsx @@ -14,9 +14,11 @@ import getBackupDownloadUrl from '@/api/server/backups/getBackupDownloadUrl'; import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; import useFlash from '@/plugins/useFlash'; import { httpErrorToHuman } from '@/api/http'; +import useWebsocketEvent from '@/plugins/useWebsocketEvent'; interface Props { backup: ServerBackup; + onBackupUpdated: (backup: ServerBackup) => void; className?: string; } @@ -32,12 +34,26 @@ const DownloadModal = ({ checksum, ...props }: RequiredModalProps & { checksum: ); -export default ({ backup, className }: Props) => { +export default ({ backup, onBackupUpdated, className }: Props) => { const { uuid } = useServer(); const { addError, clearFlashes } = useFlash(); const [ loading, setLoading ] = useState(false); const [ visible, setVisible ] = useState(false); + useWebsocketEvent(`backup completed:${backup.uuid}`, data => { + try { + const parsed = JSON.parse(data); + onBackupUpdated({ + ...backup, + sha256Hash: parsed.sha256_hash || '', + bytes: parsed.file_size || 0, + completedAt: new Date(), + }); + } catch (e) { + console.warn(e); + } + }); + const getBackupLink = () => { setLoading(true); clearFlashes('backups'); diff --git a/resources/scripts/plugins/useWebsocketEvent.ts b/resources/scripts/plugins/useWebsocketEvent.ts new file mode 100644 index 000000000..4637e304c --- /dev/null +++ b/resources/scripts/plugins/useWebsocketEvent.ts @@ -0,0 +1,24 @@ +import { ServerContext } from '@/state/server'; +import { useEffect, useRef } from 'react'; + +const useWebsocketEvent = (event: string, callback: (data: string) => void) => { + const { connected, instance } = ServerContext.useStoreState(state => state.socket); + const savedCallback = useRef(null); + + useEffect(() => { + savedCallback.current = callback; + }, [callback]); + + return useEffect(() => { + const eventListener = (event: any) => savedCallback.current(event); + if (connected && instance) { + instance.addListener(event, eventListener); + } + + return () => { + instance && instance.removeListener(event, eventListener); + }; + }, [ event, connected, instance ]); +}; + +export default useWebsocketEvent;