From 0c59953cb5ae27e0280311e0a8dee3d4de874569 Mon Sep 17 00:00:00 2001 From: Yunus M Date: Sat, 17 Feb 2024 14:59:49 +0530 Subject: [PATCH] feat: open left nav items in new tab on cmd ctrl click (#4561) --- frontend/src/AppRoutes/Private.tsx | 4 +- .../container/LogDetailedView/TableView.tsx | 25 ++-- .../src/container/LogsError/LogsError.tsx | 17 ++- frontend/src/container/NoLogs/NoLogs.tsx | 8 +- .../SideNav/NavItem/NavItem.styles.scss | 1 + .../src/container/SideNav/NavItem/NavItem.tsx | 7 +- frontend/src/container/SideNav/SideNav.tsx | 117 ++++++++++++------ 7 files changed, 128 insertions(+), 51 deletions(-) diff --git a/frontend/src/AppRoutes/Private.tsx b/frontend/src/AppRoutes/Private.tsx index aafaa932af..e409e3e3e6 100644 --- a/frontend/src/AppRoutes/Private.tsx +++ b/frontend/src/AppRoutes/Private.tsx @@ -20,7 +20,7 @@ import { UPDATE_USER_IS_FETCH } from 'types/actions/app'; import AppReducer from 'types/reducer/app'; import { routePermission } from 'utils/permission'; -import routes from './routes'; +import routes, { LIST_LICENSES } from './routes'; import afterLogin from './utils'; function PrivateRoute({ children }: PrivateRouteProps): JSX.Element { @@ -29,7 +29,7 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element { const mapRoutes = useMemo( () => new Map( - routes.map((e) => { + [...routes, LIST_LICENSES].map((e) => { const currentPath = matchPath(pathname, { path: e.path, }); diff --git a/frontend/src/container/LogDetailedView/TableView.tsx b/frontend/src/container/LogDetailedView/TableView.tsx index 29224e65ae..21774291f5 100644 --- a/frontend/src/container/LogDetailedView/TableView.tsx +++ b/frontend/src/container/LogDetailedView/TableView.tsx @@ -100,7 +100,10 @@ function TableView({ value: JSON.stringify(flattenLogData[key]), })); - const onTraceHandler = (record: DataType) => (): void => { + const onTraceHandler = ( + record: DataType, + event: React.MouseEvent, + ) => (): void => { if (flattenLogData === null) return; const traceId = flattenLogData[record.field]; @@ -119,7 +122,12 @@ function TableView({ const route = spanId ? `${basePath}?spanId=${spanId}` : basePath; - history.push(route); + if (event.ctrlKey || event.metaKey) { + // open the trace in new tab + window.open(route, '_blank'); + } else { + history.push(route); + } } }; @@ -148,17 +156,20 @@ function TableView({ {traceId && ( -
, + ): void => { + onTraceHandler(record, event); + }} > -
+
)} diff --git a/frontend/src/container/LogsError/LogsError.tsx b/frontend/src/container/LogsError/LogsError.tsx index 0b3c9f501d..6143674c6b 100644 --- a/frontend/src/container/LogsError/LogsError.tsx +++ b/frontend/src/container/LogsError/LogsError.tsx @@ -1,9 +1,20 @@ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +/* eslint-disable jsx-a11y/click-events-have-key-events */ import './LogsError.styles.scss'; import { Typography } from 'antd'; +import history from 'lib/history'; import { ArrowRight } from 'lucide-react'; +import { isCloudUser } from 'utils/app'; export default function LogsError(): JSX.Element { + const handleContactSupport = (): void => { + if (isCloudUser()) { + history.push('/support'); + } else { + window.open('https://signoz.io/slack', '_blank'); + } + }; return (
@@ -16,10 +27,12 @@ export default function LogsError(): JSX.Element { Aw snap :/ Something went wrong. Please try again or contact support. -
+ +
Contact Support + -
+
); diff --git a/frontend/src/container/NoLogs/NoLogs.tsx b/frontend/src/container/NoLogs/NoLogs.tsx index df934b7bcc..1274bdb20a 100644 --- a/frontend/src/container/NoLogs/NoLogs.tsx +++ b/frontend/src/container/NoLogs/NoLogs.tsx @@ -9,13 +9,17 @@ export default function NoLogs(): JSX.Element {
eyes emoji - No logs yet.{' '} + No logs yet. When we receive logs, they would show up here - + Sending Logs to SigNoz
diff --git a/frontend/src/container/SideNav/NavItem/NavItem.styles.scss b/frontend/src/container/SideNav/NavItem/NavItem.styles.scss index f182a1df6d..fe5952d400 100644 --- a/frontend/src/container/SideNav/NavItem/NavItem.styles.scss +++ b/frontend/src/container/SideNav/NavItem/NavItem.styles.scss @@ -7,6 +7,7 @@ height: 36px; margin-bottom: 4px; + cursor: pointer; &.active { .nav-item-active-marker { diff --git a/frontend/src/container/SideNav/NavItem/NavItem.tsx b/frontend/src/container/SideNav/NavItem/NavItem.tsx index 0ec6127da1..4171f2f4f5 100644 --- a/frontend/src/container/SideNav/NavItem/NavItem.tsx +++ b/frontend/src/container/SideNav/NavItem/NavItem.tsx @@ -16,13 +16,16 @@ export default function NavItem({ isCollapsed: boolean; item: SidebarItem; isActive: boolean; - onClick: () => void; + onClick: (event: React.MouseEvent) => void; }): JSX.Element { const { label, icon } = item; return ( -
+
onClick(event)} + >
{icon}
diff --git a/frontend/src/container/SideNav/SideNav.tsx b/frontend/src/container/SideNav/SideNav.tsx index a98d9eacd9..665a406710 100644 --- a/frontend/src/container/SideNav/SideNav.tsx +++ b/frontend/src/container/SideNav/SideNav.tsx @@ -19,7 +19,7 @@ import { RocketIcon, UserCircle, } from 'lucide-react'; -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { MouseEvent, useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import { useLocation } from 'react-router-dom'; @@ -40,7 +40,7 @@ import defaultMenuItems, { trySignozCloudMenuItem, } from './menuItems'; import NavItem from './NavItem/NavItem'; -import { SecondaryMenuItemKey } from './sideNav.types'; +import { SecondaryMenuItemKey, SidebarItem } from './sideNav.types'; import { getActiveMenuKeyFromPath } from './sideNav.utils'; interface UserManagementMenuItems { @@ -88,10 +88,6 @@ function SideNav({ window.open('https://signoz.io/slack', '_blank'); }; - const onClickVersionHandler = (): void => { - history.push(ROUTES.VERSION); - }; - const isLatestVersion = checkVersionState(currentVersion, latestVersion); const [inviteMembers] = useComponentPermission(['invite_members'], role); @@ -164,23 +160,49 @@ function SideNav({ ); }; - const onClickShortcuts = (): void => { - history.push(`/shortcuts`); + const isCtrlMetaKey = (e: MouseEvent): boolean => e.ctrlKey || e.metaKey; + + const openInNewTab = (path: string): void => { + window.open(path, '_blank'); }; - const onClickGetStarted = (): void => { - history.push(`/get-started`); + const onClickShortcuts = (e: MouseEvent): void => { + if (isCtrlMetaKey(e)) { + openInNewTab('/shortcuts'); + } else { + history.push(`/shortcuts`); + } + }; + + const onClickGetStarted = (event: MouseEvent): void => { + if (isCtrlMetaKey(event)) { + openInNewTab('/get-started'); + } else { + history.push(`/get-started`); + } + }; + + const onClickVersionHandler = (event: MouseEvent): void => { + if (isCtrlMetaKey(event)) { + openInNewTab(ROUTES.VERSION); + } else { + history.push(ROUTES.VERSION); + } }; const onClickHandler = useCallback( - (key: string) => { + (key: string, event: MouseEvent | null) => { const params = new URLSearchParams(search); const availableParams = routeConfig[key]; const queryString = getQueryString(availableParams || [], params); if (pathname !== key) { - history.push(`${key}?${queryString.join('&')}`); + if (event && isCtrlMetaKey(event)) { + openInNewTab(`${key}?${queryString.join('&')}`); + } else { + history.push(`${key}?${queryString.join('&')}`); + } } }, [pathname, search], @@ -220,16 +242,19 @@ function SideNav({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentVersion, latestVersion]); - const handleUserManagentMenuItemClick = (key: string): void => { + const handleUserManagentMenuItemClick = ( + key: string, + event: MouseEvent, + ): void => { switch (key) { case SecondaryMenuItemKey.Slack: onClickSlackHandler(); break; case SecondaryMenuItemKey.Version: - onClickVersionHandler(); + onClickVersionHandler(event); break; default: - onClickHandler(key); + onClickHandler(key, event); break; } }; @@ -255,29 +280,41 @@ function SideNav({ ? ROUTES.ORG_SETTINGS : ROUTES.SETTINGS; + const handleMenuItemClick = (event: MouseEvent, item: SidebarItem): void => { + if (item.key === ROUTES.SETTINGS) { + if (isCtrlMetaKey(event)) { + openInNewTab(settingsRoute); + } else { + history.push(settingsRoute); + } + } else if (item) { + onClickHandler(item?.key as string, event); + } + }; + useEffect(() => { registerShortcut(GlobalShortcuts.SidebarCollapse, onCollapse); registerShortcut(GlobalShortcuts.NavigateToServices, () => - onClickHandler(ROUTES.APPLICATION), + onClickHandler(ROUTES.APPLICATION, null), ); registerShortcut(GlobalShortcuts.NavigateToTraces, () => - onClickHandler(ROUTES.TRACE), + onClickHandler(ROUTES.TRACE, null), ); registerShortcut(GlobalShortcuts.NavigateToLogs, () => - onClickHandler(ROUTES.LOGS), + onClickHandler(ROUTES.LOGS, null), ); registerShortcut(GlobalShortcuts.NavigateToDashboards, () => - onClickHandler(ROUTES.ALL_DASHBOARD), + onClickHandler(ROUTES.ALL_DASHBOARD, null), ); registerShortcut(GlobalShortcuts.NavigateToAlerts, () => - onClickHandler(ROUTES.LIST_ALL_ALERT), + onClickHandler(ROUTES.LIST_ALL_ALERT, null), ); registerShortcut(GlobalShortcuts.NavigateToExceptions, () => - onClickHandler(ROUTES.ALL_ERROR), + onClickHandler(ROUTES.ALL_ERROR, null), ); return (): void => { @@ -297,9 +334,9 @@ function SideNav({
{ + onClick={(event: MouseEvent): void => { // Current home page - onClickHandler(ROUTES.APPLICATION); + onClickHandler(ROUTES.APPLICATION, event); }} > SigNoz @@ -314,7 +351,12 @@ function SideNav({ {isCloudUserVal && (
-