mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-08 16:38:04 +00:00
ui(fix): supported ellipses in tags and remove old componet (#12525)
* supported ellipses in tags and remove old componnet * fix unit test * support tags to take entire width as per content * chanegs as per comments * fix cypress issue * fix cypress issue
This commit is contained in:
parent
19e70d4ca6
commit
4a8f19a275
@ -541,7 +541,7 @@ export const addNewTagToEntity = (entityObj, term) => {
|
||||
);
|
||||
cy.wait(500);
|
||||
cy.get(
|
||||
'[data-testid="Classification-tags-0"] [data-testid="entity-tags"] [data-testid="add-tag"]'
|
||||
'[data-testid="classification-tags-0"] [data-testid="entity-tags"] [data-testid="add-tag"]'
|
||||
)
|
||||
.eq(0)
|
||||
.should('be.visible')
|
||||
@ -559,7 +559,7 @@ export const addNewTagToEntity = (entityObj, term) => {
|
||||
.scrollIntoView()
|
||||
.should('be.visible')
|
||||
.click();
|
||||
cy.get('[data-testid="Classification-tags-0"] [data-testid="tags-container"]')
|
||||
cy.get('[data-testid="classification-tags-0"] [data-testid="tags-container"]')
|
||||
.scrollIntoView()
|
||||
.contains(name)
|
||||
.should('exist');
|
||||
|
@ -40,7 +40,7 @@ const checkTags = (tag, checkForParentEntity) => {
|
||||
.contains(tag);
|
||||
} else {
|
||||
cy.get(
|
||||
'[data-testid="Classification-tags-0"] [data-testid="tags-container"] [data-testid="entity-tags"] '
|
||||
'[data-testid="classification-tags-0"] [data-testid="tags-container"] [data-testid="entity-tags"] '
|
||||
)
|
||||
.scrollIntoView()
|
||||
.contains(tag);
|
||||
@ -65,7 +65,7 @@ const removeTags = (checkForParentEntity) => {
|
||||
.should('be.visible')
|
||||
.click();
|
||||
} else {
|
||||
cy.get('[data-testid="Classification-tags-0"] [data-testid="edit-button"]')
|
||||
cy.get('[data-testid="classification-tags-0"] [data-testid="edit-button"]')
|
||||
.scrollIntoView()
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
@ -130,24 +130,24 @@ describe('Check if tags addition and removal flow working properly from tables',
|
||||
|
||||
if (entityDetails.entity === 'mlmodels') {
|
||||
cy.get(
|
||||
`[data-testid="feature-card-${entityDetails.fieldName}"] [data-testid="Classification-tags-0"]`
|
||||
`[data-testid="feature-card-${entityDetails.fieldName}"] [data-testid="classification-tags-0"]`
|
||||
).then(($container) => {
|
||||
if ($container.find('[data-testid="add-tag"]').length === 0) {
|
||||
removeTags(false);
|
||||
}
|
||||
cy.get(
|
||||
`[data-testid="feature-card-${entityDetails.fieldName}"] [data-testid="Classification-tags-0"] [data-testid="add-tag"]`
|
||||
`[data-testid="feature-card-${entityDetails.fieldName}"] [data-testid="classification-tags-0"] [data-testid="add-tag"]`
|
||||
).click();
|
||||
});
|
||||
} else {
|
||||
cy.get(
|
||||
'.ant-table-tbody [data-testid="Classification-tags-0"] [data-testid="tags-container"]'
|
||||
'.ant-table-tbody [data-testid="classification-tags-0"] [data-testid="tags-container"]'
|
||||
).then(($container) => {
|
||||
if ($container.find('[data-testid="add-tag"]').length === 0) {
|
||||
removeTags(false);
|
||||
}
|
||||
cy.get(
|
||||
'.ant-table-tbody [data-testid="Classification-tags-0"] [data-testid="tags-container"] [data-testid="add-tag"]'
|
||||
'.ant-table-tbody [data-testid="classification-tags-0"] [data-testid="tags-container"] [data-testid="add-tag"]'
|
||||
).click();
|
||||
});
|
||||
}
|
||||
|
@ -667,7 +667,7 @@ describe('Glossary page should work properly', () => {
|
||||
|
||||
// Add glossary tag to entity for mutually exclusive
|
||||
cy.get(
|
||||
'[data-testid="entity-right-panel"] [data-testid="glossary-container"] > [data-testid="entity-tags"]'
|
||||
'[data-testid="entity-right-panel"] [data-testid="glossary-container"] > [data-testid="entity-tags"] [data-testid="add-tag"]'
|
||||
).click();
|
||||
// Select 1st term
|
||||
cy.get('[data-testid="tag-selector"]').click().type(term1);
|
||||
@ -691,7 +691,7 @@ describe('Glossary page should work properly', () => {
|
||||
|
||||
// Add non mutually exclusive tags
|
||||
cy.get(
|
||||
'[data-testid="entity-right-panel"] [data-testid="glossary-container"] > [data-testid="entity-tags"]'
|
||||
'[data-testid="entity-right-panel"] [data-testid="glossary-container"] > [data-testid="entity-tags"] [data-testid="add-tag"]'
|
||||
).click();
|
||||
|
||||
// Select 1st term
|
||||
@ -714,7 +714,7 @@ describe('Glossary page should work properly', () => {
|
||||
|
||||
// Add tag to schema table
|
||||
const firstColumn =
|
||||
'[data-testid="Glossary-tags-0"] > [data-testid="tags-wrapper"] > [data-testid="glossary-container"] > [data-testid="entity-tags"]';
|
||||
'[data-testid="glossary-tags-0"] > [data-testid="tags-wrapper"] > [data-testid="glossary-container"] > [data-testid="entity-tags"] [data-testid="add-tag"]';
|
||||
cy.get(firstColumn).scrollIntoView();
|
||||
cy.get(firstColumn).click();
|
||||
|
||||
@ -729,7 +729,7 @@ describe('Glossary page should work properly', () => {
|
||||
cy.get('[data-testid="saveAssociatedTag"]').scrollIntoView().click();
|
||||
verifyResponseStatusCode('@countTag', 200);
|
||||
cy.get(
|
||||
'[data-testid="Glossary-tags-0"] > [data-testid="tags-wrapper"] > [data-testid="glossary-container"]'
|
||||
'[data-testid="glossary-tags-0"] > [data-testid="tags-wrapper"] > [data-testid="glossary-container"]'
|
||||
)
|
||||
.scrollIntoView()
|
||||
.should('contain', term3);
|
||||
@ -785,7 +785,7 @@ describe('Glossary page should work properly', () => {
|
||||
interceptURL('PATCH', '/api/v1/tables/*', 'removeSchemaTags');
|
||||
|
||||
cy.get(
|
||||
'[data-testid="Glossary-tags-0"] > [data-testid="tags-wrapper"] > [data-testid="glossary-container"]'
|
||||
'[data-testid="glossary-tags-0"] > [data-testid="tags-wrapper"] > [data-testid="glossary-container"]'
|
||||
)
|
||||
.scrollIntoView()
|
||||
.trigger('mouseover')
|
||||
@ -800,7 +800,7 @@ describe('Glossary page should work properly', () => {
|
||||
verifyResponseStatusCode('@removeSchemaTags', 200);
|
||||
|
||||
cy.get(
|
||||
'[data-testid="Glossary-tags-0"] > [data-testid="tags-wrapper"] > [data-testid="glossary-container"]'
|
||||
'[data-testid="glossary-tags-0"] > [data-testid="tags-wrapper"] > [data-testid="glossary-container"]'
|
||||
)
|
||||
.scrollIntoView()
|
||||
.should('not.contain', name)
|
||||
|
@ -71,7 +71,9 @@ export const ExtraInfoLabel = ({
|
||||
<>
|
||||
<Divider className="self-center m-x-sm" type="vertical" />
|
||||
<Typography.Text className="self-center text-xs whitespace-nowrap">
|
||||
<span className="text-grey-muted">{`${label}: `}</span>
|
||||
{!isEmpty(label) && (
|
||||
<span className="text-grey-muted">{`${label}: `}</span>
|
||||
)}
|
||||
<span className="font-medium">{value}</span>
|
||||
</Typography.Text>
|
||||
</>
|
||||
|
@ -140,10 +140,6 @@ jest.mock('../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor', () => ({
|
||||
.mockReturnValue(<p> ModalWithMarkdownEditor</p>),
|
||||
}));
|
||||
|
||||
jest.mock('components/Tag/Tags/tags', () => {
|
||||
return jest.fn().mockImplementation(({ tag }) => <span>{tag.tagFQN}</span>);
|
||||
});
|
||||
|
||||
jest.mock('utils/TableUtils', () => ({
|
||||
getAllTagsList: jest.fn().mockImplementation(() => Promise.resolve([])),
|
||||
getTagsHierarchy: jest.fn().mockReturnValue([]),
|
||||
|
@ -107,14 +107,6 @@ jest.mock(
|
||||
}
|
||||
);
|
||||
|
||||
jest.mock('components/Tag/TagsViewer/tags-viewer', () => {
|
||||
return jest.fn().mockReturnValue(<p>TagViewer</p>);
|
||||
});
|
||||
|
||||
jest.mock('components/Tag/Tags/tags', () => {
|
||||
return jest.fn().mockReturnValue(<p>Tag</p>);
|
||||
});
|
||||
|
||||
jest.mock('../../utils/TagsUtils', () => ({
|
||||
getAllTagsList: jest.fn(() => Promise.resolve([])),
|
||||
getTagsHierarchy: jest.fn().mockReturnValue([]),
|
||||
|
@ -14,6 +14,7 @@
|
||||
import classNames from 'classnames';
|
||||
import TagsContainerV2 from 'components/Tag/TagsContainerV2/TagsContainerV2';
|
||||
import { EntityField } from 'constants/Feeds.constants';
|
||||
import { lowerCase } from 'lodash';
|
||||
import EntityTasks from 'pages/TasksPage/EntityTasks/EntityTasks.component';
|
||||
import React from 'react';
|
||||
import { TableTagsComponentProps, TableUnion } from './TableTags.interface';
|
||||
@ -33,7 +34,9 @@ const TableTags = <T extends TableUnion>({
|
||||
entityType,
|
||||
}: TableTagsComponentProps<T>) => {
|
||||
return (
|
||||
<div className="hover-icon-group" data-testid={`${type}-tags-${index}`}>
|
||||
<div
|
||||
className="hover-icon-group"
|
||||
data-testid={`${lowerCase(type)}-tags-${index}`}>
|
||||
<div
|
||||
className={classNames('d-flex justify-content flex-col items-start')}
|
||||
data-testid="tags-wrapper">
|
||||
|
@ -106,7 +106,7 @@ describe('Test EntityTableTags Component', () => {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
|
||||
const tagContainer = await screen.findByTestId('Classification-tags-0');
|
||||
const tagContainer = await screen.findByTestId('classification-tags-0');
|
||||
|
||||
expect(tagContainer).toBeInTheDocument();
|
||||
});
|
||||
@ -127,7 +127,7 @@ describe('Test EntityTableTags Component', () => {
|
||||
}
|
||||
);
|
||||
|
||||
const tagContainer = await screen.findByTestId('Classification-tags-0');
|
||||
const tagContainer = await screen.findByTestId('classification-tags-0');
|
||||
|
||||
expect(tagContainer).toBeInTheDocument();
|
||||
});
|
||||
@ -147,7 +147,7 @@ describe('Test EntityTableTags Component', () => {
|
||||
}
|
||||
);
|
||||
|
||||
const tagContainer = await screen.findByTestId('Classification-tags-0');
|
||||
const tagContainer = await screen.findByTestId('classification-tags-0');
|
||||
const tagPersonal = await screen.findByTestId('tag-PersonalData.Personal');
|
||||
|
||||
expect(tagContainer).toBeInTheDocument();
|
||||
@ -170,7 +170,7 @@ describe('Test EntityTableTags Component', () => {
|
||||
}
|
||||
);
|
||||
|
||||
const tagContainer = await screen.findByTestId('Classification-tags-0');
|
||||
const tagContainer = await screen.findByTestId('classification-tags-0');
|
||||
const entityTasks = screen.queryByText('EntityTasks');
|
||||
|
||||
expect(tagContainer).toBeInTheDocument();
|
||||
@ -193,7 +193,7 @@ describe('Test EntityTableTags Component', () => {
|
||||
}
|
||||
);
|
||||
|
||||
const tagContainer = await screen.findByTestId('Classification-tags-0');
|
||||
const tagContainer = await screen.findByTestId('classification-tags-0');
|
||||
const entityTasks = screen.queryByText('EntityTasks');
|
||||
|
||||
expect(tagContainer).toBeInTheDocument();
|
||||
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 url('../../../styles/variables.less');
|
||||
|
||||
.tags-component-container {
|
||||
.tag-container-style {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
justify-content: center;
|
||||
padding: 1px 8px;
|
||||
margin: 0 4px 1px 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.outlined {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
.plus-more-tag.ant-tag {
|
||||
color: @link-color;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* 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 { TAG_START_WITH } from 'constants/Tag.constants';
|
||||
import { TagLabel } from '../../../generated/type/tagLabel';
|
||||
|
||||
export type TagProps = {
|
||||
className?: string;
|
||||
editable?: boolean;
|
||||
type?: 'contained' | 'outlined' | 'label' | 'border';
|
||||
startWith?: TAG_START_WITH;
|
||||
tag: TagLabel;
|
||||
showOnlyName?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
};
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
* 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 { Tag, Tooltip, Typography } from 'antd';
|
||||
import { ReactComponent as IconTag } from 'assets/svg/classification.svg';
|
||||
import classNames from 'classnames';
|
||||
import { FQN_SEPARATOR_CHAR } from 'constants/char.constants';
|
||||
import { ROUTES } from 'constants/constants';
|
||||
import { TagSource } from 'generated/type/tagLabel';
|
||||
import React, { FunctionComponent, useMemo } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { getTagDisplay, getTagTooltip } from 'utils/TagsUtils';
|
||||
import { ReactComponent as IconPage } from '../../../assets/svg/ic-flat-doc.svg';
|
||||
import { ReactComponent as PlusIcon } from '../../../assets/svg/plus-primary.svg';
|
||||
|
||||
import { TAG_START_WITH } from 'constants/Tag.constants';
|
||||
import { TagProps } from './tags.interface';
|
||||
import './Tags.less';
|
||||
|
||||
const Tags: FunctionComponent<TagProps> = ({
|
||||
className,
|
||||
editable,
|
||||
tag,
|
||||
startWith,
|
||||
type = 'contained',
|
||||
showOnlyName = false,
|
||||
|
||||
style,
|
||||
}: TagProps) => {
|
||||
const history = useHistory();
|
||||
|
||||
const isGlossaryTag = useMemo(
|
||||
() => tag.source === TagSource.Glossary,
|
||||
[tag.source]
|
||||
);
|
||||
|
||||
const startIcon = useMemo(() => {
|
||||
switch (startWith) {
|
||||
case TAG_START_WITH.PLUS:
|
||||
return (
|
||||
<PlusIcon
|
||||
className="flex-shrink"
|
||||
height={16}
|
||||
name="plus"
|
||||
width={16}
|
||||
/>
|
||||
);
|
||||
case TAG_START_WITH.SOURCE_ICON:
|
||||
return isGlossaryTag ? (
|
||||
<IconPage
|
||||
className="flex-shrink"
|
||||
data-testid="glossary-icon"
|
||||
height={12}
|
||||
name="glossary-icon"
|
||||
width={12}
|
||||
/>
|
||||
) : (
|
||||
<IconTag
|
||||
className="flex-shrink"
|
||||
data-testid="tags-icon"
|
||||
height={12}
|
||||
name="tag-icon"
|
||||
width={12}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return startWith;
|
||||
}
|
||||
}, [startWith, isGlossaryTag]);
|
||||
|
||||
const tagChip = useMemo(() => {
|
||||
const tagName = showOnlyName
|
||||
? tag.tagFQN.split(FQN_SEPARATOR_CHAR).slice(-2).join(FQN_SEPARATOR_CHAR)
|
||||
: tag.tagFQN;
|
||||
|
||||
return (
|
||||
<Tag
|
||||
className={classNames('tag-container-style', type, className)}
|
||||
data-testid="tags"
|
||||
icon={startIcon}
|
||||
style={style}
|
||||
onClick={() => {
|
||||
if (tag.source && startWith !== TAG_START_WITH.PLUS) {
|
||||
tag.source === TagSource.Glossary
|
||||
? history.push(
|
||||
`${ROUTES.GLOSSARY}/${encodeURIComponent(tag.tagFQN)}`
|
||||
)
|
||||
: history.push(`${ROUTES.TAGS}/${tag.tagFQN.split('.')[0]}`);
|
||||
}
|
||||
}}>
|
||||
<Typography.Paragraph
|
||||
className="m-0"
|
||||
data-testid={
|
||||
startWith === TAG_START_WITH.PLUS ? 'add-tag' : `tag-${tag.tagFQN}`
|
||||
}
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
whiteSpace: 'normal',
|
||||
wordBreak: 'break-all',
|
||||
color: 'inherit',
|
||||
}}>
|
||||
{getTagDisplay(tagName)}
|
||||
</Typography.Paragraph>
|
||||
</Tag>
|
||||
);
|
||||
}, [startIcon, tag, editable]);
|
||||
|
||||
return (
|
||||
<div className="tags-component-container">
|
||||
{startWith === TAG_START_WITH.PLUS ? (
|
||||
tagChip
|
||||
) : (
|
||||
<Tooltip
|
||||
className="cursor-pointer"
|
||||
mouseEnterDelay={1.5}
|
||||
placement="bottomLeft"
|
||||
title={getTagTooltip(tag.tagFQN, tag.description)}
|
||||
trigger="hover">
|
||||
{tagChip}
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tags;
|
@ -155,20 +155,22 @@ const TagsContainerV2 = ({
|
||||
const addTagButton = useMemo(
|
||||
() =>
|
||||
showAddTagButton ? (
|
||||
<span onClick={handleAddClick}>
|
||||
<Col onClick={handleAddClick}>
|
||||
<TagsV1 startWith={TAG_START_WITH.PLUS} tag={TAG_CONSTANT} />
|
||||
</span>
|
||||
</Col>
|
||||
) : null,
|
||||
[showAddTagButton]
|
||||
);
|
||||
|
||||
const renderTags = useMemo(
|
||||
() => (
|
||||
<TagsViewer
|
||||
showNoDataPlaceholder={showNoDataPlaceholder}
|
||||
tags={tags?.[tagType] ?? []}
|
||||
type="border"
|
||||
/>
|
||||
<Col>
|
||||
<TagsViewer
|
||||
showNoDataPlaceholder={showNoDataPlaceholder}
|
||||
tags={tags?.[tagType] ?? []}
|
||||
type="border"
|
||||
/>
|
||||
</Col>
|
||||
),
|
||||
[showNoDataPlaceholder, tags?.[tagType]]
|
||||
);
|
||||
@ -329,11 +331,11 @@ const TagsContainerV2 = ({
|
||||
{header}
|
||||
|
||||
{!isEditTags && (
|
||||
<Space wrap data-testid="entity-tags" size={4}>
|
||||
<Row data-testid="entity-tags">
|
||||
{addTagButton}
|
||||
{renderTags}
|
||||
{showInlineEditButton && editTagButton}
|
||||
</Space>
|
||||
{showInlineEditButton && <Col>{editTagButton}</Col>}
|
||||
</Row>
|
||||
)}
|
||||
{isEditTags && tagsSelectContainer}
|
||||
|
||||
|
@ -29,7 +29,12 @@ import './tagsV1.less';
|
||||
|
||||
const color = '';
|
||||
|
||||
const TagsV1 = ({ tag, startWith, showOnlyName = false }: TagsV1Props) => {
|
||||
const TagsV1 = ({
|
||||
tag,
|
||||
startWith,
|
||||
className,
|
||||
showOnlyName = false,
|
||||
}: TagsV1Props) => {
|
||||
const history = useHistory();
|
||||
|
||||
const isGlossaryTag = useMemo(
|
||||
@ -88,16 +93,17 @@ const TagsV1 = ({ tag, startWith, showOnlyName = false }: TagsV1Props) => {
|
||||
|
||||
const tagContent = useMemo(
|
||||
() => (
|
||||
<div className="d-flex">
|
||||
<div className="d-flex w-full">
|
||||
{tagColorBar}
|
||||
<span className="d-flex items-center p-x-xs">
|
||||
<div className="d-flex items-center p-x-xs w-full">
|
||||
<span className="m-r-xss">{startIcon}</span>
|
||||
<Typography.Paragraph
|
||||
ellipsis
|
||||
className="m-0 tags-label"
|
||||
data-testid={`tag-${tag.tagFQN}`}>
|
||||
{getTagDisplay(tagName)}
|
||||
</Typography.Paragraph>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
[startIcon, tagName, tag.tagFQN, tagColorBar]
|
||||
@ -106,14 +112,14 @@ const TagsV1 = ({ tag, startWith, showOnlyName = false }: TagsV1Props) => {
|
||||
const tagChip = useMemo(
|
||||
() => (
|
||||
<Tag
|
||||
className={classNames('tag-chip tag-chip-content')}
|
||||
className={classNames(className, 'tag-chip tag-chip-content')}
|
||||
data-testid="tags"
|
||||
style={{ backgroundColor: reduceColorOpacity(color, 0.1) }}
|
||||
onClick={() => redirectLink()}>
|
||||
{tagContent}
|
||||
</Tag>
|
||||
),
|
||||
[color, tagContent]
|
||||
[color, tagContent, className]
|
||||
);
|
||||
|
||||
const addTagChip = useMemo(
|
||||
@ -131,9 +137,11 @@ const TagsV1 = ({ tag, startWith, showOnlyName = false }: TagsV1Props) => {
|
||||
[tagName]
|
||||
);
|
||||
|
||||
return startWith === TAG_START_WITH.PLUS ? (
|
||||
addTagChip
|
||||
) : (
|
||||
if (startWith === TAG_START_WITH.PLUS) {
|
||||
return addTagChip;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
className="cursor-pointer"
|
||||
mouseEnterDelay={1.5}
|
||||
|
@ -18,4 +18,5 @@ export type TagsV1Props = {
|
||||
tag: TagLabel;
|
||||
startWith: TAG_START_WITH;
|
||||
showOnlyName?: boolean;
|
||||
className?: string;
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 Collate.
|
||||
* Copyright 2023 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
|
||||
@ -11,57 +11,58 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
fireEvent,
|
||||
getByTestId,
|
||||
queryByTestId,
|
||||
render,
|
||||
} from '@testing-library/react';
|
||||
import { fireEvent, getByTestId, render } from '@testing-library/react';
|
||||
import { TAG_CONSTANT, TAG_START_WITH } from 'constants/Tag.constants';
|
||||
import { LabelType, State, TagSource } from 'generated/type/tagLabel';
|
||||
import React from 'react';
|
||||
import Tags from './tags';
|
||||
import TagsV1 from './TagsV1.component';
|
||||
|
||||
const mockPush = jest.fn();
|
||||
|
||||
jest.mock('components/common/rich-text-editor/RichTextEditorPreviewer', () => {
|
||||
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
||||
});
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
useHistory: jest.fn().mockImplementation(() => ({
|
||||
push: mockPush,
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/TagsUtils', () => ({
|
||||
getTagDisplay: jest.fn().mockReturnValue('tags'),
|
||||
getTagTooltip: jest.fn().mockReturnValue(<p>ToolTip Data</p>),
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/CommonUtils', () => ({
|
||||
reduceColorOpacity: jest.fn().mockReturnValue('#00000'),
|
||||
}));
|
||||
|
||||
describe('Test tags Component', () => {
|
||||
it('Component should render', () => {
|
||||
const { container } = render(
|
||||
<Tags editable tag={{ ...TAG_CONSTANT, tagFQN: 'test' }} />
|
||||
<TagsV1
|
||||
startWith={TAG_START_WITH.SOURCE_ICON}
|
||||
tag={{ ...TAG_CONSTANT, tagFQN: 'test' }}
|
||||
/>
|
||||
);
|
||||
const tags = getByTestId(container, 'tags');
|
||||
|
||||
expect(tags).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Component should render properly for add tag button', () => {
|
||||
it('Component should render add tag button', () => {
|
||||
const { container } = render(
|
||||
<Tags
|
||||
<TagsV1
|
||||
startWith={TAG_START_WITH.PLUS}
|
||||
tag={{ ...TAG_CONSTANT, tagFQN: 'add tag' }}
|
||||
/>
|
||||
);
|
||||
const tags = getByTestId(container, 'tags');
|
||||
const remove = queryByTestId(container, 'remove-test-tag');
|
||||
const addTags = getByTestId(container, 'add-tag');
|
||||
|
||||
expect(tags).toBeInTheDocument();
|
||||
expect(remove).toBeNull();
|
||||
expect(addTags).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Clicking on tag with source Classification should redirect to the proper Classification page', () => {
|
||||
const { container } = render(
|
||||
<Tags
|
||||
editable
|
||||
<TagsV1
|
||||
startWith={TAG_START_WITH.SOURCE_ICON}
|
||||
tag={{
|
||||
labelType: LabelType.Manual,
|
||||
source: TagSource.Classification,
|
||||
@ -80,8 +81,8 @@ describe('Test tags Component', () => {
|
||||
|
||||
it('Clicking on tag with source Glossary should redirect to the proper glossary term page', () => {
|
||||
const { container } = render(
|
||||
<Tags
|
||||
editable
|
||||
<TagsV1
|
||||
startWith={TAG_START_WITH.SOURCE_ICON}
|
||||
tag={{
|
||||
description: 'TestDescription',
|
||||
labelType: LabelType.Manual,
|
@ -14,6 +14,8 @@
|
||||
@import url('../../../styles/variables.less');
|
||||
|
||||
.tag-chip {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
@ -26,10 +28,15 @@
|
||||
}
|
||||
|
||||
.tag-chip-content {
|
||||
width: max-content;
|
||||
margin: 0 5px 4px 0;
|
||||
border: none;
|
||||
padding: 0;
|
||||
background: rgba(0, 0, 0, 0.03);
|
||||
background: @tag-background-color;
|
||||
|
||||
&.diff-added {
|
||||
background: @success-background-color;
|
||||
}
|
||||
}
|
||||
|
||||
.tag-chip-add-button {
|
||||
@ -40,14 +47,13 @@
|
||||
.tag-color-bar {
|
||||
width: 5px;
|
||||
height: auto;
|
||||
background: rgba(0, 0, 0, 0.03);
|
||||
background: @tag-background-color;
|
||||
}
|
||||
|
||||
.tags-label {
|
||||
display: inline-block;
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 30px;
|
||||
color: inherit;
|
||||
}
|
||||
|
@ -11,15 +11,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Popover, Space, Tag, Typography } from 'antd';
|
||||
import { Popover, Tag, Typography } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import Tags from 'components/Tag/Tags/tags';
|
||||
import { TAG_START_WITH } from 'constants/Tag.constants';
|
||||
import { isEmpty, sortBy, uniqBy } from 'lodash';
|
||||
import { EntityTags } from 'Models';
|
||||
import React, { FunctionComponent, useCallback, useMemo } from 'react';
|
||||
import { LIST_SIZE, NO_DATA_PLACEHOLDER } from '../../../constants/constants';
|
||||
import { TagSource } from '../../../generated/type/tagLabel';
|
||||
import TagsV1 from '../TagsV1/TagsV1.component';
|
||||
import { TagsViewerProps } from './tags-viewer.interface';
|
||||
import './tags-viewer.less';
|
||||
|
||||
@ -29,14 +29,9 @@ const TagsViewer: FunctionComponent<TagsViewerProps> = ({
|
||||
type = 'label',
|
||||
showNoDataPlaceholder = true,
|
||||
}: TagsViewerProps) => {
|
||||
const tagChipStye = {
|
||||
margin: '0 0 8px 0',
|
||||
justifyContent: 'start',
|
||||
};
|
||||
|
||||
const getTagsElement = useCallback(
|
||||
(tag: EntityTags, index: number, style?: React.CSSProperties) => (
|
||||
<Tags
|
||||
(tag: EntityTags, index: number) => (
|
||||
<TagsV1
|
||||
className={classNames(
|
||||
{ 'diff-added tw-mx-1': tag?.added },
|
||||
{ 'diff-removed': tag?.removed }
|
||||
@ -44,9 +39,7 @@ const TagsViewer: FunctionComponent<TagsViewerProps> = ({
|
||||
key={index}
|
||||
showOnlyName={tag.source === TagSource.Glossary}
|
||||
startWith={TAG_START_WITH.SOURCE_ICON}
|
||||
style={style}
|
||||
tag={tag}
|
||||
type={type}
|
||||
/>
|
||||
),
|
||||
[type]
|
||||
@ -58,17 +51,19 @@ const TagsViewer: FunctionComponent<TagsViewerProps> = ({
|
||||
[tags]
|
||||
);
|
||||
|
||||
if (isEmpty(sortedTagsBySource) && showNoDataPlaceholder) {
|
||||
return (
|
||||
<Typography.Text className="text-grey-muted m-r-xss">
|
||||
{NO_DATA_PLACEHOLDER}
|
||||
</Typography.Text>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Space wrap size={4}>
|
||||
{isEmpty(sortedTagsBySource) && showNoDataPlaceholder ? (
|
||||
<Typography.Text className="text-grey-muted m-r-xss">
|
||||
{NO_DATA_PLACEHOLDER}
|
||||
</Typography.Text>
|
||||
) : sizeCap > -1 ? (
|
||||
<div>
|
||||
{sizeCap > -1 ? (
|
||||
<>
|
||||
{sortedTagsBySource
|
||||
.slice(0, sizeCap)
|
||||
.map((tag, index) => getTagsElement(tag, index))}
|
||||
{sortedTagsBySource.slice(0, sizeCap).map(getTagsElement)}
|
||||
|
||||
{sortedTagsBySource.slice(sizeCap).length > 0 && (
|
||||
<Popover
|
||||
@ -76,7 +71,7 @@ const TagsViewer: FunctionComponent<TagsViewerProps> = ({
|
||||
<>
|
||||
{sortedTagsBySource.slice(sizeCap).map((tag, index) => (
|
||||
<p className="text-left" key={index}>
|
||||
{getTagsElement(tag, index, tagChipStye)}
|
||||
{getTagsElement(tag, index)}
|
||||
</p>
|
||||
))}
|
||||
</>
|
||||
@ -93,11 +88,9 @@ const TagsViewer: FunctionComponent<TagsViewerProps> = ({
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{sortedTagsBySource.map((tag, index) => getTagsElement(tag, index))}
|
||||
</>
|
||||
sortedTagsBySource.map(getTagsElement)
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -95,10 +95,6 @@ jest.mock('components/Tag/TagsContainerV2/TagsContainerV2', () => {
|
||||
return jest.fn().mockReturnValue(<p>TagsContainerV2</p>);
|
||||
});
|
||||
|
||||
jest.mock('components/Tag/Tags/tags', () => {
|
||||
return jest.fn().mockReturnValue(<p>Tags</p>);
|
||||
});
|
||||
|
||||
jest.mock('../FeedEditor/FeedEditor', () => {
|
||||
return jest.fn().mockReturnValue(<p>FeedEditor</p>);
|
||||
});
|
||||
|
@ -476,3 +476,21 @@ a[href].link-text-grey,
|
||||
height: @entity-details-tab-height;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
/* Diff style */
|
||||
|
||||
.diff-added {
|
||||
background: @success-background-color;
|
||||
color: @success-color;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.diff-removed {
|
||||
color: grey;
|
||||
text-decoration: line-through;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.diff-description {
|
||||
color: @success-color;
|
||||
}
|
||||
|
@ -705,23 +705,6 @@ body .list-option.rdw-option-active {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Diff style */
|
||||
|
||||
.diff-added {
|
||||
background: rgba(0, 131, 118, 0.2);
|
||||
color: #008376;
|
||||
width: fit-content;
|
||||
}
|
||||
.diff-removed {
|
||||
color: #008376;
|
||||
color: grey;
|
||||
text-decoration: line-through;
|
||||
width: fit-content;
|
||||
}
|
||||
.diff-description {
|
||||
color: #008376;
|
||||
}
|
||||
|
||||
/* react-slick */
|
||||
|
||||
.slick-dots {
|
||||
|
@ -78,6 +78,8 @@
|
||||
@grey-bg-with-alpha: #7575751a;
|
||||
@btn-shadow: none;
|
||||
@user-profile-background: rgba(9, 80, 197, 0.05);
|
||||
@success-background-color: rgba(0, 131, 118, 0.2);
|
||||
@tag-background-color: rgba(0, 0, 0, 0.03);
|
||||
|
||||
@navbar-height: 64px;
|
||||
@sidebar-width: 60px;
|
||||
|
Loading…
x
Reference in New Issue
Block a user