From dc2c7c0fb72de78a4a1285c49fa84d7da37b480d Mon Sep 17 00:00:00 2001 From: Shailesh Parmar Date: Thu, 10 Feb 2022 19:13:22 +0530 Subject: [PATCH] Feat: Added support to handle error for UI side (#2708) --- .../DashboardDetailsPage.component.tsx | 90 ++++++++++++----- .../DatasetDetailsPage.component.tsx | 84 +++++++++++----- .../PipelineDetailsPage.component.tsx | 90 ++++++++++++----- .../TopicDetailsPage.component.tsx | 88 ++++++++++++----- .../ui/src/pages/database-details/index.tsx | 98 ++++++++++++------- .../resources/ui/src/pages/service/index.tsx | 62 ++++++++++-- 6 files changed, 379 insertions(+), 133 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DashboardDetailsPage/DashboardDetailsPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DashboardDetailsPage/DashboardDetailsPage.component.tsx index 870473cf53a..0ce56e0893f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/DashboardDetailsPage/DashboardDetailsPage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/DashboardDetailsPage/DashboardDetailsPage.component.tsx @@ -321,37 +321,75 @@ const DashboardDetailsPage = () => { }; const descriptionUpdateHandler = (updatedDashboard: Dashboard) => { - saveUpdatedDashboardData(updatedDashboard).then((res: AxiosResponse) => { - const { description, version } = res.data; - setCurrentVersion(version); - setDashboardDetails(res.data); - setDescription(description); - }); + saveUpdatedDashboardData(updatedDashboard) + .then((res: AxiosResponse) => { + const { description, version } = res.data; + setCurrentVersion(version); + setDashboardDetails(res.data); + setDescription(description); + }) + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || 'Error while updating description.'; + showToast({ + variant: 'error', + body: errMsg, + }); + }); }; const followDashboard = () => { - addFollower(dashboardId, USERId).then((res: AxiosResponse) => { - const { newValue } = res.data.changeDescription.fieldsAdded[0]; + addFollower(dashboardId, USERId) + .then((res: AxiosResponse) => { + const { newValue } = res.data.changeDescription.fieldsAdded[0]; - setFollowers([...followers, ...newValue]); - }); + setFollowers([...followers, ...newValue]); + }) + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || + 'Error while following dashboard entity.'; + showToast({ + variant: 'error', + body: errMsg, + }); + }); }; const unfollowDashboard = () => { - removeFollower(dashboardId, USERId).then((res: AxiosResponse) => { - const { oldValue } = res.data.changeDescription.fieldsDeleted[0]; + removeFollower(dashboardId, USERId) + .then((res: AxiosResponse) => { + const { oldValue } = res.data.changeDescription.fieldsDeleted[0]; - setFollowers( - followers.filter((follower) => follower.id !== oldValue[0].id) - ); - }); + setFollowers( + followers.filter((follower) => follower.id !== oldValue[0].id) + ); + }) + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || + 'Error while unfollowing dashboard entity.'; + showToast({ + variant: 'error', + body: errMsg, + }); + }); }; const onTagUpdate = (updatedDashboard: Dashboard) => { - saveUpdatedDashboardData(updatedDashboard).then((res: AxiosResponse) => { - setTier(getTierTags(res.data.tags)); - setCurrentVersion(res.data.version); - setTags(getTagsWithoutTier(res.data.tags)); - }); + saveUpdatedDashboardData(updatedDashboard) + .then((res: AxiosResponse) => { + setTier(getTierTags(res.data.tags)); + setCurrentVersion(res.data.version); + setTags(getTagsWithoutTier(res.data.tags)); + }) + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || 'Error while updating tags.'; + showToast({ + variant: 'error', + body: errMsg, + }); + }); }; const settingsUpdateHandler = ( @@ -366,7 +404,15 @@ const DashboardDetailsPage = () => { setTier(getTierTags(res.data.tags)); resolve(); }) - .catch(() => reject()); + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || 'Error while updating entity.'; + reject(); + showToast({ + variant: 'error', + body: errMsg, + }); + }); }); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.component.tsx index c71c0e3788d..b9e9e59eb7f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.component.tsx @@ -148,7 +148,7 @@ const DatasetDetailsPage: FunctionComponent = () => { .catch((err: AxiosError) => { showToast({ variant: 'error', - body: err.message ?? 'Error while fetching lineage data', + body: err.message ?? 'Error while fetching lineage data.', }); }) .finally(() => { @@ -232,7 +232,7 @@ const DatasetDetailsPage: FunctionComponent = () => { if (err.response?.status === 404) { setIsError(true); } else { - const errMsg = err.message || 'Error while fetching table details'; + const errMsg = err.message || 'Error while fetching table details.'; showToast({ variant: 'error', body: errMsg, @@ -259,7 +259,7 @@ const DatasetDetailsPage: FunctionComponent = () => { .catch(() => showToast({ variant: 'error', - body: 'Error while getting sample data', + body: 'Error while getting sample data.', }) ) .finally(() => setIsSampleDataLoading(false)); @@ -305,22 +305,41 @@ const DatasetDetailsPage: FunctionComponent = () => { }; const descriptionUpdateHandler = (updatedTable: Table) => { - saveUpdatedTableData(updatedTable).then((res: AxiosResponse) => { - const { description, version } = res.data; - setCurrentVersion(version); - setTableDetails(res.data); - setDescription(description); - }); + saveUpdatedTableData(updatedTable) + .then((res: AxiosResponse) => { + const { description, version } = res.data; + setCurrentVersion(version); + setTableDetails(res.data); + setDescription(description); + }) + .catch((err: AxiosError) => { + const msg = + err.response?.data.message || + `Error while updating entity description.`; + showToast({ + variant: 'error', + body: msg, + }); + }); }; const columnsUpdateHandler = (updatedTable: Table) => { - saveUpdatedTableData(updatedTable).then((res: AxiosResponse) => { - const { columns, version } = res.data; - setCurrentVersion(version); - setTableDetails(res.data); - setColumns(columns); - setTableTags(getTableTags(columns || [])); - }); + saveUpdatedTableData(updatedTable) + .then((res: AxiosResponse) => { + const { columns, version } = res.data; + setCurrentVersion(version); + setTableDetails(res.data); + setColumns(columns); + setTableTags(getTableTags(columns || [])); + }) + .catch((err: AxiosError) => { + const msg = + err.response?.data.message || `Error while updating entity.`; + showToast({ + variant: 'error', + body: msg, + }); + }); }; const settingsUpdateHandler = (updatedTable: Table): Promise => { @@ -334,7 +353,15 @@ const DatasetDetailsPage: FunctionComponent = () => { setTier(getTierTags(tags)); resolve(); }) - .catch(() => reject()); + .catch((err: AxiosError) => { + const msg = + err.response?.data.message || `Error while updating entity.`; + reject(); + showToast({ + variant: 'error', + body: msg, + }); + }); }); }; @@ -346,13 +373,20 @@ const DatasetDetailsPage: FunctionComponent = () => { }); }; const unfollowTable = () => { - removeFollower(tableId, USERId).then((res: AxiosResponse) => { - const { oldValue } = res.data.changeDescription.fieldsDeleted[0]; + removeFollower(tableId, USERId) + .then((res: AxiosResponse) => { + const { oldValue } = res.data.changeDescription.fieldsDeleted[0]; - setFollowers( - followers.filter((follower) => follower.id !== oldValue[0].id) - ); - }); + setFollowers( + followers.filter((follower) => follower.id !== oldValue[0].id) + ); + }) + .catch(() => { + showToast({ + variant: 'error', + body: `Error while unfollowing entity.`, + }); + }); }; const versionHandler = () => { @@ -400,7 +434,7 @@ const DatasetDetailsPage: FunctionComponent = () => { .catch(() => { showToast({ variant: 'error', - body: `Error while adding adding new edge`, + body: `Error while adding adding new edge.`, }); reject(); }); @@ -416,7 +450,7 @@ const DatasetDetailsPage: FunctionComponent = () => { ).catch(() => { showToast({ variant: 'error', - body: `Error while removing edge`, + body: `Error while removing edge.`, }); }); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/PipelineDetails/PipelineDetailsPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/PipelineDetails/PipelineDetailsPage.component.tsx index 3b7306f04b6..c424a6d2a92 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/PipelineDetails/PipelineDetailsPage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/PipelineDetails/PipelineDetailsPage.component.tsx @@ -267,29 +267,58 @@ const PipelineDetailsPage = () => { }; const followPipeline = () => { - addFollower(pipelineId, USERId).then((res: AxiosResponse) => { - const { newValue } = res.data.changeDescription.fieldsAdded[0]; + addFollower(pipelineId, USERId) + .then((res: AxiosResponse) => { + const { newValue } = res.data.changeDescription.fieldsAdded[0]; - setFollowers([...followers, ...newValue]); - }); + setFollowers([...followers, ...newValue]); + }) + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || + 'Error while following pipeline entity.'; + showToast({ + variant: 'error', + body: errMsg, + }); + }); }; const unfollowPipeline = () => { - removeFollower(pipelineId, USERId).then((res: AxiosResponse) => { - const { oldValue } = res.data.changeDescription.fieldsDeleted[0]; + removeFollower(pipelineId, USERId) + .then((res: AxiosResponse) => { + const { oldValue } = res.data.changeDescription.fieldsDeleted[0]; - setFollowers( - followers.filter((follower) => follower.id !== oldValue[0].id) - ); - }); + setFollowers( + followers.filter((follower) => follower.id !== oldValue[0].id) + ); + }) + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || + 'Error while unfollowing pipeline entity.'; + showToast({ + variant: 'error', + body: errMsg, + }); + }); }; const descriptionUpdateHandler = (updatedPipeline: Pipeline) => { - saveUpdatedPipelineData(updatedPipeline).then((res: AxiosResponse) => { - const { description, version } = res.data; - setCurrentVersion(version); - setPipelineDetails(res.data); - setDescription(description); - }); + saveUpdatedPipelineData(updatedPipeline) + .then((res: AxiosResponse) => { + const { description, version } = res.data; + setCurrentVersion(version); + setPipelineDetails(res.data); + setDescription(description); + }) + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || 'Error while updating description.'; + showToast({ + variant: 'error', + body: errMsg, + }); + }); }; const settingsUpdateHandler = (updatedPipeline: Pipeline): Promise => { @@ -302,16 +331,33 @@ const PipelineDetailsPage = () => { setTier(getTierTags(res.data.tags)); resolve(); }) - .catch(() => reject()); + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || 'Error while updating entity.'; + reject(); + showToast({ + variant: 'error', + body: errMsg, + }); + }); }); }; const onTagUpdate = (updatedPipeline: Pipeline) => { - saveUpdatedPipelineData(updatedPipeline).then((res: AxiosResponse) => { - setTier(getTierTags(res.data.tags)); - setCurrentVersion(res.data.version); - setTags(getTagsWithoutTier(res.data.tags)); - }); + saveUpdatedPipelineData(updatedPipeline) + .then((res: AxiosResponse) => { + setTier(getTierTags(res.data.tags)); + setCurrentVersion(res.data.version); + setTags(getTagsWithoutTier(res.data.tags)); + }) + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || 'Error while updating tags.'; + showToast({ + variant: 'error', + body: errMsg, + }); + }); }; const onTaskUpdate = (jsonPatch: Array) => { diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TopicDetails/TopicDetailsPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TopicDetails/TopicDetailsPage.component.tsx index 0c9859e374b..4bd2d84303f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TopicDetails/TopicDetailsPage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TopicDetails/TopicDetailsPage.component.tsx @@ -206,29 +206,56 @@ const TopicDetailsPage: FunctionComponent = () => { }; const followTopic = () => { - addFollower(topicId, USERId).then((res: AxiosResponse) => { - const { newValue } = res.data.changeDescription.fieldsAdded[0]; + addFollower(topicId, USERId) + .then((res: AxiosResponse) => { + const { newValue } = res.data.changeDescription.fieldsAdded[0]; - setFollowers([...followers, ...newValue]); - }); + setFollowers([...followers, ...newValue]); + }) + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || 'Error while following entity.'; + showToast({ + variant: 'error', + body: errMsg, + }); + }); }; const unfollowTopic = () => { - removeFollower(topicId, USERId).then((res: AxiosResponse) => { - const { oldValue } = res.data.changeDescription.fieldsDeleted[0]; + removeFollower(topicId, USERId) + .then((res: AxiosResponse) => { + const { oldValue } = res.data.changeDescription.fieldsDeleted[0]; - setFollowers( - followers.filter((follower) => follower.id !== oldValue[0].id) - ); - }); + setFollowers( + followers.filter((follower) => follower.id !== oldValue[0].id) + ); + }) + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || 'Error while unfollowing entity.'; + showToast({ + variant: 'error', + body: errMsg, + }); + }); }; const descriptionUpdateHandler = (updatedTopic: Topic) => { - saveUpdatedTopicData(updatedTopic).then((res: AxiosResponse) => { - const { description, version } = res.data; - setCurrentVersion(version); - setTopicDetails(res.data); - setDescription(description); - }); + saveUpdatedTopicData(updatedTopic) + .then((res: AxiosResponse) => { + const { description, version } = res.data; + setCurrentVersion(version); + setTopicDetails(res.data); + setDescription(description); + }) + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || 'Error while updating description.'; + showToast({ + variant: 'error', + body: errMsg, + }); + }); }; const settingsUpdateHandler = (updatedTopic: Topic): Promise => { @@ -241,16 +268,33 @@ const TopicDetailsPage: FunctionComponent = () => { setTier(getTierTags(res.data.tags)); resolve(); }) - .catch(() => reject()); + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || 'Error while updating entity.'; + reject(); + showToast({ + variant: 'error', + body: errMsg, + }); + }); }); }; const onTagUpdate = (updatedTopic: Topic) => { - saveUpdatedTopicData(updatedTopic).then((res: AxiosResponse) => { - setTier(getTierTags(res.data.tags)); - setCurrentVersion(res.data.version); - setTags(getTagsWithoutTier(res.data.tags)); - }); + saveUpdatedTopicData(updatedTopic) + .then((res: AxiosResponse) => { + setTier(getTierTags(res.data.tags)); + setCurrentVersion(res.data.version); + setTags(getTagsWithoutTier(res.data.tags)); + }) + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || 'Error while updating tags.'; + showToast({ + variant: 'error', + body: errMsg, + }); + }); }; const versionHandler = () => { diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/database-details/index.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/database-details/index.tsx index 21a19c706cb..24c70c80305 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/database-details/index.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/database-details/index.tsx @@ -11,7 +11,7 @@ * limitations under the License. */ -import { AxiosResponse } from 'axios'; +import { AxiosError, AxiosResponse } from 'axios'; import classNames from 'classnames'; import { compare } from 'fast-json-patch'; import { isNil } from 'lodash'; @@ -26,6 +26,7 @@ import { } from '../../axiosAPIs/databaseAPI'; import { getDatabaseTables } from '../../axiosAPIs/tableAPI'; import Description from '../../components/common/description/Description'; +import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder'; import NextPrevious from '../../components/common/next-previous/NextPrevious'; import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer'; import TabsPane from '../../components/common/TabsPane/TabsPane'; @@ -43,7 +44,8 @@ import { import { ServiceCategory } from '../../enums/service.enum'; import { Database } from '../../generated/entity/data/database'; import { Table } from '../../generated/entity/data/table'; -import { isEven } from '../../utils/CommonUtils'; +import useToastContext from '../../hooks/useToastContext'; +import { getEntityMissingError, isEven } from '../../utils/CommonUtils'; import { serviceTypeLogo } from '../../utils/ServiceUtils'; import { getOwnerFromId, getUsagePercentile } from '../../utils/TableUtils'; import { getTableTags } from '../../utils/TagsUtils'; @@ -53,6 +55,7 @@ const DatabaseDetails: FunctionComponent = () => { const [slashedTableName, setSlashedTableName] = useState< TitleBreadcrumbProps['titleLinks'] >([]); + const showToast = useToastContext(); const { databaseFQN } = useParams() as Record; const [isLoading, setIsLoading] = useState(true); const [database, setDatabase] = useState(); @@ -69,6 +72,7 @@ const DatabaseDetails: FunctionComponent = () => { const [tableInstanceCount, setTableInstanceCount] = useState(0); const [activeTab, setActiveTab] = useState(1); + const [isError, setIsError] = useState(false); const history = useHistory(); const isMounting = useRef(true); @@ -121,35 +125,48 @@ const DatabaseDetails: FunctionComponent = () => { }; const getDetailsByFQN = () => { - getDatabaseDetailsByFQN(databaseFQN).then((res: AxiosResponse) => { - const { description, id, name, service, serviceType } = res.data; - setDatabase(res.data); - setDescription(description); - setDatabaseId(id); - setDatabaseName(name); + getDatabaseDetailsByFQN(databaseFQN) + .then((res: AxiosResponse) => { + const { description, id, name, service, serviceType } = res.data; + setDatabase(res.data); + setDescription(description); + setDatabaseId(id); + setDatabaseName(name); - setServiceType(serviceType); + setServiceType(serviceType); - setSlashedTableName([ - { - name: service.name, - url: service.name - ? getServiceDetailsPath( - service.name, - serviceType, - ServiceCategory.DATABASE_SERVICES - ) - : '', - imgSrc: serviceType ? serviceTypeLogo(serviceType) : undefined, - }, - { - name: name, - url: '', - activeTitle: true, - }, - ]); - }); - fetchDatabaseTablesAndDBTModels(); + setSlashedTableName([ + { + name: service.name, + url: service.name + ? getServiceDetailsPath( + service.name, + serviceType, + ServiceCategory.DATABASE_SERVICES + ) + : '', + imgSrc: serviceType ? serviceTypeLogo(serviceType) : undefined, + }, + { + name: name, + url: '', + activeTitle: true, + }, + ]); + fetchDatabaseTablesAndDBTModels(); + }) + .catch((err: AxiosError) => { + if (err.response?.status === 404) { + setIsError(true); + } else { + const errMsg = err.message || 'Error while fetching database details'; + showToast({ + variant: 'error', + body: errMsg, + }); + } + setIsLoading(false); + }); }; const onCancel = () => { @@ -176,11 +193,20 @@ const DatabaseDetails: FunctionComponent = () => { ...database, description: updatedHTML, }; - saveUpdatedDatabaseData(updatedDatabaseDetails).then(() => { - setDatabase(updatedDatabaseDetails); - setDescription(updatedHTML); - setIsEdit(false); - }); + saveUpdatedDatabaseData(updatedDatabaseDetails) + .then(() => { + setDatabase(updatedDatabaseDetails); + setDescription(updatedHTML); + setIsEdit(false); + }) + .catch((err: AxiosError) => { + const errMsg = + err.response?.data.message || 'Error while updating description'; + showToast({ + variant: 'error', + body: errMsg, + }); + }); } }; @@ -226,6 +252,10 @@ const DatabaseDetails: FunctionComponent = () => { <> {isLoading ? ( + ) : isError ? ( + + {getEntityMissingError('database', databaseFQN)} + ) : (
{ const [activeTab, setActiveTab] = useState(1); const [isConnectionAvailable, setConnectionAvailable] = useState(true); + const [isError, setIsError] = useState(false); const [ingestions, setIngestions] = useState([]); const [serviceList] = useState>([]); const [ingestionPaging, setIngestionPaging] = useState({} as Paging); @@ -261,7 +263,17 @@ const ServicePage: FunctionComponent = () => { resolve(); getAllIngestionWorkflows(); if (triggerIngestion) { - triggerIngestionById(id, displayName).then(); + triggerIngestionById(id, displayName) + .then() + .catch((err: AxiosError) => { + const msg = err.response?.data.message; + showToast({ + variant: 'error', + body: + msg ?? + `Error while triggring ingestion workflow ${displayName}`, + }); + }); } }) .catch((err: AxiosError) => { @@ -301,7 +313,17 @@ const ServicePage: FunctionComponent = () => { setIsloading(false); getAllIngestionWorkflows(); if (triggerIngestion) { - triggerIngestionById(id, displayName).then(); + triggerIngestionById(id, displayName) + .then() + .catch((err: AxiosError) => { + const msg = err.response?.data.message; + showToast({ + variant: 'error', + body: + msg ?? + `Error while triggring ingestion workflow ${displayName}`, + }); + }); } }) .catch((err: AxiosError) => { @@ -325,7 +347,14 @@ const ServicePage: FunctionComponent = () => { setServiceDetails(res.data); resolve(); }) - .catch(() => reject()); + .catch((err: AxiosError) => { + reject(); + const msg = err.response?.data.message; + showToast({ + variant: 'error', + body: msg ?? `Error while updating config for ${serviceFQN}`, + }); + }); }); }; @@ -600,8 +629,8 @@ const ServicePage: FunctionComponent = () => { }, [serviceCategory, serviceType]); useEffect(() => { - getServiceByFQN(serviceName, serviceFQN).then( - (resService: AxiosResponse) => { + getServiceByFQN(serviceName, serviceFQN) + .then((resService: AxiosResponse) => { const { description, serviceType } = resService.data; setServiceDetails(resService.data); setDescription(description); @@ -614,8 +643,21 @@ const ServicePage: FunctionComponent = () => { }, ]); getOtherDetails(); - } - ); + }) + .catch((err: AxiosError) => { + if (err.response?.status === 404) { + setIsError(true); + } else { + const errMsg = + err.response?.data.message || + 'Error while fetching service details'; + showToast({ + variant: 'error', + body: errMsg, + }); + } + setIsloading(false); + }); }, [serviceFQN, serviceName]); useEffect(() => { @@ -679,6 +721,10 @@ const ServicePage: FunctionComponent = () => { <> {isLoading ? ( + ) : isError ? ( + + {getEntityMissingError(serviceName as string, serviceFQN)} + ) : (