diff --git a/src/taxonomy/TaxonomyListPage.jsx b/src/taxonomy/TaxonomyListPage.jsx
index 9a1e69ffd..8f991fbfd 100644
--- a/src/taxonomy/TaxonomyListPage.jsx
+++ b/src/taxonomy/TaxonomyListPage.jsx
@@ -1,19 +1,69 @@
import React, { useContext } from 'react';
import {
+ Button,
CardView,
Container,
DataTable,
+ Dropdown,
+ OverlayTrigger,
Spinner,
+ Tooltip,
} from '@edx/paragon';
+import {
+ Add,
+} from '@edx/paragon/icons';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Helmet } from 'react-helmet';
import SubHeader from '../generic/sub-header/SubHeader';
import getPageHeadTitle from '../generic/utils';
import messages from './messages';
import TaxonomyCard from './taxonomy-card';
+import { getTaxonomyTemplateApiUrl } from './data/api';
import { useTaxonomyListDataResponse, useIsTaxonomyListDataLoaded, useDeleteTaxonomy } from './data/apiHooks';
import { TaxonomyContext } from './common/context';
+const TaxonomyListHeaderButtons = () => {
+ const intl = useIntl();
+ return (
+ <>
+
+ {intl.formatMessage(messages.downloadTemplateButtonHint)}
+
+ )}
+ >
+
+
+ {intl.formatMessage(messages.downloadTemplateButtonLabel)}
+
+
+
+ {intl.formatMessage(messages.downloadTemplateButtonCSVLabel)}
+
+
+ {intl.formatMessage(messages.downloadTemplateButtonJSONLabel)}
+
+
+
+
+
+ >
+ );
+};
+
const TaxonomyListPage = () => {
const intl = useIntl();
const deleteTaxonomy = useDeleteTaxonomy();
@@ -37,12 +87,6 @@ const TaxonomyListPage = () => {
};
const { taxonomyListData, isLoaded } = useTaxonomyListData();
- const getHeaderButtons = () => (
- // Download template and import buttons.
- // TODO Add functionality to this buttons.
- undefined
- );
-
const getOrgSelect = () => (
// Organization select component
// TODO Add functionality to this component
@@ -59,7 +103,7 @@ const TaxonomyListPage = () => {
}
hideBorder
/>
diff --git a/src/taxonomy/TaxonomyListPage.test.jsx b/src/taxonomy/TaxonomyListPage.test.jsx
index 17c95034e..c7a634d29 100644
--- a/src/taxonomy/TaxonomyListPage.test.jsx
+++ b/src/taxonomy/TaxonomyListPage.test.jsx
@@ -5,7 +5,7 @@ import { AppProvider } from '@edx/frontend-platform/react';
import { act, render, fireEvent } from '@testing-library/react';
import initializeStore from '../store';
-
+import { getTaxonomyTemplateApiUrl } from './data/api';
import TaxonomyListPage from './TaxonomyListPage';
import { useTaxonomyListDataResponse, useIsTaxonomyListDataLoaded } from './data/apiHooks';
import { TaxonomyContext } from './common/context';
@@ -84,6 +84,24 @@ describe('', async () => {
});
});
+ it.each(['CSV', 'JSON'])('downloads the taxonomy template %s', async (fileFormat) => {
+ useIsTaxonomyListDataLoaded.mockReturnValue(true);
+ useTaxonomyListDataResponse.mockReturnValue({
+ results: [{
+ id: 1,
+ name: 'Taxonomy',
+ description: 'This is a description',
+ }],
+ });
+ const { findByRole } = render();
+ const templateMenu = await findByRole('button', { name: 'Download template' });
+ fireEvent.click(templateMenu);
+ const templateButton = await findByRole('link', { name: `${fileFormat} template` });
+ fireEvent.click(templateButton);
+
+ expect(templateButton.href).toBe(getTaxonomyTemplateApiUrl(fileFormat.toLowerCase()));
+ });
+
it('should show the success toast after delete', async () => {
useIsTaxonomyListDataLoaded.mockReturnValue(true);
useTaxonomyListDataResponse.mockReturnValue({
diff --git a/src/taxonomy/data/api.js b/src/taxonomy/data/api.js
index f7fdf447c..95a675ba4 100644
--- a/src/taxonomy/data/api.js
+++ b/src/taxonomy/data/api.js
@@ -18,6 +18,10 @@ export const getExportTaxonomyApiUrl = (pk, format) => new URL(
`api/content_tagging/v1/taxonomies/${pk}/export/?output_format=${format}&download=1`,
getApiBaseUrl(),
).href;
+export const getTaxonomyTemplateApiUrl = (format) => new URL(
+ `api/content_tagging/v1/taxonomies/import/template.${format}`,
+ getApiBaseUrl(),
+).href;
export const getTaxonomyApiUrl = (pk) => new URL(`api/content_tagging/v1/taxonomies/${pk}/`, getApiBaseUrl()).href;
/**
diff --git a/src/taxonomy/data/api.test.js b/src/taxonomy/data/api.test.js
index 3b83dd1b2..b95ed9a57 100644
--- a/src/taxonomy/data/api.test.js
+++ b/src/taxonomy/data/api.test.js
@@ -5,10 +5,10 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { taxonomyListMock } from '../__mocks__';
import {
- getTaxonomyListApiUrl,
getExportTaxonomyApiUrl,
- getTaxonomyListData,
getTaxonomyExportFile,
+ getTaxonomyListApiUrl,
+ getTaxonomyListData,
getTaxonomyApiUrl,
deleteTaxonomy,
} from './api';
@@ -26,6 +26,7 @@ describe('taxonomy api calls', () => {
roles: [],
},
});
+
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
});
@@ -44,14 +45,6 @@ describe('taxonomy api calls', () => {
window.location = location;
});
- it('should get taxonomy list data', async () => {
- axiosMock.onGet(getTaxonomyListApiUrl()).reply(200, taxonomyListMock);
- const result = await getTaxonomyListData();
-
- expect(axiosMock.history.get[0].url).toEqual(getTaxonomyListApiUrl());
- expect(result).toEqual(taxonomyListMock);
- });
-
it('should get taxonomy list data with org', async () => {
const org = 'testOrg';
axiosMock.onGet(getTaxonomyListApiUrl(org)).reply(200, taxonomyListMock);
@@ -68,7 +61,7 @@ describe('taxonomy api calls', () => {
expect(axiosMock.history.delete[0].url).toEqual(getTaxonomyApiUrl());
});
- it('should set window.location.href correctly', () => {
+ it('Export should set window.location.href correctly', () => {
const pk = 1;
const format = 'json';
diff --git a/src/taxonomy/messages.js b/src/taxonomy/messages.js
index 0a60c4725..ace08d33d 100644
--- a/src/taxonomy/messages.js
+++ b/src/taxonomy/messages.js
@@ -9,6 +9,18 @@ const messages = defineMessages({
id: 'course-authoring.taxonomy-list.button.download-template.label',
defaultMessage: 'Download template',
},
+ downloadTemplateButtonCSVLabel: {
+ id: 'course-authoring.taxonomy-list.button.download-template.csv.label',
+ defaultMessage: 'CSV template',
+ },
+ downloadTemplateButtonJSONLabel: {
+ id: 'course-authoring.taxonomy-list.button.download-template.json.label',
+ defaultMessage: 'JSON template',
+ },
+ downloadTemplateButtonHint: {
+ id: 'course-authoring.taxonomy-list.butotn.download-template.hint',
+ defaultMessage: 'Download example taxonomy',
+ },
importButtonLabel: {
id: 'course-authoring.taxonomy-list.button.import.label',
defaultMessage: 'Import',