diff --git a/src/taxonomy/data/types.mjs b/src/taxonomy/data/types.mjs index 6609a342a..8947c0e43 100644 --- a/src/taxonomy/data/types.mjs +++ b/src/taxonomy/data/types.mjs @@ -5,6 +5,7 @@ * @property {number} id * @property {string} name * @property {string} description + * @property {string} exportId * @property {boolean} enabled * @property {boolean} allowMultiple * @property {boolean} allowFreeText diff --git a/src/taxonomy/import-tags/__mocks__/taxonomyImportMock.js b/src/taxonomy/import-tags/__mocks__/taxonomyImportMock.js index 9db45b4a5..655c4ee08 100644 --- a/src/taxonomy/import-tags/__mocks__/taxonomyImportMock.js +++ b/src/taxonomy/import-tags/__mocks__/taxonomyImportMock.js @@ -1,4 +1,5 @@ export default { name: 'Taxonomy name', + exportId: 'taxonomy_export_id', description: 'Taxonomy description', }; diff --git a/src/taxonomy/import-tags/data/api.js b/src/taxonomy/import-tags/data/api.js index a31abace6..124d329ec 100644 --- a/src/taxonomy/import-tags/data/api.js +++ b/src/taxonomy/import-tags/data/api.js @@ -35,10 +35,11 @@ export const getTagsPlanImportApiUrl = (taxonomyId) => new URL( * @param {File} file * @returns {Promise} */ -export async function importNewTaxonomy(taxonomyName, taxonomyDescription, file) { +export async function importNewTaxonomy(taxonomyName, taxonomyExportId, taxonomyDescription, file) { // ToDo: transform this to use react-query like useImportTags const formData = new FormData(); formData.append('taxonomy_name', taxonomyName); + formData.append('taxonomy_export_id', taxonomyExportId); formData.append('taxonomy_description', taxonomyDescription); formData.append('file', file); diff --git a/src/taxonomy/import-tags/data/api.test.jsx b/src/taxonomy/import-tags/data/api.test.jsx index 6461e6808..9e4c35017 100644 --- a/src/taxonomy/import-tags/data/api.test.jsx +++ b/src/taxonomy/import-tags/data/api.test.jsx @@ -51,7 +51,7 @@ describe('import taxonomy api calls', () => { it('should call import new taxonomy', async () => { axiosMock.onPost(getTaxonomyImportNewApiUrl()).reply(201, taxonomyImportMock); - const result = await importNewTaxonomy('Taxonomy name', 'Taxonomy description'); + const result = await importNewTaxonomy('Taxonomy name', 'taxonomy_export_id', 'Taxonomy description'); expect(axiosMock.history.post[0].url).toEqual(getTaxonomyImportNewApiUrl()); expect(result).toEqual(taxonomyImportMock); diff --git a/src/taxonomy/import-tags/data/utils.js b/src/taxonomy/import-tags/data/utils.js index 71377ac72..8b06858d7 100644 --- a/src/taxonomy/import-tags/data/utils.js +++ b/src/taxonomy/import-tags/data/utils.js @@ -64,6 +64,26 @@ export const importTaxonomy = async (intl) => { // eslint-disable-line import/pr return taxonomyName; }; + const getTaxonomyExportId = () => { + let taxonomyExportId = null; + const validationRegex = /^[\p{L}\w\-.]+$/u; + while (!taxonomyExportId) { + taxonomyExportId = prompt(intl.formatMessage(messages.promptTaxonomyExportId)); + + if (taxonomyExportId == null) { + break; + } + + if (!taxonomyExportId) { + alert(intl.formatMessage(messages.promptTaxonomyExportIdRequired)); + } else if (!validationRegex.test(taxonomyExportId)) { + alert(intl.formatMessage(messages.promptTaxonomyExportIdInvalid)); + taxonomyExportId = null; + } + } + return taxonomyExportId; + }; + const getTaxonomyDescription = () => prompt(intl.formatMessage(messages.promptTaxonomyDescription)); const file = await selectFile(); @@ -77,12 +97,17 @@ export const importTaxonomy = async (intl) => { // eslint-disable-line import/pr return; } + const taxonomyExportId = getTaxonomyExportId(); + if (taxonomyExportId == null) { + return; + } + const taxonomyDescription = getTaxonomyDescription(); if (taxonomyDescription == null) { return; } - importNewTaxonomy(taxonomyName, taxonomyDescription, file) + importNewTaxonomy(taxonomyName, taxonomyExportId, taxonomyDescription, file) .then(() => { alert(intl.formatMessage(messages.importTaxonomySuccess)); }) diff --git a/src/taxonomy/import-tags/messages.js b/src/taxonomy/import-tags/messages.js index 05e4eb738..6fa09f44a 100644 --- a/src/taxonomy/import-tags/messages.js +++ b/src/taxonomy/import-tags/messages.js @@ -92,6 +92,18 @@ const messages = defineMessages({ id: 'course-authoring.import-tags.prompt.taxonomy-name.required', defaultMessage: 'You must enter a name for the new taxonomy', }, + promptTaxonomyExportId: { + id: 'course-authoring.import-tags.prompt.taxonomy-export-id', + defaultMessage: "Enter a Export ID for the new taxonomy. Should only contain alphanumeric characters or '_' '-' '.'", + }, + promptTaxonomyExportIdRequired: { + id: 'course-authoring.import-tags.prompt.taxonomy-export-id.required', + defaultMessage: 'You must enter an Export ID for the new taxonomy.', + }, + promptTaxonomyExportIdInvalid: { + id: 'course-authoring.import-tags.prompt.taxonomy-export-id.invalid', + defaultMessage: "Invalid Export ID. Should only contain alphanumeric characters or '_' '-' '.'", + }, promptTaxonomyDescription: { id: 'course-authoring.import-tags.prompt.taxonomy-description', defaultMessage: 'Enter a description for the new taxonomy', diff --git a/src/taxonomy/taxonomy-detail/TaxonomyDetailSideCard.jsx b/src/taxonomy/taxonomy-detail/TaxonomyDetailSideCard.jsx index e4eec9cb6..19ee4e5b2 100644 --- a/src/taxonomy/taxonomy-detail/TaxonomyDetailSideCard.jsx +++ b/src/taxonomy/taxonomy-detail/TaxonomyDetailSideCard.jsx @@ -18,6 +18,9 @@ const TaxonomyDetailSideCard = ({ taxonomy }) => { {taxonomy.description} + + {taxonomy.exportId} + ); }; @@ -25,6 +28,7 @@ const TaxonomyDetailSideCard = ({ taxonomy }) => { TaxonomyDetailSideCard.propTypes = { taxonomy: PropTypes.shape({ name: PropTypes.string.isRequired, + exportId: PropTypes.string.isRequired, description: PropTypes.string.isRequired, }).isRequired, }; diff --git a/src/taxonomy/taxonomy-detail/messages.js b/src/taxonomy/taxonomy-detail/messages.js index e8ac8851d..922474216 100644 --- a/src/taxonomy/taxonomy-detail/messages.js +++ b/src/taxonomy/taxonomy-detail/messages.js @@ -14,6 +14,10 @@ const messages = defineMessages({ id: 'course-authoring.taxonomy-detail.side-card.description', defaultMessage: 'Description', }, + taxonomyDetailsExportID: { + id: 'course-authoring.taxonomy-detail.side-card.exportID', + defaultMessage: 'Export ID', + }, }); export default messages;