From d923480a6a2891cbfd9f42387ecac4d868270267 Mon Sep 17 00:00:00 2001 From: ruzniaievdm Date: Wed, 5 Jul 2023 19:23:04 +0300 Subject: [PATCH 1/2] feat: Add Requirements and Licensing section --- src/assets/scss/_form.scss | 10 ++ src/generic/ApplyWrapper.jsx | 3 + src/i18n/messages/ar.json | 46 ++++++- src/i18n/messages/de.json | 46 ++++++- src/i18n/messages/de_DE.json | 46 ++++++- src/i18n/messages/es_419.json | 46 ++++++- src/i18n/messages/fr.json | 46 ++++++- src/i18n/messages/fr_CA.json | 46 ++++++- src/i18n/messages/hi.json | 46 ++++++- src/i18n/messages/it.json | 46 ++++++- src/i18n/messages/it_IT.json | 46 ++++++- src/i18n/messages/pt.json | 46 ++++++- src/i18n/messages/pt_PT.json | 46 ++++++- src/i18n/messages/ru.json | 46 ++++++- src/i18n/messages/uk.json | 46 ++++++- src/i18n/messages/zh_CN.json | 46 ++++++- .../ScheduleAndDetails.scss | 2 + .../__mocks__/courseDetails.js | 4 +- src/schedule-and-details/hooks.jsx | 36 +++-- src/schedule-and-details/index.jsx | 51 ++++++- .../license-section/LicenseSection.scss | 9 ++ .../license-section/LicenseSection.test.jsx | 28 ++++ .../license-section/constants.js | 15 ++ .../license-section/hooks.jsx | 113 +++++++++++++++ .../license-section/index.jsx | 53 +++++++ .../LicenseCommonsOptions.test.jsx | 58 ++++++++ .../license-commons-options/index.jsx | 99 +++++++++++++ .../license-commons-options/messages.js | 46 +++++++ .../license-display/LicenseDisplay.test.jsx | 30 ++++ .../license-section/license-display/index.jsx | 42 ++++++ .../license-display/messages.js | 14 ++ .../license-icons/LicenseIcons.test.jsx | 56 ++++++++ .../license-section/license-icons/index.jsx | 100 ++++++++++++++ .../license-section/license-icons/messages.js | 14 ++ .../license-selector/LicenseSelector.test.jsx | 64 +++++++++ .../license-selector/index.jsx | 79 +++++++++++ .../license-selector/messages.js | 30 ++++ .../license-section/messages.js | 46 +++++++ .../license-section/utils.js | 14 ++ src/schedule-and-details/messages.js | 8 ++ .../RequirementsSection.scss | 5 + .../RequirementsSection.test.jsx | 93 +++++++++++++ .../entrance-exam/EntranceExam.test.jsx | 61 ++++++++ .../entrance-exam/index.jsx | 93 +++++++++++++ .../entrance-exam/messages.js | 22 +++ .../GradeRequirements.test.jsx | 53 +++++++ .../grade-requirements/index.jsx | 51 +++++++ .../grade-requirements/messages.js | 15 ++ .../requirements-section/index.jsx | 130 ++++++++++++++++++ .../requirements-section/messages.js | 34 +++++ src/schedule-and-details/utils.js | 8 ++ 51 files changed, 2200 insertions(+), 33 deletions(-) create mode 100644 src/generic/ApplyWrapper.jsx create mode 100644 src/schedule-and-details/license-section/LicenseSection.scss create mode 100644 src/schedule-and-details/license-section/LicenseSection.test.jsx create mode 100644 src/schedule-and-details/license-section/constants.js create mode 100644 src/schedule-and-details/license-section/hooks.jsx create mode 100644 src/schedule-and-details/license-section/index.jsx create mode 100644 src/schedule-and-details/license-section/license-commons-options/LicenseCommonsOptions.test.jsx create mode 100644 src/schedule-and-details/license-section/license-commons-options/index.jsx create mode 100644 src/schedule-and-details/license-section/license-commons-options/messages.js create mode 100644 src/schedule-and-details/license-section/license-display/LicenseDisplay.test.jsx create mode 100644 src/schedule-and-details/license-section/license-display/index.jsx create mode 100644 src/schedule-and-details/license-section/license-display/messages.js create mode 100644 src/schedule-and-details/license-section/license-icons/LicenseIcons.test.jsx create mode 100644 src/schedule-and-details/license-section/license-icons/index.jsx create mode 100644 src/schedule-and-details/license-section/license-icons/messages.js create mode 100644 src/schedule-and-details/license-section/license-selector/LicenseSelector.test.jsx create mode 100644 src/schedule-and-details/license-section/license-selector/index.jsx create mode 100644 src/schedule-and-details/license-section/license-selector/messages.js create mode 100644 src/schedule-and-details/license-section/messages.js create mode 100644 src/schedule-and-details/license-section/utils.js create mode 100644 src/schedule-and-details/requirements-section/RequirementsSection.scss create mode 100644 src/schedule-and-details/requirements-section/RequirementsSection.test.jsx create mode 100644 src/schedule-and-details/requirements-section/entrance-exam/EntranceExam.test.jsx create mode 100644 src/schedule-and-details/requirements-section/entrance-exam/index.jsx create mode 100644 src/schedule-and-details/requirements-section/entrance-exam/messages.js create mode 100644 src/schedule-and-details/requirements-section/grade-requirements/GradeRequirements.test.jsx create mode 100644 src/schedule-and-details/requirements-section/grade-requirements/index.jsx create mode 100644 src/schedule-and-details/requirements-section/grade-requirements/messages.js create mode 100644 src/schedule-and-details/requirements-section/index.jsx create mode 100644 src/schedule-and-details/requirements-section/messages.js diff --git a/src/assets/scss/_form.scss b/src/assets/scss/_form.scss index 369ea2ccb6..18cc9da59e 100644 --- a/src/assets/scss/_form.scss +++ b/src/assets/scss/_form.scss @@ -16,4 +16,14 @@ width: 100%; justify-content: space-between; } + + .form-group-custom_isInvalid { + input { + border-color: $form-feedback-invalid-color; + } + } + + .feedback-error { + color: $form-feedback-invalid-color; + } } diff --git a/src/generic/ApplyWrapper.jsx b/src/generic/ApplyWrapper.jsx new file mode 100644 index 0000000000..ffb7ca3881 --- /dev/null +++ b/src/generic/ApplyWrapper.jsx @@ -0,0 +1,3 @@ +const ApplyWrapper = ({ condition, wrapper, children }) => (condition ? wrapper(children) : children); + +export default ApplyWrapper; diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index 2eaa7c1957..c83f3ae780 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 7984e0f687..6d410725c5 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/de_DE.json b/src/i18n/messages/de_DE.json index 3bc88d6616..33be3496bc 100644 --- a/src/i18n/messages/de_DE.json +++ b/src/i18n/messages/de_DE.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/es_419.json b/src/i18n/messages/es_419.json index 755d16b89f..73a995ee1b 100644 --- a/src/i18n/messages/es_419.json +++ b/src/i18n/messages/es_419.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index a9840b5efb..f79ad9b2ab 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/fr_CA.json b/src/i18n/messages/fr_CA.json index d908acd08e..fbe991f5d7 100644 --- a/src/i18n/messages/fr_CA.json +++ b/src/i18n/messages/fr_CA.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/hi.json b/src/i18n/messages/hi.json index 7984e0f687..6d410725c5 100644 --- a/src/i18n/messages/hi.json +++ b/src/i18n/messages/hi.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/it.json b/src/i18n/messages/it.json index 7984e0f687..6d410725c5 100644 --- a/src/i18n/messages/it.json +++ b/src/i18n/messages/it.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/it_IT.json b/src/i18n/messages/it_IT.json index c735066708..243f5a7fb7 100644 --- a/src/i18n/messages/it_IT.json +++ b/src/i18n/messages/it_IT.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index 7984e0f687..6d410725c5 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/pt_PT.json b/src/i18n/messages/pt_PT.json index 7a0b40018d..01b9d4f531 100644 --- a/src/i18n/messages/pt_PT.json +++ b/src/i18n/messages/pt_PT.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index 7984e0f687..6d410725c5 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/uk.json b/src/i18n/messages/uk.json index 7984e0f687..6d410725c5 100644 --- a/src/i18n/messages/uk.json +++ b/src/i18n/messages/uk.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/zh_CN.json b/src/i18n/messages/zh_CN.json index 7984e0f687..6d410725c5 100644 --- a/src/i18n/messages/zh_CN.json +++ b/src/i18n/messages/zh_CN.json @@ -553,5 +553,49 @@ "course-authoring.generic.alert.warning.offline.title": "Studio's having trouble saving your work", "course-authoring.generic.alert.warning.offline.description": "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.", "course-authoring.generic.alert.warning.offline.title.aria.labelled-by": "alert-internet-error-title", - "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description" + "course-authoring.generic.alert.warning.offline.subtitle.aria.described-by": "alert-internet-error-description", + "course-authoring.schedule-section.requirements.entrance.label": "Entrance exam", + "course-authoring.schedule-section.requirements.entrance.collapse.title": "Require students to pass an exam before beginning the course.", + "course-authoring.schedule-section.requirements.entrance.collapse.paragraph": "You can now view and author your course entrance exam from the {hyperlink}.", + "course-authoring.schedule-section.requirements.entrance.collapse.hyperlink": "course outline", + "course-authoring.schedule-section.requirements.entrance.collapse.label": "Grade requirements", + "course-authoring.schedule-section.requirements.entrance.collapse.help-text": "The score student must meet in order to successfully complete the entrance exam.", + "course-authoring.schedule-section.requirements.title": "Requirements", + "course-authoring.schedule-section.requirements.description": "Expectations of the students taking this course", + "course-authoring.schedule-section.requirements.timepicker.label": "Hours of effort per week", + "course-authoring.schedule-section.requirements.timepicker.help-text": "Time spent on all course work", + "course-authoring.schedule-section.requirements.dropdown.label": "Prerequisite course", + "course-authoring.schedule-section.requirements.dropdown.help-text": "Course that students must complete before beginning this course", + "course-authoring.schedule-section.requirements.dropdown.empty-text": "None", + "course-authoring.schedule-section.license.title": "Course content license", + "course-authoring.schedule-section.license.description": "Select the default license for course content", + "course-authoring.schedule-section.license.creative-commons.option.1.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.1.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.2.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.2.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.3.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.3.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.4.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.4.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule-section.license.type": "License type", + "course-authoring.schedule-section.license.choice-1": "All rights reserved", + "course-authoring.schedule-section.license.choice-2": "Creative commons", + "course-authoring.schedule-section.license.tooltip-1": "You reserve all rights for your work", + "course-authoring.schedule-section.license.tooltip-2": "You waive some rights for your work, such that others can use it too", + "course-authoring.schedule-section.license.creative-commons.url": "Learn more about creative commons", + "course-authoring.schedule-section.license.all-right-reserved.label": "All rights reserved", + "course-authoring.schedule-section.license.creative-commons.label": "Some rights reserved", + "course-authoring.schedule-section.license.license-display.label": "License display", + "course-authoring.schedule-section.license.license-display.paragraph": "The following message will be displayed at the bottom of the courseware pages within your course:", + "course-authoring.schedule-section.license.creative-commons.options.label": "Options for creative commons", + "course-authoring.schedule-section.license.creative-commons.options.help-text": "The following options are available for the creative commons license.", + "course-authoring.schedule-section.license.creative-commons.option.BY.label": "Attribution", + "course-authoring.schedule-section.license.creative-commons.option.BY.description": "Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.", + "course-authoring.schedule-section.license.creative-commons.option.NC.label": "Noncommercial", + "course-authoring.schedule-section.license.creative-commons.option.NC.description": "Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.", + "course-authoring.schedule-section.license.creative-commons.option.ND.label": "No derivatives", + "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", + "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", + "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", + "course-authoring.schedule.alert.button.saving": "Saving" } diff --git a/src/schedule-and-details/ScheduleAndDetails.scss b/src/schedule-and-details/ScheduleAndDetails.scss index 966b6917a6..e7db75d9d0 100644 --- a/src/schedule-and-details/ScheduleAndDetails.scss +++ b/src/schedule-and-details/ScheduleAndDetails.scss @@ -8,6 +8,8 @@ @import "./schedule-section/certificate-display-row/CertificateDisplayRow"; @import "./learning-outcomes-section/LearningOutcomes"; @import "./instructors-section/InstructorsSection"; +@import "./requirements-section/RequirementsSection"; +@import "./license-section/LicenseSection"; .section-container { &:not(:last-child) { diff --git a/src/schedule-and-details/__mocks__/courseDetails.js b/src/schedule-and-details/__mocks__/courseDetails.js index ef89ab38b7..9ebeb718b7 100644 --- a/src/schedule-and-details/__mocks__/courseDetails.js +++ b/src/schedule-and-details/__mocks__/courseDetails.js @@ -10,11 +10,11 @@ module.exports = { courseImageName: '', description: 'description', duration: '10h', - effort: null, + effort: '10h', endDate: null, enrollmentEnd: null, enrollmentStart: null, - entranceExamEnabled: '', + entranceExamEnabled: 'true', entranceExamId: '', entranceExamMinimumScorePct: '50', instructorInfo: { diff --git a/src/schedule-and-details/hooks.jsx b/src/schedule-and-details/hooks.jsx index 4ea13e4f82..36032530a5 100644 --- a/src/schedule-and-details/hooks.jsx +++ b/src/schedule-and-details/hooks.jsx @@ -15,11 +15,14 @@ const useSaveValuesPrompt = ( const [showModifiedAlert, setShowModifiedAlert] = useState(false); const [showOverrideInternetConnectionAlert, setOverrideInternetConnectionAlert] = useState(false); const [isQueryPending, setIsQueryPending] = useState(false); + const [isEditableState, setIsEditableState] = useState(false); const [errorFields, setErrorFields] = useState({}); const dispatch = useDispatch(); useEffect(() => { - setEditedValues(initialEditedData); + if (!isQueryPending) { + setEditedValues(initialEditedData); + } }, [initialEditedData]); useEffect(() => { @@ -28,20 +31,24 @@ const useSaveValuesPrompt = ( }, [editedValues]); const handleValuesChange = (value, fieldName) => { + setIsEditableState(true); setShowSuccessfulAlert(false); setOverrideInternetConnectionAlert(false); - if (!showModifiedAlert) { - setShowModifiedAlert(true); - } + if (editedValues[fieldName] !== value) { + setEditedValues((prevEditedValues) => ({ + ...prevEditedValues, + [fieldName]: value || '', + })); - setEditedValues((prevEditedValues) => ({ - ...prevEditedValues, - [fieldName]: value || '', - })); + if (!showModifiedAlert) { + setShowModifiedAlert(true); + } + } }; const handleResetValues = () => { + setIsEditableState(false); setEditedValues(initialEditedData || {}); setShowModifiedAlert(false); setShowSuccessfulAlert(false); @@ -50,6 +57,7 @@ const useSaveValuesPrompt = ( const handleUpdateValues = () => { setIsQueryPending(true); + setIsEditableState(false); setOverrideInternetConnectionAlert(true); }; @@ -61,16 +69,18 @@ const useSaveValuesPrompt = ( }; const handleDispatchMethodCall = () => { - setIsQueryPending(false); - setShowModifiedAlert(false); setOverrideInternetConnectionAlert(false); }; useEffect(() => { if (savingStatus === RequestStatus.SUCCESSFUL) { - setShowModifiedAlert(false); - setShowSuccessfulAlert(true); - window.scrollTo({ top: 0, behavior: 'smooth' }); + setIsQueryPending(false); + + if (!isEditableState) { + setShowModifiedAlert(false); + setShowSuccessfulAlert(true); + window.scrollTo({ top: 0, behavior: 'smooth' }); + } } }, [savingStatus]); diff --git a/src/schedule-and-details/index.jsx b/src/schedule-and-details/index.jsx index ea58ff0292..a7cb5b690d 100644 --- a/src/schedule-and-details/index.jsx +++ b/src/schedule-and-details/index.jsx @@ -1,7 +1,9 @@ import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; -import { Container, Button, Layout } from '@edx/paragon'; +import { + Container, Button, Layout, StatefulButton, +} from '@edx/paragon'; import { CheckCircle as CheckCircleIcon, WarningFilled as WarningFilledIcon, @@ -31,6 +33,8 @@ import PacingSection from './pacing-section'; import ScheduleSection from './schedule-section'; import LearningOutcomesSection from './learning-outcomes-section'; import InstructorsSection from './instructors-section'; +import RequirementsSection from './requirements-section'; +import LicenseSection from './license-section'; import ScheduleSidebar from './schedule-sidebar'; import messages from './messages'; import { useSaveValuesPrompt } from './hooks'; @@ -64,15 +68,19 @@ const ScheduleAndDetails = ({ intl, courseId }) => { upgradeDeadline, languageOptions, marketingEnabled, + licensingEnabled, aboutPageEditable, courseDisplayName, sidebarHtmlEnabled, lmsLinkForAboutPage, enrollmentEndEditable, + isEntranceExamsEnabled, creditEligibilityEnabled, shortDescriptionEditable, enableExtendedCourseDetails, + isPrerequisiteCoursesEnabled, mfeProctoredExamSettingsUrl, + possiblePreRequisiteCourses, } = courseSettings; const { @@ -80,7 +88,9 @@ const ScheduleAndDetails = ({ intl, courseId }) => { courseId: courseNumber, run, title, + effort, endDate, + license, language, subtitle, overview, @@ -95,9 +105,12 @@ const ScheduleAndDetails = ({ intl, courseId }) => { enrollmentStart, shortDescription, aboutSidebarHtml, + preRequisiteCourses, + entranceExamEnabled, courseImageAssetPath, bannerImageAssetPath, certificateAvailableDate, + entranceExamMinimumScorePct, certificatesDisplayBehavior, videoThumbnailImageAssetPath, } = editedValues; @@ -113,7 +126,15 @@ const ScheduleAndDetails = ({ intl, courseId }) => { } const showCreditSection = creditEligibilityEnabled && isCreditCourse; + const showRequirementsSection = aboutPageEditable || isPrerequisiteCoursesEnabled || isEntranceExamsEnabled; const hasErrors = !!Object.keys(errorFields).length; + const updateValuesButtonState = { + labels: { + default: intl.formatMessage(messages.buttonSaveText), + pending: intl.formatMessage(messages.buttonSavingText), + }, + disabledStates: ['pending'], + }; const alertWhileSavingTitle = hasErrors ? intl.formatMessage(messages.alertWarningOnSaveWithError) : intl.formatMessage(messages.alertWarning); @@ -227,6 +248,26 @@ const ScheduleAndDetails = ({ intl, courseId }) => { /> )} + {showRequirementsSection && ( + + )} + {licensingEnabled && ( + + )} @@ -262,9 +303,11 @@ const ScheduleAndDetails = ({ intl, courseId }) => { , - , + , ]} variant="warning" icon={WarningFilledIcon} diff --git a/src/schedule-and-details/license-section/LicenseSection.scss b/src/schedule-and-details/license-section/LicenseSection.scss new file mode 100644 index 0000000000..ab5443192b --- /dev/null +++ b/src/schedule-and-details/license-section/LicenseSection.scss @@ -0,0 +1,9 @@ +.license-section { + .license-option { + align-self: flex-start; + } + + .license-option_clickable { + cursor: pointer; + } +} diff --git a/src/schedule-and-details/license-section/LicenseSection.test.jsx b/src/schedule-and-details/license-section/LicenseSection.test.jsx new file mode 100644 index 0000000000..488d3d2c14 --- /dev/null +++ b/src/schedule-and-details/license-section/LicenseSection.test.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import { courseDetailsMock } from '../__mocks__'; +import messages from './messages'; +import LicenseSection from '.'; + +const onChangeMock = jest.fn(); + +const RootWrapper = (props) => ( + + + +); + +const props = { + license: courseDetailsMock.license, + onChange: onChangeMock, +}; + +describe('', () => { + it('renders successfully', () => { + const { getByText } = render(); + expect(getByText(messages.licenseTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.licenseDescription.defaultMessage)).toBeInTheDocument(); + }); +}); diff --git a/src/schedule-and-details/license-section/constants.js b/src/schedule-and-details/license-section/constants.js new file mode 100644 index 0000000000..7d8a62835b --- /dev/null +++ b/src/schedule-and-details/license-section/constants.js @@ -0,0 +1,15 @@ +const creativeCommonsURL = 'https://creativecommons.org/about'; + +const LICENSE_TYPE = { + allRightsReserved: 'all-rights-reserved', + creativeCommons: 'creative-commons', +}; + +const LICENSE_COMMONS_OPTIONS = { + attribution: 'BY', + nonCommercial: 'NC', + noDerivatives: 'ND', + shareAlike: 'SA', +}; + +export { creativeCommonsURL, LICENSE_TYPE, LICENSE_COMMONS_OPTIONS }; diff --git a/src/schedule-and-details/license-section/hooks.jsx b/src/schedule-and-details/license-section/hooks.jsx new file mode 100644 index 0000000000..7887c5524f --- /dev/null +++ b/src/schedule-and-details/license-section/hooks.jsx @@ -0,0 +1,113 @@ +import { useEffect, useState } from 'react'; + +import { LICENSE_TYPE, LICENSE_COMMONS_OPTIONS } from './constants'; +import { generateLicenseURL } from './utils'; + +const useLicenseDetails = (license, onChange) => { + const [licenseType, setLicenseType] = useState(null); + const [licenseDetails, setLicenseDetails] = useState({}); + const [licenseURL, setLicenseURL] = useState(''); + + const { + attribution, nonCommercial, noDerivatives, shareAlike, + } = LICENSE_COMMONS_OPTIONS; + + const defaultLicenseDetails = { + attribution: true, + nonCommercial: true, + noDerivatives: true, + shareAlike: false, + }; + + const updateLicense = () => { + if (licenseType === LICENSE_TYPE.allRightsReserved) { + onChange(LICENSE_TYPE.allRightsReserved, 'license'); + } + + if (licenseType === LICENSE_TYPE.creativeCommons) { + const orderedDetails = Object.entries(licenseDetails) + .filter(([, value]) => value) + .map(([key]) => LICENSE_COMMONS_OPTIONS[key]); + + const updatedString = `${ + LICENSE_TYPE.creativeCommons + }: ver=4.0 ${orderedDetails.join(' ')}`; + onChange(updatedString, 'license'); + } + }; + + useEffect(() => { + if (license?.includes(LICENSE_TYPE.creativeCommons)) { + setLicenseType(LICENSE_TYPE.creativeCommons); + setLicenseDetails((prevLicenseDetails) => ({ + ...prevLicenseDetails, + attribution: license.includes(attribution), + nonCommercial: license.includes(nonCommercial), + noDerivatives: license.includes(noDerivatives), + shareAlike: license.includes(shareAlike), + })); + } else if (license?.includes(LICENSE_TYPE.allRightsReserved)) { + setLicenseType(LICENSE_TYPE.allRightsReserved); + setLicenseDetails({}); + } else { + setLicenseType(null); + setLicenseDetails({}); + } + }, [license]); + + useEffect(() => { + setLicenseURL( + licenseType === LICENSE_TYPE.creativeCommons + ? generateLicenseURL(licenseDetails) + : '', + ); + updateLicense(); + }, [licenseType, licenseDetails]); + + const handleToggleCheckbox = (option) => { + const toggledLicenseDetail = Object.keys(LICENSE_COMMONS_OPTIONS).find( + (key) => LICENSE_COMMONS_OPTIONS[key] === option, + ); + + setLicenseDetails((prev) => { + if (option === noDerivatives) { + return { + ...prev, + noDerivatives: !prev.noDerivatives, + shareAlike: false, + }; + } + + if (option === shareAlike) { + return { + ...prev, + shareAlike: !prev.shareAlike, + noDerivatives: false, + }; + } + + return { + ...prev, + [toggledLicenseDetail]: !prev[toggledLicenseDetail], + }; + }); + }; + + const handleChangeLicenseType = (type) => { + setLicenseType(type); + setLicenseDetails( + type === LICENSE_TYPE.creativeCommons ? defaultLicenseDetails : {}, + ); + }; + + return { + licenseURL, + licenseType, + licenseDetails, + handleToggleCheckbox, + handleChangeLicenseType, + }; +}; + +/* eslint-disable-next-line import/prefer-default-export */ +export { useLicenseDetails }; diff --git a/src/schedule-and-details/license-section/index.jsx b/src/schedule-and-details/license-section/index.jsx new file mode 100644 index 0000000000..8fd7b4cb8c --- /dev/null +++ b/src/schedule-and-details/license-section/index.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import ScheduleSubHeader from '../schedule-sub-header'; +import LicenseDisplay from './license-display'; +import LicenseSelector from './license-selector'; +import LicenseCommonsOptions from './license-commons-options'; +import { LICENSE_TYPE } from './constants'; +import messages from './messages'; +import { useLicenseDetails } from './hooks'; + +const LicenseSection = ({ license, onChange }) => { + const intl = useIntl(); + const { + licenseURL, + licenseType, + licenseDetails, + handleToggleCheckbox, + handleChangeLicenseType, + } = useLicenseDetails(license, onChange); + + return ( +
+ + + {licenseType === LICENSE_TYPE.creativeCommons && ( + + )} + +
+ ); +}; + +LicenseSection.propTypes = { + license: PropTypes.string.isRequired, + onChange: PropTypes.func.isRequired, +}; + +export default LicenseSection; diff --git a/src/schedule-and-details/license-section/license-commons-options/LicenseCommonsOptions.test.jsx b/src/schedule-and-details/license-section/license-commons-options/LicenseCommonsOptions.test.jsx new file mode 100644 index 0000000000..5691049e45 --- /dev/null +++ b/src/schedule-and-details/license-section/license-commons-options/LicenseCommonsOptions.test.jsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { + render, fireEvent, act, waitFor, +} from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import { LICENSE_COMMONS_OPTIONS } from '../constants'; +import messages from './messages'; +import LicenseCommonsOptions from '.'; + +const onToggleCheckboxMock = jest.fn(); + +const RootWrapper = (props) => ( + + + +); + +const props = { + licenseDetails: { + attribution: true, + nonCommercial: true, + noDerivatives: true, + shareAlike: false, + }, + onToggleCheckbox: onToggleCheckboxMock, +}; + +describe('', () => { + it('renders successfully', () => { + const { getByText, getAllByRole } = render(); + expect(getByText(messages.licenseCreativeOptionsLabel.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.licenseCreativeOptionsHelpText.defaultMessage)).toBeInTheDocument(); + expect(getAllByRole('checkbox').length).toBe(4); + }); + + it('should render checkbox list correct', () => { + const { getAllByRole } = render(); + const checkboxList = getAllByRole('checkbox'); + expect(checkboxList[0].checked).toBeTruthy(); + expect(checkboxList[0].disabled).toBeTruthy(); + expect(checkboxList[1].checked).toBeTruthy(); + expect(checkboxList[2].checked).toBeTruthy(); + expect(checkboxList[3].checked).toBeFalsy(); + }); + + it('should call onToggleCheckbox event onClick', () => { + const { getAllByRole } = render(); + const checkboxList = getAllByRole('checkbox'); + act(() => { + fireEvent.click(checkboxList[1]); + }); + expect(props.onToggleCheckbox).toHaveBeenCalledWith(LICENSE_COMMONS_OPTIONS.nonCommercial); + waitFor(() => { + expect(checkboxList[1].checked).toBeFalsy(); + }); + }); +}); diff --git a/src/schedule-and-details/license-section/license-commons-options/index.jsx b/src/schedule-and-details/license-section/license-commons-options/index.jsx new file mode 100644 index 0000000000..9054fc88a9 --- /dev/null +++ b/src/schedule-and-details/license-section/license-commons-options/index.jsx @@ -0,0 +1,99 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { + ActionRow, Form, Stack, +} from '@edx/paragon'; + +import { LICENSE_COMMONS_OPTIONS } from '../constants'; +import messages from './messages'; + +const LicenseCommonsOptions = ({ licenseDetails, onToggleCheckbox }) => { + const optionDetails = [ + { + id: LICENSE_COMMONS_OPTIONS.attribution, + label: messages.licenseCreativeOptionBYLabel, + description: messages.licenseCreativeOptionBYDescription, + disabled: true, + checked: licenseDetails.attribution, + }, + { + id: LICENSE_COMMONS_OPTIONS.nonCommercial, + label: messages.licenseCreativeOptionNCLabel, + description: messages.licenseCreativeOptionNCDescription, + disabled: false, + checked: licenseDetails.nonCommercial, + }, + { + id: LICENSE_COMMONS_OPTIONS.noDerivatives, + label: messages.licenseCreativeOptionNDLabel, + description: messages.licenseCreativeOptionNDDescription, + disabled: false, + checked: licenseDetails.noDerivatives, + }, + { + id: LICENSE_COMMONS_OPTIONS.shareAlike, + label: messages.licenseCreativeOptionSALabel, + description: messages.licenseCreativeOptionSADescription, + disabled: false, + checked: licenseDetails.shareAlike, + }, + ]; + + const handleCheckboxClick = (option) => { + if (!option.disabled) { + onToggleCheckbox(option.id); + } + }; + + return ( +
+

+ +

+

+ +

+ + {optionDetails.map((option) => ( + + handleCheckboxClick(option)} + > + handleCheckboxClick(option)} + className="p-1 col-2" + > +

+ +

+
+ +

+ +

+
+
+ ))} +
+
+ ); +}; + +LicenseCommonsOptions.propTypes = { + licenseDetails: PropTypes.shape({ + attribution: PropTypes.bool.isRequired, + nonCommercial: PropTypes.bool.isRequired, + noDerivatives: PropTypes.bool.isRequired, + shareAlike: PropTypes.bool.isRequired, + }).isRequired, + onToggleCheckbox: PropTypes.func.isRequired, +}; + +export default LicenseCommonsOptions; diff --git a/src/schedule-and-details/license-section/license-commons-options/messages.js b/src/schedule-and-details/license-section/license-commons-options/messages.js new file mode 100644 index 0000000000..bc4567cfbf --- /dev/null +++ b/src/schedule-and-details/license-section/license-commons-options/messages.js @@ -0,0 +1,46 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + licenseCreativeOptionsLabel: { + id: 'course-authoring.schedule-section.license.creative-commons.options.label', + defaultMessage: 'Options for creative commons', + }, + licenseCreativeOptionsHelpText: { + id: 'course-authoring.schedule-section.license.creative-commons.options.help-text', + defaultMessage: 'The following options are available for the creative commons license.', + }, + licenseCreativeOptionBYLabel: { + id: 'course-authoring.schedule-section.license.creative-commons.option.BY.label', + defaultMessage: 'Attribution', + }, + licenseCreativeOptionBYDescription: { + id: 'course-authoring.schedule-section.license.creative-commons.option.BY.description', + defaultMessage: 'Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.', + }, + licenseCreativeOptionNCLabel: { + id: 'course-authoring.schedule-section.license.creative-commons.option.NC.label', + defaultMessage: 'Noncommercial', + }, + licenseCreativeOptionNCDescription: { + id: 'course-authoring.schedule-section.license.creative-commons.option.NC.description', + defaultMessage: ' Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.', + }, + licenseCreativeOptionNDLabel: { + id: 'course-authoring.schedule-section.license.creative-commons.option.ND.label', + defaultMessage: 'No derivatives', + }, + licenseCreativeOptionNDDescription: { + id: 'course-authoring.schedule-section.license.creative-commons.option.ND.description', + defaultMessage: 'Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with "Share Alike".', + }, + licenseCreativeOptionSALabel: { + id: 'course-authoring.schedule-section.license.creative-commons.option.SA.label', + defaultMessage: 'Share alike', + }, + licenseCreativeOptionSADescription: { + id: 'course-authoring.schedule-section.license.creative-commons.option.SA.description', + defaultMessage: 'Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with "No Derivatives"', + }, +}); + +export default messages; diff --git a/src/schedule-and-details/license-section/license-display/LicenseDisplay.test.jsx b/src/schedule-and-details/license-section/license-display/LicenseDisplay.test.jsx new file mode 100644 index 0000000000..5bdb8dbaad --- /dev/null +++ b/src/schedule-and-details/license-section/license-display/LicenseDisplay.test.jsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { + render, +} from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import { LICENSE_TYPE } from '../constants'; +import messages from './messages'; +import LicenseDisplay from '.'; + +const RootWrapper = (props) => ( + + + +); + +const props = { + licenseType: LICENSE_TYPE.allRightsReserved, + licenseDetails: {}, + licenseURL: 'link://to-license.ua', +}; + +describe('', () => { + it('renders successfully', () => { + const { getByText, queryAllByRole } = render(); + expect(getByText(messages.licenseDisplayLabel.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.licenseDisplayParagraph.defaultMessage)).toBeInTheDocument(); + expect(queryAllByRole('img', { hidden: true }).length).toBe(1); + }); +}); diff --git a/src/schedule-and-details/license-section/license-display/index.jsx b/src/schedule-and-details/license-section/license-display/index.jsx new file mode 100644 index 0000000000..dea633968e --- /dev/null +++ b/src/schedule-and-details/license-section/license-display/index.jsx @@ -0,0 +1,42 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { Form } from '@edx/paragon'; + +import { LICENSE_TYPE } from '../constants'; +import LicenseIcons from '../license-icons'; +import messages from './messages'; + +const LicenseDisplay = ({ licenseType, licenseDetails, licenseURL }) => ( + +

+ +

+

+ +

+ +
+); + +LicenseDisplay.defaultProps = { + licenseURL: '', + licenseDetails: {}, +}; + +LicenseDisplay.propTypes = { + licenseType: PropTypes.oneOf([...Object.values(LICENSE_TYPE), '']).isRequired, + licenseDetails: PropTypes.shape({ + attribution: PropTypes.bool, + nonCommercial: PropTypes.bool, + noDerivatives: PropTypes.bool, + shareAlike: PropTypes.bool, + }), + licenseURL: PropTypes.string, +}; + +export default LicenseDisplay; diff --git a/src/schedule-and-details/license-section/license-display/messages.js b/src/schedule-and-details/license-section/license-display/messages.js new file mode 100644 index 0000000000..f9e7369e4b --- /dev/null +++ b/src/schedule-and-details/license-section/license-display/messages.js @@ -0,0 +1,14 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + licenseDisplayLabel: { + id: 'course-authoring.schedule-section.license.license-display.label', + defaultMessage: 'License display', + }, + licenseDisplayParagraph: { + id: 'course-authoring.schedule-section.license.license-display.paragraph', + defaultMessage: 'The following message will be displayed at the bottom of the courseware pages within your course:', + }, +}); + +export default messages; diff --git a/src/schedule-and-details/license-section/license-icons/LicenseIcons.test.jsx b/src/schedule-and-details/license-section/license-icons/LicenseIcons.test.jsx new file mode 100644 index 0000000000..29d8bba4d9 --- /dev/null +++ b/src/schedule-and-details/license-section/license-icons/LicenseIcons.test.jsx @@ -0,0 +1,56 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import { LICENSE_TYPE } from '../constants'; +import messages from './messages'; +import LicenseIcons from '.'; + +const RootWrapper = (props) => ( + + + +); + +const props = { + licenseType: LICENSE_TYPE.allRightsReserved, + licenseDetails: {}, + licenseURL: 'link://to-license.ua', +}; + +describe('', () => { + it('renders all right reserved successfully', () => { + const { getByText, queryAllByText, queryAllByRole } = render(); + expect(getByText(messages.allRightReservedLabel.defaultMessage)).toBeInTheDocument(); + expect(queryAllByText(messages.creativeCommonsReservedLabel.defaultMessage).length).toBe(0); + expect(queryAllByRole('img', { hidden: true }).length).toBe(1); + }); + + it('renders some right reserved successfully', () => { + const initialProps = { ...props, licenseType: LICENSE_TYPE.creativeCommons }; + const { + getByText, + queryAllByText, + queryAllByRole, + getByRole, + } = render(); + expect(getByText(messages.creativeCommonsReservedLabel.defaultMessage)).toBeInTheDocument(); + expect(queryAllByText(messages.allRightReservedLabel.defaultMessage).length).toBe(0); + expect(queryAllByRole('img', { hidden: true }).length).toBe(1); + expect(getByRole('link').href).toBe(props.licenseURL); + }); + + it('should show needed icons following to licenseDetails', () => { + const initialProps = { + ...props, + licenseType: LICENSE_TYPE.creativeCommons, + licenseDetails: { + attribution: true, nonCommercial: true, noDerivatives: false, shareAlike: false, + }, + }; + const { getByText, queryAllByRole, debug } = render(); + debug(null, 20000); + expect(queryAllByRole('img', { hidden: true }).length).toBe(3); + expect(getByText(messages.creativeCommonsReservedLabel.defaultMessage)).toBeInTheDocument(); + }); +}); diff --git a/src/schedule-and-details/license-section/license-icons/index.jsx b/src/schedule-and-details/license-section/license-icons/index.jsx new file mode 100644 index 0000000000..1e5155ba7b --- /dev/null +++ b/src/schedule-and-details/license-section/license-icons/index.jsx @@ -0,0 +1,100 @@ +/* eslint-disable react/no-unstable-nested-components */ +import React from 'react'; +import PropTypes from 'prop-types'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { Icon, Stack, Hyperlink } from '@edx/paragon'; +import { + Attribution, Copyright, Cc, Nd, Nc, Sa, +} from '@edx/paragon/icons'; + +import ApplyWrapper from '../../../generic/ApplyWrapper'; +import { LICENSE_TYPE } from '../constants'; +import messages from './messages'; + +const LicenseIcons = ({ licenseType, licenseDetails, licenseURL }) => ( + ( + + {children} + + )} + > + + {[LICENSE_TYPE.allRightsReserved, null].includes(licenseType) && ( + + )} + {licenseType === LICENSE_TYPE.creativeCommons && ( + + )} + {licenseDetails?.attribution && ( + + )} + {licenseDetails?.nonCommercial && ( + + )} + {licenseDetails?.noDerivatives && ( + + )} + {licenseDetails?.shareAlike && ( + + )} + {[LICENSE_TYPE.allRightsReserved, null].includes(licenseType) && ( + + + + )} + {licenseType === LICENSE_TYPE.creativeCommons && ( + + + + )} + + +); + +LicenseIcons.defaultProps = { + licenseURL: '', +}; + +LicenseIcons.propTypes = { + licenseType: PropTypes.oneOf([...Object.values(LICENSE_TYPE), '']).isRequired, + licenseDetails: PropTypes.shape({ + attribution: PropTypes.bool, + nonCommercial: PropTypes.bool, + noDerivatives: PropTypes.bool, + shareAlike: PropTypes.bool, + }).isRequired, + licenseURL: PropTypes.string, +}; + +export default LicenseIcons; diff --git a/src/schedule-and-details/license-section/license-icons/messages.js b/src/schedule-and-details/license-section/license-icons/messages.js new file mode 100644 index 0000000000..324c286013 --- /dev/null +++ b/src/schedule-and-details/license-section/license-icons/messages.js @@ -0,0 +1,14 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + allRightReservedLabel: { + id: 'course-authoring.schedule-section.license.all-right-reserved.label', + defaultMessage: 'All rights reserved', + }, + creativeCommonsReservedLabel: { + id: 'course-authoring.schedule-section.license.creative-commons.label', + defaultMessage: 'Some rights reserved', + }, +}); + +export default messages; diff --git a/src/schedule-and-details/license-section/license-selector/LicenseSelector.test.jsx b/src/schedule-and-details/license-section/license-selector/LicenseSelector.test.jsx new file mode 100644 index 0000000000..a801dae1b6 --- /dev/null +++ b/src/schedule-and-details/license-section/license-selector/LicenseSelector.test.jsx @@ -0,0 +1,64 @@ +import React from 'react'; +import { + act, fireEvent, render, waitFor, +} from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import { LICENSE_TYPE } from '../constants'; +import messages from './messages'; +import LicenseSelector from '.'; + +const onChangeLicenseTypeMock = jest.fn(); +const RootWrapper = (props) => ( + + + +); + +const props = { + licenseType: LICENSE_TYPE.allRightsReserved, + onChangeLicenseType: onChangeLicenseTypeMock, +}; + +describe('', () => { + it('renders successfully', () => { + const { getByText, getByRole } = render(); + expect(getByText(messages.licenseType.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.creativeCommonsURLParagraph.defaultMessage)).toBeInTheDocument(); + expect(getByRole('button', { name: messages.licenseChoice1.defaultMessage })).toBeInTheDocument(); + expect(getByRole('button', { name: messages.licenseChoice2.defaultMessage })).toBeInTheDocument(); + }); + + it('should show active button', () => { + const { getByRole } = render(); + const activeButton = getByRole('button', { name: messages.licenseChoice1.defaultMessage }); + const anotherButton = getByRole('button', { name: messages.licenseChoice2.defaultMessage }); + expect(activeButton).toHaveClass('btn btn-primary'); + expect(anotherButton).toHaveClass('btn btn-outline-primary'); + }); + + it('should call onChangeLicenseType if button clicked', () => { + const { getByRole } = render(); + const button = getByRole('button', { name: messages.licenseChoice2.defaultMessage }); + expect(button).toHaveClass('btn btn-outline-primary'); + act(() => { + fireEvent.click(button); + }); + waitFor(() => { + expect(button).toHaveClass('btn btn-primary'); + }); + expect(props.onChangeLicenseType).toHaveBeenCalledWith( + LICENSE_TYPE.creativeCommons, + 'license', + ); + }); + + it('should show disabled buttons if license is null', () => { + const initialProps = { ...props, licenseType: null }; + const { getByRole } = render(); + const buttonFirst = getByRole('button', { name: messages.licenseChoice1.defaultMessage }); + const buttonSecond = getByRole('button', { name: messages.licenseChoice2.defaultMessage }); + expect(buttonFirst).toHaveClass('btn btn-outline-primary'); + expect(buttonSecond).toHaveClass('btn btn-outline-primary'); + }); +}); diff --git a/src/schedule-and-details/license-section/license-selector/index.jsx b/src/schedule-and-details/license-section/license-selector/index.jsx new file mode 100644 index 0000000000..0a434ed08a --- /dev/null +++ b/src/schedule-and-details/license-section/license-selector/index.jsx @@ -0,0 +1,79 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { + Form, + ButtonGroup, + Button, + OverlayTrigger, + Tooltip, + Hyperlink, +} from '@edx/paragon'; + +import { LICENSE_TYPE, creativeCommonsURL } from '../constants'; +import messages from './messages'; + +const LicenseSelector = ({ licenseType, onChangeLicenseType }) => { + const LICENSE_BUTTON_GROUP_LABELS = { + [LICENSE_TYPE.allRightsReserved]: { + label: , + tooltip: , + }, + [LICENSE_TYPE.creativeCommons]: { + label: , + tooltip: , + }, + }; + + const renderButton = (type) => { + const isActive = licenseType === type; + + return ( +
+ {LICENSE_BUTTON_GROUP_LABELS[type].tooltip} + } + > + + + {type === LICENSE_TYPE.creativeCommons && ( + +

+ +

+
+ )} +
+ ); + }; + + return ( + +

+ +

+ + {renderButton(LICENSE_TYPE.allRightsReserved)} + {renderButton(LICENSE_TYPE.creativeCommons)} + +
+ ); +}; + +LicenseSelector.propTypes = { + licenseType: PropTypes.oneOf([...Object.values(LICENSE_TYPE), '']).isRequired, + onChangeLicenseType: PropTypes.func.isRequired, +}; + +export default LicenseSelector; diff --git a/src/schedule-and-details/license-section/license-selector/messages.js b/src/schedule-and-details/license-section/license-selector/messages.js new file mode 100644 index 0000000000..08ccb613fa --- /dev/null +++ b/src/schedule-and-details/license-section/license-selector/messages.js @@ -0,0 +1,30 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + licenseType: { + id: 'course-authoring.schedule-section.license.type', + defaultMessage: 'License type', + }, + licenseChoice1: { + id: 'course-authoring.schedule-section.license.choice-1', + defaultMessage: 'All rights reserved', + }, + licenseChoice2: { + id: 'course-authoring.schedule-section.license.choice-2', + defaultMessage: 'Creative commons', + }, + licenseTooltip1: { + id: 'course-authoring.schedule-section.license.tooltip-1', + defaultMessage: 'You reserve all rights for your work', + }, + licenseTooltip2: { + id: 'course-authoring.schedule-section.license.tooltip-2', + defaultMessage: 'You waive some rights for your work, such that others can use it too', + }, + creativeCommonsURLParagraph: { + id: 'course-authoring.schedule-section.license.creative-commons.url', + defaultMessage: 'Learn more about creative commons', + }, +}); + +export default messages; diff --git a/src/schedule-and-details/license-section/messages.js b/src/schedule-and-details/license-section/messages.js new file mode 100644 index 0000000000..2d88b6cbea --- /dev/null +++ b/src/schedule-and-details/license-section/messages.js @@ -0,0 +1,46 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + licenseTitle: { + id: 'course-authoring.schedule-section.license.title', + defaultMessage: 'Course content license', + }, + licenseDescription: { + id: 'course-authoring.schedule-section.license.description', + defaultMessage: 'Select the default license for course content', + }, + licenseCreativeOption1Label: { + id: 'course-authoring.schedule-section.license.creative-commons.option.1.label', + defaultMessage: 'Attribution', + }, + licenseCreativeOption1Description: { + id: 'course-authoring.schedule-section.license.creative-commons.option.1.description', + defaultMessage: 'Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required.', + }, + licenseCreativeOption2Label: { + id: 'course-authoring.schedule-section.license.creative-commons.option.1.label', + defaultMessage: 'Noncommercial', + }, + licenseCreativeOption2Description: { + id: 'course-authoring.schedule-section.license.creative-commons.option.1.description', + defaultMessage: ' Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.', + }, + licenseCreativeOption3Label: { + id: 'course-authoring.schedule-section.license.creative-commons.option.1.label', + defaultMessage: 'No derivatives', + }, + licenseCreativeOption3Description: { + id: 'course-authoring.schedule-section.license.creative-commons.option.1.description', + defaultMessage: 'Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with "Share Alike".', + }, + licenseCreativeOption4Label: { + id: 'course-authoring.schedule-section.license.creative-commons.option.1.label', + defaultMessage: 'Share alike', + }, + licenseCreativeOption4Description: { + id: 'course-authoring.schedule-section.license.creative-commons.option.1.description', + defaultMessage: 'Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with "No Derivatives"', + }, +}); + +export default messages; diff --git a/src/schedule-and-details/license-section/utils.js b/src/schedule-and-details/license-section/utils.js new file mode 100644 index 0000000000..d0e3fd2d42 --- /dev/null +++ b/src/schedule-and-details/license-section/utils.js @@ -0,0 +1,14 @@ +import { LICENSE_COMMONS_OPTIONS } from './constants'; + +const generateLicenseURL = (details) => { + const url = 'https://creativecommons.org/licenses/'; + const detailsString = Object.entries(details) + .filter(([, value]) => value) + .map(([key]) => LICENSE_COMMONS_OPTIONS[key].toLowerCase()) + .join('-'); + + return `${url}${detailsString}/4.0/`; +}; + +// eslint-disable-next-line import/prefer-default-export +export { generateLicenseURL }; diff --git a/src/schedule-and-details/messages.js b/src/schedule-and-details/messages.js index 356cc125a3..0e21b4da51 100644 --- a/src/schedule-and-details/messages.js +++ b/src/schedule-and-details/messages.js @@ -21,6 +21,10 @@ const messages = defineMessages({ id: 'course-authoring.schedule.alert.button.save', defaultMessage: 'Save changes', }, + buttonSavingText: { + id: 'course-authoring.schedule.alert.button.saving', + defaultMessage: 'Saving', + }, buttonCancelText: { id: 'course-authoring.schedule.alert.button.cancel', defaultMessage: 'Cancel', @@ -89,6 +93,10 @@ const messages = defineMessages({ id: 'course-authoring.schedule.schedule-section.error-message-7', defaultMessage: 'The course must have an assigned start date.', }, + errorMessage8: { + id: 'course-authoring.schedule.schedule-section.error-message-8', + defaultMessage: 'Please enter an integer between %(min)s and %(max)s.', + }, }); export default messages; diff --git a/src/schedule-and-details/requirements-section/RequirementsSection.scss b/src/schedule-and-details/requirements-section/RequirementsSection.scss new file mode 100644 index 0000000000..96a57c82c6 --- /dev/null +++ b/src/schedule-and-details/requirements-section/RequirementsSection.scss @@ -0,0 +1,5 @@ +.requirements-section { + .form-group-custom:not(:last-child) { + margin-bottom: 2rem; + } +} diff --git a/src/schedule-and-details/requirements-section/RequirementsSection.test.jsx b/src/schedule-and-details/requirements-section/RequirementsSection.test.jsx new file mode 100644 index 0000000000..0ed6e6c301 --- /dev/null +++ b/src/schedule-and-details/requirements-section/RequirementsSection.test.jsx @@ -0,0 +1,93 @@ +import React from 'react'; +import { + render, fireEvent, act, +} from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import { courseDetailsMock, courseSettingsMock } from '../__mocks__'; +import messages from './messages'; +import entranceExamMessages from './entrance-exam/messages'; +import RequirementsSection from '.'; + +const onChangeMock = jest.fn(); +const courseIdMock = 'course-id-bar'; + +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), + useParams: () => ({ + courseId: courseIdMock, + }), +})); + +const RootWrapper = (props) => ( + + + +); +const { + effort, + entranceExamEnabled, + preRequisiteCourses, + entranceExamMinimumScorePct, +} = courseDetailsMock; + +const { + aboutPageEditable, + isEntranceExamsEnabled, + possiblePreRequisiteCourses, + isPrerequisiteCoursesEnabled, +} = courseSettingsMock; + +const props = { + effort, + errorFields: {}, + aboutPageEditable, + preRequisiteCourses, + entranceExamEnabled, + isEntranceExamsEnabled, + possiblePreRequisiteCourses, + entranceExamMinimumScorePct, + isPrerequisiteCoursesEnabled, + onChange: onChangeMock, +}; + +describe('', () => { + it('renders successfully', () => { + const { + getByText, getByLabelText, getByDisplayValue, getAllByRole, + } = render(); + const checkboxList = getAllByRole('checkbox'); + expect(getByText(messages.requirementsTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.requirementsDescription.defaultMessage)).toBeInTheDocument(); + expect(getByLabelText(messages.timepickerLabel.defaultMessage)).toBeInTheDocument(); + expect(getByDisplayValue(props.effort)).toBeInTheDocument(); + expect(getByText(messages.timepickerHelpText.defaultMessage)).toBeInTheDocument(); + expect(getByLabelText(messages.dropdownLabel.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.dropdownHelpText.defaultMessage)).toBeInTheDocument(); + expect(getByText(entranceExamMessages.requirementsEntrance.defaultMessage)).toBeInTheDocument(); + expect(checkboxList.length).toBe(1); + expect(checkboxList[0].checked).toBeTruthy(); + }); + + it('should call onChange on input change', () => { + const { getByDisplayValue } = render(); + const input = getByDisplayValue(props.effort); + act(() => { + fireEvent.change(input, { target: { value: '12h' } }); + }); + expect(props.onChange).toHaveBeenCalledWith('12h', 'effort'); + }); + + it('should hide content depend on flags', () => { + const initialProps = { + ...props, + aboutPageEditable: false, + isEntranceExamsEnabled: false, + isPrerequisiteCoursesEnabled: false, + }; + const { queryAllByLabelText } = render(); + expect(queryAllByLabelText(messages.timepickerLabel.defaultMessage).length).toBe(0); + expect(queryAllByLabelText(messages.dropdownLabel.defaultMessage).length).toBe(0); + expect(queryAllByLabelText(entranceExamMessages.requirementsEntrance.defaultMessage).length).toBe(0); + }); +}); diff --git a/src/schedule-and-details/requirements-section/entrance-exam/EntranceExam.test.jsx b/src/schedule-and-details/requirements-section/entrance-exam/EntranceExam.test.jsx new file mode 100644 index 0000000000..a6d2a8bbfa --- /dev/null +++ b/src/schedule-and-details/requirements-section/entrance-exam/EntranceExam.test.jsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { + render, fireEvent, act, waitFor, +} from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import { courseDetailsMock } from '../../__mocks__'; +import gradeRequirementsMessages from '../grade-requirements/messages'; +import messages from './messages'; +import EntranceExam from '.'; + +const onChangeMock = jest.fn(); +const courseIdMock = 'course-id-bar'; + +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), + useParams: () => ({ + courseId: courseIdMock, + }), +})); + +const RootWrapper = (props) => ( + + + +); + +const props = { + errorEffort: '', + isCheckedString: courseDetailsMock.entranceExamEnabled, + entranceExamMinimumScorePct: courseDetailsMock.entranceExamMinimumScorePct, + onChange: onChangeMock, +}; + +describe('', () => { + it('renders successfully', () => { + const { getByText, getAllByRole } = render(); + const checkboxList = getAllByRole('checkbox'); + expect(getByText(messages.requirementsEntrance.defaultMessage)).toBeInTheDocument(); + expect(checkboxList.length).toBe(1); + expect(checkboxList[0].checked).toBeTruthy(); + }); + + it('should toggle grade requirements after checkbox click', () => { + const { getByText, queryAllByText, getAllByRole } = render( + , + ); + const checkbox = getAllByRole('checkbox')[0]; + expect( + getByText(gradeRequirementsMessages.requirementsEntranceCollapseLabel.defaultMessage), + ).toBeInTheDocument(); + act(() => { + fireEvent.click(checkbox); + }); + waitFor(() => { + expect( + queryAllByText(gradeRequirementsMessages.requirementsEntranceCollapseLabel.defaultMessage).length, + ).toBe(0); + }); + }); +}); diff --git a/src/schedule-and-details/requirements-section/entrance-exam/index.jsx b/src/schedule-and-details/requirements-section/entrance-exam/index.jsx new file mode 100644 index 0000000000..5a8b0ae9a1 --- /dev/null +++ b/src/schedule-and-details/requirements-section/entrance-exam/index.jsx @@ -0,0 +1,93 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import { useParams } from 'react-router-dom'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { Form, Card, Hyperlink } from '@edx/paragon'; + +import { getPagePath } from '../../../utils'; +import GradeRequirements from '../grade-requirements'; +import messages from './messages'; + +const EntranceExam = ({ + errorEffort, + isCheckedString, + entranceExamMinimumScorePct, + onChange, +}) => { + const { courseId } = useParams(); + const initialEntranceExam = isCheckedString === 'true'; + const [showEntranceExam, setShowEntranceExam] = useState(initialEntranceExam); + + const toggleEntranceExam = () => { + onChange(showEntranceExam ? 'true' : 'false', 'entranceExamEnabled'); + setShowEntranceExam(!showEntranceExam); + }; + const courseOutlineDestination = getPagePath( + courseId, + process.env.ENABLE_NEW_COURSE_OUTLINE_PAGE, + 'course', + ); + + return ( + + + + + + + + + + + {showEntranceExam && ( + <> + + +

+ + + + ), + }} + /> +

+ +
+ + )} +
+
+ ); +}; + +EntranceExam.defaultProps = { + errorEffort: '', + isCheckedString: '', + entranceExamMinimumScorePct: '', +}; + +EntranceExam.propTypes = { + errorEffort: PropTypes.string, + isCheckedString: PropTypes.string, + entranceExamMinimumScorePct: PropTypes.string, + onChange: PropTypes.func.isRequired, +}; + +export default EntranceExam; diff --git a/src/schedule-and-details/requirements-section/entrance-exam/messages.js b/src/schedule-and-details/requirements-section/entrance-exam/messages.js new file mode 100644 index 0000000000..6f756097e9 --- /dev/null +++ b/src/schedule-and-details/requirements-section/entrance-exam/messages.js @@ -0,0 +1,22 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + requirementsEntrance: { + id: 'course-authoring.schedule-section.requirements.entrance.label', + defaultMessage: 'Entrance exam', + }, + requirementsEntranceCollapseTitle: { + id: 'course-authoring.schedule-section.requirements.entrance.collapse.title', + defaultMessage: 'Require students to pass an exam before beginning the course.', + }, + requirementsEntranceCollapseParagraph: { + id: 'course-authoring.schedule-section.requirements.entrance.collapse.paragraph', + defaultMessage: 'You can now view and author your course entrance exam from the {hyperlink}.', + }, + requirementsEntranceCollapseHyperlink: { + id: 'course-authoring.schedule-section.requirements.entrance.collapse.hyperlink', + defaultMessage: 'course outline', + }, +}); + +export default messages; diff --git a/src/schedule-and-details/requirements-section/grade-requirements/GradeRequirements.test.jsx b/src/schedule-and-details/requirements-section/grade-requirements/GradeRequirements.test.jsx new file mode 100644 index 0000000000..c3d979875d --- /dev/null +++ b/src/schedule-and-details/requirements-section/grade-requirements/GradeRequirements.test.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { + render, fireEvent, act, waitFor, +} from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import { courseDetailsMock } from '../../__mocks__'; +import scheduleMessage from '../../messages'; +import messages from './messages'; +import GradeRequirements from '.'; + +const onChangeMock = jest.fn(); + +const RootWrapper = (props) => ( + + + +); + +const props = { + errorEffort: '', + entranceExamMinimumScorePct: courseDetailsMock.entranceExamMinimumScorePct, + onChange: onChangeMock, +}; + +describe('', () => { + it('renders successfully', () => { + const { getByText, getByDisplayValue } = render(); + expect(getByText(messages.requirementsEntranceCollapseLabel.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.requirementsEntranceCollapseHelpText.defaultMessage)).toBeInTheDocument(); + expect(getByDisplayValue(props.entranceExamMinimumScorePct)).toBeInTheDocument(); + }); + + it('should call onChange on input change', () => { + const { getByDisplayValue } = render(); + const input = getByDisplayValue(props.entranceExamMinimumScorePct); + act(() => { + fireEvent.change(input, { target: { value: 'abc' } }); + }); + expect(props.onChange).toHaveBeenCalledWith('abc', 'entranceExamMinimumScorePct'); + }); + + it('should show feedback error', () => { + const { getByDisplayValue, getByText } = render(); + const input = getByDisplayValue(props.entranceExamMinimumScorePct); + act(() => { + fireEvent.change(input, { target: { value: '123' } }); + }); + waitFor(() => { + expect(getByText(scheduleMessage.errorMessage8.defaultMessage)).toBeInTheDocument(); + }); + }); +}); diff --git a/src/schedule-and-details/requirements-section/grade-requirements/index.jsx b/src/schedule-and-details/requirements-section/grade-requirements/index.jsx new file mode 100644 index 0000000000..bffbe39a89 --- /dev/null +++ b/src/schedule-and-details/requirements-section/grade-requirements/index.jsx @@ -0,0 +1,51 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { Form, Stack } from '@edx/paragon'; + +import messages from './messages'; + +const GradeRequirements = ({ + errorEffort, + entranceExamMinimumScorePct, + onChange, +}) => ( + + + + + + onChange(e.target.value, 'entranceExamMinimumScorePct')} + /> + % + + {errorEffort && ( + + {errorEffort} + + )} + + + + +); + +GradeRequirements.defaultProps = { + errorEffort: '', + entranceExamMinimumScorePct: '', +}; + +GradeRequirements.propTypes = { + errorEffort: PropTypes.string, + entranceExamMinimumScorePct: PropTypes.string, + onChange: PropTypes.func.isRequired, +}; + +export default GradeRequirements; diff --git a/src/schedule-and-details/requirements-section/grade-requirements/messages.js b/src/schedule-and-details/requirements-section/grade-requirements/messages.js new file mode 100644 index 0000000000..1993f8f81b --- /dev/null +++ b/src/schedule-and-details/requirements-section/grade-requirements/messages.js @@ -0,0 +1,15 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + requirementsEntranceCollapseLabel: { + id: 'course-authoring.schedule-section.requirements.entrance.collapse.label', + defaultMessage: 'Grade requirements', + }, + requirementsEntranceCollapseHelpText: { + id: 'course-authoring.schedule-section.requirements.entrance.collapse.help-text', + defaultMessage: + 'The score student must meet in order to successfully complete the entrance exam.', + }, +}); + +export default messages; diff --git a/src/schedule-and-details/requirements-section/index.jsx b/src/schedule-and-details/requirements-section/index.jsx new file mode 100644 index 0000000000..34e48d9902 --- /dev/null +++ b/src/schedule-and-details/requirements-section/index.jsx @@ -0,0 +1,130 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Form, Dropdown } from '@edx/paragon'; + +import { TIME_FORMAT } from '../schedule-section/datepicker-control/constants'; +import ScheduleSubHeader from '../schedule-sub-header'; +import EntranceExam from './entrance-exam'; +import messages from './messages'; + +const RequirementsSection = ({ + effort, + errorFields, + aboutPageEditable, + preRequisiteCourses, + entranceExamEnabled, + isEntranceExamsEnabled, + possiblePreRequisiteCourses, + entranceExamMinimumScorePct, + isPrerequisiteCoursesEnabled, + onChange, +}) => { + const intl = useIntl(); + const selectedItem = possiblePreRequisiteCourses.find( + (course) => course.courseKey === preRequisiteCourses[0], + ); + const formattedSelectedItem = selectedItem?.displayName || intl.formatMessage(messages.dropdownEmptyText); + + const renderPrerequisiteDropdown = () => ( + + {intl.formatMessage(messages.dropdownLabel)} + + + {formattedSelectedItem} + + + onChange([], 'preRequisiteCourses')} + > + {intl.formatMessage(messages.dropdownEmptyText)} + + {possiblePreRequisiteCourses.map((course) => ( + onChange([course.courseKey], 'preRequisiteCourses')} + > + {course.displayName} + + ))} + + + + {intl.formatMessage(messages.dropdownHelpText)} + + + ); + + return ( +
+ + {aboutPageEditable && ( + + + {intl.formatMessage(messages.timepickerLabel)} + + onChange(e.target.value, 'effort')} + /> + + {intl.formatMessage(messages.timepickerHelpText)} + + + )} + {isPrerequisiteCoursesEnabled && renderPrerequisiteDropdown()} + {isEntranceExamsEnabled && ( + + )} +
+ ); +}; + +const preRequisitesCourse = { + courseKey: PropTypes.string, + displayName: PropTypes.string, + lmsLink: PropTypes.string, + number: PropTypes.string, + org: PropTypes.string, + rerunLink: PropTypes.string, + run: PropTypes.string, + url: PropTypes.string, +}; + +RequirementsSection.defaultProps = { + effort: '', + errorFields: {}, + entranceExamEnabled: '', + preRequisiteCourses: [], + entranceExamMinimumScorePct: '', +}; + +RequirementsSection.propTypes = { + effort: PropTypes.string, + errorFields: PropTypes.objectOf(PropTypes.string), + aboutPageEditable: PropTypes.bool.isRequired, + preRequisiteCourses: PropTypes.arrayOf(PropTypes.string), + entranceExamEnabled: PropTypes.string, + isEntranceExamsEnabled: PropTypes.bool.isRequired, + possiblePreRequisiteCourses: PropTypes.arrayOf( + PropTypes.shape(preRequisitesCourse), + ).isRequired, + entranceExamMinimumScorePct: PropTypes.string, + isPrerequisiteCoursesEnabled: PropTypes.bool.isRequired, + onChange: PropTypes.func.isRequired, +}; + +export default RequirementsSection; diff --git a/src/schedule-and-details/requirements-section/messages.js b/src/schedule-and-details/requirements-section/messages.js new file mode 100644 index 0000000000..24b04e7f4a --- /dev/null +++ b/src/schedule-and-details/requirements-section/messages.js @@ -0,0 +1,34 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + requirementsTitle: { + id: 'course-authoring.schedule-section.requirements.title', + defaultMessage: 'Requirements', + }, + requirementsDescription: { + id: 'course-authoring.schedule-section.requirements.description', + defaultMessage: 'Expectations of the students taking this course', + }, + timepickerLabel: { + id: 'course-authoring.schedule-section.requirements.timepicker.label', + defaultMessage: 'Hours of effort per week', + }, + timepickerHelpText: { + id: 'course-authoring.schedule-section.requirements.timepicker.help-text', + defaultMessage: 'Time spent on all course work', + }, + dropdownLabel: { + id: 'course-authoring.schedule-section.requirements.dropdown.label', + defaultMessage: 'Prerequisite course', + }, + dropdownHelpText: { + id: 'course-authoring.schedule-section.requirements.dropdown.help-text', + defaultMessage: 'Course that students must complete before beginning this course', + }, + dropdownEmptyText: { + id: 'course-authoring.schedule-section.requirements.dropdown.empty-text', + defaultMessage: 'None', + }, +}); + +export default messages; diff --git a/src/schedule-and-details/utils.js b/src/schedule-and-details/utils.js index 3275a8a94e..f7b9b7ac13 100644 --- a/src/schedule-and-details/utils.js +++ b/src/schedule-and-details/utils.js @@ -45,6 +45,7 @@ const validateScheduleAndDetails = (courseDetails, intl) => { enrollmentEnd, enrollmentStart, certificateAvailableDate, + entranceExamMinimumScorePct, certificatesDisplayBehavior, } = courseDetails; @@ -79,6 +80,13 @@ const validateScheduleAndDetails = (courseDetails, intl) => { errors.certificateAvailableDate = intl.formatMessage(messages.errorMessage1); } + if (entranceExamMinimumScorePct) { + const number = Number(entranceExamMinimumScorePct); + if (Number.isNaN(number) || number < 1 || number > 100) { + errors.entranceExamMinimumScorePct = intl.formatMessage(messages.errorMessage8); + } + } + return errors; }; From 832485da39b40431b7a0fa6802f4ee36be87d63a Mon Sep 17 00:00:00 2001 From: ruzniaievdm Date: Thu, 6 Jul 2023 14:43:28 +0300 Subject: [PATCH 2/2] fix: add stateful button for saving advanced settings --- src/advanced-settings/AdvancedSettings.jsx | 35 ++++++++++++++++------ src/advanced-settings/messages.js | 4 +++ src/i18n/messages/ar.json | 3 +- src/i18n/messages/de.json | 3 +- src/i18n/messages/de_DE.json | 3 +- src/i18n/messages/es_419.json | 3 +- src/i18n/messages/fr.json | 3 +- src/i18n/messages/fr_CA.json | 3 +- src/i18n/messages/hi.json | 3 +- src/i18n/messages/it.json | 3 +- src/i18n/messages/it_IT.json | 3 +- src/i18n/messages/pt.json | 3 +- src/i18n/messages/pt_PT.json | 3 +- src/i18n/messages/ru.json | 3 +- src/i18n/messages/uk.json | 3 +- src/i18n/messages/zh_CN.json | 3 +- 16 files changed, 58 insertions(+), 23 deletions(-) diff --git a/src/advanced-settings/AdvancedSettings.jsx b/src/advanced-settings/AdvancedSettings.jsx index fa085140d3..3f1588f94b 100644 --- a/src/advanced-settings/AdvancedSettings.jsx +++ b/src/advanced-settings/AdvancedSettings.jsx @@ -1,7 +1,9 @@ import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; -import { Container, Button, Layout } from '@edx/paragon'; +import { + Container, Button, Layout, StatefulButton, +} from '@edx/paragon'; import { CheckCircle, Info, Warning } from '@edx/paragon/icons'; import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; @@ -35,8 +37,16 @@ const AdvancedSettings = ({ intl, courseId }) => { const [showSuccessAlert, setShowSuccessAlert] = useState(false); const loadingSettingsStatus = useSelector(getLoadingStatus); const [isQueryPending, setIsQueryPending] = useState(false); + const [isEditableState, setIsEditableState] = useState(false); const [showOverrideInternetConnectionAlert, setOverrideInternetConnectionAlert] = useState(false); const isLoading = loadingSettingsStatus === RequestStatus.IN_PROGRESS; + const updateSettingsButtonState = { + labels: { + default: intl.formatMessage(messages.buttonSaveText), + pending: intl.formatMessage(messages.buttonSavingText), + }, + disabledStates: ['pending'], + }; useEffect(() => { dispatch(fetchCourseAppSettings(courseId)); @@ -45,8 +55,13 @@ const AdvancedSettings = ({ intl, courseId }) => { useEffect(() => { if (savingStatus === RequestStatus.SUCCESSFUL) { - setShowSuccessAlert(true); - window.scrollTo({ top: 0, behavior: 'smooth' }); + setIsQueryPending(false); + + if (!isEditableState) { + showSaveSettingsPrompt(false); + setShowSuccessAlert(true); + window.scrollTo({ top: 0, behavior: 'smooth' }); + } } else if (savingStatus === RequestStatus.FAILED) { setErrorFields(settingsWithSendErrors); showErrorModal(true); @@ -63,6 +78,7 @@ const AdvancedSettings = ({ intl, courseId }) => { if (!saveSettingsPrompt) { showSaveSettingsPrompt(true); } + setIsEditableState(true); setOverrideInternetConnectionAlert(false); setShowSuccessAlert(false); setEditedSettings((prevEditedSettings) => ({ @@ -72,6 +88,7 @@ const AdvancedSettings = ({ intl, courseId }) => { }; const handleResetSettingsValues = () => { + setIsEditableState(false); showErrorModal(false); setEditedSettings({}); showSaveSettingsPrompt(false); @@ -85,9 +102,9 @@ const AdvancedSettings = ({ intl, courseId }) => { const handleUpdateAdvancedSettingsData = () => { const isValid = validateAdvancedSettingsData(editedSettings, setErrorFields, setEditedSettings); if (isValid) { + setIsEditableState(false); setIsQueryPending(true); setOverrideInternetConnectionAlert(true); - showSaveSettingsPrompt(!saveSettingsPrompt); } else { setIsQueryPending(false); showSaveSettingsPrompt(false); @@ -103,8 +120,6 @@ const AdvancedSettings = ({ intl, courseId }) => { }; const handleDispatchMethodCall = () => { - setIsQueryPending(false); - showSaveSettingsPrompt(false); setOverrideInternetConnectionAlert(false); }; @@ -221,9 +236,11 @@ const AdvancedSettings = ({ intl, courseId }) => { , - , + , ]} variant="warning" icon={Warning} diff --git a/src/advanced-settings/messages.js b/src/advanced-settings/messages.js index 535afe0e3f..5e004bf21b 100644 --- a/src/advanced-settings/messages.js +++ b/src/advanced-settings/messages.js @@ -41,6 +41,10 @@ const messages = defineMessages({ id: 'course-authoring.advanced-settings.alert.button.save', defaultMessage: 'Save changes', }, + buttonSavingText: { + id: 'course-authoring.advanced-settings.alert.button.saving', + defaultMessage: 'Saving', + }, buttonCancelText: { id: 'course-authoring.advanced-settings.alert.button.cancel', defaultMessage: 'Cancel', diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index c83f3ae780..fc6ce0d4fc 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 6d410725c5..517e1f8326 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/de_DE.json b/src/i18n/messages/de_DE.json index 33be3496bc..e2a898ccdc 100644 --- a/src/i18n/messages/de_DE.json +++ b/src/i18n/messages/de_DE.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/es_419.json b/src/i18n/messages/es_419.json index 73a995ee1b..1fc57dddac 100644 --- a/src/i18n/messages/es_419.json +++ b/src/i18n/messages/es_419.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index f79ad9b2ab..96e87f7d41 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/fr_CA.json b/src/i18n/messages/fr_CA.json index fbe991f5d7..63c39b4e8b 100644 --- a/src/i18n/messages/fr_CA.json +++ b/src/i18n/messages/fr_CA.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/hi.json b/src/i18n/messages/hi.json index 6d410725c5..517e1f8326 100644 --- a/src/i18n/messages/hi.json +++ b/src/i18n/messages/hi.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/it.json b/src/i18n/messages/it.json index 6d410725c5..517e1f8326 100644 --- a/src/i18n/messages/it.json +++ b/src/i18n/messages/it.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/it_IT.json b/src/i18n/messages/it_IT.json index 243f5a7fb7..3a539aaeae 100644 --- a/src/i18n/messages/it_IT.json +++ b/src/i18n/messages/it_IT.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index 6d410725c5..517e1f8326 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/pt_PT.json b/src/i18n/messages/pt_PT.json index 01b9d4f531..40cb1aa600 100644 --- a/src/i18n/messages/pt_PT.json +++ b/src/i18n/messages/pt_PT.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index 6d410725c5..517e1f8326 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/uk.json b/src/i18n/messages/uk.json index 6d410725c5..517e1f8326 100644 --- a/src/i18n/messages/uk.json +++ b/src/i18n/messages/uk.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" } diff --git a/src/i18n/messages/zh_CN.json b/src/i18n/messages/zh_CN.json index 6d410725c5..517e1f8326 100644 --- a/src/i18n/messages/zh_CN.json +++ b/src/i18n/messages/zh_CN.json @@ -597,5 +597,6 @@ "course-authoring.schedule-section.license.creative-commons.option.ND.description": "Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with 'Share Alike'.", "course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike", "course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.", - "course-authoring.schedule.alert.button.saving": "Saving" + "course-authoring.schedule.alert.button.saving": "Saving", + "course-authoring.advanced-settings.alert.button.saving": "Saving" }