Fix settings navigation active state for sub-pages (#12318)

Changes the default behavior for settings navigation items to stay
active when navigating to sub-pages.

**Problem:**
- Navigation items like "Data Model" and "Webhooks" were not staying
highlighted when navigating to detail pages
- This was because `matchSubPages` defaulted to requiring exact path
matches

**Solution:**
- Updated logic to make sub-page matching the default behavior (`end:
item.matchSubPages === false`)
- Only "Accounts" explicitly sets `matchSubPages: false` for its custom
sub-item navigation
- Removed redundant `matchSubPages: true` declarations throughout the
codebase

**URL Changes:** -- checked with @Bonapara 
- `/settings/workspace` → `/settings/general`
- `/settings/workspace-members` → `/settings/members`
- `/settings/api-keys` → `/settings/apis`
- `/settings/developers/webhooks` → `/settings/webhooks`

before: 


https://github.com/user-attachments/assets/56b94a49-9c31-4bb5-9875-ec24f4bc4d1e

after:


https://github.com/user-attachments/assets/38742599-c045-44d1-8020-56f3eacca779

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
nitin
2025-05-30 11:49:20 +05:30
committed by GitHub
parent dc0401edb5
commit da00dee8a1
22 changed files with 57 additions and 51 deletions

View File

@ -208,7 +208,7 @@ export const SettingsWorkspaceMembers = () => {
<Section>
<H2Title
title={t`Manage Members`}
description={t`Manage the members of your space here`}
description={t`Manage the members of your workspace here`}
/>
<StyledSearchContainer>
<StyledSearchInput

View File

@ -12,7 +12,7 @@ const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/SettingsWorkspace',
component: SettingsWorkspace,
decorators: [PageDecorator],
args: { routePath: '/settings/workspace' },
args: { routePath: '/settings/general' },
parameters: {
msw: graphqlMocks,
},

View File

@ -15,7 +15,7 @@ const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/SettingsWorkspaceMembers',
component: SettingsWorkspaceMembers,
decorators: [PageDecorator],
args: { routePath: '/settings/workspace-members' },
args: { routePath: '/settings/members' },
parameters: {
msw: graphqlMocks,
},

View File

@ -69,7 +69,7 @@ export const SettingsObjectNewFieldSelect = () => {
<SubMenuTopBarContainer
title={t`1. Select a field type`}
links={[
{ children: t`Workspace`, href: '/settings/workspace' },
{ children: t`Workspace`, href: '/settings/general' },
{ children: t`Objects`, href: '/settings/objects' },
{
children: activeObjectMetadataItem.labelPlural,

View File

@ -15,7 +15,7 @@ const meta: Meta<PageDecoratorArgs> = {
component: SettingsDevelopersApiKeyDetail,
decorators: [PageDecorator],
args: {
routePath: '/settings/developers/api-keys/:apiKeyId',
routePath: '/settings/apis/:apiKeyId',
routeParams: {
':apiKeyId': 'f7c6d736-8fcd-4e9c-ab99-28f6a9031570',
},
@ -50,14 +50,14 @@ export type Story = StoryObj<typeof SettingsDevelopersApiKeyDetail>;
export const Default: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await canvas.findByText('sfsfdsf API Key', undefined, { timeout: 3000 });
await canvas.findByText('sfsfdsf', undefined, { timeout: 3000 });
},
};
export const RegenerateApiKey: Story = {
play: async ({ step }) => {
const canvas = within(document.body);
await canvas.findByText('sfsfdsf API Key', undefined, { timeout: 3000 });
await canvas.findByText('sfsfdsf', undefined, { timeout: 3000 });
await userEvent.click(await canvas.findByText('Regenerate Key'));
@ -85,7 +85,7 @@ export const RegenerateApiKey: Story = {
export const DeleteApiKey: Story = {
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
await canvas.findByText('sfsfdsf API Key', undefined, { timeout: 3000 });
await canvas.findByText('sfsfdsf', undefined, { timeout: 3000 });
await userEvent.click(await canvas.findByText('Delete'));

View File

@ -14,7 +14,7 @@ const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/ApiKeys/SettingsDevelopersApiKeysNew',
component: SettingsDevelopersApiKeysNew,
decorators: [PageDecorator],
args: { routePath: getSettingsPath(SettingsPath.DevelopersNewApiKey) },
args: { routePath: getSettingsPath(SettingsPath.NewApiKey) },
parameters: {
msw: graphqlMocks,
},

View File

@ -14,7 +14,7 @@ const meta: Meta<PageDecoratorArgs> = {
component: SettingsDevelopersWebhooksDetail,
decorators: [PageDecorator],
args: {
routePath: '/settings/developers/webhooks/:webhookId',
routePath: '/settings/webhooks/:webhookId',
routeParams: { ':webhookId': '1234' },
},
parameters: {

View File

@ -66,7 +66,7 @@ export const SettingsApiKeys = () => {
title={t`Create API key`}
size="small"
variant="secondary"
to={getSettingsPath(SettingsPath.DevelopersNewApiKey)}
to={getSettingsPath(SettingsPath.NewApiKey)}
/>
</StyledButtonContainer>
</Section>

View File

@ -143,7 +143,7 @@ export const SettingsDevelopersApiKeyDetail = () => {
if (isNonEmptyString(apiKey?.token)) {
setApiKeyTokenCallback(apiKey.id, apiKey.token);
navigate(SettingsPath.DevelopersApiKeyDetail, {
navigate(SettingsPath.ApiKeyDetail, {
apiKeyId: apiKey.id,
});
}
@ -173,7 +173,7 @@ export const SettingsDevelopersApiKeyDetail = () => {
children: t`APIs`,
href: getSettingsPath(SettingsPath.APIs),
},
{ children: t`${apiKeyName} API Key` },
{ children: t`${apiKeyName}` },
]}
>
<SettingsPageContainer>

View File

@ -15,12 +15,12 @@ import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBa
import { useLingui } from '@lingui/react/macro';
import { useRecoilCallback } from 'recoil';
import { Key } from 'ts-key-enum';
import { useGenerateApiKeyTokenMutation } from '~/generated/graphql';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
import { isDefined } from 'twenty-shared/utils';
import { H2Title } from 'twenty-ui/display';
import { Section } from 'twenty-ui/layout';
import { useGenerateApiKeyTokenMutation } from '~/generated/graphql';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
export const SettingsDevelopersApiKeysNew = () => {
const { t } = useLingui();
@ -72,7 +72,7 @@ export const SettingsDevelopersApiKeysNew = () => {
newApiKey.id,
tokenData.data.generateApiKeyToken.token,
);
navigateSettings(SettingsPath.DevelopersApiKeyDetail, {
navigateSettings(SettingsPath.ApiKeyDetail, {
apiKeyId: newApiKey.id,
});
}

View File

@ -5,6 +5,7 @@ import { useParams, useSearchParams } from 'react-router-dom';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader';
import { useWebhookUpdateForm } from '@/settings/developers/hooks/useWebhookUpdateForm';
import { SettingsPath } from '@/types/SettingsPath';
import { Select } from '@/ui/input/components/Select';
@ -101,7 +102,7 @@ export const SettingsDevelopersWebhooksDetail = () => {
];
if (loading || !formData) {
return <></>;
return <SettingsSkeletonLoader />;
}
const confirmationText = t`yes`;
@ -115,7 +116,11 @@ export const SettingsDevelopersWebhooksDetail = () => {
children: t`Workspace`,
href: getSettingsPath(SettingsPath.Workspace),
},
{ children: t`Webhook` },
{
children: t`Webhooks`,
href: getSettingsPath(SettingsPath.Webhooks),
},
{ children: title },
]}
>
<SettingsPageContainer>

View File

@ -5,12 +5,12 @@ import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBa
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import styled from '@emotion/styled';
import { Trans, useLingui } from '@lingui/react/macro';
import { H2Title, IconPlus } from 'twenty-ui/display';
import { Button } from 'twenty-ui/input';
import { Section } from 'twenty-ui/layout';
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
import { v4 } from 'uuid';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
import { Button } from 'twenty-ui/input';
import { H2Title, IconPlus } from 'twenty-ui/display';
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
import { Section } from 'twenty-ui/layout';
const StyledButtonContainer = styled.div`
display: flex;
@ -58,7 +58,7 @@ export const SettingsWebhooks = () => {
size="small"
variant="secondary"
to={getSettingsPath(
SettingsPath.DevelopersNewWebhookDetail,
SettingsPath.WebhookDetail,
{
webhookId: v4(),
},