mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-17 23:47:12 +00:00
feat: enable global actions (#8906)
* feat: enable global actions * feat: separate actions for collapse and open sidebar * fix: remove spaces from shortcuts * chore: remove console log * chore: yarn install to update yarn.lock
This commit is contained in:
parent
32410baa72
commit
4d2094b4ce
@ -96,6 +96,7 @@
|
||||
"i18next-http-backend": "^1.3.2",
|
||||
"jest": "^27.5.1",
|
||||
"js-base64": "^3.7.2",
|
||||
"kbar": "0.1.0-beta.48",
|
||||
"less": "^4.1.2",
|
||||
"less-loader": "^10.2.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
|
||||
@ -4,6 +4,7 @@ import getLocalStorageApi from 'api/browser/localstorage/get';
|
||||
import setLocalStorageApi from 'api/browser/localstorage/set';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import AppLoading from 'components/AppLoading/AppLoading';
|
||||
import KBarCommandPalette from 'components/KBarCommandPalette/KBarCommandPalette';
|
||||
import NotFound from 'components/NotFound';
|
||||
import Spinner from 'components/Spinner';
|
||||
import UserpilotRouteTracker from 'components/UserpilotRouteTracker/UserpilotRouteTracker';
|
||||
@ -25,6 +26,7 @@ import { useAppContext } from 'providers/App/App';
|
||||
import { IUser } from 'providers/App/types';
|
||||
import { DashboardProvider } from 'providers/Dashboard/Dashboard';
|
||||
import { ErrorModalProvider } from 'providers/ErrorModalProvider';
|
||||
import { KBarCommandPaletteProvider } from 'providers/KBarCommandPaletteProvider';
|
||||
import { QueryBuilderProvider } from 'providers/QueryBuilder';
|
||||
import { Suspense, useCallback, useEffect, useState } from 'react';
|
||||
import { Route, Router, Switch } from 'react-router-dom';
|
||||
@ -368,39 +370,42 @@ function App(): JSX.Element {
|
||||
<ConfigProvider theme={themeConfig}>
|
||||
<Router history={history}>
|
||||
<CompatRouter>
|
||||
<UserpilotRouteTracker />
|
||||
<NotificationProvider>
|
||||
<ErrorModalProvider>
|
||||
<PrivateRoute>
|
||||
<ResourceProvider>
|
||||
<QueryBuilderProvider>
|
||||
<DashboardProvider>
|
||||
<KeyboardHotkeysProvider>
|
||||
<AlertRuleProvider>
|
||||
<AppLayout>
|
||||
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
|
||||
<Switch>
|
||||
{routes.map(({ path, component, exact }) => (
|
||||
<Route
|
||||
key={`${path}`}
|
||||
exact={exact}
|
||||
path={path}
|
||||
component={component}
|
||||
/>
|
||||
))}
|
||||
<Route exact path="/" component={Home} />
|
||||
<Route path="*" component={NotFound} />
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</AppLayout>
|
||||
</AlertRuleProvider>
|
||||
</KeyboardHotkeysProvider>
|
||||
</DashboardProvider>
|
||||
</QueryBuilderProvider>
|
||||
</ResourceProvider>
|
||||
</PrivateRoute>
|
||||
</ErrorModalProvider>
|
||||
</NotificationProvider>
|
||||
<KBarCommandPaletteProvider>
|
||||
<UserpilotRouteTracker />
|
||||
<KBarCommandPalette />
|
||||
<NotificationProvider>
|
||||
<ErrorModalProvider>
|
||||
<PrivateRoute>
|
||||
<ResourceProvider>
|
||||
<QueryBuilderProvider>
|
||||
<DashboardProvider>
|
||||
<KeyboardHotkeysProvider>
|
||||
<AlertRuleProvider>
|
||||
<AppLayout>
|
||||
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
|
||||
<Switch>
|
||||
{routes.map(({ path, component, exact }) => (
|
||||
<Route
|
||||
key={`${path}`}
|
||||
exact={exact}
|
||||
path={path}
|
||||
component={component}
|
||||
/>
|
||||
))}
|
||||
<Route exact path="/" component={Home} />
|
||||
<Route path="*" component={NotFound} />
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</AppLayout>
|
||||
</AlertRuleProvider>
|
||||
</KeyboardHotkeysProvider>
|
||||
</DashboardProvider>
|
||||
</QueryBuilderProvider>
|
||||
</ResourceProvider>
|
||||
</PrivateRoute>
|
||||
</ErrorModalProvider>
|
||||
</NotificationProvider>
|
||||
</KBarCommandPaletteProvider>
|
||||
</CompatRouter>
|
||||
</Router>
|
||||
</ConfigProvider>
|
||||
|
||||
@ -0,0 +1,152 @@
|
||||
.kbar-command-palette__positioner {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
padding: 1rem;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(6px);
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.kbar-command-palette__animator {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.kbar-command-palette__card {
|
||||
background: var(--bg-ink-500);
|
||||
color: var(--text-vanilla-100);
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.kbar-command-palette__search {
|
||||
padding: 12px 16px;
|
||||
font-size: 13px;
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--border-ink-200);
|
||||
color: var(--text-vanilla-100);
|
||||
outline: none;
|
||||
background-color: var(--bg-ink-500);
|
||||
}
|
||||
|
||||
.kbar-command-palette__section {
|
||||
padding: 8px 16px 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--text-robin-500);
|
||||
font-family: 'Inter', sans-serif;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.kbar-command-palette__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 16px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
|
||||
.kbar-command-palette__item:hover,
|
||||
.kbar-command-palette__item--active {
|
||||
background: var(--bg-ink-400);
|
||||
}
|
||||
|
||||
.kbar-command-palette__icon {
|
||||
flex-shrink: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.kbar-command-palette__shortcut {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.kbar-command-palette__key {
|
||||
padding: 2px 6px;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
background: var(--bg-ink-300);
|
||||
color: var(--text-vanilla-300);
|
||||
text-transform: uppercase;
|
||||
font-family: 'Space Mono', monospace;
|
||||
}
|
||||
|
||||
.kbar-command-palette__results-container {
|
||||
div {
|
||||
&::-webkit-scrollbar {
|
||||
width: 0.3rem;
|
||||
height: 0.3rem;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: var(--bg-slate-300);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--bg-slate-200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lightMode {
|
||||
.kbar-command-palette__positioner {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.kbar-command-palette__card {
|
||||
background: #fff;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.kbar-command-palette__search {
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
color: var(--text-ink-500);
|
||||
background-color: var(--bg-vanilla-100);
|
||||
}
|
||||
|
||||
.kbar-command-palette__item {
|
||||
color: var(--text-ink-500);
|
||||
}
|
||||
|
||||
.kbar-command-palette__item:hover,
|
||||
.kbar-command-palette__item--active {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.kbar-command-palette__icon {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.kbar-command-palette__key {
|
||||
background: #eee;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.kbar-command-palette__results-container {
|
||||
div {
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: var(--bg-vanilla-300);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--bg-vanilla-300);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
import './KBarCommandPalette.scss';
|
||||
|
||||
import {
|
||||
KBarAnimator,
|
||||
KBarPortal,
|
||||
KBarPositioner,
|
||||
KBarResults,
|
||||
KBarSearch,
|
||||
useMatches,
|
||||
} from 'kbar';
|
||||
|
||||
function Results(): JSX.Element {
|
||||
const { results } = useMatches();
|
||||
|
||||
const renderResults = ({
|
||||
item,
|
||||
active,
|
||||
}: {
|
||||
item: any;
|
||||
active: boolean;
|
||||
}): JSX.Element =>
|
||||
typeof item === 'string' ? (
|
||||
<div className="kbar-command-palette__section">{item}</div>
|
||||
) : (
|
||||
<div
|
||||
className={`kbar-command-palette__item ${
|
||||
active ? 'kbar-command-palette__item--active' : ''
|
||||
}`}
|
||||
>
|
||||
{item.icon}
|
||||
<span>{item.name}</span>
|
||||
{item.shortcut?.length ? (
|
||||
<span className="kbar-command-palette__shortcut">
|
||||
{item.shortcut.map((sc: string) => (
|
||||
<kbd key={sc} className="kbar-command-palette__key">
|
||||
{sc}
|
||||
</kbd>
|
||||
))}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="kbar-command-palette__results-container">
|
||||
<KBarResults items={results} onRender={renderResults} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function KBarCommandPalette(): JSX.Element {
|
||||
return (
|
||||
<KBarPortal>
|
||||
<KBarPositioner className="kbar-command-palette__positioner">
|
||||
<KBarAnimator className="kbar-command-palette__animator">
|
||||
<div className="kbar-command-palette__card">
|
||||
<KBarSearch
|
||||
className="kbar-command-palette__search"
|
||||
placeholder="Search or type a command..."
|
||||
/>
|
||||
<Results />
|
||||
</div>
|
||||
</KBarAnimator>
|
||||
</KBarPositioner>
|
||||
</KBarPortal>
|
||||
);
|
||||
}
|
||||
|
||||
export default KBarCommandPalette;
|
||||
@ -7,6 +7,7 @@ export const GlobalShortcuts = {
|
||||
NavigateToExceptions: 'e+shift',
|
||||
NavigateToMessagingQueues: 'm+shift',
|
||||
ToggleSidebar: 'b+shift',
|
||||
NavigateToHome: 'h+shift',
|
||||
};
|
||||
|
||||
export const GlobalShortcutsName = {
|
||||
@ -18,9 +19,11 @@ export const GlobalShortcutsName = {
|
||||
NavigateToExceptions: 'shift+e',
|
||||
NavigateToMessagingQueues: 'shift+m',
|
||||
ToggleSidebar: 'shift+b',
|
||||
NavigateToHome: 'shift+h',
|
||||
};
|
||||
|
||||
export const GlobalShortcutsDescription = {
|
||||
NavigateToHome: 'Navigate to Home',
|
||||
NavigateToServices: 'Navigate to Services page',
|
||||
NavigateToTraces: 'Navigate to Traces page',
|
||||
NavigateToLogs: 'Navigate to logs page',
|
||||
|
||||
@ -10,9 +10,9 @@ export const LogsExplorerShortcuts = {
|
||||
export const LogsExplorerShortcutsName = {
|
||||
StageAndRunQuery: `${
|
||||
userOS === UserOperatingSystem.MACOS ? 'cmd' : 'ctrl'
|
||||
}+enter`,
|
||||
} + enter`,
|
||||
FocusTheSearchBar: 's',
|
||||
ShowAllFilters: `${userOS === UserOperatingSystem.MACOS ? 'cmd' : 'ctrl'}+/`,
|
||||
ShowAllFilters: `${userOS === UserOperatingSystem.MACOS ? 'cmd' : 'ctrl'} + /`,
|
||||
};
|
||||
|
||||
export const LogsExplorerShortcutsDescription = {
|
||||
|
||||
@ -668,6 +668,18 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
|
||||
</div>
|
||||
);
|
||||
|
||||
const { registerShortcut, deregisterShortcut } = useKeyboardHotkeys();
|
||||
const { updateUserPreferenceInContext } = useAppContext();
|
||||
|
||||
const { mutate: updateUserPreferenceMutation } = useMutation(
|
||||
updateUserPreference,
|
||||
{
|
||||
onError: (error) => {
|
||||
showErrorNotification(notifications, error as AxiosError);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const sideNavPinnedPreference = userPreferences?.find(
|
||||
(preference) => preference.name === USER_PREFERENCES.SIDENAV_PINNED,
|
||||
)?.value as boolean;
|
||||
@ -697,18 +709,6 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
|
||||
? sideNavPinnedPreference
|
||||
: getSidebarStateFromLocalStorage();
|
||||
|
||||
const { registerShortcut, deregisterShortcut } = useKeyboardHotkeys();
|
||||
const { updateUserPreferenceInContext } = useAppContext();
|
||||
|
||||
const { mutate: updateUserPreferenceMutation } = useMutation(
|
||||
updateUserPreference,
|
||||
{
|
||||
onError: (error) => {
|
||||
showErrorNotification(notifications, error as AxiosError);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const handleToggleSidebar = useCallback((): void => {
|
||||
const newState = !isSideNavPinned;
|
||||
|
||||
|
||||
@ -103,6 +103,19 @@ function MySettings(): JSX.Element {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (autoSwitch) {
|
||||
setTheme('auto');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDarkMode) {
|
||||
setTheme('dark');
|
||||
} else {
|
||||
setTheme('light');
|
||||
}
|
||||
}, [autoSwitch, isDarkMode]);
|
||||
|
||||
const handleSideNavPinnedChange = (checked: boolean): void => {
|
||||
logEvent('Account Settings: Sidebar Pinned Changed', {
|
||||
pinned: checked,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
export const THEME_MODE = {
|
||||
LIGHT: 'light',
|
||||
DARK: 'dark',
|
||||
SYSTEM: 'auto',
|
||||
};
|
||||
|
||||
@ -22,6 +22,7 @@ export const ThemeContext = createContext({
|
||||
toggleTheme: (): void => {},
|
||||
autoSwitch: false,
|
||||
setAutoSwitch: ((): void => {}) as Dispatch<SetStateAction<boolean>>,
|
||||
setTheme: ((): void => {}) as Dispatch<SetStateAction<string>>,
|
||||
});
|
||||
|
||||
// Hook to detect system theme preference
|
||||
@ -44,7 +45,9 @@ export const useSystemTheme = (): 'light' | 'dark' => {
|
||||
};
|
||||
|
||||
export function ThemeProvider({ children }: ThemeProviderProps): JSX.Element {
|
||||
const [theme, setTheme] = useState(get(LOCALSTORAGE.THEME) || THEME_MODE.DARK);
|
||||
const [theme, setThemeState] = useState(
|
||||
get(LOCALSTORAGE.THEME) || THEME_MODE.DARK,
|
||||
);
|
||||
const [autoSwitch, setAutoSwitch] = useState(
|
||||
get(LOCALSTORAGE.THEME_AUTO_SWITCH) === 'true',
|
||||
);
|
||||
@ -55,7 +58,7 @@ export function ThemeProvider({ children }: ThemeProviderProps): JSX.Element {
|
||||
if (autoSwitch) {
|
||||
const newTheme = systemTheme === 'dark' ? THEME_MODE.DARK : THEME_MODE.LIGHT;
|
||||
if (newTheme !== theme) {
|
||||
setTheme(newTheme);
|
||||
setThemeState(newTheme);
|
||||
set(LOCALSTORAGE.THEME, newTheme);
|
||||
}
|
||||
}
|
||||
@ -68,23 +71,34 @@ export function ThemeProvider({ children }: ThemeProviderProps): JSX.Element {
|
||||
|
||||
const toggleTheme = useCallback((): void => {
|
||||
if (theme === THEME_MODE.LIGHT) {
|
||||
setTheme(THEME_MODE.DARK);
|
||||
setThemeState(THEME_MODE.DARK);
|
||||
set(LOCALSTORAGE.THEME, THEME_MODE.DARK);
|
||||
} else {
|
||||
setTheme(THEME_MODE.LIGHT);
|
||||
setThemeState(THEME_MODE.LIGHT);
|
||||
set(LOCALSTORAGE.THEME, THEME_MODE.LIGHT);
|
||||
}
|
||||
set(LOCALSTORAGE.THEME_ANALYTICS_V1, '');
|
||||
}, [theme]);
|
||||
|
||||
const setTheme = useCallback(
|
||||
(newTheme: SetStateAction<string>): void => {
|
||||
const themeValue =
|
||||
typeof newTheme === 'function' ? newTheme(theme) : newTheme;
|
||||
setThemeState(themeValue);
|
||||
set(LOCALSTORAGE.THEME, themeValue);
|
||||
},
|
||||
[theme],
|
||||
);
|
||||
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
theme,
|
||||
toggleTheme,
|
||||
autoSwitch,
|
||||
setAutoSwitch,
|
||||
setTheme,
|
||||
}),
|
||||
[theme, toggleTheme, autoSwitch, setAutoSwitch],
|
||||
[theme, toggleTheme, autoSwitch, setAutoSwitch, setTheme],
|
||||
);
|
||||
|
||||
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
|
||||
@ -99,14 +113,15 @@ interface ThemeMode {
|
||||
toggleTheme: () => void;
|
||||
autoSwitch: boolean;
|
||||
setAutoSwitch: Dispatch<SetStateAction<boolean>>;
|
||||
setTheme: (newTheme: string) => void;
|
||||
}
|
||||
|
||||
export const useThemeMode = (): ThemeMode => {
|
||||
const { theme, toggleTheme, autoSwitch, setAutoSwitch } = useContext(
|
||||
const { theme, toggleTheme, autoSwitch, setAutoSwitch, setTheme } = useContext(
|
||||
ThemeContext,
|
||||
);
|
||||
|
||||
return { theme, toggleTheme, autoSwitch, setAutoSwitch };
|
||||
return { theme, toggleTheme, autoSwitch, setAutoSwitch, setTheme };
|
||||
};
|
||||
|
||||
export const useIsDarkMode = (): boolean => {
|
||||
|
||||
@ -17,5 +17,12 @@
|
||||
font-size: 22px;
|
||||
line-height: 1.3636363636363635;
|
||||
}
|
||||
|
||||
tbody {
|
||||
.shortcut-key {
|
||||
font-family: 'Space Mono', monospace;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,11 +51,13 @@ export const shortcutColumns = [
|
||||
dataIndex: 'shortcutKey',
|
||||
key: 'shortcutKey',
|
||||
width: '30%',
|
||||
className: 'shortcut-key',
|
||||
},
|
||||
{
|
||||
title: 'Description',
|
||||
dataIndex: 'shortcutDescription',
|
||||
key: 'shortcutDescription',
|
||||
className: 'shortcut-description',
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
229
frontend/src/providers/KBarCommandPaletteProvider.tsx
Normal file
229
frontend/src/providers/KBarCommandPaletteProvider.tsx
Normal file
@ -0,0 +1,229 @@
|
||||
import setLocalStorageApi from 'api/browser/localstorage/set';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import updateUserPreference from 'api/v1/user/preferences/name/update';
|
||||
import { AxiosError } from 'axios';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { USER_PREFERENCES } from 'constants/userPreferences';
|
||||
import { useThemeMode } from 'hooks/useDarkMode';
|
||||
import { THEME_MODE } from 'hooks/useDarkMode/constant';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { KBarProvider } from 'kbar';
|
||||
import history from 'lib/history';
|
||||
import { useCallback } from 'react';
|
||||
import { useMutation } from 'react-query';
|
||||
import { UserPreference } from 'types/api/preferences/preference';
|
||||
import { showErrorNotification } from 'utils/error';
|
||||
|
||||
import { useAppContext } from './App/App';
|
||||
|
||||
export function KBarCommandPaletteProvider({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}): JSX.Element {
|
||||
const { notifications } = useNotifications();
|
||||
|
||||
const { setAutoSwitch, setTheme } = useThemeMode();
|
||||
|
||||
const handleThemeChange = (value: string): void => {
|
||||
logEvent('Account Settings: Theme Changed', {
|
||||
theme: value,
|
||||
});
|
||||
|
||||
if (value === 'auto') {
|
||||
setAutoSwitch(true);
|
||||
} else {
|
||||
setAutoSwitch(false);
|
||||
setTheme(value);
|
||||
}
|
||||
};
|
||||
|
||||
const onClickHandler = useCallback((key: string): void => {
|
||||
history.push(key);
|
||||
}, []);
|
||||
|
||||
const { updateUserPreferenceInContext } = useAppContext();
|
||||
|
||||
const { mutate: updateUserPreferenceMutation } = useMutation(
|
||||
updateUserPreference,
|
||||
{
|
||||
onError: (error) => {
|
||||
showErrorNotification(notifications, error as AxiosError);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const handleOpenSidebar = useCallback((): void => {
|
||||
setLocalStorageApi(USER_PREFERENCES.SIDENAV_PINNED, 'true');
|
||||
|
||||
// Update the context immediately
|
||||
const save = {
|
||||
name: USER_PREFERENCES.SIDENAV_PINNED,
|
||||
value: true,
|
||||
};
|
||||
|
||||
updateUserPreferenceInContext(save as UserPreference);
|
||||
|
||||
// Make the API call in the background
|
||||
updateUserPreferenceMutation({
|
||||
name: USER_PREFERENCES.SIDENAV_PINNED,
|
||||
value: true,
|
||||
});
|
||||
}, [updateUserPreferenceInContext, updateUserPreferenceMutation]);
|
||||
|
||||
const handleCloseSidebar = useCallback((): void => {
|
||||
setLocalStorageApi(USER_PREFERENCES.SIDENAV_PINNED, 'false');
|
||||
|
||||
// Update the context immediately
|
||||
const save = {
|
||||
name: USER_PREFERENCES.SIDENAV_PINNED,
|
||||
value: false,
|
||||
};
|
||||
|
||||
updateUserPreferenceInContext(save as UserPreference);
|
||||
|
||||
// Make the API call in the background
|
||||
updateUserPreferenceMutation({
|
||||
name: USER_PREFERENCES.SIDENAV_PINNED,
|
||||
value: false,
|
||||
});
|
||||
}, [updateUserPreferenceInContext, updateUserPreferenceMutation]);
|
||||
const kbarActions = [
|
||||
{
|
||||
id: 'home',
|
||||
name: 'Go to Home',
|
||||
shortcut: ['shift + h'],
|
||||
keywords: 'home',
|
||||
section: 'Navigation',
|
||||
perform: (): void => {
|
||||
onClickHandler(ROUTES.HOME);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'dashboards',
|
||||
name: 'Go to Dashboards',
|
||||
shortcut: ['shift + d'],
|
||||
keywords: 'dashboards',
|
||||
section: 'Navigation',
|
||||
perform: (): void => {
|
||||
onClickHandler(ROUTES.ALL_DASHBOARD);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'services',
|
||||
name: 'Go to Services',
|
||||
shortcut: ['shift + s'],
|
||||
keywords: 'services monitoring',
|
||||
section: 'Navigation',
|
||||
perform: (): void => {
|
||||
onClickHandler(ROUTES.APPLICATION);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'traces',
|
||||
name: 'Go to Traces',
|
||||
shortcut: ['shift + t'],
|
||||
keywords: 'traces',
|
||||
section: 'Navigation',
|
||||
perform: (): void => {
|
||||
onClickHandler(ROUTES.TRACES_EXPLORER);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'logs',
|
||||
name: 'Go to Logs',
|
||||
shortcut: ['shift + l'],
|
||||
keywords: 'logs',
|
||||
section: 'Navigation',
|
||||
perform: (): void => {
|
||||
onClickHandler(ROUTES.LOGS);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'alerts',
|
||||
name: 'Go to Alerts',
|
||||
shortcut: ['shift + a'],
|
||||
keywords: 'alerts',
|
||||
section: 'Navigation',
|
||||
perform: (): void => {
|
||||
onClickHandler(ROUTES.LIST_ALL_ALERT);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'exceptions',
|
||||
name: 'Go to Exceptions',
|
||||
shortcut: ['shift + e'],
|
||||
keywords: 'exceptions errors',
|
||||
section: 'Navigation',
|
||||
perform: (): void => {
|
||||
onClickHandler(ROUTES.ALL_ERROR);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'messaging-queues',
|
||||
name: 'Go to Messaging Queues',
|
||||
shortcut: ['shift + m'],
|
||||
keywords: 'messaging queues mq',
|
||||
section: 'Navigation',
|
||||
perform: (): void => {
|
||||
onClickHandler(ROUTES.MESSAGING_QUEUES_OVERVIEW);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'my-settings',
|
||||
name: 'Go to Account Settings',
|
||||
keywords: 'account settings',
|
||||
section: 'Navigation',
|
||||
perform: (): void => {
|
||||
onClickHandler(ROUTES.MY_SETTINGS);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'open-sidebar',
|
||||
name: 'Open Sidebar',
|
||||
keywords: 'sidebar navigation menu expand',
|
||||
section: 'Settings',
|
||||
perform: (): void => {
|
||||
handleOpenSidebar();
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'collapse-sidebar',
|
||||
name: 'Collapse Sidebar',
|
||||
keywords: 'sidebar navigation menu collapse',
|
||||
section: 'Settings',
|
||||
perform: (): void => {
|
||||
handleCloseSidebar();
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'dark-mode',
|
||||
name: 'Switch to Dark Mode',
|
||||
keywords: 'theme dark mode appearance',
|
||||
section: 'Settings',
|
||||
perform: (): void => {
|
||||
handleThemeChange(THEME_MODE.DARK);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'light-mode',
|
||||
name: 'Switch to Light Mode [Beta]',
|
||||
keywords: 'theme light mode appearance',
|
||||
section: 'Settings',
|
||||
perform: (): void => {
|
||||
handleThemeChange(THEME_MODE.LIGHT);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'system-theme',
|
||||
name: 'Switch to System Theme',
|
||||
keywords: 'system theme appearance',
|
||||
section: 'Settings',
|
||||
perform: (): void => {
|
||||
handleThemeChange(THEME_MODE.SYSTEM);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return <KBarProvider actions={kbarActions}>{children}</KBarProvider>;
|
||||
}
|
||||
@ -3729,7 +3729,7 @@
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "1.0.3"
|
||||
|
||||
"@radix-ui/react-portal@1.1.9":
|
||||
"@radix-ui/react-portal@1.1.9", "@radix-ui/react-portal@^1.0.1":
|
||||
version "1.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.9.tgz#14c3649fe48ec474ac51ed9f2b9f5da4d91c4472"
|
||||
integrity sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==
|
||||
@ -4021,6 +4021,11 @@
|
||||
rc-resize-observer "^1.3.1"
|
||||
rc-util "^5.38.0"
|
||||
|
||||
"@reach/observe-rect@^1.1.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@reach/observe-rect/-/observe-rect-1.2.0.tgz#d7a6013b8aafcc64c778a0ccb83355a11204d3b2"
|
||||
integrity sha512-Ba7HmkFgfQxZqqaeIWWkNK0rEhpxVQHIoVyW1YDSkGsGIXzcaW4deC8B0pZrNSSyLTdIk7y+5olKt5+g0GmFIQ==
|
||||
|
||||
"@react-dnd/asap@^5.0.1":
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/asap/-/asap-5.0.2.tgz#1f81f124c1cd6f39511c11a881cfb0f715343488"
|
||||
@ -9295,6 +9300,11 @@ fast-diff@^1.1.2:
|
||||
resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz"
|
||||
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
|
||||
|
||||
fast-equals@^2.0.3:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-2.0.4.tgz#3add9410585e2d7364c2deeb6a707beadb24b927"
|
||||
integrity sha512-caj/ZmjHljPrZtbzJ3kfH5ia/k4mTJe/qSiXAGzxZWRZgsgDV0cvNaQULqUX8t0/JVlzzEdYOwCN5DmzTxoD4w==
|
||||
|
||||
fast-glob@^3.2.11, fast-glob@^3.2.7, fast-glob@^3.3.0:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818"
|
||||
@ -9648,6 +9658,11 @@ functions-have-names@^1.2.2, functions-have-names@^1.2.3:
|
||||
resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz"
|
||||
integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
|
||||
|
||||
fuse.js@^6.6.2:
|
||||
version "6.6.2"
|
||||
resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-6.6.2.tgz#fe463fed4b98c0226ac3da2856a415576dc9a111"
|
||||
integrity sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA==
|
||||
|
||||
gensync@^1.0.0-beta.2:
|
||||
version "1.0.0-beta.2"
|
||||
resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz"
|
||||
@ -11869,6 +11884,17 @@ kapsule@1, kapsule@^1.14:
|
||||
dependencies:
|
||||
lodash-es "4"
|
||||
|
||||
kbar@0.1.0-beta.48:
|
||||
version "0.1.0-beta.48"
|
||||
resolved "https://registry.yarnpkg.com/kbar/-/kbar-0.1.0-beta.48.tgz#2db254cb2943f14200c5a5f47064135737527983"
|
||||
integrity sha512-HD5A1dqfK6XGeoH4fRWTmRt4y76sDbtGxY4Dh2xNa5MYtvtKsqfz+nRZ0tKgcrjjGYN4rf5TLXMJuiE7Pb8rXg==
|
||||
dependencies:
|
||||
"@radix-ui/react-portal" "^1.0.1"
|
||||
fast-equals "^2.0.3"
|
||||
fuse.js "^6.6.2"
|
||||
react-virtual "^2.8.2"
|
||||
tiny-invariant "^1.2.0"
|
||||
|
||||
keyv@^4.0.0:
|
||||
version "4.5.4"
|
||||
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
|
||||
@ -15430,6 +15456,13 @@ react-use@^17.3.2:
|
||||
ts-easing "^0.2.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
react-virtual@^2.8.2:
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/react-virtual/-/react-virtual-2.10.4.tgz#08712f0acd79d7d6f7c4726f05651a13b24d8704"
|
||||
integrity sha512-Ir6+oPQZTVHfa6+JL9M7cvMILstFZH/H3jqeYeKI4MSUX+rIruVwFC6nGVXw9wqAw8L0Kg2KvfXxI85OvYQdpQ==
|
||||
dependencies:
|
||||
"@reach/observe-rect" "^1.1.0"
|
||||
|
||||
react-virtuoso@4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.0.3.tgz#0dc8b10978095852d985b064157639b9fb9d9b1e"
|
||||
@ -17132,6 +17165,11 @@ tiny-invariant@^1.0.2, tiny-invariant@^1.0.6:
|
||||
resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz"
|
||||
integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==
|
||||
|
||||
tiny-invariant@^1.2.0:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127"
|
||||
integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==
|
||||
|
||||
tiny-warning@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user