feat: [AXIMST-19, 20, 22] Course unit - Modal windows for course unit page components (#118)
* feat: added modal windows for course unit page components * refactor: code refactoring * refactor: added translations * refactor: refactoring after review * refactor: after review
This commit is contained in:
committed by
Adolfo R. Brandes
parent
2b11df9eb5
commit
6aff1c1168
@@ -36,7 +36,7 @@ const CourseUnit = ({ courseId }) => {
|
||||
headerNavigationsActions,
|
||||
handleTitleEdit,
|
||||
handleInternetConnectionFailed,
|
||||
handleCreateNewCourseXblock,
|
||||
handleCreateNewCourseXBlock,
|
||||
} = useCourseUnit({ courseId, blockId });
|
||||
|
||||
document.title = getPageHeadTitle('', unitTitle);
|
||||
@@ -80,7 +80,7 @@ const CourseUnit = ({ courseId }) => {
|
||||
courseId={courseId}
|
||||
sequenceId={sequenceId}
|
||||
unitId={blockId}
|
||||
handleCreateNewCourseXblock={handleCreateNewCourseXblock}
|
||||
handleCreateNewCourseXBlock={handleCreateNewCourseXBlock}
|
||||
/>
|
||||
<Layout
|
||||
lg={[{ span: 9 }, { span: 3 }]}
|
||||
@@ -92,7 +92,7 @@ const CourseUnit = ({ courseId }) => {
|
||||
<Layout.Element>
|
||||
<AddComponent
|
||||
blockId={blockId}
|
||||
handleCreateNewCourseXblock={handleCreateNewCourseXblock}
|
||||
handleCreateNewCourseXBlock={handleCreateNewCourseXBlock}
|
||||
/>
|
||||
</Layout.Element>
|
||||
<Layout.Element />
|
||||
|
||||
@@ -2,30 +2,58 @@ import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Button } from '@openedx/paragon';
|
||||
import { useToggle } from '@openedx/paragon';
|
||||
|
||||
import { getCourseSectionVertical } from '../data/selectors';
|
||||
import { COMPONENT_ICON_TYPES } from '../constants';
|
||||
import ComponentIcon from './ComponentIcon';
|
||||
import ComponentModalView from './add-component-modals/ComponentModalView';
|
||||
import AddComponentButton from './add-component-btn';
|
||||
import messages from './messages';
|
||||
|
||||
const AddComponent = ({ blockId, handleCreateNewCourseXblock }) => {
|
||||
const AddComponent = ({ blockId, handleCreateNewCourseXBlock }) => {
|
||||
const navigate = useNavigate();
|
||||
const intl = useIntl();
|
||||
const [isOpenAdvanced, openAdvanced, closeAdvanced] = useToggle(false);
|
||||
const [isOpenHtml, openHtml, closeHtml] = useToggle(false);
|
||||
const [isOpenOpenAssessment, openOpenAssessment, closeOpenAssessment] = useToggle(false);
|
||||
const { componentTemplates } = useSelector(getCourseSectionVertical);
|
||||
|
||||
const handleCreateNewXblock = (type) => () => {
|
||||
const handleCreateNewXBlock = (type, moduleName) => {
|
||||
switch (type) {
|
||||
case COMPONENT_ICON_TYPES.discussion:
|
||||
case COMPONENT_ICON_TYPES.dragAndDrop:
|
||||
handleCreateNewCourseXblock({ type, parentLocator: blockId });
|
||||
handleCreateNewCourseXBlock({ type, parentLocator: blockId });
|
||||
break;
|
||||
case COMPONENT_ICON_TYPES.problem:
|
||||
case COMPONENT_ICON_TYPES.video:
|
||||
handleCreateNewCourseXblock({ type, parentLocator: blockId }, ({ courseKey, locator }) => {
|
||||
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:
|
||||
handleCreateNewCourseXBlock({ type, category: 'library_content', parentLocator: blockId });
|
||||
break;
|
||||
case COMPONENT_ICON_TYPES.advanced:
|
||||
handleCreateNewCourseXBlock({
|
||||
type: moduleName, category: moduleName, parentLocator: blockId,
|
||||
});
|
||||
break;
|
||||
case COMPONENT_ICON_TYPES.openassessment:
|
||||
handleCreateNewCourseXBlock({
|
||||
boilerplate: moduleName, category: type, parentLocator: blockId,
|
||||
});
|
||||
break;
|
||||
case COMPONENT_ICON_TYPES.html:
|
||||
handleCreateNewCourseXBlock({
|
||||
type,
|
||||
boilerplate: moduleName,
|
||||
parentLocator: blockId,
|
||||
}, ({ courseKey, locator }) => {
|
||||
navigate(`/course/${courseKey}/editor/html/${locator}`);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
}
|
||||
};
|
||||
@@ -38,19 +66,53 @@ const AddComponent = ({ blockId, handleCreateNewCourseXblock }) => {
|
||||
<div className="py-4">
|
||||
<h5 className="h3 mb-4 text-center">{intl.formatMessage(messages.title)}</h5>
|
||||
<ul className="new-component-type list-unstyled m-0 d-flex flex-wrap justify-content-center">
|
||||
{Object.keys(componentTemplates).map((component) => (
|
||||
<li key={componentTemplates[component].type}>
|
||||
<Button
|
||||
variant="outline-primary"
|
||||
className="add-component-button flex-column rounded-sm"
|
||||
onClick={handleCreateNewXblock(componentTemplates[component].type)}
|
||||
>
|
||||
<ComponentIcon type={componentTemplates[component].type} />
|
||||
<span className="sr-only">{intl.formatMessage(messages.buttonText)}</span>
|
||||
<span className="small mt-2">{componentTemplates[component].displayName}</span>
|
||||
</Button>
|
||||
</li>
|
||||
))}
|
||||
{componentTemplates.map((component) => {
|
||||
const { type, displayName } = component;
|
||||
let modalParams;
|
||||
|
||||
switch (type) {
|
||||
case COMPONENT_ICON_TYPES.advanced:
|
||||
modalParams = {
|
||||
open: openAdvanced,
|
||||
close: closeAdvanced,
|
||||
isOpen: isOpenAdvanced,
|
||||
};
|
||||
break;
|
||||
case COMPONENT_ICON_TYPES.html:
|
||||
modalParams = {
|
||||
open: openHtml,
|
||||
close: closeHtml,
|
||||
isOpen: isOpenHtml,
|
||||
};
|
||||
break;
|
||||
case COMPONENT_ICON_TYPES.openassessment:
|
||||
modalParams = {
|
||||
open: openOpenAssessment,
|
||||
close: closeOpenAssessment,
|
||||
isOpen: isOpenOpenAssessment,
|
||||
};
|
||||
break;
|
||||
default:
|
||||
return (
|
||||
<li key={type}>
|
||||
<AddComponentButton
|
||||
onClick={() => handleCreateNewXBlock(type)}
|
||||
displayName={displayName}
|
||||
type={type}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ComponentModalView
|
||||
key={type}
|
||||
component={component}
|
||||
handleCreateNewXBlock={handleCreateNewXBlock}
|
||||
modalParams={modalParams}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
@@ -58,7 +120,7 @@ const AddComponent = ({ blockId, handleCreateNewCourseXblock }) => {
|
||||
|
||||
AddComponent.propTypes = {
|
||||
blockId: PropTypes.string.isRequired,
|
||||
handleCreateNewCourseXblock: PropTypes.func.isRequired,
|
||||
handleCreateNewCourseXBlock: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default AddComponent;
|
||||
|
||||
@@ -10,3 +10,7 @@
|
||||
height: 6.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.add-component-modal-radio .pgn__form-radio-input {
|
||||
min-width: 1.25rem;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { render } from '@testing-library/react';
|
||||
import {
|
||||
render, waitFor, within,
|
||||
} from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
@@ -12,20 +14,21 @@ 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 AddComponent from './AddComponent';
|
||||
import messages from './messages';
|
||||
|
||||
let store;
|
||||
let axiosMock;
|
||||
const blockId = '123';
|
||||
const handleCreateNewCourseXblockMock = jest.fn();
|
||||
const handleCreateNewCourseXBlockMock = jest.fn();
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<AppProvider store={store}>
|
||||
<IntlProvider locale="en">
|
||||
<AddComponent
|
||||
blockId={blockId}
|
||||
handleCreateNewCourseXblock={handleCreateNewCourseXblockMock}
|
||||
handleCreateNewCourseXBlock={handleCreateNewCourseXBlockMock}
|
||||
{...props}
|
||||
/>
|
||||
</IntlProvider>
|
||||
@@ -100,7 +103,7 @@ describe('<AddComponent />', () => {
|
||||
});
|
||||
|
||||
userEvent.click(customComponentButton);
|
||||
expect(handleCreateNewCourseXblockMock).not.toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls handleCreateNewCourseXblock with correct parameters when Discussion xblock create button is clicked', () => {
|
||||
@@ -111,8 +114,8 @@ describe('<AddComponent />', () => {
|
||||
});
|
||||
|
||||
userEvent.click(discussionButton);
|
||||
expect(handleCreateNewCourseXblockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXblockMock).toHaveBeenCalledWith({
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
type: 'discussion',
|
||||
});
|
||||
@@ -126,14 +129,14 @@ describe('<AddComponent />', () => {
|
||||
});
|
||||
|
||||
userEvent.click(discussionButton);
|
||||
expect(handleCreateNewCourseXblockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXblockMock).toHaveBeenCalledWith({
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
type: 'drag-and-drop-v2',
|
||||
});
|
||||
});
|
||||
|
||||
it('calls handleCreateNewCourseXblock with correct parameters when Problem xblock create button is clicked', () => {
|
||||
it('calls handleCreateNewCourseXBlock with correct parameters when Problem xblock create button is clicked', () => {
|
||||
const { getByRole } = renderComponent();
|
||||
|
||||
const discussionButton = getByRole('button', {
|
||||
@@ -141,14 +144,14 @@ describe('<AddComponent />', () => {
|
||||
});
|
||||
|
||||
userEvent.click(discussionButton);
|
||||
expect(handleCreateNewCourseXblockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXblockMock).toHaveBeenCalledWith({
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
type: 'problem',
|
||||
}, expect.any(Function));
|
||||
});
|
||||
|
||||
it('calls handleCreateNewCourseXblock with correct parameters when Video xblock create button is clicked', () => {
|
||||
it('calls handleCreateNewCourseXBlock with correct parameters when Video xblock create button is clicked', () => {
|
||||
const { getByRole } = renderComponent();
|
||||
|
||||
const discussionButton = getByRole('button', {
|
||||
@@ -156,10 +159,187 @@ describe('<AddComponent />', () => {
|
||||
});
|
||||
|
||||
userEvent.click(discussionButton);
|
||||
expect(handleCreateNewCourseXblockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXblockMock).toHaveBeenCalledWith({
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
type: 'video',
|
||||
}, expect.any(Function));
|
||||
});
|
||||
|
||||
it('creates new "Library" xblock on click', () => {
|
||||
const { getByRole } = renderComponent();
|
||||
|
||||
const discussionButton = getByRole('button', {
|
||||
name: new RegExp(`${messages.buttonText.defaultMessage} Library Content`, 'i'),
|
||||
});
|
||||
|
||||
userEvent.click(discussionButton);
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
category: 'library_content',
|
||||
type: 'library',
|
||||
});
|
||||
});
|
||||
|
||||
it('verifies modal behavior on button click', async () => {
|
||||
const { getByRole, queryByRole } = renderComponent();
|
||||
const advancedBtn = getByRole('button', {
|
||||
name: new RegExp(`${messages.buttonText.defaultMessage} Advanced`, 'i'),
|
||||
});
|
||||
|
||||
userEvent.click(advancedBtn);
|
||||
const modalContainer = getByRole('dialog');
|
||||
|
||||
expect(within(modalContainer).getByRole('button', { name: messages.modalContainerCancelBtnText.defaultMessage })).toBeInTheDocument();
|
||||
expect(within(modalContainer).getByRole('button', { name: messages.modalBtnText.defaultMessage })).toBeInTheDocument();
|
||||
|
||||
userEvent.click(within(modalContainer).getByRole('button', { name: messages.modalContainerCancelBtnText.defaultMessage }));
|
||||
|
||||
expect(queryByRole('button', { name: messages.modalContainerCancelBtnText.defaultMessage })).toBeNull();
|
||||
expect(queryByRole('button', { name: messages.modalBtnText.defaultMessage })).toBeNull();
|
||||
});
|
||||
|
||||
it('verifies "Advanced" component selection in modal', async () => {
|
||||
const { getByRole, getByText } = renderComponent();
|
||||
const advancedBtn = getByRole('button', {
|
||||
name: new RegExp(`${messages.buttonText.defaultMessage} Advanced`, 'i'),
|
||||
});
|
||||
const componentTemplates = courseSectionVerticalMock.component_templates;
|
||||
|
||||
userEvent.click(advancedBtn);
|
||||
const modalContainer = getByRole('dialog');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(/Add advanced component/i)).toBeInTheDocument();
|
||||
componentTemplates.forEach((componentTemplate) => {
|
||||
if (componentTemplate.type === COMPONENT_ICON_TYPES.advanced) {
|
||||
componentTemplate.templates.forEach((template) => {
|
||||
expect(within(modalContainer).getByRole('radio', { name: template.display_name })).toBeInTheDocument();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('verifies "Text" component selection in modal', async () => {
|
||||
const { getByRole, getByText } = renderComponent();
|
||||
const textBtn = getByRole('button', {
|
||||
name: new RegExp(`${messages.buttonText.defaultMessage} Text`, 'i'),
|
||||
});
|
||||
const componentTemplates = courseSectionVerticalMock.component_templates;
|
||||
userEvent.click(textBtn);
|
||||
const modalContainer = getByRole('dialog');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(/Add text component/i)).toBeInTheDocument();
|
||||
componentTemplates.forEach((componentTemplate) => {
|
||||
if (componentTemplate.type === COMPONENT_ICON_TYPES.html) {
|
||||
componentTemplate.templates.forEach((template) => {
|
||||
expect(within(modalContainer).getByRole('radio', { name: template.display_name })).toBeInTheDocument();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('verifies "Open Response" component selection in modal', async () => {
|
||||
const { getByRole, getByText } = renderComponent();
|
||||
const openResponseBtn = getByRole('button', {
|
||||
name: new RegExp(`${messages.buttonText.defaultMessage} Open Response`, 'i'),
|
||||
});
|
||||
const componentTemplates = courseSectionVerticalMock.component_templates;
|
||||
|
||||
userEvent.click(openResponseBtn);
|
||||
const modalContainer = getByRole('dialog');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(/Add open response component/i)).toBeInTheDocument();
|
||||
componentTemplates.forEach((componentTemplate) => {
|
||||
if (componentTemplate.type === COMPONENT_ICON_TYPES.openassessment) {
|
||||
componentTemplate.templates.forEach((template) => {
|
||||
expect(within(modalContainer).getByRole('radio', { name: template.display_name })).toBeInTheDocument();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('verifies "Advanced" component creation and submission in modal', () => {
|
||||
const { getByRole } = renderComponent();
|
||||
const advancedButton = getByRole('button', {
|
||||
name: new RegExp(`${messages.buttonText.defaultMessage} Advanced`, 'i'),
|
||||
});
|
||||
|
||||
userEvent.click(advancedButton);
|
||||
const modalContainer = getByRole('dialog');
|
||||
|
||||
const radioInput = within(modalContainer).getByRole('radio', { name: 'Annotation' });
|
||||
const sendBtn = within(modalContainer).getByRole('button', { name: messages.modalBtnText.defaultMessage });
|
||||
|
||||
expect(sendBtn).toBeDisabled();
|
||||
userEvent.click(radioInput);
|
||||
expect(sendBtn).not.toBeDisabled();
|
||||
|
||||
userEvent.click(sendBtn);
|
||||
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
type: 'annotatable',
|
||||
category: 'annotatable',
|
||||
});
|
||||
});
|
||||
|
||||
it('verifies "Text" component creation and submission in modal', () => {
|
||||
const { getByRole } = renderComponent();
|
||||
const advancedButton = getByRole('button', {
|
||||
name: new RegExp(`${messages.buttonText.defaultMessage} Text`, 'i'),
|
||||
});
|
||||
|
||||
userEvent.click(advancedButton);
|
||||
const modalContainer = getByRole('dialog');
|
||||
|
||||
const radioInput = within(modalContainer).getByRole('radio', { name: 'Text' });
|
||||
const sendBtn = within(modalContainer).getByRole('button', { name: messages.modalBtnText.defaultMessage });
|
||||
|
||||
expect(sendBtn).toBeDisabled();
|
||||
userEvent.click(radioInput);
|
||||
expect(sendBtn).not.toBeDisabled();
|
||||
|
||||
userEvent.click(sendBtn);
|
||||
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
type: 'html',
|
||||
boilerplate: 'html',
|
||||
}, expect.any(Function));
|
||||
});
|
||||
|
||||
it('verifies "Open Response" component creation and submission in modal', () => {
|
||||
const { getByRole } = renderComponent();
|
||||
const advancedButton = getByRole('button', {
|
||||
name: new RegExp(`${messages.buttonText.defaultMessage} Open Response`, 'i'),
|
||||
});
|
||||
|
||||
userEvent.click(advancedButton);
|
||||
const modalContainer = getByRole('dialog');
|
||||
|
||||
const radioInput = within(modalContainer).getByRole('radio', { name: 'Peer Assessment Only' });
|
||||
const sendBtn = within(modalContainer).getByRole('button', { name: messages.modalBtnText.defaultMessage });
|
||||
|
||||
expect(sendBtn).toBeDisabled();
|
||||
userEvent.click(radioInput);
|
||||
expect(sendBtn).not.toBeDisabled();
|
||||
|
||||
userEvent.click(sendBtn);
|
||||
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
|
||||
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
|
||||
parentLocator: '123',
|
||||
category: 'openassessment',
|
||||
boilerplate: 'peer-assessment',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,16 +2,16 @@ import PropTypes from 'prop-types';
|
||||
import { Icon } from '@openedx/paragon';
|
||||
import { EditNote as EditNoteIcon } from '@openedx/paragon/icons';
|
||||
|
||||
import { COMPONENT_TYPE_ICON_MAP, COMPONENT_ICON_TYPES } from '../constants';
|
||||
import { COMPONENT_ICON_TYPES, COMPONENT_TYPE_ICON_MAP } from '../../constants';
|
||||
|
||||
const ComponentIcon = ({ type }) => {
|
||||
const AddComponentIcon = ({ type }) => {
|
||||
const icon = COMPONENT_TYPE_ICON_MAP[type] || EditNoteIcon;
|
||||
|
||||
return <Icon src={icon} screenReaderText={type} />;
|
||||
};
|
||||
|
||||
ComponentIcon.propTypes = {
|
||||
AddComponentIcon.propTypes = {
|
||||
type: PropTypes.oneOf(Object.values(COMPONENT_ICON_TYPES)).isRequired,
|
||||
};
|
||||
|
||||
export default ComponentIcon;
|
||||
export default AddComponentIcon;
|
||||
30
src/course-unit/add-component/add-component-btn/index.jsx
Normal file
30
src/course-unit/add-component/add-component-btn/index.jsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button } from '@openedx/paragon';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import messages from '../messages';
|
||||
import AddComponentIcon from './AddComponentIcon';
|
||||
|
||||
const AddComponentButton = ({ type, displayName, onClick }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="outline-primary"
|
||||
className="add-component-button flex-column rounded-sm"
|
||||
onClick={onClick}
|
||||
>
|
||||
<AddComponentIcon type={type} />
|
||||
<span className="sr-only">{intl.formatMessage(messages.buttonText)}</span>
|
||||
<span className="small mt-2">{displayName}</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
AddComponentButton.propTypes = {
|
||||
type: PropTypes.string.isRequired,
|
||||
displayName: PropTypes.string.isRequired,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default AddComponentButton;
|
||||
@@ -0,0 +1,93 @@
|
||||
import { useState } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Form } from '@openedx/paragon';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { updateQueryPendingStatus } from '../../data/slice';
|
||||
import AddComponentButton from '../add-component-btn';
|
||||
import messages from '../messages';
|
||||
import ModalContainer from './ModalContainer';
|
||||
|
||||
const ComponentModalView = ({
|
||||
component,
|
||||
modalParams,
|
||||
handleCreateNewXBlock,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useDispatch();
|
||||
const [moduleTitle, setModuleTitle] = useState('');
|
||||
const { open, close, isOpen } = modalParams;
|
||||
const { type, displayName, templates } = component;
|
||||
|
||||
const handleSubmit = () => {
|
||||
handleCreateNewXBlock(type, moduleTitle);
|
||||
dispatch(updateQueryPendingStatus(true));
|
||||
setModuleTitle('');
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<li>
|
||||
<AddComponentButton
|
||||
onClick={open}
|
||||
type={type}
|
||||
displayName={displayName}
|
||||
/>
|
||||
</li>
|
||||
<ModalContainer
|
||||
isOpen={isOpen}
|
||||
close={close}
|
||||
title={intl.formatMessage(messages.modalContainerTitle, { componentTitle: displayName.toLowerCase() })}
|
||||
btnText={intl.formatMessage(messages.modalBtnText)}
|
||||
onSubmit={handleSubmit}
|
||||
resetDisabled={() => setModuleTitle('')}
|
||||
hasValue={!moduleTitle.length}
|
||||
>
|
||||
<Form.Group>
|
||||
<Form.RadioSet
|
||||
name={displayName}
|
||||
onChange={(e) => setModuleTitle(e.target.value)}
|
||||
>
|
||||
{templates.map((componentTemplate) => {
|
||||
const value = componentTemplate.boilerplateName || componentTemplate.category;
|
||||
|
||||
return (
|
||||
<Form.Radio
|
||||
key={componentTemplate.displayName}
|
||||
className="add-component-modal-radio mb-2.5"
|
||||
value={value}
|
||||
>
|
||||
{componentTemplate.displayName}
|
||||
</Form.Radio>
|
||||
);
|
||||
})}
|
||||
</Form.RadioSet>
|
||||
</Form.Group>
|
||||
</ModalContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
ComponentModalView.propTypes = {
|
||||
modalParams: PropTypes.shape({
|
||||
open: PropTypes.func,
|
||||
close: PropTypes.func,
|
||||
isOpen: PropTypes.bool,
|
||||
}).isRequired,
|
||||
handleCreateNewXBlock: PropTypes.func.isRequired,
|
||||
component: PropTypes.shape({
|
||||
displayName: PropTypes.string.isRequired,
|
||||
category: PropTypes.string,
|
||||
type: PropTypes.string.isRequired,
|
||||
templates: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
boilerplateName: PropTypes.string,
|
||||
category: PropTypes.string,
|
||||
displayName: PropTypes.string.isRequired,
|
||||
}),
|
||||
),
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
export default ComponentModalView;
|
||||
@@ -0,0 +1,61 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { ActionRow, Button, StandardModal } from '@openedx/paragon';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import messages from '../messages';
|
||||
|
||||
const ModalContainer = ({
|
||||
title, isOpen, close, children, btnText, size, onSubmit, hasValue, resetDisabled,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const handleSubmit = () => {
|
||||
onSubmit();
|
||||
close();
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
resetDisabled();
|
||||
close();
|
||||
};
|
||||
|
||||
return (
|
||||
<StandardModal
|
||||
title={title}
|
||||
isOpen={isOpen}
|
||||
onClose={handleClose}
|
||||
size={size}
|
||||
footerNode={(
|
||||
<ActionRow>
|
||||
<ActionRow.Spacer />
|
||||
<Button variant="tertiary" onClick={handleClose}>
|
||||
{intl.formatMessage(messages.modalContainerCancelBtnText)}
|
||||
</Button>
|
||||
<Button onClick={handleSubmit} disabled={hasValue}>
|
||||
{btnText}
|
||||
</Button>
|
||||
</ActionRow>
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</StandardModal>
|
||||
);
|
||||
};
|
||||
|
||||
ModalContainer.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
close: PropTypes.func.isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
btnText: PropTypes.string.isRequired,
|
||||
size: PropTypes.string,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
hasValue: PropTypes.bool.isRequired,
|
||||
resetDisabled: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
ModalContainer.defaultProps = {
|
||||
size: 'md',
|
||||
};
|
||||
|
||||
export default ModalContainer;
|
||||
@@ -9,6 +9,18 @@ const messages = defineMessages({
|
||||
id: 'course-authoring.course-unit.add.component.button.text',
|
||||
defaultMessage: 'Add Component:',
|
||||
},
|
||||
modalBtnText: {
|
||||
id: 'course-authoring.course-unit.modal.button.text',
|
||||
defaultMessage: 'Select',
|
||||
},
|
||||
modalContainerTitle: {
|
||||
id: 'course-authoring.course-unit.modal.container.title',
|
||||
defaultMessage: 'Add {componentTitle} component',
|
||||
},
|
||||
modalContainerCancelBtnText: {
|
||||
id: 'course-authoring.course-unit.modal.container.cancel.button.text',
|
||||
defaultMessage: 'Cancel',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
|
||||
@@ -13,7 +13,7 @@ const Sequence = ({
|
||||
courseId,
|
||||
sequenceId,
|
||||
unitId,
|
||||
handleCreateNewCourseXblock,
|
||||
handleCreateNewCourseXBlock,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const { IN_PROGRESS, FAILED, SUCCESSFUL } = RequestStatus;
|
||||
@@ -27,7 +27,7 @@ const Sequence = ({
|
||||
sequenceId={sequenceId}
|
||||
unitId={unitId}
|
||||
courseId={courseId}
|
||||
handleCreateNewCourseXblock={handleCreateNewCourseXblock}
|
||||
handleCreateNewCourseXBlock={handleCreateNewCourseXBlock}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -60,7 +60,7 @@ Sequence.propTypes = {
|
||||
unitId: PropTypes.string,
|
||||
courseId: PropTypes.string.isRequired,
|
||||
sequenceId: PropTypes.string,
|
||||
handleCreateNewCourseXblock: PropTypes.func.isRequired,
|
||||
handleCreateNewCourseXBlock: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
Sequence.defaultProps = {
|
||||
|
||||
@@ -23,7 +23,7 @@ const SequenceNavigation = ({
|
||||
unitId,
|
||||
sequenceId,
|
||||
className,
|
||||
handleCreateNewCourseXblock,
|
||||
handleCreateNewCourseXBlock,
|
||||
}) => {
|
||||
const sequenceStatus = useSelector(getSequenceStatus);
|
||||
const {
|
||||
@@ -43,7 +43,7 @@ const SequenceNavigation = ({
|
||||
<SequenceNavigationTabs
|
||||
unitIds={sequence.unitIds || []}
|
||||
unitId={unitId}
|
||||
handleCreateNewCourseXblock={handleCreateNewCourseXblock}
|
||||
handleCreateNewCourseXBlock={handleCreateNewCourseXBlock}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -107,7 +107,7 @@ SequenceNavigation.propTypes = {
|
||||
unitId: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
sequenceId: PropTypes.string,
|
||||
handleCreateNewCourseXblock: PropTypes.func.isRequired,
|
||||
handleCreateNewCourseXBlock: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
SequenceNavigation.defaultProps = {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useIndexOfLastVisibleChild } from '../hooks';
|
||||
import SequenceNavigationDropdown from './SequenceNavigationDropdown';
|
||||
import UnitButton from './UnitButton';
|
||||
|
||||
const SequenceNavigationTabs = ({ unitIds, unitId, handleCreateNewCourseXblock }) => {
|
||||
const SequenceNavigationTabs = ({ unitIds, unitId, handleCreateNewCourseXBlock }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
@@ -28,7 +28,7 @@ const SequenceNavigationTabs = ({ unitIds, unitId, handleCreateNewCourseXblock }
|
||||
|
||||
const handleAddNewSequenceUnit = () => {
|
||||
dispatch(updateQueryPendingStatus(true));
|
||||
handleCreateNewCourseXblock({ parentLocator: sequenceId, category: 'vertical', displayName: 'Unit' }, ({ courseKey, locator }) => {
|
||||
handleCreateNewCourseXBlock({ parentLocator: sequenceId, category: 'vertical', displayName: 'Unit' }, ({ courseKey, locator }) => {
|
||||
navigate(`/course/${courseKey}/container/${locator}/${sequenceId}`, courseId);
|
||||
dispatch(changeEditTitleFormOpen(true));
|
||||
});
|
||||
@@ -72,7 +72,7 @@ const SequenceNavigationTabs = ({ unitIds, unitId, handleCreateNewCourseXblock }
|
||||
SequenceNavigationTabs.propTypes = {
|
||||
unitId: PropTypes.string.isRequired,
|
||||
unitIds: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
handleCreateNewCourseXblock: PropTypes.func.isRequired,
|
||||
handleCreateNewCourseXBlock: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default SequenceNavigationTabs;
|
||||
|
||||
@@ -14,13 +14,14 @@ const getStudioBaseUrl = () => getConfig().STUDIO_BASE_URL;
|
||||
const getLmsBaseUrl = () => getConfig().LMS_BASE_URL;
|
||||
|
||||
export const getCourseUnitApiUrl = (itemId) => `${getStudioBaseUrl()}/xblock/container/${itemId}`;
|
||||
export const postXBlockBaseApiUrl = () => `${getStudioBaseUrl()}/xblock/`;
|
||||
export const getXBlockBaseApiUrl = (itemId) => `${getStudioBaseUrl()}/xblock/${itemId}`;
|
||||
export const getCourseSectionVerticalApiUrl = (itemId) => `${getStudioBaseUrl()}/api/contentstore/v1/container_handler/${itemId}`;
|
||||
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 postXBlockBaseApiUrl = () => `${getStudioBaseUrl()}/xblock/`;
|
||||
|
||||
/**
|
||||
* Get course unit.
|
||||
* @param {string} unitId
|
||||
@@ -101,15 +102,27 @@ export async function getCourseHomeCourseMetadata(courseId, rootSlug) {
|
||||
return normalizeCourseHomeCourseMetadata(data, rootSlug);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new course XBlock.
|
||||
* @param {Object} options - The options for creating the XBlock.
|
||||
* @param {string} options.type - The type of the XBlock.
|
||||
* @param {string} [options.category] - The category of the XBlock. Defaults to the type if not provided.
|
||||
* @param {string} options.parentLocator - The parent locator of the XBlock.
|
||||
* @param {string} [options.displayName] - The display name for the XBlock.
|
||||
* @param {string} [options.boilerplate] - The boilerplate for the XBlock.
|
||||
* @returns {Promise<Object>} A Promise that resolves to the created XBlock data.
|
||||
*/
|
||||
export async function createCourseXblock({
|
||||
type, category, parentLocator, displayName,
|
||||
type, category, parentLocator, displayName, boilerplate,
|
||||
}) {
|
||||
const body = {
|
||||
type,
|
||||
boilerplate,
|
||||
category: category || type,
|
||||
parent_locator: parentLocator,
|
||||
display_name: displayName,
|
||||
};
|
||||
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.post(postXBlockBaseApiUrl(), body);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ export const getSavingStatus = (state) => state.courseUnit.savingStatus;
|
||||
export const getLoadingStatus = (state) => state.courseUnit.loadingStatus;
|
||||
export const getSequenceStatus = (state) => state.courseUnit.sequenceStatus;
|
||||
export const getCourseSectionVertical = (state) => state.courseUnit.courseSectionVertical;
|
||||
export const getCourseUnitComponentTemplates = (state) => state.courseUnit.courseSectionVertical.componentTemplates;
|
||||
export const getCourseSectionVerticalLoadingStatus = (state) => state
|
||||
.courseUnit.loadingStatus.courseSectionVerticalLoadingStatus;
|
||||
export const getCourseStatus = state => state.courseUnit.courseStatus;
|
||||
|
||||
@@ -66,7 +66,7 @@ export const useCourseUnit = ({ courseId, blockId }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateNewCourseXblock = (body, callback) => (
|
||||
const handleCreateNewCourseXBlock = (body, callback) => (
|
||||
dispatch(createNewCourseXblock(body, callback))
|
||||
);
|
||||
|
||||
@@ -101,6 +101,6 @@ export const useCourseUnit = ({ courseId, blockId }) => {
|
||||
headerNavigationsActions,
|
||||
handleTitleEdit,
|
||||
handleTitleEditSubmit,
|
||||
handleCreateNewCourseXblock,
|
||||
handleCreateNewCourseXBlock,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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"
|
||||
}
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
@@ -14,5 +14,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
@@ -991,5 +991,27 @@
|
||||
"course-authoring.course-unit.sequence.no.content": "There is no content here.",
|
||||
"course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}",
|
||||
"course-authoring.course-unit.add.component.title": "Add a new component",
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:"
|
||||
"course-authoring.course-unit.add.component.button.text": "Add Component:",
|
||||
"course-authoring.certificates.heading.title": "Certificates",
|
||||
"course-authoring.certificates.heading.subtitle": "Settings",
|
||||
"course-authoring.certificates.heading.action.button.preview": "Preview certificate",
|
||||
"course-authoring.certificates.heading.action.button.deactivate": "Deactivate",
|
||||
"course-authoring.certificates.nocertificate.text": "You haven't added any certificates to this course yet.",
|
||||
"course-authoring.certificates.setup.certificate.button": "Add your first certificate",
|
||||
"course-authoring.certificates.without.modes.text": "This course does not use a mode that offers certificates.",
|
||||
"course-authoring.certificates.sidebar.about.title": "Working with Certificates",
|
||||
"course-authoring.certificates.sidebar.about.description-1": "Specify a course title to use on the certificate if the course's official title is too long to be displayed well.",
|
||||
"course-authoring.certificates.sidebar.about.description-2": "For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.",
|
||||
"course-authoring.certificates.sidebar.about.description-2.strong": "Edit",
|
||||
"course-authoring.certificates.sidebar.about.description-3": "To view a sample certificate, choose a course mode and select {strongText}.",
|
||||
"course-authoring.certificates.sidebar.about.description-3.strong": "Preview Certificate",
|
||||
"course-authoring.certificates.sidebar.about2.title": "Issuing Certificates to Learners",
|
||||
"course-authoring.certificates.sidebar.about2.description-1": "To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.",
|
||||
"course-authoring.certificates.sidebar.about2.description-1.strong": "Activate",
|
||||
"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.modal.button.text": "Select",
|
||||
"course-authoring.course-unit.modal.container.title": "Add {componentTitle} component",
|
||||
"course-authoring.course-unit.modal.container.cancel.button.text": "Cancel"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user