diff --git a/striker-ui/components/Files/Files.tsx b/striker-ui/components/Files/Files.tsx index 61385fb7..07ec8286 100644 --- a/striker-ui/components/Files/Files.tsx +++ b/striker-ui/components/Files/Files.tsx @@ -13,13 +13,16 @@ import { BLUE } from '../../lib/consts/DEFAULT_THEME'; import FileEditForm from './FileEditForm'; import FileList from './FileList'; import FileUploadForm from './FileUploadForm'; +import IconButton from '../IconButton'; import { Panel } from '../Panels'; import MessageBox from '../MessageBox'; import Spinner from '../Spinner'; import { HeaderText } from '../Text'; import fetchJSON from '../../lib/fetchers/fetchJSON'; -import IconButton from '../IconButton'; +import periodicFetch from '../../lib/fetchers/periodicFetch'; + +const FILES_ENDPOINT_URL = `${API_BASE_URL}/files`; const Files = (): JSX.Element => { const [rawFilesOverview, setRawFilesOverview] = useState([]); @@ -44,7 +47,7 @@ const Files = (): JSX.Element => { setIsLoadingRawFilesOverview(true); try { - const data = await fetchJSON(`${API_BASE_URL}/files`); + const data = await fetchJSON(FILES_ENDPOINT_URL); setRawFilesOverview(data); } catch (fetchError) { setFetchRawFilesError('Failed to get files due to a network issue.'); @@ -82,6 +85,23 @@ const Files = (): JSX.Element => { return elements; }; + /** + * Check for new files periodically and update the file list. + * + * We need this because adding new files is done async; adding the file may + * not finish before the request returns. + * + * We don't care about edit because database updates are done before the + * edit request returns. + */ + periodicFetch(FILES_ENDPOINT_URL, { + onSuccess: (periodicFilesOverview) => { + if (periodicFilesOverview.length !== rawFilesOverview.length) { + setRawFilesOverview(periodicFilesOverview); + } + }, + }); + useEffect(() => { if (!isEditMode) { fetchRawFilesOverview(); diff --git a/striker-ui/lib/fetchers/periodicFetch.ts b/striker-ui/lib/fetchers/periodicFetch.ts index a013e3b5..26113b82 100644 --- a/striker-ui/lib/fetchers/periodicFetch.ts +++ b/striker-ui/lib/fetchers/periodicFetch.ts @@ -1,10 +1,10 @@ -import useSWR from 'swr'; +import useSWR, { SWRConfiguration } from 'swr'; import fetcher from './fetchJSON'; const periodicFetch = ( url: string, - refreshInterval = 5000, + { refreshInterval = 5000, onSuccess }: SWRConfiguration = {}, ): GetResponses => { // The purpose of react-hooks/rules-of-hooks is to ensure that react hooks // are called in order (i.e., not potentially skipped due to conditionals). @@ -12,6 +12,7 @@ const periodicFetch = ( // eslint-disable-next-line react-hooks/rules-of-hooks const { data, error } = useSWR(url, fetcher, { refreshInterval, + onSuccess, }); return {