mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-20 14:19:06 +08:00
feat: open left nav items in new tab on cmd ctrl click (#4561)
This commit is contained in:
parent
b10f17de78
commit
0c59953cb5
@ -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,
|
||||
});
|
||||
|
@ -100,7 +100,10 @@ function TableView({
|
||||
value: JSON.stringify(flattenLogData[key]),
|
||||
}));
|
||||
|
||||
const onTraceHandler = (record: DataType) => (): void => {
|
||||
const onTraceHandler = (
|
||||
record: DataType,
|
||||
event: React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
) => (): void => {
|
||||
if (flattenLogData === null) return;
|
||||
|
||||
const traceId = flattenLogData[record.field];
|
||||
@ -119,8 +122,13 @@ function TableView({
|
||||
|
||||
const route = spanId ? `${basePath}?spanId=${spanId}` : basePath;
|
||||
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
// open the trace in new tab
|
||||
window.open(route, '_blank');
|
||||
} else {
|
||||
history.push(route);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!dataSource) {
|
||||
@ -148,17 +156,20 @@ function TableView({
|
||||
|
||||
{traceId && (
|
||||
<Tooltip title="Inspect in Trace">
|
||||
<div
|
||||
style={{ cursor: 'pointer' }}
|
||||
role="presentation"
|
||||
onClick={onTraceHandler(record)}
|
||||
<Button
|
||||
className="periscope-btn"
|
||||
onClick={(
|
||||
event: React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
): void => {
|
||||
onTraceHandler(record, event);
|
||||
}}
|
||||
>
|
||||
<LinkOutlined
|
||||
style={{
|
||||
width: '15px',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Space>
|
||||
|
@ -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 (
|
||||
<div className="logs-error-container">
|
||||
<div className="logs-error-content">
|
||||
@ -16,10 +27,12 @@ export default function LogsError(): JSX.Element {
|
||||
<span className="aww-snap">Aw snap :/ </span> Something went wrong. Please
|
||||
try again or contact support.
|
||||
</Typography.Text>
|
||||
<section className="contact-support">
|
||||
|
||||
<div className="contact-support" onClick={handleContactSupport}>
|
||||
<Typography.Link className="text">Contact Support </Typography.Link>
|
||||
|
||||
<ArrowRight size={14} />
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -9,13 +9,17 @@ export default function NoLogs(): JSX.Element {
|
||||
<div className="no-logs-container-content">
|
||||
<img className="eyes-emoji" src="/Images/eyesEmoji.svg" alt="eyes emoji" />
|
||||
<Typography className="no-logs-text">
|
||||
No logs yet.{' '}
|
||||
No logs yet.
|
||||
<span className="sub-text">
|
||||
When we receive logs, they would show up here
|
||||
</span>
|
||||
</Typography>
|
||||
|
||||
<Typography.Link className="send-logs-link">
|
||||
<Typography.Link
|
||||
className="send-logs-link"
|
||||
href="https://signoz.io/docs/userguide/logs/"
|
||||
target="_blank"
|
||||
>
|
||||
Sending Logs to SigNoz <ArrowUpRight size={16} />
|
||||
</Typography.Link>
|
||||
</div>
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
height: 36px;
|
||||
margin-bottom: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
.nav-item-active-marker {
|
||||
|
@ -16,13 +16,16 @@ export default function NavItem({
|
||||
isCollapsed: boolean;
|
||||
item: SidebarItem;
|
||||
isActive: boolean;
|
||||
onClick: () => void;
|
||||
onClick: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
||||
}): JSX.Element {
|
||||
const { label, icon } = item;
|
||||
|
||||
return (
|
||||
<Tooltip title={isCollapsed ? label : ''} placement="right">
|
||||
<div className={cx('nav-item', isActive ? 'active' : '')} onClick={onClick}>
|
||||
<div
|
||||
className={cx('nav-item', isActive ? 'active' : '')}
|
||||
onClick={(event): void => onClick(event)}
|
||||
>
|
||||
<div className="nav-item-active-marker" />
|
||||
<div className="nav-item-data">
|
||||
<div className="nav-item-icon">{icon}</div>
|
||||
|
@ -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,24 +160,50 @@ 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 => {
|
||||
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) {
|
||||
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({
|
||||
<div
|
||||
className="brand-logo"
|
||||
// eslint-disable-next-line react/no-unknown-property
|
||||
onClick={(): void => {
|
||||
onClick={(event: MouseEvent): void => {
|
||||
// Current home page
|
||||
onClickHandler(ROUTES.APPLICATION);
|
||||
onClickHandler(ROUTES.APPLICATION, event);
|
||||
}}
|
||||
>
|
||||
<img src="/Logos/signoz-brand-logo.svg" alt="SigNoz" />
|
||||
@ -314,7 +351,12 @@ function SideNav({
|
||||
|
||||
{isCloudUserVal && (
|
||||
<div className="get-started-nav-items">
|
||||
<Button className="get-started-btn" onClick={onClickGetStarted}>
|
||||
<Button
|
||||
className="get-started-btn"
|
||||
onClick={(event: MouseEvent): void => {
|
||||
onClickGetStarted(event);
|
||||
}}
|
||||
>
|
||||
<RocketIcon size={16} />
|
||||
|
||||
{!collapsed && <> Get Started </>}
|
||||
@ -329,12 +371,8 @@ function SideNav({
|
||||
key={item.key || index}
|
||||
item={item}
|
||||
isActive={activeMenuKey === item.key}
|
||||
onClick={(): void => {
|
||||
if (item.key === ROUTES.SETTINGS) {
|
||||
history.push(settingsRoute);
|
||||
} else if (item) {
|
||||
onClickHandler(item?.key as string);
|
||||
}
|
||||
onClick={(event): void => {
|
||||
handleMenuItemClick(event, item);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
@ -366,8 +404,8 @@ function SideNav({
|
||||
key={item?.key || index}
|
||||
item={item}
|
||||
isActive={activeMenuKey === item?.key}
|
||||
onClick={(): void => {
|
||||
handleUserManagentMenuItemClick(item?.key as string);
|
||||
onClick={(event: MouseEvent): void => {
|
||||
handleUserManagentMenuItemClick(item?.key as string, event);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
@ -379,8 +417,12 @@ function SideNav({
|
||||
key={inviteMemberMenuItem.key}
|
||||
item={inviteMemberMenuItem}
|
||||
isActive={activeMenuKey === inviteMemberMenuItem?.key}
|
||||
onClick={(): void => {
|
||||
onClick={(event: React.MouseEvent): void => {
|
||||
if (isCtrlMetaKey(event)) {
|
||||
openInNewTab(`${inviteMemberMenuItem.key}`);
|
||||
} else {
|
||||
history.push(`${inviteMemberMenuItem.key}`);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@ -391,8 +433,11 @@ function SideNav({
|
||||
key={ROUTES.MY_SETTINGS}
|
||||
item={userSettingsMenuItem}
|
||||
isActive={activeMenuKey === userSettingsMenuItem?.key}
|
||||
onClick={(): void => {
|
||||
handleUserManagentMenuItemClick(userSettingsMenuItem?.key as string);
|
||||
onClick={(event: MouseEvent): void => {
|
||||
handleUserManagentMenuItemClick(
|
||||
userSettingsMenuItem?.key as string,
|
||||
event,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
Loading…
x
Reference in New Issue
Block a user