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:
Ashish Gupta 2023-07-24 14:27:01 +05:30 committed by GitHub
parent 19e70d4ca6
commit 4a8f19a275
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 130 additions and 330 deletions

View File

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

View File

@ -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();
});
}

View File

@ -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)

View File

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

View File

@ -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([]),

View File

@ -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([]),

View File

@ -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">

View File

@ -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();

View File

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

View File

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

View File

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

View File

@ -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}

View File

@ -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}

View File

@ -18,4 +18,5 @@ export type TagsV1Props = {
tag: TagLabel;
startWith: TAG_START_WITH;
showOnlyName?: boolean;
className?: string;
};

View File

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

View File

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

View File

@ -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>
);
};

View File

@ -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>);
});

View File

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

View File

@ -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 {

View File

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