feat: [FC-0044] Unit page - display component support label (#913)
* feat: [FC-0044] Unit page - display component support label * fix: add message description for tooltip of module support
This commit is contained in:
@@ -5,7 +5,7 @@ import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { useToggle } from '@openedx/paragon';
|
||||
|
||||
import { getCourseSectionVertical } from '../data/selectors';
|
||||
import { COMPONENT_ICON_TYPES } from '../constants';
|
||||
import { COMPONENT_TYPES } from '../constants';
|
||||
import ComponentModalView from './add-component-modals/ComponentModalView';
|
||||
import AddComponentButton from './add-component-btn';
|
||||
import messages from './messages';
|
||||
@@ -20,32 +20,32 @@ const AddComponent = ({ blockId, handleCreateNewCourseXBlock }) => {
|
||||
|
||||
const handleCreateNewXBlock = (type, moduleName) => {
|
||||
switch (type) {
|
||||
case COMPONENT_ICON_TYPES.discussion:
|
||||
case COMPONENT_ICON_TYPES.dragAndDrop:
|
||||
case COMPONENT_TYPES.discussion:
|
||||
case COMPONENT_TYPES.dragAndDrop:
|
||||
handleCreateNewCourseXBlock({ type, parentLocator: blockId });
|
||||
break;
|
||||
case COMPONENT_ICON_TYPES.problem:
|
||||
case COMPONENT_ICON_TYPES.video:
|
||||
case COMPONENT_TYPES.problem:
|
||||
case COMPONENT_TYPES.video:
|
||||
handleCreateNewCourseXBlock({ type, parentLocator: blockId }, ({ courseKey, locator }) => {
|
||||
navigate(`/course/${courseKey}/editor/${type}/${locator}`);
|
||||
});
|
||||
break;
|
||||
// TODO: The library functional will be a bit different of current legacy (CMS)
|
||||
// behaviour and this ticket is on hold (blocked by other development team).
|
||||
case COMPONENT_ICON_TYPES.library:
|
||||
case COMPONENT_TYPES.library:
|
||||
handleCreateNewCourseXBlock({ type, category: 'library_content', parentLocator: blockId });
|
||||
break;
|
||||
case COMPONENT_ICON_TYPES.advanced:
|
||||
case COMPONENT_TYPES.advanced:
|
||||
handleCreateNewCourseXBlock({
|
||||
type: moduleName, category: moduleName, parentLocator: blockId,
|
||||
});
|
||||
break;
|
||||
case COMPONENT_ICON_TYPES.openassessment:
|
||||
case COMPONENT_TYPES.openassessment:
|
||||
handleCreateNewCourseXBlock({
|
||||
boilerplate: moduleName, category: type, parentLocator: blockId,
|
||||
});
|
||||
break;
|
||||
case COMPONENT_ICON_TYPES.html:
|
||||
case COMPONENT_TYPES.html:
|
||||
handleCreateNewCourseXBlock({
|
||||
type,
|
||||
boilerplate: moduleName,
|
||||
@@ -70,22 +70,26 @@ const AddComponent = ({ blockId, handleCreateNewCourseXBlock }) => {
|
||||
const { type, displayName } = component;
|
||||
let modalParams;
|
||||
|
||||
if (!component.templates.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case COMPONENT_ICON_TYPES.advanced:
|
||||
case COMPONENT_TYPES.advanced:
|
||||
modalParams = {
|
||||
open: openAdvanced,
|
||||
close: closeAdvanced,
|
||||
isOpen: isOpenAdvanced,
|
||||
};
|
||||
break;
|
||||
case COMPONENT_ICON_TYPES.html:
|
||||
case COMPONENT_TYPES.html:
|
||||
modalParams = {
|
||||
open: openHtml,
|
||||
close: closeHtml,
|
||||
isOpen: isOpenHtml,
|
||||
};
|
||||
break;
|
||||
case COMPONENT_ICON_TYPES.openassessment:
|
||||
case COMPONENT_TYPES.openassessment:
|
||||
modalParams = {
|
||||
open: openOpenAssessment,
|
||||
close: closeOpenAssessment,
|
||||
|
||||
@@ -14,7 +14,7 @@ import { executeThunk } from '../../utils';
|
||||
import { fetchCourseSectionVerticalData } from '../data/thunk';
|
||||
import { getCourseSectionVerticalApiUrl } from '../data/api';
|
||||
import { courseSectionVerticalMock } from '../__mocks__';
|
||||
import { COMPONENT_ICON_TYPES } from '../constants';
|
||||
import { COMPONENT_TYPES } from '../constants';
|
||||
import AddComponent from './AddComponent';
|
||||
import messages from './messages';
|
||||
|
||||
@@ -66,7 +66,7 @@ describe('<AddComponent />', () => {
|
||||
));
|
||||
});
|
||||
|
||||
it('doesn\'t render AddComponent component when there aren\'t componentTemplates', async () => {
|
||||
it('AddComponent component doesn\'t render when there aren\'t componentTemplates', async () => {
|
||||
axiosMock
|
||||
.onGet(getCourseSectionVerticalApiUrl(blockId))
|
||||
.reply(200, {
|
||||
@@ -80,7 +80,43 @@ describe('<AddComponent />', () => {
|
||||
expect(queryByRole('heading', { name: messages.title.defaultMessage })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does\'t call handleCreateNewCourseXblock with custom component create button is clicked', async () => {
|
||||
it('AddComponent component item doesn\'t render when there aren\'t templates', async () => {
|
||||
const componentTemplates = courseSectionVerticalMock.component_templates;
|
||||
axiosMock
|
||||
.onGet(getCourseSectionVerticalApiUrl(blockId))
|
||||
.reply(200, {
|
||||
...courseSectionVerticalMock,
|
||||
component_templates: [
|
||||
...courseSectionVerticalMock.component_templates.map((component) => {
|
||||
if (component.type === COMPONENT_TYPES.discussion) {
|
||||
return {
|
||||
...component,
|
||||
templates: [],
|
||||
};
|
||||
}
|
||||
|
||||
return component;
|
||||
}),
|
||||
],
|
||||
});
|
||||
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
|
||||
|
||||
const { queryByRole, getByRole } = renderComponent();
|
||||
|
||||
Object.keys(componentTemplates).map((component) => {
|
||||
if (componentTemplates[component].type === COMPONENT_TYPES.discussion) {
|
||||
return expect(queryByRole('button', {
|
||||
name: new RegExp(`${messages.buttonText.defaultMessage} ${componentTemplates[component].display_name}`, 'i'),
|
||||
})).not.toBeInTheDocument();
|
||||
}
|
||||
|
||||
return expect(getByRole('button', {
|
||||
name: new RegExp(`${messages.buttonText.defaultMessage} ${componentTemplates[component].display_name}`, 'i'),
|
||||
})).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('handleCreateNewCourseXblock does\'t call with custom component create button is clicked', async () => {
|
||||
axiosMock
|
||||
.onGet(getCourseSectionVerticalApiUrl(blockId))
|
||||
.reply(200, {
|
||||
@@ -88,7 +124,7 @@ describe('<AddComponent />', () => {
|
||||
component_templates: [
|
||||
{
|
||||
type: 'custom',
|
||||
templates: [],
|
||||
templates: [{ display_name: 'Custom' }],
|
||||
display_name: 'Custom',
|
||||
support_legend: {},
|
||||
},
|
||||
@@ -117,7 +153,7 @@ describe('<AddComponent />', () => {
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
type: 'discussion',
|
||||
type: COMPONENT_TYPES.discussion,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -132,7 +168,7 @@ describe('<AddComponent />', () => {
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
type: 'drag-and-drop-v2',
|
||||
type: COMPONENT_TYPES.dragAndDrop,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -147,7 +183,7 @@ describe('<AddComponent />', () => {
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
type: 'problem',
|
||||
type: COMPONENT_TYPES.problem,
|
||||
}, expect.any(Function));
|
||||
});
|
||||
|
||||
@@ -162,7 +198,7 @@ describe('<AddComponent />', () => {
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
type: 'video',
|
||||
type: COMPONENT_TYPES.video,
|
||||
}, expect.any(Function));
|
||||
});
|
||||
|
||||
@@ -178,7 +214,7 @@ describe('<AddComponent />', () => {
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
category: 'library_content',
|
||||
type: 'library',
|
||||
type: COMPONENT_TYPES.library,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -213,7 +249,7 @@ describe('<AddComponent />', () => {
|
||||
await waitFor(() => {
|
||||
expect(getByText(/Add advanced component/i)).toBeInTheDocument();
|
||||
componentTemplates.forEach((componentTemplate) => {
|
||||
if (componentTemplate.type === COMPONENT_ICON_TYPES.advanced) {
|
||||
if (componentTemplate.type === COMPONENT_TYPES.advanced) {
|
||||
componentTemplate.templates.forEach((template) => {
|
||||
expect(within(modalContainer).getByRole('radio', { name: template.display_name })).toBeInTheDocument();
|
||||
});
|
||||
@@ -234,7 +270,7 @@ describe('<AddComponent />', () => {
|
||||
await waitFor(() => {
|
||||
expect(getByText(/Add text component/i)).toBeInTheDocument();
|
||||
componentTemplates.forEach((componentTemplate) => {
|
||||
if (componentTemplate.type === COMPONENT_ICON_TYPES.html) {
|
||||
if (componentTemplate.type === COMPONENT_TYPES.html) {
|
||||
componentTemplate.templates.forEach((template) => {
|
||||
expect(within(modalContainer).getByRole('radio', { name: template.display_name })).toBeInTheDocument();
|
||||
});
|
||||
@@ -256,7 +292,7 @@ describe('<AddComponent />', () => {
|
||||
await waitFor(() => {
|
||||
expect(getByText(/Add open response component/i)).toBeInTheDocument();
|
||||
componentTemplates.forEach((componentTemplate) => {
|
||||
if (componentTemplate.type === COMPONENT_ICON_TYPES.openassessment) {
|
||||
if (componentTemplate.type === COMPONENT_TYPES.openassessment) {
|
||||
componentTemplate.templates.forEach((template) => {
|
||||
expect(within(modalContainer).getByRole('radio', { name: template.display_name })).toBeInTheDocument();
|
||||
});
|
||||
@@ -312,8 +348,8 @@ describe('<AddComponent />', () => {
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
type: 'html',
|
||||
boilerplate: 'html',
|
||||
type: COMPONENT_TYPES.html,
|
||||
boilerplate: COMPONENT_TYPES.html,
|
||||
}, expect.any(Function));
|
||||
});
|
||||
|
||||
@@ -338,8 +374,102 @@ describe('<AddComponent />', () => {
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
category: 'openassessment',
|
||||
category: COMPONENT_TYPES.openassessment,
|
||||
boilerplate: 'peer-assessment',
|
||||
});
|
||||
});
|
||||
|
||||
describe('component support label', () => {
|
||||
it('component support label is hidden if component support legend is disabled', async () => {
|
||||
const supportLevels = ['fs', 'ps'];
|
||||
axiosMock
|
||||
.onGet(getCourseSectionVerticalApiUrl(blockId))
|
||||
.reply(200, {
|
||||
...courseSectionVerticalMock,
|
||||
component_templates: [
|
||||
...courseSectionVerticalMock.component_templates.map((component) => {
|
||||
if (component.type === COMPONENT_TYPES.advanced) {
|
||||
return {
|
||||
...component,
|
||||
support_legend: { show_legend: false },
|
||||
templates: [
|
||||
...component.templates.map((template, i) => ({
|
||||
...template,
|
||||
support_level: supportLevels[i] || true,
|
||||
})),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
return component;
|
||||
}),
|
||||
],
|
||||
});
|
||||
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
|
||||
|
||||
const { getByRole } = renderComponent();
|
||||
const advancedButton = getByRole('button', {
|
||||
name: new RegExp(`${messages.buttonText.defaultMessage} Advanced`, 'i'),
|
||||
});
|
||||
|
||||
userEvent.click(advancedButton);
|
||||
const modalContainer = getByRole('dialog');
|
||||
const fullySupportLabel = within(modalContainer)
|
||||
.queryByText(messages.modalComponentSupportLabelFullySupported.defaultMessage);
|
||||
const provisionallySupportLabel = within(modalContainer)
|
||||
.queryByText(messages.modalComponentSupportLabelProvisionallySupported.defaultMessage);
|
||||
|
||||
expect(fullySupportLabel).not.toBeInTheDocument();
|
||||
expect(provisionallySupportLabel).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays component support label and tooltip in component modal', async () => {
|
||||
const supportLevels = ['fs', 'ps'];
|
||||
axiosMock
|
||||
.onGet(getCourseSectionVerticalApiUrl(blockId))
|
||||
.reply(200, {
|
||||
...courseSectionVerticalMock,
|
||||
component_templates: [
|
||||
...courseSectionVerticalMock.component_templates.map((component) => {
|
||||
if (component.type === COMPONENT_TYPES.advanced) {
|
||||
return {
|
||||
...component,
|
||||
support_legend: { show_legend: true },
|
||||
templates: [
|
||||
...component.templates.map((template, i) => ({
|
||||
...template,
|
||||
support_level: supportLevels[i] || true,
|
||||
})),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
return component;
|
||||
}),
|
||||
],
|
||||
});
|
||||
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
|
||||
|
||||
const { getByRole, getByText } = renderComponent();
|
||||
const advancedButton = getByRole('button', {
|
||||
name: new RegExp(`${messages.buttonText.defaultMessage} Advanced`, 'i'),
|
||||
});
|
||||
|
||||
userEvent.click(advancedButton);
|
||||
const modalContainer = getByRole('dialog');
|
||||
const fullySupportLabel = within(modalContainer)
|
||||
.getByText(messages.modalComponentSupportLabelFullySupported.defaultMessage);
|
||||
const provisionallySupportLabel = within(modalContainer)
|
||||
.getByText(messages.modalComponentSupportLabelProvisionallySupported.defaultMessage);
|
||||
|
||||
expect(fullySupportLabel).toBeInTheDocument();
|
||||
expect(provisionallySupportLabel).toBeInTheDocument();
|
||||
|
||||
userEvent.hover(fullySupportLabel);
|
||||
expect(getByText(messages.modalComponentSupportTooltipFullySupported.defaultMessage)).toBeInTheDocument();
|
||||
|
||||
userEvent.hover(provisionallySupportLabel);
|
||||
expect(getByText(messages.modalComponentSupportTooltipProvisionallySupported.defaultMessage)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
|
||||
import { Icon } from '@openedx/paragon';
|
||||
import { EditNote as EditNoteIcon } from '@openedx/paragon/icons';
|
||||
|
||||
import { COMPONENT_ICON_TYPES, COMPONENT_TYPE_ICON_MAP } from '../../constants';
|
||||
import { COMPONENT_TYPES, COMPONENT_TYPE_ICON_MAP } from '../../constants';
|
||||
|
||||
const AddComponentIcon = ({ type }) => {
|
||||
const icon = COMPONENT_TYPE_ICON_MAP[type] || EditNoteIcon;
|
||||
@@ -11,7 +11,7 @@ const AddComponentIcon = ({ type }) => {
|
||||
};
|
||||
|
||||
AddComponentIcon.propTypes = {
|
||||
type: PropTypes.oneOf(Object.values(COMPONENT_ICON_TYPES)).isRequired,
|
||||
type: PropTypes.oneOf(Object.values(COMPONENT_TYPES)).isRequired,
|
||||
};
|
||||
|
||||
export default AddComponentIcon;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { useState } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Form } from '@openedx/paragon';
|
||||
import { Form, OverlayTrigger, Tooltip } from '@openedx/paragon';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { updateQueryPendingStatus } from '../../data/slice';
|
||||
import { getXBlockSupportMessages } from '../../constants';
|
||||
import AddComponentButton from '../add-component-btn';
|
||||
import messages from '../messages';
|
||||
import ModalContainer from './ModalContainer';
|
||||
@@ -18,7 +19,10 @@ const ComponentModalView = ({
|
||||
const dispatch = useDispatch();
|
||||
const [moduleTitle, setModuleTitle] = useState('');
|
||||
const { open, close, isOpen } = modalParams;
|
||||
const { type, displayName, templates } = component;
|
||||
const {
|
||||
type, displayName, templates, supportLegend,
|
||||
} = component;
|
||||
const supportLabels = getXBlockSupportMessages(intl);
|
||||
|
||||
const handleSubmit = () => {
|
||||
handleCreateNewXBlock(type, moduleTitle);
|
||||
@@ -51,15 +55,32 @@ const ComponentModalView = ({
|
||||
>
|
||||
{templates.map((componentTemplate) => {
|
||||
const value = componentTemplate.boilerplateName || componentTemplate.category;
|
||||
const isDisplaySupportLabel = supportLegend.showLegend && supportLabels[componentTemplate.supportLevel];
|
||||
|
||||
return (
|
||||
<Form.Radio
|
||||
key={componentTemplate.displayName}
|
||||
className="add-component-modal-radio mb-2.5"
|
||||
value={value}
|
||||
>
|
||||
{componentTemplate.displayName}
|
||||
</Form.Radio>
|
||||
<div className="d-flex justify-content-between w-100 mb-2.5 align-items-end">
|
||||
<Form.Radio
|
||||
key={componentTemplate.displayName}
|
||||
className="add-component-modal-radio"
|
||||
value={value}
|
||||
>
|
||||
{componentTemplate.displayName}
|
||||
</Form.Radio>
|
||||
{isDisplaySupportLabel && (
|
||||
<OverlayTrigger
|
||||
placement="right"
|
||||
overlay={(
|
||||
<Tooltip>
|
||||
{supportLabels[componentTemplate.supportLevel].tooltip}
|
||||
</Tooltip>
|
||||
)}
|
||||
>
|
||||
<span className="x-small text-gray-500 flex-shrink-0 ml-2">
|
||||
{supportLabels[componentTemplate.supportLevel].label}
|
||||
</span>
|
||||
</OverlayTrigger>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Form.RadioSet>
|
||||
@@ -85,8 +106,14 @@ ComponentModalView.propTypes = {
|
||||
boilerplateName: PropTypes.string,
|
||||
category: PropTypes.string,
|
||||
displayName: PropTypes.string.isRequired,
|
||||
supportLevel: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
|
||||
}),
|
||||
),
|
||||
supportLegend: PropTypes.shape({
|
||||
allowUnsupportedXblocks: PropTypes.bool,
|
||||
documentationLabel: PropTypes.string,
|
||||
showLegend: PropTypes.bool,
|
||||
}),
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
|
||||
@@ -21,6 +21,46 @@ const messages = defineMessages({
|
||||
id: 'course-authoring.course-unit.modal.container.cancel.button.text',
|
||||
defaultMessage: 'Cancel',
|
||||
},
|
||||
modalComponentSupportLabelFullySupported: {
|
||||
id: 'course-authoring.course-unit.modal.component.support.label.fully-supported',
|
||||
defaultMessage: 'Fully supported',
|
||||
description: 'Label for advance problem type\'s support status with full platform support',
|
||||
},
|
||||
modalComponentSupportLabelProvisionallySupported: {
|
||||
id: 'course-authoring.course-unit.modal.component.support.label.provisionally-support',
|
||||
defaultMessage: 'Provisionally supported',
|
||||
description: 'Label for advance problem type\'s support status with provisional platform support',
|
||||
},
|
||||
modalComponentSupportLabelNotSupported: {
|
||||
id: 'course-authoring.course-unit.modal.component.support.label.not-supported',
|
||||
defaultMessage: 'Not supported',
|
||||
description: 'Label for advance problem type\'s support status with no platform support',
|
||||
},
|
||||
modalComponentSupportTooltipFullySupported: {
|
||||
id: 'course-authoring.course-unit.modal.component.support.tooltip.fully-supported',
|
||||
defaultMessage: 'Fully supported tools and features are available on edX, are '
|
||||
+ 'fully tested, have user interfaces where applicable, and are documented in the '
|
||||
+ 'official edX guides that are available on docs.edx.org.',
|
||||
description: 'Message for support status tooltip for modules with full platform support',
|
||||
},
|
||||
modalComponentSupportTooltipNotSupported: {
|
||||
id: 'course-authoring.course-unit.modal.component.support.tooltip.not-supported',
|
||||
defaultMessage: 'Tools with no support are not maintained by edX, and might be '
|
||||
+ 'deprecated in the future. They are not recommended for use in courses due to '
|
||||
+ 'non-compliance with one or more of the base requirements, such as testing, '
|
||||
+ 'accessibility, internationalization, and documentation.',
|
||||
description: 'Message for support status tooltip for modules which is not supported',
|
||||
},
|
||||
modalComponentSupportTooltipProvisionallySupported: {
|
||||
id: 'course-authoring.course-unit.modal.component.support.tooltip.provisionally-support',
|
||||
defaultMessage: 'Provisionally supported tools might lack the robustness of functionality '
|
||||
+ 'that your courses require. edX does not have control over the quality of the software, '
|
||||
+ 'or of the content that can be provided using these tools. Test these tools thoroughly '
|
||||
+ 'before using them in your course, especially in graded sections. Complete documentation '
|
||||
+ 'might not be available for provisionally supported tools, or documentation might be '
|
||||
+ 'available from sources other than edX.',
|
||||
description: 'Message for support status tooltip for modules with provisional platform support',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
|
||||
@@ -12,11 +12,13 @@ import {
|
||||
TextFields as TextFieldsIcon,
|
||||
VideoCamera as VideoCameraIcon,
|
||||
} from '@openedx/paragon/icons';
|
||||
|
||||
import messages from './sidebar/messages';
|
||||
import addComponentMessages from './add-component/messages';
|
||||
|
||||
export const UNIT_ICON_TYPES = ['video', 'other', 'vertical', 'problem', 'lock'];
|
||||
|
||||
export const COMPONENT_ICON_TYPES = {
|
||||
export const COMPONENT_TYPES = {
|
||||
advanced: 'advanced',
|
||||
discussion: 'discussion',
|
||||
library: 'library',
|
||||
@@ -36,14 +38,14 @@ export const TYPE_ICONS_MAP = {
|
||||
};
|
||||
|
||||
export const COMPONENT_TYPE_ICON_MAP = {
|
||||
[COMPONENT_ICON_TYPES.advanced]: ScienceIcon,
|
||||
[COMPONENT_ICON_TYPES.discussion]: QuestionAnswerOutlineIcon,
|
||||
[COMPONENT_ICON_TYPES.library]: LibraryIcon,
|
||||
[COMPONENT_ICON_TYPES.html]: TextFieldsIcon,
|
||||
[COMPONENT_ICON_TYPES.openassessment]: EditNoteIcon,
|
||||
[COMPONENT_ICON_TYPES.problem]: HelpOutlineIcon,
|
||||
[COMPONENT_ICON_TYPES.video]: VideoCameraIcon,
|
||||
[COMPONENT_ICON_TYPES.dragAndDrop]: BackHandIcon,
|
||||
[COMPONENT_TYPES.advanced]: ScienceIcon,
|
||||
[COMPONENT_TYPES.discussion]: QuestionAnswerOutlineIcon,
|
||||
[COMPONENT_TYPES.library]: LibraryIcon,
|
||||
[COMPONENT_TYPES.html]: TextFieldsIcon,
|
||||
[COMPONENT_TYPES.openassessment]: EditNoteIcon,
|
||||
[COMPONENT_TYPES.problem]: HelpOutlineIcon,
|
||||
[COMPONENT_TYPES.video]: VideoCameraIcon,
|
||||
[COMPONENT_TYPES.dragAndDrop]: BackHandIcon,
|
||||
};
|
||||
|
||||
export const getUnitReleaseStatus = (intl) => ({
|
||||
@@ -68,3 +70,18 @@ export const PUBLISH_TYPES = {
|
||||
discardChanges: 'discard_changes',
|
||||
makePublic: 'make_public',
|
||||
};
|
||||
|
||||
export const getXBlockSupportMessages = (intl) => ({
|
||||
fs: { // Fully supported
|
||||
label: intl.formatMessage(addComponentMessages.modalComponentSupportLabelFullySupported),
|
||||
tooltip: intl.formatMessage(addComponentMessages.modalComponentSupportTooltipFullySupported),
|
||||
},
|
||||
ps: { // Provisionally supported
|
||||
label: intl.formatMessage(addComponentMessages.modalComponentSupportLabelProvisionallySupported),
|
||||
tooltip: intl.formatMessage(addComponentMessages.modalComponentSupportTooltipProvisionallySupported),
|
||||
},
|
||||
us: { // Not supported
|
||||
label: intl.formatMessage(addComponentMessages.modalComponentSupportLabelNotSupported),
|
||||
tooltip: intl.formatMessage(addComponentMessages.modalComponentSupportTooltipNotSupported),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useNavigate } from 'react-router-dom';
|
||||
import DeleteModal from '../../generic/delete-modal/DeleteModal';
|
||||
import { scrollToElement } from '../../course-outline/utils';
|
||||
import { getCourseId } from '../data/selectors';
|
||||
import { COMPONENT_ICON_TYPES } from '../constants';
|
||||
import { COMPONENT_TYPES } from '../constants';
|
||||
import messages from './messages';
|
||||
|
||||
const CourseXBlock = ({
|
||||
@@ -30,9 +30,9 @@ const CourseXBlock = ({
|
||||
|
||||
const handleEdit = () => {
|
||||
switch (type) {
|
||||
case COMPONENT_ICON_TYPES.html:
|
||||
case COMPONENT_ICON_TYPES.problem:
|
||||
case COMPONENT_ICON_TYPES.video:
|
||||
case COMPONENT_TYPES.html:
|
||||
case COMPONENT_TYPES.problem:
|
||||
case COMPONENT_TYPES.video:
|
||||
navigate(`/course/${courseId}/editor/${type}/${id}`);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -6,7 +6,7 @@ import { camelCaseObject, initializeMockApp } from '@edx/frontend-platform';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
|
||||
import { getCourseId } from '../data/selectors';
|
||||
import { COMPONENT_ICON_TYPES } from '../constants';
|
||||
import { COMPONENT_TYPES } from '../constants';
|
||||
import { courseVerticalChildrenMock } from '../__mocks__';
|
||||
import CourseXBlock from './CourseXBlock';
|
||||
|
||||
@@ -143,7 +143,7 @@ describe('<CourseXBlock />', () => {
|
||||
describe('edit', () => {
|
||||
it('navigates to editor page on edit HTML xblock', () => {
|
||||
const { getByText, getByRole } = renderComponent({
|
||||
type: COMPONENT_ICON_TYPES.html,
|
||||
type: COMPONENT_TYPES.html,
|
||||
});
|
||||
|
||||
const editButton = getByRole('button', { name: messages.blockAltButtonEdit.defaultMessage });
|
||||
@@ -157,7 +157,7 @@ describe('<CourseXBlock />', () => {
|
||||
|
||||
it('navigates to editor page on edit Video xblock', () => {
|
||||
const { getByText, getByRole } = renderComponent({
|
||||
type: COMPONENT_ICON_TYPES.video,
|
||||
type: COMPONENT_TYPES.video,
|
||||
});
|
||||
|
||||
const editButton = getByRole('button', { name: messages.blockAltButtonEdit.defaultMessage });
|
||||
@@ -171,7 +171,7 @@ describe('<CourseXBlock />', () => {
|
||||
|
||||
it('navigates to editor page on edit Problem xblock', () => {
|
||||
const { getByText, getByRole } = renderComponent({
|
||||
type: COMPONENT_ICON_TYPES.problem,
|
||||
type: COMPONENT_TYPES.problem,
|
||||
});
|
||||
|
||||
const editButton = getByRole('button', { name: messages.blockAltButtonEdit.defaultMessage });
|
||||
|
||||
Reference in New Issue
Block a user