From 8dfc215cc98c93b91cf31c2c03f98257a94083db Mon Sep 17 00:00:00 2001 From: XnpioChV Date: Tue, 22 Jul 2025 14:15:50 -0500 Subject: [PATCH 1/4] style: Fixing nits about sync units * Stay visible the sync icon in the course outline * Update the message in the sync unit modal * Add warning banner about units in the libraries sync page --- src/course-libraries/CourseLibraries.test.tsx | 8 ++++---- src/course-libraries/CourseLibraries.tsx | 9 ++++++++- src/course-libraries/messages.ts | 5 +++++ src/course-outline/card-header/CardHeader.jsx | 17 ++++++++--------- src/course-outline/unit-card/UnitCard.test.jsx | 4 ++-- .../component-comparison/messages.ts | 2 +- 6 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/course-libraries/CourseLibraries.test.tsx b/src/course-libraries/CourseLibraries.test.tsx index 4c44144246..486c995bd7 100644 --- a/src/course-libraries/CourseLibraries.test.tsx +++ b/src/course-libraries/CourseLibraries.test.tsx @@ -82,7 +82,7 @@ describe('', () => { expect(reviewTab).toHaveAttribute('aria-selected', 'true'); userEvent.click(allTab); - const alert = await screen.findByRole('alert'); + const alert = (await screen.findAllByRole('alert'))[0]; expect(await within(alert).findByText( '5 library components are out of sync. Review updates to accept or ignore changes', )).toBeInTheDocument(); @@ -105,7 +105,7 @@ describe('', () => { userEvent.click(allTab); expect(allTab).toHaveAttribute('aria-selected', 'true'); - const alert = await screen.findByRole('alert'); + const alert = (await screen.findAllByRole('alert'))[0]; expect(await within(alert).findByText( '5 library components are out of sync. Review updates to accept or ignore changes', )).toBeInTheDocument(); @@ -133,7 +133,7 @@ describe('', () => { expect(reviewTab).toHaveAttribute('aria-selected', 'true'); userEvent.click(allTab); - const alert = await screen.findByRole('alert'); + const alert = (await screen.findAllByRole('alert'))[0]; expect(await within(alert).findByText( '5 library components are out of sync. Review updates to accept or ignore changes', )).toBeInTheDocument(); @@ -156,7 +156,7 @@ describe('', () => { screen.logTestingPlaygroundURL(); - expect(screen.queryByRole('alert')).not.toBeInTheDocument(); + expect(screen.queryAllByRole('alert').length).toEqual(1); }); }); diff --git a/src/course-libraries/CourseLibraries.tsx b/src/course-libraries/CourseLibraries.tsx index 2d0cfadf0f..9298c5d2cb 100644 --- a/src/course-libraries/CourseLibraries.tsx +++ b/src/course-libraries/CourseLibraries.tsx @@ -17,7 +17,7 @@ import { Tabs, } from '@openedx/paragon'; import { - Cached, CheckCircle, Launch, Loop, + Cached, CheckCircle, Launch, Loop, Info, } from '@openedx/paragon/icons'; import sumBy from 'lodash/sumBy'; @@ -33,6 +33,7 @@ import { useStudioHome } from '../studio-home/hooks'; import NewsstandIcon from '../generic/NewsstandIcon'; import ReviewTabContent from './ReviewTabContent'; import { OutOfSyncAlert } from './OutOfSyncAlert'; +import AlertMessage from '../generic/alert-message'; interface Props { courseId: string; @@ -199,6 +200,12 @@ export const CourseLibraries: React.FC = ({ courseId }) => { showAlert={showReviewAlert && tabKey === CourseLibraryTabs.all} setShowAlert={setShowReviewAlert} /> + { /* TODO: Remove this alert after implement container in this page */} + {titleComponent} - {readyToSync && ( - - )} )} {extraActionsComponent} + {readyToSync && ( + + )} ', () => { // Should open compare preview modal expect(screen.getByRole('heading', { name: /preview changes: unit name/i })).toBeInTheDocument(); - expect(screen.getByText('Preview not available')).toBeInTheDocument(); + expect(screen.getByText('Preview not available for unit changes at this time')).toBeInTheDocument(); // Click on accept changes const acceptChangesButton = screen.getByText(/accept changes/i); @@ -196,7 +196,7 @@ describe('', () => { // Should open compare preview modal expect(screen.getByRole('heading', { name: /preview changes: unit name/i })).toBeInTheDocument(); - expect(screen.getByText('Preview not available')).toBeInTheDocument(); + expect(screen.getByText('Preview not available for unit changes at this time')).toBeInTheDocument(); // Click on ignore changes const ignoreChangesButton = screen.getByRole('button', { name: /ignore changes/i }); diff --git a/src/library-authoring/component-comparison/messages.ts b/src/library-authoring/component-comparison/messages.ts index 322eaee3a4..5a86fdaad5 100644 --- a/src/library-authoring/component-comparison/messages.ts +++ b/src/library-authoring/component-comparison/messages.ts @@ -19,7 +19,7 @@ const messages = defineMessages({ }, previewNotAvailable: { id: 'course-authoring.library-authoring.component-comparison.preview-not-available', - defaultMessage: 'Preview not available', + defaultMessage: 'Preview not available for unit changes at this time', description: 'Message shown when preview is not available.', }, }); From f834e24dea731dc4690c189c13ee124d4c180cfb Mon Sep 17 00:00:00 2001 From: XnpioChV Date: Fri, 1 Aug 2025 17:56:23 -0500 Subject: [PATCH 2/4] feat: Add tooltip to sync button & Add disable style to edit button --- src/course-outline/card-header/CardHeader.jsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/course-outline/card-header/CardHeader.jsx b/src/course-outline/card-header/CardHeader.jsx index 76e453eec8..0108f50461 100644 --- a/src/course-outline/card-header/CardHeader.jsx +++ b/src/course-outline/card-header/CardHeader.jsx @@ -10,6 +10,7 @@ import { Hyperlink, Icon, IconButton, + IconButtonWithTooltip, useToggle, } from '@openedx/paragon'; import { @@ -133,10 +134,12 @@ const CardHeader = ({ ) : ( <> {titleComponent} - {intl.formatMessage(messages.altButtonEdit)}} iconAs={EditIcon} onClick={onClickEdit} // @ts-ignore @@ -153,10 +156,11 @@ const CardHeader = ({ )} {extraActionsComponent} {readyToSync && ( - {intl.formatMessage(messages.readyToSyncButtonAlt)}} onClick={onClickSync} /> )} From a9e8b02737048181cfb0bbda1891e8ce4d7e4d42 Mon Sep 17 00:00:00 2001 From: XnpioChV Date: Mon, 11 Aug 2025 20:10:14 -0500 Subject: [PATCH 3/4] feat: Update unit from library edit button --- src/course-outline/card-header/CardHeader.jsx | 21 +++++++++++++++---- .../card-header/CardHeader.scss | 6 ++++++ src/course-outline/card-header/messages.js | 5 +++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/course-outline/card-header/CardHeader.jsx b/src/course-outline/card-header/CardHeader.jsx index 0108f50461..1eb9d0c0a8 100644 --- a/src/course-outline/card-header/CardHeader.jsx +++ b/src/course-outline/card-header/CardHeader.jsx @@ -1,6 +1,7 @@ // @ts-check import React, { useEffect, useRef, useState } from 'react'; import PropTypes from 'prop-types'; +import classNames from 'classnames'; import { getConfig } from '@edx/frontend-platform'; import { useIntl } from '@edx/frontend-platform/i18n'; import { useSearchParams } from 'react-router-dom'; @@ -135,11 +136,23 @@ const CardHeader = ({ <> {titleComponent} {intl.formatMessage(messages.altButtonEdit)}} + alt={intl.formatMessage( + isDisabledEditField ? messages.cannotEditTooltip : messages.altButtonEdit, + )} + tooltipContent={( +
+ {intl.formatMessage( + isDisabledEditField ? messages.cannotEditTooltip : messages.altButtonEdit, + )} +
+ )} iconAs={EditIcon} onClick={onClickEdit} // @ts-ignore diff --git a/src/course-outline/card-header/CardHeader.scss b/src/course-outline/card-header/CardHeader.scss index 8753847831..156b2838c1 100644 --- a/src/course-outline/card-header/CardHeader.scss +++ b/src/course-outline/card-header/CardHeader.scss @@ -25,6 +25,12 @@ &:hover { .item-card-button-icon { opacity: 1; + + &.item-card-button-icon-disabled { + pointer-events: all; + opacity: .5; + cursor: default; + } } } } diff --git a/src/course-outline/card-header/messages.js b/src/course-outline/card-header/messages.js index 4874525d5b..15d975d822 100644 --- a/src/course-outline/card-header/messages.js +++ b/src/course-outline/card-header/messages.js @@ -82,6 +82,11 @@ const messages = defineMessages({ defaultMessage: 'Update available - click to sync', description: 'Alt text for the sync icon button.', }, + cannotEditTooltip: { + id: 'course-authoring.course-outline.card.button.edit.disable.tooltip', + defaultMessage: 'This object was added from a library, so it cannot be edited.', + description: 'Tooltip text of button when the object was added from a library.', + }, }); export default messages; From d74bddf28ad24758d9df4cba988d1163913c616e Mon Sep 17 00:00:00 2001 From: XnpioChV Date: Wed, 27 Aug 2025 18:25:47 -0500 Subject: [PATCH 4/4] refactor: Change edit tooltip to rename --- src/course-outline/card-header/CardHeader.jsx | 4 ++-- src/course-outline/card-header/messages.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/course-outline/card-header/CardHeader.jsx b/src/course-outline/card-header/CardHeader.jsx index 1eb9d0c0a8..f47070cd9e 100644 --- a/src/course-outline/card-header/CardHeader.jsx +++ b/src/course-outline/card-header/CardHeader.jsx @@ -144,12 +144,12 @@ const CardHeader = ({ )} data-testid={`${namePrefix}-edit-button`} alt={intl.formatMessage( - isDisabledEditField ? messages.cannotEditTooltip : messages.altButtonEdit, + isDisabledEditField ? messages.cannotEditTooltip : messages.altButtonRename, )} tooltipContent={(
{intl.formatMessage( - isDisabledEditField ? messages.cannotEditTooltip : messages.altButtonEdit, + isDisabledEditField ? messages.cannotEditTooltip : messages.altButtonRename, )}
)} diff --git a/src/course-outline/card-header/messages.js b/src/course-outline/card-header/messages.js index 15d975d822..4933192d78 100644 --- a/src/course-outline/card-header/messages.js +++ b/src/course-outline/card-header/messages.js @@ -29,9 +29,9 @@ const messages = defineMessages({ id: 'course-authoring.course-outline.card.status-badge.draft-unpublished-changes', defaultMessage: 'Draft (Unpublished changes)', }, - altButtonEdit: { + altButtonRename: { id: 'course-authoring.course-outline.card.button.edit.alt', - defaultMessage: 'Edit', + defaultMessage: 'Rename', }, menuPublish: { id: 'course-authoring.course-outline.card.menu.publish',