diff --git a/frontend/src/components/RouteTab/RouteTab.test.tsx b/frontend/src/components/RouteTab/RouteTab.test.tsx
new file mode 100644
index 0000000000..21894cb006
--- /dev/null
+++ b/frontend/src/components/RouteTab/RouteTab.test.tsx
@@ -0,0 +1,90 @@
+import { fireEvent, render, screen } from '@testing-library/react';
+import { createMemoryHistory } from 'history';
+import { Router } from 'react-router-dom';
+
+import RouteTab from './index';
+
+function DummyComponent1(): JSX.Element {
+ return
Dummy Component 1
;
+}
+function DummyComponent2(): JSX.Element {
+ return Dummy Component 2
;
+}
+
+const testRoutes = [
+ {
+ name: 'Tab1',
+ route: '/tab1',
+ Component: DummyComponent1,
+ },
+ {
+ name: 'Tab2',
+ route: '/tab2',
+ Component: DummyComponent2,
+ },
+];
+
+describe('RouteTab component', () => {
+ test('renders correctly', () => {
+ const history = createMemoryHistory();
+ render(
+
+
+ ,
+ );
+ expect(screen.getByRole('tab', { name: 'Tab1' })).toBeInTheDocument();
+ expect(screen.getByRole('tab', { name: 'Tab2' })).toBeInTheDocument();
+ });
+
+ test('renders correct number of tabs', () => {
+ const history = createMemoryHistory();
+ render(
+
+
+ ,
+ );
+ const tabs = screen.getAllByRole('tab');
+ expect(tabs.length).toBe(testRoutes.length);
+ });
+
+ test('sets provided activeKey as active tab', () => {
+ const history = createMemoryHistory();
+ render(
+
+
+ ,
+ );
+ expect(
+ screen.getByRole('tab', { name: 'Tab2', selected: true }),
+ ).toBeInTheDocument();
+ });
+
+ test('navigates to correct route on tab click', () => {
+ const history = createMemoryHistory();
+ render(
+
+
+ ,
+ );
+ expect(history.location.pathname).toBe('/');
+ fireEvent.click(screen.getByRole('tab', { name: 'Tab2' }));
+ expect(history.location.pathname).toBe('/tab2');
+ });
+
+ test('calls onChangeHandler on tab change', () => {
+ const onChangeHandler = jest.fn();
+ const history = createMemoryHistory();
+ render(
+
+
+ ,
+ );
+ fireEvent.click(screen.getByRole('tab', { name: 'Tab2' }));
+ expect(onChangeHandler).toHaveBeenCalled();
+ });
+});
diff --git a/frontend/src/components/RouteTab/index.tsx b/frontend/src/components/RouteTab/index.tsx
index 07b9f70938..4e4a9fe72e 100644
--- a/frontend/src/components/RouteTab/index.tsx
+++ b/frontend/src/components/RouteTab/index.tsx
@@ -1,10 +1,11 @@
import { Tabs, TabsProps } from 'antd';
-import history from 'lib/history';
+import { History } from 'history';
function RouteTab({
routes,
activeKey,
onChangeHandler,
+ history,
...rest
}: RouteTabProps & TabsProps): JSX.Element {
const onChange = (activeRoute: string): void => {
@@ -47,6 +48,7 @@ interface RouteTabProps {
}[];
activeKey: TabsProps['activeKey'];
onChangeHandler?: VoidFunction;
+ history: History;
}
RouteTab.defaultProps = {
diff --git a/frontend/src/container/MetricsApplication/index.tsx b/frontend/src/container/MetricsApplication/index.tsx
index e0d76100ec..7127405450 100644
--- a/frontend/src/container/MetricsApplication/index.tsx
+++ b/frontend/src/container/MetricsApplication/index.tsx
@@ -1,7 +1,8 @@
import RouteTab from 'components/RouteTab';
import ROUTES from 'constants/routes';
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
-import { memo } from 'react';
+import history from 'lib/history';
+import { memo, useMemo } from 'react';
import { generatePath, useParams } from 'react-router-dom';
import { useLocation } from 'react-use';
@@ -52,35 +53,37 @@ function ServiceMetrics(): JSX.Element {
const activeKey = getActiveKey();
+ const routes = useMemo(
+ () => [
+ {
+ Component: OverViewTab,
+ name: overMetrics,
+ route: `${generatePath(ROUTES.SERVICE_METRICS, {
+ servicename,
+ })}?tab=${overMetrics}`,
+ },
+ {
+ Component: DbCallTab,
+ name: dbCallMetrics,
+ route: `${generatePath(ROUTES.SERVICE_METRICS, {
+ servicename,
+ })}?tab=${dbCallMetrics}`,
+ },
+ {
+ Component: ExternalTab,
+ name: externalMetrics,
+ route: `${generatePath(ROUTES.SERVICE_METRICS, {
+ servicename,
+ })}?tab=${externalMetrics}`,
+ },
+ ],
+ [servicename],
+ );
+
return (
<>
-
+
>
);
}
diff --git a/frontend/src/hooks/useComponentPermission.test.ts b/frontend/src/hooks/useComponentPermission.test.ts
new file mode 100644
index 0000000000..17fcc5b921
--- /dev/null
+++ b/frontend/src/hooks/useComponentPermission.test.ts
@@ -0,0 +1,100 @@
+import { renderHook } from '@testing-library/react';
+import { ComponentTypes } from 'utils/permission';
+
+import useComponentPermission from './useComponentPermission';
+
+describe('useComponentPermission', () => {
+ const componentList: ComponentTypes[] = [
+ 'current_org_settings',
+ 'invite_members',
+ 'create_new_dashboards',
+ 'import_dashboard',
+ 'export_dashboard',
+ 'add_new_alert',
+ 'add_new_channel',
+ 'set_retention_period',
+ 'action',
+ 'save_layout',
+ 'edit_dashboard',
+ 'delete_widget',
+ 'new_dashboard',
+ 'new_alert_action',
+ 'edit_widget',
+ 'add_panel',
+ ];
+
+ it('should return correct permissions for ADMIN role', () => {
+ const { result } = renderHook(() =>
+ useComponentPermission(componentList, 'ADMIN'),
+ );
+ const expectedResult = [
+ true, // current_org_settings
+ true, // invite_members
+ true, // create_new_dashboards
+ true, // import_dashboard
+ true, // export_dashboard
+ true, // add_new_alert
+ true, // add_new_channel
+ true, // set_retention_period
+ true, // action
+ true, // save_layout
+ true, // edit_dashboard
+ true, // delete_widget
+ true, // new_dashboard
+ true, // new_alert_action
+ true, // edit_widget
+ true, // add_panel
+ ];
+ expect(result.current).toEqual(expectedResult);
+ });
+
+ it('should return correct permissions for EDITOR role', () => {
+ const { result } = renderHook(() =>
+ useComponentPermission(componentList, 'EDITOR'),
+ );
+ const expectedResult = [
+ false, // current_org_settings
+ false, // invite_members
+ true, // create_new_dashboards
+ true, // import_dashboard
+ true, // export_dashboard
+ true, // add_new_alert
+ false, // add_new_channel
+ false, // set_retention_period
+ true, // action
+ true, // save_layout
+ true, // edit_dashboard
+ true, // delete_widget
+ true, // new_dashboard
+ false, // new_alert_action
+ true, // edit_widget
+ true, // add_panel
+ ];
+ expect(result.current).toEqual(expectedResult);
+ });
+
+ it('should return correct permissions for VIEWER role', () => {
+ const { result } = renderHook(() =>
+ useComponentPermission(componentList, 'VIEWER'),
+ );
+ const expectedResult = [
+ false, // current_org_settings
+ false, // invite_members
+ false, // create_new_dashboards
+ false, // import_dashboard
+ true, // export_dashboard
+ false, // add_new_alert
+ false, // add_new_channel
+ false, // set_retention_period
+ false, // action
+ false, // save_layout
+ false, // edit_dashboard
+ false, // delete_widget
+ false, // new_dashboard
+ false, // new_alert_action
+ false, // edit_widget
+ false, // add_panel
+ ];
+ expect(result.current).toEqual(expectedResult);
+ });
+});
diff --git a/frontend/src/pages/AlertChannelCreate/index.tsx b/frontend/src/pages/AlertChannelCreate/index.tsx
index 09d55d320e..3ed6348969 100644
--- a/frontend/src/pages/AlertChannelCreate/index.tsx
+++ b/frontend/src/pages/AlertChannelCreate/index.tsx
@@ -11,6 +11,7 @@ function SettingsPage(): JSX.Element {
const { t } = useTranslation();
return (
[
+ {
+ Component: AllErrorsContainer,
+ name: t('routes.all_errors'),
+ route: ROUTES.ALL_ERROR,
+ },
+ ],
+ [t],
+ );
+
return (
<>
>
);
diff --git a/frontend/src/pages/Settings/index.tsx b/frontend/src/pages/Settings/index.tsx
index 93a668b420..9e1be1f4f0 100644
--- a/frontend/src/pages/Settings/index.tsx
+++ b/frontend/src/pages/Settings/index.tsx
@@ -52,10 +52,9 @@ function SettingsPage(): JSX.Element {
return (
);
}