mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-27 09:55:36 +00:00
UI : Fix the Classifications Count issue (#9744)
* Fix the Tags Count * minor changes * added unit test for left panel count
This commit is contained in:
parent
1e731856e8
commit
25ef20fe16
@ -225,7 +225,7 @@ const SelectTestSuite: React.FC<SelectTestSuiteProps> = ({
|
|||||||
<SVGIcons
|
<SVGIcons
|
||||||
alt="plus"
|
alt="plus"
|
||||||
className="w-4 m-r-xss"
|
className="w-4 m-r-xss"
|
||||||
icon={Icons.ICON_PLUS_PRIMERY}
|
icon={Icons.ICON_PLUS_PRIMARY}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
onClick={() => setIsNewTestSuite(true)}>
|
onClick={() => setIsNewTestSuite(true)}>
|
||||||
|
@ -323,7 +323,7 @@ const GlossaryV1 = ({
|
|||||||
data-testid="add-glossary"
|
data-testid="add-glossary"
|
||||||
disabled={!createGlossaryPermission}
|
disabled={!createGlossaryPermission}
|
||||||
onClick={handleAddGlossaryClick}>
|
onClick={handleAddGlossaryClick}>
|
||||||
<SVGIcons alt="plus" icon={Icons.ICON_PLUS_PRIMERY} />{' '}
|
<SVGIcons alt="plus" icon={Icons.ICON_PLUS_PRIMARY} />{' '}
|
||||||
<span>{t('label.add-glossary')}</span>
|
<span>{t('label.add-glossary')}</span>
|
||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -54,7 +54,7 @@ const Tags: FunctionComponent<TagProps> = ({
|
|||||||
<SVGIcons
|
<SVGIcons
|
||||||
alt="plus"
|
alt="plus"
|
||||||
className="tw-w-3.5 tw-mr-1"
|
className="tw-w-3.5 tw-mr-1"
|
||||||
icon={Icons.ICON_PLUS_PRIMERY}
|
icon={Icons.ICON_PLUS_PRIMARY}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
startWith
|
startWith
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 Collate.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { LoadingState } from 'Models';
|
||||||
|
|
||||||
|
export type DeleteTagDetailsType = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
categoryName?: string;
|
||||||
|
isCategory: boolean;
|
||||||
|
status?: LoadingState;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DeleteTagsType = {
|
||||||
|
data: DeleteTagDetailsType | undefined;
|
||||||
|
state: boolean;
|
||||||
|
};
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 Collate.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import Loader from 'components/Loader/Loader';
|
||||||
|
import React from 'react';
|
||||||
|
import SVGIcons from 'utils/SvgUtils';
|
||||||
|
import { DeleteTagsType } from './TagsPage.interface';
|
||||||
|
|
||||||
|
export const getDeleteIcon = (
|
||||||
|
deleteTags: DeleteTagsType,
|
||||||
|
id: string | undefined
|
||||||
|
) => {
|
||||||
|
if (deleteTags.data?.id === id) {
|
||||||
|
if (deleteTags.data?.status === 'success') {
|
||||||
|
return <FontAwesomeIcon icon="check" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Loader size="small" type="default" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SVGIcons alt="delete" icon="icon-delete" title="Delete" width="16px" />
|
||||||
|
);
|
||||||
|
};
|
@ -18,6 +18,7 @@ import {
|
|||||||
findByTestId,
|
findByTestId,
|
||||||
findByText,
|
findByText,
|
||||||
fireEvent,
|
fireEvent,
|
||||||
|
getByText,
|
||||||
queryByTitle,
|
queryByTitle,
|
||||||
render,
|
render,
|
||||||
screen,
|
screen,
|
||||||
@ -297,6 +298,27 @@ describe('Test TagsPage page', () => {
|
|||||||
expect(sidePanelCategories).toHaveLength(3);
|
expect(sidePanelCategories).toHaveLength(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Classification LeftPanel count should render properly', async () => {
|
||||||
|
await act(async () => {
|
||||||
|
render(<TagsPage />);
|
||||||
|
});
|
||||||
|
const leftPanelContent = await screen.findByTestId('left-panel-content');
|
||||||
|
const sidePanelCategories = await screen.findAllByTestId(
|
||||||
|
'side-panel-classification'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(leftPanelContent).toBeInTheDocument();
|
||||||
|
expect(sidePanelCategories).toHaveLength(3);
|
||||||
|
|
||||||
|
const getAllCounts = await screen.findAllByTestId('filter-count');
|
||||||
|
|
||||||
|
expect(getAllCounts).toHaveLength(3);
|
||||||
|
|
||||||
|
expect(getByText(getAllCounts[0], '2')).toBeInTheDocument();
|
||||||
|
expect(getByText(getAllCounts[1], '3')).toBeInTheDocument();
|
||||||
|
expect(getByText(getAllCounts[2], '5')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it('OnClick of add new tag, FormModal should display', async () => {
|
it('OnClick of add new tag, FormModal should display', async () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
render(<TagsPage />);
|
render(<TagsPage />);
|
||||||
|
@ -44,7 +44,7 @@ import {
|
|||||||
import TagsLeftPanelSkeleton from 'components/Skeleton/Tags/TagsLeftPanelSkeleton.component';
|
import TagsLeftPanelSkeleton from 'components/Skeleton/Tags/TagsLeftPanelSkeleton.component';
|
||||||
import { compare } from 'fast-json-patch';
|
import { compare } from 'fast-json-patch';
|
||||||
import { isEmpty, isUndefined, toLower, trim } from 'lodash';
|
import { isEmpty, isUndefined, toLower, trim } from 'lodash';
|
||||||
import { FormErrorData, LoadingState } from 'Models';
|
import { FormErrorData } from 'Models';
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Link, useHistory, useParams } from 'react-router-dom';
|
import { Link, useHistory, useParams } from 'react-router-dom';
|
||||||
@ -91,19 +91,8 @@ import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
|||||||
import { showErrorToast } from '../../utils/ToastUtils';
|
import { showErrorToast } from '../../utils/ToastUtils';
|
||||||
import Form from './Form';
|
import Form from './Form';
|
||||||
import './TagPage.style.less';
|
import './TagPage.style.less';
|
||||||
|
import { DeleteTagsType } from './TagsPage.interface';
|
||||||
type DeleteTagDetailsType = {
|
import { getDeleteIcon } from './TagsPageUtils';
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
categoryName?: string;
|
|
||||||
isCategory: boolean;
|
|
||||||
status?: LoadingState;
|
|
||||||
};
|
|
||||||
|
|
||||||
type DeleteTagsType = {
|
|
||||||
data: DeleteTagDetailsType | undefined;
|
|
||||||
state: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const TagsPage = () => {
|
const TagsPage = () => {
|
||||||
const { getEntityPermission, permissions } = usePermissionProvider();
|
const { getEntityPermission, permissions } = usePermissionProvider();
|
||||||
@ -205,7 +194,7 @@ const TagsPage = () => {
|
|||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await getAllClassifications('', 1000);
|
const response = await getAllClassifications('termCount', 1000);
|
||||||
setClassifications(response.data);
|
setClassifications(response.data);
|
||||||
if (setCurrent && response.data.length) {
|
if (setCurrent && response.data.length) {
|
||||||
setCurrentClassification(response.data[0]);
|
setCurrentClassification(response.data[0]);
|
||||||
@ -229,11 +218,23 @@ const TagsPage = () => {
|
|||||||
if (currentClassification?.name !== name || update) {
|
if (currentClassification?.name !== name || update) {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const currentClassification = await getClassificationByName(
|
const currentClassification = await getClassificationByName(name, [
|
||||||
name,
|
'usageCount',
|
||||||
'usageCount'
|
'termCount',
|
||||||
);
|
]);
|
||||||
if (currentClassification) {
|
if (currentClassification) {
|
||||||
|
setClassifications((prevClassifications) =>
|
||||||
|
prevClassifications.map((data) => {
|
||||||
|
if (data.name === name) {
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
termCount: currentClassification.termCount,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
})
|
||||||
|
);
|
||||||
setCurrentClassification(currentClassification);
|
setCurrentClassification(currentClassification);
|
||||||
setCurrentClassificationName(currentClassification.name);
|
setCurrentClassificationName(currentClassification.name);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@ -587,6 +588,8 @@ const TagsPage = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Use the component in the render method
|
||||||
|
|
||||||
const fetchLeftPanel = () => {
|
const fetchLeftPanel = () => {
|
||||||
return (
|
return (
|
||||||
<LeftPanelCard id="tags">
|
<LeftPanelCard id="tags">
|
||||||
@ -613,7 +616,7 @@ const TagsPage = () => {
|
|||||||
setIsAddingClassification((prevState) => !prevState);
|
setIsAddingClassification((prevState) => !prevState);
|
||||||
setErrorDataClassification(undefined);
|
setErrorDataClassification(undefined);
|
||||||
}}>
|
}}>
|
||||||
<SVGIcons alt="plus" icon={Icons.ICON_PLUS_PRIMERY} />{' '}
|
<SVGIcons alt="plus" icon={Icons.ICON_PLUS_PRIMARY} />{' '}
|
||||||
<span>
|
<span>
|
||||||
{t('label.add-entity', {
|
{t('label.add-entity', {
|
||||||
entity: t('label.classification'),
|
entity: t('label.classification'),
|
||||||
@ -641,7 +644,7 @@ const TagsPage = () => {
|
|||||||
{getEntityName(category as unknown as EntityReference)}
|
{getEntityName(category as unknown as EntityReference)}
|
||||||
</Typography.Paragraph>
|
</Typography.Paragraph>
|
||||||
{getCountBadge(
|
{getCountBadge(
|
||||||
0,
|
category.termCount,
|
||||||
'tw-self-center',
|
'tw-self-center',
|
||||||
currentClassification?.name === category.name
|
currentClassification?.name === category.name
|
||||||
)}
|
)}
|
||||||
@ -731,20 +734,7 @@ const TagsPage = () => {
|
|||||||
!classificationPermissions.EditAll
|
!classificationPermissions.EditAll
|
||||||
}
|
}
|
||||||
onClick={() => handleActionDeleteTag(record)}>
|
onClick={() => handleActionDeleteTag(record)}>
|
||||||
{deleteTags.data?.id === record.id ? (
|
{getDeleteIcon(deleteTags, record.id)}
|
||||||
deleteTags.data?.status === 'success' ? (
|
|
||||||
<FontAwesomeIcon icon="check" />
|
|
||||||
) : (
|
|
||||||
<Loader size="small" type="default" />
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<SVGIcons
|
|
||||||
alt="delete"
|
|
||||||
icon="icon-delete"
|
|
||||||
title="Delete"
|
|
||||||
width="16px"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</button>
|
</button>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -22,6 +22,7 @@ export const MOCK_ALL_CLASSIFICATIONS = {
|
|||||||
updatedAt: 1672147362401,
|
updatedAt: 1672147362401,
|
||||||
updatedBy: 'admin',
|
updatedBy: 'admin',
|
||||||
href: 'http://localhost:8585/api/v1/classifications/5e77a82e-4bc8-46eb-af52-a383a505eea6',
|
href: 'http://localhost:8585/api/v1/classifications/5e77a82e-4bc8-46eb-af52-a383a505eea6',
|
||||||
|
termCount: 2,
|
||||||
changeDescription: {
|
changeDescription: {
|
||||||
fieldsAdded: [],
|
fieldsAdded: [],
|
||||||
fieldsUpdated: [
|
fieldsUpdated: [
|
||||||
@ -57,6 +58,7 @@ export const MOCK_ALL_CLASSIFICATIONS = {
|
|||||||
deleted: false,
|
deleted: false,
|
||||||
provider: 'system',
|
provider: 'system',
|
||||||
mutuallyExclusive: true,
|
mutuallyExclusive: true,
|
||||||
|
termCount: 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '9005388e-5355-412c-8ba9-fc6dbe192a45',
|
id: '9005388e-5355-412c-8ba9-fc6dbe192a45',
|
||||||
@ -70,6 +72,7 @@ export const MOCK_ALL_CLASSIFICATIONS = {
|
|||||||
deleted: false,
|
deleted: false,
|
||||||
provider: 'user',
|
provider: 'user',
|
||||||
mutuallyExclusive: false,
|
mutuallyExclusive: false,
|
||||||
|
termCount: 5,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
paging: {
|
paging: {
|
||||||
|
@ -309,7 +309,7 @@ export const Icons = {
|
|||||||
ICON_DEPLOY: 'icon-deploy',
|
ICON_DEPLOY: 'icon-deploy',
|
||||||
TOUR: 'tour',
|
TOUR: 'tour',
|
||||||
ICON_PLUS: 'icon-plus',
|
ICON_PLUS: 'icon-plus',
|
||||||
ICON_PLUS_PRIMERY: 'icon-plus-primary',
|
ICON_PLUS_PRIMARY: 'icon-plus-primary',
|
||||||
ICON_PLUS_PRIMARY_OUTLINED: 'icon-plus-primary-outlined',
|
ICON_PLUS_PRIMARY_OUTLINED: 'icon-plus-primary-outlined',
|
||||||
ICON_MINUS: 'icon-minus',
|
ICON_MINUS: 'icon-minus',
|
||||||
TAG: 'icon-tag',
|
TAG: 'icon-tag',
|
||||||
@ -776,7 +776,7 @@ const SVGIcons: FunctionComponent<Props> = ({ icon, ...props }: Props) => {
|
|||||||
IconComponent = IconPlus;
|
IconComponent = IconPlus;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Icons.ICON_PLUS_PRIMERY:
|
case Icons.ICON_PLUS_PRIMARY:
|
||||||
IconComponent = IconPlusPrimery;
|
IconComponent = IconPlusPrimery;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user