From 62ae4b55ec153e8b8081c7e6ea72ffccab6ddeda Mon Sep 17 00:00:00 2001 From: Ihor Romaniuk Date: Tue, 23 Jan 2024 14:17:15 +0100 Subject: [PATCH 01/10] feat: [FC-0044] Unit page - display xblock components --- package-lock.json | 10 ++ src/course-outline/CourseOutline.jsx | 8 +- src/course-unit/CourseUnit.jsx | 17 ++- src/course-unit/CourseUnit.scss | 1 + src/course-unit/CourseUnit.test.jsx | 87 +++++++++++++- .../__mocks__/courseVerticalChildren.js | 15 +++ src/course-unit/__mocks__/index.js | 1 + .../course-xblock/CourseXBlock.jsx | 104 +++++++++++++++++ .../course-xblock/CourseXBlock.test.jsx | 108 ++++++++++++++++++ .../course-xblock/CourseXblock.scss | 15 +++ src/course-unit/course-xblock/messages.js | 34 ++++++ src/course-unit/data/api.js | 41 +++++++ src/course-unit/data/selectors.js | 1 + src/course-unit/data/slice.js | 28 +++++ src/course-unit/data/thunk.js | 64 ++++++++++- src/course-unit/hooks.jsx | 21 +++- .../delete-modal/DeleteModal.jsx | 11 +- .../delete-modal/DeleteModal.test.jsx | 7 +- .../delete-modal/messages.js | 0 src/i18n/messages/ar.json | 35 +++++- src/i18n/messages/de.json | 35 +++++- src/i18n/messages/de_DE.json | 35 +++++- src/i18n/messages/es_419.json | 35 +++++- src/i18n/messages/fa_IR.json | 35 +++++- src/i18n/messages/fr.json | 35 +++++- src/i18n/messages/fr_CA.json | 35 +++++- src/i18n/messages/hi.json | 35 +++++- src/i18n/messages/it.json | 35 +++++- src/i18n/messages/it_IT.json | 35 +++++- src/i18n/messages/pt.json | 35 +++++- src/i18n/messages/pt_PT.json | 35 +++++- src/i18n/messages/ru.json | 35 +++++- src/i18n/messages/uk.json | 35 +++++- src/i18n/messages/zh_CN.json | 35 +++++- 34 files changed, 1060 insertions(+), 38 deletions(-) create mode 100644 src/course-unit/__mocks__/courseVerticalChildren.js create mode 100644 src/course-unit/course-xblock/CourseXBlock.jsx create mode 100644 src/course-unit/course-xblock/CourseXBlock.test.jsx create mode 100644 src/course-unit/course-xblock/CourseXblock.scss create mode 100644 src/course-unit/course-xblock/messages.js rename src/{course-outline => generic}/delete-modal/DeleteModal.jsx (76%) rename src/{course-outline => generic}/delete-modal/DeleteModal.test.jsx (94%) rename src/{course-outline => generic}/delete-modal/messages.js (100%) diff --git a/package-lock.json b/package-lock.json index 2df108aad5..2f013f58d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21855,6 +21855,7 @@ } }, "plugins/course-apps/calculator": { + "name": "@openedx-plugins/course-app-calculator", "version": "0.1.0", "peerDependencies": { "@edx/frontend-app-course-authoring": "*", @@ -21870,6 +21871,7 @@ } }, "plugins/course-apps/edxnotes": { + "name": "@openedx-plugins/course-app-edxnotes", "version": "0.1.0", "peerDependencies": { "@edx/frontend-app-course-authoring": "*", @@ -21885,6 +21887,7 @@ } }, "plugins/course-apps/learning_assistant": { + "name": "@openedx-plugins/course-app-learning_assistant", "version": "0.1.0", "peerDependencies": { "@edx/frontend-app-course-authoring": "*", @@ -21901,6 +21904,7 @@ } }, "plugins/course-apps/live": { + "name": "@openedx-plugins/course-app-live", "version": "0.1.0", "peerDependencies": { "@edx/frontend-app-course-authoring": "*", @@ -21921,6 +21925,7 @@ } }, "plugins/course-apps/ora_settings": { + "name": "@openedx-plugins/course-app-ora_settings", "version": "0.1.0", "peerDependencies": { "@edx/frontend-app-course-authoring": "*", @@ -21937,6 +21942,7 @@ } }, "plugins/course-apps/proctoring": { + "name": "@openedx-plugins/course-app-proctoring", "version": "0.1.0", "peerDependencies": { "@edx/frontend-app-course-authoring": "*", @@ -21955,6 +21961,7 @@ } }, "plugins/course-apps/progress": { + "name": "@openedx-plugins/course-app-progress", "version": "0.1.0", "peerDependencies": { "@edx/frontend-app-course-authoring": "*", @@ -21971,6 +21978,7 @@ } }, "plugins/course-apps/teams": { + "name": "@openedx-plugins/course-app-teams", "version": "0.1.0", "peerDependencies": { "@edx/frontend-app-course-authoring": "*", @@ -21989,6 +21997,7 @@ } }, "plugins/course-apps/wiki": { + "name": "@openedx-plugins/course-app-wiki", "version": "0.1.0", "peerDependencies": { "@edx/frontend-app-course-authoring": "*", @@ -22005,6 +22014,7 @@ } }, "plugins/course-apps/xpert_unit_summary": { + "name": "@openedx-plugins/course-app-xpert_unit_summary", "version": "0.1.0", "peerDependencies": { "@edx/frontend-app-course-authoring": "*", diff --git a/src/course-outline/CourseOutline.jsx b/src/course-outline/CourseOutline.jsx index 986969ee56..5710fd01cd 100644 --- a/src/course-outline/CourseOutline.jsx +++ b/src/course-outline/CourseOutline.jsx @@ -24,8 +24,11 @@ import { RequestStatus } from '../data/constants'; import SubHeader from '../generic/sub-header/SubHeader'; import ProcessingNotification from '../generic/processing-notification'; import InternetConnectionAlert from '../generic/internet-connection-alert'; +import DeleteModal from '../generic/delete-modal/DeleteModal'; import AlertMessage from '../generic/alert-message'; import getPageHeadTitle from '../generic/utils'; +import { getCurrentItem } from './data/selectors'; +import { COURSE_BLOCK_NAMES } from './constants'; import HeaderNavigations from './header-navigations/HeaderNavigations'; import OutlineSideBar from './outline-sidebar/OutlineSidebar'; import StatusBar from './status-bar/StatusBar'; @@ -37,7 +40,6 @@ import HighlightsModal from './highlights-modal/HighlightsModal'; import EmptyPlaceholder from './empty-placeholder/EmptyPlaceholder'; import PublishModal from './publish-modal/PublishModal'; import ConfigureModal from './configure-modal/ConfigureModal'; -import DeleteModal from './delete-modal/DeleteModal'; import PageAlerts from './page-alerts/PageAlerts'; import { useCourseOutline } from './hooks'; import messages from './messages'; @@ -115,6 +117,9 @@ const CourseOutline = ({ courseId }) => { title: processingNotificationTitle, } = useSelector(getProcessingNotification); + const { category } = useSelector(getCurrentItem); + const deleteCategory = COURSE_BLOCK_NAMES[category]?.name.toLowerCase(); + const finalizeSectionOrder = () => (newSections) => { initialSections = [...sectionsList]; handleSectionDragAndDrop(newSections.map(section => section.id), () => { @@ -459,6 +464,7 @@ const CourseOutline = ({ courseId }) => { onConfigureSubmit={handleConfigureItemSubmit} /> { isTitleEditFormOpen, isErrorAlert, isInternetConnectionAlertFailed, + unitXBlockActions, handleTitleEditSubmit, headerNavigationsActions, handleTitleEdit, handleInternetConnectionFailed, handleCreateNewCourseXBlock, + courseVerticalChildren, } = useCourseUnit({ courseId, blockId }); document.title = getPageHeadTitle('', unitTitle); @@ -90,6 +93,18 @@ const CourseUnit = ({ courseId }) => { xl={[{ span: 9 }, { span: 3 }]} > + + {courseVerticalChildren.children.map(({ name, blockId: id, shouldScroll }) => ( + + ))} + ', () => { .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, courseSectionVerticalMock); await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); + axiosMock + .onGet(getCourseVerticalChildrenApiUrl(blockId)) + .reply(200, courseVerticalChildrenMock); + await executeThunk(fetchCourseVerticalChildrenData(blockId), store.dispatch); }); it('render CourseUnit component correctly', async () => { @@ -169,7 +179,7 @@ describe('', () => { await waitFor(() => { const videoButton = getByRole('button', { - name: new RegExp(`${messages.buttonText.defaultMessage} Video`, 'i'), + name: new RegExp(`${addComponentMessages.buttonText.defaultMessage} Video`, 'i'), }); userEvent.click(videoButton); @@ -186,7 +196,7 @@ describe('', () => { await waitFor(() => { const problemButton = getByRole('button', { - name: new RegExp(`${messages.buttonText.defaultMessage} Problem`, 'i'), + name: new RegExp(`${addComponentMessages.buttonText.defaultMessage} Problem`, 'i'), }); userEvent.click(problemButton); @@ -291,7 +301,7 @@ describe('', () => { await waitFor(() => { const videoButton = getByRole('button', { - name: new RegExp(`${messages.buttonText.defaultMessage} Video`, 'i'), + name: new RegExp(`${addComponentMessages.buttonText.defaultMessage} Video`, 'i'), }); userEvent.click(videoButton); @@ -299,4 +309,73 @@ describe('', () => { expect(mockedUsedNavigate).toHaveBeenCalledWith(`/course/${courseKey}/editor/video/${locator}`); }); }); + + it('checks whether xblock is deleted when corresponding delete button is clicked', async () => { + axiosMock + .onDelete(getXBlockBaseApiUrl(courseVerticalChildrenMock.children[0].block_id)) + .replyOnce(200, { dummy: 'value' }); + + const { + getByText, + getAllByLabelText, + getByRole, + getAllByTestId, + } = render(); + + await waitFor(() => { + expect(getByText(unitDisplayName)).toBeInTheDocument(); + const [xblockActionBtn] = getAllByLabelText(courseXBlockMessages.blockActionsDropdownAlt.defaultMessage); + userEvent.click(xblockActionBtn); + + const deleteBtn = getByRole('button', { name: courseXBlockMessages.blockLabelButtonDelete.defaultMessage }); + userEvent.click(deleteBtn); + expect(getByText(/Delete this component?/)).toBeInTheDocument(); + + const deleteConfirmBtn = getByRole('button', { name: deleteModalMessages.deleteButton.defaultMessage }); + userEvent.click(deleteConfirmBtn); + + expect(getAllByTestId('course-xblock')).toHaveLength(1); + }); + }); + + it('checks whether xblock is duplicate when corresponding delete button is clicked', async () => { + axiosMock + .onPost(postXBlockBaseApiUrl({ + parent_locator: blockId, + duplicate_source_locator: courseVerticalChildrenMock.children[0].block_id, + })) + .replyOnce(200, { locator: '1234567890' }); + + axiosMock + .onGet(getCourseVerticalChildrenApiUrl(blockId)) + .reply(200, { + ...courseVerticalChildrenMock, + children: [ + ...courseVerticalChildrenMock.children, + { + name: 'New Cloned XBlock', + block_id: '1234567890', + block_type: 'drag-and-drop-v2', + }, + ], + }); + + const { + getByText, + getAllByLabelText, + getAllByTestId, + } = render(); + + await waitFor(() => { + expect(getByText(unitDisplayName)).toBeInTheDocument(); + const [xblockActionBtn] = getAllByLabelText(courseXBlockMessages.blockActionsDropdownAlt.defaultMessage); + userEvent.click(xblockActionBtn); + + const duplicateBtn = getByText(courseXBlockMessages.blockLabelButtonDuplicate.defaultMessage); + userEvent.click(duplicateBtn); + + expect(getAllByTestId('course-xblock')).toHaveLength(3); + expect(getByText('New Cloned XBlock')).toBeInTheDocument(); + }); + }); }); diff --git a/src/course-unit/__mocks__/courseVerticalChildren.js b/src/course-unit/__mocks__/courseVerticalChildren.js new file mode 100644 index 0000000000..8c3651ba6c --- /dev/null +++ b/src/course-unit/__mocks__/courseVerticalChildren.js @@ -0,0 +1,15 @@ +module.exports = { + children: [ + { + name: 'Discussion', + block_id: 'block-v1:edX+L153+3T2023+type@discussion+block@fecd20842dd24f50bdc06643e791b013', + block_type: 'discussion', + }, + { + name: 'Drag and Drop', + block_id: 'block-v1:edX+L153+3T2023+type@drag-and-drop-v2+block@b33cf1f6df4c41639659bc91132eeb02', + block_type: 'drag-and-drop-v2', + }, + ], + is_published: false, +}; diff --git a/src/course-unit/__mocks__/index.js b/src/course-unit/__mocks__/index.js index cd5c4ffdfe..d8c220b7a4 100644 --- a/src/course-unit/__mocks__/index.js +++ b/src/course-unit/__mocks__/index.js @@ -2,3 +2,4 @@ export { default as courseUnitIndexMock } from './courseUnitIndex'; export { default as courseSectionVerticalMock } from './courseSectionVertical'; export { default as courseUnitMock } from './courseUnit'; export { default as courseCreateXblockMock } from './courseCreateXblock'; +export { default as courseVerticalChildrenMock } from './courseVerticalChildren'; diff --git a/src/course-unit/course-xblock/CourseXBlock.jsx b/src/course-unit/course-xblock/CourseXBlock.jsx new file mode 100644 index 0000000000..bd8a11ebfc --- /dev/null +++ b/src/course-unit/course-xblock/CourseXBlock.jsx @@ -0,0 +1,104 @@ +import { useEffect, useRef } from 'react'; +import PropTypes from 'prop-types'; +import { + ActionRow, Card, Dropdown, Icon, IconButton, useToggle, +} from '@openedx/paragon'; +import { EditOutline as EditIcon, MoreVert as MoveVertIcon } from '@openedx/paragon/icons'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import DeleteModal from '../../generic/delete-modal/DeleteModal'; +import { scrollToElement } from '../../course-outline/utils'; +import messages from './messages'; + +const CourseXBlock = ({ + id, title, unitXBlockActions, shouldScroll, ...props +}) => { + const courseXBlockElementRef = useRef(null); + const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useToggle(false); + const intl = useIntl(); + + const onXBlockDelete = () => { + unitXBlockActions.handleDelete(id); + closeDeleteModal(); + }; + + useEffect(() => { + // if this item has been newly added, scroll to it. + if (courseXBlockElementRef.current && shouldScroll) { + scrollToElement(courseXBlockElementRef.current); + } + }, []); + + return ( +
+ + + {}} + /> + + + + + {intl.formatMessage(messages.blockLabelButtonCopy)} + + unitXBlockActions.handleDuplicate(id)}> + {intl.formatMessage(messages.blockLabelButtonDuplicate)} + + + {intl.formatMessage(messages.blockLabelButtonMove)} + + + {intl.formatMessage(messages.blockLabelButtonManageAccess)} + + + {intl.formatMessage(messages.blockLabelButtonDelete)} + + + + + + )} + size="md" + /> + +
+ + +
+ ); +}; + +CourseXBlock.defaultProps = { + shouldScroll: false, +}; + +CourseXBlock.propTypes = { + id: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + shouldScroll: PropTypes.bool, + unitXBlockActions: PropTypes.shape({ + handleDelete: PropTypes.func, + handleDuplicate: PropTypes.func, + }).isRequired, +}; + +export default CourseXBlock; diff --git a/src/course-unit/course-xblock/CourseXBlock.test.jsx b/src/course-unit/course-xblock/CourseXBlock.test.jsx new file mode 100644 index 0000000000..2c6defc766 --- /dev/null +++ b/src/course-unit/course-xblock/CourseXBlock.test.jsx @@ -0,0 +1,108 @@ +import { render, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { initializeMockApp } from '@edx/frontend-platform'; +import { AppProvider } from '@edx/frontend-platform/react'; + +import { courseVerticalChildrenMock } from '../__mocks__'; +import CourseXBlock from './CourseXBlock'; + +import deleteModalMessages from '../../generic/delete-modal/messages'; +import messages from './messages'; + +let store; +const handleDeleteMock = jest.fn(); +const handleDuplicateMock = jest.fn(); +const xblockData = courseVerticalChildrenMock.children[0]; +const unitXBlockActionsMock = { + handleDelete: handleDeleteMock, + handleDuplicate: handleDuplicateMock, +}; + +const renderComponent = () => render( + + + + + , +); + +describe('', () => { + beforeEach(async () => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + }); + + it('render CourseXBlock component correctly', async () => { + const { getByText, getByLabelText } = renderComponent(); + + await waitFor(() => { + expect(getByText(xblockData.block_id)).toBeInTheDocument(); + expect(getByLabelText(messages.blockAltButtonEdit.defaultMessage)).toBeInTheDocument(); + expect(getByLabelText(messages.blockActionsDropdownAlt.defaultMessage)).toBeInTheDocument(); + }); + }); + + it('render CourseXBlock component action dropdown correctly', async () => { + const { getByRole, getByLabelText } = renderComponent(); + + await waitFor(() => { + userEvent.click(getByLabelText(messages.blockActionsDropdownAlt.defaultMessage)); + expect(getByRole('button', { name: messages.blockLabelButtonCopy.defaultMessage })).toBeInTheDocument(); + expect(getByRole('button', { name: messages.blockLabelButtonDuplicate.defaultMessage })).toBeInTheDocument(); + expect(getByRole('button', { name: messages.blockLabelButtonMove.defaultMessage })).toBeInTheDocument(); + expect(getByRole('button', { name: messages.blockLabelButtonManageAccess.defaultMessage })).toBeInTheDocument(); + expect(getByRole('button', { name: messages.blockLabelButtonDelete.defaultMessage })).toBeInTheDocument(); + }); + }); + + it('calls handleDuplicate when item is clicked', async () => { + const { getByText, getByLabelText } = renderComponent(); + + await waitFor(() => { + userEvent.click(getByLabelText(messages.blockActionsDropdownAlt.defaultMessage)); + const duplicateBtn = getByText(messages.blockLabelButtonDuplicate.defaultMessage); + + userEvent.click(duplicateBtn); + expect(handleDuplicateMock).toHaveBeenCalledTimes(1); + expect(handleDuplicateMock).toHaveBeenCalledWith(xblockData.block_id); + }); + }); + + it('opens confirm delete modal and calls handleDelete when deleting was confirmed', async () => { + const { getByText, getByLabelText, getByRole } = renderComponent(); + + await waitFor(() => { + userEvent.click(getByLabelText(messages.blockActionsDropdownAlt.defaultMessage)); + const deleteBtn = getByText(messages.blockLabelButtonDelete.defaultMessage); + + userEvent.click(deleteBtn); + expect(getByText(/Delete this component?/)).toBeInTheDocument(); + expect(getByText(/Deleting this component is permanent and cannot be undone./)).toBeInTheDocument(); + expect(getByRole('button', { name: deleteModalMessages.cancelButton.defaultMessage })).toBeInTheDocument(); + expect(getByRole('button', { name: deleteModalMessages.deleteButton.defaultMessage })).toBeInTheDocument(); + + userEvent.click(getByRole('button', { name: deleteModalMessages.cancelButton.defaultMessage })); + expect(handleDeleteMock).not.toHaveBeenCalled(); + + userEvent.click(getByText(messages.blockLabelButtonDelete.defaultMessage)); + expect(getByText(/Delete this component?/)).toBeInTheDocument(); + + userEvent.click(deleteBtn); + userEvent.click(getByRole('button', { name: deleteModalMessages.deleteButton.defaultMessage })); + expect(handleDeleteMock).toHaveBeenCalled(); + expect(handleDeleteMock).toHaveBeenCalledWith(xblockData.block_id); + }); + }); +}); diff --git a/src/course-unit/course-xblock/CourseXblock.scss b/src/course-unit/course-xblock/CourseXblock.scss new file mode 100644 index 0000000000..52c8e0bef5 --- /dev/null +++ b/src/course-unit/course-xblock/CourseXblock.scss @@ -0,0 +1,15 @@ +.course-unit { + .pgn__card .pgn__card-header { + border-bottom: 1px solid $light-400; + padding-bottom: map-get($spacers, 2); + + .pgn__card-header-content { + margin-top: map-get($spacers, 3\.5); + } + + .btn-icon .btn-icon__icon { + width: 1.5rem; + height: 1.5rem; + } + } +} diff --git a/src/course-unit/course-xblock/messages.js b/src/course-unit/course-xblock/messages.js new file mode 100644 index 0000000000..80e25dac13 --- /dev/null +++ b/src/course-unit/course-xblock/messages.js @@ -0,0 +1,34 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + blockAltButtonEdit: { + id: 'course-authoring.course-unit.xblock.button.edit.alt', + defaultMessage: 'Edit Item', + }, + blockActionsDropdownAlt: { + id: 'course-authoring.course-unit.xblock.button.actions.alt', + defaultMessage: 'Actions', + }, + blockLabelButtonCopy: { + id: 'course-authoring.course-unit.xblock.button.copy.label', + defaultMessage: 'Copy', + }, + blockLabelButtonDuplicate: { + id: 'course-authoring.course-unit.xblock.button.duplicate.label', + defaultMessage: 'Duplicate', + }, + blockLabelButtonMove: { + id: 'course-authoring.course-unit.xblock.button.move.label', + defaultMessage: 'Move', + }, + blockLabelButtonManageAccess: { + id: 'course-authoring.course-unit.xblock.button.manageAccess.label', + defaultMessage: 'Manage access', + }, + blockLabelButtonDelete: { + id: 'course-authoring.course-unit.xblock.button.delete.label', + defaultMessage: 'Delete', + }, +}); + +export default messages; diff --git a/src/course-unit/data/api.js b/src/course-unit/data/api.js index 5e1e5158a6..43992f576d 100644 --- a/src/course-unit/data/api.js +++ b/src/course-unit/data/api.js @@ -19,6 +19,7 @@ export const getCourseSectionVerticalApiUrl = (itemId) => `${getStudioBaseUrl()} export const getLearningSequencesOutlineApiUrl = (courseId) => `${getLmsBaseUrl()}/api/learning_sequences/v1/course_outline/${courseId}`; export const getCourseMetadataApiUrl = (courseId) => `${getLmsBaseUrl()}/api/courseware/course/${courseId}`; export const getCourseHomeCourseMetadataApiUrl = (courseId) => `${getLmsBaseUrl()}/api/course_home/course_metadata/${courseId}`; +export const getCourseVerticalChildrenApiUrl = (itemId) => `${getStudioBaseUrl()}/api/contentstore/v1/container/vertical/${itemId}/children`; export const postXBlockBaseApiUrl = () => `${getStudioBaseUrl()}/xblock/`; @@ -128,3 +129,43 @@ export async function createCourseXblock({ return data; } + +/** + * Get an object containing course section vertical children data. + * @param {string} itemId + * @returns {Promise} + */ +export async function getCourseVerticalChildren(itemId) { + const { data } = await getAuthenticatedHttpClient() + .get(getCourseVerticalChildrenApiUrl(itemId)); + + return camelCaseObject(data); +} + +/** + * Delete a unit item. + * @param {string} itemId + * @returns {Promise} + */ +export async function deleteUnitItem(itemId) { + const { data } = await getAuthenticatedHttpClient() + .delete(getXBlockBaseApiUrl(itemId)); + + return data; +} + +/** + * Duplicate a unit item. + * @param {string} itemId + * @param {string} XBlockId + * @returns {Promise} + */ +export async function duplicateUnitItem(itemId, XBlockId) { + const { data } = await getAuthenticatedHttpClient() + .post(postXBlockBaseApiUrl(), { + parent_locator: itemId, + duplicate_source_locator: XBlockId, + }); + + return data; +} diff --git a/src/course-unit/data/selectors.js b/src/course-unit/data/selectors.js index a5a1eb95b6..5fa52ac1b4 100644 --- a/src/course-unit/data/selectors.js +++ b/src/course-unit/data/selectors.js @@ -16,6 +16,7 @@ export const getCoursewareMeta = state => state.models.coursewareMeta; export const getSections = state => state.models.sections; export const getCourseId = state => state.courseDetail.courseId; export const getSequenceId = state => state.courseUnit.sequenceId; +export const getCourseVerticalChildren = state => state.courseUnit.courseVerticalChildren; export const sequenceIdsSelector = createSelector( [getCourseStatus, getCoursewareMeta, getSections, getCourseId], (courseStatus, coursewareMeta, sections, courseId) => { diff --git a/src/course-unit/data/slice.js b/src/course-unit/data/slice.js index 7f243c5110..bd4066afcc 100644 --- a/src/course-unit/data/slice.js +++ b/src/course-unit/data/slice.js @@ -12,9 +12,11 @@ const slice = createSlice({ loadingStatus: { fetchUnitLoadingStatus: RequestStatus.IN_PROGRESS, courseSectionVerticalLoadingStatus: RequestStatus.IN_PROGRESS, + courseVerticalChildrenLoadingStatus: RequestStatus.IN_PROGRESS, }, unit: {}, courseSectionVertical: {}, + courseVerticalChildren: [], }, reducers: { fetchCourseItemSuccess: (state, { payload }) => { @@ -87,6 +89,28 @@ const slice = createSlice({ fetchUnitLoadingStatus: payload.status, }; }, + updateCourseVerticalChildren: (state, { payload }) => { + state.courseVerticalChildren = payload; + }, + updateCourseVerticalChildrenLoadingStatus: (state, { payload }) => { + state.loadingStatus.courseVerticalChildrenLoadingStatus = payload.status; + }, + deleteXBlock: (state, { payload }) => { + state.courseVerticalChildren.children = state.courseVerticalChildren.children.filter( + (component) => component.blockId !== payload, + ); + }, + duplicateXBlock: (state, { payload }) => { + state.courseVerticalChildren = { + ...payload.newCourseVerticalChildren, + children: payload.newCourseVerticalChildren.children.map((component) => { + if (component.blockId === payload.newId) { + component.shouldScroll = true; + } + return component; + }), + }; + }, }, }); @@ -107,6 +131,10 @@ export const { changeEditTitleFormOpen, updateQueryPendingStatus, updateLoadingCourseXblockStatus, + updateCourseVerticalChildren, + updateCourseVerticalChildrenLoadingStatus, + deleteXBlock, + duplicateXBlock, } = slice.actions; export const { diff --git a/src/course-unit/data/thunk.js b/src/course-unit/data/thunk.js index defb940cd6..b6e2477849 100644 --- a/src/course-unit/data/thunk.js +++ b/src/course-unit/data/thunk.js @@ -17,6 +17,9 @@ import { getCourseHomeCourseMetadata, getCourseSectionVerticalData, createCourseXblock, + getCourseVerticalChildren, + deleteUnitItem, + duplicateUnitItem, } from './api'; import { updateLoadingCourseUnitStatus, @@ -32,6 +35,10 @@ import { fetchCourseSectionVerticalDataSuccess, updateLoadingCourseSectionVerticalDataStatus, updateLoadingCourseXblockStatus, + updateCourseVerticalChildren, + updateCourseVerticalChildrenLoadingStatus, + deleteXBlock, + duplicateXBlock, } from './slice'; export function fetchCourseUnitQuery(courseId) { @@ -192,7 +199,7 @@ export function fetchCourse(courseId) { }; } -export function createNewCourseXblock(body, callback) { +export function createNewCourseXBlock(body, callback, blockId) { return async (dispatch) => { dispatch(updateLoadingCourseXblockStatus({ status: RequestStatus.IN_PROGRESS })); dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.adding)); @@ -205,7 +212,8 @@ export function createNewCourseXblock(body, callback) { const courseSectionVerticalData = await getCourseSectionVerticalData(result.locator); dispatch(fetchCourseSectionVerticalDataSuccess(courseSectionVerticalData)); } - // ToDo: implement fetching (update) xblocks after success creating + const courseVerticalChildrenData = await getCourseVerticalChildren(blockId); + dispatch(updateCourseVerticalChildren(courseVerticalChildrenData)); dispatch(hideProcessingNotification()); dispatch(updateLoadingCourseXblockStatus({ status: RequestStatus.SUCCESSFUL })); dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); @@ -221,3 +229,55 @@ export function createNewCourseXblock(body, callback) { } }; } + +export function fetchCourseVerticalChildrenData(itemId) { + return async (dispatch) => { + dispatch(updateCourseVerticalChildrenLoadingStatus({ status: RequestStatus.IN_PROGRESS })); + + try { + const courseVerticalChildrenData = await getCourseVerticalChildren(itemId); + dispatch(updateCourseVerticalChildren(courseVerticalChildrenData)); + dispatch(updateCourseVerticalChildrenLoadingStatus({ status: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(updateCourseVerticalChildrenLoadingStatus({ status: RequestStatus.FAILED })); + } + }; +} + +export function deleteUnitItemQuery(itemId, xblockId) { + return async (dispatch) => { + dispatch(updateSavingStatus({ status: RequestStatus.PENDING })); + dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.deleting)); + + try { + await deleteUnitItem(xblockId); + dispatch(deleteXBlock(xblockId)); + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatus({ status: RequestStatus.FAILED })); + } + }; +} + +export function duplicateUnitItemQuery(itemId, xblockId) { + return async (dispatch) => { + dispatch(updateSavingStatus({ status: RequestStatus.PENDING })); + dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.duplicating)); + + try { + const { locator } = await duplicateUnitItem(itemId, xblockId); + const newCourseVerticalChildren = await getCourseVerticalChildren(itemId); + dispatch(duplicateXBlock({ + newId: locator, + newCourseVerticalChildren, + })); + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatus({ status: RequestStatus.FAILED })); + } + }; +} diff --git a/src/course-unit/hooks.jsx b/src/course-unit/hooks.jsx index 7c7a01fc93..b99bfaed1a 100644 --- a/src/course-unit/hooks.jsx +++ b/src/course-unit/hooks.jsx @@ -4,14 +4,18 @@ import { useNavigate } from 'react-router-dom'; import { RequestStatus } from '../data/constants'; import { - createNewCourseXblock, + createNewCourseXBlock, fetchCourseUnitQuery, editCourseItemQuery, fetchCourse, fetchCourseSectionVerticalData, + fetchCourseVerticalChildrenData, + deleteUnitItemQuery, + duplicateUnitItemQuery, } from './data/thunk'; import { getCourseSectionVertical, + getCourseVerticalChildren, getCourseUnitData, getLoadingStatus, getSavingStatus, @@ -28,6 +32,7 @@ export const useCourseUnit = ({ courseId, blockId }) => { const savingStatus = useSelector(getSavingStatus); const loadingStatus = useSelector(getLoadingStatus); const { draftPreviewLink, publishedPreviewLink } = useSelector(getCourseSectionVertical); + const courseVerticalChildren = useSelector(getCourseVerticalChildren); const navigate = useNavigate(); const isTitleEditFormOpen = useSelector(state => state.courseUnit.isTitleEditFormOpen); const isQueryPending = useSelector(state => state.courseUnit.isQueryPending); @@ -67,9 +72,18 @@ export const useCourseUnit = ({ courseId, blockId }) => { }; const handleCreateNewCourseXBlock = (body, callback) => ( - dispatch(createNewCourseXblock(body, callback)) + dispatch(createNewCourseXBlock(body, callback, blockId)) ); + const unitXBlockActions = { + handleDelete: (XBlockId) => { + dispatch(deleteUnitItemQuery(blockId, XBlockId)); + }, + handleDuplicate: (XBlockId) => { + dispatch(duplicateUnitItemQuery(blockId, XBlockId)); + }, + }; + useEffect(() => { if (savingStatus === RequestStatus.SUCCESSFUL) { dispatch(updateQueryPendingStatus(false)); @@ -81,6 +95,7 @@ export const useCourseUnit = ({ courseId, blockId }) => { useEffect(() => { dispatch(fetchCourseUnitQuery(blockId)); dispatch(fetchCourseSectionVerticalData(blockId, sequenceId)); + dispatch(fetchCourseVerticalChildrenData(blockId)); dispatch(fetchCourse(courseId)); handleNavigate(sequenceId); @@ -98,9 +113,11 @@ export const useCourseUnit = ({ courseId, blockId }) => { isTitleEditFormOpen, isInternetConnectionAlertFailed: savingStatus === RequestStatus.FAILED, handleInternetConnectionFailed, + unitXBlockActions, headerNavigationsActions, handleTitleEdit, handleTitleEditSubmit, handleCreateNewCourseXBlock, + courseVerticalChildren, }; }; diff --git a/src/course-outline/delete-modal/DeleteModal.jsx b/src/generic/delete-modal/DeleteModal.jsx similarity index 76% rename from src/course-outline/delete-modal/DeleteModal.jsx rename to src/generic/delete-modal/DeleteModal.jsx index eff6cb3176..1f9ebc286f 100644 --- a/src/course-outline/delete-modal/DeleteModal.jsx +++ b/src/generic/delete-modal/DeleteModal.jsx @@ -1,21 +1,17 @@ -import React from 'react'; import PropTypes from 'prop-types'; import { ActionRow, Button, AlertModal, } from '@openedx/paragon'; -import { useSelector } from 'react-redux'; import { useIntl } from '@edx/frontend-platform/i18n'; -import { COURSE_BLOCK_NAMES } from '../constants'; -import { getCurrentItem } from '../data/selectors'; import messages from './messages'; -const DeleteModal = ({ isOpen, close, onDeleteSubmit }) => { +const DeleteModal = ({ + category, isOpen, close, onDeleteSubmit, +}) => { const intl = useIntl(); - let { category } = useSelector(getCurrentItem); - category = COURSE_BLOCK_NAMES[category]?.name.toLowerCase(); return ( { DeleteModal.propTypes = { isOpen: PropTypes.bool.isRequired, close: PropTypes.func.isRequired, + category: PropTypes.string.isRequired, onDeleteSubmit: PropTypes.func.isRequired, }; diff --git a/src/course-outline/delete-modal/DeleteModal.test.jsx b/src/generic/delete-modal/DeleteModal.test.jsx similarity index 94% rename from src/course-outline/delete-modal/DeleteModal.test.jsx rename to src/generic/delete-modal/DeleteModal.test.jsx index e03e4a4b8b..5edf101f81 100644 --- a/src/course-outline/delete-modal/DeleteModal.test.jsx +++ b/src/generic/delete-modal/DeleteModal.test.jsx @@ -1,7 +1,6 @@ import React from 'react'; import { render, fireEvent } from '@testing-library/react'; import { IntlProvider } from '@edx/frontend-platform/i18n'; -import { useSelector } from 'react-redux'; import { initializeMockApp } from '@edx/frontend-platform'; import MockAdapter from 'axios-mock-adapter'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; @@ -30,16 +29,13 @@ jest.mock('@edx/frontend-platform/i18n', () => ({ }), })); -const currentItemMock = { - displayName: 'Delete', -}; - const renderComponent = (props) => render( @@ -60,7 +56,6 @@ describe('', () => { store = initializeStore(); axiosMock = new MockAdapter(getAuthenticatedHttpClient()); - useSelector.mockReturnValue(currentItemMock); }); it('render DeleteModal component correctly', () => { diff --git a/src/course-outline/delete-modal/messages.js b/src/generic/delete-modal/messages.js similarity index 100% rename from src/course-outline/delete-modal/messages.js rename to src/generic/delete-modal/messages.js diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index b7f55cd56d..57a247dbfa 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -1013,5 +1013,38 @@ "course-authoring.course-unit.add.component.button.text": "Add Component:", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index e3311ad17a..e06d421e34 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -1013,5 +1013,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/de_DE.json b/src/i18n/messages/de_DE.json index 5b567106ab..5ad4d1441d 100644 --- a/src/i18n/messages/de_DE.json +++ b/src/i18n/messages/de_DE.json @@ -1013,5 +1013,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/es_419.json b/src/i18n/messages/es_419.json index 29a33d6318..979df0d74d 100644 --- a/src/i18n/messages/es_419.json +++ b/src/i18n/messages/es_419.json @@ -1013,5 +1013,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/fa_IR.json b/src/i18n/messages/fa_IR.json index 423f64688a..1252d8c29d 100644 --- a/src/i18n/messages/fa_IR.json +++ b/src/i18n/messages/fa_IR.json @@ -36,5 +36,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index 8a81812490..003397d4db 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -1013,5 +1013,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/fr_CA.json b/src/i18n/messages/fr_CA.json index dc8f5d57fa..0b0f31624f 100644 --- a/src/i18n/messages/fr_CA.json +++ b/src/i18n/messages/fr_CA.json @@ -1013,5 +1013,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/hi.json b/src/i18n/messages/hi.json index e3311ad17a..e06d421e34 100644 --- a/src/i18n/messages/hi.json +++ b/src/i18n/messages/hi.json @@ -1013,5 +1013,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/it.json b/src/i18n/messages/it.json index e3311ad17a..e06d421e34 100644 --- a/src/i18n/messages/it.json +++ b/src/i18n/messages/it.json @@ -1013,5 +1013,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/it_IT.json b/src/i18n/messages/it_IT.json index a17d786ee6..de45f7f487 100644 --- a/src/i18n/messages/it_IT.json +++ b/src/i18n/messages/it_IT.json @@ -1013,5 +1013,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index e3311ad17a..e06d421e34 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -1013,5 +1013,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/pt_PT.json b/src/i18n/messages/pt_PT.json index b345c4711f..c804de2752 100644 --- a/src/i18n/messages/pt_PT.json +++ b/src/i18n/messages/pt_PT.json @@ -1013,5 +1013,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index e3311ad17a..e06d421e34 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -1013,5 +1013,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/uk.json b/src/i18n/messages/uk.json index e3311ad17a..e06d421e34 100644 --- a/src/i18n/messages/uk.json +++ b/src/i18n/messages/uk.json @@ -1013,5 +1013,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/zh_CN.json b/src/i18n/messages/zh_CN.json index e3311ad17a..e06d421e34 100644 --- a/src/i18n/messages/zh_CN.json +++ b/src/i18n/messages/zh_CN.json @@ -1013,5 +1013,38 @@ "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", - "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel" + "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", + "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", + "course-authoring.course-unit.xblock.button.copy.label": "Copy", + "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", + "course-authoring.course-unit.xblock.button.move.label": "Move", + "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", + "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } From 55a98888ddc63c02a21f574ecc49708d2fc80de1 Mon Sep 17 00:00:00 2001 From: Peter Kulko <93188219+PKulkoRaccoonGang@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:52:04 +0200 Subject: [PATCH 02/10] feat: [AXIMST-23] Course unit - Sidebar with unit info (#117) * feat: added Sidebar with unit info * feat: added unit location * refactor: added legacy behavior * feat: added live variant * refactor: code refactoring * feat: added tests and translations * feat: added new font size * refactor: after review --- src/course-unit/CourseUnit.jsx | 14 ++- src/course-unit/CourseUnit.scss | 1 + src/course-unit/CourseUnit.test.jsx | 40 +++++++ src/course-unit/constants.js | 18 +++ src/course-unit/sidebar/Sidebar.scss | 71 +++++++++++ .../components/ReleaseInfoComponent.jsx | 29 +++++ .../sidebar/components/SidebarBody.jsx | 65 +++++++++++ .../sidebar/components/SidebarHeader.jsx | 41 +++++++ src/course-unit/sidebar/components/index.js | 3 + .../sidebar-footer/ActionButtons.jsx | 49 ++++++++ .../sidebar-footer/UnitVisibilityInfo.jsx | 55 +++++++++ .../components/sidebar-footer/index.jsx | 40 +++++++ src/course-unit/sidebar/hooks.jsx | 43 +++++++ src/course-unit/sidebar/index.jsx | 52 +++++++++ src/course-unit/sidebar/messages.js | 110 ++++++++++++++++++ src/course-unit/sidebar/utils.js | 102 ++++++++++++++++ src/i18n/messages/ar.json | 1 - src/i18n/messages/de.json | 26 ----- src/i18n/messages/es_419.json | 26 ----- src/i18n/messages/fa_IR.json | 26 ----- src/i18n/messages/fr.json | 26 ----- src/i18n/messages/fr_CA.json | 26 ----- src/i18n/messages/hi.json | 26 ----- src/i18n/messages/it.json | 26 ----- src/i18n/messages/it_IT.json | 26 ----- src/i18n/messages/pt.json | 26 ----- src/i18n/messages/pt_PT.json | 26 ----- src/i18n/messages/ru.json | 26 ----- src/i18n/messages/uk.json | 26 ----- src/i18n/messages/zh_CN.json | 26 ----- 30 files changed, 729 insertions(+), 343 deletions(-) create mode 100644 src/course-unit/sidebar/Sidebar.scss create mode 100644 src/course-unit/sidebar/components/ReleaseInfoComponent.jsx create mode 100644 src/course-unit/sidebar/components/SidebarBody.jsx create mode 100644 src/course-unit/sidebar/components/SidebarHeader.jsx create mode 100644 src/course-unit/sidebar/components/index.js create mode 100644 src/course-unit/sidebar/components/sidebar-footer/ActionButtons.jsx create mode 100644 src/course-unit/sidebar/components/sidebar-footer/UnitVisibilityInfo.jsx create mode 100644 src/course-unit/sidebar/components/sidebar-footer/index.jsx create mode 100644 src/course-unit/sidebar/hooks.jsx create mode 100644 src/course-unit/sidebar/index.jsx create mode 100644 src/course-unit/sidebar/messages.js create mode 100644 src/course-unit/sidebar/utils.js diff --git a/src/course-unit/CourseUnit.jsx b/src/course-unit/CourseUnit.jsx index a1b5e12ba9..682e991b1b 100644 --- a/src/course-unit/CourseUnit.jsx +++ b/src/course-unit/CourseUnit.jsx @@ -18,6 +18,7 @@ import HeaderTitle from './header-title/HeaderTitle'; import Breadcrumbs from './breadcrumbs/Breadcrumbs'; import HeaderNavigations from './header-navigations/HeaderNavigations'; import Sequence from './course-sequence'; +import Sidebar from './sidebar'; import { useCourseUnit } from './hooks'; import messages from './messages'; @@ -86,9 +87,9 @@ const CourseUnit = ({ courseId }) => { handleCreateNewCourseXBlock={handleCreateNewCourseXBlock} /> @@ -110,7 +111,12 @@ const CourseUnit = ({ courseId }) => { handleCreateNewCourseXBlock={handleCreateNewCourseXBlock} /> - + + + + + + diff --git a/src/course-unit/CourseUnit.scss b/src/course-unit/CourseUnit.scss index d54e7ad232..16d588f44e 100644 --- a/src/course-unit/CourseUnit.scss +++ b/src/course-unit/CourseUnit.scss @@ -2,3 +2,4 @@ @import "./course-sequence/CourseSequence"; @import "./add-component/AddComponent"; @import "./course-xblock/CourseXblock"; +@import "./sidebar/Sidebar"; diff --git a/src/course-unit/CourseUnit.test.jsx b/src/course-unit/CourseUnit.test.jsx index cf35db7c08..555aa10286 100644 --- a/src/course-unit/CourseUnit.test.jsx +++ b/src/course-unit/CourseUnit.test.jsx @@ -34,6 +34,8 @@ import CourseUnit from './CourseUnit'; import headerNavigationsMessages from './header-navigations/messages'; import headerTitleMessages from './header-title/messages'; import courseSequenceMessages from './course-sequence/messages'; +import sidebarMessages from './sidebar/messages'; +import { extractCourseUnitId } from './sidebar/utils'; import deleteModalMessages from '../generic/delete-modal/messages'; import courseXBlockMessages from './course-xblock/messages'; @@ -310,6 +312,44 @@ describe('', () => { }); }); + it('renders course unit details for a draft with unpublished changes', async () => { + const { getByText } = render(); + + await waitFor(() => { + expect(getByText(sidebarMessages.sidebarTitleDraftUnpublishedChanges.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityStaffAndLearnersTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.releaseStatusTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.sidebarBodyNote.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityWillBeVisibleToTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(courseUnitIndexMock.release_date)).toBeInTheDocument(); + expect(getByText( + sidebarMessages.publishInfoDraftSaved.defaultMessage + .replace('{editedOn}', courseUnitIndexMock.edited_on) + .replace('{editedBy}', courseUnitIndexMock.edited_by), + )).toBeInTheDocument(); + expect(getByText( + sidebarMessages.releaseInfoWithSection.defaultMessage + .replace('{sectionName}', courseUnitIndexMock.release_date_from), + )).toBeInTheDocument(); + }); + }); + + it('renders course unit details in the sidebar', async () => { + const { getByText } = render(); + const courseUnitLocationId = extractCourseUnitId(courseUnitIndexMock.id); + + await waitFor(() => { + expect(getByText(sidebarMessages.sidebarHeaderUnitLocationTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.unitLocationTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(courseUnitLocationId)).toBeInTheDocument(); + expect(getByText(sidebarMessages.unitLocationDescription.defaultMessage + .replace('{id}', courseUnitLocationId))).toBeInTheDocument(); + }); + }); + it('checks whether xblock is deleted when corresponding delete button is clicked', async () => { axiosMock .onDelete(getXBlockBaseApiUrl(courseVerticalChildrenMock.children[0].block_id)) diff --git a/src/course-unit/constants.js b/src/course-unit/constants.js index 3786de4a10..ecf07815f2 100644 --- a/src/course-unit/constants.js +++ b/src/course-unit/constants.js @@ -12,6 +12,7 @@ import { TextFields as TextFieldsIcon, VideoCamera as VideoCameraIcon, } from '@openedx/paragon/icons'; +import messages from './sidebar/messages'; export const UNIT_ICON_TYPES = ['video', 'other', 'vertical', 'problem', 'lock']; @@ -44,3 +45,20 @@ export const COMPONENT_TYPE_ICON_MAP = { [COMPONENT_ICON_TYPES.video]: VideoCameraIcon, [COMPONENT_ICON_TYPES.dragAndDrop]: BackHandIcon, }; + +export const getUnitReleaseStatus = (intl) => ({ + release: intl.formatMessage(messages.releaseStatusTitle), + released: intl.formatMessage(messages.releasedStatusTitle), + scheduled: intl.formatMessage(messages.scheduledStatusTitle), +}); + +export const UNIT_VISIBILITY_STATES = { + staffOnly: 'staff_only', + live: 'live', + ready: 'ready', +}; + +export const COLORS = { + BLACK: '#000', + GREEN: '#0D7D4D', +}; diff --git a/src/course-unit/sidebar/Sidebar.scss b/src/course-unit/sidebar/Sidebar.scss new file mode 100644 index 0000000000..537e521082 --- /dev/null +++ b/src/course-unit/sidebar/Sidebar.scss @@ -0,0 +1,71 @@ +%base-font-params { + font-size: $font-size-sm; + line-height: $line-height-base; +} + +.course-unit-sidebar { + .course-unit-sidebar-header { + padding: $spacer $spacer map-get($spacers, 3\.5); + + .course-unit-sidebar-header-icon { + margin-right: map-get($spacers, 1); + } + + .course-unit-sidebar-header-title { + font-size: $font-size-base; + line-height: $line-height-base; + } + } + + .course-unit-sidebar-footer { + padding: 0 $spacer $spacer; + + .course-unit-sidebar-visibility { + .course-unit-sidebar-visibility-title { + font-weight: $font-weight-normal; + color: $gray-700; + + @extend %base-font-params; + } + + .course-unit-sidebar-location-description { + font-size: $font-size-xs; + line-height: $line-height-base; + } + + .course-unit-sidebar-visibility-copy { + font-weight: $font-weight-bold; + color: $gray-700; + + @extend %base-font-params; + } + + .course-unit-sidebar-visibility-checkbox .pgn__form-label { + font-size: $font-size-sm; + line-height: $headings-line-height; + } + } + } + + .course-unit-sidebar-date { + padding: 0 $spacer $spacer; + + @extend %base-font-params; + + .course-unit-sidebar-date-stage { + font-weight: $font-weight-normal; + + @extend %base-font-params; + } + + .course-unit-sidebar-date-timestamp { + color: $gray-700; + + @extend %base-font-params; + } + } + + &.is-stuff-only .course-unit-sidebar-date-and-with { + text-decoration: line-through; + } +} diff --git a/src/course-unit/sidebar/components/ReleaseInfoComponent.jsx b/src/course-unit/sidebar/components/ReleaseInfoComponent.jsx new file mode 100644 index 0000000000..9861fa2094 --- /dev/null +++ b/src/course-unit/sidebar/components/ReleaseInfoComponent.jsx @@ -0,0 +1,29 @@ +import { useSelector } from 'react-redux'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { getCourseUnitData } from '../../data/selectors'; +import { getReleaseInfo } from '../utils'; + +const ReleaseInfoComponent = () => { + const intl = useIntl(); + const { + releaseDate, + releaseDateFrom, + } = useSelector(getCourseUnitData); + const releaseInfo = getReleaseInfo(intl, releaseDate, releaseDateFrom); + + if (releaseInfo.isScheduled) { + return ( + +
+ {releaseInfo.releaseDate}  +
+ {releaseInfo.sectionNameMessage} +
+ ); + } + + return releaseInfo.message; +}; + +export default ReleaseInfoComponent; diff --git a/src/course-unit/sidebar/components/SidebarBody.jsx b/src/course-unit/sidebar/components/SidebarBody.jsx new file mode 100644 index 0000000000..3b24fd5210 --- /dev/null +++ b/src/course-unit/sidebar/components/SidebarBody.jsx @@ -0,0 +1,65 @@ +import PropTypes from 'prop-types'; +import { useSelector } from 'react-redux'; +import { Card, Stack } from '@openedx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { getCourseUnitData } from '../../data/selectors'; +import { getPublishInfo } from '../utils'; +import messages from '../messages'; +import ReleaseInfoComponent from './ReleaseInfoComponent'; + +const SidebarBody = ({ releaseLabel, isDisplayUnitLocation, locationId }) => { + const intl = useIntl(); + const { + editedOn, + editedBy, + hasChanges, + publishedBy, + publishedOn, + } = useSelector(getCourseUnitData); + + return ( + + + {isDisplayUnitLocation ? ( + +
+ {intl.formatMessage(messages.unitLocationTitle)} +
+

+ {locationId} +

+
+ ) : ( + <> + + {getPublishInfo(intl, hasChanges, editedBy, editedOn, publishedBy, publishedOn)} + + +
+ {releaseLabel} +
+ +
+

+ {intl.formatMessage(messages.sidebarBodyNote)} +

+ + )} +
+
+ ); +}; + +SidebarBody.propTypes = { + releaseLabel: PropTypes.string.isRequired, + isDisplayUnitLocation: PropTypes.bool, + locationId: PropTypes.string, +}; + +SidebarBody.defaultProps = { + isDisplayUnitLocation: false, + locationId: null, +}; + +export default SidebarBody; diff --git a/src/course-unit/sidebar/components/SidebarHeader.jsx b/src/course-unit/sidebar/components/SidebarHeader.jsx new file mode 100644 index 0000000000..188ad15a0c --- /dev/null +++ b/src/course-unit/sidebar/components/SidebarHeader.jsx @@ -0,0 +1,41 @@ +import PropTypes from 'prop-types'; +import { useSelector } from 'react-redux'; +import { Icon, Stack } from '@openedx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { getCourseUnitData } from '../../data/selectors'; +import { getIconVariant } from '../utils'; +import messages from '../messages'; + +const SidebarHeader = ({ title, visibilityState, isDisplayUnitLocation }) => { + const intl = useIntl(); + const { hasChanges, published } = useSelector(getCourseUnitData); + const { iconSrc, colorVariant } = getIconVariant(visibilityState, published, hasChanges); + + return ( + + {!isDisplayUnitLocation && ( + + )} +

+ {isDisplayUnitLocation ? intl.formatMessage(messages.sidebarHeaderUnitLocationTitle) : title} +

+
+ ); +}; + +SidebarHeader.propTypes = { + title: PropTypes.string.isRequired, + visibilityState: PropTypes.string.isRequired, + isDisplayUnitLocation: PropTypes.bool, +}; + +SidebarHeader.defaultProps = { + isDisplayUnitLocation: false, +}; + +export default SidebarHeader; diff --git a/src/course-unit/sidebar/components/index.js b/src/course-unit/sidebar/components/index.js new file mode 100644 index 0000000000..6637529e61 --- /dev/null +++ b/src/course-unit/sidebar/components/index.js @@ -0,0 +1,3 @@ +export { default as SidebarHeader } from './SidebarHeader'; +export { default as SidebarBody } from './SidebarBody'; +export { default as SidebarFooter } from './sidebar-footer'; diff --git a/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.jsx b/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.jsx new file mode 100644 index 0000000000..3fb98f5cc6 --- /dev/null +++ b/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.jsx @@ -0,0 +1,49 @@ +import { useSelector } from 'react-redux'; +import { Button } from '@openedx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { getCourseUnitData } from '../../../data/selectors'; +import messages from '../../messages'; + +const ActionButtons = () => { + const intl = useIntl(); + const { + published, + hasChanges, + enableCopyPasteUnits, + } = useSelector(getCourseUnitData); + + return ( + <> + {(!published || hasChanges) && ( + + )} + {(published && hasChanges) && ( + + )} + {enableCopyPasteUnits && ( + + )} + + ); +}; + +export default ActionButtons; diff --git a/src/course-unit/sidebar/components/sidebar-footer/UnitVisibilityInfo.jsx b/src/course-unit/sidebar/components/sidebar-footer/UnitVisibilityInfo.jsx new file mode 100644 index 0000000000..2603330011 --- /dev/null +++ b/src/course-unit/sidebar/components/sidebar-footer/UnitVisibilityInfo.jsx @@ -0,0 +1,55 @@ +import { useSelector } from 'react-redux'; +import { Form } from '@openedx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { getCourseUnitData } from '../../../data/selectors'; +import { getVisibilityTitle } from '../../utils'; +import messages from '../../messages'; + +const UnitVisibilityInfo = () => { + const intl = useIntl(); + const { + published, + hasChanges, + staffLockFrom, + releaseDateFrom, + releasedToStudents, + visibleToStaffOnly, + hasExplicitStaffLock, + } = useSelector(getCourseUnitData); + + return ( + <> + + {getVisibilityTitle(intl, releasedToStudents, published, hasChanges)} + + {visibleToStaffOnly ? ( + <> +
+ {intl.formatMessage(messages.visibilityStaffOnlyTitle)} +
+ {!hasExplicitStaffLock && ( + + {intl.formatMessage(messages.visibilityHasExplicitStaffLockText, { + date: releaseDateFrom, sectionName: staffLockFrom, + })} + + )} + + ) : ( +
+ {intl.formatMessage(messages.visibilityStaffAndLearnersTitle)} +
+ )} + {}} + > + {intl.formatMessage(messages.visibilityCheckboxTitle)} + + + ); +}; + +export default UnitVisibilityInfo; diff --git a/src/course-unit/sidebar/components/sidebar-footer/index.jsx b/src/course-unit/sidebar/components/sidebar-footer/index.jsx new file mode 100644 index 0000000000..35ed27dc84 --- /dev/null +++ b/src/course-unit/sidebar/components/sidebar-footer/index.jsx @@ -0,0 +1,40 @@ +import PropTypes from 'prop-types'; +import { Card, Stack } from '@openedx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import messages from '../../messages'; +import UnitVisibilityInfo from './UnitVisibilityInfo'; +import ActionButtons from './ActionButtons'; + +const SidebarFooter = ({ isDisplayUnitLocation, locationId }) => { + const intl = useIntl(); + + return ( + + + {isDisplayUnitLocation ? ( + + {intl.formatMessage(messages.unitLocationDescription, { id: locationId })} + + ) : ( + <> + + + + )} + + + ); +}; + +SidebarFooter.propTypes = { + isDisplayUnitLocation: PropTypes.bool, + locationId: PropTypes.string, +}; + +SidebarFooter.defaultProps = { + isDisplayUnitLocation: false, + locationId: null, +}; + +export default SidebarFooter; diff --git a/src/course-unit/sidebar/hooks.jsx b/src/course-unit/sidebar/hooks.jsx new file mode 100644 index 0000000000..bbe6c073fc --- /dev/null +++ b/src/course-unit/sidebar/hooks.jsx @@ -0,0 +1,43 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { getUnitReleaseStatus, UNIT_VISIBILITY_STATES } from '../constants'; +import messages from './messages'; +import { extractCourseUnitId } from './utils'; + +const useCourseUnitData = ({ + hasChanges, published, visibilityState, id, +}) => { + const intl = useIntl(); + const releaseStatus = getUnitReleaseStatus(intl); + const locationId = extractCourseUnitId(id); + const visibleToStaffOnly = visibilityState === UNIT_VISIBILITY_STATES.staffOnly; + const titleMessages = { + [UNIT_VISIBILITY_STATES.staffOnly]: messages.sidebarTitleVisibleToStaffOnly, + [UNIT_VISIBILITY_STATES.live]: messages.sidebarTitlePublishedAndLive, + // eslint-disable-next-line no-nested-ternary + default: published + ? (hasChanges ? messages.sidebarTitleDraftUnpublishedChanges + : messages.sidebarTitlePublishedNotYetReleased) + : messages.sidebarTitleDraftNeverPublished, + }; + + const releaseLabels = { + [UNIT_VISIBILITY_STATES.staffOnly]: releaseStatus.release, + [UNIT_VISIBILITY_STATES.live]: releaseStatus.released, + [UNIT_VISIBILITY_STATES.ready]: releaseStatus.scheduled, + default: releaseStatus.release, + }; + + const title = intl.formatMessage(titleMessages[visibilityState] || titleMessages.default); + const releaseLabel = releaseLabels[visibilityState] || releaseLabels.default; + + return { + title, + locationId, + releaseLabel, + visibilityState, + visibleToStaffOnly, + }; +}; + +export default useCourseUnitData; diff --git a/src/course-unit/sidebar/index.jsx b/src/course-unit/sidebar/index.jsx new file mode 100644 index 0000000000..eae1e1b2f7 --- /dev/null +++ b/src/course-unit/sidebar/index.jsx @@ -0,0 +1,52 @@ +import PropTypes from 'prop-types'; +import { useSelector } from 'react-redux'; +import classNames from 'classnames'; +import { Card } from '@openedx/paragon'; + +import { getCourseUnitData } from '../data/selectors'; +import { SidebarBody, SidebarFooter, SidebarHeader } from './components'; +import useCourseUnitData from './hooks'; + +const Sidebar = ({ isDisplayUnitLocation }) => { + const { + title, + locationId, + releaseLabel, + visibilityState, + visibleToStaffOnly, + } = useCourseUnitData(useSelector(getCourseUnitData)); + + return ( + + + + + + ); +}; + +Sidebar.propTypes = { + isDisplayUnitLocation: PropTypes.bool, +}; + +Sidebar.defaultProps = { + isDisplayUnitLocation: false, +}; + +export default Sidebar; diff --git a/src/course-unit/sidebar/messages.js b/src/course-unit/sidebar/messages.js new file mode 100644 index 0000000000..bb9a75c311 --- /dev/null +++ b/src/course-unit/sidebar/messages.js @@ -0,0 +1,110 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + sidebarTitleDraftNeverPublished: { + id: 'course-authoring.course-unit.sidebar.title.draft.never-published', + defaultMessage: 'Draft (never published)', + }, + sidebarTitleVisibleToStaffOnly: { + id: 'course-authoring.course-unit.sidebar.title.visible.to-staff-only', + defaultMessage: 'Visible to staff only', + }, + sidebarTitlePublishedAndLive: { + id: 'course-authoring.course-unit.sidebar.title.published.live', + defaultMessage: 'Published and live', + }, + sidebarTitleDraftUnpublishedChanges: { + id: 'course-authoring.course-unit.sidebar.title.draft.unpublished', + defaultMessage: 'Draft (unpublished changes)', + }, + sidebarTitlePublishedNotYetReleased: { + id: 'course-authoring.course-unit.sidebar.title.published.not-yet-released', + defaultMessage: 'Published (not yet released)', + }, + sidebarHeaderUnitLocationTitle: { + id: 'course-authoring.course-unit.sidebar.header.unit-location.title', + defaultMessage: 'Unit location', + }, + sidebarBodyNote: { + id: 'course-authoring.course-unit.sidebar.body.note', + defaultMessage: 'Note: Do not hide graded assignments after they have been released.', + }, + publishInfoPreviouslyPublished: { + id: 'course-authoring.course-unit.publish.info.previously-published', + defaultMessage: 'Previously published', + }, + publishInfoDraftSaved: { + id: 'course-authoring.course-unit.publish.info.draft.saved', + defaultMessage: 'Draft saved on {editedOn} by {editedBy}', + }, + publishLastPublished: { + id: 'course-authoring.course-unit.publish.info.last.published', + defaultMessage: 'Last published {publishedOn} by {publishedBy}', + }, + releaseInfoUnscheduled: { + id: 'course-authoring.course-unit.release.info.unscheduled', + defaultMessage: 'Unscheduled', + }, + releaseInfoWithSection: { + id: 'course-authoring.course-unit.release.info.with-unit', + defaultMessage: 'with {sectionName}', + }, + visibilityIsVisibleToTitle: { + id: 'course-authoring.course-unit.visibility.is-visible-to.title', + defaultMessage: 'IS VISIBLE TO', + }, + visibilityWillBeVisibleToTitle: { + id: 'course-authoring.course-unit.visibility.will-be-visible-to.title', + defaultMessage: 'WILL BE VISIBLE TO', + }, + unitLocationTitle: { + id: 'course-authoring.course-unit.unit-location.title', + defaultMessage: 'LOCATION ID', + }, + unitLocationDescription: { + id: 'course-authoring.course-unit.unit-location.description', + defaultMessage: 'To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value', + }, + visibilityCheckboxTitle: { + id: 'course-authoring.course-unit.visibility.checkbox.title', + defaultMessage: 'Hide from learners', + }, + visibilityStaffOnlyTitle: { + id: 'course-authoring.course-unit.visibility.staff-only.title', + defaultMessage: 'Staff only', + }, + visibilityStaffAndLearnersTitle: { + id: 'course-authoring.course-unit.visibility.staff-and-learners.title', + defaultMessage: 'Staff and learners', + }, + visibilityHasExplicitStaffLockText: { + id: 'course-authoring.course-unit.visibility.has-explicit-staff-lock.text', + defaultMessage: 'with {date} {sectionName}', + }, + actionButtonPublishTitle: { + id: 'course-authoring.course-unit.action-buttons.publish.title', + defaultMessage: 'Publish', + }, + actionButtonDiscardChangesTitle: { + id: 'course-authoring.course-unit.action-button.discard-changes.title', + defaultMessage: 'Discard changes', + }, + actionButtonCopyUnitTitle: { + id: 'course-authoring.course-unit.action-button.copy-unit.title', + defaultMessage: 'Copy unit', + }, + releaseStatusTitle: { + id: 'course-authoring.course-unit.status.release.title', + defaultMessage: 'RELEASE', + }, + releasedStatusTitle: { + id: 'course-authoring.course-unit.status.released.title', + defaultMessage: 'RELEASED', + }, + scheduledStatusTitle: { + id: 'course-authoring.course-unit.status.scheduled.title', + defaultMessage: 'SCHEDULED', + }, +}); + +export default messages; diff --git a/src/course-unit/sidebar/utils.js b/src/course-unit/sidebar/utils.js new file mode 100644 index 0000000000..9a36a35597 --- /dev/null +++ b/src/course-unit/sidebar/utils.js @@ -0,0 +1,102 @@ +import { + CheckCircle as CheckCircleIcon, + CheckCircleOutline as CheckCircleOutlineIcon, + InfoOutline as InfoOutlineIcon, +} from '@openedx/paragon/icons'; + +import { COLORS, UNIT_VISIBILITY_STATES } from '../constants'; +import messages from './messages'; + +/** + * Get information about the publishing status. + * @param {Object} intl - The internationalization object. + * @param {boolean} hasChanges - Indicates if there are unpublished changes. + * @param {string} editedBy - The user who edited the content. + * @param {string} editedOn - The timestamp when the content was edited. + * @param {string} publishedBy - The user who last published the content. + * @param {string} publishedOn - The timestamp when the content was last published. + * @returns {string} Publish information based on the provided parameters. + */ +export const getPublishInfo = (intl, hasChanges, editedBy, editedOn, publishedBy, publishedOn) => { + let publishInfoText; + if (hasChanges && editedOn && editedBy) { + publishInfoText = intl.formatMessage(messages.publishInfoDraftSaved, { editedOn, editedBy }); + } else if (publishedOn && publishedBy) { + publishInfoText = intl.formatMessage(messages.publishLastPublished, { publishedOn, publishedBy }); + } else { + publishInfoText = intl.formatMessage(messages.publishInfoPreviouslyPublished); + } + + return publishInfoText; +}; + +/** + * Get information about the release status. + * @param {Object} intl - The internationalization object. + * @param {string} releaseDate - The release date of the content. + * @param {string} releaseDateFrom - The section name associated with the release date. + * @returns {string|ReactElement} Release information based on the provided parameters. + */ +export const getReleaseInfo = (intl, releaseDate, releaseDateFrom) => { + if (releaseDate) { + return { + isScheduled: true, + releaseDate, + releaseDateFrom, + sectionNameMessage: intl.formatMessage(messages.releaseInfoWithSection, { sectionName: releaseDateFrom }), + }; + } + return { + isScheduled: false, + message: intl.formatMessage(messages.releaseInfoUnscheduled), + }; +}; + +/** + * Get the visibility title. + * @param {Object} intl - The internationalization object. + * @param {boolean} releasedToStudents - Indicates if the content is released to students. + * @param {boolean} published - Indicates if the content is published. + * @param {boolean} hasChanges - Indicates if there are unpublished changes. + * @returns {string} The visibility title determined by the provided parameters. + */ +export const getVisibilityTitle = (intl, releasedToStudents, published, hasChanges) => { + if (releasedToStudents && published && !hasChanges) { + return intl.formatMessage(messages.visibilityIsVisibleToTitle); + } + + return intl.formatMessage(messages.visibilityWillBeVisibleToTitle); +}; + +/** + * Get the icon variant based on the provided visibility state and publication status. + * @param {string} visibilityState - The visibility state of the content. + * @param {boolean} published - Indicates if the content is published. + * @param {boolean} hasChanges - Indicates if there are unpublished changes. + * @returns {Object} An object containing the icon component and color variant. + * - iconSrc: The source component for the icon. + * - colorVariant: The color variant for the icon. + */ +export const getIconVariant = (visibilityState, published, hasChanges) => { + const iconVariants = { + [UNIT_VISIBILITY_STATES.staffOnly]: { iconSrc: InfoOutlineIcon, colorVariant: COLORS.BLACK }, + [UNIT_VISIBILITY_STATES.live]: { iconSrc: CheckCircleIcon, colorVariant: COLORS.GREEN }, + publishedNoChanges: { iconSrc: CheckCircleOutlineIcon, colorVariant: COLORS.BLACK }, + publishedWithChanges: { iconSrc: InfoOutlineIcon, colorVariant: COLORS.BLACK }, + default: { iconSrc: InfoOutlineIcon, colorVariant: COLORS.BLACK }, + }; + if (visibilityState in iconVariants) { + return iconVariants[visibilityState]; + } + if (published) { + return hasChanges ? iconVariants.publishedWithChanges : iconVariants.publishedNoChanges; + } + return iconVariants.default; +}; + +/** + * Extracts the clear course unit ID from the given course unit data. + * @param {string} id - The course unit ID. + * @returns {string} The clear course unit ID extracted from the provided data. + */ +export const extractCourseUnitId = (id) => id.match(/block@(.+)$/)[1]; diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index 57a247dbfa..a26a97c577 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -1010,7 +1010,6 @@ "course-authoring.certificates.sidebar.about2.description-2": "{strongText} delete certificates after a course has started; learners who have already earned certificates will no longer be able to access them.", "course-authoring.certificates.sidebar.about2.description-2.strong": "Do not", "course-authoring.certificates.sidebar.learnmore.button": "Learn more about certificates", - "course-authoring.course-unit.add.component.button.text": "Add Component:", "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index e06d421e34..6a18e9e180 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -1014,32 +1014,6 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", - "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", - "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", - "course-authoring.course-unit.sidebar.title.published.live": "Published and live", - "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", - "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", - "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", - "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", - "course-authoring.course-unit.publish.info.previously-published": "Previously published", - "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", - "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", - "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", - "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", - "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", - "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", - "course-authoring.course-unit.unit-location.title": "LOCATION ID", - "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", - "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", - "course-authoring.course-unit.visibility.staff-only.title": "Staff only", - "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", - "course-authoring.course-unit.action-buttons.publish.title": "Publish", - "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", - "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", - "course-authoring.course-unit.status.release.title": "RELEASE", - "course-authoring.course-unit.status.released.title": "RELEASED", - "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/es_419.json b/src/i18n/messages/es_419.json index 979df0d74d..d6efdea78f 100644 --- a/src/i18n/messages/es_419.json +++ b/src/i18n/messages/es_419.json @@ -1014,32 +1014,6 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", - "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", - "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", - "course-authoring.course-unit.sidebar.title.published.live": "Published and live", - "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", - "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", - "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", - "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", - "course-authoring.course-unit.publish.info.previously-published": "Previously published", - "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", - "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", - "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", - "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", - "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", - "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", - "course-authoring.course-unit.unit-location.title": "LOCATION ID", - "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", - "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", - "course-authoring.course-unit.visibility.staff-only.title": "Staff only", - "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", - "course-authoring.course-unit.action-buttons.publish.title": "Publish", - "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", - "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", - "course-authoring.course-unit.status.release.title": "RELEASE", - "course-authoring.course-unit.status.released.title": "RELEASED", - "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/fa_IR.json b/src/i18n/messages/fa_IR.json index 1252d8c29d..e2fc0af12f 100644 --- a/src/i18n/messages/fa_IR.json +++ b/src/i18n/messages/fa_IR.json @@ -37,32 +37,6 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", - "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", - "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", - "course-authoring.course-unit.sidebar.title.published.live": "Published and live", - "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", - "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", - "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", - "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", - "course-authoring.course-unit.publish.info.previously-published": "Previously published", - "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", - "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", - "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", - "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", - "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", - "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", - "course-authoring.course-unit.unit-location.title": "LOCATION ID", - "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", - "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", - "course-authoring.course-unit.visibility.staff-only.title": "Staff only", - "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", - "course-authoring.course-unit.action-buttons.publish.title": "Publish", - "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", - "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", - "course-authoring.course-unit.status.release.title": "RELEASE", - "course-authoring.course-unit.status.released.title": "RELEASED", - "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index 003397d4db..4c874a0659 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -1014,32 +1014,6 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", - "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", - "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", - "course-authoring.course-unit.sidebar.title.published.live": "Published and live", - "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", - "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", - "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", - "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", - "course-authoring.course-unit.publish.info.previously-published": "Previously published", - "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", - "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", - "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", - "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", - "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", - "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", - "course-authoring.course-unit.unit-location.title": "LOCATION ID", - "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", - "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", - "course-authoring.course-unit.visibility.staff-only.title": "Staff only", - "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", - "course-authoring.course-unit.action-buttons.publish.title": "Publish", - "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", - "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", - "course-authoring.course-unit.status.release.title": "RELEASE", - "course-authoring.course-unit.status.released.title": "RELEASED", - "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/fr_CA.json b/src/i18n/messages/fr_CA.json index 0b0f31624f..f2c2d095d3 100644 --- a/src/i18n/messages/fr_CA.json +++ b/src/i18n/messages/fr_CA.json @@ -1014,32 +1014,6 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", - "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", - "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", - "course-authoring.course-unit.sidebar.title.published.live": "Published and live", - "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", - "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", - "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", - "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", - "course-authoring.course-unit.publish.info.previously-published": "Previously published", - "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", - "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", - "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", - "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", - "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", - "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", - "course-authoring.course-unit.unit-location.title": "LOCATION ID", - "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", - "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", - "course-authoring.course-unit.visibility.staff-only.title": "Staff only", - "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", - "course-authoring.course-unit.action-buttons.publish.title": "Publish", - "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", - "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", - "course-authoring.course-unit.status.release.title": "RELEASE", - "course-authoring.course-unit.status.released.title": "RELEASED", - "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/hi.json b/src/i18n/messages/hi.json index e06d421e34..6a18e9e180 100644 --- a/src/i18n/messages/hi.json +++ b/src/i18n/messages/hi.json @@ -1014,32 +1014,6 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", - "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", - "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", - "course-authoring.course-unit.sidebar.title.published.live": "Published and live", - "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", - "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", - "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", - "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", - "course-authoring.course-unit.publish.info.previously-published": "Previously published", - "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", - "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", - "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", - "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", - "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", - "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", - "course-authoring.course-unit.unit-location.title": "LOCATION ID", - "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", - "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", - "course-authoring.course-unit.visibility.staff-only.title": "Staff only", - "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", - "course-authoring.course-unit.action-buttons.publish.title": "Publish", - "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", - "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", - "course-authoring.course-unit.status.release.title": "RELEASE", - "course-authoring.course-unit.status.released.title": "RELEASED", - "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/it.json b/src/i18n/messages/it.json index e06d421e34..6a18e9e180 100644 --- a/src/i18n/messages/it.json +++ b/src/i18n/messages/it.json @@ -1014,32 +1014,6 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", - "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", - "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", - "course-authoring.course-unit.sidebar.title.published.live": "Published and live", - "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", - "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", - "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", - "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", - "course-authoring.course-unit.publish.info.previously-published": "Previously published", - "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", - "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", - "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", - "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", - "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", - "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", - "course-authoring.course-unit.unit-location.title": "LOCATION ID", - "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", - "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", - "course-authoring.course-unit.visibility.staff-only.title": "Staff only", - "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", - "course-authoring.course-unit.action-buttons.publish.title": "Publish", - "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", - "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", - "course-authoring.course-unit.status.release.title": "RELEASE", - "course-authoring.course-unit.status.released.title": "RELEASED", - "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/it_IT.json b/src/i18n/messages/it_IT.json index de45f7f487..3c53c52637 100644 --- a/src/i18n/messages/it_IT.json +++ b/src/i18n/messages/it_IT.json @@ -1014,32 +1014,6 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", - "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", - "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", - "course-authoring.course-unit.sidebar.title.published.live": "Published and live", - "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", - "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", - "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", - "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", - "course-authoring.course-unit.publish.info.previously-published": "Previously published", - "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", - "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", - "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", - "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", - "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", - "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", - "course-authoring.course-unit.unit-location.title": "LOCATION ID", - "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", - "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", - "course-authoring.course-unit.visibility.staff-only.title": "Staff only", - "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", - "course-authoring.course-unit.action-buttons.publish.title": "Publish", - "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", - "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", - "course-authoring.course-unit.status.release.title": "RELEASE", - "course-authoring.course-unit.status.released.title": "RELEASED", - "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index e06d421e34..6a18e9e180 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -1014,32 +1014,6 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", - "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", - "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", - "course-authoring.course-unit.sidebar.title.published.live": "Published and live", - "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", - "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", - "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", - "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", - "course-authoring.course-unit.publish.info.previously-published": "Previously published", - "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", - "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", - "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", - "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", - "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", - "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", - "course-authoring.course-unit.unit-location.title": "LOCATION ID", - "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", - "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", - "course-authoring.course-unit.visibility.staff-only.title": "Staff only", - "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", - "course-authoring.course-unit.action-buttons.publish.title": "Publish", - "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", - "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", - "course-authoring.course-unit.status.release.title": "RELEASE", - "course-authoring.course-unit.status.released.title": "RELEASED", - "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/pt_PT.json b/src/i18n/messages/pt_PT.json index c804de2752..88c7ddd23a 100644 --- a/src/i18n/messages/pt_PT.json +++ b/src/i18n/messages/pt_PT.json @@ -1014,32 +1014,6 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", - "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", - "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", - "course-authoring.course-unit.sidebar.title.published.live": "Published and live", - "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", - "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", - "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", - "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", - "course-authoring.course-unit.publish.info.previously-published": "Previously published", - "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", - "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", - "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", - "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", - "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", - "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", - "course-authoring.course-unit.unit-location.title": "LOCATION ID", - "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", - "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", - "course-authoring.course-unit.visibility.staff-only.title": "Staff only", - "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", - "course-authoring.course-unit.action-buttons.publish.title": "Publish", - "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", - "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", - "course-authoring.course-unit.status.release.title": "RELEASE", - "course-authoring.course-unit.status.released.title": "RELEASED", - "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index e06d421e34..6a18e9e180 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -1014,32 +1014,6 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", - "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", - "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", - "course-authoring.course-unit.sidebar.title.published.live": "Published and live", - "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", - "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", - "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", - "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", - "course-authoring.course-unit.publish.info.previously-published": "Previously published", - "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", - "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", - "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", - "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", - "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", - "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", - "course-authoring.course-unit.unit-location.title": "LOCATION ID", - "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", - "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", - "course-authoring.course-unit.visibility.staff-only.title": "Staff only", - "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", - "course-authoring.course-unit.action-buttons.publish.title": "Publish", - "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", - "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", - "course-authoring.course-unit.status.release.title": "RELEASE", - "course-authoring.course-unit.status.released.title": "RELEASED", - "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/uk.json b/src/i18n/messages/uk.json index e06d421e34..6a18e9e180 100644 --- a/src/i18n/messages/uk.json +++ b/src/i18n/messages/uk.json @@ -1014,32 +1014,6 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", - "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", - "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", - "course-authoring.course-unit.sidebar.title.published.live": "Published and live", - "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", - "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", - "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", - "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", - "course-authoring.course-unit.publish.info.previously-published": "Previously published", - "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", - "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", - "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", - "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", - "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", - "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", - "course-authoring.course-unit.unit-location.title": "LOCATION ID", - "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", - "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", - "course-authoring.course-unit.visibility.staff-only.title": "Staff only", - "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", - "course-authoring.course-unit.action-buttons.publish.title": "Publish", - "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", - "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", - "course-authoring.course-unit.status.release.title": "RELEASE", - "course-authoring.course-unit.status.released.title": "RELEASED", - "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/zh_CN.json b/src/i18n/messages/zh_CN.json index e06d421e34..6a18e9e180 100644 --- a/src/i18n/messages/zh_CN.json +++ b/src/i18n/messages/zh_CN.json @@ -1014,32 +1014,6 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", - "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", - "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", - "course-authoring.course-unit.sidebar.title.published.live": "Published and live", - "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", - "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", - "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", - "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", - "course-authoring.course-unit.publish.info.previously-published": "Previously published", - "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", - "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", - "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", - "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", - "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", - "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", - "course-authoring.course-unit.unit-location.title": "LOCATION ID", - "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", - "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", - "course-authoring.course-unit.visibility.staff-only.title": "Staff only", - "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", - "course-authoring.course-unit.action-buttons.publish.title": "Publish", - "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", - "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", - "course-authoring.course-unit.status.release.title": "RELEASE", - "course-authoring.course-unit.status.released.title": "RELEASED", - "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", From 39c6abde1398c463ebd517fc52e130372b56c12d Mon Sep 17 00:00:00 2001 From: Peter Kulko <93188219+PKulkoRaccoonGang@users.noreply.github.com> Date: Mon, 29 Jan 2024 14:42:04 +0200 Subject: [PATCH 03/10] feat: [AXIMST-24] Course unit - Sidebar buttons functional (#134) * feat: [AXIMST-24] sidebar buttons functional * refactor: removed modal extra className * refactor: refactoring after review --- src/constants.js | 4 + src/course-unit/CourseUnit.jsx | 4 +- src/course-unit/CourseUnit.test.jsx | 171 +++++++++++++++++- src/course-unit/constants.js | 6 + src/course-unit/data/api.js | 25 +++ src/course-unit/data/thunk.js | 30 +++ src/course-unit/data/utils.js | 25 +++ src/course-unit/sidebar/Sidebar.scss | 1 + .../sidebar-footer/ActionButtons.jsx | 26 +-- .../sidebar-footer/UnitVisibilityInfo.jsx | 23 ++- .../components/sidebar-footer/index.jsx | 25 ++- src/course-unit/sidebar/index.jsx | 58 +++++- src/course-unit/sidebar/messages.js | 32 ++++ .../export-modal-error/ExportModalError.jsx | 7 +- .../index.jsx} | 20 +- src/i18n/messages/ar.json | 31 ++++ src/i18n/messages/de.json | 33 +++- src/i18n/messages/de_DE.json | 33 +++- src/i18n/messages/es_419.json | 33 +++- src/i18n/messages/fa_IR.json | 33 +++- src/i18n/messages/fr.json | 33 +++- src/i18n/messages/fr_CA.json | 33 +++- src/i18n/messages/hi.json | 33 +++- src/i18n/messages/it.json | 33 +++- src/i18n/messages/it_IT.json | 33 +++- src/i18n/messages/pt.json | 33 +++- src/i18n/messages/pt_PT.json | 33 +++- src/i18n/messages/ru.json | 33 +++- src/i18n/messages/uk.json | 33 +++- src/i18n/messages/zh_CN.json | 33 +++- 30 files changed, 896 insertions(+), 54 deletions(-) rename src/generic/{modal-error/ModalError.jsx => modal-notification/index.jsx} (72%) diff --git a/src/constants.js b/src/constants.js index eb1b17b372..2913884a94 100644 --- a/src/constants.js +++ b/src/constants.js @@ -26,6 +26,10 @@ export const NOTIFICATION_MESSAGES = { deleting: 'Deleting', copying: 'Copying', pasting: 'Pasting', + discardChanges: 'Discarding changes', + publishing: 'Publishing', + hidingFromStudents: 'Hiding from students', + makingVisibleToStudents: 'Making visible to students', empty: '', }; diff --git a/src/course-unit/CourseUnit.jsx b/src/course-unit/CourseUnit.jsx index 682e991b1b..f94bf3497c 100644 --- a/src/course-unit/CourseUnit.jsx +++ b/src/course-unit/CourseUnit.jsx @@ -113,8 +113,8 @@ const CourseUnit = ({ courseId }) => { - - + + diff --git a/src/course-unit/CourseUnit.test.jsx b/src/course-unit/CourseUnit.test.jsx index 555aa10286..75d6578620 100644 --- a/src/course-unit/CourseUnit.test.jsx +++ b/src/course-unit/CourseUnit.test.jsx @@ -1,6 +1,6 @@ import MockAdapter from 'axios-mock-adapter'; import { - act, render, waitFor, fireEvent, + act, render, waitFor, fireEvent, within, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { IntlProvider } from '@edx/frontend-platform/i18n'; @@ -17,6 +17,7 @@ import { postXBlockBaseApiUrl, } from './data/api'; import { + editCourseUnitVisibilityAndData, fetchCourseSectionVerticalData, fetchCourseUnitQuery, fetchCourseVerticalChildrenData, @@ -40,6 +41,7 @@ import { extractCourseUnitId } from './sidebar/utils'; import deleteModalMessages from '../generic/delete-modal/messages'; import courseXBlockMessages from './course-xblock/messages'; import addComponentMessages from './add-component/messages'; +import { PUBLISH_TYPES, UNIT_VISIBILITY_STATES } from './constants'; let axiosMock; let store; @@ -47,6 +49,7 @@ const courseId = '123'; const blockId = '567890'; const unitDisplayName = courseUnitIndexMock.metadata.display_name; const mockedUsedNavigate = jest.fn(); +const userName = 'edx'; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -418,4 +421,170 @@ describe('', () => { expect(getByText('New Cloned XBlock')).toBeInTheDocument(); }); }); + + it('should toggle visibility and update course unit state accordingly', async () => { + const { getByRole, getByTestId } = render(); + let courseUnitSidebar; + let draftUnpublishedChangesHeading; + let visibilityCheckbox; + + await waitFor(() => { + courseUnitSidebar = getByTestId('course-unit-sidebar'); + + draftUnpublishedChangesHeading = within(courseUnitSidebar) + .getByText(sidebarMessages.sidebarTitleDraftUnpublishedChanges.defaultMessage); + expect(draftUnpublishedChangesHeading).toBeInTheDocument(); + + visibilityCheckbox = within(courseUnitSidebar) + .getByLabelText(sidebarMessages.visibilityCheckboxTitle.defaultMessage); + expect(visibilityCheckbox).not.toBeChecked(); + + userEvent.click(visibilityCheckbox); + }); + + axiosMock + .onPost(getXBlockBaseApiUrl(blockId), { + publish: PUBLISH_TYPES.republish, + metadata: { visible_to_staff_only: true }, + }) + .reply(200, { dummy: 'value' }); + axiosMock + .onGet(getCourseUnitApiUrl(blockId)) + .reply(200, { + ...courseUnitIndexMock, + visibility_state: UNIT_VISIBILITY_STATES.staffOnly, + has_explicit_staff_lock: true, + }); + + await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.republish, true), store.dispatch); + + expect(visibilityCheckbox).toBeChecked(); + expect(within(courseUnitSidebar) + .getByText(sidebarMessages.sidebarTitleVisibleToStaffOnly.defaultMessage)).toBeInTheDocument(); + expect(within(courseUnitSidebar) + .getByText(sidebarMessages.visibilityStaffOnlyTitle.defaultMessage)).toBeInTheDocument(); + + userEvent.click(visibilityCheckbox); + + const modalNotification = getByRole('dialog'); + const makeVisibilityBtn = within(modalNotification).getByRole('button', { name: sidebarMessages.modalMakeVisibilityActionButtonText.defaultMessage }); + const cancelBtn = within(modalNotification).getByRole('button', { name: sidebarMessages.modalMakeVisibilityCancelButtonText.defaultMessage }); + const headingElement = within(modalNotification).getByRole('heading', { name: sidebarMessages.modalMakeVisibilityTitle.defaultMessage, class: 'pgn__modal-title' }); + + expect(makeVisibilityBtn).toBeInTheDocument(); + expect(cancelBtn).toBeInTheDocument(); + expect(headingElement).toBeInTheDocument(); + expect(within(modalNotification) + .getByText(sidebarMessages.modalMakeVisibilityDescription.defaultMessage)).toBeInTheDocument(); + + userEvent.click(makeVisibilityBtn); + + axiosMock + .onPost(getXBlockBaseApiUrl(blockId), { + publish: PUBLISH_TYPES.republish, + metadata: { visible_to_staff_only: null }, + }) + .reply(200, { dummy: 'value' }); + axiosMock + .onGet(getCourseUnitApiUrl(blockId)) + .reply(200, courseUnitIndexMock); + + await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.republish, null), store.dispatch); + + expect(within(courseUnitSidebar) + .getByText(sidebarMessages.visibilityStaffAndLearnersTitle.defaultMessage)).toBeInTheDocument(); + expect(visibilityCheckbox).not.toBeChecked(); + expect(draftUnpublishedChangesHeading).toBeInTheDocument(); + }); + + it('should publish course unit after click on the "Publish" button', async () => { + const { getByTestId } = render(); + let courseUnitSidebar; + let publishBtn; + + await waitFor(() => { + courseUnitSidebar = getByTestId('course-unit-sidebar'); + publishBtn = within(courseUnitSidebar).queryByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage }); + expect(publishBtn).toBeInTheDocument(); + + userEvent.click(publishBtn); + }); + + axiosMock + .onPost(getXBlockBaseApiUrl(blockId), { + publish: PUBLISH_TYPES.makePublic, + }) + .reply(200, { dummy: 'value' }); + axiosMock + .onGet(getCourseUnitApiUrl(blockId)) + .reply(200, { + ...courseUnitIndexMock, + visibility_state: UNIT_VISIBILITY_STATES.live, + has_changes: false, + published_by: userName, + }); + + await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); + + expect(within(courseUnitSidebar) + .getByText(sidebarMessages.sidebarTitlePublishedAndLive.defaultMessage)).toBeInTheDocument(); + expect(within(courseUnitSidebar).getByText( + sidebarMessages.publishLastPublished.defaultMessage + .replace('{publishedOn}', courseUnitIndexMock.published_on) + .replace('{publishedBy}', userName), + )).toBeInTheDocument(); + expect(publishBtn).not.toBeInTheDocument(); + }); + + it('should discard changes after click on the "Discard changes" button', async () => { + const { getByTestId, getByRole } = render(); + let courseUnitSidebar; + let discardChangesBtn; + + await waitFor(() => { + courseUnitSidebar = getByTestId('course-unit-sidebar'); + + const draftUnpublishedChangesHeading = within(courseUnitSidebar) + .getByText(sidebarMessages.sidebarTitleDraftUnpublishedChanges.defaultMessage); + expect(draftUnpublishedChangesHeading).toBeInTheDocument(); + discardChangesBtn = within(courseUnitSidebar).queryByRole('button', { name: sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage }); + expect(discardChangesBtn).toBeInTheDocument(); + + userEvent.click(discardChangesBtn); + + const modalNotification = getByRole('dialog'); + expect(modalNotification).toBeInTheDocument(); + expect(within(modalNotification) + .getByText(sidebarMessages.modalDiscardUnitChangesDescription.defaultMessage)).toBeInTheDocument(); + expect(within(modalNotification) + .getByText(sidebarMessages.modalDiscardUnitChangesCancelButtonText.defaultMessage)).toBeInTheDocument(); + const headingElement = within(modalNotification).getByRole('heading', { name: sidebarMessages.modalDiscardUnitChangesTitle.defaultMessage, class: 'pgn__modal-title' }); + expect(headingElement).toBeInTheDocument(); + const actionBtn = within(modalNotification).getByRole('button', { name: sidebarMessages.modalDiscardUnitChangesActionButtonText.defaultMessage }); + expect(actionBtn).toBeInTheDocument(); + + userEvent.click(actionBtn); + }); + + axiosMock + .onPost(getXBlockBaseApiUrl(blockId), { + publish: PUBLISH_TYPES.discardChanges, + }) + .reply(200, { dummy: 'value' }); + axiosMock + .onGet(getCourseUnitApiUrl(blockId)) + .reply(200, { + ...courseUnitIndexMock, published: true, has_changes: false, + }); + + await executeThunk(editCourseUnitVisibilityAndData( + blockId, + PUBLISH_TYPES.discardChanges, + true, + ), store.dispatch); + + expect(within(courseUnitSidebar) + .getByText(sidebarMessages.sidebarTitlePublishedNotYetReleased.defaultMessage)).toBeInTheDocument(); + expect(discardChangesBtn).not.toBeInTheDocument(); + }); }); diff --git a/src/course-unit/constants.js b/src/course-unit/constants.js index ecf07815f2..c32d123796 100644 --- a/src/course-unit/constants.js +++ b/src/course-unit/constants.js @@ -62,3 +62,9 @@ export const COLORS = { BLACK: '#000', GREEN: '#0D7D4D', }; + +export const PUBLISH_TYPES = { + republish: 'republish', + discardChanges: 'discard_changes', + makePublic: 'make_public', +}; diff --git a/src/course-unit/data/api.js b/src/course-unit/data/api.js index 43992f576d..f7adc33b47 100644 --- a/src/course-unit/data/api.js +++ b/src/course-unit/data/api.js @@ -2,6 +2,7 @@ import { camelCaseObject, getConfig } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import { PUBLISH_TYPES } from '../constants'; import { normalizeLearningSequencesData, normalizeMetadata, @@ -130,6 +131,30 @@ export async function createCourseXblock({ return data; } +/** + * Handles the visibility and data of a course unit, such as publishing, resetting to default values, + * and toggling visibility to students. + * @param {string} unitId - The ID of the course unit. + * @param {string} type - The action type (e.g., PUBLISH_TYPES.discardChanges). + * @param {boolean} isVisible - The visibility status for students. + * @returns {Promise} A promise that resolves with the response data. + */ +export async function handleCourseUnitVisibilityAndData(unitId, type, isVisible) { + const body = { + publish: type, + ...(type === PUBLISH_TYPES.republish ? { + metadata: { + visible_to_staff_only: isVisible, + }, + } : {}), + }; + + const { data } = await getAuthenticatedHttpClient() + .post(getXBlockBaseApiUrl(unitId), body); + + return camelCaseObject(data); +} + /** * Get an object containing course section vertical children data. * @param {string} itemId diff --git a/src/course-unit/data/thunk.js b/src/course-unit/data/thunk.js index b6e2477849..7117acd439 100644 --- a/src/course-unit/data/thunk.js +++ b/src/course-unit/data/thunk.js @@ -18,6 +18,7 @@ import { getCourseSectionVerticalData, createCourseXblock, getCourseVerticalChildren, + handleCourseUnitVisibilityAndData, deleteUnitItem, duplicateUnitItem, } from './api'; @@ -37,9 +38,11 @@ import { updateLoadingCourseXblockStatus, updateCourseVerticalChildren, updateCourseVerticalChildrenLoadingStatus, + updateQueryPendingStatus, deleteXBlock, duplicateXBlock, } from './slice'; +import { getNotificationMessage } from './utils'; export function fetchCourseUnitQuery(courseId) { return async (dispatch) => { @@ -117,6 +120,31 @@ export function editCourseItemQuery(itemId, displayName, sequenceId) { }; } +export function editCourseUnitVisibilityAndData(itemId, type, isVisible) { + return async (dispatch) => { + dispatch(updateSavingStatus({ status: RequestStatus.PENDING })); + dispatch(updateQueryPendingStatus(true)); + const notificationMessage = getNotificationMessage(type, isVisible); + dispatch(showProcessingNotification(notificationMessage)); + + try { + await handleCourseUnitVisibilityAndData(itemId, type, isVisible).then(async (result) => { + if (result) { + const courseUnit = await getCourseUnitData(itemId); + dispatch(fetchCourseItemSuccess(courseUnit)); + const courseVerticalChildrenData = await getCourseVerticalChildren(itemId); + dispatch(updateCourseVerticalChildren(courseVerticalChildrenData)); + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); + } + }); + } catch (error) { + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatus({ status: RequestStatus.FAILED })); + } + }; +} + export function fetchCourse(courseId) { return async (dispatch) => { dispatch(fetchCourseRequest({ courseId })); @@ -221,6 +249,8 @@ export function createNewCourseXBlock(body, callback, blockId) { callback(result); } } + const courseUnit = await getCourseUnitData(blockId); + dispatch(fetchCourseItemSuccess(courseUnit)); }); } catch (error) { dispatch(hideProcessingNotification()); diff --git a/src/course-unit/data/utils.js b/src/course-unit/data/utils.js index c41db3a85a..afd6e0a03a 100644 --- a/src/course-unit/data/utils.js +++ b/src/course-unit/data/utils.js @@ -1,5 +1,8 @@ import { camelCaseObject } from '@edx/frontend-platform'; +import { NOTIFICATION_MESSAGES } from '../../constants'; +import { PUBLISH_TYPES } from '../constants'; + export function getTimeOffsetMillis(headerDate, requestTime, responseTime) { // Time offset computation should move down into the HttpClient wrapper to maintain a global time correction reference // Requires 'Access-Control-Expose-Headers: Date' on the server response per https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#access-control-expose-headers @@ -211,3 +214,25 @@ export function normalizeCourseSectionVerticalData(metadata) { })), }; } + +/** + * Get the notification message based on the publishing type and visibility. + * @param {string} type - The publishing type. + * @param {boolean} isVisible - The visibility status. + * @returns {string} The corresponding notification message. + */ +export const getNotificationMessage = (type, isVisible) => { + let notificationMessage; + + if (type === PUBLISH_TYPES.discardChanges) { + notificationMessage = NOTIFICATION_MESSAGES.discardChanges; + } else if (type === PUBLISH_TYPES.makePublic) { + notificationMessage = NOTIFICATION_MESSAGES.publishing; + } else if (type === PUBLISH_TYPES.republish && !isVisible) { + notificationMessage = NOTIFICATION_MESSAGES.makingVisibleToStudents; + } else if (type === PUBLISH_TYPES.republish && isVisible) { + notificationMessage = NOTIFICATION_MESSAGES.hidingFromStudents; + } + + return notificationMessage; +}; diff --git a/src/course-unit/sidebar/Sidebar.scss b/src/course-unit/sidebar/Sidebar.scss index 537e521082..eb4bd0adac 100644 --- a/src/course-unit/sidebar/Sidebar.scss +++ b/src/course-unit/sidebar/Sidebar.scss @@ -31,6 +31,7 @@ .course-unit-sidebar-location-description { font-size: $font-size-xs; line-height: $line-height-base; + word-break: break-word; } .course-unit-sidebar-visibility-copy { diff --git a/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.jsx b/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.jsx index 3fb98f5cc6..ac0a63287d 100644 --- a/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.jsx +++ b/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.jsx @@ -1,3 +1,4 @@ +import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { Button } from '@openedx/paragon'; import { useIntl } from '@edx/frontend-platform/i18n'; @@ -5,7 +6,7 @@ import { useIntl } from '@edx/frontend-platform/i18n'; import { getCourseUnitData } from '../../../data/selectors'; import messages from '../../messages'; -const ActionButtons = () => { +const ActionButtons = ({ openDiscardModal, handlePublishing }) => { const intl = useIntl(); const { published, @@ -16,29 +17,17 @@ const ActionButtons = () => { return ( <> {(!published || hasChanges) && ( - )} {(published && hasChanges) && ( - )} {enableCopyPasteUnits && ( - )} @@ -46,4 +35,9 @@ const ActionButtons = () => { ); }; +ActionButtons.propTypes = { + openDiscardModal: PropTypes.func.isRequired, + handlePublishing: PropTypes.func.isRequired, +}; + export default ActionButtons; diff --git a/src/course-unit/sidebar/components/sidebar-footer/UnitVisibilityInfo.jsx b/src/course-unit/sidebar/components/sidebar-footer/UnitVisibilityInfo.jsx index 2603330011..13c566b1bc 100644 --- a/src/course-unit/sidebar/components/sidebar-footer/UnitVisibilityInfo.jsx +++ b/src/course-unit/sidebar/components/sidebar-footer/UnitVisibilityInfo.jsx @@ -1,23 +1,32 @@ -import { useSelector } from 'react-redux'; +import PropTypes from 'prop-types'; +import { useDispatch, useSelector } from 'react-redux'; import { Form } from '@openedx/paragon'; import { useIntl } from '@edx/frontend-platform/i18n'; +import { useParams } from 'react-router-dom'; import { getCourseUnitData } from '../../../data/selectors'; +import { editCourseUnitVisibilityAndData } from '../../../data/thunk'; +import { PUBLISH_TYPES } from '../../../constants'; import { getVisibilityTitle } from '../../utils'; import messages from '../../messages'; -const UnitVisibilityInfo = () => { +const UnitVisibilityInfo = ({ openVisibleModal, visibleToStaffOnly }) => { const intl = useIntl(); + const { blockId } = useParams(); + const dispatch = useDispatch(); const { published, hasChanges, staffLockFrom, releaseDateFrom, releasedToStudents, - visibleToStaffOnly, hasExplicitStaffLock, } = useSelector(getCourseUnitData); + const handleCourseUnitVisibility = () => { + dispatch(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.republish, true)); + }; + return ( <> @@ -44,7 +53,8 @@ const UnitVisibilityInfo = () => { {}} + onChange={hasExplicitStaffLock ? null : handleCourseUnitVisibility} + onClick={hasExplicitStaffLock ? openVisibleModal : null} > {intl.formatMessage(messages.visibilityCheckboxTitle)} @@ -52,4 +62,9 @@ const UnitVisibilityInfo = () => { ); }; +UnitVisibilityInfo.propTypes = { + openVisibleModal: PropTypes.func.isRequired, + visibleToStaffOnly: PropTypes.bool.isRequired, +}; + export default UnitVisibilityInfo; diff --git a/src/course-unit/sidebar/components/sidebar-footer/index.jsx b/src/course-unit/sidebar/components/sidebar-footer/index.jsx index 35ed27dc84..36387a08e1 100644 --- a/src/course-unit/sidebar/components/sidebar-footer/index.jsx +++ b/src/course-unit/sidebar/components/sidebar-footer/index.jsx @@ -6,7 +6,14 @@ import messages from '../../messages'; import UnitVisibilityInfo from './UnitVisibilityInfo'; import ActionButtons from './ActionButtons'; -const SidebarFooter = ({ isDisplayUnitLocation, locationId }) => { +const SidebarFooter = ({ + locationId, + openVisibleModal, + handlePublishing, + openDiscardModal, + visibleToStaffOnly, + isDisplayUnitLocation, +}) => { const intl = useIntl(); return ( @@ -18,8 +25,14 @@ const SidebarFooter = ({ isDisplayUnitLocation, locationId }) => { ) : ( <> - - + + )} @@ -28,8 +41,12 @@ const SidebarFooter = ({ isDisplayUnitLocation, locationId }) => { }; SidebarFooter.propTypes = { - isDisplayUnitLocation: PropTypes.bool, locationId: PropTypes.string, + isDisplayUnitLocation: PropTypes.bool, + openDiscardModal: PropTypes.func.isRequired, + openVisibleModal: PropTypes.func.isRequired, + handlePublishing: PropTypes.func.isRequired, + visibleToStaffOnly: PropTypes.bool.isRequired, }; SidebarFooter.defaultProps = { diff --git a/src/course-unit/sidebar/index.jsx b/src/course-unit/sidebar/index.jsx index eae1e1b2f7..cd35cd3e03 100644 --- a/src/course-unit/sidebar/index.jsx +++ b/src/course-unit/sidebar/index.jsx @@ -1,13 +1,19 @@ import PropTypes from 'prop-types'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import classNames from 'classnames'; -import { Card } from '@openedx/paragon'; +import { Card, useToggle } from '@openedx/paragon'; +import { InfoOutline as InfoOutlineIcon } from '@openedx/paragon/icons'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import ModalNotification from '../../generic/modal-notification'; +import { editCourseUnitVisibilityAndData } from '../data/thunk'; import { getCourseUnitData } from '../data/selectors'; +import { PUBLISH_TYPES } from '../constants'; import { SidebarBody, SidebarFooter, SidebarHeader } from './components'; import useCourseUnitData from './hooks'; +import messages from './messages'; -const Sidebar = ({ isDisplayUnitLocation }) => { +const Sidebar = ({ blockId, isDisplayUnitLocation, ...props }) => { const { title, locationId, @@ -15,13 +21,31 @@ const Sidebar = ({ isDisplayUnitLocation }) => { visibilityState, visibleToStaffOnly, } = useCourseUnitData(useSelector(getCourseUnitData)); + const intl = useIntl(); + const dispatch = useDispatch(); + const [isOpenDiscardModal, openDiscardModal, closeDiscardModal] = useToggle(false); + const [isOpenVisibleModal, openVisibleModal, closeVisibleModal] = useToggle(false); + + const handleCourseUnitVisibility = () => { + closeVisibleModal(); + dispatch(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.republish, null)); + }; + + const handleCourseUnitDiscardChanges = () => { + closeDiscardModal(); + dispatch(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.discardChanges)); + }; + + const handleCourseUnitPublish = () => { + dispatch(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic)); + }; return ( { /> + + ); }; Sidebar.propTypes = { + blockId: PropTypes.string, isDisplayUnitLocation: PropTypes.bool, }; Sidebar.defaultProps = { + blockId: null, isDisplayUnitLocation: false, }; diff --git a/src/course-unit/sidebar/messages.js b/src/course-unit/sidebar/messages.js index bb9a75c311..ddc4b45678 100644 --- a/src/course-unit/sidebar/messages.js +++ b/src/course-unit/sidebar/messages.js @@ -105,6 +105,38 @@ const messages = defineMessages({ id: 'course-authoring.course-unit.status.scheduled.title', defaultMessage: 'SCHEDULED', }, + modalDiscardUnitChangesTitle: { + id: 'course-authoring.course-unit.modal.discard-unit-changes.title', + defaultMessage: 'Discard changes', + }, + modalDiscardUnitChangesActionButtonText: { + id: 'course-authoring.course-unit.modal.discard-unit-changes.btn.action.text', + defaultMessage: 'Discard changes', + }, + modalDiscardUnitChangesCancelButtonText: { + id: 'course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text', + defaultMessage: 'Cancel', + }, + modalDiscardUnitChangesDescription: { + id: 'course-authoring.course-unit.modal.discard-unit-changes.description', + defaultMessage: 'Are you sure you want to revert to the last published version of the unit? You cannot undo this action.', + }, + modalMakeVisibilityTitle: { + id: 'course-authoring.course-unit.modal.make-visibility.title', + defaultMessage: 'Make visible to students', + }, + modalMakeVisibilityActionButtonText: { + id: 'course-authoring.course-unit.modal.make-visibility.btn.action.text', + defaultMessage: 'Make visible to students', + }, + modalMakeVisibilityCancelButtonText: { + id: 'course-authoring.course-unit.modal.make-visibility.btn.cancel.text', + defaultMessage: 'Cancel', + }, + modalMakeVisibilityDescription: { + id: 'course-authoring.course-unit.modal.make-visibility.description', + defaultMessage: 'If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?', + }, }); export default messages; diff --git a/src/export-page/export-modal-error/ExportModalError.jsx b/src/export-page/export-modal-error/ExportModalError.jsx index 56921a84c4..64d67f2f16 100644 --- a/src/export-page/export-modal-error/ExportModalError.jsx +++ b/src/export-page/export-modal-error/ExportModalError.jsx @@ -3,8 +3,9 @@ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { useDispatch, useSelector } from 'react-redux'; import { getConfig } from '@edx/frontend-platform'; import PropTypes from 'prop-types'; +import { Error as ErrorIcon } from '@openedx/paragon/icons'; -import ModalError from '../../generic/modal-error/ModalError'; +import ModalNotification from '../../generic/modal-notification'; import { getError, getIsErrorModalOpen } from '../data/selectors'; import { updateIsErrorModalOpen } from '../data/slice'; import messages from './messages'; @@ -20,7 +21,7 @@ const ExportModalError = ({ const handleUnitRedirect = () => { window.location.assign(unitErrorUrl); }; const handleRedirectCourseHome = () => { window.location.assign(`${getConfig().STUDIO_BASE_URL}/course/${courseId}`); }; return ( - dispatch(updateIsErrorModalOpen(false))} handleAction={unitErrorUrl ? handleUnitRedirect : handleRedirectCourseHome} + variant="danger" + icon={ErrorIcon} /> ); }; diff --git a/src/generic/modal-error/ModalError.jsx b/src/generic/modal-notification/index.jsx similarity index 72% rename from src/generic/modal-error/ModalError.jsx rename to src/generic/modal-notification/index.jsx index a4de402b69..ae1dc2ba87 100644 --- a/src/generic/modal-error/ModalError.jsx +++ b/src/generic/modal-notification/index.jsx @@ -1,16 +1,15 @@ import React from 'react'; import PropTypes from 'prop-types'; import { ActionRow, AlertModal, Button } from '@openedx/paragon'; -import { Error } from '@openedx/paragon/icons'; -const ModalError = ({ - isOpen, title, message, handleCancel, handleAction, cancelButtonText, actionButtonText, +const ModalNotification = ({ + isOpen, title, message, handleCancel, handleAction, cancelButtonText, actionButtonText, variant, icon, }) => ( @@ -22,7 +21,7 @@ const ModalError = ({ ); -ModalError.propTypes = { +ModalNotification.propTypes = { isOpen: PropTypes.bool.isRequired, title: PropTypes.string.isRequired, message: PropTypes.string.isRequired, @@ -30,6 +29,13 @@ ModalError.propTypes = { handleAction: PropTypes.func.isRequired, cancelButtonText: PropTypes.string.isRequired, actionButtonText: PropTypes.string.isRequired, + variant: PropTypes.string, + icon: PropTypes.elementType, }; -export default ModalError; +ModalNotification.defaultProps = { + variant: 'default', + icon: undefined, +}; + +export default ModalNotification; diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index a26a97c577..0689d8e79a 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -1045,5 +1045,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience.", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", "course-authoring.course-unit.xblock.button.actions.alt": "Actions" } diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 6a18e9e180..8bc76c831c 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -1020,5 +1020,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience." } diff --git a/src/i18n/messages/de_DE.json b/src/i18n/messages/de_DE.json index 5ad4d1441d..943696a976 100644 --- a/src/i18n/messages/de_DE.json +++ b/src/i18n/messages/de_DE.json @@ -1046,5 +1046,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience.", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?" } diff --git a/src/i18n/messages/es_419.json b/src/i18n/messages/es_419.json index d6efdea78f..b2124e2d7d 100644 --- a/src/i18n/messages/es_419.json +++ b/src/i18n/messages/es_419.json @@ -1020,5 +1020,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience." } diff --git a/src/i18n/messages/fa_IR.json b/src/i18n/messages/fa_IR.json index e2fc0af12f..12e1514790 100644 --- a/src/i18n/messages/fa_IR.json +++ b/src/i18n/messages/fa_IR.json @@ -43,5 +43,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience." } diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index 4c874a0659..6f6a47dc5d 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -1020,5 +1020,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience." } diff --git a/src/i18n/messages/fr_CA.json b/src/i18n/messages/fr_CA.json index f2c2d095d3..8840d70b3d 100644 --- a/src/i18n/messages/fr_CA.json +++ b/src/i18n/messages/fr_CA.json @@ -1020,5 +1020,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience." } diff --git a/src/i18n/messages/hi.json b/src/i18n/messages/hi.json index 6a18e9e180..8bc76c831c 100644 --- a/src/i18n/messages/hi.json +++ b/src/i18n/messages/hi.json @@ -1020,5 +1020,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience." } diff --git a/src/i18n/messages/it.json b/src/i18n/messages/it.json index 6a18e9e180..8bc76c831c 100644 --- a/src/i18n/messages/it.json +++ b/src/i18n/messages/it.json @@ -1020,5 +1020,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience." } diff --git a/src/i18n/messages/it_IT.json b/src/i18n/messages/it_IT.json index 3c53c52637..3bb8914eca 100644 --- a/src/i18n/messages/it_IT.json +++ b/src/i18n/messages/it_IT.json @@ -1020,5 +1020,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience." } diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index 6a18e9e180..8bc76c831c 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -1020,5 +1020,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience." } diff --git a/src/i18n/messages/pt_PT.json b/src/i18n/messages/pt_PT.json index 88c7ddd23a..9519dcc9d2 100644 --- a/src/i18n/messages/pt_PT.json +++ b/src/i18n/messages/pt_PT.json @@ -1020,5 +1020,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience." } diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index 6a18e9e180..8bc76c831c 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -1020,5 +1020,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience." } diff --git a/src/i18n/messages/uk.json b/src/i18n/messages/uk.json index 6a18e9e180..8bc76c831c 100644 --- a/src/i18n/messages/uk.json +++ b/src/i18n/messages/uk.json @@ -1020,5 +1020,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience." } diff --git a/src/i18n/messages/zh_CN.json b/src/i18n/messages/zh_CN.json index 6a18e9e180..8bc76c831c 100644 --- a/src/i18n/messages/zh_CN.json +++ b/src/i18n/messages/zh_CN.json @@ -1020,5 +1020,36 @@ "course-authoring.course-unit.xblock.button.move.label": "Move", "course-authoring.course-unit.xblock.button.manageAccess.label": "Manage access", "course-authoring.course-unit.xblock.button.delete.label": "Delete", - "course-authoring.course-unit.xblock.button.actions.alt": "Actions" + "course-authoring.course-unit.xblock.button.actions.alt": "Actions", + "course-authoring.course-unit.modal.discard-unit-changes.title": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.action.text": "Discard changes", + "course-authoring.course-unit.modal.discard-unit-changes.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.discard-unit-changes.description": "Are you sure you want to revert to the last published version of the unit? You cannot undo this action.", + "course-authoring.course-unit.modal.make-visibility.title": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.action.text": "Make visible to students", + "course-authoring.course-unit.modal.make-visibility.btn.cancel.text": "Cancel", + "course-authoring.course-unit.modal.make-visibility.description": "If the unit was previously published and released to students, any changes you made to the unit when it was hidden will now be visible to students. Do you want to proceed?", + "course-authoring.group-configurations.heading-title": "Group configurations", + "course-authoring.group-configurations.heading-sub-title": "Settings", + "course-authoring.group-configurations.container.empty-content-groups": "In the {outlineComponentLink}, use this group to control access to a component.", + "course-authoring.group-configurations.container.empty-experiment-group": "This group configuration is not in use. Start by adding a content experiment to any Unit via the {outlineComponentLink}.", + "course-authoring.group-configurations.container.course-outline": "Course outline", + "course-authoring.group-configurations.container.action.edit": "Edit", + "course-authoring.group-configurations.container.action.delete": "Delete", + "course-authoring.group-configurations.container.access-to": "This group controls access to:", + "course-authoring.group-configurations.container.experiment-access-to": "This group configuration is used in:", + "course-authoring.group-configurations.container.contains-groups": "Contains {len} groups", + "course-authoring.group-configurations.container.contains-group": "Contains 1 group", + "course-authoring.group-configurations.container.not-in-use": "Not in use", + "course-authoring.group-configurations.container.used-in-locations": "Used in {len} locations", + "course-authoring.group-configurations.container.used-in-location": "Used in 1 location", + "course-authoring.group-configurations.container.title-id": "ID: {id}", + "course-authoring.group-configurations.experiment-group.title": "Experiment group configurations", + "course-authoring.group-configurations.experiment-group.add-new-group": "New group configuration", + "course-authoring.group-configurations.empty-placeholder.title": "You have not created any content groups yet.", + "course-authoring.group-configurations.experimental-empty-placeholder.title": "You have not created any group configurations yet.", + "course-authoring.group-configurations.empty-placeholder.button": "Add your first content group", + "course-authoring.group-configurations.experimental-empty-placeholder.button": "Add your first group configuration", + "course-authoring.group-configurations.content-groups.add-new-group": "New content group", + "course-authoring.course-unit.general.alert.unpublished-version.description": "Note: The last published version of this unit is live. By publishing changes you will change the student experience." } From 895f6560fe29b51fb630e947bec32d34199dd388 Mon Sep 17 00:00:00 2001 From: Peter Kulko <93188219+PKulkoRaccoonGang@users.noreply.github.com> Date: Fri, 26 Jan 2024 17:33:02 +0200 Subject: [PATCH 04/10] feat: [AXIMST-25] Course unit - Alert notification about unpublished changes (#135) * feat: [AXIMST-25] added alert notification about unpublished changes * feat: added tests * feat: added translations --- src/course-unit/CourseUnit.jsx | 10 +++++++++ src/course-unit/CourseUnit.test.jsx | 33 ++++++++++++++++++++++++++++- src/course-unit/hooks.jsx | 3 +++ src/course-unit/messages.js | 4 ++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/course-unit/CourseUnit.jsx b/src/course-unit/CourseUnit.jsx index f94bf3497c..7c40f9daf6 100644 --- a/src/course-unit/CourseUnit.jsx +++ b/src/course-unit/CourseUnit.jsx @@ -4,11 +4,13 @@ import { useParams } from 'react-router-dom'; import { Container, Layout, Stack } from '@openedx/paragon'; import { useIntl, injectIntl } from '@edx/frontend-platform/i18n'; import { ErrorAlert } from '@edx/frontend-lib-content-components'; +import { Warning as WarningIcon } from '@openedx/paragon/icons'; import { getProcessingNotification } from '../generic/processing-notification/data/selectors'; import SubHeader from '../generic/sub-header/SubHeader'; import { RequestStatus } from '../data/constants'; import getPageHeadTitle from '../generic/utils'; +import AlertMessage from '../generic/alert-message'; import ProcessingNotification from '../generic/processing-notification'; import InternetConnectionAlert from '../generic/internet-connection-alert'; import Loading from '../generic/Loading'; @@ -33,6 +35,7 @@ const CourseUnit = ({ courseId }) => { savingStatus, isTitleEditFormOpen, isErrorAlert, + isLastUnpublishedVersion, isInternetConnectionAlertFailed, unitXBlockActions, handleTitleEditSubmit, @@ -94,6 +97,13 @@ const CourseUnit = ({ courseId }) => { xl={[{ span: 9 }, { span: 3 }]} > + {isLastUnpublishedVersion && ( + + )} {courseVerticalChildren.children.map(({ name, blockId: id, shouldScroll }) => ( ', () => { }); }); + it('should display a warning alert for unpublished course unit version', async () => { + const { getByRole } = render(); + + await waitFor(() => { + const unpublishedAlert = getByRole('alert', { class: 'course-unit-unpublished-alert' }); + expect(unpublishedAlert).toHaveTextContent(messages.alertUnpublishedVersion.defaultMessage); + expect(unpublishedAlert).toHaveClass('alert-warning'); + }); + }); + + it('should not display an unpublished alert for a course unit with explicit staff lock and unpublished status', async () => { + const { queryByRole } = render(); + + axiosMock + .onGet(getCourseUnitApiUrl(courseId)) + .reply(200, { + ...courseUnitIndexMock, + has_explicit_staff_lock: true, + release_date: null, + published: false, + }); + + await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); + + await waitFor(() => { + const unpublishedAlert = queryByRole('alert', { class: 'course-unit-unpublished-alert' }); + expect(unpublishedAlert).toBeNull(); + }); + }); + it('checks whether xblock is deleted when corresponding delete button is clicked', async () => { axiosMock .onDelete(getXBlockBaseApiUrl(courseVerticalChildrenMock.children[0].block_id)) diff --git a/src/course-unit/hooks.jsx b/src/course-unit/hooks.jsx index b99bfaed1a..f6f8838286 100644 --- a/src/course-unit/hooks.jsx +++ b/src/course-unit/hooks.jsx @@ -36,6 +36,8 @@ export const useCourseUnit = ({ courseId, blockId }) => { const navigate = useNavigate(); const isTitleEditFormOpen = useSelector(state => state.courseUnit.isTitleEditFormOpen); const isQueryPending = useSelector(state => state.courseUnit.isQueryPending); + const { hasExplicitStaffLock, published, releaseDate } = courseUnit; + const isLastUnpublishedVersion = !hasExplicitStaffLock && published && releaseDate; const unitTitle = courseUnit.metadata?.displayName || ''; const sequenceId = courseUnit.ancestorInfo?.ancestors[0].id; @@ -108,6 +110,7 @@ export const useCourseUnit = ({ courseId, blockId }) => { savingStatus, isQueryPending, isErrorAlert, + isLastUnpublishedVersion, isLoading: loadingStatus.fetchUnitLoadingStatus === RequestStatus.IN_PROGRESS || loadingStatus.courseSectionVerticalLoadingStatus === RequestStatus.IN_PROGRESS, isTitleEditFormOpen, diff --git a/src/course-unit/messages.js b/src/course-unit/messages.js index 42533513e5..ba27b0fb78 100644 --- a/src/course-unit/messages.js +++ b/src/course-unit/messages.js @@ -5,6 +5,10 @@ const messages = defineMessages({ id: 'course-authoring.course-unit.general.alert.error.description', defaultMessage: 'Unable to {actionName} {type}. Please try again.', }, + alertUnpublishedVersion: { + id: 'course-authoring.course-unit.general.alert.unpublished-version.description', + defaultMessage: 'Note: The last published version of this unit is live. By publishing changes you will change the student experience.', + }, }); export default messages; From ffc3f6fd71986bf55a46d7f25b3811ca048e6c89 Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Thu, 1 Feb 2024 12:19:21 +0200 Subject: [PATCH 05/10] fix: [AXIMST-427] fixed unpublished changes alert --- src/course-unit/CourseUnit.jsx | 4 ++-- src/course-unit/CourseUnit.test.jsx | 4 +--- src/course-unit/hooks.jsx | 5 ++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/course-unit/CourseUnit.jsx b/src/course-unit/CourseUnit.jsx index 7c40f9daf6..48d91978a9 100644 --- a/src/course-unit/CourseUnit.jsx +++ b/src/course-unit/CourseUnit.jsx @@ -35,7 +35,7 @@ const CourseUnit = ({ courseId }) => { savingStatus, isTitleEditFormOpen, isErrorAlert, - isLastUnpublishedVersion, + currentlyVisibleToStudents, isInternetConnectionAlertFailed, unitXBlockActions, handleTitleEditSubmit, @@ -97,7 +97,7 @@ const CourseUnit = ({ courseId }) => { xl={[{ span: 9 }, { span: 3 }]} > - {isLastUnpublishedVersion && ( + {currentlyVisibleToStudents && ( ', () => { .onGet(getCourseUnitApiUrl(courseId)) .reply(200, { ...courseUnitIndexMock, - has_explicit_staff_lock: true, - release_date: null, - published: false, + currently_visible_to_students: false, }); await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); diff --git a/src/course-unit/hooks.jsx b/src/course-unit/hooks.jsx index f6f8838286..dea7599b89 100644 --- a/src/course-unit/hooks.jsx +++ b/src/course-unit/hooks.jsx @@ -36,8 +36,7 @@ export const useCourseUnit = ({ courseId, blockId }) => { const navigate = useNavigate(); const isTitleEditFormOpen = useSelector(state => state.courseUnit.isTitleEditFormOpen); const isQueryPending = useSelector(state => state.courseUnit.isQueryPending); - const { hasExplicitStaffLock, published, releaseDate } = courseUnit; - const isLastUnpublishedVersion = !hasExplicitStaffLock && published && releaseDate; + const { currentlyVisibleToStudents } = courseUnit; const unitTitle = courseUnit.metadata?.displayName || ''; const sequenceId = courseUnit.ancestorInfo?.ancestors[0].id; @@ -110,7 +109,7 @@ export const useCourseUnit = ({ courseId, blockId }) => { savingStatus, isQueryPending, isErrorAlert, - isLastUnpublishedVersion, + currentlyVisibleToStudents, isLoading: loadingStatus.fetchUnitLoadingStatus === RequestStatus.IN_PROGRESS || loadingStatus.courseSectionVerticalLoadingStatus === RequestStatus.IN_PROGRESS, isTitleEditFormOpen, From cad3346497639eedefba846c23ed83b9af2a4115 Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Wed, 7 Feb 2024 13:29:05 +0200 Subject: [PATCH 06/10] fix: [AXIMST-472] fixed sidebar visibility notification --- src/course-unit/sidebar/Sidebar.scss | 4 +++ .../sidebar-footer/UnitVisibilityInfo.jsx | 7 ++--- src/course-unit/sidebar/messages.js | 2 +- src/i18n/messages/ar.json | 2 +- src/i18n/messages/de.json | 26 +++++++++++++++++++ src/i18n/messages/de_DE.json | 2 +- src/i18n/messages/es_419.json | 26 +++++++++++++++++++ src/i18n/messages/fa_IR.json | 26 +++++++++++++++++++ src/i18n/messages/fr.json | 26 +++++++++++++++++++ src/i18n/messages/fr_CA.json | 26 +++++++++++++++++++ src/i18n/messages/hi.json | 26 +++++++++++++++++++ src/i18n/messages/it.json | 26 +++++++++++++++++++ src/i18n/messages/it_IT.json | 26 +++++++++++++++++++ src/i18n/messages/pt.json | 26 +++++++++++++++++++ src/i18n/messages/pt_PT.json | 26 +++++++++++++++++++ src/i18n/messages/ru.json | 26 +++++++++++++++++++ src/i18n/messages/uk.json | 26 +++++++++++++++++++ src/i18n/messages/zh_CN.json | 26 +++++++++++++++++++ 18 files changed, 347 insertions(+), 8 deletions(-) diff --git a/src/course-unit/sidebar/Sidebar.scss b/src/course-unit/sidebar/Sidebar.scss index eb4bd0adac..954e20d4b2 100644 --- a/src/course-unit/sidebar/Sidebar.scss +++ b/src/course-unit/sidebar/Sidebar.scss @@ -28,6 +28,10 @@ @extend %base-font-params; } + .course-unit-sidebar-visibility-section { + @extend %base-font-params; + } + .course-unit-sidebar-location-description { font-size: $font-size-xs; line-height: $line-height-base; diff --git a/src/course-unit/sidebar/components/sidebar-footer/UnitVisibilityInfo.jsx b/src/course-unit/sidebar/components/sidebar-footer/UnitVisibilityInfo.jsx index 13c566b1bc..b4dc35b568 100644 --- a/src/course-unit/sidebar/components/sidebar-footer/UnitVisibilityInfo.jsx +++ b/src/course-unit/sidebar/components/sidebar-footer/UnitVisibilityInfo.jsx @@ -18,7 +18,6 @@ const UnitVisibilityInfo = ({ openVisibleModal, visibleToStaffOnly }) => { published, hasChanges, staffLockFrom, - releaseDateFrom, releasedToStudents, hasExplicitStaffLock, } = useSelector(getCourseUnitData); @@ -38,10 +37,8 @@ const UnitVisibilityInfo = ({ openVisibleModal, visibleToStaffOnly }) => { {intl.formatMessage(messages.visibilityStaffOnlyTitle)} {!hasExplicitStaffLock && ( - - {intl.formatMessage(messages.visibilityHasExplicitStaffLockText, { - date: releaseDateFrom, sectionName: staffLockFrom, - })} + + {intl.formatMessage(messages.visibilityHasExplicitStaffLockText, { sectionName: staffLockFrom })} )} diff --git a/src/course-unit/sidebar/messages.js b/src/course-unit/sidebar/messages.js index ddc4b45678..7d9d161d5c 100644 --- a/src/course-unit/sidebar/messages.js +++ b/src/course-unit/sidebar/messages.js @@ -79,7 +79,7 @@ const messages = defineMessages({ }, visibilityHasExplicitStaffLockText: { id: 'course-authoring.course-unit.visibility.has-explicit-staff-lock.text', - defaultMessage: 'with {date} {sectionName}', + defaultMessage: 'with {sectionName}', }, actionButtonPublishTitle: { id: 'course-authoring.course-unit.action-buttons.publish.title', diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index 0689d8e79a..5ddf05c815 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -1032,7 +1032,7 @@ "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", "course-authoring.course-unit.visibility.staff-only.title": "Staff only", "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", "course-authoring.course-unit.action-buttons.publish.title": "Publish", "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 8bc76c831c..ad312d6647 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -1014,6 +1014,32 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/de_DE.json b/src/i18n/messages/de_DE.json index 943696a976..ad043c3f7c 100644 --- a/src/i18n/messages/de_DE.json +++ b/src/i18n/messages/de_DE.json @@ -1033,7 +1033,7 @@ "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", "course-authoring.course-unit.visibility.staff-only.title": "Staff only", "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", - "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {date} {sectionName}", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", "course-authoring.course-unit.action-buttons.publish.title": "Publish", "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", diff --git a/src/i18n/messages/es_419.json b/src/i18n/messages/es_419.json index b2124e2d7d..8ecd721182 100644 --- a/src/i18n/messages/es_419.json +++ b/src/i18n/messages/es_419.json @@ -1014,6 +1014,32 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/fa_IR.json b/src/i18n/messages/fa_IR.json index 12e1514790..a9d33d6636 100644 --- a/src/i18n/messages/fa_IR.json +++ b/src/i18n/messages/fa_IR.json @@ -37,6 +37,32 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index 6f6a47dc5d..6287473708 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -1014,6 +1014,32 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/fr_CA.json b/src/i18n/messages/fr_CA.json index 8840d70b3d..071a2b2934 100644 --- a/src/i18n/messages/fr_CA.json +++ b/src/i18n/messages/fr_CA.json @@ -1014,6 +1014,32 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/hi.json b/src/i18n/messages/hi.json index 8bc76c831c..ad312d6647 100644 --- a/src/i18n/messages/hi.json +++ b/src/i18n/messages/hi.json @@ -1014,6 +1014,32 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/it.json b/src/i18n/messages/it.json index 8bc76c831c..ad312d6647 100644 --- a/src/i18n/messages/it.json +++ b/src/i18n/messages/it.json @@ -1014,6 +1014,32 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/it_IT.json b/src/i18n/messages/it_IT.json index 3bb8914eca..b743fe0365 100644 --- a/src/i18n/messages/it_IT.json +++ b/src/i18n/messages/it_IT.json @@ -1014,6 +1014,32 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index 8bc76c831c..ad312d6647 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -1014,6 +1014,32 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/pt_PT.json b/src/i18n/messages/pt_PT.json index 9519dcc9d2..b0567f5942 100644 --- a/src/i18n/messages/pt_PT.json +++ b/src/i18n/messages/pt_PT.json @@ -1014,6 +1014,32 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index 8bc76c831c..ad312d6647 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -1014,6 +1014,32 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/uk.json b/src/i18n/messages/uk.json index 8bc76c831c..ad312d6647 100644 --- a/src/i18n/messages/uk.json +++ b/src/i18n/messages/uk.json @@ -1014,6 +1014,32 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", diff --git a/src/i18n/messages/zh_CN.json b/src/i18n/messages/zh_CN.json index 8bc76c831c..ad312d6647 100644 --- a/src/i18n/messages/zh_CN.json +++ b/src/i18n/messages/zh_CN.json @@ -1014,6 +1014,32 @@ "course-authoring.course-unit.modal.button.text": "Select", "course-authoring.course-unit.modal.container.title": "Add {componentTitle} component", "course-authoring.course-unit.modal.container.cancel.button.text": "Cancel", + "course-authoring.course-unit.sidebar.title.draft.never-published": "Draft (never published)", + "course-authoring.course-unit.sidebar.title.visible.to-staff-only": "Visible to staff only", + "course-authoring.course-unit.sidebar.title.published.live": "Published and live", + "course-authoring.course-unit.sidebar.title.draft.unpublished": "Draft (unpublished changes)", + "course-authoring.course-unit.sidebar.title.published.not-yet-released": "Published (not yet released)", + "course-authoring.course-unit.sidebar.header.unit-location.title": "Unit location", + "course-authoring.course-unit.sidebar.body.note": "Note: Do not hide graded assignments after they have been released.", + "course-authoring.course-unit.publish.info.previously-published": "Previously published", + "course-authoring.course-unit.publish.info.draft.saved": "Draft saved on {editedOn} by {editedBy}", + "course-authoring.course-unit.publish.info.last.published": "Last published {publishedOn} by {publishedBy}", + "course-authoring.course-unit.release.info.unscheduled": "Unscheduled", + "course-authoring.course-unit.release.info.with-unit": "with {sectionName}", + "course-authoring.course-unit.visibility.is-visible-to.title": "IS VISIBLE TO", + "course-authoring.course-unit.visibility.will-be-visible-to.title": "WILL BE VISIBLE TO", + "course-authoring.course-unit.unit-location.title": "LOCATION ID", + "course-authoring.course-unit.unit-location.description": "To create a link to this unit from an HTML component in this course, enter /jump_to_id/{id} as the URL value", + "course-authoring.course-unit.visibility.checkbox.title": "Hide from learners", + "course-authoring.course-unit.visibility.staff-only.title": "Staff only", + "course-authoring.course-unit.visibility.staff-and-learners.title": "Staff and learners", + "course-authoring.course-unit.visibility.has-explicit-staff-lock.text": "with {sectionName}", + "course-authoring.course-unit.action-buttons.publish.title": "Publish", + "course-authoring.course-unit.action-button.discard-changes.title": "Discard changes", + "course-authoring.course-unit.action-button.copy-unit.title": "Copy unit", + "course-authoring.course-unit.status.release.title": "RELEASE", + "course-authoring.course-unit.status.released.title": "RELEASED", + "course-authoring.course-unit.status.scheduled.title": "SCHEDULED", "course-authoring.course-unit.xblock.button.edit.alt": "Edit Item", "course-authoring.course-unit.xblock.button.copy.label": "Copy", "course-authoring.course-unit.xblock.button.duplicate.label": "Duplicate", From ec2a681940f9c21d873635b674113cc5229857e4 Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Wed, 7 Feb 2024 19:15:34 +0200 Subject: [PATCH 07/10] fix: [AXIMST-473] fixed sidebar publish status --- src/course-unit/CourseUnit.test.jsx | 105 +++++++++++++++++++++++++++- src/course-unit/data/thunk.js | 3 + 2 files changed, 106 insertions(+), 2 deletions(-) diff --git a/src/course-unit/CourseUnit.test.jsx b/src/course-unit/CourseUnit.test.jsx index 4c4c4b53c1..f969321fe5 100644 --- a/src/course-unit/CourseUnit.test.jsx +++ b/src/course-unit/CourseUnit.test.jsx @@ -198,7 +198,27 @@ describe('', () => { axiosMock .onPost(postXBlockBaseApiUrl({ type: 'problem', category: 'problem', parentLocator: blockId })) .reply(200, courseCreateXblockMock); - const { getByRole } = render(); + const { getByText, getByRole } = render(); + + await waitFor(() => { + userEvent.click(getByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage })); + }); + + axiosMock + .onPost(getXBlockBaseApiUrl(blockId), { + publish: PUBLISH_TYPES.makePublic, + }) + .reply(200, { dummy: 'value' }); + axiosMock + .onGet(getCourseUnitApiUrl(blockId)) + .reply(200, { + ...courseUnitIndexMock, + visibility_state: UNIT_VISIBILITY_STATES.live, + has_changes: false, + published_by: userName, + }); + + await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); await waitFor(() => { const problemButton = getByRole('button', { @@ -209,6 +229,32 @@ describe('', () => { expect(mockedUsedNavigate).toHaveBeenCalled(); expect(mockedUsedNavigate).toHaveBeenCalledWith(`/course/${courseKey}/editor/problem/${locator}`); }); + + axiosMock + .onGet(getCourseUnitApiUrl(blockId)) + .reply(200, courseUnitIndexMock); + + await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); + + // after creating problem xblock, the sidebar status changes to Draft (unpublished changes) + expect(getByText(sidebarMessages.sidebarTitleDraftUnpublishedChanges.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityStaffAndLearnersTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.releaseStatusTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.sidebarBodyNote.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityWillBeVisibleToTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(courseUnitIndexMock.release_date)).toBeInTheDocument(); + expect(getByText( + sidebarMessages.publishInfoDraftSaved.defaultMessage + .replace('{editedOn}', courseUnitIndexMock.edited_on) + .replace('{editedBy}', courseUnitIndexMock.edited_by), + )).toBeInTheDocument(); + expect(getByText( + sidebarMessages.releaseInfoWithSection.defaultMessage + .replace('{sectionName}', courseUnitIndexMock.release_date_from), + )).toBeInTheDocument(); }); it('correct addition of a new course unit after click on the "Add new unit" button', async () => { @@ -303,9 +349,38 @@ describe('', () => { axiosMock .onPost(postXBlockBaseApiUrl({ type: 'video', category: 'video', parentLocator: blockId })) .reply(200, courseCreateXblockMock); - const { getByRole } = render(); + const { getByText, queryByRole, getByRole } = render(); await waitFor(() => { + userEvent.click(getByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage })); + }); + + axiosMock + .onPost(getXBlockBaseApiUrl(blockId), { + publish: PUBLISH_TYPES.makePublic, + }) + .reply(200, { dummy: 'value' }); + axiosMock + .onGet(getCourseUnitApiUrl(blockId)) + .reply(200, { + ...courseUnitIndexMock, + visibility_state: UNIT_VISIBILITY_STATES.live, + has_changes: false, + published_by: userName, + }); + + await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); + + await waitFor(() => { + // check if the sidebar status is Published and Live + expect(getByText(sidebarMessages.sidebarTitlePublishedAndLive.defaultMessage)).toBeInTheDocument(); + expect(getByText( + sidebarMessages.publishLastPublished.defaultMessage + .replace('{publishedOn}', courseUnitIndexMock.published_on) + .replace('{publishedBy}', userName), + )).toBeInTheDocument(); + expect(queryByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage })).not.toBeInTheDocument(); + const videoButton = getByRole('button', { name: new RegExp(`${addComponentMessages.buttonText.defaultMessage} Video`, 'i'), }); @@ -314,6 +389,32 @@ describe('', () => { expect(mockedUsedNavigate).toHaveBeenCalled(); expect(mockedUsedNavigate).toHaveBeenCalledWith(`/course/${courseKey}/editor/video/${locator}`); }); + + axiosMock + .onGet(getCourseUnitApiUrl(blockId)) + .reply(200, courseUnitIndexMock); + + await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); + + // after creating video xblock, the sidebar status changes to Draft (unpublished changes) + expect(getByText(sidebarMessages.sidebarTitleDraftUnpublishedChanges.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityStaffAndLearnersTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.releaseStatusTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.sidebarBodyNote.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityWillBeVisibleToTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(courseUnitIndexMock.release_date)).toBeInTheDocument(); + expect(getByText( + sidebarMessages.publishInfoDraftSaved.defaultMessage + .replace('{editedOn}', courseUnitIndexMock.edited_on) + .replace('{editedBy}', courseUnitIndexMock.edited_by), + )).toBeInTheDocument(); + expect(getByText( + sidebarMessages.releaseInfoWithSection.defaultMessage + .replace('{sectionName}', courseUnitIndexMock.release_date_from), + )).toBeInTheDocument(); }); it('renders course unit details for a draft with unpublished changes', async () => { diff --git a/src/course-unit/data/thunk.js b/src/course-unit/data/thunk.js index 7117acd439..1a318beb17 100644 --- a/src/course-unit/data/thunk.js +++ b/src/course-unit/data/thunk.js @@ -248,6 +248,9 @@ export function createNewCourseXBlock(body, callback, blockId) { if (callback) { callback(result); } + const currentBlockId = body.category === 'vertical' ? formattedResult.locator : blockId; + const courseUnit = await getCourseUnitData(currentBlockId); + dispatch(fetchCourseItemSuccess(courseUnit)); } const courseUnit = await getCourseUnitData(blockId); dispatch(fetchCourseItemSuccess(courseUnit)); From 3a2f81bb95ed212ab5778fbea7b3161986cfdbdd Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Thu, 29 Feb 2024 13:27:49 +0200 Subject: [PATCH 08/10] refactor: after rebase --- src/course-unit/data/thunk.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/course-unit/data/thunk.js b/src/course-unit/data/thunk.js index 1a318beb17..7d5bdc3a9b 100644 --- a/src/course-unit/data/thunk.js +++ b/src/course-unit/data/thunk.js @@ -1,4 +1,5 @@ import { logError, logInfo } from '@edx/frontend-platform/logging'; +import { camelCaseObject } from '@edx/frontend-platform'; import { hideProcessingNotification, @@ -236,8 +237,9 @@ export function createNewCourseXBlock(body, callback, blockId) { try { await createCourseXblock(body).then(async (result) => { if (result) { + const formattedResult = camelCaseObject(result); if (body.category === 'vertical') { - const courseSectionVerticalData = await getCourseSectionVerticalData(result.locator); + const courseSectionVerticalData = await getCourseSectionVerticalData(formattedResult.locator); dispatch(fetchCourseSectionVerticalDataSuccess(courseSectionVerticalData)); } const courseVerticalChildrenData = await getCourseVerticalChildren(blockId); From 6ea3f0dbef6b9424081c1ce175d6e1dbce85b945 Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Tue, 6 Feb 2024 16:00:40 +0200 Subject: [PATCH 09/10] fix: [AXIMST-470] fixed sidebar status after deleting or duplicating xblock --- src/course-unit/CourseUnit.test.jsx | 184 ++++++++++++++++++++++++++++ src/course-unit/data/thunk.js | 4 + 2 files changed, 188 insertions(+) diff --git a/src/course-unit/CourseUnit.test.jsx b/src/course-unit/CourseUnit.test.jsx index f969321fe5..d197e75e69 100644 --- a/src/course-unit/CourseUnit.test.jsx +++ b/src/course-unit/CourseUnit.test.jsx @@ -17,6 +17,7 @@ import { postXBlockBaseApiUrl, } from './data/api'; import { + deleteUnitItemQuery, editCourseUnitVisibilityAndData, fetchCourseSectionVerticalData, fetchCourseUnitQuery, @@ -717,4 +718,187 @@ describe('', () => { .getByText(sidebarMessages.sidebarTitlePublishedNotYetReleased.defaultMessage)).toBeInTheDocument(); expect(discardChangesBtn).not.toBeInTheDocument(); }); + + it('checks whether xblock is removed when the corresponding delete button is clicked and sidebar is the updated', async () => { + const { + getByText, + getAllByLabelText, + getByRole, + getAllByTestId, + queryByRole, + } = render(); + + await waitFor(() => { + userEvent.click(getByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage })); + }); + + axiosMock + .onPost(getXBlockBaseApiUrl(blockId), { + publish: PUBLISH_TYPES.makePublic, + }) + .reply(200, { dummy: 'value' }); + axiosMock + .onGet(getCourseUnitApiUrl(blockId)) + .reply(200, { + ...courseUnitIndexMock, + visibility_state: UNIT_VISIBILITY_STATES.live, + has_changes: false, + published_by: userName, + }); + + await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); + + axiosMock + .onDelete(getXBlockBaseApiUrl(courseVerticalChildrenMock.children[0].block_id)) + .replyOnce(200, { dummy: 'value' }); + + await executeThunk(deleteUnitItemQuery(courseId, blockId), store.dispatch); + + await waitFor(() => { + // check if the sidebar status is Published and Live + expect(getByText(sidebarMessages.sidebarTitlePublishedAndLive.defaultMessage)).toBeInTheDocument(); + expect(getByText( + sidebarMessages.publishLastPublished.defaultMessage + .replace('{publishedOn}', courseUnitIndexMock.published_on) + .replace('{publishedBy}', userName), + )).toBeInTheDocument(); + expect(queryByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage })).not.toBeInTheDocument(); + + expect(getByText(unitDisplayName)).toBeInTheDocument(); + const [xblockActionBtn] = getAllByLabelText(courseXBlockMessages.blockActionsDropdownAlt.defaultMessage); + userEvent.click(xblockActionBtn); + + const deleteBtn = getByRole('button', { name: courseXBlockMessages.blockLabelButtonDelete.defaultMessage }); + userEvent.click(deleteBtn); + expect(getByText(/Delete this component?/)).toBeInTheDocument(); + + const deleteConfirmBtn = getByRole('button', { name: deleteModalMessages.deleteButton.defaultMessage }); + userEvent.click(deleteConfirmBtn); + + expect(getAllByTestId('course-xblock')).toHaveLength(1); + }); + + axiosMock + .onGet(getCourseUnitApiUrl(blockId)) + .reply(200, courseUnitIndexMock); + + await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); + + // after removing the xblock, the sidebar status changes to Draft (unpublished changes) + expect(getByText(sidebarMessages.sidebarTitleDraftUnpublishedChanges.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityStaffAndLearnersTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.releaseStatusTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.sidebarBodyNote.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityWillBeVisibleToTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(courseUnitIndexMock.release_date)).toBeInTheDocument(); + expect(getByText( + sidebarMessages.publishInfoDraftSaved.defaultMessage + .replace('{editedOn}', courseUnitIndexMock.edited_on) + .replace('{editedBy}', courseUnitIndexMock.edited_by), + )).toBeInTheDocument(); + expect(getByText( + sidebarMessages.releaseInfoWithSection.defaultMessage + .replace('{sectionName}', courseUnitIndexMock.release_date_from), + )).toBeInTheDocument(); + }); + + it('checks if xblock is a duplicate when the corresponding duplicate button is clicked and if the sidebar status is updated', async () => { + axiosMock + .onPost(postXBlockBaseApiUrl({ + parent_locator: blockId, + duplicate_source_locator: courseVerticalChildrenMock.children[0].block_id, + })) + .replyOnce(200, { locator: '1234567890' }); + + axiosMock + .onGet(getCourseVerticalChildrenApiUrl(blockId)) + .reply(200, { + ...courseVerticalChildrenMock, + children: [ + ...courseVerticalChildrenMock.children, + { + ...courseVerticalChildrenMock.children[0], + name: 'New Cloned XBlock', + }, + ], + }); + + const { + getByText, + getAllByLabelText, + getAllByTestId, + queryByRole, + getByRole, + } = render(); + + await waitFor(() => { + userEvent.click(getByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage })); + }); + + axiosMock + .onPost(getXBlockBaseApiUrl(blockId), { + publish: PUBLISH_TYPES.makePublic, + }) + .reply(200, { dummy: 'value' }); + axiosMock + .onGet(getCourseUnitApiUrl(blockId)) + .reply(200, { + ...courseUnitIndexMock, + visibility_state: UNIT_VISIBILITY_STATES.live, + has_changes: false, + published_by: userName, + }); + + await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); + + await waitFor(() => { + // check if the sidebar status is Published and Live + expect(getByText(sidebarMessages.sidebarTitlePublishedAndLive.defaultMessage)).toBeInTheDocument(); + expect(getByText( + sidebarMessages.publishLastPublished.defaultMessage + .replace('{publishedOn}', courseUnitIndexMock.published_on) + .replace('{publishedBy}', userName), + )).toBeInTheDocument(); + expect(queryByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage })).not.toBeInTheDocument(); + + expect(getByText(unitDisplayName)).toBeInTheDocument(); + const [xblockActionBtn] = getAllByLabelText(courseXBlockMessages.blockActionsDropdownAlt.defaultMessage); + userEvent.click(xblockActionBtn); + + const duplicateBtn = getByText(courseXBlockMessages.blockLabelButtonDuplicate.defaultMessage); + userEvent.click(duplicateBtn); + + expect(getAllByTestId('course-xblock')).toHaveLength(3); + expect(getByText('New Cloned XBlock')).toBeInTheDocument(); + }); + + axiosMock + .onGet(getCourseUnitApiUrl(blockId)) + .reply(200, courseUnitIndexMock); + + await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); + + // after duplicate the xblock, the sidebar status changes to Draft (unpublished changes) + expect(getByText(sidebarMessages.sidebarTitleDraftUnpublishedChanges.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityStaffAndLearnersTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.releaseStatusTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.sidebarBodyNote.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityWillBeVisibleToTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(courseUnitIndexMock.release_date)).toBeInTheDocument(); + expect(getByText( + sidebarMessages.publishInfoDraftSaved.defaultMessage + .replace('{editedOn}', courseUnitIndexMock.edited_on) + .replace('{editedBy}', courseUnitIndexMock.edited_by), + )).toBeInTheDocument(); + expect(getByText( + sidebarMessages.releaseInfoWithSection.defaultMessage + .replace('{sectionName}', courseUnitIndexMock.release_date_from), + )).toBeInTheDocument(); + }); }); diff --git a/src/course-unit/data/thunk.js b/src/course-unit/data/thunk.js index 7d5bdc3a9b..23b39937a1 100644 --- a/src/course-unit/data/thunk.js +++ b/src/course-unit/data/thunk.js @@ -287,6 +287,8 @@ export function deleteUnitItemQuery(itemId, xblockId) { try { await deleteUnitItem(xblockId); dispatch(deleteXBlock(xblockId)); + const courseUnit = await getCourseUnitData(itemId); + dispatch(fetchCourseItemSuccess(courseUnit)); dispatch(hideProcessingNotification()); dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); } catch (error) { @@ -308,6 +310,8 @@ export function duplicateUnitItemQuery(itemId, xblockId) { newId: locator, newCourseVerticalChildren, })); + const courseUnit = await getCourseUnitData(itemId); + dispatch(fetchCourseItemSuccess(courseUnit)); dispatch(hideProcessingNotification()); dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); } catch (error) { From 8a62e6001e55f9dd12f05ecd60a7c50d69cf59df Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Tue, 5 Mar 2024 21:09:18 +0200 Subject: [PATCH 10/10] refactor: refactoring after review --- src/course-unit/CourseUnit.jsx | 2 +- src/course-unit/CourseUnit.scss | 2 +- src/course-unit/CourseUnit.test.jsx | 4 ++-- .../__mocks__/courseVerticalChildren.js | 4 ++-- src/course-unit/constants.js | 2 +- .../{CourseXblock.scss => CourseXBlock.scss} | 0 .../sidebar/components/SidebarBody.jsx | 8 ++++---- .../sidebar/components/SidebarHeader.jsx | 10 +++++----- .../components/sidebar-footer/index.jsx | 8 ++++---- src/course-unit/sidebar/index.jsx | 20 +++++++++---------- src/course-unit/sidebar/utils.js | 12 +++++------ 11 files changed, 36 insertions(+), 36 deletions(-) rename src/course-unit/course-xblock/{CourseXblock.scss => CourseXBlock.scss} (100%) diff --git a/src/course-unit/CourseUnit.jsx b/src/course-unit/CourseUnit.jsx index 48d91978a9..8a117abab3 100644 --- a/src/course-unit/CourseUnit.jsx +++ b/src/course-unit/CourseUnit.jsx @@ -124,7 +124,7 @@ const CourseUnit = ({ courseId }) => { - + diff --git a/src/course-unit/CourseUnit.scss b/src/course-unit/CourseUnit.scss index 16d588f44e..270691ecae 100644 --- a/src/course-unit/CourseUnit.scss +++ b/src/course-unit/CourseUnit.scss @@ -1,5 +1,5 @@ @import "./breadcrumbs/Breadcrumbs"; @import "./course-sequence/CourseSequence"; @import "./add-component/AddComponent"; -@import "./course-xblock/CourseXblock"; +@import "./course-xblock/CourseXBlock"; @import "./sidebar/Sidebar"; diff --git a/src/course-unit/CourseUnit.test.jsx b/src/course-unit/CourseUnit.test.jsx index d197e75e69..233bb63cc1 100644 --- a/src/course-unit/CourseUnit.test.jsx +++ b/src/course-unit/CourseUnit.test.jsx @@ -51,7 +51,7 @@ const courseId = '123'; const blockId = '567890'; const unitDisplayName = courseUnitIndexMock.metadata.display_name; const mockedUsedNavigate = jest.fn(); -const userName = 'edx'; +const userName = 'openedx'; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -719,7 +719,7 @@ describe('', () => { expect(discardChangesBtn).not.toBeInTheDocument(); }); - it('checks whether xblock is removed when the corresponding delete button is clicked and sidebar is the updated', async () => { + it('checks whether xblock is removed when the corresponding delete button is clicked and the sidebar is the updated', async () => { const { getByText, getAllByLabelText, diff --git a/src/course-unit/__mocks__/courseVerticalChildren.js b/src/course-unit/__mocks__/courseVerticalChildren.js index 8c3651ba6c..d7cc9bf611 100644 --- a/src/course-unit/__mocks__/courseVerticalChildren.js +++ b/src/course-unit/__mocks__/courseVerticalChildren.js @@ -2,12 +2,12 @@ module.exports = { children: [ { name: 'Discussion', - block_id: 'block-v1:edX+L153+3T2023+type@discussion+block@fecd20842dd24f50bdc06643e791b013', + block_id: 'block-v1:OpenedX+L153+3T2023+type@discussion+block@fecd20842dd24f50bdc06643e791b013', block_type: 'discussion', }, { name: 'Drag and Drop', - block_id: 'block-v1:edX+L153+3T2023+type@drag-and-drop-v2+block@b33cf1f6df4c41639659bc91132eeb02', + block_id: 'block-v1:OpenedX+L153+3T2023+type@drag-and-drop-v2+block@b33cf1f6df4c41639659bc91132eeb02', block_type: 'drag-and-drop-v2', }, ], diff --git a/src/course-unit/constants.js b/src/course-unit/constants.js index c32d123796..1351689a36 100644 --- a/src/course-unit/constants.js +++ b/src/course-unit/constants.js @@ -58,7 +58,7 @@ export const UNIT_VISIBILITY_STATES = { ready: 'ready', }; -export const COLORS = { +export const ICON_COLOR_VARIANTS = { BLACK: '#000', GREEN: '#0D7D4D', }; diff --git a/src/course-unit/course-xblock/CourseXblock.scss b/src/course-unit/course-xblock/CourseXBlock.scss similarity index 100% rename from src/course-unit/course-xblock/CourseXblock.scss rename to src/course-unit/course-xblock/CourseXBlock.scss diff --git a/src/course-unit/sidebar/components/SidebarBody.jsx b/src/course-unit/sidebar/components/SidebarBody.jsx index 3b24fd5210..679384377d 100644 --- a/src/course-unit/sidebar/components/SidebarBody.jsx +++ b/src/course-unit/sidebar/components/SidebarBody.jsx @@ -8,7 +8,7 @@ import { getPublishInfo } from '../utils'; import messages from '../messages'; import ReleaseInfoComponent from './ReleaseInfoComponent'; -const SidebarBody = ({ releaseLabel, isDisplayUnitLocation, locationId }) => { +const SidebarBody = ({ releaseLabel, displayUnitLocation, locationId }) => { const intl = useIntl(); const { editedOn, @@ -21,7 +21,7 @@ const SidebarBody = ({ releaseLabel, isDisplayUnitLocation, locationId }) => { return ( - {isDisplayUnitLocation ? ( + {displayUnitLocation ? (
{intl.formatMessage(messages.unitLocationTitle)} @@ -53,12 +53,12 @@ const SidebarBody = ({ releaseLabel, isDisplayUnitLocation, locationId }) => { SidebarBody.propTypes = { releaseLabel: PropTypes.string.isRequired, - isDisplayUnitLocation: PropTypes.bool, + displayUnitLocation: PropTypes.bool, locationId: PropTypes.string, }; SidebarBody.defaultProps = { - isDisplayUnitLocation: false, + displayUnitLocation: false, locationId: null, }; diff --git a/src/course-unit/sidebar/components/SidebarHeader.jsx b/src/course-unit/sidebar/components/SidebarHeader.jsx index 188ad15a0c..b6b6feda03 100644 --- a/src/course-unit/sidebar/components/SidebarHeader.jsx +++ b/src/course-unit/sidebar/components/SidebarHeader.jsx @@ -7,14 +7,14 @@ import { getCourseUnitData } from '../../data/selectors'; import { getIconVariant } from '../utils'; import messages from '../messages'; -const SidebarHeader = ({ title, visibilityState, isDisplayUnitLocation }) => { +const SidebarHeader = ({ title, visibilityState, displayUnitLocation }) => { const intl = useIntl(); const { hasChanges, published } = useSelector(getCourseUnitData); const { iconSrc, colorVariant } = getIconVariant(visibilityState, published, hasChanges); return ( - {!isDisplayUnitLocation && ( + {!displayUnitLocation && ( { /> )}

- {isDisplayUnitLocation ? intl.formatMessage(messages.sidebarHeaderUnitLocationTitle) : title} + {displayUnitLocation ? intl.formatMessage(messages.sidebarHeaderUnitLocationTitle) : title}

); @@ -31,11 +31,11 @@ const SidebarHeader = ({ title, visibilityState, isDisplayUnitLocation }) => { SidebarHeader.propTypes = { title: PropTypes.string.isRequired, visibilityState: PropTypes.string.isRequired, - isDisplayUnitLocation: PropTypes.bool, + displayUnitLocation: PropTypes.bool, }; SidebarHeader.defaultProps = { - isDisplayUnitLocation: false, + displayUnitLocation: false, }; export default SidebarHeader; diff --git a/src/course-unit/sidebar/components/sidebar-footer/index.jsx b/src/course-unit/sidebar/components/sidebar-footer/index.jsx index 36387a08e1..ee1e816bad 100644 --- a/src/course-unit/sidebar/components/sidebar-footer/index.jsx +++ b/src/course-unit/sidebar/components/sidebar-footer/index.jsx @@ -12,14 +12,14 @@ const SidebarFooter = ({ handlePublishing, openDiscardModal, visibleToStaffOnly, - isDisplayUnitLocation, + displayUnitLocation, }) => { const intl = useIntl(); return ( - {isDisplayUnitLocation ? ( + {displayUnitLocation ? ( {intl.formatMessage(messages.unitLocationDescription, { id: locationId })} @@ -42,7 +42,7 @@ const SidebarFooter = ({ SidebarFooter.propTypes = { locationId: PropTypes.string, - isDisplayUnitLocation: PropTypes.bool, + displayUnitLocation: PropTypes.bool, openDiscardModal: PropTypes.func.isRequired, openVisibleModal: PropTypes.func.isRequired, handlePublishing: PropTypes.func.isRequired, @@ -50,7 +50,7 @@ SidebarFooter.propTypes = { }; SidebarFooter.defaultProps = { - isDisplayUnitLocation: false, + displayUnitLocation: false, locationId: null, }; diff --git a/src/course-unit/sidebar/index.jsx b/src/course-unit/sidebar/index.jsx index cd35cd3e03..f2817639b2 100644 --- a/src/course-unit/sidebar/index.jsx +++ b/src/course-unit/sidebar/index.jsx @@ -13,7 +13,7 @@ import { SidebarBody, SidebarFooter, SidebarHeader } from './components'; import useCourseUnitData from './hooks'; import messages from './messages'; -const Sidebar = ({ blockId, isDisplayUnitLocation, ...props }) => { +const Sidebar = ({ blockId, displayUnitLocation, ...props }) => { const { title, locationId, @@ -23,8 +23,8 @@ const Sidebar = ({ blockId, isDisplayUnitLocation, ...props }) => { } = useCourseUnitData(useSelector(getCourseUnitData)); const intl = useIntl(); const dispatch = useDispatch(); - const [isOpenDiscardModal, openDiscardModal, closeDiscardModal] = useToggle(false); - const [isOpenVisibleModal, openVisibleModal, closeVisibleModal] = useToggle(false); + const [isDiscardModalOpen, openDiscardModal, closeDiscardModal] = useToggle(false); + const [isVisibleModalOpen, openVisibleModal, closeVisibleModal] = useToggle(false); const handleCourseUnitVisibility = () => { closeVisibleModal(); @@ -50,24 +50,24 @@ const Sidebar = ({ blockId, isDisplayUnitLocation, ...props }) => { { /> { Sidebar.propTypes = { blockId: PropTypes.string, - isDisplayUnitLocation: PropTypes.bool, + displayUnitLocation: PropTypes.bool, }; Sidebar.defaultProps = { blockId: null, - isDisplayUnitLocation: false, + displayUnitLocation: false, }; export default Sidebar; diff --git a/src/course-unit/sidebar/utils.js b/src/course-unit/sidebar/utils.js index 9a36a35597..af3263861f 100644 --- a/src/course-unit/sidebar/utils.js +++ b/src/course-unit/sidebar/utils.js @@ -4,7 +4,7 @@ import { InfoOutline as InfoOutlineIcon, } from '@openedx/paragon/icons'; -import { COLORS, UNIT_VISIBILITY_STATES } from '../constants'; +import { ICON_COLOR_VARIANTS, UNIT_VISIBILITY_STATES } from '../constants'; import messages from './messages'; /** @@ -79,11 +79,11 @@ export const getVisibilityTitle = (intl, releasedToStudents, published, hasChang */ export const getIconVariant = (visibilityState, published, hasChanges) => { const iconVariants = { - [UNIT_VISIBILITY_STATES.staffOnly]: { iconSrc: InfoOutlineIcon, colorVariant: COLORS.BLACK }, - [UNIT_VISIBILITY_STATES.live]: { iconSrc: CheckCircleIcon, colorVariant: COLORS.GREEN }, - publishedNoChanges: { iconSrc: CheckCircleOutlineIcon, colorVariant: COLORS.BLACK }, - publishedWithChanges: { iconSrc: InfoOutlineIcon, colorVariant: COLORS.BLACK }, - default: { iconSrc: InfoOutlineIcon, colorVariant: COLORS.BLACK }, + [UNIT_VISIBILITY_STATES.staffOnly]: { iconSrc: InfoOutlineIcon, colorVariant: ICON_COLOR_VARIANTS.BLACK }, + [UNIT_VISIBILITY_STATES.live]: { iconSrc: CheckCircleIcon, colorVariant: ICON_COLOR_VARIANTS.GREEN }, + publishedNoChanges: { iconSrc: CheckCircleOutlineIcon, colorVariant: ICON_COLOR_VARIANTS.BLACK }, + publishedWithChanges: { iconSrc: InfoOutlineIcon, colorVariant: ICON_COLOR_VARIANTS.BLACK }, + default: { iconSrc: InfoOutlineIcon, colorVariant: ICON_COLOR_VARIANTS.BLACK }, }; if (visibilityState in iconVariants) { return iconVariants[visibilityState];