From c40e9ff6853078401ce4ccd27341760ec7c829af Mon Sep 17 00:00:00 2001 From: Sachin Chaurasiya Date: Thu, 14 Jul 2022 11:44:17 +0530 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Activity=20Feed:=20Show=20"Request?= =?UTF-8?q?=20Tag"=20button=20for=20table=20column=20Tags=20(#6039)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ Activity Feed: Show "Request Tag" button for table column Tags * Add support for task icon * Addressing review comment * Fix unit tests * Fix unit test * Fix explore page issue --- .../EntityTable/EntityTable.component.tsx | 100 ++++++++++-------- .../EntityTable/EntityTable.constant.ts | 35 ++++++ .../EntityTable/EntityTable.interface.ts | 34 ++++++ .../EntityTable/EntityTable.test.tsx | 27 +++++ .../components/Explore/Explore.component.tsx | 14 ++- .../common/facetfilter/FacetFilter.tsx | 2 +- 6 files changed, 162 insertions(+), 50 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.constant.ts create mode 100644 openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.interface.ts diff --git a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.component.tsx index 943ea2b2608..46a77547ca0 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.component.tsx @@ -15,7 +15,7 @@ import { faCaretDown, faCaretRight } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Popover } from 'antd'; import classNames from 'classnames'; -import { cloneDeep, isNil, isUndefined, lowerCase } from 'lodash'; +import { cloneDeep, isEmpty, isNil, isUndefined, lowerCase } from 'lodash'; import { EntityFieldThreads, EntityTags, TagOption } from 'Models'; import React, { Fragment, useEffect, useState } from 'react'; import { Link, useHistory } from 'react-router-dom'; @@ -28,10 +28,8 @@ import { SettledStatus } from '../../enums/axios.enum'; import { EntityType, FqnPart } from '../../enums/entity.enum'; import { Column, - ColumnJoins, ColumnTest, JoinedWith, - Table, } from '../../generated/entity/data/table'; import { ThreadType } from '../../generated/entity/feed/thread'; import { Operation } from '../../generated/entity/policies/accessControl/rule'; @@ -59,6 +57,7 @@ import { import { getTagCategories, getTaglist } from '../../utils/TagsUtils'; import { getRequestDescriptionPath, + getRequestTagsPath, getUpdateDescriptionPath, } from '../../utils/TasksUtils'; import NonAdminAction from '../common/non-admin-action/NonAdminAction'; @@ -67,23 +66,8 @@ import RichTextEditorPreviewer from '../common/rich-text-editor/RichTextEditorPr import { ModalWithMarkdownEditor } from '../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor'; import TagsContainer from '../tags-container/tags-container'; import TagsViewer from '../tags-viewer/tags-viewer'; - -interface Props { - owner: Table['owner']; - tableColumns: ModifiedTableColumn[]; - joins: Array; - columnName: string; - hasEditAccess: boolean; - tableConstraints: Table['tableConstraints']; - searchText?: string; - isReadOnly?: boolean; - entityFqn?: string; - entityFieldThreads?: EntityFieldThreads[]; - entityFieldTasks?: EntityFieldThreads[]; - onUpdate?: (columns: ModifiedTableColumn[]) => void; - onThreadLinkSelect?: (value: string, threadType?: ThreadType) => void; - onEntityFieldSelect?: (value: string) => void; -} +import { TABLE_HEADERS } from './EntityTable.constant'; +import { EntityTableProps } from './EntityTable.interface'; const EntityTable = ({ tableColumns, @@ -98,35 +82,11 @@ const EntityTable = ({ entityFqn, tableConstraints, entityFieldTasks, -}: Props) => { +}: EntityTableProps) => { const { isAdminUser, userPermissions } = useAuth(); const { isAuthDisabled } = useAuthContext(); const history = useHistory(); - const columns = React.useMemo( - () => [ - { - Header: 'Name', - accessor: 'name', - }, - { - Header: 'Type', - accessor: 'dataTypeDisplay', - }, - { - Header: 'Data Quality', - accessor: 'columnTests', - }, - { - Header: 'Description', - accessor: 'description', - }, - { - Header: 'Tags', - accessor: 'tags', - }, - ], - [] - ); + const columns = TABLE_HEADERS; const [searchedColumns, setSearchedColumns] = useState( [] @@ -405,6 +365,15 @@ const EntityTable = ({ ); }; + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + const onRequestTagsHandler = (cell: any) => { + const field = EntityField.COLUMNS; + const value = getColumnName(cell); + history.push( + getRequestTagsPath(EntityType.TABLE, entityFqn as string, field, value) + ); + }; + const prepareConstraintIcon = ( columnName: string, columnConstraint?: string @@ -460,6 +429,27 @@ const EntityTable = ({ ); }; + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + const getRequestTagsElement = (cell: any) => { + const hasTags = !isEmpty(cell.value || []); + + return !hasTags ? ( + + ) : null; + }; + useEffect(() => { if (!searchText) { setSearchedColumns(tableColumns); @@ -677,6 +667,7 @@ const EntityTable = ({ />
+ {getRequestTagsElement(cell)} {getFieldThreadElement( getColumnName(cell), 'tags', @@ -689,6 +680,23 @@ const EntityTable = ({ )}${ENTITY_LINK_SEPARATOR}tags`, Boolean(cell.value.length) )} + {getFieldThreadElement( + getColumnName(cell), + EntityField.TAGS, + entityFieldTasks as EntityFieldThreads[], + onThreadLinkSelect, + EntityType.TABLE, + entityFqn, + `${ + EntityField.COLUMNS + }${ENTITY_LINK_SEPARATOR}${getColumnName( + cell + )}${ENTITY_LINK_SEPARATOR}${ + EntityField.TAGS + }`, + Boolean(cell.value), + ThreadType.Task + )}
)} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.constant.ts b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.constant.ts new file mode 100644 index 00000000000..727171c51dd --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.constant.ts @@ -0,0 +1,35 @@ +/* + * Copyright 2021 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. + */ + +export const TABLE_HEADERS = [ + { + Header: 'Name', + accessor: 'name', + }, + { + Header: 'Type', + accessor: 'dataTypeDisplay', + }, + { + Header: 'Data Quality', + accessor: 'columnTests', + }, + { + Header: 'Description', + accessor: 'description', + }, + { + Header: 'Tags', + accessor: 'tags', + }, +]; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.interface.ts new file mode 100644 index 00000000000..c0c3c1306d2 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.interface.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2021 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 { EntityFieldThreads } from 'Models'; +import { ThreadType } from '../../generated/api/feed/createThread'; +import { ColumnJoins, Table } from '../../generated/entity/data/table'; +import { ModifiedTableColumn } from '../../interface/dataQuality.interface'; + +export interface EntityTableProps { + owner: Table['owner']; + tableColumns: ModifiedTableColumn[]; + joins: Array; + columnName: string; + hasEditAccess: boolean; + tableConstraints: Table['tableConstraints']; + searchText?: string; + isReadOnly?: boolean; + entityFqn?: string; + entityFieldThreads?: EntityFieldThreads[]; + entityFieldTasks?: EntityFieldThreads[]; + onUpdate?: (columns: ModifiedTableColumn[]) => void; + onThreadLinkSelect?: (value: string, threadType?: ThreadType) => void; + onEntityFieldSelect?: (value: string) => void; +} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.test.tsx index 4f21429d9e8..4a8d9b29ec9 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.test.tsx @@ -286,6 +286,33 @@ jest.mock('../../utils/TagsUtils', () => ({ }), })); +jest.mock('./EntityTable.constant', () => { + return { + TABLE_HEADERS: [ + { + Header: 'Name', + accessor: 'name', + }, + { + Header: 'Type', + accessor: 'dataTypeDisplay', + }, + { + Header: 'Data Quality', + accessor: 'columnTests', + }, + { + Header: 'Description', + accessor: 'description', + }, + { + Header: 'Tags', + accessor: 'tags', + }, + ], + }; +}); + describe('Test EntityTable Component', () => { it('Check if it has all child elements', async () => { const { container } = render(, { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Explore/Explore.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Explore/Explore.component.tsx index aa499627597..d23f3a195e0 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Explore/Explore.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Explore/Explore.component.tsx @@ -18,7 +18,7 @@ import { import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Card } from 'antd'; import classNames from 'classnames'; -import { cloneDeep, isEmpty, isUndefined, lowerCase } from 'lodash'; +import { cloneDeep, isEmpty, lowerCase } from 'lodash'; import { AggregationType, Bucket, @@ -131,6 +131,9 @@ const Explore: React.FC = ({ const [selectedAdvancedFields, setSelectedAdvancedField] = useState< Array >([]); + const [isInitialFilterSet, setIsInitialFilterSet] = useState( + !isEmpty(initialFilter) + ); const onAdvancedFieldSelect = (value: string) => { const flag = selectedAdvancedFields.some((field) => field.key === value); @@ -505,7 +508,11 @@ const Explore: React.FC = ({ const getData = () => { if (!isMounting.current && previsouIndex === getCurrentIndex(tab)) { - forceSetAgg.current = !isFilterSet; + if (isInitialFilterSet) { + forceSetAgg.current = isInitialFilterSet; + } else { + forceSetAgg.current = !isFilterSet; + } fetchTableData(); } }; @@ -565,7 +572,7 @@ const Explore: React.FC = ({ if (searchResult) { updateSearchResults(searchResult.resSearchResults); setCount(searchResult.resSearchResults.data.hits.total.value); - if (forceSetAgg.current || !isUndefined(initialFilter)) { + if (forceSetAgg.current) { setAggregations( searchResult.resSearchResults.data.hits.hits.length > 0 ? getAggregationList( @@ -573,6 +580,7 @@ const Explore: React.FC = ({ ) : getAggregationListFromQS(location.search) ); + setIsInitialFilterSet(false); } else { const aggServiceType = getAggregationList( searchResult.resAggServiceType.data.aggregations, diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/facetfilter/FacetFilter.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/facetfilter/FacetFilter.tsx index 99aa14a7266..c4254798a66 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/facetfilter/FacetFilter.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/facetfilter/FacetFilter.tsx @@ -178,7 +178,7 @@ const FacetFilter: FunctionComponent = ({ className="sidebar-my-data-holder mt-2 mb-3" data-testid="show-deleted-cntnr">