From f53ea0332079982c1c4520beea0e43553adb23ae Mon Sep 17 00:00:00 2001
From: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
Date: Sun, 23 Apr 2023 20:03:23 +0530
Subject: [PATCH] fix(ui): added no permission placeholder instead 404 (#11205)
* fix(ui): added no permission placeholder instead 404
* fix unit tests
---
.../TableSummary/TableSummary.component.tsx | 18 +--
.../TopicSummary/TopicSummary.component.tsx | 19 +--
.../TopicSummary/TopicSummary.test.tsx | 58 ++++++---
.../GlobalSetting/GlobalSetting.tsx | 35 ------
.../GlobalSettingLeftPanel.test.tsx | 81 -------------
.../GlobalSetting/GlobalSettingLeftPanel.tsx | 113 ------------------
.../components/router/AdminProtectedRoute.tsx | 19 ++-
.../router/AuthenticatedAppRouter.tsx | 5 +
.../components/router/GlobalSettingRouter.tsx | 8 +-
.../ui/src/constants/HelperTextUtil.ts | 4 +
.../ui/src/locale/languages/en-us.json | 1 +
.../ui/src/locale/languages/es-es.json | 1 +
.../ui/src/locale/languages/fr-fr.json | 1 +
.../ui/src/locale/languages/ja-jp.json | 1 +
.../ui/src/locale/languages/pt-br.json | 1 +
.../ui/src/locale/languages/zh-cn.json | 1 +
.../pages/BotDetailsPage/BotDetailsPage.tsx | 11 +-
.../src/pages/ContainerPage/ContainerPage.tsx | 13 +-
.../CustomPropertiesPageV1.tsx | 5 +-
.../DashboardDetailsPage.component.tsx | 11 +-
.../DataModelPage/DataModelPage.component.tsx | 13 +-
.../DatasetDetailsPage.component.tsx | 11 +-
.../GlobalSettingPage/GlobalSettingPage.tsx | 103 +++++++++++++++-
.../global-setting-page.style.less} | 0
.../MlModelPage/MlModelPage.component.tsx | 18 ++-
.../PipelineDetailsPage.component.tsx | 11 +-
.../pages/QueryPage/QueryPage.component.tsx | 13 +-
.../TestSuiteDetailsPage.component.tsx | 11 +-
.../TopicDetailsPage.component.tsx | 11 +-
.../ui/src/pages/services/ServicesPage.tsx | 9 +-
.../ui/src/pages/teams/TeamsPage.tsx | 11 +-
.../main/resources/ui/src/utils/ToastUtils.ts | 4 +-
32 files changed, 322 insertions(+), 299 deletions(-)
delete mode 100644 openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSetting.tsx
delete mode 100644 openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSettingLeftPanel.test.tsx
delete mode 100644 openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSettingLeftPanel.tsx
rename openmetadata-ui/src/main/resources/ui/src/{components/GlobalSetting/GlobalSetting.less => pages/GlobalSettingPage/global-setting-page.style.less} (100%)
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/TableSummary/TableSummary.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/TableSummary/TableSummary.component.tsx
index d1397164af1..acd129e1686 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/TableSummary/TableSummary.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/TableSummary/TableSummary.component.tsx
@@ -16,6 +16,7 @@ import { AxiosError } from 'axios';
import classNames from 'classnames';
import SummaryTagsDescription from 'components/common/SummaryTagsDescription/SummaryTagsDescription.component';
import SummaryPanelSkeleton from 'components/Skeleton/SummaryPanelSkeleton/SummaryPanelSkeleton.component';
+import { ClientErrors } from 'enums/axios.enum';
import { ExplorePageTabs } from 'enums/Explore.enum';
import { isEmpty, isUndefined } from 'lodash';
import {
@@ -120,13 +121,16 @@ function TableSummary({
return {} as Table;
}
});
- } catch {
- showErrorToast(
- t('server.entity-details-fetch-error', {
- entityType: t('label.table-lowercase'),
- entityName: entityDetails.name,
- })
- );
+ } catch (error) {
+ const axiosError = error as AxiosError;
+ if (axiosError.response?.status !== ClientErrors.FORBIDDEN) {
+ showErrorToast(
+ t('server.entity-details-fetch-error', {
+ entityType: t('label.table-lowercase'),
+ entityName: entityDetails.name,
+ })
+ );
+ }
}
}, [entityDetails]);
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/TopicSummary/TopicSummary.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/TopicSummary/TopicSummary.component.tsx
index 5edc7f17cfe..314d8e8374f 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/TopicSummary/TopicSummary.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/TopicSummary/TopicSummary.component.tsx
@@ -12,9 +12,11 @@
*/
import { Col, Divider, Row, Typography } from 'antd';
+import { AxiosError } from 'axios';
import SummaryTagsDescription from 'components/common/SummaryTagsDescription/SummaryTagsDescription.component';
import SummaryPanelSkeleton from 'components/Skeleton/SummaryPanelSkeleton/SummaryPanelSkeleton.component';
import { getTeamAndUserDetailsPath } from 'constants/constants';
+import { ClientErrors } from 'enums/axios.enum';
import { isArray, isEmpty } from 'lodash';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
@@ -90,13 +92,16 @@ function TopicSummary({
const { partitions, messageSchema } = res;
setTopicDetails({ ...entityDetails, partitions, messageSchema });
- } catch {
- showErrorToast(
- t('server.entity-details-fetch-error', {
- entityType: t('label.topic-lowercase'),
- entityName: entityDetails.name,
- })
- );
+ } catch (error) {
+ const axiosError = error as AxiosError;
+ if (axiosError.response?.status !== ClientErrors.FORBIDDEN) {
+ showErrorToast(
+ t('server.entity-details-fetch-error', {
+ entityType: t('label.topic-lowercase'),
+ entityName: entityDetails.name,
+ })
+ );
+ }
}
}, [entityDetails]);
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/TopicSummary/TopicSummary.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/TopicSummary/TopicSummary.test.tsx
index 6c78baabea3..eada1ab8c7c 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/TopicSummary/TopicSummary.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/TopicSummary/TopicSummary.test.tsx
@@ -27,31 +27,55 @@ jest.mock('../SummaryList/SummaryList.component', () =>
);
jest.mock('rest/topicsAPI', () => ({
- getTopicByFqn: jest.fn().mockImplementation(() => mockTopicByFqnResponse),
+ getTopicByFqn: jest
+ .fn()
+ .mockImplementation(() => Promise.resolve(mockTopicByFqnResponse)),
}));
+jest.mock(
+ 'components/common/SummaryTagsDescription/SummaryTagsDescription.component',
+ () => jest.fn().mockImplementation(() =>
SummaryTagDescription
)
+);
+
+jest.mock(
+ 'components/Skeleton/SummaryPanelSkeleton/SummaryPanelSkeleton.component',
+ () => jest.fn().mockImplementation(({ children }) => <>{children}>)
+);
+
describe('TopicSummary component tests', () => {
it('Component should render properly', async () => {
await act(async () => {
render();
});
- const partitionsLabel = screen.getByTestId('Partitions-label');
- const replicationFactorLabel = screen.getByTestId(
+ const partitionsLabel = await screen.findByTestId('Partitions-label');
+ const replicationFactorLabel = await screen.findByTestId(
'Replication Factor-label'
);
- const retentionSizeLabel = screen.getByTestId('Retention Size-label');
- const cleanUpPoliciesLabel = screen.getByTestId('CleanUp Policies-label');
- const maxMessageSizeLabel = screen.getByTestId('Max Message Size-label');
- const partitionsValue = screen.getByTestId('Partitions-value');
- const replicationFactorValue = screen.getByTestId(
+ const retentionSizeLabel = await screen.findByTestId(
+ 'Retention Size-label'
+ );
+ const cleanUpPoliciesLabel = await screen.findByTestId(
+ 'CleanUp Policies-label'
+ );
+ const maxMessageSizeLabel = await screen.findByTestId(
+ 'Max Message Size-label'
+ );
+ const partitionsValue = await screen.findByTestId('Partitions-value');
+ const replicationFactorValue = await screen.findByTestId(
'Replication Factor-value'
);
- const retentionSizeValue = screen.getByTestId('Retention Size-value');
- const cleanUpPoliciesValue = screen.getByTestId('CleanUp Policies-value');
- const maxMessageSizeValue = screen.getByTestId('Max Message Size-value');
- const schemaHeader = screen.getByTestId('schema-header');
- const summaryList = screen.getByTestId('SummaryList');
+ const retentionSizeValue = await screen.findByTestId(
+ 'Retention Size-value'
+ );
+ const cleanUpPoliciesValue = await screen.findByTestId(
+ 'CleanUp Policies-value'
+ );
+ const maxMessageSizeValue = await screen.findByTestId(
+ 'Max Message Size-value'
+ );
+ const schemaHeader = await screen.findByTestId('schema-header');
+ const summaryList = await screen.findByTestId('SummaryList');
expect(partitionsLabel).toBeInTheDocument();
expect(replicationFactorLabel).toBeInTheDocument();
@@ -68,7 +92,9 @@ describe('TopicSummary component tests', () => {
});
it('No data message should be shown in case no schemaFields are available in topic details', async () => {
- (getTopicByFqn as jest.Mock).mockImplementation(() => Promise.resolve({}));
+ (getTopicByFqn as jest.Mock).mockImplementation(() =>
+ Promise.resolve({ ...mockTopicEntityDetails, messageSchema: {} })
+ );
await act(async () => {
render();
@@ -82,7 +108,9 @@ describe('TopicSummary component tests', () => {
});
it('In case any topic field is not present, "-" should be displayed in place of value', async () => {
- (getTopicByFqn as jest.Mock).mockImplementationOnce(() => Promise.reject());
+ (getTopicByFqn as jest.Mock).mockImplementationOnce(() =>
+ Promise.reject({})
+ );
await act(async () => {
render();
});
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSetting.tsx b/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSetting.tsx
deleted file mode 100644
index 8c0564429fa..00000000000
--- a/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSetting.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2022 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 React from 'react';
-import { useTranslation } from 'react-i18next';
-
-import PageLayoutV1 from '../containers/PageLayoutV1';
-import GlobalSettingRouter from '../router/GlobalSettingRouter';
-import './GlobalSetting.less';
-import GlobalSettingLeftPanel from './GlobalSettingLeftPanel';
-
-const GlobalSetting = () => {
- const { t } = useTranslation();
-
- return (
- }
- pageTitle={t('label.setting-plural')}>
-
-
- );
-};
-
-export default GlobalSetting;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSettingLeftPanel.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSettingLeftPanel.test.tsx
deleted file mode 100644
index 688b6c52788..00000000000
--- a/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSettingLeftPanel.test.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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 { render, screen, waitForElement } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { PERMISSIONS } from 'mocks/Permissions.mock';
-import React from 'react';
-import { MemoryRouter, Route } from 'react-router-dom';
-import GlobalSettingLeftPanel from './GlobalSettingLeftPanel';
-
-jest.mock('../PermissionProvider/PermissionProvider', () => ({
- usePermissionProvider: jest.fn().mockImplementation(() => ({
- permissions: PERMISSIONS,
- getEntityPermission: jest.fn().mockResolvedValue({
- Create: true,
- Delete: true,
- EditAll: true,
- EditCustomFields: true,
- EditDataProfile: true,
- EditDescription: true,
- EditDisplayName: true,
- EditLineage: true,
- EditOwner: true,
- EditQueries: true,
- EditSampleData: true,
- EditTags: true,
- EditTests: true,
- EditTier: true,
- ViewAll: true,
- ViewDataProfile: true,
- ViewQueries: true,
- ViewSampleData: true,
- ViewTests: true,
- ViewUsage: true,
- }),
- })),
-}));
-
-const selectedCategory = 'services';
-const selectedOption = 'storages';
-const url = `/settings/${selectedCategory}/${selectedOption}`;
-
-describe('GlobalSettingLeftPanel', () => {
- it('Should render global settings menu with correct selected item', () => {
- render(
-
-
-
-
-
- );
-
- expect(screen.getByText('label.service-plural')).toBeInTheDocument();
- expect(screen.getByText('label.storage-plural')).toBeInTheDocument();
- });
-
- it('Should change the location path on user click', () => {
- render(
-
-
-
-
-
- );
-
- userEvent.click(screen.getByText('label.team-plural'));
-
- waitForElement(() =>
- expect(window.location.pathname).toEqual('/teams/organizations')
- );
- });
-});
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSettingLeftPanel.tsx b/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSettingLeftPanel.tsx
deleted file mode 100644
index 6c1258884ef..00000000000
--- a/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSettingLeftPanel.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2022 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 { Menu, MenuProps } from 'antd';
-import { ItemType } from 'antd/lib/menu/hooks/useItems';
-import { ELASTIC_SEARCH_RE_INDEX_PAGE_TABS } from 'enums/ElasticSearch.enum';
-import React, { useMemo } from 'react';
-import { useTranslation } from 'react-i18next';
-import { useHistory, useParams } from 'react-router-dom';
-import { GlobalSettingOptions } from '../../constants/GlobalSettings.constants';
-import { TeamType } from '../../generated/entity/teams/team';
-import { useAuth } from '../../hooks/authHooks';
-import {
- getGlobalSettingMenuItem,
- getGlobalSettingsMenuWithPermission,
- MenuList,
-} from '../../utils/GlobalSettingsUtils';
-import {
- getSettingPath,
- getSettingsPathWithFqn,
- getTeamsWithFqnPath,
-} from '../../utils/RouterUtils';
-import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder';
-import LeftPanelCard from '../common/LeftPanelCard/LeftPanelCard';
-import { usePermissionProvider } from '../PermissionProvider/PermissionProvider';
-
-const GlobalSettingLeftPanel = () => {
- const history = useHistory();
- const { t } = useTranslation();
- const { tab, settingCategory } = useParams<{ [key: string]: string }>();
-
- const { permissions } = usePermissionProvider();
-
- const { isAdminUser } = useAuth();
-
- const menuItems: ItemType[] = useMemo(
- () =>
- getGlobalSettingsMenuWithPermission(permissions, isAdminUser).reduce(
- (acc: ItemType[], curr: MenuList) => {
- const menuItem = getGlobalSettingMenuItem({
- label: curr.category,
- key: curr.key,
- category: curr.category,
- children: curr.items,
- type: 'group',
- isBeta: curr.isBeta,
- });
- if (menuItem.children?.length) {
- return [...acc, menuItem];
- } else {
- return acc;
- }
- },
- [] as ItemType[]
- ),
- [permissions]
- );
-
- const onClick: MenuProps['onClick'] = (e) => {
- // As we are setting key as "category.option" and extracting here category and option
- const [category, option] = e.key.split('.');
-
- switch (option) {
- case GlobalSettingOptions.TEAMS:
- history.push(getTeamsWithFqnPath(TeamType.Organization));
-
- break;
- case GlobalSettingOptions.SEARCH:
- history.push(
- getSettingsPathWithFqn(
- category,
- option,
- ELASTIC_SEARCH_RE_INDEX_PAGE_TABS.ON_DEMAND
- )
- );
-
- break;
- default:
- history.push(getSettingPath(category, option));
-
- break;
- }
- };
-
- return menuItems.length ? (
-
-
-
- ) : (
-
- {t('message.no-data-available')}
-
- );
-};
-
-export default GlobalSettingLeftPanel;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/router/AdminProtectedRoute.tsx b/openmetadata-ui/src/main/resources/ui/src/components/router/AdminProtectedRoute.tsx
index f71e782c8d8..94d96b247b5 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/router/AdminProtectedRoute.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/router/AdminProtectedRoute.tsx
@@ -11,11 +11,15 @@
* limitations under the License.
*/
+import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
+import {
+ NO_PERMISSION_TO_VIEW,
+ REACH_OUT_TO_ADMIN_FOR_ACCESS,
+} from 'constants/HelperTextUtil';
import React from 'react';
import { Redirect, Route, RouteProps } from 'react-router-dom';
import { ROUTES } from '../../constants/constants';
import { useAuth } from '../../hooks/authHooks';
-import { useAuthContext } from '../authentication/auth-provider/AuthProvider';
interface AdminProtectedRouteProps extends RouteProps {
hasPermission: boolean;
@@ -23,12 +27,17 @@ interface AdminProtectedRouteProps extends RouteProps {
const AdminProtectedRoute = (routeProps: AdminProtectedRouteProps) => {
const { isAdminUser } = useAuth();
- const { isAuthDisabled, isAuthenticated } = useAuthContext();
- if (isAuthDisabled || isAdminUser || routeProps.hasPermission) {
+ if (isAdminUser || routeProps.hasPermission) {
return ;
- } else if (isAuthenticated) {
- return ;
+ } else if (!routeProps.hasPermission) {
+ return (
+
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
+
+ );
} else {
return ;
}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/router/AuthenticatedAppRouter.tsx b/openmetadata-ui/src/main/resources/ui/src/components/router/AuthenticatedAppRouter.tsx
index d5f56efda05..09dbeaa4f30 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/router/AuthenticatedAppRouter.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/router/AuthenticatedAppRouter.tsx
@@ -245,6 +245,10 @@ const AddQueryPage = withSuspenseFallback(
React.lazy(() => import('pages/AddQueryPage/AddQueryPage.component'))
);
+const PageNotFound = withSuspenseFallback(
+ React.lazy(() => import('pages/page-not-found'))
+);
+
const AuthenticatedAppRouter: FunctionComponent = () => {
const { permissions } = usePermissionProvider();
@@ -603,6 +607,7 @@ const AuthenticatedAppRouter: FunctionComponent = () => {
+
);
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/router/GlobalSettingRouter.tsx b/openmetadata-ui/src/main/resources/ui/src/components/router/GlobalSettingRouter.tsx
index 764c91f4ba6..d3429c3b90f 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/router/GlobalSettingRouter.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/router/GlobalSettingRouter.tsx
@@ -17,7 +17,6 @@ import {
GlobalSettingOptions,
GlobalSettingsMenuCategory,
} from '../../constants/GlobalSettings.constants';
-
import { TeamType } from '../../generated/entity/teams/team';
import { userPermissions } from '../../utils/PermissionsUtils';
import {
@@ -27,7 +26,6 @@ import {
} from '../../utils/RouterUtils';
import { usePermissionProvider } from '../PermissionProvider/PermissionProvider';
import { ResourceEntity } from '../PermissionProvider/PermissionProvider.interface';
-
import AdminProtectedRoute from './AdminProtectedRoute';
import withSuspenseFallback from './withSuspenseFallback';
@@ -117,9 +115,13 @@ const GlobalSettingRouter = () => {
- {
{botPermission.ViewAll || botPermission.ViewBasic ? (
getBotsDetailComponent()
) : (
- {NO_PERMISSION_TO_VIEW}
+
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
+
)}
>
)}
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/ContainerPage/ContainerPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/ContainerPage/ContainerPage.tsx
index 1458d816a83..e2d097849fd 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/ContainerPage/ContainerPage.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/ContainerPage/ContainerPage.tsx
@@ -37,7 +37,10 @@ import {
} from 'components/PermissionProvider/PermissionProvider.interface';
import { FQN_SEPARATOR_CHAR } from 'constants/char.constants';
import { getServiceDetailsPath, getVersionPath } from 'constants/constants';
-import { NO_PERMISSION_TO_VIEW } from 'constants/HelperTextUtil';
+import {
+ NO_PERMISSION_TO_VIEW,
+ REACH_OUT_TO_ADMIN_FOR_ACCESS,
+} from 'constants/HelperTextUtil';
import { EntityInfo, EntityType } from 'enums/entity.enum';
import { ServiceCategory } from 'enums/service.enum';
import { OwnerType } from 'enums/user.enum';
@@ -620,7 +623,13 @@ const ContainerPage = () => {
}
if (!hasViewPermission && !isLoading) {
- return {NO_PERMISSION_TO_VIEW};
+ return (
+
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
+
+ );
}
return (
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/CustomPropertiesPageV1/CustomPropertiesPageV1.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/CustomPropertiesPageV1/CustomPropertiesPageV1.tsx
index 340e1fbebd5..ee2e0339501 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/CustomPropertiesPageV1/CustomPropertiesPageV1.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/CustomPropertiesPageV1/CustomPropertiesPageV1.tsx
@@ -39,6 +39,7 @@ import { CUSTOM_PROPERTIES_DOCS } from '../../constants/docs.constants';
import {
NO_PERMISSION_FOR_ACTION,
NO_PERMISSION_TO_VIEW,
+ REACH_OUT_TO_ADMIN_FOR_ACCESS,
} from '../../constants/HelperTextUtil';
import { PAGE_HEADERS } from '../../constants/PageHeaders.constant';
import { Type } from '../../generated/entity/type';
@@ -297,7 +298,9 @@ const CustomEntityDetailV1 = () => {
- {NO_PERMISSION_TO_VIEW}
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
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 e6139f9e85c..909b54013b0 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
@@ -37,7 +37,10 @@ import {
getServiceDetailsPath,
getVersionPath,
} from '../../constants/constants';
-import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil';
+import {
+ NO_PERMISSION_TO_VIEW,
+ REACH_OUT_TO_ADMIN_FOR_ACCESS,
+} from '../../constants/HelperTextUtil';
import { EntityType, TabSpecificField } from '../../enums/entity.enum';
import { FeedFilter } from '../../enums/mydata.enum';
import { ServiceCategory } from '../../enums/service.enum';
@@ -540,7 +543,11 @@ const DashboardDetailsPage = () => {
onExtensionUpdate={handleExtensionUpdate}
/>
) : (
- {NO_PERMISSION_TO_VIEW}
+
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
+
)}
>
)}
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DataModelPage/DataModelPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DataModelPage/DataModelPage.component.tsx
index b1b10072ba3..d644cebd256 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/DataModelPage/DataModelPage.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/DataModelPage/DataModelPage.component.tsx
@@ -21,7 +21,10 @@ import {
OperationPermission,
ResourceEntity,
} from 'components/PermissionProvider/PermissionProvider.interface';
-import { NO_PERMISSION_TO_VIEW } from 'constants/HelperTextUtil';
+import {
+ NO_PERMISSION_TO_VIEW,
+ REACH_OUT_TO_ADMIN_FOR_ACCESS,
+} from 'constants/HelperTextUtil';
import { EntityType } from 'enums/entity.enum';
import { FeedFilter } from 'enums/mydata.enum';
import { compare, Operation } from 'fast-json-patch';
@@ -469,7 +472,13 @@ const DataModelsPage = () => {
}
if (!hasViewPermission && !isLoading) {
- return {NO_PERMISSION_TO_VIEW};
+ return (
+
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
+
+ );
}
return (
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 35e3b9899db..7feecdbc30f 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
@@ -50,7 +50,10 @@ import {
getVersionPath,
pagingObject,
} from '../../constants/constants';
-import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil';
+import {
+ NO_PERMISSION_TO_VIEW,
+ REACH_OUT_TO_ADMIN_FOR_ACCESS,
+} from '../../constants/HelperTextUtil';
import { EntityType, FqnPart, TabSpecificField } from '../../enums/entity.enum';
import { FeedFilter } from '../../enums/mydata.enum';
import { ServiceCategory } from '../../enums/service.enum';
@@ -620,7 +623,11 @@ const DatasetDetailsPage: FunctionComponent = () => {
versionHandler={versionHandler}
/>
) : (
- {NO_PERMISSION_TO_VIEW}
+
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
+
)}
>
)}
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/GlobalSettingPage/GlobalSettingPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/GlobalSettingPage/GlobalSettingPage.tsx
index e97b11e5a23..4af38dcded8 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/GlobalSettingPage/GlobalSettingPage.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/GlobalSettingPage/GlobalSettingPage.tsx
@@ -11,14 +11,111 @@
* limitations under the License.
*/
+import { Menu, MenuProps } from 'antd';
+import { ItemType } from 'antd/lib/menu/hooks/useItems';
+import LeftPanelCard from 'components/common/LeftPanelCard/LeftPanelCard';
import PageContainerV1 from 'components/containers/PageContainerV1';
-import GlobalSetting from 'components/GlobalSetting/GlobalSetting';
-import React from 'react';
+import PageLayoutV1 from 'components/containers/PageLayoutV1';
+import { usePermissionProvider } from 'components/PermissionProvider/PermissionProvider';
+import GlobalSettingRouter from 'components/router/GlobalSettingRouter';
+import { GlobalSettingOptions } from 'constants/GlobalSettings.constants';
+import { ELASTIC_SEARCH_RE_INDEX_PAGE_TABS } from 'enums/ElasticSearch.enum';
+import { TeamType } from 'generated/entity/teams/team';
+import { useAuth } from 'hooks/authHooks';
+import React, { useMemo } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useHistory, useParams } from 'react-router-dom';
+import {
+ getGlobalSettingMenuItem,
+ getGlobalSettingsMenuWithPermission,
+ MenuList,
+} from 'utils/GlobalSettingsUtils';
+import {
+ getSettingPath,
+ getSettingsPathWithFqn,
+ getTeamsWithFqnPath,
+} from 'utils/RouterUtils';
+import './global-setting-page.style.less';
const GlobalSettingPage = () => {
+ const history = useHistory();
+ const { t } = useTranslation();
+ const { tab, settingCategory } = useParams<{ [key: string]: string }>();
+
+ const { permissions } = usePermissionProvider();
+
+ const { isAdminUser } = useAuth();
+
+ const menuItems: ItemType[] = useMemo(
+ () =>
+ getGlobalSettingsMenuWithPermission(permissions, isAdminUser).reduce(
+ (acc: ItemType[], curr: MenuList) => {
+ const menuItem = getGlobalSettingMenuItem({
+ label: curr.category,
+ key: curr.key,
+ category: curr.category,
+ children: curr.items,
+ type: 'group',
+ isBeta: curr.isBeta,
+ });
+ if (menuItem.children?.length) {
+ return [...acc, menuItem];
+ } else {
+ return acc;
+ }
+ },
+ [] as ItemType[]
+ ),
+ [permissions]
+ );
+
+ const onClick: MenuProps['onClick'] = (e) => {
+ // As we are setting key as "category.option" and extracting here category and option
+ const [category, option] = e.key.split('.');
+
+ switch (option) {
+ case GlobalSettingOptions.TEAMS:
+ history.push(getTeamsWithFqnPath(TeamType.Organization));
+
+ break;
+ case GlobalSettingOptions.SEARCH:
+ history.push(
+ getSettingsPathWithFqn(
+ category,
+ option,
+ ELASTIC_SEARCH_RE_INDEX_PAGE_TABS.ON_DEMAND
+ )
+ );
+
+ break;
+ default:
+ history.push(getSettingPath(category, option));
+
+ break;
+ }
+ };
+
+ const leftPanel = menuItems.length ? (
+
+
+
+ ) : null;
+
return (
-
+
+
+
);
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSetting.less b/openmetadata-ui/src/main/resources/ui/src/pages/GlobalSettingPage/global-setting-page.style.less
similarity index 100%
rename from openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSetting.less
rename to openmetadata-ui/src/main/resources/ui/src/pages/GlobalSettingPage/global-setting-page.style.less
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/MlModelPage/MlModelPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/MlModelPage/MlModelPage.component.tsx
index af0a7bf07b2..4b6540faab6 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/MlModelPage/MlModelPage.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/MlModelPage/MlModelPage.component.tsx
@@ -20,6 +20,9 @@ import { ResourceEntity } from 'components/PermissionProvider/PermissionProvider
import { compare, Operation } from 'fast-json-patch';
import { isEmpty, isNil, isUndefined, omitBy } from 'lodash';
import { observer } from 'mobx-react';
+import React, { Fragment, useEffect, useMemo, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useHistory, useParams } from 'react-router-dom';
import { getAllFeeds, postFeedById, postThread } from 'rest/feedsAPI';
import {
addFollower,
@@ -27,13 +30,12 @@ import {
patchMlModelDetails,
removeFollower,
} from 'rest/mlModelAPI';
-
-import React, { Fragment, useEffect, useMemo, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import { useHistory, useParams } from 'react-router-dom';
import AppState from '../../AppState';
import { getMlModelPath, getVersionPath } from '../../constants/constants';
-import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil';
+import {
+ NO_PERMISSION_TO_VIEW,
+ REACH_OUT_TO_ADMIN_FOR_ACCESS,
+} from '../../constants/HelperTextUtil';
import { EntityType, TabSpecificField } from '../../enums/entity.enum';
import { FeedFilter } from '../../enums/mydata.enum';
import { CreateThread } from '../../generated/api/feed/createThread';
@@ -450,7 +452,11 @@ const MlModelPage = () => {
{mlModelPermissions.ViewAll || mlModelPermissions.ViewBasic ? (
getMlModelDetail()
) : (
- {NO_PERMISSION_TO_VIEW}
+
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
+
)}
>
)}
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 99188cea96e..8f736e6787f 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
@@ -34,7 +34,10 @@ import {
getServiceDetailsPath,
getVersionPath,
} from '../../constants/constants';
-import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil';
+import {
+ NO_PERMISSION_TO_VIEW,
+ REACH_OUT_TO_ADMIN_FOR_ACCESS,
+} from '../../constants/HelperTextUtil';
import { EntityType } from '../../enums/entity.enum';
import { ServiceCategory } from '../../enums/service.enum';
import { Pipeline } from '../../generated/entity/data/pipeline';
@@ -310,7 +313,11 @@ const PipelineDetailsPage = () => {
onExtensionUpdate={handleExtensionUpdate}
/>
) : (
- {NO_PERMISSION_TO_VIEW}
+
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
+
)}
>
)}
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/QueryPage/QueryPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/QueryPage/QueryPage.component.tsx
index c10833b027f..5135c2c7870 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/QueryPage/QueryPage.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/QueryPage/QueryPage.component.tsx
@@ -31,7 +31,10 @@ import {
getServiceDetailsPath,
getTableTabPath,
} from 'constants/constants';
-import { NO_PERMISSION_TO_VIEW } from 'constants/HelperTextUtil';
+import {
+ NO_PERMISSION_TO_VIEW,
+ REACH_OUT_TO_ADMIN_FOR_ACCESS,
+} from 'constants/HelperTextUtil';
import { FqnPart } from 'enums/entity.enum';
import { ServiceCategory } from 'enums/service.enum';
import { compare } from 'fast-json-patch';
@@ -214,7 +217,13 @@ const QueryPage = () => {
return ;
}
if (!isViewAllowed) {
- return {NO_PERMISSION_TO_VIEW};
+ return (
+
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
+
+ );
}
if (isUndefined(query)) {
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TestSuiteDetailsPage/TestSuiteDetailsPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TestSuiteDetailsPage/TestSuiteDetailsPage.component.tsx
index e06bad64003..d6557deee7e 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/TestSuiteDetailsPage/TestSuiteDetailsPage.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/TestSuiteDetailsPage/TestSuiteDetailsPage.component.tsx
@@ -47,7 +47,10 @@ import {
pagingObject,
ROUTES,
} from '../../constants/constants';
-import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil';
+import {
+ NO_PERMISSION_TO_VIEW,
+ REACH_OUT_TO_ADMIN_FOR_ACCESS,
+} from '../../constants/HelperTextUtil';
import { ACTION_TYPE } from '../../enums/common.enum';
import { OwnerType } from '../../enums/user.enum';
import { TestCase } from '../../generated/tests/testCase';
@@ -363,7 +366,11 @@ const TestSuiteDetailsPage = () => {
) : (
- {NO_PERMISSION_TO_VIEW}
+
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
+
)}
>
);
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 7face105236..c68925f1629 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
@@ -40,7 +40,10 @@ import {
getTopicDetailsPath,
getVersionPath,
} from '../../constants/constants';
-import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil';
+import {
+ NO_PERMISSION_TO_VIEW,
+ REACH_OUT_TO_ADMIN_FOR_ACCESS,
+} from '../../constants/HelperTextUtil';
import { EntityType, TabSpecificField } from '../../enums/entity.enum';
import { FeedFilter } from '../../enums/mydata.enum';
import { ServiceCategory } from '../../enums/service.enum';
@@ -466,7 +469,11 @@ const TopicDetailsPage: FunctionComponent = () => {
onExtensionUpdate={handleExtensionUpdate}
/>
) : (
- {NO_PERMISSION_TO_VIEW}
+
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
+
)}
>
)}
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/services/ServicesPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/services/ServicesPage.tsx
index 65a3bd9f57f..1b1ed337bfc 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/services/ServicesPage.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/services/ServicesPage.tsx
@@ -23,7 +23,10 @@ import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom';
import { getServices } from 'rest/serviceAPI';
import { pagingObject, SERVICE_VIEW_CAP } from '../../constants/constants';
-import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil';
+import {
+ NO_PERMISSION_TO_VIEW,
+ REACH_OUT_TO_ADMIN_FOR_ACCESS,
+} from '../../constants/HelperTextUtil';
import {
OPEN_METADATA,
SERVICE_CATEGORY,
@@ -119,7 +122,9 @@ const ServicesPage = () => {
- {NO_PERMISSION_TO_VIEW}
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/teams/TeamsPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/teams/TeamsPage.tsx
index dc0ed1be01c..59d76ba2f0c 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/teams/TeamsPage.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/teams/TeamsPage.tsx
@@ -42,7 +42,10 @@ import {
PAGE_SIZE_MEDIUM,
pagingObject,
} from '../../constants/constants';
-import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil';
+import {
+ NO_PERMISSION_TO_VIEW,
+ REACH_OUT_TO_ADMIN_FOR_ACCESS,
+} from '../../constants/HelperTextUtil';
import { myDataSearchIndex } from '../../constants/Mydata.constants';
import { SearchIndex } from '../../enums/search.enum';
import { CreateTeam, TeamType } from '../../generated/api/teams/createTeam';
@@ -603,7 +606,11 @@ const TeamsPage = () => {
/>
>
) : (
- {NO_PERMISSION_TO_VIEW}
+
+
+ {NO_PERMISSION_TO_VIEW}
{REACH_OUT_TO_ADMIN_FOR_ACCESS}
+
+
);
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/ToastUtils.ts b/openmetadata-ui/src/main/resources/ui/src/utils/ToastUtils.ts
index 6e7366e129d..a60c2492eac 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/ToastUtils.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/ToastUtils.ts
@@ -12,6 +12,7 @@
*/
import { AxiosError } from 'axios';
+import { ClientErrors } from 'enums/axios.enum';
import { isEmpty, isString } from 'lodash';
import React from 'react';
import { toast } from 'react-toastify';
@@ -60,7 +61,8 @@ export const showErrorToast = (
// except for principal domain mismatch errors
if (
error &&
- error.response?.status === 401 &&
+ (error.response?.status === ClientErrors.UNAUTHORIZED ||
+ error.response?.status === ClientErrors.FORBIDDEN) &&
!errorMessage.includes('principal domain')
) {
return;