From 3b5db0e4aac0c28b8ba504b3c37d9be951798484 Mon Sep 17 00:00:00 2001 From: Alex Gustafsson Date: Tue, 14 Jan 2025 21:02:21 +0100 Subject: [PATCH] Improve UX of scheduling update Improve the UX of scheduling the update of an image's data: - Add hover, active and disable styles to the button - Add a spinner animation for when the request is in-flight - Add a warning if the request fails - Add another string shown when the request was successful Solves: #69 --- web/api.ts | 23 ++++++------ web/pages/ImagePage.tsx | 77 +++++++++++++++++++++++++++++++---------- 2 files changed, 69 insertions(+), 31 deletions(-) diff --git a/web/api.ts b/web/api.ts index 618a042..9fc78a5 100644 --- a/web/api.ts +++ b/web/api.ts @@ -328,19 +328,18 @@ export function usePagination( return pages } -export function useScheduleScan(): (reference: string) => Promise { - return async (reference: string) => { - const query = new URLSearchParams({ reference }) - const res = await fetch( - `${import.meta.env.VITE_API_ENDPOINT}/image/scans?${query.toString()}`, - { - method: 'POST', - } - ) - - if (res.status !== 202) { - throw new Error(`unexpected status - ${res.status}`) +export async function scheduleScan(reference: string): Promise { + const query = new URLSearchParams({ reference }) + const res = await fetch( + `${import.meta.env.VITE_API_ENDPOINT}/image/scans?${query.toString()}`, + { + method: 'POST', + signal: AbortSignal.timeout(5000), } + ) + + if (res.status !== 202) { + throw new Error(`unexpected status - ${res.status}`) } } diff --git a/web/pages/ImagePage.tsx b/web/pages/ImagePage.tsx index c49bc3f..45db328 100644 --- a/web/pages/ImagePage.tsx +++ b/web/pages/ImagePage.tsx @@ -1,13 +1,13 @@ -import type { JSX, ReactNode } from 'react' +import { type JSX, type ReactNode, useCallback, useState } from 'react' import { Link, NavLink, Navigate, useSearchParams } from 'react-router-dom' import { type Graph, + scheduleScan, useImage, useImageDescription, useImageGraph, useImageReleaseNotes, - useScheduleScan, useTags, } from '../api' import { Badge } from '../components/Badge' @@ -132,8 +132,6 @@ export function ImagePage(): JSX.Element { const releaseNotes = useImageReleaseNotes(reference) const graph = useImageGraph(reference) - const scheduleScan = useScheduleScan() - if ( tags.status === 'idle' || image.status === 'idle' || @@ -359,23 +357,64 @@ export function ImagePage(): JSX.Element { {graph.value && }
-

- Last processed{' '} - - {formatRelativeTimeTo(new Date(image.value.lastModified))} - -

- +
) } + +type ProcessStatusProps = { + lastModified: string + reference: string +} + +function ProcessStatus({ + lastModified, + reference, +}: ProcessStatusProps): JSX.Element { + const [status, setStatus] = useState< + 'idle' | 'in-flight' | 'successful' | 'failed' + >('idle') + + const onSchedule = useCallback(() => { + setStatus('in-flight') + scheduleScan(reference) + .then(() => setStatus('successful')) + .catch(() => setStatus('failed')) + }, [reference]) + + return ( + <> + {status !== 'successful' && ( +

+ Last processed{' '} + + {formatRelativeTimeTo(new Date(lastModified))} + +

+ )} +

{status === 'successful' && 'Image is scheduled for processing'}

+ + + ) +}