Skip to content

Commit

Permalink
feat: display all child tags in the "bare bones" taxonomy detail page
Browse files Browse the repository at this point in the history
  • Loading branch information
bradenmacdonald committed Nov 17, 2023
1 parent 0fdaa07 commit 1e3aa3e
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 20 deletions.
31 changes: 17 additions & 14 deletions src/generic/Loading.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,30 @@ import React from 'react';
import { Spinner } from '@edx/paragon';
import { FormattedMessage } from '@edx/frontend-platform/i18n';


Check failure on line 5 in src/generic/Loading.jsx

View workflow job for this annotation

GitHub Actions / tests

More than 1 blank line not allowed
export const LoadingSpinner = () => (
<Spinner
animation="border"
role="status"
variant="primary"
screenReaderText={(
<FormattedMessage
id="authoring.loading"
defaultMessage="Loading..."
description="Screen-reader message for when a page is loading."
/>
)}
/>
);

const Loading = () => (
<div
className="d-flex justify-content-center align-items-center flex-column"
style={{
height: '100vh',
}}
>
<Spinner
animation="border"
role="status"
variant="primary"
screenReaderText={(
<span className="sr-only">
<FormattedMessage
id="authoring.loading"
defaultMessage="Loading..."
description="Screen-reader message for when a page is loading."
/>
</span>
)}
/>
<LoadingSpinner />
</div>
);

Expand Down
47 changes: 42 additions & 5 deletions src/taxonomy/tag-list/TagListTable.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,38 @@
// ts-check
import { useIntl } from '@edx/frontend-platform/i18n';
import {
DataTable,
} from '@edx/paragon';
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
import { DataTable } from '@edx/paragon';
import _ from 'lodash';
import Proptypes from 'prop-types';
import { useState } from 'react';

import { LoadingSpinner } from '../../generic/Loading';
import messages from './messages';
import { useTagListDataResponse, useTagListDataStatus } from './data/apiHooks';
import { useSubTags } from './data/api';

const SubTagsExpanded = ({ taxonomyId, parentTagValue }) => {

Check failure on line 13 in src/taxonomy/tag-list/TagListTable.jsx

View workflow job for this annotation

GitHub Actions / tests

Block must not be padded by blank lines

const subTagsData = useSubTags(taxonomyId, parentTagValue);

if (subTagsData.isLoading) {
return <LoadingSpinner />;
} else if (subTagsData.isError) {

Check failure on line 19 in src/taxonomy/tag-list/TagListTable.jsx

View workflow job for this annotation

GitHub Actions / tests

Unnecessary 'else' after 'return'
return <FormattedMessage {...messages.tagListError} />

Check failure on line 20 in src/taxonomy/tag-list/TagListTable.jsx

View workflow job for this annotation

GitHub Actions / tests

Missing semicolon
}

return <ul style={{ listStyleType: "none" }}>

Check failure on line 23 in src/taxonomy/tag-list/TagListTable.jsx

View workflow job for this annotation

GitHub Actions / tests

Missing parentheses around multilines JSX

Check failure on line 23 in src/taxonomy/tag-list/TagListTable.jsx

View workflow job for this annotation

GitHub Actions / tests

Strings must use singlequote
{subTagsData.data.results.map(tagData =>
<li key={tagData.id} style={{ paddingLeft: ((tagData.depth - 1) * 30) + "px" }}>

Check failure on line 25 in src/taxonomy/tag-list/TagListTable.jsx

View workflow job for this annotation

GitHub Actions / tests

Expected no linebreak before this expression

Check failure on line 25 in src/taxonomy/tag-list/TagListTable.jsx

View workflow job for this annotation

GitHub Actions / tests

Missing parentheses around multilines JSX

Check failure on line 25 in src/taxonomy/tag-list/TagListTable.jsx

View workflow job for this annotation

GitHub Actions / tests

Unexpected string concatenation

Check failure on line 25 in src/taxonomy/tag-list/TagListTable.jsx

View workflow job for this annotation

GitHub Actions / tests

Strings must use singlequote
{tagData.value} <span className="text-light-900">{tagData.childCount > 0 ? `(${tagData.childCount})` : null}</span>
</li>
)}
</ul>;
};

SubTagsExpanded.propTypes = {
taxonomyId: Proptypes.number.isRequired,
parentTagValue: Proptypes.string.isRequired,
};

const TagListTable = ({ taxonomyId }) => {
const intl = useIntl();
Expand Down Expand Up @@ -46,11 +70,24 @@ const TagListTable = ({ taxonomyId }) => {
itemCount={tagList?.count || 0}
pageCount={tagList?.numPages || 0}
initialState={options}
isExpandable
// This is a temporary "bare bones" solution for brute-force loading all the child tags. In future we'll match
// the Figma design and do something more sophisticated.
renderRowSubComponent={({ row }) => <SubTagsExpanded taxonomyId={taxonomyId} parentTagValue={row.values.value} />}
columns={[
{
Header: intl.formatMessage(messages.tagListColumnValueHeader),
accessor: 'value',
},
{
id: 'expander',
Header: DataTable.ExpandAll,
Cell: ({row}) => row.values.childCount > 0 ? <DataTable.ExpandRow row={row} /> : null,
},
{
Header: intl.formatMessage(messages.tagListColumnChildCountHeader),
accessor: 'childCount',
},
]}
>
<DataTable.TableControlBar />
Expand All @@ -62,7 +99,7 @@ const TagListTable = ({ taxonomyId }) => {
};

TagListTable.propTypes = {
taxonomyId: Proptypes.string.isRequired,
taxonomyId: Proptypes.number.isRequired,
};

export default TagListTable;
18 changes: 18 additions & 0 deletions src/taxonomy/tag-list/data/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,21 @@ export const useTagListData = (taxonomyId, options) => {
.then(camelCaseObject),
});
};

/**
* @param {number} taxonomyId
* @param {string} parentTagValue
* @returns {import('@tanstack/react-query').UseQueryResult<import('./types.mjs').TagData>}
*/
export const useSubTags = (taxonomyId, parentTagValue) => {
return useQuery({
queryKey: ['subtagsList', taxonomyId, parentTagValue],
queryFn: async () => {
const url = new URL(`api/content_tagging/v1/taxonomies/${taxonomyId}/tags/`, getApiBaseUrl());
url.searchParams.set("full_depth_threshold", "10000"); // Load as deeply as we can
url.searchParams.set("parent_tag", parentTagValue);
const response = await getAuthenticatedHttpClient().get(url.href);
return camelCaseObject(response.data);
},
});
};
8 changes: 8 additions & 0 deletions src/taxonomy/tag-list/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ const messages = defineMessages({
id: 'course-authoring.tag-list.column.value.header',
defaultMessage: 'Value',
},
tagListColumnChildCountHeader: {
id: 'course-authoring.tag-list.column.value.header',
defaultMessage: '# child tags',
},
tagListError: {
id: 'course-authoring.tag-list.error',
defaultMessage: 'Error: unable to load child tags',
},
});

export default messages;
3 changes: 2 additions & 1 deletion src/taxonomy/taxonomy-detail/TaxonomyDetailPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import { useTaxonomyDetailDataResponse, useTaxonomyDetailDataStatus } from './da

const TaxonomyDetailPage = () => {
const intl = useIntl();
const { taxonomyId } = useParams();
const { taxonomyId: taxonomyIdString } = useParams();
const taxonomyId = Number(taxonomyIdString);

const useTaxonomyDetailData = () => {
const { isError, isFetched } = useTaxonomyDetailDataStatus(taxonomyId);
Expand Down

0 comments on commit 1e3aa3e

Please sign in to comment.