diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/PersonaFlow.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/PersonaFlow.spec.ts index 96400bdae87..ffd9ca0d040 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/PersonaFlow.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/PersonaFlow.spec.ts @@ -160,12 +160,14 @@ describe('Persona operations', { tags: 'Settings' }, () => { verifyResponseStatusCode('@getPersonaDetails', 200); - cy.get( - '[data-testid="page-header-container"] [data-testid="heading"]' - ).should('contain', PERSONA_DETAILS.displayName); - cy.get( - '[data-testid="page-header-container"] [data-testid="sub-heading"]' - ).should('contain', PERSONA_DETAILS.name); + cy.get('[data-testid="entity-header-name"]').should( + 'contain', + PERSONA_DETAILS.name + ); + cy.get('[data-testid="entity-header-display-name"]').should( + 'contain', + PERSONA_DETAILS.displayName + ); cy.get( '[data-testid="viewer-container"] [data-testid="markdown-parser"]' ).should('contain', PERSONA_DETAILS.description); @@ -222,11 +224,14 @@ describe('Persona operations', { tags: 'Settings' }, () => { updatePersonaDisplayName('Test Persona'); - cy.get('[data-testid="heading"]').should('contain', 'Test Persona'); + cy.get('[data-testid="entity-header-display-name"]').should( + 'contain', + 'Test Persona' + ); updatePersonaDisplayName(PERSONA_DETAILS.displayName); - cy.get('[data-testid="heading"]').should( + cy.get('[data-testid="entity-header-display-name"]').should( 'contain', PERSONA_DETAILS.displayName ); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Glossary.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Glossary.spec.ts index 39487199ed6..fc73fb6af5e 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Glossary.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Glossary.spec.ts @@ -504,7 +504,7 @@ describe('Glossary page should work properly', { tags: 'Governance' }, () => { interceptURL('GET', `/api/v1/teams/**`, 'getTeams'); interceptURL( 'GET', - `/api/v1/users?fields=teams%2Croles&limit=25&team=${appName}`, + `/api/v1/users?fields=*&limit=25&team=${appName}`, 'teamUsers' ); diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-personas.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-personas.svg index a156e913c52..43e3bf10271 100644 --- a/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-personas.svg +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-personas.svg @@ -1,6 +1,6 @@ - - - + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Database/SchemaTable/SchemaTable.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Database/SchemaTable/SchemaTable.component.tsx index 41aa6a006ad..8cec144a7bd 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Database/SchemaTable/SchemaTable.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Database/SchemaTable/SchemaTable.component.tsx @@ -30,6 +30,7 @@ import { EntityTags, TagFilterOptions } from 'Models'; import React, { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ReactComponent as IconEdit } from '../../../assets/svg/edit-new.svg'; +import { FQN_SEPARATOR_CHAR } from '../../../constants/char.constants'; import { DE_ACTIVE_COLOR, ICON_DIMENSION, @@ -110,6 +111,16 @@ const SchemaTable = ({ const [editColumnDisplayName, setEditColumnDisplayName] = useState(); const { getEntityPermissionByFqn } = usePermissionProvider(); + const tableFqn = useMemo( + () => + getPartialNameFromTableFQN( + decodedEntityFqn, + [FqnPart.Service, FqnPart.Database, FqnPart.Schema, FqnPart.Table], + FQN_SEPARATOR_CHAR + ), + [decodedEntityFqn] + ); + const sortByOrdinalPosition = useMemo( () => sortBy(tableColumns, 'ordinalPosition'), [tableColumns] @@ -143,10 +154,10 @@ const SchemaTable = ({ ); useEffect(() => { - if (!isEmpty(decodedEntityFqn)) { - fetchResourcePermission(decodedEntityFqn); + if (!isEmpty(tableFqn)) { + fetchResourcePermission(tableFqn); } - }, [decodedEntityFqn]); + }, [tableFqn]); const handleEditColumn = (column: Column): void => { setEditColumn(column); @@ -253,7 +264,7 @@ const SchemaTable = ({ field: record.description, record, }} - entityFqn={decodedEntityFqn} + entityFqn={tableFqn} entityType={EntityType.TABLE} hasEditPermission={hasDescriptionEditAccess} index={index} @@ -422,7 +433,7 @@ const SchemaTable = ({ ), render: (tags: TagLabel[], record: Column, index: number) => ( - entityFqn={decodedEntityFqn} + entityFqn={tableFqn} entityType={EntityType.TABLE} handleTagSelection={handleTagSelection} hasTagEditAccess={hasTagEditAccess} @@ -454,7 +465,7 @@ const SchemaTable = ({ ), render: (tags: TagLabel[], record: Column, index: number) => ( - entityFqn={decodedEntityFqn} + entityFqn={tableFqn} entityType={EntityType.TABLE} handleTagSelection={handleTagSelection} hasTagEditAccess={hasTagEditAccess} @@ -490,7 +501,7 @@ const SchemaTable = ({ }, ], [ - decodedEntityFqn, + tableFqn, isReadOnly, tableConstraints, hasTagEditAccess, diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsV1/TagsV1.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsV1/TagsV1.component.tsx index 70c0907ee00..cc4a57f41a0 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsV1/TagsV1.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsV1/TagsV1.component.tsx @@ -153,7 +153,7 @@ const TagsV1 = ({ {...tagProps}> {/* Wrap only content to avoid redirect on closeable icons */} {tagContent} diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseDetailsPage/DatabaseDetailsPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseDetailsPage/DatabaseDetailsPage.test.tsx index fcb71f265dd..f51d625acba 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseDetailsPage/DatabaseDetailsPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseDetailsPage/DatabaseDetailsPage.test.tsx @@ -143,7 +143,10 @@ jest.mock('react-router-dom', () => ({ .mockImplementation(({ children }: { children: React.ReactNode }) => (

{children}

)), - useHistory: jest.fn(), + useHistory: () => ({ + push: jest.fn(), + replace: jest.fn(), + }), useParams: jest.fn().mockReturnValue({ fqn: 'bigquery.shopify', }), diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/Persona/PersonaDetailsPage/PersonaDetailsPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/Persona/PersonaDetailsPage/PersonaDetailsPage.test.tsx index 9d2be9c7c12..fe70f17845b 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/Persona/PersonaDetailsPage/PersonaDetailsPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/Persona/PersonaDetailsPage/PersonaDetailsPage.test.tsx @@ -144,13 +144,18 @@ jest.mock('../../../utils/ToastUtils', () => ({ showErrorToast: jest.fn(), })); +jest.mock( + '../../../components/Entity/EntityHeaderTitle/EntityHeaderTitle.component', + () => jest.fn().mockImplementation(() =>
EntityHeaderTitle
) +); + describe('PersonaDetailsPage', () => { it('Component should render', async () => { render(); await waitForElementToBeRemoved(() => screen.getByTestId('loader')); - expect(screen.getByTestId('persona-heading')).toBeInTheDocument(); + expect(screen.getByText('EntityHeaderTitle')).toBeInTheDocument(); expect(screen.getByText('TitleBreadcrumb.component')).toBeInTheDocument(); expect( await screen.findByText('ManageButton.component') diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/Persona/PersonaDetailsPage/PersonaDetailsPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/Persona/PersonaDetailsPage/PersonaDetailsPage.tsx index 9309cc1c008..9ccda19b876 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/Persona/PersonaDetailsPage/PersonaDetailsPage.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/Persona/PersonaDetailsPage/PersonaDetailsPage.tsx @@ -10,19 +10,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Button, Col, Row, Tabs, Typography } from 'antd'; +import Icon from '@ant-design/icons/lib/components/Icon'; +import { Button, Col, Row, Tabs } from 'antd'; import { AxiosError } from 'axios'; import { compare } from 'fast-json-patch'; import { isUndefined } from 'lodash'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useHistory } from 'react-router-dom'; +import { ReactComponent as IconPersona } from '../../../assets/svg/ic-personas.svg'; import DescriptionV1 from '../../../components/common/EntityDescription/DescriptionV1'; import ManageButton from '../../../components/common/EntityPageInfos/ManageButton/ManageButton'; import NoDataPlaceholder from '../../../components/common/ErrorWithPlaceholder/NoDataPlaceholder'; import Loader from '../../../components/common/Loader/Loader'; import TitleBreadcrumb from '../../../components/common/TitleBreadcrumb/TitleBreadcrumb.component'; import { UserSelectableList } from '../../../components/common/UserSelectableList/UserSelectableList.component'; +import EntityHeaderTitle from '../../../components/Entity/EntityHeaderTitle/EntityHeaderTitle.component'; import { EntityName } from '../../../components/Modals/EntityNameModal/EntityNameModal.interface'; import PageLayoutV1 from '../../../components/PageLayoutV1/PageLayoutV1'; import { UsersTab } from '../../../components/Settings/Users/UsersTab/UsersTabs.component'; @@ -182,14 +185,18 @@ export const PersonaDetailsPage = () => {
-
+
- - {getEntityName(personaDetails)} - + + + } + name={personaDetails?.name} + serviceName={personaDetails.name} + />
{ ); const [testCaseSummary, setTestCaseSummary] = useState(); + const tableFqn = useMemo( + () => + getPartialNameFromTableFQN( + datasetFQN, + [FqnPart.Service, FqnPart.Database, FqnPart.Schema, FqnPart.Table], + FQN_SEPARATOR_CHAR + ), + [datasetFQN] + ); + const extraDropdownContent = useMemo( () => entityUtilClassBase.getManageExtraOptions( EntityType.TABLE, - datasetFQN, + tableFqn, tablePermissions ), - [tablePermissions, datasetFQN] + [tablePermissions, tableFqn] ); const { viewUsagePermission, viewTestCasePermission } = useMemo( @@ -160,16 +170,6 @@ const TableDetailsPageV1: React.FC = () => { [tablePermissions] ); - const tableFqn = useMemo( - () => - getPartialNameFromTableFQN( - datasetFQN, - [FqnPart.Service, FqnPart.Database, FqnPart.Schema, FqnPart.Table], - FQN_SEPARATOR_CHAR - ), - [datasetFQN] - ); - const isViewTableType = useMemo( () => tableDetails?.tableType === TableType.View, [tableDetails?.tableType] @@ -560,7 +560,7 @@ const TableDetailsPageV1: React.FC = () => { { editCustomAttributePermission } editTagPermission={editTagsPermission} - entityFQN={datasetFQN} + entityFQN={tableFqn} entityId={tableDetails?.id ?? ''} entityType={EntityType.TABLE} selectedTags={tableTags} @@ -635,14 +635,22 @@ const TableDetailsPageV1: React.FC = () => { ), [ + isTourPage, + tableTags, + joinedTables, + tableFqn, isEdit, + deleted, tableDetails, entityName, onDescriptionEdit, onDescriptionUpdate, + testCaseSummary, editTagsPermission, editDescriptionPermission, editAllPermission, + viewAllPermission, + editCustomAttributePermission, ] ); diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.test.tsx index 06ebac77d8e..4cfb863ab1f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.test.tsx @@ -58,6 +58,9 @@ jest.mock('../../../utils/TasksUtils', () => ({ getBreadCrumbList: jest.fn().mockReturnValue([]), getTaskMessage: jest.fn().mockReturnValue('Task message'), getTaskAssignee: jest.fn().mockReturnValue(MOCK_TASK_ASSIGNEE), + getTaskEntityFQN: jest + .fn() + .mockReturnValue('sample_data.ecommerce_db.shopify.dim_location'), })); jest.mock('../shared/Assignees', () => jest.fn().mockImplementation(() =>
Assignees.component
) diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.tsx index ce44320100f..1dc32d813b7 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.tsx @@ -47,6 +47,7 @@ import { fetchOptions, getBreadCrumbList, getTaskAssignee, + getTaskEntityFQN, getTaskMessage, } from '../../../utils/TasksUtils'; import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils'; @@ -64,7 +65,7 @@ const RequestDescription = () => { const { entityType } = useParams<{ entityType: EntityType }>(); - const { fqn: decodedEntityFQN } = useFqn(); + const { fqn } = useFqn(); const queryParams = new URLSearchParams(location.search); const field = queryParams.get('field'); @@ -76,6 +77,11 @@ const RequestDescription = () => { const [suggestion, setSuggestion] = useState(''); const [isLoading, setIsLoading] = useState(false); + const entityFQN = useMemo( + () => getTaskEntityFQN(entityType, fqn), + [fqn, entityType] + ); + const taskMessage = useMemo( () => getTaskMessage({ @@ -116,7 +122,7 @@ const RequestDescription = () => { const data: CreateThread = { from: currentUser?.name as string, message: value.title || taskMessage, - about: getEntityFeedLink(entityType, decodedEntityFQN, getTaskAbout()), + about: getEntityFeedLink(entityType, entityFQN, getTaskAbout()), taskDetails: { assignees: assignees.map((assignee) => ({ id: assignee.value, @@ -138,7 +144,7 @@ const RequestDescription = () => { history.push( entityUtilClassBase.getEntityLink( entityType, - decodedEntityFQN, + entityFQN, EntityTabs.ACTIVITY_FEED, ActivityFeedTabs.TASKS ) @@ -152,8 +158,8 @@ const RequestDescription = () => { }; useEffect(() => { - fetchEntityDetail(entityType, decodedEntityFQN, setEntityData); - }, [decodedEntityFQN, entityType]); + fetchEntityDetail(entityType, entityFQN, setEntityData); + }, [entityFQN, entityType]); useEffect(() => { const defaultAssignee = getTaskAssignee(entityData as Glossary); diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.test.tsx index 65c854ac854..9185b67dd5f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.test.tsx @@ -59,6 +59,9 @@ jest.mock('../../../utils/TasksUtils', () => ({ getBreadCrumbList: jest.fn().mockReturnValue([]), getTaskMessage: jest.fn().mockReturnValue('Task message'), getTaskAssignee: jest.fn().mockReturnValue(MOCK_TASK_ASSIGNEE), + getTaskEntityFQN: jest + .fn() + .mockReturnValue('sample_data.ecommerce_db.shopify.dim_location'), })); jest.mock('../shared/Assignees', () => jest.fn().mockImplementation(() =>
Assignees.component
) diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.tsx index eaff073b797..a5eb04e32ce 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.tsx @@ -46,6 +46,7 @@ import { fetchOptions, getBreadCrumbList, getTaskAssignee, + getTaskEntityFQN, getTaskMessage, } from '../../../utils/TasksUtils'; import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils'; @@ -61,7 +62,7 @@ const RequestTag = () => { const history = useHistory(); const [form] = useForm(); const { entityType } = useParams<{ entityType: EntityType }>(); - const { fqn: entityFQN } = useFqn(); + const { fqn } = useFqn(); const queryParams = new URLSearchParams(location.search); const field = queryParams.get('field'); @@ -73,6 +74,11 @@ const RequestTag = () => { const [suggestion] = useState([]); const [isLoading, setIsLoading] = useState(false); + const entityFQN = useMemo( + () => getTaskEntityFQN(entityType, fqn), + [fqn, entityType] + ); + const taskMessage = useMemo( () => getTaskMessage({ diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateDescriptionPage/UpdateDescriptionPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateDescriptionPage/UpdateDescriptionPage.test.tsx index 029decf955a..de9a49fb270 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateDescriptionPage/UpdateDescriptionPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateDescriptionPage/UpdateDescriptionPage.test.tsx @@ -80,6 +80,9 @@ jest.mock('../../../utils/TasksUtils', () => ({ description: mockTableData.columns[0].description, })), getTaskAssignee: jest.fn().mockReturnValue(MOCK_TASK_ASSIGNEE), + getTaskEntityFQN: jest + .fn() + .mockReturnValue('sample_data.ecommerce_db.shopify.dim_location'), })); jest.mock('../shared/Assignees', () => jest.fn().mockImplementation(() =>
Assignees.component
) diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateDescriptionPage/UpdateDescriptionPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateDescriptionPage/UpdateDescriptionPage.tsx index fc551d633f4..a63d616cc3c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateDescriptionPage/UpdateDescriptionPage.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateDescriptionPage/UpdateDescriptionPage.tsx @@ -50,6 +50,7 @@ import { getColumnObject, getEntityColumnsDetails, getTaskAssignee, + getTaskEntityFQN, getTaskMessage, } from '../../../utils/TasksUtils'; import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils'; @@ -66,7 +67,7 @@ const UpdateDescription = () => { const [form] = useForm(); const { entityType } = useParams<{ entityType: EntityType }>(); - const { fqn: entityFQN } = useFqn(); + const { fqn } = useFqn(); const queryParams = new URLSearchParams(location.search); const field = queryParams.get('field'); @@ -78,6 +79,11 @@ const UpdateDescription = () => { const [currentDescription, setCurrentDescription] = useState(''); const [isLoading, setIsLoading] = useState(false); + const entityFQN = useMemo( + () => getTaskEntityFQN(entityType, fqn), + [fqn, entityType] + ); + const sanitizeValue = useMemo( () => value?.replaceAll(TASK_SANITIZE_VALUE_REGEX, '') ?? '', [value] diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateTagPage/UpdateTagPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateTagPage/UpdateTagPage.test.tsx index 1fa9b84980c..028c01e8c9e 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateTagPage/UpdateTagPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateTagPage/UpdateTagPage.test.tsx @@ -90,6 +90,9 @@ jest.mock('../../../utils/TasksUtils', () => ({ getColumnObject: jest.fn().mockImplementation(() => ({ tags: mockTableData.columns[0].tags, })), + getTaskEntityFQN: jest + .fn() + .mockReturnValue('sample_data.ecommerce_db.shopify.dim_location'), getTaskAssignee: jest.fn().mockReturnValue(MOCK_TASK_ASSIGNEE), })); jest.mock('../shared/Assignees', () => diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateTagPage/UpdateTagPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateTagPage/UpdateTagPage.tsx index 27079ba4a04..a76afaf72bc 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateTagPage/UpdateTagPage.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateTagPage/UpdateTagPage.tsx @@ -51,6 +51,7 @@ import { getColumnObject, getEntityColumnsDetails, getTaskAssignee, + getTaskEntityFQN, getTaskMessage, } from '../../../utils/TasksUtils'; import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils'; @@ -68,7 +69,7 @@ const UpdateTag = () => { const { entityType } = useParams<{ entityType: EntityType }>(); - const { fqn: entityFQN } = useFqn(); + const { fqn } = useFqn(); const queryParams = new URLSearchParams(location.search); const field = queryParams.get('field'); @@ -83,6 +84,11 @@ const UpdateTag = () => { const [suggestion, setSuggestion] = useState([]); const [isLoading, setIsLoading] = useState(false); + const entityFQN = useMemo( + () => getTaskEntityFQN(entityType, fqn), + [fqn, entityType] + ); + const sanitizeValue = useMemo( () => value?.replaceAll(TASK_SANITIZE_VALUE_REGEX, '') ?? '', [value] diff --git a/openmetadata-ui/src/main/resources/ui/src/styles/components/size.less b/openmetadata-ui/src/main/resources/ui/src/styles/components/size.less index 778b076e16a..d0897617df8 100644 --- a/openmetadata-ui/src/main/resources/ui/src/styles/components/size.less +++ b/openmetadata-ui/src/main/resources/ui/src/styles/components/size.less @@ -174,6 +174,9 @@ .w-max-full-140 { max-width: calc(100% - 140px); } +.w-max-stretch { + max-width: stretch; +} .w-auto { width: auto; diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchClassBase.ts b/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchClassBase.ts index 952d0f3a023..d08fad88811 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchClassBase.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchClassBase.ts @@ -12,7 +12,7 @@ */ import { t } from 'i18next'; -import { sortBy } from 'lodash'; +import { isEmpty, sortBy } from 'lodash'; import { AsyncFetchListValues, AsyncFetchListValuesResult, @@ -97,19 +97,6 @@ class AdvancedSearchClassBase { }, }, - 'columns.name.keyword': { - label: t('label.column'), - type: 'select', - mainWidgetProps: this.mainWidgetProps, - fieldSettings: { - asyncFetch: this.autocomplete({ - searchIndex: SearchIndex.TABLE, - entityField: EntityFields.COLUMN, - }), - useAsyncSearch: true, - }, - }, - tableType: { label: t('label.table-type'), type: 'select', @@ -320,18 +307,6 @@ class AdvancedSearchClassBase { useAsyncSearch: true, }, }, - 'columns.name.keyword': { - label: t('label.data-model-column'), - type: 'select', - mainWidgetProps: this.mainWidgetProps, - fieldSettings: { - asyncFetch: this.autocomplete({ - searchIndex: SearchIndex.DASHBOARD_DATA_MODEL, - entityField: EntityFields.COLUMN, - }), - useAsyncSearch: true, - }, - }, 'project.keyword': { label: t('label.project'), type: 'select', @@ -551,6 +526,36 @@ class AdvancedSearchClassBase { }; } + // Since the column field key 'columns.name.keyword` is common in table and data model, + // Following function is used to get the column field config based on the search index + // or if it is an explore page + public getColumnConfig = (entitySearchIndex: SearchIndex[]) => { + const searchIndexWithColumns = entitySearchIndex.filter( + (index) => + index === SearchIndex.TABLE || + index === SearchIndex.DASHBOARD_DATA_MODEL || + index === SearchIndex.DATA_ASSET || + index === SearchIndex.ALL + ); + + return !isEmpty(searchIndexWithColumns) + ? { + 'columns.name.keyword': { + label: t('label.column'), + type: 'select', + mainWidgetProps: this.mainWidgetProps, + fieldSettings: { + asyncFetch: this.autocomplete({ + searchIndex: searchIndexWithColumns, + entityField: EntityFields.COLUMN, + }), + useAsyncSearch: true, + }, + }, + } + : {}; + }; + /** * Get entity specific fields for the query builder */ @@ -631,6 +636,7 @@ class AdvancedSearchClassBase { ...this.getCommonConfig({ entitySearchIndex, tierOptions }), ...(shouldAddServiceField ? serviceQueryBuilderFields : {}), ...this.getEntitySpecificQueryBuilderFields(entitySearchIndex), + ...this.getColumnConfig(entitySearchIndex), }; // Sort the fields according to the label @@ -648,7 +654,7 @@ class AdvancedSearchClassBase { isExplorePage?: boolean ) => BasicConfig = (tierOptions, entitySearchIndex, isExplorePage) => { const searchIndexWithServices = [ - SearchIndex.ALL, + SearchIndex.DATA_ASSET, SearchIndex.TABLE, SearchIndex.DASHBOARD, SearchIndex.PIPELINE, diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/TasksUtils.test.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/TasksUtils.test.tsx index 0f286429427..b141b35405e 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/TasksUtils.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/TasksUtils.test.tsx @@ -21,6 +21,7 @@ import { fetchOptions, getEntityTableName, getTaskAssignee, + getTaskEntityFQN, getTaskMessage, } from './TasksUtils'; @@ -298,3 +299,28 @@ describe('Tests for getTaskAssignee', () => { ]); }); }); + +describe('Tests for getTaskEntityFQN', () => { + it('should return fqn for table entity', async () => { + const fqn = 'sample_data.ecommerce_db.shopify."dim.product"'; + const response = getTaskEntityFQN(EntityType.TABLE, fqn); + + expect(response).toEqual(fqn); + }); + + it('should return table fqn only when column name present in fqn', async () => { + const response = getTaskEntityFQN( + EntityType.TABLE, + 'sample_data.ecommerce_db.shopify."dim.product".address_id' + ); + + expect(response).toEqual('sample_data.ecommerce_db.shopify."dim.product"'); + }); + + it('should return fqn as it is if entity type is not table', async () => { + const fqn = 'sample_looker.customers'; + const response = getTaskEntityFQN(EntityType.DASHBOARD, fqn); + + expect(response).toEqual(fqn); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/TasksUtils.ts b/openmetadata-ui/src/main/resources/ui/src/utils/TasksUtils.ts index 6ac37869555..01bbfc20cd3 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/TasksUtils.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/TasksUtils.ts @@ -19,6 +19,7 @@ import { ReactComponent as CancelColored } from '../assets/svg/cancel-colored.sv import { ReactComponent as EditColored } from '../assets/svg/edit-colored.svg'; import { ReactComponent as SuccessColored } from '../assets/svg/success-colored.svg'; import { ActivityFeedTabs } from '../components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface'; +import { FQN_SEPARATOR_CHAR } from '../constants/char.constants'; import { getEntityDetailsPath, getGlossaryTermDetailsPath, @@ -901,3 +902,15 @@ export const getTaskAssignee = (entityData: Glossary): Option[] => { return defaultAssignee; }; + +export const getTaskEntityFQN = (entityType: EntityType, fqn: string) => { + if (entityType === EntityType.TABLE) { + return getPartialNameFromTableFQN( + fqn, + [FqnPart.Service, FqnPart.Database, FqnPart.Schema, FqnPart.Table], + FQN_SEPARATOR_CHAR + ); + } + + return fqn; +};