feat: add download template button to taxonomy list [FC-0036] (#674)

This commit adds a new button in the Taxonomy List to allow users to download a sample taxonomy template in the format used to import taxonomies.
This commit is contained in:
Rômulo Penido
2023-12-19 01:01:48 -03:00
committed by GitHub
parent c68b2e3b06
commit a37d13f788
5 changed files with 90 additions and 19 deletions

View File

@@ -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 (
<>
<OverlayTrigger
placement="top"
overlay={(
<Tooltip>
{intl.formatMessage(messages.downloadTemplateButtonHint)}
</Tooltip>
)}
>
<Dropdown>
<Dropdown.Toggle
variant="outline-primary"
data-testid="taxonomy-download-template"
>
{intl.formatMessage(messages.downloadTemplateButtonLabel)}
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item
href={getTaxonomyTemplateApiUrl('csv')}
data-testid="taxonomy-download-template-csv"
>
{intl.formatMessage(messages.downloadTemplateButtonCSVLabel)}
</Dropdown.Item>
<Dropdown.Item
href={getTaxonomyTemplateApiUrl('json')}
data-testid="taxonomy-download-template-json"
>
{intl.formatMessage(messages.downloadTemplateButtonJSONLabel)}
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</OverlayTrigger>
<Button iconBefore={Add} disabled>
{intl.formatMessage(messages.importButtonLabel)}
</Button>
</>
);
};
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 = () => {
<SubHeader
title={intl.formatMessage(messages.headerTitle)}
titleActions={getOrgSelect()}
headerActions={getHeaderButtons()}
headerActions={<TaxonomyListHeaderButtons />}
hideBorder
/>
</Container>

View File

@@ -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('<TaxonomyListPage />', 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(<RootWrapper />);
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({

View File

@@ -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;
/**

View File

@@ -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';

View File

@@ -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',