From 11d7c2425d9b89c21c6fafcadd6ec9e62b057682 Mon Sep 17 00:00:00 2001 From: adewar Date: Fri, 10 Jan 2025 11:53:44 -0700 Subject: [PATCH] Fixes 5036: Update upload modal to allow cancellation --- jest.ci.config.js | 23 -- package.json | 4 +- .../SnapshotListModal/SnapshotListModal.tsx | 1 - .../UploadContent/UploadContent.test.tsx | 5 +- .../UploadContent/UploadContent.tsx | 11 +- .../UploadContent/components/FileUploader.tsx | 218 ++++++++++++------ .../components/UploadStatusItem.tsx | 18 +- .../UploadContent/components/helpers.tsx | 8 +- .../TemplateDetails/TemplateDetails.test.tsx | 8 +- .../TemplateDetails/TemplateDetails.tsx | 9 +- .../components/UseTemplate/AnsibleTab.tsx | 216 +++++++++-------- .../components/UseTemplate/CurlTab.tsx | 159 +++++++------ .../components/UseTemplate/InsightsTab.tsx | 148 ++++++------ .../UseTemplate/UseTemplateModal.tsx | 142 ++++++------ src/services/Content/ContentApi.ts | 18 +- 15 files changed, 549 insertions(+), 439 deletions(-) delete mode 100644 jest.ci.config.js diff --git a/jest.ci.config.js b/jest.ci.config.js deleted file mode 100644 index edbd57e4..00000000 --- a/jest.ci.config.js +++ /dev/null @@ -1,23 +0,0 @@ -module.exports = { - roots: ['/src/'], - preset: 'ts-jest', - testEnvironment: 'jsdom', - transform: { - '^.+\\.(t)s$': 'ts-jest', - }, - setupFiles: [], - setupFilesAfterEnv: ['/config/setupAfterEnv.ts'], - moduleDirectories: ['/node_modules', '/src'], - - moduleNameMapper: { - // Below replaces imports for speed - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': - '/config/empty.js', - '\\.(css|scss|svg)$': 'identity-obj-proxy', - '^uuid$': require.resolve('uuid'), - }, - transformIgnorePatterns: [ - // Ignores imports of icons and other unneeded modules - '/node_modules/(?!@redhat-cloud-services|@openshift|lodash-es|uuid|@patternfly/react-icons)', - ], -}; diff --git a/package.json b/package.json index 4dbfc6a1..51598e1f 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ "local": "BACKEND_PORT=8000 npm start", "verify": "npm-run-all build lint test-ci", "postinstall": "ts-patch install", - "test": "TZ=UTC jest --config jest.config.js --verbose", - "test-ci": "TZ=UTC jest --config jest.ci.config.js --verbose --no-cache", + "test": "TZ=UTC jest --verbose", + "test-ci": "TZ=UTC jest --verbose --no-cache", "testAllPreviewFailures": "npm-run-all -p test jestPreview", "jestPreview": "jest-preview", "jestClear": "jest --clearCache" diff --git a/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/SnapshotListModal.tsx b/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/SnapshotListModal.tsx index 9107b116..89e4e364 100644 --- a/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/SnapshotListModal.tsx +++ b/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/SnapshotListModal.tsx @@ -1,4 +1,3 @@ -/* eslint-disable quotes */ import { Button, Flex, diff --git a/src/Pages/Repositories/ContentListTable/components/UploadContent/UploadContent.test.tsx b/src/Pages/Repositories/ContentListTable/components/UploadContent/UploadContent.test.tsx index 40da7fc5..f16abe8a 100644 --- a/src/Pages/Repositories/ContentListTable/components/UploadContent/UploadContent.test.tsx +++ b/src/Pages/Repositories/ContentListTable/components/UploadContent/UploadContent.test.tsx @@ -20,7 +20,10 @@ it('Render base upload modal', async () => { jest .spyOn(React, 'useState') - .mockImplementationOnce(() => realUseState([{ sha256: 'string', uuid: 'string' }] as unknown)) + .mockImplementationOnce(() => + realUseState([{ sha256: 'string', uuid: 'string', href: 'string' }] as unknown), + ) + .mockImplementationOnce(() => realUseState(false as unknown)) .mockImplementationOnce(() => realUseState(true as unknown)); const { queryByText } = render(); diff --git a/src/Pages/Repositories/ContentListTable/components/UploadContent/UploadContent.tsx b/src/Pages/Repositories/ContentListTable/components/UploadContent/UploadContent.tsx index 3fe2c016..1823df70 100644 --- a/src/Pages/Repositories/ContentListTable/components/UploadContent/UploadContent.tsx +++ b/src/Pages/Repositories/ContentListTable/components/UploadContent/UploadContent.tsx @@ -26,6 +26,7 @@ const UploadContent = () => { const classes = useStyles(); const { repoUUID: uuid } = useParams(); const [fileUUIDs, setFileUUIDs] = useState<{ sha256: string; uuid: string; href: string }[]>([]); + const [childLoading, setChildLoading] = useState(false); const [confirmModal, setConfirmModal] = useState(false); const rootPath = useRootPath(); @@ -75,10 +76,14 @@ const UploadContent = () => { ouiaId='modal_save' variant='primary' isLoading={isLoading} - isDisabled={!fileUUIDs.length} + isDisabled={!fileUUIDs.length || childLoading} onClick={() => uploadItems().then(onClose)} > - {fileUUIDs.length ? 'Confirm changes' : 'No content uploaded'} + {fileUUIDs.length && !childLoading + ? 'Confirm changes' + : childLoading + ? 'Uploading' + : 'No content uploaded'} + + + + return ( +
+ - - Close - - } - > - - Insights (Preferred)} - tabContentId={INSIGHTS_TAB} - tabContentRef={contentRefInsights} - aria-label='insights-tab' - /> - Curl} - tabContentId={CURL_TAB} - tabContentRef={contentRefCurl} - aria-label='curl-tab' - /> - Ansible} - tabContentId={ANSIBLE_TAB} - tabContentRef={contentRefAnsible} - aria-label='ansible-tab' - /> - -
- - - -
-
+ + Close + + } + > + + Insights (Preferred)} + tabContentId={INSIGHTS_TAB} + tabContentRef={contentRefInsights} + aria-label='insights-tab' + /> + Curl} + tabContentId={CURL_TAB} + tabContentRef={contentRefCurl} + aria-label='curl-tab' + /> + Ansible} + tabContentId={ANSIBLE_TAB} + tabContentRef={contentRefAnsible} + aria-label='ansible-tab' + /> + +
+ + +
- ) -} +
+
+ ); +}; -export default UseTemplateModal +export default UseTemplateModal; diff --git a/src/services/Content/ContentApi.ts b/src/services/Content/ContentApi.ts index 5f312f54..1c3b3f32 100644 --- a/src/services/Content/ContentApi.ts +++ b/src/services/Content/ContentApi.ts @@ -560,21 +560,21 @@ export const createUpload: (size: number, sha256: string) => Promise Promise = async ({ - chunkRange, - upload_uuid, - file, - sha256, -}) => { +export const uploadChunk: ( + chunkRequest: UploadChunkRequest, +) => [Promise, () => void] = ({ chunkRange, upload_uuid, file, sha256 }) => { const formData = new FormData(); + const controller = new AbortController(); + formData.set('file', file); formData.set('sha256', sha256); - const { data } = await axios.post( + const request = axios.post( `/api/content-sources/v1.0/repositories/uploads/${upload_uuid}/upload_chunk/`, formData, - { headers: { 'Content-Range': chunkRange } }, + { headers: { 'Content-Range': chunkRange }, signal: controller.signal }, ); - return data; + const abort = () => controller.abort(); + return [request as unknown as Promise, abort]; }; export const addUploads: (chunkRequest: AddUploadRequest) => Promise = async ({