diff --git a/src/explore-education-statistics-admin/src/pages/release/data/components/DataFilesTable.tsx b/src/explore-education-statistics-admin/src/pages/release/data/components/DataFilesTable.tsx index 3f96a737ce..a0112653c5 100644 --- a/src/explore-education-statistics-admin/src/pages/release/data/components/DataFilesTable.tsx +++ b/src/explore-education-statistics-admin/src/pages/release/data/components/DataFilesTable.tsx @@ -19,8 +19,10 @@ import { import ButtonGroup from '@common/components/ButtonGroup'; import ButtonText from '@common/components/ButtonText'; import Modal from '@common/components/Modal'; +import ReorderableList from '@common/components/ReorderableList'; +import reorder from '@common/utils/reorder'; +import React, { useEffect, useState } from 'react'; import { generatePath } from 'react-router'; -import React from 'react'; import styles from './DataFilesTable.module.scss'; interface Props { @@ -28,86 +30,146 @@ interface Props { publicationId: string; releaseId: string; canUpdateRelease?: boolean; - handleDeleteFile: (dataFile: DataFile) => Promise; - handleStatusChange: ( + isReordering: boolean; + onCancelReordering: () => void; + onConfirmReordering: (nextSeries: DataFile[]) => void; + onDeleteFile: (dataFile: DataFile) => Promise; + onStatusChange: ( dataFile: DataFile, { totalRows, status }: DataFileImportStatus, ) => Promise; } const DataFilesTable = ({ - dataFiles, + dataFiles: initialDataFiles, publicationId, releaseId, canUpdateRelease, - handleDeleteFile, - handleStatusChange, + isReordering, + onCancelReordering, + onConfirmReordering, + onDeleteFile, + onStatusChange, }: Props) => { + const [dataFiles, setDataFiles] = useState(initialDataFiles); + + useEffect(() => { + setDataFiles(initialDataFiles); + }, [initialDataFiles]); + + if (isReordering) { + return ( + ({ + id, + label: title, + }))} + onCancel={() => { + setDataFiles(initialDataFiles); + onCancelReordering(); + }} + onConfirm={() => onConfirmReordering(dataFiles)} + onMoveItem={({ prevIndex, nextIndex }) => { + const reordered = reorder(dataFiles, prevIndex, nextIndex); + setDataFiles(reordered); + }} + onReverse={() => { + setDataFiles(dataFiles.toReversed()); + }} + /> + ); + } + return ( - <> -

Uploaded data files

- - - - - - {/* */} - - {/* */} - {/* - */} - - - +
Subject titleSizeRowsStatusUploaded byDate uploadedActions
+ + + + + + + + - - {dataFiles.map(dataFile => ( - - - - {/* */} - - {/* */} - {/* */} - + {dataFiles.map(dataFile => ( + + + + + - - ))} - -
Subject titleSizeStatusActions
{dataFile.title} - {dataFile.fileSize.size.toLocaleString()}{' '} - {dataFile.fileSize.unit} - {dataFile.rows} - - - {dataFile.userName} - - {!dataFile.created ? undefined : ( - - {dataFile.created} - - )} - - - View details} - > - - - {canUpdateRelease && - terminalImportStatuses.includes(dataFile.status) && ( - <> - {dataFile.status === 'COMPLETE' && ( - <> +
{dataFile.title} + {dataFile.fileSize.size.toLocaleString()} {dataFile.fileSize.unit} + + + + + View details} + > + + + {canUpdateRelease && + terminalImportStatuses.includes(dataFile.status) && ( + <> + {dataFile.status === 'COMPLETE' && ( + <> + ( + releaseDataFileRoute.path, + { + publicationId, + releaseId, + fileId: dataFile.id, + }, + )} + > + Edit title + + {dataFile.publicApiDataSetId ? ( + Replace data + } + > +

+ This data file has an API data set linked to it. + Please remove the API data set before replacing + the data. +

+

+ ( + releaseApiDataSetDetailsRoute.path, + { + publicationId, + releaseId, + dataSetId: dataFile.publicApiDataSetId, + }, + )} + > + Go to API data set + +

+
+ ) : ( ( - releaseDataFileRoute.path, + to={generatePath( + releaseDataFileReplaceRoute.path, { publicationId, releaseId, @@ -115,104 +177,62 @@ const DataFilesTable = ({ }, )} > - Edit title + Replace data - {dataFile.publicApiDataSetId ? ( - Replace data - } - > -

- This data file has an API data set linked to - it. Please remove the API data set before - replacing the data. -

-

- ( - releaseApiDataSetDetailsRoute.path, - { - publicationId, - releaseId, - dataSetId: dataFile.publicApiDataSetId, - }, - )} - > - Go to API data set - -

-
- ) : ( - ( - releaseDataFileReplaceRoute.path, - { - publicationId, - releaseId, - fileId: dataFile.id, - }, - )} - > - Replace data - - )} - - )} - {dataFile.publicApiDataSetId ? ( - - Delete files - - } - > -

- This data file has an API data set linked to it. - Please remove the API data set before deleting. -

-

- ( - releaseApiDataSetDetailsRoute.path, - { - publicationId, - releaseId, - dataSetId: dataFile.publicApiDataSetId, - }, - )} - > - Go to API data set - -

-
- ) : ( - handleDeleteFile(dataFile)} - variant="warning" - > - Delete files - - )} - - )} - {dataFile.permissions.canCancelImport && ( - + )} + + )} + {dataFile.publicApiDataSetId ? ( + + Delete files + + } + > +

+ This data file has an API data set linked to it. + Please remove the API data set before deleting. +

+

+ ( + releaseApiDataSetDetailsRoute.path, + { + publicationId, + releaseId, + dataSetId: dataFile.publicApiDataSetId, + }, + )} + > + Go to API data set + +

+
+ ) : ( + onDeleteFile(dataFile)} + variant="warning" + > + Delete files + + )} + )} -
-
- + {dataFile.permissions.canCancelImport && ( + + )} + + + + ))} + + ); }; diff --git a/src/explore-education-statistics-admin/src/pages/release/data/components/ReleaseDataUploadsSection.tsx b/src/explore-education-statistics-admin/src/pages/release/data/components/ReleaseDataUploadsSection.tsx index d77e771a52..3cb7e9473c 100644 --- a/src/explore-education-statistics-admin/src/pages/release/data/components/ReleaseDataUploadsSection.tsx +++ b/src/explore-education-statistics-admin/src/pages/release/data/components/ReleaseDataUploadsSection.tsx @@ -9,10 +9,12 @@ import releaseDataFileService, { DataFileImportStatus, DeleteDataFilePlan, } from '@admin/services/releaseDataFileService'; +import Button from '@common/components/Button'; import InsetText from '@common/components/InsetText'; import LoadingSpinner from '@common/components/LoadingSpinner'; import ModalConfirm from '@common/components/ModalConfirm'; import WarningMessage from '@common/components/WarningMessage'; +import useToggle from '@common/hooks/useToggle'; import logger from '@common/services/logger'; import { useQuery } from '@tanstack/react-query'; import React, { useCallback, useEffect, useState } from 'react'; @@ -40,6 +42,7 @@ const ReleaseDataUploadsSection = ({ const [deleteDataFile, setDeleteDataFile] = useState(); const [dataFiles, setDataFiles] = useState([]); const [bulkUploadPlan, setBulkUploadPlan] = useState(); + const [isReordering, toggleReordering] = useToggle(false); const { data: initialDataFiles, @@ -218,14 +221,34 @@ const ReleaseDataUploadsSection = ({ {dataFiles.length > 0 ? ( - + <> +

Uploaded data files

+ { + setDataFiles( + await releaseDataFileService.updateDataFilesOrder( + releaseId, + nextDataFiles.map(file => file.id), + ), + ); + toggleReordering.off(); + }} + onStatusChange={handleStatusChange} + onDeleteFile={handleDeleteFile} + publicationId={publicationId} + releaseId={releaseId} + /> + + {isReordering ? undefined : ( + + )} + ) : ( No data files have been uploaded. )}