diff --git a/plugins/course-apps/proctoring/messages.js b/plugins/course-apps/proctoring/messages.js index 82b147fc0..b5192c1fe 100644 --- a/plugins/course-apps/proctoring/messages.js +++ b/plugins/course-apps/proctoring/messages.js @@ -1,11 +1,6 @@ import { defineMessages } from '@edx/frontend-platform/i18n'; const messages = defineMessages({ - 'authoring.proctoring.alert.error': { - id: 'authoring.proctoring.alert.error', - defaultMessage: 'We encountered a technical error while trying to save proctored exam settings. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {support_link} for help.', - description: 'Alert message for proctoring settings save error.', - }, 'authoring.proctoring.alert.forbidden': { id: 'authoring.proctoring.alert.forbidden', defaultMessage: 'You do not have permission to edit proctored exam settings for this course. If you are a course team member and this problem persists, please go to the {support_link} for help.', diff --git a/src/course-libraries/messages.ts b/src/course-libraries/messages.ts index 8c817e3b2..efd3bb7a2 100644 --- a/src/course-libraries/messages.ts +++ b/src/course-libraries/messages.ts @@ -32,7 +32,7 @@ const messages = defineMessages({ description: 'Tab title for review tab', }, reviewTabDescriptionEmpty: { - id: 'course-authoring.course-libraries.tab.home.description-no-links', + id: 'course-authoring.course-libraries.tab.review.description-no-links', defaultMessage: 'All components are up to date', description: 'Description text for home tab', }, diff --git a/src/course-outline/card-header/CardHeader.test.tsx b/src/course-outline/card-header/CardHeader.test.tsx index 8adc35e9e..e542f94bb 100644 --- a/src/course-outline/card-header/CardHeader.test.tsx +++ b/src/course-outline/card-header/CardHeader.test.tsx @@ -7,6 +7,7 @@ import { import CardHeader from './CardHeader'; import TitleButton from './TitleButton'; import messages from './messages'; +import { RequestStatus } from '../../data/constants'; const onExpandMock = jest.fn(); const onClickMenuButtonMock = jest.fn(); @@ -232,16 +233,6 @@ describe('', () => { }); }); - it('check is field disabled when isDisabledEditField is true', async () => { - renderComponent({ - ...cardHeaderProps, - isFormOpen: true, - isDisabledEditField: true, - }); - - expect(await screen.findByTestId('subsection-edit-field')).toBeDisabled(); - }); - it('check editing is enabled when isDisabledEditField is false', async () => { renderComponent({ ...cardHeaderProps }); @@ -254,8 +245,8 @@ describe('', () => { expect(await screen.findByTestId('subsection-card-header__menu-manage-tags-button')).not.toHaveAttribute('aria-disabled'); }); - it('check editing is disabled when isDisabledEditField is true', async () => { - renderComponent({ ...cardHeaderProps, isDisabledEditField: true }); + it('check editing is disabled when saving is in progress', async () => { + renderComponent({ ...cardHeaderProps, savingStatus: RequestStatus.IN_PROGRESS }); expect(await screen.findByTestId('subsection-edit-button')).toBeDisabled(); diff --git a/src/course-outline/card-header/CardHeader.tsx b/src/course-outline/card-header/CardHeader.tsx index ba8870e3f..cd914c523 100644 --- a/src/course-outline/card-header/CardHeader.tsx +++ b/src/course-outline/card-header/CardHeader.tsx @@ -24,6 +24,7 @@ import { ContentTagsDrawerSheet } from '@src/content-tags-drawer'; import TagCount from '@src/generic/tag-count'; import { useEscapeClick } from '@src/hooks'; import { XBlockActions } from '@src/data/types'; +import { RequestStatus, RequestStatusType } from '@src/data/constants'; import { ITEM_BADGE_STATUS } from '../constants'; import { scrollToElement } from '../utils'; import CardStatus from './CardStatus'; @@ -41,7 +42,6 @@ interface CardHeaderProps { isFormOpen: boolean; onEditSubmit: (titleValue: string) => void; closeForm: () => void; - isDisabledEditField: boolean; onClickDelete: () => void; onClickUnlink: () => void; onClickDuplicate: () => void; @@ -69,6 +69,7 @@ interface CardHeaderProps { extraActionsComponent?: ReactNode, onClickSync?: () => void; readyToSync?: boolean; + savingStatus?: RequestStatusType; } const CardHeader = ({ @@ -83,7 +84,6 @@ const CardHeader = ({ isFormOpen, onEditSubmit, closeForm, - isDisabledEditField, onClickDelete, onClickUnlink, onClickDuplicate, @@ -103,6 +103,7 @@ const CardHeader = ({ extraActionsComponent, onClickSync, readyToSync, + savingStatus, }: CardHeaderProps) => { const intl = useIntl(); const [searchParams] = useSearchParams(); @@ -119,6 +120,7 @@ const CardHeader = ({ || status === ITEM_BADGE_STATUS.publishedNotLive) && !hasChanges; const { data: contentTagCount } = useContentTagsCount(cardId); + const isSaving = savingStatus === RequestStatus.IN_PROGRESS; useEffect(() => { const locatorId = searchParams.get('show'); @@ -172,7 +174,7 @@ const CardHeader = ({ onEditSubmit(titleValue); } }} - disabled={isDisabledEditField} + disabled={isSaving} /> ) : ( @@ -186,7 +188,7 @@ const CardHeader = ({ iconAs={EditIcon} onClick={onClickEdit} // @ts-ignore - disabled={isDisabledEditField} + disabled={isSaving} /> )} @@ -238,7 +240,7 @@ const CardHeader = ({ {intl.formatMessage(messages.menuConfigure)} @@ -246,7 +248,7 @@ const CardHeader = ({ {getConfig().ENABLE_TAGGING_TAXONOMY_PAGES === 'true' && ( {intl.formatMessage(messages.menuManageTags)} diff --git a/src/course-outline/section-card/SectionCard.test.tsx b/src/course-outline/section-card/SectionCard.test.tsx index 117ebe89c..ec73b0f2e 100644 --- a/src/course-outline/section-card/SectionCard.test.tsx +++ b/src/course-outline/section-card/SectionCard.test.tsx @@ -88,7 +88,6 @@ const renderComponent = (props?: object, entry = '/course/:courseId') => render( onOpenDeleteModal={jest.fn()} onOpenUnlinkModal={jest.fn()} onOpenConfigureModal={jest.fn()} - savingStatus="" onEditSectionSubmit={onEditSectionSubmit} onDuplicateSubmit={jest.fn()} isSectionsExpanded diff --git a/src/course-outline/section-card/SectionCard.tsx b/src/course-outline/section-card/SectionCard.tsx index 3bdafe683..7d615eaea 100644 --- a/src/course-outline/section-card/SectionCard.tsx +++ b/src/course-outline/section-card/SectionCard.tsx @@ -11,7 +11,7 @@ import classNames from 'classnames'; import { useQueryClient } from '@tanstack/react-query'; import { setCurrentItem, setCurrentSection } from '@src/course-outline/data/slice'; -import { RequestStatus } from '@src/data/constants'; +import { RequestStatus, RequestStatusType } from '@src/data/constants'; import CardHeader from '@src/course-outline/card-header/CardHeader'; import SortableItem from '@src/course-outline/drag-helper/SortableItem'; import { DragContext } from '@src/course-outline/drag-helper/DragContextProvider'; @@ -39,7 +39,7 @@ interface SectionCardProps { onOpenPublishModal: () => void, onOpenConfigureModal: () => void, onEditSectionSubmit: (itemId: string, sectionId: string, displayName: string) => void, - savingStatus: string, + savingStatus?: RequestStatusType, onOpenDeleteModal: () => void, onOpenUnlinkModal: () => void, onDuplicateSubmit: () => void, @@ -301,7 +301,7 @@ const SectionCard = ({ isFormOpen={isFormOpen} closeForm={closeForm} onEditSubmit={handleEditSubmit} - isDisabledEditField={savingStatus === RequestStatus.IN_PROGRESS} + savingStatus={savingStatus} onClickDuplicate={onDuplicateSubmit} titleComponent={titleComponent} namePrefix={namePrefix} diff --git a/src/course-outline/subsection-card/SubsectionCard.test.tsx b/src/course-outline/subsection-card/SubsectionCard.test.tsx index c8c3576bd..f3203671e 100644 --- a/src/course-outline/subsection-card/SubsectionCard.test.tsx +++ b/src/course-outline/subsection-card/SubsectionCard.test.tsx @@ -115,7 +115,6 @@ const renderComponent = (props?: object, entry = '/course/:courseId') => render( onNewUnitSubmit={jest.fn()} onAddUnitFromLibrary={handleOnAddUnitFromLibrary} isCustomRelativeDatesActive={false} - savingStatus="" onEditSubmit={onEditSubectionSubmit} onDuplicateSubmit={jest.fn()} onOpenConfigureModal={jest.fn()} diff --git a/src/course-outline/subsection-card/SubsectionCard.tsx b/src/course-outline/subsection-card/SubsectionCard.tsx index 8dda3ac94..2a9e654e8 100644 --- a/src/course-outline/subsection-card/SubsectionCard.tsx +++ b/src/course-outline/subsection-card/SubsectionCard.tsx @@ -11,7 +11,7 @@ import { isEmpty } from 'lodash'; import CourseOutlineSubsectionCardExtraActionsSlot from '@src/plugin-slots/CourseOutlineSubsectionCardExtraActionsSlot'; import { setCurrentItem, setCurrentSection, setCurrentSubsection } from '@src/course-outline/data/slice'; -import { RequestStatus } from '@src/data/constants'; +import { RequestStatus, RequestStatusType } from '@src/data/constants'; import CardHeader from '@src/course-outline/card-header/CardHeader'; import SortableItem from '@src/course-outline/drag-helper/SortableItem'; import { DragContext } from '@src/course-outline/drag-helper/DragContextProvider'; @@ -40,7 +40,7 @@ interface SubsectionCardProps { isCustomRelativeDatesActive: boolean, onOpenPublishModal: () => void, onEditSubmit: (itemId: string, sectionId: string, displayName: string) => void, - savingStatus: string, + savingStatus?: RequestStatusType, onOpenDeleteModal: () => void, onOpenUnlinkModal: () => void, onDuplicateSubmit: () => void, @@ -303,7 +303,7 @@ const SubsectionCard = ({ isFormOpen={isFormOpen} closeForm={closeForm} onEditSubmit={handleEditSubmit} - isDisabledEditField={savingStatus === RequestStatus.IN_PROGRESS} + savingStatus={savingStatus} onClickDuplicate={onDuplicateSubmit} titleComponent={titleComponent} namePrefix={namePrefix} diff --git a/src/course-outline/unit-card/UnitCard.test.tsx b/src/course-outline/unit-card/UnitCard.test.tsx index d6d5c15b4..e52ca99a1 100644 --- a/src/course-outline/unit-card/UnitCard.test.tsx +++ b/src/course-outline/unit-card/UnitCard.test.tsx @@ -81,7 +81,6 @@ const renderComponent = (props?: object) => render( onOpenDeleteModal={jest.fn()} onOpenUnlinkModal={jest.fn()} onOpenConfigureModal={jest.fn()} - savingStatus="" onEditSubmit={jest.fn()} onDuplicateSubmit={jest.fn()} getTitleLink={(id) => `/some/${id}`} diff --git a/src/course-outline/unit-card/UnitCard.tsx b/src/course-outline/unit-card/UnitCard.tsx index 69e9cbcf3..ebfe6ffcf 100644 --- a/src/course-outline/unit-card/UnitCard.tsx +++ b/src/course-outline/unit-card/UnitCard.tsx @@ -13,8 +13,7 @@ import { useQueryClient } from '@tanstack/react-query'; import CourseOutlineUnitCardExtraActionsSlot from '@src/plugin-slots/CourseOutlineUnitCardExtraActionsSlot'; import { setCurrentItem, setCurrentSection, setCurrentSubsection } from '@src/course-outline/data/slice'; import { fetchCourseSectionQuery } from '@src/course-outline/data/thunk'; -import { RequestStatus } from '@src/data/constants'; -import { isUnitReadOnly } from '@src/course-unit/data/utils'; +import { RequestStatus, RequestStatusType } from '@src/data/constants'; import CardHeader from '@src/course-outline/card-header/CardHeader'; import SortableItem from '@src/course-outline/drag-helper/SortableItem'; import TitleLink from '@src/course-outline/card-header/TitleLink'; @@ -33,7 +32,7 @@ interface UnitCardProps { onOpenPublishModal: () => void; onOpenConfigureModal: () => void; onEditSubmit: (itemId: string, sectionId: string, displayName: string) => void, - savingStatus: string; + savingStatus?: RequestStatusType; onOpenDeleteModal: () => void; onOpenUnlinkModal: () => void; onDuplicateSubmit: () => void; @@ -108,8 +107,6 @@ const UnitCard = ({ }; }, [upstreamInfo]); - const readOnly = isUnitReadOnly(unit); - // re-create actions object for customizations const actions = { ...unitActions }; // add actions to control display of move up & down menu buton. @@ -247,7 +244,7 @@ const UnitCard = ({ isFormOpen={isFormOpen} closeForm={closeForm} onEditSubmit={handleEditSubmit} - isDisabledEditField={readOnly || savingStatus === RequestStatus.IN_PROGRESS} + savingStatus={savingStatus} onClickDuplicate={onDuplicateSubmit} titleComponent={titleComponent} namePrefix={namePrefix} diff --git a/src/course-unit/CourseUnit.test.jsx b/src/course-unit/CourseUnit.test.jsx index 31c973255..8177f0165 100644 --- a/src/course-unit/CourseUnit.test.jsx +++ b/src/course-unit/CourseUnit.test.jsx @@ -2353,14 +2353,14 @@ describe('', () => { expect(screen.getByText(/this unit can only be edited from the \./i)).toBeInTheDocument(); - // Disable the "Edit" button + // Edit button should be enabled even for library imported units const unitHeaderTitle = screen.getByTestId('unit-header-title'); const editButton = within(unitHeaderTitle).getByRole( 'button', { name: 'Edit' }, ); expect(editButton).toBeInTheDocument(); - expect(editButton).toBeDisabled(); + expect(editButton).toBeEnabled(); // The "Publish" button should still be enabled const courseUnitSidebar = screen.getByTestId('course-unit-sidebar'); @@ -2371,14 +2371,6 @@ describe('', () => { expect(publishButton).toBeInTheDocument(); expect(publishButton).toBeEnabled(); - // Disable the "Manage Tags" button - const manageTagsButton = screen.getByRole( - 'button', - { name: tagsDrawerMessages.manageTagsButton.defaultMessage }, - ); - expect(manageTagsButton).toBeInTheDocument(); - expect(manageTagsButton).toBeDisabled(); - // Does not render the "Add Components" section expect(screen.queryByText(addComponentMessages.title.defaultMessage)).not.toBeInTheDocument(); }); diff --git a/src/course-unit/data/api.js b/src/course-unit/data/api.js index ba505c3dd..5c32cdde6 100644 --- a/src/course-unit/data/api.js +++ b/src/course-unit/data/api.js @@ -3,7 +3,7 @@ import { camelCaseObject, getConfig } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { PUBLISH_TYPES } from '../constants'; -import { isUnitReadOnly, normalizeCourseSectionVerticalData, updateXBlockBlockIdToId } from './utils'; +import { isUnitImportedFromLib, normalizeCourseSectionVerticalData, updateXBlockBlockIdToId } from './utils'; const getStudioBaseUrl = () => getConfig().STUDIO_BASE_URL; @@ -41,7 +41,7 @@ export async function getVerticalData(unitId) { .get(getCourseSectionVerticalApiUrl(unitId)); const courseSectionVerticalData = normalizeCourseSectionVerticalData(data); - courseSectionVerticalData.xblockInfo.readOnly = isUnitReadOnly(courseSectionVerticalData.xblockInfo); + courseSectionVerticalData.xblockInfo.readOnly = isUnitImportedFromLib(courseSectionVerticalData.xblockInfo); return courseSectionVerticalData; } diff --git a/src/course-unit/data/utils.ts b/src/course-unit/data/utils.ts index 94c457455..3cf46f903 100644 --- a/src/course-unit/data/utils.ts +++ b/src/course-unit/data/utils.ts @@ -102,7 +102,7 @@ export const updateXBlockBlockIdToId = (data: object): object => { * @param unit - uses the 'upstreamInfo' object if found. * @returns True if readOnly, False if editable. */ -export const isUnitReadOnly = ({ upstreamInfo }: XBlock): boolean => ( +export const isUnitImportedFromLib = ({ upstreamInfo }: XBlock): boolean => ( !!upstreamInfo && !!upstreamInfo.upstreamRef && upstreamInfo.upstreamRef.startsWith('lct:') diff --git a/src/course-unit/header-title/HeaderTitle.jsx b/src/course-unit/header-title/HeaderTitle.jsx index f87199e16..1bcb8a5c9 100644 --- a/src/course-unit/header-title/HeaderTitle.jsx +++ b/src/course-unit/header-title/HeaderTitle.jsx @@ -34,8 +34,6 @@ const HeaderTitle = ({ COURSE_BLOCK_NAMES.component.id, ].includes(currentItemData.category); - const readOnly = !!currentItemData.readOnly; - const onConfigureSubmit = (...arg) => { handleConfigureSubmit(currentItemData.id, ...arg, closeConfigureModal); }; @@ -82,7 +80,6 @@ const HeaderTitle = ({ className="ml-1 flex-shrink-0" iconAs={EditIcon} onClick={handleTitleEdit} - disabled={readOnly} /> ', () => { expect(getByRole('button', { name: messages.altButtonSettings.defaultMessage })).toBeEnabled(); }); - it('Units sourced from upstream show a disabled edit button', async () => { + it('Units sourced from upstream show a enabled edit button', async () => { // Override mock unit with one sourced from an upstream library axiosMock = new MockAdapter(getAuthenticatedHttpClient()); axiosMock @@ -95,7 +95,7 @@ describe('', () => { const { getByRole } = renderComponent(); - expect(getByRole('button', { name: messages.altButtonEdit.defaultMessage })).toBeDisabled(); + expect(getByRole('button', { name: messages.altButtonEdit.defaultMessage })).toBeEnabled(); expect(getByRole('button', { name: messages.altButtonSettings.defaultMessage })).toBeEnabled(); }); diff --git a/src/library-authoring/component-info/messages.ts b/src/library-authoring/component-info/messages.ts index bbbe3524b..d59d9d75d 100644 --- a/src/library-authoring/component-info/messages.ts +++ b/src/library-authoring/component-info/messages.ts @@ -37,7 +37,7 @@ const messages = defineMessages({ description: 'Button to save changes to the OLX', }, advancedDetailsOLXCancelButton: { - id: 'course-authoring.library-authoring.component.advanced.olx-save', + id: 'course-authoring.library-authoring.component.advanced.olx-cancel', defaultMessage: 'Cancel', description: 'Button to cancel changes to the OLX', }, diff --git a/src/library-authoring/components/messages.ts b/src/library-authoring/components/messages.ts index 0c5188c4e..5127793fe 100644 --- a/src/library-authoring/components/messages.ts +++ b/src/library-authoring/components/messages.ts @@ -41,11 +41,6 @@ const messages = defineMessages({ defaultMessage: 'Remove from collection', description: 'Menu item for remove a component from collection.', }, - menuRemoveFromContainer: { - id: 'course-authoring.library-authoring.component.menu.remove', - defaultMessage: 'Remove from {containerType}', - description: 'Menu item for remove an item from {containerType}.', - }, removeComponentFromCollectionSuccess: { id: 'course-authoring.library-authoring.component.remove-from-collection-success', defaultMessage: 'Item successfully removed', diff --git a/src/library-authoring/containers/messages.ts b/src/library-authoring/containers/messages.ts index e6e5f9987..44da1dfbf 100644 --- a/src/library-authoring/containers/messages.ts +++ b/src/library-authoring/containers/messages.ts @@ -122,7 +122,7 @@ const messages = defineMessages({ description: 'Title text for the warning displayed before deleting a Subsection', }, deleteSubsectionCourseMessaage: { - id: 'course-authoring.library-authoring.subsection.delete-parent-message', + id: 'course-authoring.library-authoring.subsection.delete-course-message', defaultMessage: 'This subsection is used {courseCount, plural, one {{courseCountText} time} other {{courseCountText} times}} in courses, and will stop receiving updates there.', description: 'Course usage details shown before deleting a subsection', }, diff --git a/src/library-authoring/library-info/messages.ts b/src/library-authoring/library-info/messages.ts index ff233548d..30f56009f 100644 --- a/src/library-authoring/library-info/messages.ts +++ b/src/library-authoring/library-info/messages.ts @@ -47,7 +47,7 @@ const messages = defineMessages({ description: 'Message when the library changes are reverted successfully.', }, revertErrorMsg: { - id: 'course-authoring.library-authoring.publish.error', + id: 'course-authoring.library-authoring.revert.error', defaultMessage: 'There was an error reverting changes in the library.', description: 'Message when there is an error when reverting changes in the library.', }, diff --git a/src/library-authoring/messages.ts b/src/library-authoring/messages.ts index 66e336c1d..69c167b3a 100644 --- a/src/library-authoring/messages.ts +++ b/src/library-authoring/messages.ts @@ -71,11 +71,6 @@ const messages = defineMessages({ defaultMessage: 'Coming soon!', description: 'Temp placeholder for the collections container. This will be replaced with the actual collection list.', }, - createLibrary: { - id: 'course-authoring.library-authoring.create-library', - defaultMessage: 'Create library', - description: 'Header for the create library form', - }, createLibraryTempPlaceholder: { id: 'course-authoring.library-authoring.create-library-temp-placeholder', defaultMessage: 'This is a placeholder for the create library form. This will be replaced with the actual form.',