From de06d50e7f2ba37201dd868d3fc074a0aaa868a2 Mon Sep 17 00:00:00 2001 From: Ashish Gupta Date: Tue, 1 Aug 2023 14:12:47 +0530 Subject: [PATCH] fix(ui): ui breaking as url was not encoded. (#12643) * fix ui breaking because of url having percent in it * added support for % in about * fix test cases * checkstyle * url fix * fix storage url * encoded topic, mlmodel and pipeline entity --------- Co-authored-by: 07Himank --- .../service/resources/EntityResourceTest.java | 2 +- .../resources/feeds/FeedResourceTest.java | 2 +- .../resources/json/schema/type/basic.json | 2 +- .../ActivityFeedTab.component.tsx | 8 +++++++- .../AddService/AddService.component.tsx | 8 +++++++- .../DashboardDetails.component.tsx | 5 ++++- .../DataModels/DataModelDetails.component.tsx | 6 +++++- .../EntitySummaryPanel.component.tsx | 2 +- .../ExploreSearchCard/ExploreSearchCard.tsx | 4 ++-- .../IngestionRecentRuns.component.tsx | 3 ++- .../Ingestion/PipelineActions.component.tsx | 7 +++++-- .../MlModelDetail/MlModelDetail.component.tsx | 3 ++- .../PipelineDetails.component.tsx | 5 +++-- .../Tag/TagsV1/TagsV1.component.tsx | 7 +++++-- .../TopicDetails/TopicDetails.component.tsx | 3 ++- .../common/PopOverCard/EntityPopOverCard.tsx | 14 ++++++++++++- .../resources/ui/src/constants/constants.ts | 2 +- .../src/pages/ContainerPage/ContainerPage.tsx | 8 ++++++-- .../DatabaseDetailsPage.tsx | 8 ++++++-- .../DatabaseSchemaPage.component.tsx | 11 +++++++--- .../pages/LogsViewer/LogsViewer.component.tsx | 3 ++- .../ServiceDetailsPage/ServiceDetailsPage.tsx | 15 +++++++------- .../resources/ui/src/utils/EntityUtils.tsx | 13 ++++++------ .../resources/ui/src/utils/ServiceUtils.tsx | 3 ++- .../resources/ui/src/utils/TableUtils.tsx | 20 +++++++++---------- 25 files changed, 111 insertions(+), 53 deletions(-) diff --git a/openmetadata-service/src/test/java/org/openmetadata/service/resources/EntityResourceTest.java b/openmetadata-service/src/test/java/org/openmetadata/service/resources/EntityResourceTest.java index 38da68d6528..f4687b1d9ab 100644 --- a/openmetadata-service/src/test/java/org/openmetadata/service/resources/EntityResourceTest.java +++ b/openmetadata-service/src/test/java/org/openmetadata/service/resources/EntityResourceTest.java @@ -234,7 +234,7 @@ public abstract class EntityResourceTest$\"]"; + "[entityLink must match \"^(?U)<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#%]+>$\"]"; // Random unicode string generator to test entity name accepts all the unicode characters protected static final RandomStringGenerator RANDOM_STRING_GENERATOR = diff --git a/openmetadata-service/src/test/java/org/openmetadata/service/resources/feeds/FeedResourceTest.java b/openmetadata-service/src/test/java/org/openmetadata/service/resources/feeds/FeedResourceTest.java index b16ce9076d7..cacec77f33c 100644 --- a/openmetadata-service/src/test/java/org/openmetadata/service/resources/feeds/FeedResourceTest.java +++ b/openmetadata-service/src/test/java/org/openmetadata/service/resources/feeds/FeedResourceTest.java @@ -199,7 +199,7 @@ public class FeedResourceTest extends OpenMetadataApplicationTest { // Create thread without addressed to entity in the request CreateThread create = create().withFrom(USER.getName()).withAbout("<>"); // Invalid EntityLink - String failureReason = "[about must match \"^(?U)<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#]+>$\"]"; + String failureReason = "[about must match \"^(?U)<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#%]+>$\"]"; assertResponseContains(() -> createThread(create, USER_AUTH_HEADERS), BAD_REQUEST, failureReason); create.withAbout("<#E::>"); // Invalid EntityLink - missing entityType and entityId diff --git a/openmetadata-spec/src/main/resources/json/schema/type/basic.json b/openmetadata-spec/src/main/resources/json/schema/type/basic.json index a272a61cf38..935acf04c7e 100644 --- a/openmetadata-spec/src/main/resources/json/schema/type/basic.json +++ b/openmetadata-spec/src/main/resources/json/schema/type/basic.json @@ -93,7 +93,7 @@ "entityLink": { "description": "Link to an entity or field within an entity using this format `<#E::{entities}::{entityType}::{field}::{arrayFieldName}::{arrayFieldValue}`.", "type": "string", - "pattern": "^(?U)<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#]+>$" + "pattern": "^(?U)<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#%]+>$" }, "entityName": { "description": "Name that identifies a entity.", diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.component.tsx index 04389721187..0ed6f0fb22d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.component.tsx @@ -38,6 +38,7 @@ import { useHistory, useParams } from 'react-router-dom'; import { getAllFeeds, getFeedCount } from 'rest/feedsAPI'; import { getCountBadge, getEntityDetailLink } from 'utils/CommonUtils'; import { ENTITY_LINK_SEPARATOR, getEntityFeedLink } from 'utils/EntityUtils'; +import { getEncodedFqn } from 'utils/StringsUtils'; import '../../Widgets/FeedsWidget/feeds-widget.less'; import ActivityFeedEditor from '../ActivityFeedEditor/ActivityFeedEditor'; import ActivityFeedListV1 from '../ActivityFeedList/ActivityFeedListV1.component'; @@ -108,7 +109,12 @@ export const ActivityFeedTab = ({ const handleTabChange = (subTab: string) => { history.push( - getEntityDetailLink(entityType, fqn, EntityTabs.ACTIVITY_FEED, subTab) + getEntityDetailLink( + entityType, + EntityType.TABLE === entityType ? getEncodedFqn(fqn) : fqn, + EntityTabs.ACTIVITY_FEED, + subTab + ) ); setActiveThread(); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddService/AddService.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddService/AddService.component.tsx index 9f7b1da584c..ba75fbb8844 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/AddService/AddService.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/AddService/AddService.component.tsx @@ -25,6 +25,7 @@ import { capitalize, isEmpty, isUndefined } from 'lodash'; import { LoadingState } from 'Models'; import React, { useEffect, useState } from 'react'; import { useHistory } from 'react-router-dom'; +import { getEncodedFqn } from 'utils/StringsUtils'; import { showErrorToast } from 'utils/ToastUtils'; import { getServiceDetailsPath } from '../../constants/constants'; import { GlobalSettingsMenuCategory } from '../../constants/GlobalSettings.constants'; @@ -171,7 +172,12 @@ const AddService = ({ // View new service const handleViewServiceClick = () => { if (!isUndefined(newServiceData)) { - history.push(getServiceDetailsPath(newServiceData.name, serviceCategory)); + history.push( + getServiceDetailsPath( + getEncodedFqn(newServiceData.name), + serviceCategory + ) + ); } }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.component.tsx index b206d73f5c0..833183c0bcd 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.component.tsx @@ -68,6 +68,7 @@ import { withActivityFeed } from 'components/router/withActivityFeed'; import TableDescription from 'components/TableDescription/TableDescription.component'; import { DisplayType } from 'components/Tag/TagsViewer/TagsViewer.interface'; import { handleDataAssetAfterDeleteAction } from 'utils/Assets/AssetsUtils'; +import { getDecodedFqn } from 'utils/StringsUtils'; const DashboardDetails = ({ charts, @@ -219,7 +220,9 @@ const DashboardDetails = ({ const handleTabChange = (activeKey: string) => { if (activeKey !== activeTab) { - history.push(getDashboardDetailsPath(dashboardFQN, activeKey)); + history.push( + getDashboardDetailsPath(getDecodedFqn(dashboardFQN), activeKey) + ); } }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataModels/DataModelDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataModels/DataModelDetails.component.tsx index 731a60c8796..dbb132f2800 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataModels/DataModelDetails.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataModels/DataModelDetails.component.tsx @@ -43,6 +43,7 @@ import { handleDataAssetAfterDeleteAction } from 'utils/Assets/AssetsUtils'; import { getFeedCounts, refreshPage } from 'utils/CommonUtils'; import { getEntityName, getEntityThreadLink } from 'utils/EntityUtils'; import { getEntityFieldThreadCounts } from 'utils/FeedUtils'; +import { getDecodedFqn } from 'utils/StringsUtils'; import { getTagsWithoutTier } from 'utils/TableUtils'; import { showErrorToast, showSuccessToast } from 'utils/ToastUtils'; import { DataModelDetailsProps } from './DataModelDetails.interface'; @@ -148,7 +149,10 @@ const DataModelDetails = ({ const handleTabChange = (tabValue: EntityTabs) => { if (tabValue !== activeTab) { history.push({ - pathname: getDataModelDetailsPath(dashboardDataModelFQN, tabValue), + pathname: getDataModelDetailsPath( + getDecodedFqn(dashboardDataModelFQN), + tabValue + ), }); } }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/EntitySummaryPanel.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/EntitySummaryPanel.component.tsx index 4e3fbe9a92a..233445ab75c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/EntitySummaryPanel.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/EntitySummaryPanel.component.tsx @@ -132,7 +132,7 @@ export default function EntitySummaryPanel({ (entityDetails.details.fullyQualifiedName && entityDetails.details.entityType && getEntityLinkFromType( - getEncodedFqn(entityDetails.details.fullyQualifiedName), + entityDetails.details.fullyQualifiedName, entityDetails.details.entityType as EntityType )) ?? '', diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ExploreV1/ExploreSearchCard/ExploreSearchCard.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ExploreV1/ExploreSearchCard/ExploreSearchCard.tsx index 74ed1372136..062c8d07ef5 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/ExploreV1/ExploreSearchCard/ExploreSearchCard.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/ExploreV1/ExploreSearchCard/ExploreSearchCard.tsx @@ -31,7 +31,7 @@ import { getEntityLinkFromType, getEntityName, } from 'utils/EntityUtils'; -import { getEncodedFqn, stringToHTML } from 'utils/StringsUtils'; +import { stringToHTML } from 'utils/StringsUtils'; import { getServiceIcon, getUsagePercentile } from 'utils/TableUtils'; import './explore-search-card.less'; import { ExploreSearchCardProps } from './ExploreSearchCard.interface'; @@ -140,7 +140,7 @@ const ExploreSearchCard: React.FC = forwardRef< to={ source.fullyQualifiedName && source.entityType ? getEntityLinkFromType( - getEncodedFqn(source.fullyQualifiedName), + source.fullyQualifiedName, source.entityType as EntityType ) : '' diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Ingestion/IngestionRecentRun/IngestionRecentRuns.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Ingestion/IngestionRecentRun/IngestionRecentRuns.component.tsx index b34eee45651..2dfc94ff614 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Ingestion/IngestionRecentRun/IngestionRecentRuns.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Ingestion/IngestionRecentRun/IngestionRecentRuns.component.tsx @@ -22,6 +22,7 @@ import React, { } from 'react'; import { useTranslation } from 'react-i18next'; import { getRunHistoryForPipeline } from 'rest/ingestionPipelineAPI'; +import { getEncodedFqn } from 'utils/StringsUtils'; import { IngestionPipeline, PipelineStatus, @@ -54,7 +55,7 @@ export const IngestionRecentRuns: FunctionComponent = ({ setLoading(true); try { const response = await getRunHistoryForPipeline( - ingestion.fullyQualifiedName || '', + getEncodedFqn(ingestion.fullyQualifiedName || ''), queryParams ); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Ingestion/PipelineActions.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Ingestion/PipelineActions.component.tsx index 48eb5443284..35f19ac403c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Ingestion/PipelineActions.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Ingestion/PipelineActions.component.tsx @@ -21,6 +21,7 @@ import { useTranslation } from 'react-i18next'; import { Link, useHistory } from 'react-router-dom'; import { getLoadingStatus } from 'utils/CommonUtils'; import { getEditIngestionPath, getLogsViewerPath } from 'utils/RouterUtils'; +import { getEncodedFqn } from 'utils/StringsUtils'; import { showErrorToast, showSuccessToast } from 'utils/ToastUtils'; import { PipelineActionsProps } from './PipelineActions.interface'; @@ -83,7 +84,9 @@ function PipelineActions({ getEditIngestionPath( serviceCategory, serviceName, - ingestion.fullyQualifiedName || `${serviceName}.${ingestion.name}`, + getEncodedFqn( + ingestion.fullyQualifiedName || `${serviceName}.${ingestion.name}` + ), ingestion.pipelineType ) ); @@ -214,7 +217,7 @@ function PipelineActions({ to={getLogsViewerPath( serviceCategory, record.service?.name || '', - record?.fullyQualifiedName || record?.name || '' + getEncodedFqn(record?.fullyQualifiedName || record?.name || '') )}>