diff --git a/frontend/src/container/AppLayout/index.tsx b/frontend/src/container/AppLayout/index.tsx
index 7574e59143..6546271c7f 100644
--- a/frontend/src/container/AppLayout/index.tsx
+++ b/frontend/src/container/AppLayout/index.tsx
@@ -25,7 +25,7 @@ import {
} from 'types/actions/app';
import AppReducer from 'types/reducer/app';
-import { ChildrenContainer, Layout } from './styles';
+import { ChildrenContainer, Layout, LayoutContent } from './styles';
import { getRouteKey } from './utils';
function AppLayout(props: AppLayoutProps): JSX.Element {
@@ -240,12 +240,12 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
{isToDisplayLayout && }
{isToDisplayLayout && }
-
+
{isToDisplayLayout && }
{children}
-
+
);
diff --git a/frontend/src/container/AppLayout/styles.ts b/frontend/src/container/AppLayout/styles.ts
index 1f48b54033..d3a030bf1f 100644
--- a/frontend/src/container/AppLayout/styles.ts
+++ b/frontend/src/container/AppLayout/styles.ts
@@ -7,9 +7,14 @@ export const Layout = styled(LayoutComponent)`
position: relative;
min-height: calc(100vh - 4rem);
overflow: hidden;
+ height: 100%;
}
`;
+export const LayoutContent = styled(LayoutComponent.Content)`
+ overflow-y: auto;
+`;
+
export const ChildrenContainer = styled.div`
margin: 0 1rem;
display: flex;
diff --git a/frontend/src/container/SideNav/index.tsx b/frontend/src/container/SideNav/SideNav.tsx
similarity index 59%
rename from frontend/src/container/SideNav/index.tsx
rename to frontend/src/container/SideNav/SideNav.tsx
index 0a4942f115..4271b47690 100644
--- a/frontend/src/container/SideNav/index.tsx
+++ b/frontend/src/container/SideNav/SideNav.tsx
@@ -1,33 +1,30 @@
import { CheckCircleTwoTone, WarningOutlined } from '@ant-design/icons';
-import { Menu, MenuProps } from 'antd';
+import { MenuProps } from 'antd';
import getLocalStorageKey from 'api/browser/localstorage/get';
import { IS_SIDEBAR_COLLAPSED } from 'constants/app';
import ROUTES from 'constants/routes';
import history from 'lib/history';
-import {
- ReactNode,
- useCallback,
- useLayoutEffect,
- useMemo,
- useState,
-} from 'react';
+import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
-import { SideBarCollapse } from 'store/actions/app';
+import { sideBarCollapse } from 'store/actions/app';
import { AppState } from 'store/reducers';
import AppReducer from 'types/reducer/app';
import { routeConfig, styles } from './config';
import { getQueryString } from './helper';
-import menus from './menuItems';
+import menuItems from './menuItems';
+import { MenuItem, SecondaryMenuItemKey } from './sideNav.types';
+import { getActiveMenuKeyFromPath } from './sideNav.utils';
import Slack from './Slack';
import {
+ MenuLabelContainer,
RedDot,
Sider,
- SlackButton,
- SlackMenuItemContainer,
- VersionContainer,
+ StyledPrimaryMenu,
+ StyledSecondaryMenu,
+ StyledText,
} from './styles';
function SideNav(): JSX.Element {
@@ -49,7 +46,7 @@ function SideNav(): JSX.Element {
}, []);
useLayoutEffect(() => {
- dispatch(SideBarCollapse(collapsed));
+ dispatch(sideBarCollapse(collapsed));
}, [collapsed, dispatch]);
const onClickHandler = useCallback(
@@ -80,90 +77,56 @@ function SideNav(): JSX.Element {
const isNotCurrentVersion = currentVersion !== latestVersion;
- const sidebar: SidebarItem[] = [
+ const secondaryMenuItems: MenuItem[] = [
{
- onClick: onClickSlackHandler,
- icon: ,
- text: Support,
- key: 'slack',
- },
- {
- onClick: onClickVersionHandler,
- key: 'version',
+ key: SecondaryMenuItemKey.Version,
icon: isNotCurrentVersion ? (
) : (
),
- text: (
-
- {!isCurrentVersionError ? (
- {currentVersion}
- ) : (
- {t('n_a')}
- )}
+ label: (
+
+
+ {!isCurrentVersionError ? currentVersion : t('n_a')}
+
{isNotCurrentVersion && }
-
+
),
+ onClick: onClickVersionHandler,
+ },
+ {
+ key: SecondaryMenuItemKey.Slack,
+ icon: ,
+ label: Support,
+ onClick: onClickSlackHandler,
},
];
- const currentMenu = useMemo(() => {
- const routeKeys = Object.keys(ROUTES) as (keyof typeof ROUTES)[];
- const currentRouteKey = routeKeys.find((key) => {
- const route = ROUTES[key];
- return pathname === route;
- });
-
- if (!currentRouteKey) return null;
-
- return ROUTES[currentRouteKey];
- }, [pathname]);
-
- const sidebarItems = (props: SidebarItem, index: number): SidebarItem => ({
- key: `${index}`,
- icon: props.icon,
- onClick: props.onClick,
- label: props.text,
- });
+ const activeMenuKey = useMemo(() => getActiveMenuKeyFromPath(pathname), [
+ pathname,
+ ]);
return (
-
- {sidebar.map((props, index) => (
-
-
-
- ))}
+
);
}
-interface SidebarItem {
- onClick: VoidFunction;
- icon?: ReactNode;
- text?: ReactNode;
- key: string;
- label?: ReactNode;
-}
-
export default SideNav;
diff --git a/frontend/src/container/SideNav/Slack.tsx b/frontend/src/container/SideNav/Slack.tsx
index 118ac924c1..ed9992cdf3 100644
--- a/frontend/src/container/SideNav/Slack.tsx
+++ b/frontend/src/container/SideNav/Slack.tsx
@@ -1,6 +1,6 @@
interface ISlackProps {
- width?: number;
- height?: number;
+ width?: number | string;
+ height?: number | string;
}
function Slack({ width, height }: ISlackProps): JSX.Element {
return (
@@ -47,8 +47,8 @@ function Slack({ width, height }: ISlackProps): JSX.Element {
);
}
Slack.defaultProps = {
- width: 28,
- height: 28,
+ width: '1em',
+ height: '1em',
};
export default Slack;
diff --git a/frontend/src/container/SideNav/index.ts b/frontend/src/container/SideNav/index.ts
new file mode 100644
index 0000000000..919d1a693f
--- /dev/null
+++ b/frontend/src/container/SideNav/index.ts
@@ -0,0 +1,3 @@
+import SideNav from './SideNav';
+
+export default SideNav;
diff --git a/frontend/src/container/SideNav/menuItems.tsx b/frontend/src/container/SideNav/menuItems.tsx
index b7348e3d50..3591923cc4 100644
--- a/frontend/src/container/SideNav/menuItems.tsx
+++ b/frontend/src/container/SideNav/menuItems.tsx
@@ -10,28 +10,11 @@ import {
MenuOutlined,
SettingOutlined,
} from '@ant-design/icons';
-import { MenuProps, Space, Typography } from 'antd';
import ROUTES from 'constants/routes';
-import { Tags } from './styles';
+import { SidebarMenu } from './sideNav.types';
-type MenuItem = Required['items'][number];
-
-export const createLabelWithTags = (
- label: string,
- tags: string[],
-): JSX.Element => (
-
- {label}
- {tags.map((tag) => (
-
- {tag}
-
- ))}
-
-);
-
-const menus: SidebarMenu[] = [
+const menuItems: SidebarMenu[] = [
{
key: ROUTES.APPLICATION,
label: 'Services',
@@ -111,8 +94,11 @@ const menus: SidebarMenu[] = [
},
];
-type SidebarMenu = MenuItem & {
- tags?: string[];
+/** Mapping of some newly added routes and their corresponding active sidebar menu key */
+export const NEW_ROUTES_MENU_ITEM_KEY_MAP = {
+ [ROUTES.TRACES_EXPLORER]: ROUTES.TRACE,
+ [ROUTES.TRACE_EXPLORER]: ROUTES.TRACE,
+ [ROUTES.LOGS_EXPLORER]: ROUTES.LOGS,
};
-export default menus;
+export default menuItems;
diff --git a/frontend/src/container/SideNav/sideNav.types.ts b/frontend/src/container/SideNav/sideNav.types.ts
new file mode 100644
index 0000000000..d67862e51c
--- /dev/null
+++ b/frontend/src/container/SideNav/sideNav.types.ts
@@ -0,0 +1,21 @@
+import { MenuProps } from 'antd';
+import { ReactNode } from 'react';
+
+export type MenuItem = Required['items'][number];
+
+export type SidebarMenu = MenuItem & {
+ tags?: string[];
+};
+
+export interface SidebarItem {
+ onClick: VoidFunction;
+ icon?: ReactNode;
+ text?: ReactNode;
+ key: string;
+ label?: ReactNode;
+}
+
+export enum SecondaryMenuItemKey {
+ Slack = 'slack',
+ Version = 'version',
+}
diff --git a/frontend/src/container/SideNav/sideNav.utils.ts b/frontend/src/container/SideNav/sideNav.utils.ts
new file mode 100644
index 0000000000..3c455ddab2
--- /dev/null
+++ b/frontend/src/container/SideNav/sideNav.utils.ts
@@ -0,0 +1,11 @@
+import { NEW_ROUTES_MENU_ITEM_KEY_MAP } from './menuItems';
+
+export const getActiveMenuKeyFromPath = (pathname: string): string => {
+ const basePath = pathname?.split('/')?.[1]; // Get the base path, Eg; /dashboard/dc5beb63-589c-46a3-ad4c-1b9ca248ee33 -> dashboard
+
+ if (!basePath) return '';
+
+ const baseRoute = `/${basePath}`;
+
+ return NEW_ROUTES_MENU_ITEM_KEY_MAP[baseRoute] || baseRoute;
+};
diff --git a/frontend/src/container/SideNav/styles.ts b/frontend/src/container/SideNav/styles.ts
index 9cdca6065c..35dcc2ed38 100644
--- a/frontend/src/container/SideNav/styles.ts
+++ b/frontend/src/container/SideNav/styles.ts
@@ -1,87 +1,68 @@
-import { Layout, Tag, Typography } from 'antd';
-import { StyledCSS } from 'container/GantChart/Trace/styles';
-import styled, { css } from 'styled-components';
+import { Layout, Menu, Typography } from 'antd';
+import styled from 'styled-components';
const { Sider: SiderComponent } = Layout;
-interface LogoProps {
- collapsed: boolean;
- index: number;
-}
-
export const Sider = styled(SiderComponent)`
&&& {
background: #1f1f1f;
+ .ant-layout-sider-children {
+ display: flex;
+ flex-direction: column;
+ }
+
.ant-layout-sider-trigger {
background: #1f1f1f;
}
}
`;
-export const SlackButton = styled(Typography)`
- &&& {
- margin-left: 1rem;
- color: white;
- }
+export const StyledPrimaryMenu = styled(Menu)`
+ flex: 1;
+ overflow-y: auto;
`;
-export const SlackMenuItemContainer = styled.div`
- position: fixed;
- bottom: ${({ index }): string => `${index * 48 + (index + 16)}px`};
- background: #262626;
- width: ${({ collapsed }): string => (!collapsed ? '200px' : '80px')};
- transition: inherit;
- background: #1f1f1f;
-
+export const StyledSecondaryMenu = styled(Menu)`
&&& {
- li {
- ${({ collapsed }): StyledCSS =>
- collapsed &&
- css`
- padding-left: 24px;
- padding-top: 6px;
- `}
+ :not(.ant-menu-inline-collapsed) > .ant-menu-item {
+ padding-inline: 48px;
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
}
- svg {
- margin-left: ${({ collapsed }): string => (collapsed ? '0' : '24px')};
- width: 28px;
- height: 28px;
-
- ${({ collapsed }): StyledCSS =>
- collapsed &&
- css`
- height: 100%;
- margin: 0 auto;
- `}
- }
.ant-menu-title-content {
- margin: 0;
+ margin-inline-start: 10px;
+ width: 100%;
+ }
+
+ &.ant-menu-inline-collapsed .ant-menu-title-content {
+ opacity: 0;
}
}
`;
export const RedDot = styled.div`
- width: 12px;
- height: 12px;
+ width: 10px;
+ height: 10px;
background: #d32029;
border-radius: 50%;
margin-left: 0.5rem;
- margin-top: 0.5rem;
`;
-export const VersionContainer = styled.div`
- &&& {
- display: flex;
- }
+export const MenuLabelContainer = styled.div`
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+
+ width: 100%;
`;
-export const Tags = styled(Tag)`
- &&& {
- position: absolute;
- top: 0;
- border-radius: 0.5rem;
- }
+export const StyledText = styled(Typography.Text)`
+ width: 100%;
+
+ color: white;
`;
diff --git a/frontend/src/container/TopNav/styles.ts b/frontend/src/container/TopNav/styles.ts
index feda027d24..ef3cb15c37 100644
--- a/frontend/src/container/TopNav/styles.ts
+++ b/frontend/src/container/TopNav/styles.ts
@@ -4,6 +4,5 @@ import styled from 'styled-components';
export const Container = styled(Row)`
&&& {
margin-top: 2rem;
- min-height: 8vh;
}
`;
diff --git a/frontend/src/globalStyles.ts b/frontend/src/globalStyles.ts
new file mode 100644
index 0000000000..86dc8258ed
--- /dev/null
+++ b/frontend/src/globalStyles.ts
@@ -0,0 +1,18 @@
+import { createGlobalStyle } from 'styled-components';
+
+const GlobalStyles = createGlobalStyle`
+#root,
+html,
+body {
+ height: 100%;
+ overflow: hidden;
+}
+
+body {
+ padding: 0;
+ margin: 0;
+ box-sizing: border-box;
+}
+`;
+
+export default GlobalStyles;
diff --git a/frontend/src/index.html.ejs b/frontend/src/index.html.ejs
index 6d7c037e1f..0e198e2cf3 100644
--- a/frontend/src/index.html.ejs
+++ b/frontend/src/index.html.ejs
@@ -57,7 +57,7 @@
rel="stylesheet"
/>
-
+
diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx
index 049c0a4c0e..fd2d4c7b0e 100644
--- a/frontend/src/index.tsx
+++ b/frontend/src/index.tsx
@@ -2,6 +2,7 @@ import './wdyr';
import './ReactI18';
import AppRoutes from 'AppRoutes';
+import GlobalStyles from 'globalStyles';
import { ThemeProvider } from 'hooks/useDarkMode';
import { createRoot } from 'react-dom/client';
import { HelmetProvider } from 'react-helmet-async';
@@ -33,6 +34,7 @@ if (container) {
+
{process.env.NODE_ENV === 'development' && (
diff --git a/frontend/src/store/actions/app/sideBarCollapse.ts b/frontend/src/store/actions/app/sideBarCollapse.ts
index dc2fde6108..c99d79b6fb 100644
--- a/frontend/src/store/actions/app/sideBarCollapse.ts
+++ b/frontend/src/store/actions/app/sideBarCollapse.ts
@@ -3,7 +3,7 @@ import { IS_SIDEBAR_COLLAPSED } from 'constants/app';
import { Dispatch } from 'redux';
import AppActions from 'types/actions';
-export const SideBarCollapse = (
+export const sideBarCollapse = (
collapseState: boolean,
): ((dispatch: Dispatch) => void) => {
setLocalStorageKey(IS_SIDEBAR_COLLAPSED, `${collapseState}`);