From 85251f8cae6fa2d6a77a73697fb0575cd37c1c92 Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Fri, 29 Sep 2023 22:13:26 -0400 Subject: [PATCH] fix: Tags Page Polish (#25403) Co-authored-by: Lily Kuang --- .../features/allEntities/AllEntitiesTable.tsx | 112 +++++++++++++++--- .../src/pages/AllEntities/index.tsx | 9 +- .../src/pages/DashboardList/index.tsx | 2 +- superset/daos/tag.py | 16 +-- superset/tags/schemas.py | 14 ++- 5 files changed, 116 insertions(+), 37 deletions(-) diff --git a/superset-frontend/src/features/allEntities/AllEntitiesTable.tsx b/superset-frontend/src/features/allEntities/AllEntitiesTable.tsx index 79e1c11ecc..75491c5baa 100644 --- a/superset-frontend/src/features/allEntities/AllEntitiesTable.tsx +++ b/superset-frontend/src/features/allEntities/AllEntitiesTable.tsx @@ -22,18 +22,33 @@ import { t, styled, logging } from '@superset-ui/core'; import TableView, { EmptyWrapperType } from 'src/components/TableView'; import { addDangerToast } from 'src/components/MessageToasts/actions'; import Loading from 'src/components/Loading'; +import { TagsList } from 'src/components/Tags'; +import FacePile from 'src/components/FacePile'; +import Tag from 'src/types/TagType'; +import Owner from 'src/types/Owner'; +import { EmptyStateBig } from 'src/components/EmptyState'; import { fetchObjects } from '../tags/tags'; +const MAX_TAGS_TO_SHOW = 3; + const AllEntitiesTableContainer = styled.div` text-align: left; border-radius: ${({ theme }) => theme.gridUnit * 1}px 0; - margin: 0 ${({ theme }) => theme.gridUnit * 4}px; .table { table-layout: fixed; } .td { width: 33%; } + .entity-title { + font-family: Inter; + font-size: ${({ theme }) => theme.typography.sizes.m}px; + font-weight: ${({ theme }) => theme.typography.weights.medium}; + line-height: 17px; + letter-spacing: 0px; + text-align: left; + margin: ${({ theme }) => theme.gridUnit * 4}px 0; + } `; interface TaggedObject { @@ -44,6 +59,8 @@ interface TaggedObject { changed_on: moment.MomentInput; created_by: number | undefined; creator: string; + owners: Owner[]; + tags: Tag[]; } interface TaggedObjects { @@ -54,10 +71,12 @@ interface TaggedObjects { interface AllEntitiesTableProps { search?: string; + setShowTagModal: (show: boolean) => void; } export default function AllEntitiesTable({ search = '', + setShowTagModal, }: AllEntitiesTableProps) { type objectType = 'dashboard' | 'chart' | 'query'; @@ -66,8 +85,19 @@ export default function AllEntitiesTable({ chart: [], query: [], }); + const [isLoading, setLoading] = useState(true); + const showListViewObjs = + objects.dashboard.length > 0 || + objects.chart.length > 0 || + objects.query.length > 0; useEffect(() => { + if (search === '') { + return; + } + + setLoading(true); + fetchObjects( { tags: search, types: null }, (data: TaggedObject[]) => { @@ -77,6 +107,7 @@ export default function AllEntitiesTable({ objects[object_type].push(object); }); setObjects(objects); + setLoading(false); }, (error: Response) => { addDangerToast('Error Fetching Tagged Objects'); @@ -89,7 +120,10 @@ export default function AllEntitiesTable({ const data = objects[type].map((o: TaggedObject) => ({ [type]: {o.name}, modified: moment.utc(o.changed_on).fromNow(), + tags: o.tags, + owners: o.owners, })); + return ( ( + // Only show custom type tags + + tag.type === 'TagTypes.custom' || tag.type === 1, + )} + maxTags={MAX_TAGS_TO_SHOW} + /> + ), + Header: t('Tags'), + accessor: 'tags', + disableSortBy: true, + }, + { + Cell: ({ + row: { + original: { owners = [] }, + }, + }: any) => , + Header: t('Owners'), + accessor: 'owners', + disableSortBy: true, + size: 'xl', }, - { accessor: 'modified', Header: 'Modified' }, ]} /> ); }; - if (objects) { - return ( - -

{t('Dashboards')}

- {renderTable('dashboard')} -
-

{t('Charts')}

- {renderTable('chart')} -
-

{t('Queries')}

- {renderTable('query')} -
- ); - } - return ; + if (isLoading) return ; + return ( + + {showListViewObjs ? ( + <> +
{t('Dashboards')}
+ {renderTable('dashboard')} +
{t('Charts')}
+ {renderTable('chart')} +
{t('Queries')}
+ {renderTable('query')} + + ) : ( + setShowTagModal(true)} + buttonText={t('Add tag to entities')} + /> + )} +
+ ); } diff --git a/superset-frontend/src/pages/AllEntities/index.tsx b/superset-frontend/src/pages/AllEntities/index.tsx index eaa8e35703..63d5883537 100644 --- a/superset-frontend/src/pages/AllEntities/index.tsx +++ b/superset-frontend/src/pages/AllEntities/index.tsx @@ -57,7 +57,7 @@ const AllEntitiesContainer = styled.div` margin-bottom: ${theme.gridUnit * 1}px; } .entities { - margin: ${theme.gridUnit * 7.5}px; 0px; + margin: ${theme.gridUnit * 6}px; 0px; } `} `; @@ -88,6 +88,7 @@ function AllEntities() { const [tag, setTag] = useState(null); const [showTagModal, setShowTagModal] = useState(false); const { addSuccessToast, addDangerToast } = useToasts(); + const editableTitleProps = { title: tag?.name || '', placeholder: 'testing', @@ -166,10 +167,14 @@ function AllEntities() { menuDropdownProps={{ disabled: true, }} + showMenuDropdown={false} />
- +
); diff --git a/superset-frontend/src/pages/DashboardList/index.tsx b/superset-frontend/src/pages/DashboardList/index.tsx index 29bb51b961..d7760ffbbc 100644 --- a/superset-frontend/src/pages/DashboardList/index.tsx +++ b/superset-frontend/src/pages/DashboardList/index.tsx @@ -86,7 +86,7 @@ interface DashboardListProps { }; } -interface Dashboard { +export interface Dashboard { changed_by_name: string; changed_on_delta_humanized: string; changed_by: string; diff --git a/superset/daos/tag.py b/superset/daos/tag.py index c063657ea0..b6872a5376 100644 --- a/superset/daos/tag.py +++ b/superset/daos/tag.py @@ -175,16 +175,6 @@ class TagDAO(BaseDAO[Tag]): returns a list of tagged objects filtered by tag names and object types if no filters applied returns all tagged objects """ - # id = fields.Int() - # type = fields.String() - # name = fields.String() - # url = fields.String() - # changed_on = fields.DateTime() - # created_by = fields.Nested(UserSchema) - # creator = fields.String( - - # filter types - results: list[dict[str, Any]] = [] # dashboards @@ -211,6 +201,8 @@ class TagDAO(BaseDAO[Tag]): "changed_on": obj.changed_on, "created_by": obj.created_by_fk, "creator": obj.creator(), + "tags": obj.tags, + "owners": obj.owners, } for obj in dashboards ) @@ -238,6 +230,8 @@ class TagDAO(BaseDAO[Tag]): "changed_on": obj.changed_on, "created_by": obj.created_by_fk, "creator": obj.creator(), + "tags": obj.tags, + "owners": obj.owners, } for obj in charts ) @@ -265,6 +259,8 @@ class TagDAO(BaseDAO[Tag]): "changed_on": obj.changed_on, "created_by": obj.created_by_fk, "creator": obj.creator(), + "tags": obj.tags, + "owners": [obj.creator()], } for obj in saved_queries ) diff --git a/superset/tags/schemas.py b/superset/tags/schemas.py index 571a2a03c9..75fdc2410a 100644 --- a/superset/tags/schemas.py +++ b/superset/tags/schemas.py @@ -38,6 +38,12 @@ openapi_spec_methods_override = { } +class TagGetResponseSchema(Schema): + id = fields.Int() + name = fields.String() + type = fields.String() + + class TaggedObjectEntityResponseSchema(Schema): id = fields.Int() type = fields.String() @@ -46,12 +52,8 @@ class TaggedObjectEntityResponseSchema(Schema): changed_on = fields.DateTime() created_by = fields.Nested(UserSchema(exclude=["username"])) creator = fields.String() - - -class TagGetResponseSchema(Schema): - id = fields.Int() - name = fields.String() - type = fields.String() + tags = fields.List(fields.Nested(TagGetResponseSchema)) + owners = fields.List(fields.Nested(UserSchema)) class TagObjectSchema(Schema):