From 2285ac5b509ee180d2a8e3dab6f047e73e79ca55 Mon Sep 17 00:00:00 2001 From: David Ormsbee Date: Wed, 10 Dec 2025 23:22:54 -0500 Subject: [PATCH 1/2] fix: support "in progress" status for lib upload When uploading a library archive file during the creation of a new library, the code prior to this commit did not properly handle the "In Progress" state, which is when the celery task doing the archive processing is actively running. Note that this is distinct from the "Pending" state, which is when the task is waiting in the queue to be run (which in practice should almost never happen unless there is an operational issue). Since celery tasks run in-process during local development, the task was always finished by the time that the browser made a call to check on the status. The problem only happened on slower sandboxes, where processing truly runs asynchronously and might take a few seconds. Because this case wasn't handled, the frontend would never poll for updates either, so the upload was basically lost as far as the user was concerned. --- .../create-library/CreateLibrary.tsx | 3 +- .../create-library/data/apiHooks.test.tsx | 28 +++++++++++++++++++ .../create-library/data/apiHooks.ts | 5 +++- .../create-library/data/restoreConstants.ts | 1 + 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/library-authoring/create-library/CreateLibrary.tsx b/src/library-authoring/create-library/CreateLibrary.tsx index 9bae528191..c9d67de91c 100644 --- a/src/library-authoring/create-library/CreateLibrary.tsx +++ b/src/library-authoring/create-library/CreateLibrary.tsx @@ -253,7 +253,8 @@ export const CreateLibrary = ({ {(restoreTaskId || isError || restoreMutation.isError) && (
- {restoreStatus?.state === LibraryRestoreStatus.Pending && ( + {(restoreStatus?.state === LibraryRestoreStatus.Pending + || restoreStatus?.state === LibraryRestoreStatus.InProgress) && ( {intl.formatMessage(messages.restoreInProgress)} diff --git a/src/library-authoring/create-library/data/apiHooks.test.tsx b/src/library-authoring/create-library/data/apiHooks.test.tsx index e4befed86d..0075bcac65 100644 --- a/src/library-authoring/create-library/data/apiHooks.test.tsx +++ b/src/library-authoring/create-library/data/apiHooks.test.tsx @@ -173,6 +173,34 @@ describe('create library apiHooks', () => { expect(axiosMock.history.get[0].url).toEqual(`http://localhost:18010/api/libraries/v2/restore/?task_id=${taskId}`); }); + it('should handle in-progress status with refetch interval', async () => { + const taskId = 'in-progress-task-id'; + const inProgressResult = { + state: LibraryRestoreStatus.InProgress, + result: null, + error: null, + error_log: null, + }; + + const expectedResult = { + state: LibraryRestoreStatus.InProgress, + result: null, + error: null, + errorLog: null, + }; + + axiosMock.onGet(`http://localhost:18010/api/libraries/v2/restore/?task_id=${taskId}`).reply(200, inProgressResult); + + const { result } = renderHook(() => useGetLibraryRestoreStatus(taskId), { wrapper }); + + await waitFor(() => { + expect(result.current.isLoading).toBeFalsy(); + }); + + expect(result.current.data).toEqual(expectedResult); + expect(axiosMock.history.get[0].url).toEqual(`http://localhost:18010/api/libraries/v2/restore/?task_id=${taskId}`); + }); + it('should handle failed status', async () => { const taskId = 'failed-task-id'; const failedResult = { diff --git a/src/library-authoring/create-library/data/apiHooks.ts b/src/library-authoring/create-library/data/apiHooks.ts index 9fac3edf75..1f53719684 100644 --- a/src/library-authoring/create-library/data/apiHooks.ts +++ b/src/library-authoring/create-library/data/apiHooks.ts @@ -41,7 +41,10 @@ export const useGetLibraryRestoreStatus = (taskId: string) => useQuery getLibraryRestoreStatus(taskId), enabled: !!taskId, // Only run the query if taskId is provided - refetchInterval: (query) => (query.state.data?.state === LibraryRestoreStatus.Pending ? 2000 : false), + refetchInterval: (query) => ( + (query.state.data?.state === LibraryRestoreStatus.Pending + || query.state.data?.state === LibraryRestoreStatus.InProgress + ) ? 2000 : false), }); export const useCreateLibraryRestore = () => useMutation({ diff --git a/src/library-authoring/create-library/data/restoreConstants.ts b/src/library-authoring/create-library/data/restoreConstants.ts index 323821e631..4545285cee 100644 --- a/src/library-authoring/create-library/data/restoreConstants.ts +++ b/src/library-authoring/create-library/data/restoreConstants.ts @@ -32,6 +32,7 @@ export interface GetLibraryRestoreStatusResponse { export enum LibraryRestoreStatus { Pending = 'Pending', + InProgress = 'In Progress', Succeeded = 'Succeeded', Failed = 'Failed', } From d77751764a3ac4fe17802735b019affdcf0b5ca2 Mon Sep 17 00:00:00 2001 From: Navin Karkera Date: Sat, 20 Dec 2025 06:06:31 +0530 Subject: [PATCH 2/2] feat: add temporary message alert in sections settings tab in libraries (#2734) (#2766) - add temporary message alert in sections settings tab in libraries - increase sidebar width to remove `More` option and display all tabs together (cherry picked from commit 3eeca244d76d78782a155cb1a2351c78e02b321c) --- src/library-authoring/LibraryAuthoringPage.scss | 2 +- src/library-authoring/containers/ContainerInfo.tsx | 14 ++++++++++++-- src/library-authoring/containers/messages.ts | 5 +++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/library-authoring/LibraryAuthoringPage.scss b/src/library-authoring/LibraryAuthoringPage.scss index 5a4470008c..5f0ceb7881 100644 --- a/src/library-authoring/LibraryAuthoringPage.scss +++ b/src/library-authoring/LibraryAuthoringPage.scss @@ -13,7 +13,7 @@ .library-authoring-sidebar { z-index: 1000; // same as header - flex: 500px 0 0; + flex: 530px 0 0; position: sticky; top: 0; right: 0; diff --git a/src/library-authoring/containers/ContainerInfo.tsx b/src/library-authoring/containers/ContainerInfo.tsx index d3d3afbd48..d2c7c4c78c 100644 --- a/src/library-authoring/containers/ContainerInfo.tsx +++ b/src/library-authoring/containers/ContainerInfo.tsx @@ -8,10 +8,11 @@ import { Icon, IconButton, useToggle, + Alert, } from '@openedx/paragon'; import React, { useCallback } from 'react'; import { Link } from 'react-router-dom'; -import { MoreVert } from '@openedx/paragon/icons'; +import { InfoOutline, MoreVert } from '@openedx/paragon/icons'; import { useClipboard } from '@src/generic/clipboard'; import { ContainerType, getBlockType } from '@src/generic/key-utils'; @@ -149,6 +150,15 @@ const ContainerActions = ({ ); }; +/* istanbul ignore next */ +/* istanbul ignore next */ +const ContainerSettings = () => ( + +

+ +

+
+); const ContainerInfo = () => { const intl = useIntl(); const { @@ -222,7 +232,7 @@ const ContainerInfo = () => { {renderTab( CONTAINER_INFO_TABS.Settings, intl.formatMessage(messages.settingsTabTitle), - // TODO: container settings component + , )} diff --git a/src/library-authoring/containers/messages.ts b/src/library-authoring/containers/messages.ts index f18da2c389..b4cbbc6fdc 100644 --- a/src/library-authoring/containers/messages.ts +++ b/src/library-authoring/containers/messages.ts @@ -66,6 +66,11 @@ const messages = defineMessages({ defaultMessage: 'Container actions menu', description: 'Alt/title text for the container card menu button.', }, + containerSettingsMsg: { + id: 'course-authoring.library-authoring.container.settings.alert.message', + defaultMessage: 'Section settings cannot be configured within Libraries and must be set within a course. In a future release, Libraries may support configuring some settings.', + description: 'Temporary message for settings tab being', + }, menuOpen: { id: 'course-authoring.library-authoring.menu.open', defaultMessage: 'Open',