mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-10-31 02:29:03 +00:00 
			
		
		
		
	UI - feedback bug fixes and improvements (#12592)
* fixed loading issue in KPI widget on landing page * fixed redirection links for the notification box tabs * Fixed redirection issue after soft and hard deleting data assets * fixed version page layout issue * Fixed data model restore issue * Added loader to summary panel while fetching permissions * Fixed alerts settings page error placeholder alignment issue * changed the dashboard and pipeline url display method * fixed cypress test * updated the logic to perform the after delete action in DeleteWidgetModal * changed the logic to update the history object through util functions * added `experimentalMemoryManagement` to the cypress config * reverted the cypress config changes * fixed flaky test * worked on comments * removed unnecessary code
This commit is contained in:
		
							parent
							
								
									cb9e5d8b6f
								
							
						
					
					
						commit
						fe3766e106
					
				| @ -706,10 +706,12 @@ export const deleteSoftDeletedUser = (username) => { | |||||||
|   cy.get('[data-testid="search-error-placeholder"]').should('be.visible'); |   cy.get('[data-testid="search-error-placeholder"]').should('be.visible'); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const toastNotification = (msg) => { | export const toastNotification = (msg, closeToast = true) => { | ||||||
|   cy.get('.Toastify__toast-body').should('be.visible').contains(msg); |   cy.get('.Toastify__toast-body').should('be.visible').contains(msg); | ||||||
|   cy.wait(200); |   cy.wait(200); | ||||||
|   cy.get('.Toastify__close-button').should('be.visible').click(); |   if (closeToast) { | ||||||
|  |     cy.get('.Toastify__close-button').should('be.visible').click(); | ||||||
|  |   } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const addCustomPropertiesForEntity = ( | export const addCustomPropertiesForEntity = ( | ||||||
|  | |||||||
| @ -66,7 +66,7 @@ describe('Restore entity functionality should work properly', () => { | |||||||
|     cy.get('[data-testid="confirm-button"]').click(); |     cy.get('[data-testid="confirm-button"]').click(); | ||||||
|     verifyResponseStatusCode('@softDeleteTable', 200); |     verifyResponseStatusCode('@softDeleteTable', 200); | ||||||
| 
 | 
 | ||||||
|     toastNotification('Table deleted successfully!'); |     toastNotification('Table deleted successfully!', false); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   it('Check Soft Deleted entity table', () => { |   it('Check Soft Deleted entity table', () => { | ||||||
|  | |||||||
| @ -25,16 +25,17 @@ import { TOAST_OPTIONS } from 'constants/Toasts.constants'; | |||||||
| import React, { FunctionComponent } from 'react'; | import React, { FunctionComponent } from 'react'; | ||||||
| import { HelmetProvider } from 'react-helmet-async'; | import { HelmetProvider } from 'react-helmet-async'; | ||||||
| import { I18nextProvider } from 'react-i18next'; | import { I18nextProvider } from 'react-i18next'; | ||||||
| import { BrowserRouter as Router } from 'react-router-dom'; | import { Router } from 'react-router-dom'; | ||||||
| import { ToastContainer } from 'react-toastify'; | import { ToastContainer } from 'react-toastify'; | ||||||
| import 'react-toastify/dist/ReactToastify.min.css'; | import 'react-toastify/dist/ReactToastify.min.css'; | ||||||
|  | import { history } from 'utils/HistoryUtils'; | ||||||
| import i18n from 'utils/i18next/LocalUtil'; | import i18n from 'utils/i18next/LocalUtil'; | ||||||
| 
 | 
 | ||||||
| const App: FunctionComponent = () => { | const App: FunctionComponent = () => { | ||||||
|   return ( |   return ( | ||||||
|     <div className="main-container"> |     <div className="main-container"> | ||||||
|       <div className="content-wrapper" data-testid="content-wrapper"> |       <div className="content-wrapper" data-testid="content-wrapper"> | ||||||
|         <Router> |         <Router history={history}> | ||||||
|           <I18nextProvider i18n={i18n}> |           <I18nextProvider i18n={i18n}> | ||||||
|             <ErrorBoundary> |             <ErrorBoundary> | ||||||
|               <ApplicationConfigProvider> |               <ApplicationConfigProvider> | ||||||
|  | |||||||
| @ -67,6 +67,7 @@ import { | |||||||
| import { withActivityFeed } from 'components/router/withActivityFeed'; | import { withActivityFeed } from 'components/router/withActivityFeed'; | ||||||
| import TableDescription from 'components/TableDescription/TableDescription.component'; | import TableDescription from 'components/TableDescription/TableDescription.component'; | ||||||
| import { DisplayType } from 'components/Tag/TagsViewer/TagsViewer.interface'; | import { DisplayType } from 'components/Tag/TagsViewer/TagsViewer.interface'; | ||||||
|  | import { handleDataAssetAfterDeleteAction } from 'utils/Assets/AssetsUtils'; | ||||||
| 
 | 
 | ||||||
| const DashboardDetails = ({ | const DashboardDetails = ({ | ||||||
|   charts, |   charts, | ||||||
| @ -723,6 +724,7 @@ const DashboardDetails = ({ | |||||||
|       <Row gutter={[0, 12]}> |       <Row gutter={[0, 12]}> | ||||||
|         <Col className="p-x-lg" span={24}> |         <Col className="p-x-lg" span={24}> | ||||||
|           <DataAssetsHeader |           <DataAssetsHeader | ||||||
|  |             afterDeleteAction={handleDataAssetAfterDeleteAction} | ||||||
|             dataAsset={dashboardDetails} |             dataAsset={dashboardDetails} | ||||||
|             entityType={EntityType.DASHBOARD} |             entityType={EntityType.DASHBOARD} | ||||||
|             permissions={dashboardPermissions} |             permissions={dashboardPermissions} | ||||||
|  | |||||||
| @ -104,6 +104,7 @@ export const ExtraInfoLink = ({ | |||||||
| 
 | 
 | ||||||
| export const DataAssetsHeader = ({ | export const DataAssetsHeader = ({ | ||||||
|   allowSoftDelete = true, |   allowSoftDelete = true, | ||||||
|  |   afterDeleteAction, | ||||||
|   dataAsset, |   dataAsset, | ||||||
|   onOwnerUpdate, |   onOwnerUpdate, | ||||||
|   onTierUpdate, |   onTierUpdate, | ||||||
| @ -403,6 +404,7 @@ export const DataAssetsHeader = ({ | |||||||
|                   /> |                   /> | ||||||
|                 </Tooltip> |                 </Tooltip> | ||||||
|                 <ManageButton |                 <ManageButton | ||||||
|  |                   afterDeleteAction={afterDeleteAction} | ||||||
|                   allowSoftDelete={!dataAsset.deleted && allowSoftDelete} |                   allowSoftDelete={!dataAsset.deleted && allowSoftDelete} | ||||||
|                   canDelete={permissions.Delete} |                   canDelete={permissions.Delete} | ||||||
|                   deleted={dataAsset.deleted} |                   deleted={dataAsset.deleted} | ||||||
|  | |||||||
| @ -75,6 +75,7 @@ export type DataAssetsHeaderProps = { | |||||||
|   permissions: OperationPermission; |   permissions: OperationPermission; | ||||||
|   allowSoftDelete?: boolean; |   allowSoftDelete?: boolean; | ||||||
|   isRecursiveDelete?: boolean; |   isRecursiveDelete?: boolean; | ||||||
|  |   afterDeleteAction?: (isSoftDelete?: boolean) => void; | ||||||
|   onTierUpdate: (tier?: string) => Promise<void>; |   onTierUpdate: (tier?: string) => Promise<void>; | ||||||
|   onOwnerUpdate: (owner?: EntityReference) => Promise<void>; |   onOwnerUpdate: (owner?: EntityReference) => Promise<void>; | ||||||
|   onVersionClick?: () => void; |   onVersionClick?: () => void; | ||||||
|  | |||||||
| @ -37,7 +37,7 @@ function DataAssetsVersionHeader({ | |||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Row className="p-x-lg" gutter={[8, 12]} justify="space-between"> |     <Row className="p-x-lg" gutter={[8, 12]} justify="space-between"> | ||||||
|       <Col className="self-center"> |       <Col className="self-center" span={21}> | ||||||
|         <Row gutter={[16, 12]}> |         <Row gutter={[16, 12]}> | ||||||
|           <Col span={24}> |           <Col span={24}> | ||||||
|             <TitleBreadcrumb titleLinks={breadcrumbLinks} /> |             <TitleBreadcrumb titleLinks={breadcrumbLinks} /> | ||||||
| @ -83,14 +83,18 @@ function DataAssetsVersionHeader({ | |||||||
|           </Col> |           </Col> | ||||||
|         </Row> |         </Row> | ||||||
|       </Col> |       </Col> | ||||||
|       <Col> |       <Col span={3}> | ||||||
|         <Button |         <Row justify="end"> | ||||||
|           className="w-16 p-0" |           <Col> | ||||||
|           data-testid="version-button" |             <Button | ||||||
|           icon={<Icon component={VersionIcon} />} |               className="w-16 p-0" | ||||||
|           onClick={onVersionClick}> |               data-testid="version-button" | ||||||
|           <Typography.Text>{version}</Typography.Text> |               icon={<Icon component={VersionIcon} />} | ||||||
|         </Button> |               onClick={onVersionClick}> | ||||||
|  |               <Typography.Text>{version}</Typography.Text> | ||||||
|  |             </Button> | ||||||
|  |           </Col> | ||||||
|  |         </Row> | ||||||
|       </Col> |       </Col> | ||||||
|     </Row> |     </Row> | ||||||
|   ); |   ); | ||||||
|  | |||||||
| @ -43,6 +43,7 @@ import KPILatestResultsV1 from './KPILatestResultsV1'; | |||||||
| interface Props { | interface Props { | ||||||
|   kpiList: Array<Kpi>; |   kpiList: Array<Kpi>; | ||||||
|   selectedDays: number; |   selectedDays: number; | ||||||
|  |   isKPIListLoading: boolean; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const EmptyPlaceholder = () => { | const EmptyPlaceholder = () => { | ||||||
| @ -78,13 +79,13 @@ const EmptyPlaceholder = () => { | |||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const KPIChartV1: FC<Props> = ({ kpiList, selectedDays }) => { | const KPIChartV1: FC<Props> = ({ isKPIListLoading, kpiList, selectedDays }) => { | ||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
| 
 | 
 | ||||||
|   const [kpiResults, setKpiResults] = useState<KpiResult[]>([]); |   const [kpiResults, setKpiResults] = useState<KpiResult[]>([]); | ||||||
|   const [kpiLatestResults, setKpiLatestResults] = |   const [kpiLatestResults, setKpiLatestResults] = | ||||||
|     useState<Record<string, UIKpiResult>>(); |     useState<Record<string, UIKpiResult>>(); | ||||||
|   const [isLoading, setIsLoading] = useState<boolean>(true); |   const [isLoading, setIsLoading] = useState<boolean>(false); | ||||||
| 
 | 
 | ||||||
|   const fetchKpiResults = useCallback(async () => { |   const fetchKpiResults = useCallback(async () => { | ||||||
|     setIsLoading(true); |     setIsLoading(true); | ||||||
| @ -180,7 +181,7 @@ const KPIChartV1: FC<Props> = ({ kpiList, selectedDays }) => { | |||||||
|       className="kpi-widget-card h-full" |       className="kpi-widget-card h-full" | ||||||
|       data-testid="kpi-card" |       data-testid="kpi-card" | ||||||
|       id="kpi-charts" |       id="kpi-charts" | ||||||
|       loading={isLoading}> |       loading={isKPIListLoading || isLoading}> | ||||||
|       <Row> |       <Row> | ||||||
|         <Col span={24}> |         <Col span={24}> | ||||||
|           <Typography.Text className="font-medium"> |           <Typography.Text className="font-medium"> | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| import { Card, Col, Row, Space, Tabs } from 'antd'; | import { Card, Col, Row, Space, Tabs } from 'antd'; | ||||||
|  | import { AxiosError } from 'axios'; | ||||||
| import { useActivityFeedProvider } from 'components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider'; | import { useActivityFeedProvider } from 'components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider'; | ||||||
| import { ActivityFeedTab } from 'components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.component'; | import { ActivityFeedTab } from 'components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.component'; | ||||||
| import ActivityThreadPanel from 'components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel'; | import ActivityThreadPanel from 'components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel'; | ||||||
| @ -37,10 +38,13 @@ import { EntityTags } from 'Models'; | |||||||
| import React, { useEffect, useMemo, useState } from 'react'; | import React, { useEffect, useMemo, useState } from 'react'; | ||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| import { useHistory, useParams } from 'react-router-dom'; | import { useHistory, useParams } from 'react-router-dom'; | ||||||
| import { getFeedCounts } from 'utils/CommonUtils'; | import { restoreDataModel } from 'rest/dataModelsAPI'; | ||||||
|  | import { handleDataAssetAfterDeleteAction } from 'utils/Assets/AssetsUtils'; | ||||||
|  | import { getFeedCounts, refreshPage } from 'utils/CommonUtils'; | ||||||
| import { getEntityName, getEntityThreadLink } from 'utils/EntityUtils'; | import { getEntityName, getEntityThreadLink } from 'utils/EntityUtils'; | ||||||
| import { getEntityFieldThreadCounts } from 'utils/FeedUtils'; | import { getEntityFieldThreadCounts } from 'utils/FeedUtils'; | ||||||
| import { getTagsWithoutTier } from 'utils/TableUtils'; | import { getTagsWithoutTier } from 'utils/TableUtils'; | ||||||
|  | import { showErrorToast, showSuccessToast } from 'utils/ToastUtils'; | ||||||
| import { DataModelDetailsProps } from './DataModelDetails.interface'; | import { DataModelDetailsProps } from './DataModelDetails.interface'; | ||||||
| import ModelTab from './ModelTab/ModelTab.component'; | import ModelTab from './ModelTab/ModelTab.component'; | ||||||
| 
 | 
 | ||||||
| @ -159,6 +163,26 @@ const DataModelDetails = ({ | |||||||
|     handleUpdateTags(updatedTags); |     handleUpdateTags(updatedTags); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |   const handleRestoreDataModel = async () => { | ||||||
|  |     try { | ||||||
|  |       await restoreDataModel(dataModelData.id ?? ''); | ||||||
|  |       showSuccessToast( | ||||||
|  |         t('message.restore-entities-success', { | ||||||
|  |           entity: t('label.data-model'), | ||||||
|  |         }), | ||||||
|  |         2000 | ||||||
|  |       ); | ||||||
|  |       refreshPage(); | ||||||
|  |     } catch (error) { | ||||||
|  |       showErrorToast( | ||||||
|  |         error as AxiosError, | ||||||
|  |         t('message.restore-entities-error', { | ||||||
|  |           entity: t('label.data-model'), | ||||||
|  |         }) | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|   const modelComponent = useMemo(() => { |   const modelComponent = useMemo(() => { | ||||||
|     return ( |     return ( | ||||||
|       <Row gutter={[0, 16]} wrap={false}> |       <Row gutter={[0, 16]} wrap={false}> | ||||||
| @ -335,13 +359,14 @@ const DataModelDetails = ({ | |||||||
|       <Row gutter={[0, 12]}> |       <Row gutter={[0, 12]}> | ||||||
|         <Col className="p-x-lg" span={24}> |         <Col className="p-x-lg" span={24}> | ||||||
|           <DataAssetsHeader |           <DataAssetsHeader | ||||||
|  |             afterDeleteAction={handleDataAssetAfterDeleteAction} | ||||||
|             dataAsset={dataModelData} |             dataAsset={dataModelData} | ||||||
|             entityType={EntityType.DASHBOARD_DATA_MODEL} |             entityType={EntityType.DASHBOARD_DATA_MODEL} | ||||||
|             permissions={dataModelPermissions} |             permissions={dataModelPermissions} | ||||||
|             onDisplayNameUpdate={handleUpdateDisplayName} |             onDisplayNameUpdate={handleUpdateDisplayName} | ||||||
|             onFollowClick={handleFollowDataModel} |             onFollowClick={handleFollowDataModel} | ||||||
|             onOwnerUpdate={handleUpdateOwner} |             onOwnerUpdate={handleUpdateOwner} | ||||||
|             onRestoreDataAsset={() => Promise.resolve()} |             onRestoreDataAsset={handleRestoreDataModel} | ||||||
|             onTierUpdate={handleUpdateTier} |             onTierUpdate={handleUpdateTier} | ||||||
|             onVersionClick={versionHandler} |             onVersionClick={versionHandler} | ||||||
|           /> |           /> | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ | |||||||
| 
 | 
 | ||||||
| import { Drawer, Typography } from 'antd'; | import { Drawer, Typography } from 'antd'; | ||||||
| import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder'; | import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder'; | ||||||
|  | import Loader from 'components/Loader/Loader'; | ||||||
| import { usePermissionProvider } from 'components/PermissionProvider/PermissionProvider'; | import { usePermissionProvider } from 'components/PermissionProvider/PermissionProvider'; | ||||||
| import { | import { | ||||||
|   OperationPermission, |   OperationPermission, | ||||||
| @ -51,18 +52,22 @@ export default function EntitySummaryPanel({ | |||||||
|   const { tab } = useParams<{ tab: string }>(); |   const { tab } = useParams<{ tab: string }>(); | ||||||
| 
 | 
 | ||||||
|   const { getEntityPermission } = usePermissionProvider(); |   const { getEntityPermission } = usePermissionProvider(); | ||||||
| 
 |   const [isPermissionLoading, setIsPermissionLoading] = | ||||||
|  |     useState<boolean>(false); | ||||||
|   const [entityPermissions, setEntityPermissions] = |   const [entityPermissions, setEntityPermissions] = | ||||||
|     useState<OperationPermission>(DEFAULT_ENTITY_PERMISSION); |     useState<OperationPermission>(DEFAULT_ENTITY_PERMISSION); | ||||||
| 
 | 
 | ||||||
|   const fetchResourcePermission = async (entityFqn: string) => { |   const fetchResourcePermission = async (entityFqn: string) => { | ||||||
|     try { |     try { | ||||||
|  |       setIsPermissionLoading(true); | ||||||
|       const type = |       const type = | ||||||
|         get(entityDetails, 'details.entityType') ?? ResourceEntity.TABLE; |         get(entityDetails, 'details.entityType') ?? ResourceEntity.TABLE; | ||||||
|       const permissions = await getEntityPermission(type, entityFqn); |       const permissions = await getEntityPermission(type, entityFqn); | ||||||
|       setEntityPermissions(permissions); |       setEntityPermissions(permissions); | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|       // Error
 |       // Error
 | ||||||
|  |     } finally { | ||||||
|  |       setIsPermissionLoading(false); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| @ -78,6 +83,9 @@ export default function EntitySummaryPanel({ | |||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   const summaryComponent = useMemo(() => { |   const summaryComponent = useMemo(() => { | ||||||
|  |     if (isPermissionLoading) { | ||||||
|  |       return <Loader />; | ||||||
|  |     } | ||||||
|     if (!viewPermission) { |     if (!viewPermission) { | ||||||
|       return ( |       return ( | ||||||
|         <ErrorPlaceHolder |         <ErrorPlaceHolder | ||||||
| @ -117,7 +125,7 @@ export default function EntitySummaryPanel({ | |||||||
|       default: |       default: | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|   }, [tab, entityDetails, viewPermission]); |   }, [tab, entityDetails, viewPermission, isPermissionLoading]); | ||||||
| 
 | 
 | ||||||
|   const entityLink = useMemo( |   const entityLink = useMemo( | ||||||
|     () => |     () => | ||||||
|  | |||||||
| @ -22,14 +22,18 @@ import './kpi-widget.less'; | |||||||
| 
 | 
 | ||||||
| const KPIWidget = () => { | const KPIWidget = () => { | ||||||
|   const [kpiList, setKpiList] = useState<Array<Kpi>>([]); |   const [kpiList, setKpiList] = useState<Array<Kpi>>([]); | ||||||
|  |   const [isKPIListLoading, setIsKPIListLoading] = useState<boolean>(false); | ||||||
| 
 | 
 | ||||||
|   const fetchKpiList = async () => { |   const fetchKpiList = async () => { | ||||||
|     try { |     try { | ||||||
|  |       setIsKPIListLoading(true); | ||||||
|       const response = await getListKPIs({ fields: 'dataInsightChart' }); |       const response = await getListKPIs({ fields: 'dataInsightChart' }); | ||||||
|       setKpiList(response.data); |       setKpiList(response.data); | ||||||
|     } catch (_err) { |     } catch (_err) { | ||||||
|       setKpiList([]); |       setKpiList([]); | ||||||
|       showErrorToast(_err as AxiosError); |       showErrorToast(_err as AxiosError); | ||||||
|  |     } finally { | ||||||
|  |       setIsKPIListLoading(false); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| @ -41,7 +45,11 @@ const KPIWidget = () => { | |||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div className="kpi-widget-container h-full"> |     <div className="kpi-widget-container h-full"> | ||||||
|       <KPIChartV1 kpiList={kpiList} selectedDays={CHART_WIDGET_DAYS_DURATION} /> |       <KPIChartV1 | ||||||
|  |         isKPIListLoading={isKPIListLoading} | ||||||
|  |         kpiList={kpiList} | ||||||
|  |         selectedDays={CHART_WIDGET_DAYS_DURATION} | ||||||
|  |       /> | ||||||
|     </div> |     </div> | ||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -34,6 +34,7 @@ import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; | |||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| import { useHistory, useParams } from 'react-router-dom'; | import { useHistory, useParams } from 'react-router-dom'; | ||||||
| import { restoreMlmodel } from 'rest/mlModelAPI'; | import { restoreMlmodel } from 'rest/mlModelAPI'; | ||||||
|  | import { handleDataAssetAfterDeleteAction } from 'utils/Assets/AssetsUtils'; | ||||||
| import { getEntityName, getEntityThreadLink } from 'utils/EntityUtils'; | import { getEntityName, getEntityThreadLink } from 'utils/EntityUtils'; | ||||||
| import AppState from '../../AppState'; | import AppState from '../../AppState'; | ||||||
| import { getMlModelDetailsPath } from '../../constants/constants'; | import { getMlModelDetailsPath } from '../../constants/constants'; | ||||||
| @ -555,6 +556,7 @@ const MlModelDetail: FC<MlModelDetailProp> = ({ | |||||||
|       <Row gutter={[0, 12]}> |       <Row gutter={[0, 12]}> | ||||||
|         <Col className="p-x-lg" span={24}> |         <Col className="p-x-lg" span={24}> | ||||||
|           <DataAssetsHeader |           <DataAssetsHeader | ||||||
|  |             afterDeleteAction={handleDataAssetAfterDeleteAction} | ||||||
|             dataAsset={mlModelDetail} |             dataAsset={mlModelDetail} | ||||||
|             entityType={EntityType.MLMODEL} |             entityType={EntityType.MLMODEL} | ||||||
|             permissions={mlModelPermissions} |             permissions={mlModelPermissions} | ||||||
|  | |||||||
| @ -15,7 +15,6 @@ import { Badge, Button, List, Tabs, Typography } from 'antd'; | |||||||
| import { AxiosError } from 'axios'; | import { AxiosError } from 'axios'; | ||||||
| import { ActivityFeedTabs } from 'components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface'; | import { ActivityFeedTabs } from 'components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface'; | ||||||
| import { EntityTabs } from 'enums/entity.enum'; | import { EntityTabs } from 'enums/entity.enum'; | ||||||
| import { UserProfileTab } from 'enums/user.enum'; |  | ||||||
| import { isEmpty } from 'lodash'; | import { isEmpty } from 'lodash'; | ||||||
| import React, { useCallback, useEffect, useMemo, useState } from 'react'; | import React, { useCallback, useEffect, useMemo, useState } from 'react'; | ||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| @ -62,7 +61,7 @@ const NotificationBox = ({ | |||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   const notificationDropDownList = useMemo(() => { |   const notificationDropDownList = useMemo(() => { | ||||||
|     return notifications.slice(0, 5).map((feed, idx) => { |     return notifications.slice(0, 5).map((feed) => { | ||||||
|       const mainFeed = { |       const mainFeed = { | ||||||
|         message: feed.message, |         message: feed.message, | ||||||
|         postTs: feed.threadTs, |         postTs: feed.threadTs, | ||||||
| @ -79,7 +78,7 @@ const NotificationBox = ({ | |||||||
|           entityFQN={entityFQN as string} |           entityFQN={entityFQN as string} | ||||||
|           entityType={entityType as string} |           entityType={entityType as string} | ||||||
|           feedType={feed.type || ThreadType.Conversation} |           feedType={feed.type || ThreadType.Conversation} | ||||||
|           key={`${mainFeed.from} ${idx}`} |           key={`${mainFeed.from} ${mainFeed.id}`} | ||||||
|           task={feed} |           task={feed} | ||||||
|           timestamp={mainFeed.postTs} |           timestamp={mainFeed.postTs} | ||||||
|         /> |         /> | ||||||
| @ -117,11 +116,13 @@ const NotificationBox = ({ | |||||||
|       getNotificationData(threadType, feedFilter); |       getNotificationData(threadType, feedFilter); | ||||||
| 
 | 
 | ||||||
|       setViewAllPath( |       setViewAllPath( | ||||||
|         `${getUserPath(currentUser?.name as string)}/${(threadType === |         getUserPath( | ||||||
|         ThreadType.Conversation |           currentUser?.name as string, | ||||||
|           ? UserProfileTab.ACTIVITY |           EntityTabs.ACTIVITY_FEED, | ||||||
|           : threadType |           key === NotificationTabsKey.TASK | ||||||
|         ).toLowerCase()}?feedFilter=${feedFilter}` |             ? ActivityFeedTabs.TASKS | ||||||
|  |             : ActivityFeedTabs.MENTIONS | ||||||
|  |         ) | ||||||
|       ); |       ); | ||||||
| 
 | 
 | ||||||
|       if (hasTaskNotification || hasMentionNotification) { |       if (hasTaskNotification || hasMentionNotification) { | ||||||
| @ -132,7 +133,7 @@ const NotificationBox = ({ | |||||||
|         }, NOTIFICATION_READ_TIMER); |         }, NOTIFICATION_READ_TIMER); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     [currentUser, hasTaskNotification, hasMentionNotification] |     [onTabChange, currentUser, hasTaskNotification, hasMentionNotification] | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
| @ -187,7 +188,7 @@ const NotificationBox = ({ | |||||||
|           size="small" |           size="small" | ||||||
|         /> |         /> | ||||||
|       ), |       ), | ||||||
|     [notifications] |     [notifications, notificationDropDownList, viewAllPath] | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|  | |||||||
| @ -43,6 +43,7 @@ import { useTranslation } from 'react-i18next'; | |||||||
| import { Link, useHistory, useParams } from 'react-router-dom'; | import { Link, useHistory, useParams } from 'react-router-dom'; | ||||||
| import { postThread } from 'rest/feedsAPI'; | import { postThread } from 'rest/feedsAPI'; | ||||||
| import { restorePipeline } from 'rest/pipelineAPI'; | import { restorePipeline } from 'rest/pipelineAPI'; | ||||||
|  | import { handleDataAssetAfterDeleteAction } from 'utils/Assets/AssetsUtils'; | ||||||
| import { ReactComponent as ExternalLinkIcon } from '../../assets/svg/external-links.svg'; | import { ReactComponent as ExternalLinkIcon } from '../../assets/svg/external-links.svg'; | ||||||
| import { | import { | ||||||
|   getPipelineDetailsPath, |   getPipelineDetailsPath, | ||||||
| @ -746,6 +747,7 @@ const PipelineDetails = ({ | |||||||
|       <Row gutter={[0, 12]}> |       <Row gutter={[0, 12]}> | ||||||
|         <Col className="p-x-lg" span={24}> |         <Col className="p-x-lg" span={24}> | ||||||
|           <DataAssetsHeader |           <DataAssetsHeader | ||||||
|  |             afterDeleteAction={handleDataAssetAfterDeleteAction} | ||||||
|             dataAsset={pipelineDetails} |             dataAsset={pipelineDetails} | ||||||
|             entityType={EntityType.PIPELINE} |             entityType={EntityType.PIPELINE} | ||||||
|             permissions={pipelinePermissions} |             permissions={pipelinePermissions} | ||||||
|  | |||||||
| @ -36,6 +36,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; | |||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| import { useHistory, useParams } from 'react-router-dom'; | import { useHistory, useParams } from 'react-router-dom'; | ||||||
| import { restoreTopic } from 'rest/topicsAPI'; | import { restoreTopic } from 'rest/topicsAPI'; | ||||||
|  | import { handleDataAssetAfterDeleteAction } from 'utils/Assets/AssetsUtils'; | ||||||
| import { getEntityName, getEntityThreadLink } from 'utils/EntityUtils'; | import { getEntityName, getEntityThreadLink } from 'utils/EntityUtils'; | ||||||
| import { EntityField } from '../../constants/Feeds.constants'; | import { EntityField } from '../../constants/Feeds.constants'; | ||||||
| import { EntityTabs, EntityType } from '../../enums/entity.enum'; | import { EntityTabs, EntityType } from '../../enums/entity.enum'; | ||||||
| @ -450,6 +451,7 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({ | |||||||
|       <Row gutter={[0, 12]}> |       <Row gutter={[0, 12]}> | ||||||
|         <Col className="p-x-lg" span={24}> |         <Col className="p-x-lg" span={24}> | ||||||
|           <DataAssetsHeader |           <DataAssetsHeader | ||||||
|  |             afterDeleteAction={handleDataAssetAfterDeleteAction} | ||||||
|             dataAsset={topicDetails} |             dataAsset={topicDetails} | ||||||
|             entityType={EntityType.TOPIC} |             entityType={EntityType.TOPIC} | ||||||
|             permissions={topicPermissions} |             permissions={topicPermissions} | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ export interface DeleteWidgetModalProps { | |||||||
|   entityId?: string; |   entityId?: string; | ||||||
|   prepareType?: boolean; |   prepareType?: boolean; | ||||||
|   isRecursiveDelete?: boolean; |   isRecursiveDelete?: boolean; | ||||||
|   afterDeleteAction?: () => void; |   afterDeleteAction?: (isSoftDelete?: boolean) => void; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface DeleteSectionProps { | export interface DeleteSectionProps { | ||||||
|  | |||||||
| @ -22,15 +22,13 @@ import React, { | |||||||
|   useState, |   useState, | ||||||
| } from 'react'; | } from 'react'; | ||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| import { useHistory } from 'react-router-dom'; |  | ||||||
| import { deleteEntity } from 'rest/miscAPI'; | import { deleteEntity } from 'rest/miscAPI'; | ||||||
| import { ENTITY_DELETE_STATE } from '../../../constants/entity.constants'; |  | ||||||
| import { EntityType } from '../../../enums/entity.enum'; |  | ||||||
| import { | import { | ||||||
|   getEntityDeleteMessage, |   getDeleteMessage, | ||||||
|   Transi18next, |   prepareEntityType, | ||||||
| } from '../../../utils/CommonUtils'; | } from 'utils/DeleteWidgetModalUtils'; | ||||||
| import { getTitleCase } from '../../../utils/EntityUtils'; | import { ENTITY_DELETE_STATE } from '../../../constants/entity.constants'; | ||||||
|  | import { Transi18next } from '../../../utils/CommonUtils'; | ||||||
| import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils'; | import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils'; | ||||||
| import { DeleteType, DeleteWidgetModalProps } from './DeleteWidget.interface'; | import { DeleteType, DeleteWidgetModalProps } from './DeleteWidget.interface'; | ||||||
| 
 | 
 | ||||||
| @ -49,7 +47,6 @@ const DeleteWidgetModal = ({ | |||||||
|   afterDeleteAction, |   afterDeleteAction, | ||||||
| }: DeleteWidgetModalProps) => { | }: DeleteWidgetModalProps) => { | ||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|   const history = useHistory(); |  | ||||||
|   const [entityDeleteState, setEntityDeleteState] = |   const [entityDeleteState, setEntityDeleteState] = | ||||||
|     useState<typeof ENTITY_DELETE_STATE>(ENTITY_DELETE_STATE); |     useState<typeof ENTITY_DELETE_STATE>(ENTITY_DELETE_STATE); | ||||||
|   const [name, setName] = useState<string>(''); |   const [name, setName] = useState<string>(''); | ||||||
| @ -58,123 +55,95 @@ const DeleteWidgetModal = ({ | |||||||
|   ); |   ); | ||||||
|   const [isLoading, setIsLoading] = useState(false); |   const [isLoading, setIsLoading] = useState(false); | ||||||
| 
 | 
 | ||||||
|   const prepareDeleteMessage = (softDelete = false) => { |   const DELETE_OPTION = useMemo( | ||||||
|     const softDeleteText = t('message.soft-delete-message-for-entity', { |     () => [ | ||||||
|       entity: entityName, |       { | ||||||
|     }); |         title: `${t('label.delete')} ${entityType} “${entityName}”`, | ||||||
|     const hardDeleteText = getEntityDeleteMessage(getTitleCase(entityType), ''); |         description: `${getDeleteMessage( | ||||||
|  |           entityName, | ||||||
|  |           entityType, | ||||||
|  |           true | ||||||
|  |         )} ${softDeleteMessagePostFix}`,
 | ||||||
|  |         type: DeleteType.SOFT_DELETE, | ||||||
|  |         isAllowed: allowSoftDelete, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         title: `${t('label.permanently-delete')} ${entityType} “${entityName}”`, | ||||||
|  |         description: `${ | ||||||
|  |           deleteMessage || getDeleteMessage(entityName, entityType) | ||||||
|  |         } ${hardDeleteMessagePostFix}`,
 | ||||||
|  |         type: DeleteType.HARD_DELETE, | ||||||
|  |         isAllowed: true, | ||||||
|  |       }, | ||||||
|  |     ], | ||||||
|  |     [ | ||||||
|  |       entityType, | ||||||
|  |       entityName, | ||||||
|  |       softDeleteMessagePostFix, | ||||||
|  |       allowSoftDelete, | ||||||
|  |       deleteMessage, | ||||||
|  |       hardDeleteMessagePostFix, | ||||||
|  |     ] | ||||||
|  |   ); | ||||||
| 
 | 
 | ||||||
|     return softDelete ? softDeleteText : hardDeleteText; |   const handleOnChange = useCallback((e: ChangeEvent<HTMLInputElement>) => { | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const DELETE_OPTION = [ |  | ||||||
|     { |  | ||||||
|       title: `${t('label.delete')} ${entityType} “${entityName}”`, |  | ||||||
|       description: `${prepareDeleteMessage(true)} ${softDeleteMessagePostFix}`, |  | ||||||
|       type: DeleteType.SOFT_DELETE, |  | ||||||
|       isAllowd: allowSoftDelete, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       title: `${t('label.permanently-delete')} ${entityType} “${entityName}”`, |  | ||||||
|       description: `${ |  | ||||||
|         deleteMessage || prepareDeleteMessage() |  | ||||||
|       } ${hardDeleteMessagePostFix}`,
 |  | ||||||
|       type: DeleteType.HARD_DELETE, |  | ||||||
|       isAllowd: true, |  | ||||||
|     }, |  | ||||||
|   ]; |  | ||||||
| 
 |  | ||||||
|   const handleOnChange = (e: ChangeEvent<HTMLInputElement>) => { |  | ||||||
|     setName(e.target.value); |     setName(e.target.value); | ||||||
|   }; |   }, []); | ||||||
| 
 | 
 | ||||||
|   const handleOnEntityDelete = (softDelete = true) => { |   const handleOnEntityDelete = useCallback((softDelete = true) => { | ||||||
|     setEntityDeleteState((prev) => ({ ...prev, state: true, softDelete })); |     setEntityDeleteState((prev) => ({ ...prev, state: true, softDelete })); | ||||||
|   }; |   }, []); | ||||||
| 
 | 
 | ||||||
|   const handleOnEntityDeleteCancel = () => { |   const handleOnEntityDeleteCancel = useCallback(() => { | ||||||
|     setEntityDeleteState(ENTITY_DELETE_STATE); |     setEntityDeleteState(ENTITY_DELETE_STATE); | ||||||
|     setName(''); |     setName(''); | ||||||
|     setValue(DeleteType.SOFT_DELETE); |     setValue(DeleteType.SOFT_DELETE); | ||||||
|     onCancel(); |     onCancel(); | ||||||
|   }; |   }, [onCancel]); | ||||||
| 
 | 
 | ||||||
|   const prepareEntityType = () => { |   const handleOnEntityDeleteConfirm = useCallback(async () => { | ||||||
|     const services = [ |     try { | ||||||
|       EntityType.DASHBOARD_SERVICE, |       setIsLoading(false); | ||||||
|       EntityType.DATABASE_SERVICE, |       setEntityDeleteState((prev) => ({ ...prev, loading: 'waiting' })); | ||||||
|       EntityType.MESSAGING_SERVICE, |       const response = await deleteEntity( | ||||||
|       EntityType.PIPELINE_SERVICE, |         prepareType ? prepareEntityType(entityType) : entityType, | ||||||
|       EntityType.METADATA_SERVICE, |         entityId ?? '', | ||||||
|       EntityType.STORAGE_SERVICE, |         Boolean(isRecursiveDelete), | ||||||
|       EntityType.MLMODEL_SERVICE, |         !entityDeleteState.softDelete | ||||||
|     ]; |       ); | ||||||
| 
 | 
 | ||||||
|     const dataQuality = [EntityType.TEST_SUITE, EntityType.TEST_CASE]; |       if (response.status === 200) { | ||||||
| 
 |         showSuccessToast( | ||||||
|     if (services.includes((entityType || '') as EntityType)) { |           t('server.entity-deleted-successfully', { | ||||||
|       return `services/${entityType}s`; |             entity: startCase(entityType), | ||||||
|     } else if (entityType === EntityType.GLOSSARY) { |  | ||||||
|       return `glossaries`; |  | ||||||
|     } else if (entityType === EntityType.POLICY) { |  | ||||||
|       return 'policies'; |  | ||||||
|     } else if (entityType === EntityType.KPI) { |  | ||||||
|       return entityType; |  | ||||||
|     } else if (entityType === EntityType.DASHBOARD_DATA_MODEL) { |  | ||||||
|       return `dashboard/datamodels`; |  | ||||||
|     } else if (dataQuality.includes(entityType as EntityType)) { |  | ||||||
|       return `dataQuality/${entityType}s`; |  | ||||||
|     } else if (entityType === EntityType.SUBSCRIPTION) { |  | ||||||
|       return `events/${entityType}s`; |  | ||||||
|     } else { |  | ||||||
|       return `${entityType}s`; |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const handleOnEntityDeleteConfirm = () => { |  | ||||||
|     setIsLoading(false); |  | ||||||
|     setEntityDeleteState((prev) => ({ ...prev, loading: 'waiting' })); |  | ||||||
|     deleteEntity( |  | ||||||
|       prepareType ? prepareEntityType() : entityType, |  | ||||||
|       entityId ?? '', |  | ||||||
|       Boolean(isRecursiveDelete), |  | ||||||
|       !entityDeleteState.softDelete |  | ||||||
|     ) |  | ||||||
|       .then((res) => { |  | ||||||
|         if (res.status === 200) { |  | ||||||
|           setTimeout(() => { |  | ||||||
|             handleOnEntityDeleteCancel(); |  | ||||||
|             showSuccessToast( |  | ||||||
|               t('server.entity-deleted-successfully', { |  | ||||||
|                 entity: startCase(entityType), |  | ||||||
|               }) |  | ||||||
|             ); |  | ||||||
| 
 |  | ||||||
|             if (afterDeleteAction) { |  | ||||||
|               afterDeleteAction(); |  | ||||||
|             } else { |  | ||||||
|               setTimeout(() => { |  | ||||||
|                 history.push('/'); |  | ||||||
|               }, 500); |  | ||||||
|             } |  | ||||||
|           }, 1000); |  | ||||||
|         } else { |  | ||||||
|           showErrorToast(t('server.unexpected-response')); |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|       .catch((error: AxiosError) => { |  | ||||||
|         showErrorToast( |  | ||||||
|           error, |  | ||||||
|           t('server.delete-entity-error', { |  | ||||||
|             entity: entityName, |  | ||||||
|           }) |           }) | ||||||
|         ); |         ); | ||||||
|       }) |         if (afterDeleteAction) { | ||||||
|       .finally(() => { |           afterDeleteAction(entityDeleteState.softDelete); | ||||||
|         handleOnEntityDeleteCancel(); |         } | ||||||
|         setIsLoading(false); |       } else { | ||||||
|       }); |         showErrorToast(t('server.unexpected-response')); | ||||||
|   }; |       } | ||||||
|  |     } catch (error) { | ||||||
|  |       showErrorToast( | ||||||
|  |         error as AxiosError, | ||||||
|  |         t('server.delete-entity-error', { | ||||||
|  |           entity: entityName, | ||||||
|  |         }) | ||||||
|  |       ); | ||||||
|  |     } finally { | ||||||
|  |       handleOnEntityDeleteCancel(); | ||||||
|  |       setIsLoading(false); | ||||||
|  |     } | ||||||
|  |   }, [ | ||||||
|  |     entityType, | ||||||
|  |     entityId, | ||||||
|  |     isRecursiveDelete, | ||||||
|  |     entityDeleteState, | ||||||
|  |     afterDeleteAction, | ||||||
|  |     entityName, | ||||||
|  |     handleOnEntityDeleteCancel, | ||||||
|  |   ]); | ||||||
| 
 | 
 | ||||||
|   const isNameMatching = useCallback(() => { |   const isNameMatching = useCallback(() => { | ||||||
|     return ( |     return ( | ||||||
| @ -183,11 +152,14 @@ const DeleteWidgetModal = ({ | |||||||
|     ); |     ); | ||||||
|   }, [name]); |   }, [name]); | ||||||
| 
 | 
 | ||||||
|   const onChange = (e: RadioChangeEvent) => { |   const onChange = useCallback( | ||||||
|     const value = e.target.value; |     (e: RadioChangeEvent) => { | ||||||
|     setValue(value); |       const value = e.target.value; | ||||||
|     handleOnEntityDelete(value === DeleteType.SOFT_DELETE); |       setValue(value); | ||||||
|   }; |       handleOnEntityDelete(value === DeleteType.SOFT_DELETE); | ||||||
|  |     }, | ||||||
|  |     [handleOnEntityDelete] | ||||||
|  |   ); | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     setValue(allowSoftDelete ? DeleteType.SOFT_DELETE : DeleteType.HARD_DELETE); |     setValue(allowSoftDelete ? DeleteType.SOFT_DELETE : DeleteType.HARD_DELETE); | ||||||
| @ -217,7 +189,12 @@ const DeleteWidgetModal = ({ | |||||||
|         </Button> |         </Button> | ||||||
|       </Space> |       </Space> | ||||||
|     ); |     ); | ||||||
|   }, [entityDeleteState, isNameMatching]); |   }, [ | ||||||
|  |     entityDeleteState, | ||||||
|  |     handleOnEntityDeleteCancel, | ||||||
|  |     handleOnEntityDeleteConfirm, | ||||||
|  |     isNameMatching, | ||||||
|  |   ]); | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Modal |     <Modal | ||||||
| @ -233,7 +210,7 @@ const DeleteWidgetModal = ({ | |||||||
|       <Radio.Group value={value} onChange={onChange}> |       <Radio.Group value={value} onChange={onChange}> | ||||||
|         {DELETE_OPTION.map( |         {DELETE_OPTION.map( | ||||||
|           (option) => |           (option) => | ||||||
|             option.isAllowd && ( |             option.isAllowed && ( | ||||||
|               <Radio |               <Radio | ||||||
|                 data-testid={option.type} |                 data-testid={option.type} | ||||||
|                 key={option.type} |                 key={option.type} | ||||||
|  | |||||||
| @ -33,7 +33,7 @@ import './ManageButton.less'; | |||||||
| 
 | 
 | ||||||
| interface Props { | interface Props { | ||||||
|   allowSoftDelete?: boolean; |   allowSoftDelete?: boolean; | ||||||
|   afterDeleteAction?: () => void; |   afterDeleteAction?: (isSoftDelete?: boolean) => void; | ||||||
|   buttonClassName?: string; |   buttonClassName?: string; | ||||||
|   entityName: string; |   entityName: string; | ||||||
|   entityId?: string; |   entityId?: string; | ||||||
|  | |||||||
| @ -167,29 +167,6 @@ const AlertsPage = () => { | |||||||
|     [] |     [] | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   if (loading) { |  | ||||||
|     return <Loader />; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   if (isEmpty(alerts)) { |  | ||||||
|     return ( |  | ||||||
|       <ErrorPlaceHolder |  | ||||||
|         permission |  | ||||||
|         doc={ALERTS_DOCS} |  | ||||||
|         heading={t('label.alert')} |  | ||||||
|         type={ERROR_PLACEHOLDER_TYPE.CREATE} |  | ||||||
|         onClick={() => |  | ||||||
|           history.push( |  | ||||||
|             getSettingPath( |  | ||||||
|               GlobalSettingsMenuCategory.NOTIFICATIONS, |  | ||||||
|               GlobalSettingOptions.ADD_ALERTS |  | ||||||
|             ) |  | ||||||
|           ) |  | ||||||
|         } |  | ||||||
|       /> |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   return ( |   return ( | ||||||
|     <> |     <> | ||||||
|       <Row gutter={[16, 16]}> |       <Row gutter={[16, 16]}> | ||||||
| @ -212,6 +189,29 @@ const AlertsPage = () => { | |||||||
|             bordered |             bordered | ||||||
|             columns={columns} |             columns={columns} | ||||||
|             dataSource={alerts} |             dataSource={alerts} | ||||||
|  |             loading={{ | ||||||
|  |               spinning: loading, | ||||||
|  |               indicator: <Loader size="small" />, | ||||||
|  |             }} | ||||||
|  |             locale={{ | ||||||
|  |               emptyText: !loading && ( | ||||||
|  |                 <ErrorPlaceHolder | ||||||
|  |                   permission | ||||||
|  |                   className="p-y-md" | ||||||
|  |                   doc={ALERTS_DOCS} | ||||||
|  |                   heading={t('label.alert')} | ||||||
|  |                   type={ERROR_PLACEHOLDER_TYPE.CREATE} | ||||||
|  |                   onClick={() => | ||||||
|  |                     history.push( | ||||||
|  |                       getSettingPath( | ||||||
|  |                         GlobalSettingsMenuCategory.NOTIFICATIONS, | ||||||
|  |                         GlobalSettingOptions.ADD_ALERTS | ||||||
|  |                       ) | ||||||
|  |                     ) | ||||||
|  |                   } | ||||||
|  |                 /> | ||||||
|  |               ), | ||||||
|  |             }} | ||||||
|             pagination={false} |             pagination={false} | ||||||
|             rowKey="id" |             rowKey="id" | ||||||
|             size="middle" |             size="middle" | ||||||
|  | |||||||
| @ -60,6 +60,7 @@ import { | |||||||
|   removeContainerFollower, |   removeContainerFollower, | ||||||
|   restoreContainer, |   restoreContainer, | ||||||
| } from 'rest/storageAPI'; | } from 'rest/storageAPI'; | ||||||
|  | import { handleDataAssetAfterDeleteAction } from 'utils/Assets/AssetsUtils'; | ||||||
| import { | import { | ||||||
|   addToRecentViewed, |   addToRecentViewed, | ||||||
|   getCurrentUserId, |   getCurrentUserId, | ||||||
| @ -690,6 +691,7 @@ const ContainerPage = () => { | |||||||
|       <Row gutter={[0, 12]}> |       <Row gutter={[0, 12]}> | ||||||
|         <Col className="p-x-lg" span={24}> |         <Col className="p-x-lg" span={24}> | ||||||
|           <DataAssetsHeader |           <DataAssetsHeader | ||||||
|  |             afterDeleteAction={handleDataAssetAfterDeleteAction} | ||||||
|             dataAsset={containerData} |             dataAsset={containerData} | ||||||
|             entityType={EntityType.CONTAINER} |             entityType={EntityType.CONTAINER} | ||||||
|             permissions={containerPermissions} |             permissions={containerPermissions} | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ import { EmptyGraphPlaceholder } from 'components/DataInsightDetail/EmptyGraphPl | |||||||
| import Loader from 'components/Loader/Loader'; | import Loader from 'components/Loader/Loader'; | ||||||
| import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum'; | import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum'; | ||||||
| import { isUndefined } from 'lodash'; | import { isUndefined } from 'lodash'; | ||||||
| import React, { useEffect, useMemo, useState } from 'react'; | import React, { useCallback, useEffect, useMemo, useState } from 'react'; | ||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| import { Link, useHistory } from 'react-router-dom'; | import { Link, useHistory } from 'react-router-dom'; | ||||||
| import { getListKPIs } from 'rest/KpiAPI'; | import { getListKPIs } from 'rest/KpiAPI'; | ||||||
| @ -184,6 +184,10 @@ const KPIList = ({ viewKPIPermission }: { viewKPIPermission: boolean }) => { | |||||||
|     fetchKpiList(); |     fetchKpiList(); | ||||||
|   }, []); |   }, []); | ||||||
| 
 | 
 | ||||||
|  |   const handleAfterDeleteAction = useCallback(() => { | ||||||
|  |     fetchKpiList(); | ||||||
|  |   }, [fetchKpiList]); | ||||||
|  | 
 | ||||||
|   const noDataPlaceHolder = useMemo( |   const noDataPlaceHolder = useMemo( | ||||||
|     () => |     () => | ||||||
|       viewKPIPermission ? ( |       viewKPIPermission ? ( | ||||||
| @ -225,7 +229,7 @@ const KPIList = ({ viewKPIPermission }: { viewKPIPermission: boolean }) => { | |||||||
| 
 | 
 | ||||||
|       {selectedKpi && ( |       {selectedKpi && ( | ||||||
|         <DeleteWidgetModal |         <DeleteWidgetModal | ||||||
|           afterDeleteAction={fetchKpiList} |           afterDeleteAction={handleAfterDeleteAction} | ||||||
|           allowSoftDelete={false} |           allowSoftDelete={false} | ||||||
|           deleteMessage={`Are you sure you want to delete ${getEntityName( |           deleteMessage={`Are you sure you want to delete ${getEntityName( | ||||||
|             selectedKpi |             selectedKpi | ||||||
|  | |||||||
| @ -60,6 +60,7 @@ import { | |||||||
|   restoreDatabase, |   restoreDatabase, | ||||||
| } from 'rest/databaseAPI'; | } from 'rest/databaseAPI'; | ||||||
| import { getFeedCount, postThread } from 'rest/feedsAPI'; | import { getFeedCount, postThread } from 'rest/feedsAPI'; | ||||||
|  | import { handleDataAssetAfterDeleteAction } from 'utils/Assets/AssetsUtils'; | ||||||
| import { default as appState } from '../../AppState'; | import { default as appState } from '../../AppState'; | ||||||
| import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants'; | import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants'; | ||||||
| import { | import { | ||||||
| @ -748,8 +749,8 @@ const DatabaseDetails: FunctionComponent = () => { | |||||||
|       <Row gutter={[0, 12]}> |       <Row gutter={[0, 12]}> | ||||||
|         <Col className="p-x-lg" span={24}> |         <Col className="p-x-lg" span={24}> | ||||||
|           <DataAssetsHeader |           <DataAssetsHeader | ||||||
|             allowSoftDelete |  | ||||||
|             isRecursiveDelete |             isRecursiveDelete | ||||||
|  |             afterDeleteAction={handleDataAssetAfterDeleteAction} | ||||||
|             dataAsset={database} |             dataAsset={database} | ||||||
|             entityType={EntityType.DATABASE} |             entityType={EntityType.DATABASE} | ||||||
|             permissions={databasePermission} |             permissions={databasePermission} | ||||||
|  | |||||||
| @ -55,6 +55,7 @@ import { | |||||||
| } from 'rest/databaseAPI'; | } from 'rest/databaseAPI'; | ||||||
| import { getFeedCount, postThread } from 'rest/feedsAPI'; | import { getFeedCount, postThread } from 'rest/feedsAPI'; | ||||||
| import { getTableList, TableListParams } from 'rest/tableAPI'; | import { getTableList, TableListParams } from 'rest/tableAPI'; | ||||||
|  | import { handleDataAssetAfterDeleteAction } from 'utils/Assets/AssetsUtils'; | ||||||
| import { default as appState } from '../../AppState'; | import { default as appState } from '../../AppState'; | ||||||
| import { getDatabaseSchemaDetailsPath } from '../../constants/constants'; | import { getDatabaseSchemaDetailsPath } from '../../constants/constants'; | ||||||
| import { EntityTabs, EntityType } from '../../enums/entity.enum'; | import { EntityTabs, EntityType } from '../../enums/entity.enum'; | ||||||
| @ -557,8 +558,8 @@ const DatabaseSchemaPage: FunctionComponent = () => { | |||||||
|             /> |             /> | ||||||
|           ) : ( |           ) : ( | ||||||
|             <DataAssetsHeader |             <DataAssetsHeader | ||||||
|               allowSoftDelete |  | ||||||
|               isRecursiveDelete |               isRecursiveDelete | ||||||
|  |               afterDeleteAction={handleDataAssetAfterDeleteAction} | ||||||
|               dataAsset={databaseSchema} |               dataAsset={databaseSchema} | ||||||
|               entityType={EntityType.DATABASE_SCHEMA} |               entityType={EntityType.DATABASE_SCHEMA} | ||||||
|               permissions={databaseSchemaPermission} |               permissions={databaseSchemaPermission} | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ import RichTextEditorPreviewer from 'components/common/rich-text-editor/RichText | |||||||
| import { usePermissionProvider } from 'components/PermissionProvider/PermissionProvider'; | import { usePermissionProvider } from 'components/PermissionProvider/PermissionProvider'; | ||||||
| import { ResourceEntity } from 'components/PermissionProvider/PermissionProvider.interface'; | import { ResourceEntity } from 'components/PermissionProvider/PermissionProvider.interface'; | ||||||
| import { isEmpty, isUndefined, uniqueId } from 'lodash'; | import { isEmpty, isUndefined, uniqueId } from 'lodash'; | ||||||
| import React, { FC, useMemo, useState } from 'react'; | import React, { FC, useCallback, useMemo, useState } from 'react'; | ||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| import { Link } from 'react-router-dom'; | import { Link } from 'react-router-dom'; | ||||||
| import { getEntityName } from 'utils/EntityUtils'; | import { getEntityName } from 'utils/EntityUtils'; | ||||||
| @ -181,6 +181,10 @@ const PoliciesList: FC<PolicyListProps> = ({ policies, fetchPolicies }) => { | |||||||
|     ]; |     ]; | ||||||
|   }, []); |   }, []); | ||||||
| 
 | 
 | ||||||
|  |   const handleAfterDeleteAction = useCallback(() => { | ||||||
|  |     fetchPolicies(); | ||||||
|  |   }, [fetchPolicies]); | ||||||
|  | 
 | ||||||
|   return ( |   return ( | ||||||
|     <> |     <> | ||||||
|       <Table |       <Table | ||||||
| @ -195,7 +199,7 @@ const PoliciesList: FC<PolicyListProps> = ({ policies, fetchPolicies }) => { | |||||||
|       /> |       /> | ||||||
|       {selectedPolicy && deletePolicyPermission && ( |       {selectedPolicy && deletePolicyPermission && ( | ||||||
|         <DeleteWidgetModal |         <DeleteWidgetModal | ||||||
|           afterDeleteAction={fetchPolicies} |           afterDeleteAction={handleAfterDeleteAction} | ||||||
|           allowSoftDelete={false} |           allowSoftDelete={false} | ||||||
|           deleteMessage={t('message.are-you-sure-delete-entity', { |           deleteMessage={t('message.are-you-sure-delete-entity', { | ||||||
|             entity: getEntityName(selectedPolicy), |             entity: getEntityName(selectedPolicy), | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ import RichTextEditorPreviewer from 'components/common/rich-text-editor/RichText | |||||||
| import { usePermissionProvider } from 'components/PermissionProvider/PermissionProvider'; | import { usePermissionProvider } from 'components/PermissionProvider/PermissionProvider'; | ||||||
| import { ResourceEntity } from 'components/PermissionProvider/PermissionProvider.interface'; | import { ResourceEntity } from 'components/PermissionProvider/PermissionProvider.interface'; | ||||||
| import { isEmpty, isUndefined, uniqueId } from 'lodash'; | import { isEmpty, isUndefined, uniqueId } from 'lodash'; | ||||||
| import React, { FC, useMemo, useState } from 'react'; | import React, { FC, useCallback, useMemo, useState } from 'react'; | ||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| import { Link } from 'react-router-dom'; | import { Link } from 'react-router-dom'; | ||||||
| import { getEntityName } from 'utils/EntityUtils'; | import { getEntityName } from 'utils/EntityUtils'; | ||||||
| @ -178,6 +178,10 @@ const RolesList: FC<RolesListProps> = ({ roles, fetchRoles }) => { | |||||||
|     ]; |     ]; | ||||||
|   }, []); |   }, []); | ||||||
| 
 | 
 | ||||||
|  |   const handleAfterDeleteAction = useCallback(() => { | ||||||
|  |     fetchRoles(); | ||||||
|  |   }, [fetchRoles]); | ||||||
|  | 
 | ||||||
|   return ( |   return ( | ||||||
|     <> |     <> | ||||||
|       <Table |       <Table | ||||||
| @ -192,7 +196,7 @@ const RolesList: FC<RolesListProps> = ({ roles, fetchRoles }) => { | |||||||
|       /> |       /> | ||||||
|       {selectedRole && ( |       {selectedRole && ( | ||||||
|         <DeleteWidgetModal |         <DeleteWidgetModal | ||||||
|           afterDeleteAction={fetchRoles} |           afterDeleteAction={handleAfterDeleteAction} | ||||||
|           allowSoftDelete={false} |           allowSoftDelete={false} | ||||||
|           deleteMessage={t('message.are-you-sure-delete-entity', { |           deleteMessage={t('message.are-you-sure-delete-entity', { | ||||||
|             entity: getEntityName(selectedRole), |             entity: getEntityName(selectedRole), | ||||||
|  | |||||||
| @ -72,6 +72,7 @@ import { | |||||||
|   removeFollower, |   removeFollower, | ||||||
|   restoreTable, |   restoreTable, | ||||||
| } from 'rest/tableAPI'; | } from 'rest/tableAPI'; | ||||||
|  | import { handleDataAssetAfterDeleteAction } from 'utils/Assets/AssetsUtils'; | ||||||
| import { | import { | ||||||
|   addToRecentViewed, |   addToRecentViewed, | ||||||
|   getCurrentUserId, |   getCurrentUserId, | ||||||
| @ -887,6 +888,7 @@ const TableDetailsPageV1 = () => { | |||||||
|         {/* Entity Heading */} |         {/* Entity Heading */} | ||||||
|         <Col className="p-x-lg" data-testid="entity-page-header" span={24}> |         <Col className="p-x-lg" data-testid="entity-page-header" span={24}> | ||||||
|           <DataAssetsHeader |           <DataAssetsHeader | ||||||
|  |             afterDeleteAction={handleDataAssetAfterDeleteAction} | ||||||
|             dataAsset={tableDetails} |             dataAsset={tableDetails} | ||||||
|             entityType={EntityType.TABLE} |             entityType={EntityType.TABLE} | ||||||
|             permissions={tablePermissions} |             permissions={tablePermissions} | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ import { DashboardDataModel } from 'generated/entity/data/dashboardDataModel'; | |||||||
| import { EntityHistory } from 'generated/type/entityHistory'; | import { EntityHistory } from 'generated/type/entityHistory'; | ||||||
| import { EntityReference } from 'generated/type/entityReference'; | import { EntityReference } from 'generated/type/entityReference'; | ||||||
| import { Include } from 'generated/type/include'; | import { Include } from 'generated/type/include'; | ||||||
|  | import { RestoreRequestType } from 'Models'; | ||||||
| import { getURLWithQueryFields } from 'utils/APIUtils'; | import { getURLWithQueryFields } from 'utils/APIUtils'; | ||||||
| import APIClient from './index'; | import APIClient from './index'; | ||||||
| 
 | 
 | ||||||
| @ -117,3 +118,12 @@ export const getDataModelVersion = async (id: string, version: string) => { | |||||||
| 
 | 
 | ||||||
|   return response.data; |   return response.data; | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | export const restoreDataModel = async (id: string) => { | ||||||
|  |   const response = await APIClient.put< | ||||||
|  |     RestoreRequestType, | ||||||
|  |     AxiosResponse<DashboardDataModel> | ||||||
|  |   >('/dashboard/datamodels/restore', { id }); | ||||||
|  | 
 | ||||||
|  |   return response.data; | ||||||
|  | }; | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ import { getPipelineByFqn, patchPipelineDetails } from 'rest/pipelineAPI'; | |||||||
| import { getContainerByName, patchContainerDetails } from 'rest/storageAPI'; | import { getContainerByName, patchContainerDetails } from 'rest/storageAPI'; | ||||||
| import { getTableDetailsByFQN, patchTableDetails } from 'rest/tableAPI'; | import { getTableDetailsByFQN, patchTableDetails } from 'rest/tableAPI'; | ||||||
| import { getTopicByFqn, patchTopicDetails } from 'rest/topicsAPI'; | import { getTopicByFqn, patchTopicDetails } from 'rest/topicsAPI'; | ||||||
|  | import { history } from 'utils/HistoryUtils'; | ||||||
| 
 | 
 | ||||||
| export const getAPIfromSource = ( | export const getAPIfromSource = ( | ||||||
|   source: AssetsUnion |   source: AssetsUnion | ||||||
| @ -66,3 +67,13 @@ export const getEntityAPIfromSource = ( | |||||||
|       return getContainerByName; |       return getContainerByName; | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | export const handleDataAssetAfterDeleteAction = (isSoftDelete?: boolean) => { | ||||||
|  |   if (isSoftDelete) { | ||||||
|  |     setTimeout(() => { | ||||||
|  |       history.go(0); | ||||||
|  |     }, 1000); | ||||||
|  |   } else { | ||||||
|  |     history.push('/'); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | |||||||
| @ -76,6 +76,7 @@ import { TagLabel } from '../generated/type/tagLabel'; | |||||||
| import { EntityFieldThreadCount } from '../interface/feed.interface'; | import { EntityFieldThreadCount } from '../interface/feed.interface'; | ||||||
| import { getEntityFeedLink, getTitleCase } from './EntityUtils'; | import { getEntityFeedLink, getTitleCase } from './EntityUtils'; | ||||||
| import Fqn from './Fqn'; | import Fqn from './Fqn'; | ||||||
|  | import { history } from './HistoryUtils'; | ||||||
| import { serviceTypeLogo } from './ServiceUtils'; | import { serviceTypeLogo } from './ServiceUtils'; | ||||||
| import { TASK_ENTITIES } from './TasksUtils'; | import { TASK_ENTITIES } from './TasksUtils'; | ||||||
| import { showErrorToast } from './ToastUtils'; | import { showErrorToast } from './ToastUtils'; | ||||||
| @ -701,7 +702,9 @@ export const getLoadingStatus = ( | |||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const refreshPage = () => window.location.reload(); | export const refreshPage = () => { | ||||||
|  |   history.go(0); | ||||||
|  | }; | ||||||
| // return array of id as  strings
 | // return array of id as  strings
 | ||||||
| export const getEntityIdArray = (entities: EntityReference[]): string[] => | export const getEntityIdArray = (entities: EntityReference[]): string[] => | ||||||
|   entities.map((item) => item.id); |   entities.map((item) => item.id); | ||||||
|  | |||||||
| @ -46,6 +46,7 @@ import { | |||||||
|   getBreadcrumbForEntitiesWithServiceOnly, |   getBreadcrumbForEntitiesWithServiceOnly, | ||||||
|   getBreadcrumbForTable, |   getBreadcrumbForTable, | ||||||
|   getEntityBreadcrumbs, |   getEntityBreadcrumbs, | ||||||
|  |   getEntityName, | ||||||
| } from './EntityUtils'; | } from './EntityUtils'; | ||||||
| import { bytesToSize } from './StringsUtils'; | import { bytesToSize } from './StringsUtils'; | ||||||
| import { getUsagePercentile } from './TableUtils'; | import { getUsagePercentile } from './TableUtils'; | ||||||
| @ -92,8 +93,8 @@ export const getDataAssetsHeaderInfo = ( | |||||||
|           {dashboardDetails.sourceUrl && ( |           {dashboardDetails.sourceUrl && ( | ||||||
|             <ExtraInfoLink |             <ExtraInfoLink | ||||||
|               href={dashboardDetails.sourceUrl} |               href={dashboardDetails.sourceUrl} | ||||||
|               label={entityName} |               label="" | ||||||
|               value={dashboardDetails.sourceUrl} |               value={getEntityName(dashboardDetails)} | ||||||
|             /> |             /> | ||||||
|           )} |           )} | ||||||
|           {dashboardDetails.dashboardType && ( |           {dashboardDetails.dashboardType && ( | ||||||
| @ -126,7 +127,7 @@ export const getDataAssetsHeaderInfo = ( | |||||||
|             <ExtraInfoLink |             <ExtraInfoLink | ||||||
|               href={pipelineDetails.sourceUrl} |               href={pipelineDetails.sourceUrl} | ||||||
|               label="" |               label="" | ||||||
|               value={pipelineDetails.sourceUrl} |               value={getEntityName(pipelineDetails)} | ||||||
|             /> |             /> | ||||||
|           )} |           )} | ||||||
|         </> |         </> | ||||||
|  | |||||||
| @ -0,0 +1,62 @@ | |||||||
|  | /* | ||||||
|  |  *  Copyright 2023 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 { EntityType } from 'enums/entity.enum'; | ||||||
|  | import { t } from 'i18next'; | ||||||
|  | import { getEntityDeleteMessage } from './CommonUtils'; | ||||||
|  | import { getTitleCase } from './EntityUtils'; | ||||||
|  | 
 | ||||||
|  | export const prepareEntityType = (entityType: string) => { | ||||||
|  |   const services = [ | ||||||
|  |     EntityType.DASHBOARD_SERVICE, | ||||||
|  |     EntityType.DATABASE_SERVICE, | ||||||
|  |     EntityType.MESSAGING_SERVICE, | ||||||
|  |     EntityType.PIPELINE_SERVICE, | ||||||
|  |     EntityType.METADATA_SERVICE, | ||||||
|  |     EntityType.STORAGE_SERVICE, | ||||||
|  |     EntityType.MLMODEL_SERVICE, | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   const dataQuality = [EntityType.TEST_SUITE, EntityType.TEST_CASE]; | ||||||
|  | 
 | ||||||
|  |   if (services.includes((entityType || '') as EntityType)) { | ||||||
|  |     return `services/${entityType}s`; | ||||||
|  |   } else if (entityType === EntityType.GLOSSARY) { | ||||||
|  |     return `glossaries`; | ||||||
|  |   } else if (entityType === EntityType.POLICY) { | ||||||
|  |     return 'policies'; | ||||||
|  |   } else if (entityType === EntityType.KPI) { | ||||||
|  |     return entityType; | ||||||
|  |   } else if (entityType === EntityType.DASHBOARD_DATA_MODEL) { | ||||||
|  |     return `dashboard/datamodels`; | ||||||
|  |   } else if (dataQuality.includes(entityType as EntityType)) { | ||||||
|  |     return `dataQuality/${entityType}s`; | ||||||
|  |   } else if (entityType === EntityType.SUBSCRIPTION) { | ||||||
|  |     return `events/${entityType}s`; | ||||||
|  |   } else { | ||||||
|  |     return `${entityType}s`; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export const getDeleteMessage = ( | ||||||
|  |   entityName: string, | ||||||
|  |   entityType: string, | ||||||
|  |   softDelete = false | ||||||
|  | ) => { | ||||||
|  |   const softDeleteText = t('message.soft-delete-message-for-entity', { | ||||||
|  |     entity: entityName, | ||||||
|  |   }); | ||||||
|  |   const hardDeleteText = getEntityDeleteMessage(getTitleCase(entityType), ''); | ||||||
|  | 
 | ||||||
|  |   return softDelete ? softDeleteText : hardDeleteText; | ||||||
|  | }; | ||||||
| @ -0,0 +1,16 @@ | |||||||
|  | /* | ||||||
|  |  *  Copyright 2023 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 { createBrowserHistory } from 'history'; | ||||||
|  | 
 | ||||||
|  | export const history = createBrowserHistory(); | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Aniket Katkar
						Aniket Katkar