Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions src/content-tags-drawer/ContentTagsCollapsibleHelper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,6 @@ const getLeafTags = (tree) => {
* @param {StagedTagData[]} stagedContentTags
* - Array of staged tags represented as objects with value/label
* @param {TaxonomyData & {contentTags: ContentTagData[]}} taxonomyAndTagsData
* @returns {{
* tagChangeHandler: (tagSelectableBoxValue: string, checked: boolean) => void,
* removeAppliedTagHandler: (tagSelectableBoxValue: string) => void,
* appliedContentTagsTree: Record<string, TagTreeEntry>,
* stagedContentTagsTree: Record<string, TagTreeEntry>,
* contentTagsCount: number,
* checkedTags: any,
* commitStagedTagsToGlobal: () => void,
* updateTags: import('@tanstack/react-query').UseMutationResult<
* any, unknown, { tagsData: Promise<UpdateTagsData[]>; }, unknown
* >
* }}
*/
const useContentTagsCollapsibleHelper = (
Expand Down
1 change: 0 additions & 1 deletion src/content-tags-drawer/ContentTagsDrawerHelper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,6 @@ export const useCreateContentTagsDrawerContext = (contentId, canTagObject, fetch
tags: tags.contentTags.map(t => t.value),
});
});
// @ts-ignore
updateTags.mutate({ tagsData });
}, [tagsByTaxonomy]);

Expand Down
3 changes: 3 additions & 0 deletions src/content-tags-drawer/ContentTagsSnippet.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.tag-snippet-chip {
max-width: 260px;
}
55 changes: 55 additions & 0 deletions src/content-tags-drawer/ContentTagsSnippet.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {
render, screen, waitFor, initializeMocks,
} from '@src/testUtils';

import { mockContentTaxonomyTagsData } from './data/api.mocks';
import { ContentTagsSnippet } from './ContentTagsSnippet';

mockContentTaxonomyTagsData.applyMock();

const {
otherTagsId,
largeTagsId,
veryLongTagsId,
} = mockContentTaxonomyTagsData;

describe('<ContentTagsSnippet />', () => {
beforeEach(() => {
initializeMocks();
});

it('should render the tags correctly', async () => {
render(<ContentTagsSnippet contentId={otherTagsId} />);
await waitFor(() => {
expect(screen.getByText('Taxonomy 1 (2)')).toBeInTheDocument();
});
expect(screen.getByText('Tag 1')).toBeInTheDocument();
expect(screen.getByText('Tag 2')).toBeInTheDocument();
expect(screen.getByText('Taxonomy 2 (2)')).toBeInTheDocument();
expect(screen.getByText('Tag 3')).toBeInTheDocument();
expect(screen.getByText('Tag 4')).toBeInTheDocument();
});

it('should render the tags with lineage correctly', async () => {
render(<ContentTagsSnippet contentId={largeTagsId} />);
await waitFor(() => {
expect(screen.getByText('Taxonomy 3 (1)')).toBeInTheDocument();
});
expect(screen.getByText('Tag 1 > Tag 1.1 > Tag 1.1.1')).toBeInTheDocument();
});

it('should render the very long lineage correctly', async () => {
render(<ContentTagsSnippet contentId={veryLongTagsId} />);
await waitFor(() => {
expect(screen.getByText('ESDC Skills and Competencies (2)')).toBeInTheDocument();
});

// Skills > Technical Skills Sub-Category > Technical Skills
// Can fit only first and last level
expect(screen.getByText('Skills > .. > Technical Skills')).toBeInTheDocument();

// Abilities > Cognitive Abilities > Communication Abilities
// can fit only last level
expect(screen.getByText('.. > Communication Abilities')).toBeInTheDocument();
});
});
67 changes: 67 additions & 0 deletions src/content-tags-drawer/ContentTagsSnippet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Chip, Stack } from '@openedx/paragon';
import { Tag as TagIcon } from '@openedx/paragon/icons';

import { useContentTaxonomyTagsData } from './data/apiHooks';
import { Tag } from './data/types';

interface ContentTagsSnippetProps {
contentId: string;
}

const ContentTagChip = ({ tag }: { tag: Tag }) => {
let lineageStr = tag.lineage.join(' > ');
const lineageLength = tag.lineage.length;
const MAX_TAG_LENGTH = 30;

if (lineageStr.length > MAX_TAG_LENGTH && lineageLength > 1) {
if (lineageLength > 2) {
// NOTE: If the tag lineage is too long and have more than 2 tags, we truncate it to the first and last level
// i.e "Abilities > Cognitive Abilities > Communication Abilities" becomes
// "Abilities > .. > Communication Abilities"
lineageStr = `${tag.lineage[0]} > .. > ${tag.lineage[lineageLength - 1]}`;
}

if (lineageStr.length > MAX_TAG_LENGTH) {
// NOTE: If the tag lineage is still too long, we truncate it only to the last level
// i.e "Knowledge > .. > Administration and Management" becomes
// ".. > Administration and Management"
lineageStr = `.. > ${tag.lineage[lineageLength - 1]}`;
}
}

return (
<Chip
iconBefore={TagIcon}
className="mr-1 tag-snippet-chip small"
>
{lineageStr}
</Chip>
);
};

export const ContentTagsSnippet = ({ contentId }: ContentTagsSnippetProps) => {
const {
data,
} = useContentTaxonomyTagsData(contentId);

if (!data) {
return null;
}

return (
<Stack gap={2}>
{data.taxonomies.map((taxonomy) => (
<div key={taxonomy.taxonomyId}>
<h4 className="font-weight-bold x-small text-muted">
{`${taxonomy.name} (${taxonomy.tags.length})`}
</h4>
<div className="d-flex flex-wrap">
{taxonomy.tags.map((tag) => (
<ContentTagChip key={tag.value} tag={tag} />
))}
</div>
</div>
))}
</Stack>
);
};
20 changes: 0 additions & 20 deletions src/content-tags-drawer/TagOutlineIcon.tsx

This file was deleted.

101 changes: 0 additions & 101 deletions src/content-tags-drawer/data/api.js

This file was deleted.

32 changes: 32 additions & 0 deletions src/content-tags-drawer/data/api.mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export async function mockContentTaxonomyTagsData(contentId: string): Promise<an
case thisMock.largeTagsId: return thisMock.largeTags;
case thisMock.containerTagsId: return thisMock.largeTags;
case thisMock.emptyTagsId: return thisMock.emptyTags;
case thisMock.veryLongTagsId: return thisMock.veryLongTags;
default: throw new Error(`No mock has been set up for contentId "${contentId}"`);
}
}
Expand Down Expand Up @@ -205,6 +206,37 @@ mockContentTaxonomyTagsData.emptyTagsId = 'block-v1:EmptyTagsOrg+STC1+2023_1+typ
mockContentTaxonomyTagsData.emptyTags = {
taxonomies: [],
};
mockContentTaxonomyTagsData.veryLongTagsId = 'block-v1:VeryLongTagsOrg+STC1+2023_1+type@vertical+block@veryLongTagsId';
mockContentTaxonomyTagsData.veryLongTags = {
taxonomies: [
{
name: 'ESDC Skills and Competencies',
taxonomyId: 1,
canTagObject: true,
tags: [
{
value: 'Technical Skills',
lineage: [
'Skills',
'Technical Skills Sub-Category',
'Technical Skills',
],
canDeleteObjecttag: true,
},
{
value: 'Communication Abilities',
lineage: [
'Abilities',
'Cognitive Abilities',
'Communication Abilities',
],
canDeleteObjecttag: true,
},
],
},
],
};

mockContentTaxonomyTagsData.containerTagsId = 'lct:StagedTagsOrg:lib:unit:container_tags';
mockContentTaxonomyTagsData.applyMock = () => jest.spyOn(api, 'getContentTaxonomyTagsData').mockImplementation(mockContentTaxonomyTagsData);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-check
import MockAdapter from 'axios-mock-adapter';
import { initializeMockApp } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
Expand Down
Loading