Compare commits

...

2 Commits

Author SHA1 Message Date
SagarRajput-7
a08170bb09 feat: settings nav categorisation 2026-03-05 02:11:15 +05:30
SagarRajput-7
4ff2d44188 feat: revamped the settings nav and setting dropdown 2026-03-05 02:05:25 +05:30
8 changed files with 249 additions and 173 deletions

View File

@@ -674,7 +674,7 @@ function GeneralSettings({
return (
<div className="general-settings-page">
<div className="general-settings-header">
<span className="general-settings-title">General</span>
<span className="general-settings-title">Workspace</span>
<span className="general-settings-subtitle">
Manage your workspace settings.
</span>

View File

@@ -161,7 +161,7 @@ function MySettings(): JSX.Element {
<div className="my-settings-container">
<div className="user-info-section">
<div className="user-info-section-header">
<div className="user-info-section-title">General </div>
<div className="user-info-section-title">Account </div>
<div className="user-info-section-subtitle">
Manage your account settings.

View File

@@ -1057,21 +1057,20 @@
gap: 8px;
.user-settings-dropdown-label-text {
color: var(--bg-slate-50, #62687c);
color: var(--l3-foreground);
font-family: Inter;
font-size: 10px;
font-family: Inter;
font-weight: 600;
font-size: var(--uppercase-small-500-font-size);
font-weight: var(--uppercase-small-500-font-weight);
font-style: normal;
line-height: 18px; /* 163.636% */
line-height: 18px;
letter-spacing: 0.88px;
text-transform: uppercase;
}
.user-settings-dropdown-label-email {
color: var(--bg-vanilla-400, #c0c1c3);
color: var(--l1-foreground);
font-family: Inter;
font-size: 12px;
font-size: var(--font-size-xs);
font-style: normal;
line-height: normal;
letter-spacing: 0.14px;
@@ -1079,7 +1078,7 @@
}
.ant-dropdown-menu-item-divider {
background-color: var(--bg-slate-500, #161922) !important;
background-color: var(--secondary) !important;
}
.ant-dropdown-menu-item-disabled {
@@ -1095,6 +1094,14 @@
.help-support-dropdown {
.ant-dropdown-menu-item {
min-height: 32px;
.ant-dropdown-menu-title-content {
color: var(--l1-foreground) !important;
}
.user-settings-dropdown-logout-section {
color: var(--danger-background);
}
}
}
@@ -1271,7 +1278,7 @@
}
.help-support-dropdown li.ant-dropdown-menu-item-divider {
background-color: var(--bg-slate-500, #161922) !important;
background-color: var(--secondary) !important;
}
.lightMode {
@@ -1431,22 +1438,6 @@
}
}
.settings-dropdown {
.user-settings-dropdown-logged-in-section {
.user-settings-dropdown-label-text {
color: var(--bg-ink-400);
}
.user-settings-dropdown-label-email {
color: var(--bg-ink-300);
}
}
.ant-dropdown-menu-item-divider {
background-color: var(--bg-vanilla-300) !important;
}
}
.reorder-shortcut-nav-items-modal {
.ant-modal-content {
border: 1px solid var(--bg-vanilla-300);
@@ -1503,10 +1494,6 @@
color: var(--bg-ink-400);
}
}
.help-support-dropdown li.ant-dropdown-menu-item-divider {
background-color: var(--bg-vanilla-300) !important;
}
}
.version-tooltip-overlay {

View File

@@ -69,6 +69,7 @@ import { routeConfig } from './config';
import { getQueryString } from './helper';
import {
defaultMoreMenuItems,
getUserSettingsDropdownMenuItems,
helpSupportDropdownMenuItems as DefaultHelpSupportDropdownMenuItems,
helpSupportMenuItem,
primaryMenuItems,
@@ -485,48 +486,12 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
const userSettingsDropdownMenuItems: MenuProps['items'] = useMemo(
() =>
[
{
key: 'label',
label: (
<div className="user-settings-dropdown-logged-in-section">
<span className="user-settings-dropdown-label-text">LOGGED IN AS</span>
<span className="user-settings-dropdown-label-email">{user.email}</span>
</div>
),
disabled: true,
dataTestId: 'logged-in-as-nav-item',
},
{ type: 'divider' as const },
{
key: 'account',
label: 'Account Settings',
dataTestId: 'account-settings-nav-item',
},
{
key: 'workspace',
label: 'Workspace Settings',
disabled: isWorkspaceBlocked,
dataTestId: 'workspace-settings-nav-item',
},
...(isEnterpriseSelfHostedUser || isCommunityEnterpriseUser
? [
{
key: 'license',
label: 'Manage License',
dataTestId: 'manage-license-nav-item',
},
]
: []),
{ type: 'divider' as const },
{
key: 'logout',
label: (
<span className="user-settings-dropdown-logout-section">Sign out</span>
),
dataTestId: 'logout-nav-item',
},
].filter(Boolean),
getUserSettingsDropdownMenuItems({
userEmail: user.email,
isWorkspaceBlocked,
isEnterpriseSelfHostedUser,
isCommunityEnterpriseUser,
}),
[
isEnterpriseSelfHostedUser,
isCommunityEnterpriseUser,
@@ -856,9 +821,6 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
});
switch (item.key) {
case ROUTES.SHORTCUTS:
history.push(ROUTES.SHORTCUTS);
break;
case 'invite-collaborators':
history.push(`${ROUTES.ORG_SETTINGS}#invite-team-members`);
break;
@@ -878,7 +840,7 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
};
const handleSettingsMenuItemClick = (info: SidebarItem): void => {
const item = userSettingsDropdownMenuItems.find(
const item = (userSettingsDropdownMenuItems ?? []).find(
(item) => item?.key === info.key,
);
let menuLabel = '';
@@ -904,6 +866,9 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
case 'license':
history.push(ROUTES.LIST_LICENSES);
break;
case 'keyboard-shortcuts':
history.push(ROUTES.SHORTCUTS);
break;
case 'logout':
Logout();
break;

View File

@@ -1,4 +1,6 @@
import { RocketOutlined } from '@ant-design/icons';
import { Style } from '@signozhq/design-tokens';
import { MenuProps } from 'antd';
import ROUTES from 'constants/routes';
import {
ArrowUpRight,
@@ -8,6 +10,7 @@ import {
Book,
Boxes,
BugIcon,
Building2,
ChartArea,
Cloudy,
DraftingCompass,
@@ -20,6 +23,7 @@ import {
Layers2,
LayoutGrid,
ListMinus,
LogOut,
MessageSquareText,
Plus,
Receipt,
@@ -34,7 +38,11 @@ import {
UserPlus,
} from 'lucide-react';
import { SecondaryMenuItemKey, SidebarItem } from './sideNav.types';
import {
SecondaryMenuItemKey,
SettingsNavSection,
SidebarItem,
} from './sideNav.types';
export const getStartedMenuItem = {
key: ROUTES.GET_STARTED,
@@ -296,77 +304,87 @@ export const defaultMoreMenuItems: SidebarItem[] = [
},
];
export const settingsMenuItems: SidebarItem[] = [
export const settingsNavSections: SettingsNavSection[] = [
{
key: ROUTES.SETTINGS,
label: 'General',
icon: <Settings size={16} />,
isEnabled: true,
itemKey: 'general',
},
{
key: ROUTES.BILLING,
label: 'Billing',
icon: <Receipt size={16} />,
isEnabled: false,
itemKey: 'billing',
},
{
key: ROUTES.ROLES_SETTINGS,
label: 'Roles',
icon: <Shield size={16} />,
isEnabled: false,
itemKey: 'roles',
},
{
key: ROUTES.ORG_SETTINGS,
label: 'Members & SSO',
icon: <User size={16} />,
isEnabled: false,
itemKey: 'members-sso',
key: 'general',
items: [
{
key: ROUTES.SETTINGS,
label: 'Workspace',
icon: <Settings size={16} />,
isEnabled: true,
itemKey: 'workspace',
},
{
key: ROUTES.MY_SETTINGS,
label: 'Account',
icon: <User size={16} />,
isEnabled: true,
itemKey: 'account',
},
{
key: ROUTES.ALL_CHANNELS,
label: 'Notification Channels',
icon: <FileKey2 size={16} />,
isEnabled: true,
itemKey: 'notification-channels',
},
{
key: ROUTES.BILLING,
label: 'Billing',
icon: <Receipt size={16} />,
isEnabled: false,
itemKey: 'billing',
},
],
},
{
key: ROUTES.INTEGRATIONS,
label: 'Integrations',
icon: <Unplug size={16} />,
isEnabled: false,
itemKey: 'integrations',
key: 'identity-access',
title: 'IDENTITY & ACCESS',
items: [
{
key: ROUTES.ROLES_SETTINGS,
label: 'Roles',
icon: <Shield size={16} />,
isEnabled: false,
itemKey: 'roles',
},
{
key: ROUTES.INTEGRATIONS,
label: 'Integrations',
icon: <Unplug size={16} />,
isEnabled: false,
itemKey: 'integrations',
},
{
key: ROUTES.API_KEYS,
label: 'API Keys',
icon: <Key size={16} />,
isEnabled: false,
itemKey: 'api-keys',
},
{
key: ROUTES.INGESTION_SETTINGS,
label: 'Ingestion',
icon: <RocketOutlined rotate={45} />,
isEnabled: false,
itemKey: 'ingestion',
},
],
},
{
key: ROUTES.ALL_CHANNELS,
label: 'Notification Channels',
icon: <FileKey2 size={16} />,
isEnabled: true,
itemKey: 'notification-channels',
},
{
key: ROUTES.API_KEYS,
label: 'API Keys',
icon: <Key size={16} />,
isEnabled: false,
itemKey: 'api-keys',
},
{
key: ROUTES.INGESTION_SETTINGS,
label: 'Ingestion',
icon: <RocketOutlined rotate={45} />,
isEnabled: false,
itemKey: 'ingestion',
},
{
key: ROUTES.MY_SETTINGS,
label: 'Account Settings',
icon: <User size={16} />,
isEnabled: true,
itemKey: 'account-settings',
},
{
key: ROUTES.SHORTCUTS,
label: 'Keyboard Shortcuts',
icon: <Layers2 size={16} />,
isEnabled: true,
itemKey: 'keyboard-shortcuts',
key: 'authentication',
title: 'Authentication',
items: [
{
key: ROUTES.ORG_SETTINGS,
label: 'Members & SSO',
icon: <User size={16} />,
isEnabled: false,
itemKey: 'members-sso',
},
],
},
];
@@ -417,12 +435,6 @@ export const helpSupportDropdownMenuItems: SidebarItem[] = [
icon: <MessageSquareText size={14} />,
itemKey: 'chat-support',
},
{
key: ROUTES.SHORTCUTS,
label: 'Keyboard Shortcuts',
icon: <Keyboard size={14} />,
itemKey: 'keyboard-shortcuts',
},
{
key: 'invite-collaborators',
label: 'Invite a Team Member',
@@ -431,6 +443,78 @@ export const helpSupportDropdownMenuItems: SidebarItem[] = [
},
];
export interface UserSettingsMenuItemsParams {
userEmail: string;
isWorkspaceBlocked: boolean;
isEnterpriseSelfHostedUser: boolean;
isCommunityEnterpriseUser: boolean;
}
export const getUserSettingsDropdownMenuItems = ({
userEmail,
isWorkspaceBlocked,
isEnterpriseSelfHostedUser,
isCommunityEnterpriseUser,
}: UserSettingsMenuItemsParams): MenuProps['items'] =>
[
{
key: 'label',
label: (
<div className="user-settings-dropdown-logged-in-section">
<span className="user-settings-dropdown-label-text">LOGGED IN AS</span>
<span className="user-settings-dropdown-label-email">{userEmail}</span>
</div>
),
disabled: true,
dataTestId: 'logged-in-as-nav-item',
},
{ type: 'divider' as const },
{
key: 'workspace',
label: 'Workspace Settings',
icon: <Building2 size={14} color={Style.L1_FOREGROUND} />,
disabled: isWorkspaceBlocked,
dataTestId: 'workspace-settings-nav-item',
},
{
key: 'account',
label: 'Account Settings',
icon: <User size={14} color={Style.L1_FOREGROUND} />,
dataTestId: 'account-settings-nav-item',
},
...(isEnterpriseSelfHostedUser || isCommunityEnterpriseUser
? [
{
key: 'license',
label: 'Manage License',
icon: <Shield size={14} color={Style.L1_FOREGROUND} />,
dataTestId: 'manage-license-nav-item',
},
]
: []),
{
key: 'keyboard-shortcuts',
label: 'Keyboard Shortcuts',
icon: <Keyboard size={14} color={Style.L1_FOREGROUND} />,
dataTestId: 'keyboard-shortcuts-nav-item',
},
{ type: 'divider' as const },
{
key: 'logout',
label: (
<span className="user-settings-dropdown-logout-section">Sign out</span>
),
icon: (
<LogOut
size={14}
className="user-settings-dropdown-logout-section"
color={Style.DANGER_BACKGROUND}
/>
),
dataTestId: 'logout-nav-item',
},
].filter(Boolean);
/** Mapping of some newly added routes and their corresponding active sidebar menu key */
export const NEW_ROUTES_MENU_ITEM_KEY_MAP: Record<string, string> = {
[ROUTES.TRACE]: ROUTES.TRACES_EXPLORER,

View File

@@ -24,6 +24,12 @@ export interface SidebarItem {
export const CHANGELOG_LABEL = 'Full Changelog';
export interface SettingsNavSection {
title?: string;
items: SidebarItem[];
key: string;
}
export interface DropdownSeparator {
type: 'divider' | 'group';
label?: ReactNode;

View File

@@ -31,9 +31,28 @@
.settings-page-sidenav {
width: 240px;
height: calc(100vh - 48px);
border-right: 1px solid var(--Slate-500, #161922);
background: var(--Ink-500, #0b0c0e);
margin-top: 4px;
border-right: 1px solid var(--secondary);
background: var(--sidebar-primary-foreground);
padding-top: var(--padding-1);
display: flex;
flex-direction: column;
gap: var(--spacing-12);
overflow-y: auto;
.settings-nav-section {
display: flex;
flex-direction: column;
}
.settings-nav-section-title {
font-size: var(--uppercase-small-600-font-size);
font-weight: var(--uppercase-small-600-font-weight);
letter-spacing: 0.88px;
text-transform: uppercase;
color: var(--l3-foreground);
margin-bottom: var(--margin-2);
padding: var(--padding-1) var(--padding-3);
}
.nav-item {
.nav-item-data {

View File

@@ -7,7 +7,7 @@ import { FeatureKeys } from 'constants/features';
import ROUTES from 'constants/routes';
import { routeConfig } from 'container/SideNav/config';
import { getQueryString } from 'container/SideNav/helper';
import { settingsMenuItems as defaultSettingsMenuItems } from 'container/SideNav/menuItems';
import { settingsNavSections } from 'container/SideNav/menuItems';
import NavItem from 'container/SideNav/NavItem/NavItem';
import { SidebarItem } from 'container/SideNav/sideNav.types';
import useComponentPermission from 'hooks/useComponentPermission';
@@ -33,7 +33,7 @@ function SettingsPage(): JSX.Element {
const { isCloudUser, isEnterpriseSelfHostedUser } = useGetTenantLicense();
const [settingsMenuItems, setSettingsMenuItems] = useState<SidebarItem[]>(
defaultSettingsMenuItems,
settingsNavSections.flatMap((section) => section.items),
);
const isAdmin = user.role === USER_ROLES.ADMIN;
@@ -252,25 +252,40 @@ function SettingsPage(): JSX.Element {
<div className="settings-page-content-container">
<div className="settings-page-sidenav" data-testid="settings-page-sidenav">
{settingsMenuItems
.filter((item) => item.isEnabled)
.map((item) => (
<NavItem
key={item.key}
item={item}
isActive={isActiveNavItem(item.key as string)}
isDisabled={false}
showIcon={false}
onClick={(event): void => {
logEvent('Settings V2: Menu clicked', {
menuLabel: item.label,
menuRoute: item.key,
});
handleMenuItemClick((event as unknown) as MouseEvent, item);
}}
dataTestId={item.itemKey}
/>
))}
{settingsNavSections.map((section) => {
const enabledItems = section.items.filter((sectionItem) =>
settingsMenuItems.some(
(item) => item.key === sectionItem.key && item.isEnabled,
),
);
if (enabledItems.length === 0) {
return null;
}
return (
<div key={section.key} className="settings-nav-section">
{section.title && (
<div className="settings-nav-section-title">{section.title}</div>
)}
{enabledItems.map((item) => (
<NavItem
key={item.key}
item={item}
isActive={isActiveNavItem(item.key as string)}
isDisabled={false}
showIcon={false}
onClick={(event): void => {
logEvent('Settings V2: Menu clicked', {
menuLabel: item.label,
menuRoute: item.key,
});
handleMenuItemClick((event as unknown) as MouseEvent, item);
}}
dataTestId={item.itemKey}
/>
))}
</div>
);
})}
</div>
<div className="settings-page-content">