Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Frontend tagging #20876

Merged
merged 90 commits into from
Feb 21, 2023
Merged
Show file tree
Hide file tree
Changes from 89 commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
6289724
CLDN-1440 tagging for 1.5
cccs-nik Jun 2, 2022
f5a36d6
CLDN-1440 package.json
cccs-nik Jun 2, 2022
fa93533
WIP
cccs-nik Jun 23, 2022
8b87403
WIP
cccs-nik Jun 24, 2022
005b506
datasets
cccs-nik Jun 29, 2022
cdb55ed
WIP
cccs-nik Jun 29, 2022
95bf70e
tags in datasets list_columns
cccs-nik Jun 29, 2022
44cef3b
CLDN-1416 Search dashboards, charts, queries tags
cccs-nik Jul 4, 2022
4b93f0a
CLDN-1416 /api/v1/tag WIP
cccs-nik Jul 4, 2022
1f4d0bf
CLDN-1416 Search dataset tags
cccs-nik Jul 4, 2022
9bd55a7
minor fixes for compatability
cccs-RyanK Jul 14, 2022
0030258
added select component for adding new tags
cccs-RyanK Jul 19, 2022
97b4613
changed code for better understandability and function
cccs-RyanK Jul 20, 2022
084e947
aligned edit button vertically
cccs-RyanK Jul 21, 2022
9501669
Merge branch 'master' of github.com:CybercentreCanada/superset into F…
cccs-RyanK Jul 21, 2022
ca2e212
moved tags editing to properties editor in chart explorer
cccs-RyanK Jul 21, 2022
de54aa0
fixes to tags displaying and updating
cccs-RyanK Jul 25, 2022
7b8b95d
added some component tests
cccs-RyanK Jul 25, 2022
1c88ab5
removed dataset tagging for PR
cccs-RyanK Jul 25, 2022
bcfb95a
fixed linting errors
cccs-RyanK Jul 25, 2022
f98a7fa
Merge branch 'master' of github.com:CybercentreCanada/superset into F…
cccs-RyanK Jul 25, 2022
22d5b8d
fixed linting errors
cccs-RyanK Jul 25, 2022
b38dd2b
fixed package json and added feature flags
cccs-RyanK Jul 26, 2022
65c927b
fixed feature flag
cccs-RyanK Jul 27, 2022
1aba266
Merge branch 'master' of github.com:CybercentreCanada/superset into F…
cccs-RyanK Jul 27, 2022
a335a1c
hide tags search filter when feature flag disabled
cccs-RyanK Jul 27, 2022
885c219
added allow new tags in dashboard properties modal
cccs-RyanK Jul 27, 2022
97a1231
added allow new tags in dashboard properties modal
cccs-RyanK Jul 27, 2022
3a2de6a
lint fixes
cccs-RyanK Jul 29, 2022
5a97eb6
added tags api integration tests
cccs-RyanK Aug 2, 2022
aebbf16
removed tags from headers for dashboards and charts
cccs-RyanK Aug 9, 2022
82fd77b
Tags display in multiselect in properties modal
cccs-RyanK Aug 9, 2022
63be030
CRUD tag search is now a select
cccs-RyanK Aug 9, 2022
f794b69
added styles and removed comments
cccs-RyanK Aug 30, 2022
10a5cef
added missing error handling
cccs-RyanK Aug 31, 2022
4f03a3f
changed tags view to all entities view
cccs-RyanK Sep 15, 2022
211d62c
added tags and allentities CRUD views
cccs-RyanK Sep 29, 2022
6436c7a
Merge branch 'master' of github.com:CybercentreCanada/superset into F…
cccs-RyanK Sep 29, 2022
01e1b17
Merge branch 'master' of github.com:CybercentreCanada/superset into F…
cccs-RyanK Oct 3, 2022
abd2499
added TODOs for add/edit/delete tags in CRUD view
cccs-RyanK Oct 5, 2022
9a25ffe
Merge branch 'master' of github.com:CybercentreCanada/superset into F…
cccs-RyanK Dec 1, 2022
fc15648
fixed imports from tags models refactoring
cccs-RyanK Dec 1, 2022
7a2144b
fixed initialization and tag list view
cccs-RyanK Dec 1, 2022
7a5d8f7
lint fixes
cccs-RyanK Dec 2, 2022
06820db
undid acidental changes
cccs-RyanK Dec 2, 2022
347c3d2
pylint errors
cccs-RyanK Dec 2, 2022
8970fba
suggestion fixes and removing unused object tags
cccs-RyanK Dec 5, 2022
74733e5
added TagList stories file
cccs-RyanK Dec 5, 2022
4ca90da
fixed package-lock
cccs-RyanK Dec 6, 2022
2cab6ee
fixed import errors and changed tag crud so they display as antdtags
cccs-RyanK Dec 6, 2022
c4b4fa2
fixed type errors
cccs-RyanK Dec 6, 2022
a060998
fixed api test error
cccs-RyanK Dec 6, 2022
adcde81
fixed frontend tests
cccs-RyanK Dec 6, 2022
6d1bf01
Merge branch 'master' of github.com:CybercentreCanada/superset into F…
cccs-RyanK Dec 6, 2022
14a24ef
fixed unused import
cccs-RyanK Dec 7, 2022
8e00386
fixed feature flag set
cccs-RyanK Dec 7, 2022
56e77dd
Merge branches 'Frontend-Tagging' and 'master' of github.com:Cybercen…
cccs-RyanK Dec 7, 2022
b07343c
feature flag fixes
cccs-RyanK Dec 7, 2022
6d9dca4
fixed pylint error
cccs-RyanK Dec 7, 2022
6ad3653
fixed pylint error v2
cccs-RyanK Dec 7, 2022
b0fb771
removed accidental test fixture error
cccs-RyanK Dec 7, 2022
2093ecc
fixing tagging tests
cccs-RyanK Dec 8, 2022
b2ce91c
Merge branch 'master' of github.com:CybercentreCanada/superset into F…
cccs-RyanK Dec 8, 2022
6311bd2
precommit fixes
cccs-RyanK Dec 8, 2022
0b30e48
feedback changes
cccs-RyanK Dec 13, 2022
66827a5
precommit fixes
cccs-RyanK Dec 13, 2022
74d78a3
added tag name as key and value to avoid duplicating tags in the sele…
cccs-RyanK Dec 20, 2022
24ee63f
Merge branch 'master' of github.com:CybercentreCanada/superset into F…
cccs-RyanK Dec 20, 2022
f7a1b86
Merge branches 'Frontend-Tagging' and 'master' of github.com:Cybercen…
Jan 13, 2023
1897e9f
refactored create tag to create custom tag, changed add tag functions…
Jan 16, 2023
230b3d4
lint fixes
Jan 16, 2023
7bf806f
precommit fixes
Jan 19, 2023
9848d73
Merge branches 'Frontend-Tagging' and 'master' of github.com:Cybercen…
Jan 20, 2023
137d4d6
fixing properties modal tests to not include tags
Jan 20, 2023
e343609
added check for tags heading
Jan 20, 2023
7ca0509
lint fix
Jan 20, 2023
2ebaacc
moved endpoints to api and added test
Feb 1, 2023
f9ff7c9
Merge branch 'master' of github.com:CybercentreCanada/superset into F…
Feb 2, 2023
a8974e7
fixed lint and apispec errors
Feb 2, 2023
ddaa260
fixed lint errors and old tagging tests
Feb 2, 2023
8e157e3
fixed precommit error
Feb 2, 2023
cfa1c6c
fixed pylint error
Feb 2, 2023
2c22fba
fixed pre-commit errors
Feb 3, 2023
27d6b6a
removed unnecessary commit
Feb 3, 2023
f19ee77
fixed api tests and dao tests
Feb 6, 2023
14e2159
fixed precommit error
Feb 6, 2023
ecb02fc
fixed tagging tests for postrges and mysql
Feb 6, 2023
242d26f
Merge branch 'master' of github.com:CybercentreCanada/superset into F…
cccs-RyanK Feb 13, 2023
876cf4d
post merge fixes
cccs-RyanK Feb 13, 2023
c1080fc
small frontend changes
cccs-RyanK Feb 16, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export enum FeatureFlag {
SQL_VALIDATORS_BY_ENGINE = 'SQL_VALIDATORS_BY_ENGINE',
THUMBNAILS = 'THUMBNAILS',
USE_ANALAGOUS_COLORS = 'USE_ANALAGOUS_COLORS',
TAGGING_SYSTEM = 'TAGGING_SYSTEM',
UX_BETA = 'UX_BETA',
VERSIONED_EXPORT = 'VERSIONED_EXPORT',
SSH_TUNNELING = 'SSH_TUNNELING',
Expand Down
3 changes: 3 additions & 0 deletions superset-frontend/src/components/ListView/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,7 @@ export enum FilterOperator {
datasetIsCertified = 'dataset_is_certified',
dashboardHasCreatedBy = 'dashboard_has_created_by',
chartHasCreatedBy = 'chart_has_created_by',
dashboardTags = 'dashboard_tags',
chartTags = 'chart_tags',
savedQueryTags = 'saved_query_tags',
}
35 changes: 35 additions & 0 deletions superset-frontend/src/components/Tags/Tag.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 React from 'react';
import { render } from 'spec/helpers/testing-library';
import TagType from 'src/types/TagType';
import Tag from './Tag';

const mockedProps: TagType = {
name: 'example-tag',
id: 1,
onDelete: undefined,
editable: false,
onClick: undefined,
};

test('should render', () => {
const { container } = render(<Tag {...mockedProps} />);
expect(container).toBeInTheDocument();
});
86 changes: 86 additions & 0 deletions superset-frontend/src/components/Tags/Tag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 { styled } from '@superset-ui/core';
import TagType from 'src/types/TagType';
import AntdTag from 'antd/lib/tag';
import React, { useMemo } from 'react';
import { Tooltip } from 'src/components/Tooltip';

const StyledTag = styled(AntdTag)`
${({ theme }) => `
margin-top: ${theme.gridUnit}px;
margin-bottom: ${theme.gridUnit}px;
font-size: ${theme.typography.sizes.s}px;
`};
`;

const Tag = ({
name,
id,
index = undefined,
onDelete = undefined,
editable = false,
onClick = undefined,
}: TagType) => {
const isLongTag = useMemo(() => name.length > 20, [name]);

const handleClose = () => (index ? onDelete?.(index) : null);

const tagElem = (
<>
{editable ? (
<StyledTag
key={id}
closable={editable}
onClose={handleClose}
color="blue"
>
{isLongTag ? `${name.slice(0, 20)}...` : name}
</StyledTag>
) : (
<StyledTag role="link" key={id} onClick={onClick}>
{id ? (
<a
href={`/superset/tags/?tags=${name}`}
target="_blank"
rel="noreferrer"
>
{isLongTag ? `${name.slice(0, 20)}...` : name}
</a>
) : isLongTag ? (
`${name.slice(0, 20)}...`
) : (
name
)}
</StyledTag>
)}
</>
);

return isLongTag ? (
<Tooltip title={name} key={name}>
{tagElem}
</Tooltip>
) : (
tagElem
);
};

export default Tag;
58 changes: 58 additions & 0 deletions superset-frontend/src/components/Tags/TagsList.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 React from 'react';
import TagType from 'src/types/TagType';
import { TagsList } from '.';
import { TagsListProps } from './TagsList';

export default {
title: 'Tags',
component: TagsList,
};

export const InteractiveTags = ({ tags, editable, maxTags }: TagsListProps) => (
<TagsList tags={tags} editable={editable} maxTags={maxTags} />
);

const tags: TagType[] = [
{ name: 'tag1' },
{ name: 'tag2' },
{ name: 'tag3' },
{ name: 'tag4' },
{ name: 'tag5' },
{ name: 'tag6' },
];

const editable = true;

const maxTags = 3;

InteractiveTags.args = {
tags,
editable,
maxTags,
};

InteractiveTags.story = {
parameters: {
knobs: {
disable: true,
},
},
};
78 changes: 78 additions & 0 deletions superset-frontend/src/components/Tags/TagsList.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 React from 'react';
import { render, waitFor } from 'spec/helpers/testing-library';
import TagsList, { TagsListProps } from './TagsList';

const testTags = [
{
name: 'example-tag1',
id: 1,
},
{
name: 'example-tag2',
id: 2,
},
{
name: 'example-tag3',
id: 3,
},
{
name: 'example-tag4',
id: 4,
},
{
name: 'example-tag5',
id: 5,
},
];

const mockedProps: TagsListProps = {
tags: testTags,
onDelete: undefined,
maxTags: 5,
};

const getElementsByClassName = (className: string) =>
document.querySelectorAll(className)! as NodeListOf<HTMLElement>;

const findAllTags = () => waitFor(() => getElementsByClassName('.ant-tag'));

test('should render', () => {
const { container } = render(<TagsList {...mockedProps} />);
expect(container).toBeInTheDocument();
});

test('should render 5 elements', async () => {
render(<TagsList {...mockedProps} />);
const tagsListItems = await findAllTags();
expect(tagsListItems).toHaveLength(5);
expect(tagsListItems[0]).toHaveTextContent(testTags[0].name);
expect(tagsListItems[1]).toHaveTextContent(testTags[1].name);
expect(tagsListItems[2]).toHaveTextContent(testTags[2].name);
expect(tagsListItems[3]).toHaveTextContent(testTags[3].name);
expect(tagsListItems[4]).toHaveTextContent(testTags[4].name);
});

test('should render 3 elements when maxTags is set to 3', async () => {
render(<TagsList {...mockedProps} maxTags={3} />);
const tagsListItems = await findAllTags();
expect(tagsListItems).toHaveLength(3);
expect(tagsListItems[2]).toHaveTextContent('+3...');
});
112 changes: 112 additions & 0 deletions superset-frontend/src/components/Tags/TagsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 React, { useMemo, useState } from 'react';
import { styled } from '@superset-ui/core';
import TagType from 'src/types/TagType';
import Tag from './Tag';

export type TagsListProps = {
tags: TagType[];
editable?: boolean;
/**
* OnDelete:
* Only applies when editable is true
* Callback for when a tag is deleted
*/
onDelete?: ((index: number) => void) | undefined;
maxTags?: number | undefined;
};

const TagsDiv = styled.div`
max-width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
`;

const TagsList = ({
tags,
editable = false,
onDelete,
maxTags,
}: TagsListProps) => {
const [tempMaxTags, setTempMaxTags] = useState<number | undefined>(maxTags);

const handleDelete = (index: number) => {
onDelete?.(index);
};

const expand = () => setTempMaxTags(undefined);

const collapse = () => setTempMaxTags(maxTags);

const tagsIsLong: boolean | null = useMemo(
() => (tempMaxTags ? tags.length > tempMaxTags : null),
[tags.length, tempMaxTags],
);

const extraTags: number | null = useMemo(
() =>
typeof tempMaxTags === 'number' ? tags.length - tempMaxTags + 1 : null,
[tagsIsLong, tags.length, tempMaxTags],
);

return (
<TagsDiv className="tag-list">
{tagsIsLong && typeof tempMaxTags === 'number' ? (
<>
{tags.slice(0, tempMaxTags - 1).map((tag: TagType, index) => (
<Tag
id={tag.id}
key={tag.id}
name={tag.name}
index={index}
onDelete={handleDelete}
editable={editable}
/>
))}
{tags.length > tempMaxTags ? (
<Tag name={`+${extraTags}...`} onClick={expand} />
) : null}
</>
) : (
<>
{tags.map((tag: TagType, index) => (
<Tag
id={tag.id}
key={tag.id}
name={tag.name}
index={index}
onDelete={handleDelete}
editable={editable}
/>
))}
{maxTags ? (
tags.length > maxTags ? (
<Tag name="..." onClick={collapse} />
) : null
) : null}
</>
)}
</TagsDiv>
);
};

export default TagsList;
Loading