diff --git a/packages/twenty-front/src/modules/app/components/SettingsRoutes.tsx b/packages/twenty-front/src/modules/app/components/SettingsRoutes.tsx
index 5e250fbd180eb..3bde2e353a2e3 100644
--- a/packages/twenty-front/src/modules/app/components/SettingsRoutes.tsx
+++ b/packages/twenty-front/src/modules/app/components/SettingsRoutes.tsx
@@ -24,20 +24,6 @@ const SettingsRestPlayground = lazy(() =>
),
);
-const SettingsAccountsCalendars = lazy(() =>
- import('~/pages/settings/accounts/SettingsAccountsCalendars').then(
- (module) => ({
- default: module.SettingsAccountsCalendars,
- }),
- ),
-);
-
-const SettingsAccountsEmails = lazy(() =>
- import('~/pages/settings/accounts/SettingsAccountsEmails').then((module) => ({
- default: module.SettingsAccountsEmails,
- })),
-);
-
const SettingsAccountsConfiguration = lazy(() =>
import('~/pages/settings/accounts/SettingsAccountsConfiguration').then(
(module) => ({
@@ -122,20 +108,20 @@ const SettingsLogicFunctionDetail = lazy(() =>
),
);
-const SettingsWorkspace = lazy(() =>
- import('~/pages/settings/SettingsWorkspace').then((module) => ({
- default: module.SettingsWorkspace,
+const SettingsGeneral = lazy(() =>
+ import('~/pages/settings/general/SettingsGeneral').then((module) => ({
+ default: module.SettingsGeneral,
})),
);
const SettingsWorkspaceEmail = lazy(() =>
- import('~/pages/settings/SettingsWorkspaceEmail').then((module) => ({
+ import('~/pages/settings/email/SettingsWorkspaceEmail').then((module) => ({
default: module.SettingsWorkspaceEmail,
})),
);
const SettingsWorkspaceEmailGroupChannelDetail = lazy(() =>
- import('~/pages/settings/workspace/SettingsWorkspaceEmailGroupChannelDetail').then(
+ import('~/pages/settings/email/SettingsWorkspaceEmailGroupChannelDetail').then(
(module) => ({
default: module.SettingsWorkspaceEmailGroupChannelDetail,
}),
@@ -157,9 +143,11 @@ const SettingsCustomDomainPage = lazy(() =>
);
const SettingsApiWebhooks = lazy(() =>
- import('~/pages/settings/workspace/SettingsApiWebhooks').then((module) => ({
- default: module.SettingsApiWebhooks,
- })),
+ import('~/pages/settings/api-webhooks/SettingsApiWebhooks').then(
+ (module) => ({
+ default: module.SettingsApiWebhooks,
+ }),
+ ),
);
const SettingsAI = lazy(() =>
@@ -319,13 +307,13 @@ const SettingsWorkspaceMember = lazy(() =>
);
const SettingsProfile = lazy(() =>
- import('~/pages/settings/SettingsProfile').then((module) => ({
+ import('~/pages/settings/profile/SettingsProfile').then((module) => ({
default: module.SettingsProfile,
})),
);
const SettingsTwoFactorAuthenticationMethod = lazy(() =>
- import('~/pages/settings/SettingsTwoFactorAuthenticationMethod').then(
+ import('~/pages/settings/profile/SettingsTwoFactorAuthenticationMethod').then(
(module) => ({
default: module.SettingsTwoFactorAuthenticationMethod,
}),
@@ -346,20 +334,34 @@ const SettingsAccounts = lazy(() =>
})),
);
+const SettingsAccountsEmails = lazy(() =>
+ import('~/pages/settings/accounts/SettingsAccountsEmails').then((module) => ({
+ default: module.SettingsAccountsEmails,
+ })),
+);
+
+const SettingsAccountsCalendars = lazy(() =>
+ import('~/pages/settings/accounts/SettingsAccountsCalendars').then(
+ (module) => ({
+ default: module.SettingsAccountsCalendars,
+ }),
+ ),
+);
+
const SettingsBilling = lazy(() =>
- import('~/pages/settings/SettingsBilling').then((module) => ({
+ import('~/pages/settings/billing/SettingsBilling').then((module) => ({
default: module.SettingsBilling,
})),
);
const SettingsUsage = lazy(() =>
- import('~/pages/settings/SettingsUsage').then((module) => ({
+ import('~/pages/settings/billing/SettingsUsage').then((module) => ({
default: module.SettingsUsage,
})),
);
const SettingsUsageUserDetail = lazy(() =>
- import('~/pages/settings/SettingsUsageUserDetail').then((module) => ({
+ import('~/pages/settings/billing/SettingsUsageUserDetail').then((module) => ({
default: module.SettingsUsageUserDetail,
})),
);
@@ -417,12 +419,6 @@ const SettingsObjectFieldEdit = lazy(() =>
),
);
-const SettingsSecurity = lazy(() =>
- import('~/pages/settings/security/SettingsSecurity').then((module) => ({
- default: module.SettingsSecurity,
- })),
-);
-
const SettingsSecuritySSOIdentifyProvider = lazy(() =>
import('~/pages/settings/security/SettingsSecuritySSOIdentifyProvider').then(
(module) => ({
@@ -565,9 +561,9 @@ const SettingsAdminWorkspaceChatThread = lazy(() =>
),
);
-const SettingsUpdates = lazy(() =>
- import('~/pages/settings/updates/SettingsUpdates').then((module) => ({
- default: module.SettingsUpdates,
+const SettingsCommunity = lazy(() =>
+ import('~/pages/settings/community/SettingsCommunity').then((module) => ({
+ default: module.SettingsCommunity,
})),
);
@@ -624,20 +620,20 @@ export const SettingsRoutes = ({ isAdminPageEnabled }: SettingsRoutesProps) => (
>
} />
}
- />
- }
+ path={SettingsPath.AccountsEmails}
+ element={}
/>
}
/>
}
+ path={SettingsPath.NewAccount}
+ element={}
+ />
+ }
/>
(
/>
}
>
- } />
+ } />
}
@@ -916,6 +912,13 @@ export const SettingsRoutes = ({ isAdminPageEnabled }: SettingsRoutesProps) => (
/>
+
+ }
+ />
+
(
/>
}
>
- } />
}
@@ -1018,7 +1020,7 @@ export const SettingsRoutes = ({ isAdminPageEnabled }: SettingsRoutesProps) => (
/>
}
>
- } />
+ } />
diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsContainer.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsContainer.tsx
index 9b0f1ebaa4897..c15e4720d2621 100644
--- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsContainer.tsx
+++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsContainer.tsx
@@ -1,70 +1,32 @@
-import { styled } from '@linaria/react';
-
+import { type CalendarChannel } from '@/accounts/types/CalendarChannel';
import { SettingsAccountsCalendarChannelDetails } from '@/settings/accounts/components/SettingsAccountsCalendarChannelDetails';
-import { SettingsNewAccountSection } from '@/settings/accounts/components/SettingsNewAccountSection';
import { SETTINGS_ACCOUNT_CALENDAR_CHANNELS_TAB_LIST_COMPONENT_ID } from '@/settings/accounts/constants/SettingsAccountCalendarChannelsTabListComponentId';
-import { useMyCalendarChannels } from '@/settings/accounts/hooks/useMyCalendarChannels';
-import { TabList } from '@/ui/layout/tab-list/components/TabList';
-import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
-import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
+import { useSettingsActiveTabId } from '@/settings/components/layout/useSettingsActiveTabId';
import React from 'react';
-import { CalendarChannelSyncStage } from 'twenty-shared/types';
-import { themeCssVariables } from 'twenty-ui/theme-constants';
-const StyledCalenderContainer = styled.div`
- padding-bottom: ${themeCssVariables.spacing[6]};
-`;
+type SettingsAccountsCalendarChannelsContainerProps = {
+ calendarChannels: CalendarChannel[];
+};
-export const SettingsAccountsCalendarChannelsContainer = () => {
- const activeTabId = useAtomComponentStateValue(
- activeTabIdComponentState,
+export const SettingsAccountsCalendarChannelsContainer = ({
+ calendarChannels,
+}: SettingsAccountsCalendarChannelsContainerProps) => {
+ const activeTabId = useSettingsActiveTabId(
SETTINGS_ACCOUNT_CALENDAR_CHANNELS_TAB_LIST_COMPONENT_ID,
+ calendarChannels.map((channel) => channel.id),
);
- const { channels: allCalendarChannels } = useMyCalendarChannels();
-
- const calendarChannels = allCalendarChannels.filter(
- (channel) =>
- channel.syncStage !== CalendarChannelSyncStage.PENDING_CONFIGURATION,
- );
-
- const tabs = [
- ...calendarChannels.map((calendarChannel) => ({
- id: calendarChannel.id,
- title: calendarChannel.handle,
- })),
- ];
-
- if (!calendarChannels.length) {
- return ;
- }
-
return (
<>
- {tabs.length > 1 && (
-
-
-
- )}
{calendarChannels.map((calendarChannel) => (
- {(calendarChannels.length === 1 ||
- calendarChannel.id === activeTabId) && (
+ {calendarChannel.id === activeTabId && (
)}
))}
- {/* TODO: remove or keep? */}
- {/* {activeTabId === 'general' && (
-
- )} */}
>
);
};
diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEditImapSmtpCaldavConnection.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEditImapSmtpCaldavConnection.tsx
index 08072ca8dbcb4..2915570c6d628 100644
--- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEditImapSmtpCaldavConnection.tsx
+++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEditImapSmtpCaldavConnection.tsx
@@ -5,7 +5,7 @@ import { useParams } from 'react-router-dom';
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { SettingsPath } from 'twenty-shared/types';
import { Loader } from 'twenty-ui/feedback';
@@ -64,7 +64,7 @@ export const SettingsAccountsEditImapSmtpCaldavConnection = () => {
const renderForm = () => (
// oxlint-disable-next-line react/jsx-props-no-spreading
- {
existingProtocols={existingProtocols}
/>
-
+
);
diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelsContainer.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelsContainer.tsx
index 0c695d6b9cd30..328ec49708d11 100644
--- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelsContainer.tsx
+++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelsContainer.tsx
@@ -1,86 +1,30 @@
-import { styled } from '@linaria/react';
-
+import { type MessageChannel } from '@/accounts/types/MessageChannel';
import { SettingsAccountsMessageChannelDetails } from '@/settings/accounts/components/SettingsAccountsMessageChannelDetails';
import { SettingsAccountsSelectedMessageChannelEffect } from '@/settings/accounts/components/SettingsAccountsSelectedMessageChannelEffect';
-import { SettingsNewAccountSection } from '@/settings/accounts/components/SettingsNewAccountSection';
import { SETTINGS_ACCOUNT_MESSAGE_CHANNELS_TAB_LIST_COMPONENT_ID } from '@/settings/accounts/constants/SettingsAccountMessageChannelsTabListComponentId';
-import { useMyMessageChannels } from '@/settings/accounts/hooks/useMyMessageChannels';
-import { settingsAccountsSelectedMessageChannelState } from '@/settings/accounts/states/settingsAccountsSelectedMessageChannelState';
-import { TabList } from '@/ui/layout/tab-list/components/TabList';
-import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
-import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
-import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
-import React, { useCallback } from 'react';
-import {
- MessageChannelSyncStage,
- MessageChannelType,
-} from 'twenty-shared/types';
-import { isDefined } from 'twenty-shared/utils';
-import { themeCssVariables } from 'twenty-ui/theme-constants';
+import { useSettingsActiveTabId } from '@/settings/components/layout/useSettingsActiveTabId';
+import React from 'react';
-const StyledMessageContainer = styled.div`
- padding-bottom: ${themeCssVariables.spacing[6]};
-`;
+type SettingsAccountsMessageChannelsContainerProps = {
+ messageChannels: MessageChannel[];
+};
-export const SettingsAccountsMessageChannelsContainer = () => {
- const activeTabId = useAtomComponentStateValue(
- activeTabIdComponentState,
+export const SettingsAccountsMessageChannelsContainer = ({
+ messageChannels,
+}: SettingsAccountsMessageChannelsContainerProps) => {
+ const activeTabId = useSettingsActiveTabId(
SETTINGS_ACCOUNT_MESSAGE_CHANNELS_TAB_LIST_COMPONENT_ID,
+ messageChannels.map((channel) => channel.id),
);
- const setSettingsAccountsSelectedMessageChannel = useSetAtomState(
- settingsAccountsSelectedMessageChannelState,
- );
-
- const { channels: allMessageChannels } = useMyMessageChannels();
-
- const messageChannels = allMessageChannels.filter(
- (channel) =>
- channel.isSyncEnabled &&
- channel.syncStage !== MessageChannelSyncStage.PENDING_CONFIGURATION &&
- channel.type !== MessageChannelType.EMAIL_GROUP,
- );
-
- const tabs = messageChannels.map((messageChannel) => ({
- id: messageChannel.id,
- title: messageChannel.handle,
- }));
-
- const handleTabChange = useCallback(
- (tabId: string) => {
- const selectedMessageChannel = messageChannels.find(
- (channel) => channel.id === tabId,
- );
- if (isDefined(selectedMessageChannel)) {
- setSettingsAccountsSelectedMessageChannel(selectedMessageChannel);
- }
- },
- [messageChannels, setSettingsAccountsSelectedMessageChannel],
- );
-
- if (!messageChannels.length) {
- return ;
- }
return (
<>
- {tabs.length > 1 && (
-
-
-
- )}
{messageChannels.map((messageChannel) => (
- {(messageChannels.length === 1 ||
- messageChannel.id === activeTabId) && (
+ {messageChannel.id === activeTabId && (
diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsNewEmailGroupChannel.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsNewEmailGroupChannel.tsx
index fa07c2abc00a0..66395637af58d 100644
--- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsNewEmailGroupChannel.tsx
+++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsNewEmailGroupChannel.tsx
@@ -12,7 +12,7 @@ import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
export const SettingsAccountsNewEmailGroupChannel = () => {
@@ -45,12 +45,12 @@ export const SettingsAccountsNewEmailGroupChannel = () => {
}, [createEmailGroupChannel, handle, navigate, enqueueErrorSnackBar, t]);
return (
- {
/>
-
+
);
};
diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsNewImapSmtpCaldavConnection.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsNewImapSmtpCaldavConnection.tsx
index d8e1c23e73e5a..bda25b5aef660 100644
--- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsNewImapSmtpCaldavConnection.tsx
+++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsNewImapSmtpCaldavConnection.tsx
@@ -3,7 +3,7 @@ import { FormProvider } from 'react-hook-form';
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
@@ -30,7 +30,7 @@ export const SettingsAccountsNewImapSmtpCaldavConnection = () => {
return (
// oxlint-disable-next-line react/jsx-props-no-spreading
- {
-
+
);
};
diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsSelectedMessageChannelEffect.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsSelectedMessageChannelEffect.tsx
index 023b41169bcea..040b7fac18760 100644
--- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsSelectedMessageChannelEffect.tsx
+++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsSelectedMessageChannelEffect.tsx
@@ -1,8 +1,7 @@
import { type MessageChannel } from '@/accounts/types/MessageChannel';
import { SETTINGS_ACCOUNT_MESSAGE_CHANNELS_TAB_LIST_COMPONENT_ID } from '@/settings/accounts/constants/SettingsAccountMessageChannelsTabListComponentId';
import { settingsAccountsSelectedMessageChannelState } from '@/settings/accounts/states/settingsAccountsSelectedMessageChannelState';
-import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
-import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
+import { useSettingsActiveTabId } from '@/settings/components/layout/useSettingsActiveTabId';
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
import { useEffect } from 'react';
@@ -13,9 +12,9 @@ type SettingsAccountsSelectedMessageChannelEffectProps = {
export const SettingsAccountsSelectedMessageChannelEffect = ({
messageChannels,
}: SettingsAccountsSelectedMessageChannelEffectProps) => {
- const activeTabId = useAtomComponentStateValue(
- activeTabIdComponentState,
+ const activeTabId = useSettingsActiveTabId(
SETTINGS_ACCOUNT_MESSAGE_CHANNELS_TAB_LIST_COMPONENT_ID,
+ messageChannels.map((channel) => channel.id),
);
const setSettingsAccountsSelectedMessageChannel = useSetAtomState(
@@ -27,13 +26,13 @@ export const SettingsAccountsSelectedMessageChannelEffect = ({
return;
}
- const currentSelectionStillExists = activeTabId
- ? messageChannels.some((channel) => channel.id === activeTabId)
- : false;
+ const activeChannel = messageChannels.find(
+ (channel) => channel.id === activeTabId,
+ );
- if (!currentSelectionStillExists) {
- setSettingsAccountsSelectedMessageChannel(messageChannels[0]);
- }
+ setSettingsAccountsSelectedMessageChannel(
+ activeChannel ?? messageChannels[0],
+ );
}, [messageChannels, activeTabId, setSettingsAccountsSelectedMessageChannel]);
return null;
diff --git a/packages/twenty-front/src/modules/settings/components/SettingsPageContainer.tsx b/packages/twenty-front/src/modules/settings/components/SettingsPageContainer.tsx
index e25f724a425e6..cbb2b4b5acad9 100644
--- a/packages/twenty-front/src/modules/settings/components/SettingsPageContainer.tsx
+++ b/packages/twenty-front/src/modules/settings/components/SettingsPageContainer.tsx
@@ -8,6 +8,8 @@ import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath, isDefined } from 'twenty-shared/utils';
import { themeCssVariables } from 'twenty-ui/theme-constants';
+const SETTINGS_CONTENT_MAX_WIDTH = 760;
+
const StyledSettingsPageContainer = styled.div<{
width?: number;
isMobile?: boolean;
@@ -16,6 +18,8 @@ const StyledSettingsPageContainer = styled.div<{
display: flex;
flex-direction: column;
gap: ${themeCssVariables.spacing[8]};
+ margin: 0 auto;
+ max-width: ${SETTINGS_CONTENT_MAX_WIDTH}px;
overflow: auto;
padding: ${themeCssVariables.spacing[6]} ${themeCssVariables.spacing[8]}
${themeCssVariables.spacing[8]};
diff --git a/packages/twenty-front/src/modules/settings/components/layout/SettingsPageHeader.tsx b/packages/twenty-front/src/modules/settings/components/layout/SettingsPageHeader.tsx
new file mode 100644
index 0000000000000..99485695259ed
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/components/layout/SettingsPageHeader.tsx
@@ -0,0 +1,87 @@
+import { useNavigationDrawerExpanded } from '@/navigation/hooks/useNavigationDrawerExpanded';
+import { SIDE_PANEL_TOP_BAR_HEIGHT } from '@/side-panel/constants/SidePanelTopBarHeight';
+import {
+ Breadcrumb,
+ type BreadcrumbProps,
+} from '@/ui/navigation/bread-crumb/components/Breadcrumb';
+import { NavigationDrawerCollapseButton } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton';
+import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
+import { styled } from '@linaria/react';
+import { type ReactNode } from 'react';
+import { isDefined } from 'twenty-shared/utils';
+import { themeCssVariables } from 'twenty-ui/theme-constants';
+
+type SettingsPageHeaderProps = {
+ links: BreadcrumbProps['links'];
+ title?: ReactNode;
+ tag?: ReactNode;
+ actionButton?: ReactNode;
+};
+
+// minmax(0, 1fr) side tracks (not 1fr) let a long breadcrumb truncate instead of
+// pushing the centered title off its shared axis with the tabs and body.
+const StyledHeader = styled.div`
+ align-items: center;
+ background-color: ${themeCssVariables.background.secondary};
+ border-bottom: 1px solid ${themeCssVariables.border.color.medium};
+ box-sizing: border-box;
+ display: grid;
+ gap: ${themeCssVariables.spacing[2]};
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
+ min-height: ${SIDE_PANEL_TOP_BAR_HEIGHT}px;
+ padding: 0 ${themeCssVariables.spacing[3]};
+ width: 100%;
+`;
+
+const StyledLeft = styled.div`
+ align-items: center;
+ display: flex;
+ gap: ${themeCssVariables.spacing[1]};
+ min-width: 0;
+ overflow: hidden;
+`;
+
+const StyledTitle = styled.div`
+ align-items: center;
+ color: ${themeCssVariables.font.color.primary};
+ display: flex;
+ font-size: ${themeCssVariables.font.size.md};
+ font-weight: ${themeCssVariables.font.weight.semiBold};
+ gap: ${themeCssVariables.spacing[2]};
+ min-width: 0;
+ text-align: center;
+`;
+
+const StyledRight = styled.div`
+ align-items: center;
+ display: flex;
+ gap: ${themeCssVariables.spacing[2]};
+ justify-content: flex-end;
+ min-width: 0;
+`;
+
+export const SettingsPageHeader = ({
+ links,
+ title,
+ tag,
+ actionButton,
+}: SettingsPageHeaderProps) => {
+ const isMobile = useIsMobile();
+ const isNavigationDrawerExpanded = useNavigationDrawerExpanded();
+
+ return (
+
+
+ {!isNavigationDrawerExpanded && (
+
+ )}
+
+
+
+ {!isMobile && isDefined(title) && title}
+ {!isMobile && tag}
+
+ {actionButton}
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/settings/components/layout/SettingsPageLayout.tsx b/packages/twenty-front/src/modules/settings/components/layout/SettingsPageLayout.tsx
new file mode 100644
index 0000000000000..11fd2d3aebe26
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/components/layout/SettingsPageLayout.tsx
@@ -0,0 +1,95 @@
+import { CommandMenuForMobile } from '@/command-menu/components/CommandMenuForMobile';
+import { useCommandMenuHotKeys } from '@/command-menu/hooks/useCommandMenuHotKeys';
+import { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper';
+import { SettingsPageHeader } from '@/settings/components/layout/SettingsPageHeader';
+import { SettingsSecondaryBar } from '@/settings/components/layout/SettingsSecondaryBar';
+import { SidePanelForDesktop } from '@/side-panel/components/SidePanelForDesktop';
+import { type BreadcrumbProps } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
+import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
+import { styled } from '@linaria/react';
+import { type JSX, type ReactNode } from 'react';
+import { isDefined } from 'twenty-shared/utils';
+import { themeCssVariables } from 'twenty-ui/theme-constants';
+
+type SettingsPageLayoutProps = {
+ links: BreadcrumbProps['links'];
+ title?: ReactNode;
+ actionButton?: ReactNode;
+ secondaryBar?: ReactNode;
+ children: ReactNode;
+ tag?: JSX.Element;
+};
+
+const StyledRoot = styled.div<{ isMobile: boolean }>`
+ display: flex;
+ flex: 1;
+ flex-direction: row;
+ min-height: 0;
+ min-width: 0;
+ padding: ${({ isMobile }) =>
+ isMobile ? themeCssVariables.spacing[1] : themeCssVariables.spacing[2]};
+`;
+
+const StyledMainCardWrapper = styled.div`
+ display: flex;
+ flex: 1 1 0;
+ min-width: 0;
+ width: 0;
+`;
+
+const StyledCard = styled.div`
+ background: ${themeCssVariables.background.primary};
+ border: 1px solid ${themeCssVariables.border.color.medium};
+ border-radius: ${themeCssVariables.border.radius.md};
+ box-sizing: border-box;
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ min-height: 0;
+ overflow: hidden;
+ width: 100%;
+`;
+
+const StyledBodyContent = styled.div`
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ min-height: 0;
+ width: 100%;
+`;
+
+export const SettingsPageLayout = ({
+ links,
+ title,
+ actionButton,
+ secondaryBar,
+ children,
+ tag,
+}: SettingsPageLayoutProps) => {
+ const isMobile = useIsMobile();
+
+ useCommandMenuHotKeys();
+
+ return (
+
+
+
+
+ {isDefined(secondaryBar) && (
+ {secondaryBar}
+ )}
+
+
+ {children}
+
+
+
+ {isMobile ? : }
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/settings/components/layout/SettingsSecondaryBar.tsx b/packages/twenty-front/src/modules/settings/components/layout/SettingsSecondaryBar.tsx
new file mode 100644
index 0000000000000..027edd9e90fd7
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/components/layout/SettingsSecondaryBar.tsx
@@ -0,0 +1,29 @@
+import { styled } from '@linaria/react';
+import { type ReactNode } from 'react';
+import { themeCssVariables } from 'twenty-ui/theme-constants';
+
+// Bottom separator is an ::after (not border-bottom), and the bar keeps full
+// height (default align-items) so the active tab's underline lands exactly on it.
+const StyledSecondaryBar = styled.div`
+ box-sizing: border-box;
+ display: flex;
+ flex-shrink: 0;
+ min-height: ${themeCssVariables.spacing[10]};
+ padding: 0 ${themeCssVariables.spacing[3]};
+ position: relative;
+ width: 100%;
+
+ &::after {
+ background-color: ${themeCssVariables.border.color.light};
+ bottom: 0;
+ content: '';
+ height: 1px;
+ left: 0;
+ position: absolute;
+ right: 0;
+ }
+`;
+
+export const SettingsSecondaryBar = ({ children }: { children: ReactNode }) => (
+ {children}
+);
diff --git a/packages/twenty-front/src/modules/settings/components/layout/SettingsTabBar.tsx b/packages/twenty-front/src/modules/settings/components/layout/SettingsTabBar.tsx
new file mode 100644
index 0000000000000..3bb97f1d1ca19
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/components/layout/SettingsTabBar.tsx
@@ -0,0 +1,64 @@
+import { useSettingsActiveTabId } from '@/settings/components/layout/useSettingsActiveTabId';
+import { TabListFromUrlOptionalEffect } from '@/ui/layout/tab-list/components/TabListFromUrlOptionalEffect';
+import { TAB_LIST_GAP } from '@/ui/layout/tab-list/constants/TabListGap';
+import { TabListComponentInstanceContext } from '@/ui/layout/tab-list/states/contexts/TabListComponentInstanceContext';
+import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps';
+import { styled } from '@linaria/react';
+import { TabButton } from 'twenty-ui/input';
+
+type SettingsTabBarProps = {
+ tabs: SingleTabProps[];
+ componentInstanceId: string;
+};
+
+const StyledTabBar = styled.div`
+ display: flex;
+ flex: 1;
+ gap: ${TAB_LIST_GAP}px;
+ justify-content: center;
+ min-width: 0;
+`;
+
+export const SettingsTabBar = ({
+ tabs,
+ componentInstanceId,
+}: SettingsTabBarProps) => {
+ const visibleTabs = tabs.filter((tab) => !tab.hide);
+ const visibleTabIds = visibleTabs.map((tab) => tab.id);
+
+ const activeTabId = useSettingsActiveTabId(
+ componentInstanceId,
+ visibleTabIds,
+ );
+
+ if (visibleTabs.length === 0) {
+ return null;
+ }
+
+ return (
+
+
+
+ {visibleTabs.map((tab) => (
+
+ ))}
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/settings/components/layout/SettingsWizardStepBar.tsx b/packages/twenty-front/src/modules/settings/components/layout/SettingsWizardStepBar.tsx
new file mode 100644
index 0000000000000..7d503a756ff7c
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/components/layout/SettingsWizardStepBar.tsx
@@ -0,0 +1,63 @@
+import { styled } from '@linaria/react';
+import { type ReactNode } from 'react';
+import { IconChevronLeft } from 'twenty-ui/display';
+import { LightIconButton } from 'twenty-ui/input';
+import { themeCssVariables } from 'twenty-ui/theme-constants';
+
+type SettingsWizardStepBarProps = {
+ label: ReactNode;
+ onBack?: () => void;
+ trailing?: ReactNode;
+};
+
+const StyledStepBar = styled.div`
+ align-items: center;
+ display: grid;
+ flex: 1;
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
+ min-width: 0;
+`;
+
+const StyledLeft = styled.div`
+ align-items: center;
+ display: flex;
+ min-width: 0;
+`;
+
+const StyledLabel = styled.div`
+ color: ${themeCssVariables.font.color.primary};
+ font-size: ${themeCssVariables.font.size.md};
+ font-weight: ${themeCssVariables.font.weight.semiBold};
+ justify-self: center;
+ min-width: 0;
+ text-align: center;
+`;
+
+const StyledRight = styled.div`
+ align-items: center;
+ display: flex;
+ gap: ${themeCssVariables.spacing[2]};
+ justify-content: flex-end;
+ min-width: 0;
+`;
+
+export const SettingsWizardStepBar = ({
+ label,
+ onBack,
+ trailing,
+}: SettingsWizardStepBarProps) => (
+
+
+ {onBack && (
+
+ )}
+
+ {label}
+ {trailing}
+
+);
diff --git a/packages/twenty-front/src/modules/settings/components/layout/useSettingsActiveTabId.ts b/packages/twenty-front/src/modules/settings/components/layout/useSettingsActiveTabId.ts
new file mode 100644
index 0000000000000..9649ec71ef4bb
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/components/layout/useSettingsActiveTabId.ts
@@ -0,0 +1,29 @@
+import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
+import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
+import { useLocation } from 'react-router-dom';
+import { isDefined } from 'twenty-shared/utils';
+
+// Resolves the active tab synchronously so the content never renders a null/blank
+// frame before the effects settle: the URL hash if it points to a tab (so deep-links
+// win), else the stored tab if still valid, else the first tab.
+export const useSettingsActiveTabId = (
+ componentInstanceId: string,
+ tabIds: string[],
+): string | null => {
+ const activeTabId = useAtomComponentStateValue(
+ activeTabIdComponentState,
+ componentInstanceId,
+ );
+ const { hash } = useLocation();
+
+ const hashTabId = hash.replace('#', '');
+ if (tabIds.includes(hashTabId)) {
+ return hashTabId;
+ }
+
+ if (isDefined(activeTabId) && tabIds.includes(activeTabId)) {
+ return activeTabId;
+ }
+
+ return tabIds[0] ?? null;
+};
diff --git a/packages/twenty-front/src/modules/settings/developers/components/SettingsDevelopersWebhookForm.tsx b/packages/twenty-front/src/modules/settings/developers/components/SettingsDevelopersWebhookForm.tsx
index d955f1f52a014..de3a460ef5938 100644
--- a/packages/twenty-front/src/modules/settings/developers/components/SettingsDevelopersWebhookForm.tsx
+++ b/packages/twenty-front/src/modules/settings/developers/components/SettingsDevelopersWebhookForm.tsx
@@ -9,7 +9,7 @@ import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
import { TextArea } from '@/ui/input/components/TextArea';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { Trans, useLingui } from '@lingui/react/macro';
import { SettingsPath } from 'twenty-shared/types';
import {
@@ -72,13 +72,12 @@ export const SettingsDevelopersWebhookForm = ({
return (
// oxlint-disable-next-line react/jsx-props-no-spreading
-
)}
-
+
{!isCreationMode && (
{
};
return (
- Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: Apps,
@@ -286,6 +286,6 @@ export const SettingPublicDomain = () => {
/>
-
+
);
};
diff --git a/packages/twenty-front/src/modules/settings/domains/components/SettingsCustomDomain.tsx b/packages/twenty-front/src/modules/settings/domains/components/SettingsCustomDomain.tsx
index 94bcefaffa600..6b4486054dd84 100644
--- a/packages/twenty-front/src/modules/settings/domains/components/SettingsCustomDomain.tsx
+++ b/packages/twenty-front/src/modules/settings/domains/components/SettingsCustomDomain.tsx
@@ -7,7 +7,7 @@ import { SettingsDomainRecords } from '@/settings/domains/components/SettingsDom
import { useSettingsCustomDomain } from '@/settings/domains/hooks/useSettingsCustomDomain';
import { customDomainRecordsState } from '@/settings/domains/states/customDomainRecordsState';
import { TextInput } from '@/ui/input/components/TextInput';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { Trans, useLingui } from '@lingui/react/macro';
import { styled } from '@linaria/react';
@@ -62,22 +62,22 @@ export const SettingsCustomDomain = () => {
} = useSettingsCustomDomain();
return (
- Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: General,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{ children: Custom Domain },
]}
actionButton={
navigate(SettingsPath.Workspace)}
+ onCancel={() => navigate(SettingsPath.General)}
isSaveDisabled={isSaveDisabled}
isLoading={isSubmitting}
onSave={handleSave}
@@ -133,6 +133,6 @@ export const SettingsCustomDomain = () => {
)}
-
+
);
};
diff --git a/packages/twenty-front/src/modules/settings/domains/components/SettingsSubdomain.tsx b/packages/twenty-front/src/modules/settings/domains/components/SettingsSubdomain.tsx
index 722e15071fa24..e0f7fed6bd3eb 100644
--- a/packages/twenty-front/src/modules/settings/domains/components/SettingsSubdomain.tsx
+++ b/packages/twenty-front/src/modules/settings/domains/components/SettingsSubdomain.tsx
@@ -8,7 +8,7 @@ import {
} from '@/settings/domains/hooks/useSettingsSubdomain';
import { TextInput } from '@/ui/input/components/TextInput';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { Trans, useLingui } from '@lingui/react/macro';
import { styled } from '@linaria/react';
@@ -41,22 +41,22 @@ export const SettingsSubdomain = () => {
return (
<>
- Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: General,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{ children: Subdomain },
]}
actionButton={
navigate(SettingsPath.Workspace)}
+ onCancel={() => navigate(SettingsPath.General)}
isSaveDisabled={isSaveDisabled}
isLoading={isSubmitting}
onSave={handleSave}
@@ -86,7 +86,7 @@ export const SettingsSubdomain = () => {
-
+
{
items: [
{
label: t`General`,
- path: SettingsPath.Workspace,
+ path: SettingsPath.General,
Icon: IconSettings,
isHidden: !permissionMap[PermissionFlagType.WORKSPACE],
},
@@ -168,14 +166,12 @@ const useSettingsNavigationItems = (): SettingsNavigationSection[] => {
path: SettingsPath.Applications,
Icon: IconPlug,
isHidden: !permissionMap[PermissionFlagType.APPLICATIONS],
- modifier: 'new',
},
{
label: t`AI`,
path: SettingsPath.AI,
Icon: IconSparkles,
isHidden: !permissionMap[PermissionFlagType.AI],
- modifier: 'new',
},
{
label: t`Email`,
@@ -185,13 +181,6 @@ const useSettingsNavigationItems = (): SettingsNavigationSection[] => {
!isEmailGroupFeatureEnabled ||
!permissionMap[PermissionFlagType.WORKSPACE],
},
- {
- label: t`Security`,
- path: SettingsPath.Security,
- Icon: IconKey,
- isAdvanced: true,
- isHidden: !permissionMap[PermissionFlagType.SECURITY],
- },
],
},
{
@@ -204,9 +193,9 @@ const useSettingsNavigationItems = (): SettingsNavigationSection[] => {
isHidden: !isAdminEnabled,
},
{
- label: t`Updates`,
- path: SettingsPath.Updates,
- Icon: IconRocket,
+ label: t`Community`,
+ path: SettingsPath.Community,
+ Icon: IconUsers,
isHidden: !permissionMap[PermissionFlagType.WORKSPACE],
},
{
diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectForm.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectForm.tsx
index 80c5b603939e2..2d13312594384 100644
--- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectForm.tsx
+++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectForm.tsx
@@ -6,10 +6,11 @@ import { SettingsRolePermissionsObjectLevelObjectFieldPermissionTable } from '@/
import { SettingsRolePermissionsObjectLevelObjectFormObjectLevel } from '@/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectFormObjectLevel';
import { SettingsRolePermissionsObjectLevelRecordLevelSection } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
+import { SettingsWizardStepBar } from '@/settings/components/layout/SettingsWizardStepBar';
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
import { t } from '@lingui/core/macro';
-import { useSearchParams } from 'react-router-dom';
+import { useNavigate, useSearchParams } from 'react-router-dom';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { SettingsPath } from 'twenty-shared/types';
import {
@@ -35,6 +36,7 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({
objectMetadataId,
}: SettingsRolePermissionsObjectLevelObjectFormProps) => {
const [searchParams] = useSearchParams();
+ const navigate = useNavigate();
const fromAgentId = searchParams.get('fromAgent');
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
@@ -74,7 +76,7 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({
? [
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: t`AI`,
@@ -93,7 +95,7 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({
: [
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: t`Members`,
@@ -119,6 +121,13 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({
? getSettingsPath(SettingsPath.AiAgentDetail, { agentId: agent.id })
: getSettingsPath(SettingsPath.RoleDetail, { roleId });
+ const previousStepPath = `${getSettingsPath(SettingsPath.RoleAddObjectLevel, {
+ roleId,
+ })}${fromAgentId ? `?fromAgent=${fromAgentId}` : ''}`;
+
+ const headerTitle =
+ fromAgentId && isDefined(agent) ? agent.label : settingsDraftRole.label;
+
const objectPredicates =
settingsDraftRole.rowLevelPermissionPredicates?.filter(
(predicate) => predicate.objectMetadataId === objectMetadataItem.id,
@@ -138,17 +147,23 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({
const isFinishDisabled = hasInvalidPredicate;
return (
- navigate(previousStepPath)}
+ trailing={
+
+ }
/>
}
>
@@ -167,6 +182,6 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({
hasOrganizationPlan={isRLSBillingEntitlementEnabled}
/>
-
+
);
};
diff --git a/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRole.tsx b/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRole.tsx
index 4996e35b1f53d..98b4cb92f08f4 100644
--- a/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRole.tsx
+++ b/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRole.tsx
@@ -10,8 +10,8 @@ import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDr
import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState';
import { settingsRolesIsLoadingState } from '@/settings/roles/states/settingsRolesIsLoadingState';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
-import { TabList } from '@/ui/layout/tab-list/components/TabList';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
+import { SettingsTabBar } from '@/settings/components/layout/SettingsTabBar';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useLoadCurrentUser } from '@/users/hooks/useLoadCurrentUser';
@@ -134,12 +134,20 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
}
return (
- }
+ secondaryBar={
+
+ }
links={[
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: t`Members`,
@@ -165,13 +173,6 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
}
>
-
{activeTabId === SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.ASSIGNMENT && (
)}
@@ -189,6 +190,6 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
/>
)}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/security/SettingsSecurity.tsx b/packages/twenty-front/src/modules/settings/security/components/SettingsSecuritySettings.tsx
similarity index 56%
rename from packages/twenty-front/src/pages/settings/security/SettingsSecurity.tsx
rename to packages/twenty-front/src/modules/settings/security/components/SettingsSecuritySettings.tsx
index 99b992d60049c..c403f70dcb4e0 100644
--- a/packages/twenty-front/src/pages/settings/security/SettingsSecurity.tsx
+++ b/packages/twenty-front/src/modules/settings/security/components/SettingsSecuritySettings.tsx
@@ -1,5 +1,5 @@
import { styled } from '@linaria/react';
-import { Trans, useLingui } from '@lingui/react/macro';
+import { useLingui } from '@lingui/react/macro';
import { Link } from 'react-router-dom';
import { useDebouncedCallback } from 'use-debounce';
@@ -12,7 +12,6 @@ import { SettingsEnterpriseFeatureGateCard } from '@/settings/components/Setting
import { SettingsOptionCardContentButton } from '@/settings/components/SettingsOptions/SettingsOptionCardContentButton';
import { SettingsOptionCardContentCounter } from '@/settings/components/SettingsOptions/SettingsOptionCardContentCounter';
import { SettingsOptionCardContentToggle } from '@/settings/components/SettingsOptions/SettingsOptionCardContentToggle';
-import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsRoleDefaultRole } from '@/settings/roles/components/SettingsRolesDefaultRole';
import { SettingsRolesQueryEffect } from '@/settings/roles/components/SettingsRolesQueryEffect';
import { useSettingsAllRoles } from '@/settings/roles/hooks/useSettingsAllRoles';
@@ -23,7 +22,6 @@ import { SettingsSecurityEditableProfileFields } from '@/settings/security/compo
import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProvidersState';
import { ToggleImpersonate } from '@/settings/workspace/components/ToggleImpersonate';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { CombinedGraphQLErrors } from '@apollo/client/errors';
@@ -69,7 +67,7 @@ const StyledLinkContainer = styled.div`
}
`;
-export const SettingsSecurity = () => {
+export const SettingsSecuritySettings = () => {
const { t } = useLingui();
const { enqueueErrorSnackBar } = useSnackBar();
@@ -198,80 +196,14 @@ export const SettingsSecurity = () => {
const isEventLogsEnabled = hasEnterpriseAccess && isClickHouseConfigured;
return (
- Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
- },
- { children: Security },
- ]}
- >
-
-
-
-
-
-
-
-
-
-
- {shouldShowBypassSection && (
-
- )}
- {isMultiWorkspaceEnabled && (
-
- )}
+ <>
+
+
+
{
/>
}
/>
- {hasEnterpriseAccess ? (
-
-
-
-
-
-
- }
- />
- {isEventLogsEnabled && (
- <>
-
-
- >
- )}
-
- ) : (
-
+
+
+
+
+
+
+ {shouldShowBypassSection && (
+
+ )}
+ {isMultiWorkspaceEnabled && (
+ )}
+
+
-
-
+ {hasEnterpriseAccess ? (
+
+
+
+
+
+
}
- onChange={handleSyncInternalEmailsChange}
- advancedMode
/>
+ {isEventLogsEnabled && (
+ <>
+
+
+ >
+ )}
-
-
-
-
+ ) : (
+
+ )}
+
+
+
+ >
);
};
diff --git a/packages/twenty-front/src/modules/ui/layout/page/components/SubMenuTopBarContainer.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/SubMenuTopBarContainer.tsx
deleted file mode 100644
index 1a68e76e93641..0000000000000
--- a/packages/twenty-front/src/modules/ui/layout/page/components/SubMenuTopBarContainer.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper';
-import { MainContainerLayoutWithSidePanel } from '@/object-record/components/MainContainerLayoutWithSidePanel';
-import {
- Breadcrumb,
- type BreadcrumbProps,
-} from '@/ui/navigation/bread-crumb/components/Breadcrumb';
-import { isDefined } from 'twenty-shared/utils';
-import { styled } from '@linaria/react';
-import { type JSX, type ReactNode } from 'react';
-import { PageHeader } from './PageHeader';
-import { themeCssVariables } from 'twenty-ui/theme-constants';
-
-type SubMenuTopBarContainerProps = {
- children: JSX.Element | JSX.Element[];
- title?: string | JSX.Element;
- reserveTitleSpace?: boolean;
- actionButton?: ReactNode;
- className?: string;
- links: BreadcrumbProps['links'];
- tag?: JSX.Element;
-};
-
-const SETTINGS_CONTENT_MAX_WIDTH = 760;
-
-const StyledContainer = styled.div`
- display: flex;
- flex-direction: column;
- width: 100%;
-`;
-
-// flex: 1 + min-height: 0 are required for PagePanel's overflow chain — the
-// child must participate in the flex height calc rather than collapse to content.
-const StyledBodyContentWrapper = styled.div`
- display: flex;
- flex: 1;
- flex-direction: column;
- margin: 0 auto;
- max-width: ${SETTINGS_CONTENT_MAX_WIDTH}px;
- min-height: 0;
- width: 100%;
-`;
-
-const StyledTitle = styled.span<{ reserveTitleSpace?: boolean }>`
- color: ${themeCssVariables.font.color.primary};
- display: flex;
- font-size: ${themeCssVariables.font.size.lg};
- font-weight: ${themeCssVariables.font.weight.semiBold};
- gap: ${themeCssVariables.spacing[2]};
- line-height: 1.2;
- margin: ${themeCssVariables.spacing[8]} ${themeCssVariables.spacing[8]}
- ${themeCssVariables.spacing[2]};
- min-height: ${({ reserveTitleSpace }) =>
- reserveTitleSpace ? themeCssVariables.spacing[5] : 'none'};
-`;
-
-export const SubMenuTopBarContainer = ({
- children,
- title,
- tag,
- reserveTitleSpace,
- actionButton,
- className,
- links,
-}: SubMenuTopBarContainerProps) => {
- return (
-
- }>
- {actionButton}
-
-
-
-
- {(isDefined(title) || reserveTitleSpace === true) && (
-
- {title}
- {tag}
-
- )}
- {children}
-
-
-
- );
-};
diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/__stories__/NavigationDrawer.stories.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/__stories__/NavigationDrawer.stories.tsx
index 900072b6b3591..4745e1718bcfa 100644
--- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/__stories__/NavigationDrawer.stories.tsx
+++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/__stories__/NavigationDrawer.stories.tsx
@@ -164,7 +164,7 @@ export const Settings: Story = {
{
- const { t } = useLingui();
-
- const isMultiWorkspaceEnabled = useAtomStateValue(
- isMultiWorkspaceEnabledState,
- );
-
- return (
-
-
-
-
- {isMultiWorkspaceEnabled && (
-
- )}
-
-
-
- );
-};
diff --git a/packages/twenty-front/src/pages/settings/__stories__/SettingsBilling.stories.tsx b/packages/twenty-front/src/pages/settings/__stories__/SettingsBilling.stories.tsx
index dd3a4dc1b5383..a7c595502a373 100644
--- a/packages/twenty-front/src/pages/settings/__stories__/SettingsBilling.stories.tsx
+++ b/packages/twenty-front/src/pages/settings/__stories__/SettingsBilling.stories.tsx
@@ -11,7 +11,7 @@ import { sleep } from '~/utils/sleep';
import { getSettingsPath } from 'twenty-shared/utils';
-import { SettingsBilling } from '~/pages/settings/SettingsBilling';
+import { SettingsBilling } from '~/pages/settings/billing/SettingsBilling';
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
const meta: Meta = {
diff --git a/packages/twenty-front/src/pages/settings/__stories__/SettingsWorkspace.stories.tsx b/packages/twenty-front/src/pages/settings/__stories__/SettingsGeneral.stories.tsx
similarity index 68%
rename from packages/twenty-front/src/pages/settings/__stories__/SettingsWorkspace.stories.tsx
rename to packages/twenty-front/src/pages/settings/__stories__/SettingsGeneral.stories.tsx
index b1d410b13c7c0..26df0fa1febef 100644
--- a/packages/twenty-front/src/pages/settings/__stories__/SettingsWorkspace.stories.tsx
+++ b/packages/twenty-front/src/pages/settings/__stories__/SettingsGeneral.stories.tsx
@@ -6,11 +6,11 @@ import {
} from '~/testing/decorators/PageDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
-import { SettingsWorkspace } from '~/pages/settings/SettingsWorkspace';
+import { SettingsGeneral } from '~/pages/settings/general/SettingsGeneral';
const meta: Meta = {
- title: 'Pages/Settings/SettingsWorkspace',
- component: SettingsWorkspace,
+ title: 'Pages/Settings/SettingsGeneral',
+ component: SettingsGeneral,
decorators: [PageDecorator],
args: { routePath: '/settings/general' },
parameters: {
@@ -20,6 +20,6 @@ const meta: Meta = {
export default meta;
-export type Story = StoryObj;
+export type Story = StoryObj;
export const Default: Story = {};
diff --git a/packages/twenty-front/src/pages/settings/__stories__/SettingsProfile.stories.tsx b/packages/twenty-front/src/pages/settings/__stories__/SettingsProfile.stories.tsx
index 78ddbbedb50cb..6ae66cb2dde4a 100644
--- a/packages/twenty-front/src/pages/settings/__stories__/SettingsProfile.stories.tsx
+++ b/packages/twenty-front/src/pages/settings/__stories__/SettingsProfile.stories.tsx
@@ -6,7 +6,7 @@ import {
} from '~/testing/decorators/PageDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
-import { SettingsProfile } from '~/pages/settings/SettingsProfile';
+import { SettingsProfile } from '~/pages/settings/profile/SettingsProfile';
const meta: Meta = {
title: 'Pages/Settings/SettingsProfile',
diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccounts.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccounts.tsx
index a25028f81e107..9967a18cabf65 100644
--- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccounts.tsx
+++ b/packages/twenty-front/src/pages/settings/accounts/SettingsAccounts.tsx
@@ -1,12 +1,12 @@
-import { SettingsPath } from 'twenty-shared/types';
-import { SettingsSectionSkeletonLoader } from '@/settings/components/SettingsSectionSkeletonLoader';
import { SettingsAccountsBlocklistSection } from '@/settings/accounts/components/SettingsAccountsBlocklistSection';
import { SettingsAccountsConnectedAccountsListCard } from '@/settings/accounts/components/SettingsAccountsConnectedAccountsListCard';
import { SettingsAccountsSettingsSection } from '@/settings/accounts/components/SettingsAccountsSettingsSection';
import { useMyConnectedAccounts } from '@/settings/accounts/hooks/useMyConnectedAccounts';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsSectionSkeletonLoader } from '@/settings/components/SettingsSectionSkeletonLoader';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useLingui } from '@lingui/react/macro';
+import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
import { H2Title } from 'twenty-ui/display';
import { Section } from 'twenty-ui/layout';
@@ -17,7 +17,7 @@ export const SettingsAccounts = () => {
const { accounts: allAccounts, loading } = useMyConnectedAccounts();
return (
- {
>
)}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx
index 3211c3bedf885..8bd254ec27076 100644
--- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx
+++ b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx
@@ -1,34 +1,80 @@
import { SettingsAccountsCalendarChannelsContainer } from '@/settings/accounts/components/SettingsAccountsCalendarChannelsContainer';
+import { SettingsNewAccountSection } from '@/settings/accounts/components/SettingsNewAccountSection';
+import { SETTINGS_ACCOUNT_CALENDAR_CHANNELS_TAB_LIST_COMPONENT_ID } from '@/settings/accounts/constants/SettingsAccountCalendarChannelsTabListComponentId';
+import { useMyCalendarChannels } from '@/settings/accounts/hooks/useMyCalendarChannels';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
-import { Trans, useLingui } from '@lingui/react/macro';
-import { SettingsPath } from 'twenty-shared/types';
+import { SettingsSectionSkeletonLoader } from '@/settings/components/SettingsSectionSkeletonLoader';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
+import { SettingsTabBar } from '@/settings/components/layout/SettingsTabBar';
+import { useLingui } from '@lingui/react/macro';
+import { useMemo } from 'react';
+import { CalendarChannelSyncStage, SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
import { Section } from 'twenty-ui/layout';
export const SettingsAccountsCalendars = () => {
const { t } = useLingui();
+ const { channels: allCalendarChannels, loading } = useMyCalendarChannels();
+
+ const calendarChannels = useMemo(
+ () =>
+ allCalendarChannels.filter(
+ (channel) =>
+ channel.syncStage !== CalendarChannelSyncStage.PENDING_CONFIGURATION,
+ ),
+ [allCalendarChannels],
+ );
+
+ const tabs = calendarChannels.map((calendarChannel) => ({
+ id: calendarChannel.id,
+ title: calendarChannel.handle,
+ }));
+
+ const renderContent = () => {
+ if (loading) {
+ return ;
+ }
+
+ if (calendarChannels.length === 0) {
+ return ;
+ }
+
+ return (
+
+ );
+ };
+
return (
- User,
+ children: t`User`,
href: getSettingsPath(SettingsPath.ProfilePage),
},
{
- children: Accounts,
+ children: t`Accounts`,
href: getSettingsPath(SettingsPath.Accounts),
},
- { children: Calendars },
+ { children: t`Calendars` },
]}
+ secondaryBar={
+ tabs.length > 1 ? (
+
+ ) : undefined
+ }
>
-
-
-
-
+ {renderContent()}
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsConfigurationStepCalendar.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsConfigurationStepCalendar.tsx
index 5cf5c512ec7db..6b957b454838f 100644
--- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsConfigurationStepCalendar.tsx
+++ b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsConfigurationStepCalendar.tsx
@@ -4,7 +4,7 @@ import { type CalendarChannel } from '@/accounts/types/CalendarChannel';
import { type MessageChannel } from '@/accounts/types/MessageChannel';
import { SettingsAccountsCalendarChannelDetails } from '@/settings/accounts/components/SettingsAccountsCalendarChannelDetails';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath, isDefined } from 'twenty-shared/utils';
import { IconDeviceFloppy } from 'twenty-ui/display';
@@ -29,7 +29,7 @@ export const SettingsAccountsConfigurationStepCalendar = ({
const stepTitle = t`${stepNumber}. Calendar`;
return (
-
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsConfigurationStepEmail.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsConfigurationStepEmail.tsx
index e438e489af461..6aa71e4ca0511 100644
--- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsConfigurationStepEmail.tsx
+++ b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsConfigurationStepEmail.tsx
@@ -3,7 +3,7 @@ import { Trans, useLingui } from '@lingui/react/macro';
import { type MessageChannel } from '@/accounts/types/MessageChannel';
import { SettingsAccountsMessageChannelDetails } from '@/settings/accounts/components/SettingsAccountsMessageChannelDetails';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
import { IconChevronRight, IconPlus } from 'twenty-ui/display';
@@ -27,7 +27,7 @@ export const SettingsAccountsConfigurationStepEmail = ({
const { t } = useLingui();
return (
-
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmails.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmails.tsx
index 67cdf0bb41eb1..02754b016bd52 100644
--- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmails.tsx
+++ b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmails.tsx
@@ -1,16 +1,62 @@
import { SettingsAccountsMessageChannelsContainer } from '@/settings/accounts/components/SettingsAccountsMessageChannelsContainer';
+import { SettingsNewAccountSection } from '@/settings/accounts/components/SettingsNewAccountSection';
+import { SETTINGS_ACCOUNT_MESSAGE_CHANNELS_TAB_LIST_COMPONENT_ID } from '@/settings/accounts/constants/SettingsAccountMessageChannelsTabListComponentId';
+import { useMyMessageChannels } from '@/settings/accounts/hooks/useMyMessageChannels';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsSectionSkeletonLoader } from '@/settings/components/SettingsSectionSkeletonLoader';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
+import { SettingsTabBar } from '@/settings/components/layout/SettingsTabBar';
import { useLingui } from '@lingui/react/macro';
-import { SettingsPath } from 'twenty-shared/types';
+import { useMemo } from 'react';
+import {
+ MessageChannelSyncStage,
+ MessageChannelType,
+ SettingsPath,
+} from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
import { Section } from 'twenty-ui/layout';
export const SettingsAccountsEmails = () => {
const { t } = useLingui();
+ const { channels: allMessageChannels, loading } = useMyMessageChannels();
+
+ const messageChannels = useMemo(
+ () =>
+ allMessageChannels.filter(
+ (channel) =>
+ channel.isSyncEnabled &&
+ channel.syncStage !== MessageChannelSyncStage.PENDING_CONFIGURATION &&
+ channel.type !== MessageChannelType.EMAIL_GROUP,
+ ),
+ [allMessageChannels],
+ );
+
+ const tabs = messageChannels.map((messageChannel) => ({
+ id: messageChannel.id,
+ title: messageChannel.handle,
+ }));
+
+ const renderContent = () => {
+ if (loading) {
+ return ;
+ }
+
+ if (messageChannels.length === 0) {
+ return ;
+ }
+
+ return (
+
+ );
+ };
+
return (
- {
},
{ children: t`Emails` },
]}
+ secondaryBar={
+ tabs.length > 1 ? (
+
+ ) : undefined
+ }
>
-
-
-
-
+ {renderContent()}
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsNewAccount.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsNewAccount.tsx
index b76a080e27750..30bbedff85906 100644
--- a/packages/twenty-front/src/pages/settings/accounts/SettingsNewAccount.tsx
+++ b/packages/twenty-front/src/pages/settings/accounts/SettingsNewAccount.tsx
@@ -1,13 +1,13 @@
import { SettingsNewAccountSection } from '@/settings/accounts/components/SettingsNewAccountSection';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { t } from '@lingui/core/macro';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
export const SettingsNewAccount = () => {
return (
- {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdmin.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdmin.tsx
index e17eba5ec6ef6..da303a0a60eb8 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdmin.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdmin.tsx
@@ -1,6 +1,6 @@
import { SettingsAdminContent } from '@/settings/admin-panel/components/SettingsAdminContent';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useLingui } from '@lingui/react/macro';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
@@ -9,7 +9,7 @@ export const SettingsAdmin = () => {
const { t } = useLingui();
return (
- {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminAiProviderDetail.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminAiProviderDetail.tsx
index 3d9a93014e0f6..6b36f157d6c15 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminAiProviderDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminAiProviderDetail.tsx
@@ -40,7 +40,7 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import {
type AdminAiModelConfig,
SetAdminAiModelEnabledDocument,
@@ -303,7 +303,7 @@ export const SettingsAdminAiProviderDetail = () => {
}
return (
- {
confirmButtonText={t`Remove`}
confirmButtonAccent="danger"
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminApplicationRegistrationConfigVariableDetail.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminApplicationRegistrationConfigVariableDetail.tsx
index 8ff039323acd1..3a33e24f5ea4c 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminApplicationRegistrationConfigVariableDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminApplicationRegistrationConfigVariableDetail.tsx
@@ -8,7 +8,7 @@ import {
} from '~/generated-admin/graphql';
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { APPLICATION_REGISTRATION_ADMIN_PATH } from '@/settings/admin-panel/apps/constants/ApplicationRegistrationAdminPath';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { getSettingsPath } from 'twenty-shared/utils';
import { SettingsPath } from 'twenty-shared/types';
import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader';
@@ -73,7 +73,7 @@ export const SettingsAdminApplicationRegistrationConfigVariableDetail = () => {
};
return (
- {
variable={variable}
onUpdateVariable={onUpdateVariable}
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminApplicationRegistrationDetail.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminApplicationRegistrationDetail.tsx
index 001df7de7117e..eb2fb0f01e8e0 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminApplicationRegistrationDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminApplicationRegistrationDetail.tsx
@@ -4,7 +4,7 @@ import { FindOneAdminApplicationRegistrationDocument } from '~/generated-admin/g
import { getSettingsPath, isDefined } from 'twenty-shared/utils';
import { SettingsPath } from 'twenty-shared/types';
import { useLingui } from '@lingui/react/macro';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { APPLICATION_REGISTRATION_ADMIN_PATH } from '@/settings/admin-panel/apps/constants/ApplicationRegistrationAdminPath';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
@@ -102,7 +102,7 @@ export const SettingsAdminApplicationRegistrationDetail = () => {
};
return (
-
{
/>
{renderActiveTabContent()}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminConfigVariableDetails.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminConfigVariableDetails.tsx
index 8af066cf7aaa3..a9d386f7395ee 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminConfigVariableDetails.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminConfigVariableDetails.tsx
@@ -9,7 +9,7 @@ import { ConfigVariableValueInput } from '@/settings/admin-panel/config-variable
import { useConfigVariableActions } from '@/settings/admin-panel/config-variables/hooks/useConfigVariableActions';
import { ConfigVariableEdit } from '@/settings/config-variables/components/ConfigVariableEdit';
import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { SettingsPath, type ConfigVariableValue } from 'twenty-shared/types';
import { getSettingsPath, isDefined } from 'twenty-shared/utils';
@@ -97,7 +97,7 @@ export const SettingsAdminConfigVariableDetails = () => {
};
return (
- {
/>
}
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminIndicatorHealthStatus.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminIndicatorHealthStatus.tsx
index 513aa90bd8419..aefaaaba30357 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminIndicatorHealthStatus.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminIndicatorHealthStatus.tsx
@@ -4,7 +4,7 @@ import { SettingsAdminIndicatorHealthStatusContent } from '@/settings/admin-pane
import { SettingsAdminIndicatorHealthContext } from '@/settings/admin-panel/health-status/contexts/SettingsAdminIndicatorHealthContext';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { styled } from '@linaria/react';
import { useLingui } from '@lingui/react/macro';
import { useParams } from 'react-router-dom';
@@ -47,7 +47,7 @@ export const SettingsAdminIndicatorHealthStatus = () => {
}
return (
- {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminInferredVersion.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminInferredVersion.tsx
index 57e49e7a06f28..a76178e477e33 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminInferredVersion.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminInferredVersion.tsx
@@ -2,7 +2,7 @@ import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApo
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsTableCard } from '@/settings/components/SettingsTableCard';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useMutation, useQuery } from '@apollo/client/react';
import { styled } from '@linaria/react';
import { t } from '@lingui/core/macro';
@@ -63,7 +63,7 @@ export const SettingsAdminInferredVersion = () => {
};
return (
- {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminInstanceStatus.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminInstanceStatus.tsx
index d2ed70884e5ae..530328b950f23 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminInstanceStatus.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminInstanceStatus.tsx
@@ -3,7 +3,7 @@ import { getUpgradeHealthStatusBadge } from '@/settings/admin-panel/utils/getUpg
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsTableCard } from '@/settings/components/SettingsTableCard';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { UserContext } from '@/users/contexts/UserContext';
import { useMutation, useQuery } from '@apollo/client/react';
@@ -94,7 +94,7 @@ export const SettingsAdminInstanceStatus = () => {
};
return (
- {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
index 339044bfff65a..a34ac244f01e8 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
@@ -23,7 +23,7 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { Select } from '@/ui/input/components/Select';
import { TextInput } from '@/ui/input/components/TextInput';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { Checkbox, Toggle } from 'twenty-ui/input';
const StyledComboInputContainer = styled.div`
@@ -278,7 +278,7 @@ export const SettingsAdminNewAiModel = () => {
return (
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminNewAiProvider.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminNewAiProvider.tsx
index abc5c9961577b..fb1203a9cbc89 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminNewAiProvider.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminNewAiProvider.tsx
@@ -25,7 +25,7 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { Select } from '@/ui/input/components/Select';
import { TextInput } from '@/ui/input/components/TextInput';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
type ModelsDevProvider = { id: string; modelCount: number; npm: AiSdkPackage };
@@ -229,7 +229,7 @@ export const SettingsAdminNewAiProvider = () => {
return (
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminQueueDetail.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminQueueDetail.tsx
index 9385c34fd8052..f4a0c05ae5c79 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminQueueDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminQueueDetail.tsx
@@ -1,6 +1,6 @@
import { SettingsAdminQueueJobsTable } from '@/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { plural, t } from '@lingui/core/macro';
import { useState } from 'react';
import { useParams } from 'react-router-dom';
@@ -52,7 +52,7 @@ export const SettingsAdminQueueDetail = () => {
: t`Loading retention configuration...`;
return (
- {
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminUserDetail.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminUserDetail.tsx
index e2e222c259148..0b4837560d5d6 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminUserDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminUserDetail.tsx
@@ -19,7 +19,7 @@ import { useHandleImpersonate } from '@/settings/admin-panel/hooks/useHandleImpe
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader';
import { SettingsTableCard } from '@/settings/components/SettingsTableCard';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { DEFAULT_WORKSPACE_LOGO } from '@/ui/navigation/navigation-drawer/constants/DefaultWorkspaceLogo';
@@ -123,7 +123,7 @@ export const SettingsAdminUserDetail = () => {
}
return (
- {
>
)}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminWorkspaceChatThread.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminWorkspaceChatThread.tsx
index 53e42f652ed99..ba13817a90d1b 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminWorkspaceChatThread.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminWorkspaceChatThread.tsx
@@ -11,7 +11,7 @@ import { SettingsAdminChatThreadMessageList } from '@/settings/admin-panel/compo
import { GET_ADMIN_CHAT_THREAD_MESSAGES } from '@/settings/admin-panel/graphql/queries/getAdminChatThreadMessages';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { H2Title } from 'twenty-ui/display';
import { Section } from 'twenty-ui/layout';
import { type GetAdminChatThreadMessagesQuery } from '~/generated-admin/graphql';
@@ -40,7 +40,7 @@ export const SettingsAdminWorkspaceChatThread = () => {
}
return (
- {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminWorkspaceDetail.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminWorkspaceDetail.tsx
index a2f82505fe5d1..1becb061c3884 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminWorkspaceDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminWorkspaceDetail.tsx
@@ -21,7 +21,7 @@ import { useHandleImpersonate } from '@/settings/admin-panel/hooks/useHandleImpe
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { Table } from '@/ui/layout/table/components/Table';
@@ -201,7 +201,7 @@ export const SettingsAdminWorkspaceDetail = () => {
}
return (
- {
)}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminWorkspacesStatus.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminWorkspacesStatus.tsx
index ff3b7327d71e8..e84719994f4cb 100644
--- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminWorkspacesStatus.tsx
+++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminWorkspacesStatus.tsx
@@ -3,7 +3,7 @@ import { SettingsAdminWorkspacesByHealthAccordion } from '@/settings/admin-panel
import { SettingsAdminWorkspacesStatusSummaryCard } from '@/settings/admin-panel/health-status/components/SettingsAdminWorkspacesStatusSummaryCard';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useMutation, useQuery } from '@apollo/client/react';
import { styled } from '@linaria/react';
import { plural, t } from '@lingui/core/macro';
@@ -70,7 +70,7 @@ export const SettingsAdminWorkspacesStatus = () => {
};
return (
- {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsAI.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsAI.tsx
index e971ece7b5cb1..675997fb4525f 100644
--- a/packages/twenty-front/src/pages/settings/ai/SettingsAI.tsx
+++ b/packages/twenty-front/src/pages/settings/ai/SettingsAI.tsx
@@ -1,9 +1,8 @@
import { SettingsDiscoveryHeroCard } from '@/settings/components/SettingsDiscoveryHeroCard';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
-import { TabList } from '@/ui/layout/tab-list/components/TabList';
-import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
-import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
+import { SettingsTabBar } from '@/settings/components/layout/SettingsTabBar';
+import { useSettingsActiveTabId } from '@/settings/components/layout/useSettingsActiveTabId';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
@@ -35,11 +34,6 @@ const SETTINGS_AI_HERO_INSTANCE_ID_PREFIX = 'settings-ai-hero';
export const SettingsAI = () => {
const { handleCreateTool, isCreatingTool } = useCreateTool();
- const activeTabId = useAtomComponentStateValue(
- activeTabIdComponentState,
- SETTINGS_AI_TABS.COMPONENT_INSTANCE_ID,
- );
-
const tabs = [
{
id: SETTINGS_AI_TABS.TABS_IDS.OVERVIEW,
@@ -68,7 +62,11 @@ export const SettingsAI = () => {
},
];
- const resolvedTabId = activeTabId ?? SETTINGS_AI_TABS.TABS_IDS.OVERVIEW;
+ const resolvedTabId =
+ useSettingsActiveTabId(
+ SETTINGS_AI_TABS.COMPONENT_INSTANCE_ID,
+ tabs.map((tab) => tab.id),
+ ) ?? SETTINGS_AI_TABS.TABS_IDS.OVERVIEW;
const isOverviewTab = resolvedTabId === SETTINGS_AI_TABS.TABS_IDS.OVERVIEW;
const isModelsTab = resolvedTabId === SETTINGS_AI_TABS.TABS_IDS.MODELS;
const isSkillsTab = resolvedTabId === SETTINGS_AI_TABS.TABS_IDS.SKILLS;
@@ -76,8 +74,14 @@ export const SettingsAI = () => {
const isUsageTab = resolvedTabId === SETTINGS_AI_TABS.TABS_IDS.USAGE;
return (
-
+ }
actionButton={
isSkillsTab ? (
@@ -102,7 +106,7 @@ export const SettingsAI = () => {
links={[
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{ children: t`AI` },
]}
@@ -136,16 +140,12 @@ export const SettingsAI = () => {
playButtonAriaLabel={t`Watch AI demo`}
/>
-
{isOverviewTab && }
{isModelsTab && }
{isSkillsTab && }
{isToolsTab && }
{isUsageTab && }
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsAgentForm.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsAgentForm.tsx
index 6dfdd573b8bcd..dae2f6d4d149d 100644
--- a/packages/twenty-front/src/pages/settings/ai/SettingsAgentForm.tsx
+++ b/packages/twenty-front/src/pages/settings/ai/SettingsAgentForm.tsx
@@ -10,7 +10,7 @@ import { useSaveDraftRoleToDB } from '@/settings/roles/role/hooks/useSaveDraftRo
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
@@ -401,7 +401,7 @@ export const SettingsAgentForm = ({ mode }: { mode: 'create' | 'edit' }) => {
return (
<>
- {
links={[
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{ children: t`AI`, href: getSettingsPath(SettingsPath.AI) },
{ children: breadcrumbText },
@@ -470,7 +470,7 @@ export const SettingsAgentForm = ({ mode }: { mode: 'create' | 'edit' }) => {
)}
-
+
>
);
};
diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsAgentTurnDetail.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsAgentTurnDetail.tsx
index ad4429d27c8ab..90264f2f2e47f 100644
--- a/packages/twenty-front/src/pages/settings/ai/SettingsAgentTurnDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/ai/SettingsAgentTurnDetail.tsx
@@ -1,7 +1,7 @@
import { AiChatAssistantMessageRenderer } from '@/ai/components/AiChatAssistantMessageRenderer';
import { mapDBMessagesToUIMessages } from '@/ai/utils/mapDBMessagesToUIMessages';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { Table } from '@/ui/layout/table/components/Table';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
@@ -74,12 +74,12 @@ export const SettingsAgentTurnDetail = () => {
if (loading) {
return (
- {
-
+
);
}
if (!turn) {
return (
- {
{t`Turn not found`}
-
+
);
}
return (
- {
)}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsAiPrompts.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsAiPrompts.tsx
index fda214ee600be..d7c6487358a49 100644
--- a/packages/twenty-front/src/pages/settings/ai/SettingsAiPrompts.tsx
+++ b/packages/twenty-front/src/pages/settings/ai/SettingsAiPrompts.tsx
@@ -3,7 +3,7 @@ import { styled } from '@linaria/react';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { FormAdvancedTextFieldInput } from '@/object-record/record-field/ui/form-types/components/FormAdvancedTextFieldInput';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { useQuery } from '@apollo/client/react';
import { t } from '@lingui/core/macro';
@@ -71,11 +71,11 @@ export const SettingsAiPrompts = () => {
: '';
return (
- {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsAiUsageUserDetail.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsAiUsageUserDetail.tsx
index d642d30078fe1..9c7e1aa734acc 100644
--- a/packages/twenty-front/src/pages/settings/ai/SettingsAiUsageUserDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/ai/SettingsAiUsageUserDetail.tsx
@@ -6,7 +6,7 @@ import { UsageDailyChartSection } from '@/settings/usage/components/UsageDailyCh
import { UsageSectionSkeleton } from '@/settings/usage/components/UsageSectionSkeleton';
import { AI_OPERATION_TYPES } from '@/settings/usage/constants/AiOperationTypes';
import { useUsageAnalyticsData } from '@/settings/usage/hooks/useUsageAnalyticsData';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { t } from '@lingui/core/macro';
import { Trans, useLingui } from '@lingui/react/macro';
import { useParams } from 'react-router-dom';
@@ -38,7 +38,7 @@ export const SettingsAiUsageUserDetail = () => {
const breadcrumbLinks = [
{
children: Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: AI,
@@ -49,7 +49,7 @@ export const SettingsAiUsageUserDetail = () => {
if (isInitialLoading) {
return (
-
@@ -57,12 +57,12 @@ export const SettingsAiUsageUserDetail = () => {
-
+
);
}
return (
-
+
{!hasAnyData && (
@@ -102,6 +102,6 @@ export const SettingsAiUsageUserDetail = () => {
sectionId="ai-user-model"
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsSkillForm.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsSkillForm.tsx
index c3b6e72af76fe..b869b22900b0f 100644
--- a/packages/twenty-front/src/pages/settings/ai/SettingsSkillForm.tsx
+++ b/packages/twenty-front/src/pages/settings/ai/SettingsSkillForm.tsx
@@ -13,7 +13,7 @@ import { IconPicker } from '@/ui/input/components/IconPicker';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
import { TextArea } from '@/ui/input/components/TextArea';
import { TitleInput } from '@/ui/input/components/TitleInput';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { t } from '@lingui/core/macro';
import { AppPath, SettingsPath } from 'twenty-shared/types';
import { getSettingsPath, isDefined } from 'twenty-shared/utils';
@@ -422,7 +422,7 @@ export const SettingsSkillForm = ({ mode }: { mode: 'create' | 'edit' }) => {
);
return (
- {
links={[
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{ children: t`AI`, href: getSettingsPath(SettingsPath.AI) },
{ children: breadcrumbText },
@@ -602,6 +602,6 @@ export const SettingsSkillForm = ({ mode }: { mode: 'create' | 'edit' }) => {
confirmButtonText={t`Delete`}
loading={isSubmitting}
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsToolDetail.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsToolDetail.tsx
index bffbf5c3e43f6..657dae36fc7b0 100644
--- a/packages/twenty-front/src/pages/settings/ai/SettingsToolDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/ai/SettingsToolDetail.tsx
@@ -14,7 +14,7 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { TextArea } from '@/ui/input/components/TextArea';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath, isDefined, isValidUuid } from 'twenty-shared/utils';
@@ -169,7 +169,7 @@ export const SettingsToolDetail = () => {
};
return (
- {
links={[
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: t`AI`,
@@ -263,6 +263,6 @@ export const SettingsToolDetail = () => {
confirmButtonText={t`Delete`}
loading={isDeleting}
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/workspace/SettingsApiWebhooks.tsx b/packages/twenty-front/src/pages/settings/api-webhooks/SettingsApiWebhooks.tsx
similarity index 87%
rename from packages/twenty-front/src/pages/settings/workspace/SettingsApiWebhooks.tsx
rename to packages/twenty-front/src/pages/settings/api-webhooks/SettingsApiWebhooks.tsx
index 1fd587ff80ef3..a79c578625404 100644
--- a/packages/twenty-front/src/pages/settings/workspace/SettingsApiWebhooks.tsx
+++ b/packages/twenty-front/src/pages/settings/api-webhooks/SettingsApiWebhooks.tsx
@@ -4,13 +4,12 @@ import { SettingsApiKeysTable } from '@/settings/developers/components/SettingsA
import { SettingsWebhooksTable } from '@/settings/developers/components/SettingsWebhooksTable';
import { PlaygroundSetupForm } from '@/settings/playground/components/PlaygroundSetupForm';
import { SettingsMcpSetup } from '@/settings/playground/components/SettingsMcpSetup';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import PlaygroundCoverDark from '@/settings/playground/assets/cover-dark.png';
import PlaygroundCoverLight from '@/settings/playground/assets/cover-light.png';
-import { TabList } from '@/ui/layout/tab-list/components/TabList';
-import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
+import { SettingsTabBar } from '@/settings/components/layout/SettingsTabBar';
+import { useSettingsActiveTabId } from '@/settings/components/layout/useSettingsActiveTabId';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
-import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { styled } from '@linaria/react';
import { useLingui } from '@lingui/react/macro';
import { SettingsPath } from 'twenty-shared/types';
@@ -26,7 +25,7 @@ import {
import { Button } from 'twenty-ui/input';
import { Section } from 'twenty-ui/layout';
import { MOBILE_VIEWPORT, themeCssVariables } from 'twenty-ui/theme-constants';
-import { SETTINGS_API_WEBHOOKS_TABS } from '~/pages/settings/workspace/constants/SettingsApiWebhooksTabs';
+import { SETTINGS_API_WEBHOOKS_TABS } from '~/pages/settings/api-webhooks/constants/SettingsApiWebhooksTabs';
type TabKey =
(typeof SETTINGS_API_WEBHOOKS_TABS.TABS_IDS)[keyof typeof SETTINGS_API_WEBHOOKS_TABS.TABS_IDS];
@@ -60,13 +59,6 @@ export const SettingsApiWebhooks = () => {
const isMobile = useIsMobile();
const { t } = useLingui();
- const activeTabId = useAtomComponentStateValue(
- activeTabIdComponentState,
- SETTINGS_API_WEBHOOKS_TABS.COMPONENT_INSTANCE_ID,
- );
- const activeTab: TabKey =
- (activeTabId as TabKey) ?? SETTINGS_API_WEBHOOKS_TABS.TABS_IDS.API;
-
const tabs = [
{
id: SETTINGS_API_WEBHOOKS_TABS.TABS_IDS.API,
@@ -85,13 +77,25 @@ export const SettingsApiWebhooks = () => {
},
];
+ const activeTab: TabKey =
+ (useSettingsActiveTabId(
+ SETTINGS_API_WEBHOOKS_TABS.COMPONENT_INSTANCE_ID,
+ tabs.map((tab) => tab.id),
+ ) as TabKey) ?? SETTINGS_API_WEBHOOKS_TABS.TABS_IDS.API;
+
return (
-
+ }
links={[
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{ children: t`APIs & Webhooks` },
]}
@@ -120,11 +124,6 @@ export const SettingsApiWebhooks = () => {
/>
-
-
{activeTab === SETTINGS_API_WEBHOOKS_TABS.TABS_IDS.API && (
@@ -185,6 +184,6 @@ export const SettingsApiWebhooks = () => {
)}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/workspace/constants/SettingsApiWebhooksTabs.ts b/packages/twenty-front/src/pages/settings/api-webhooks/constants/SettingsApiWebhooksTabs.ts
similarity index 100%
rename from packages/twenty-front/src/pages/settings/workspace/constants/SettingsApiWebhooksTabs.ts
rename to packages/twenty-front/src/pages/settings/api-webhooks/constants/SettingsApiWebhooksTabs.ts
diff --git a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationCommandMenuItemDetail.tsx b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationCommandMenuItemDetail.tsx
index 76deaf83c0311..bacf7ca4dc186 100644
--- a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationCommandMenuItemDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationCommandMenuItemDetail.tsx
@@ -1,6 +1,6 @@
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsSectionSkeletonLoader } from '@/settings/components/SettingsSectionSkeletonLoader';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useQuery } from '@apollo/client/react';
import { t } from '@lingui/core/macro';
import { useParams } from 'react-router-dom';
@@ -40,7 +40,7 @@ export const SettingsApplicationCommandMenuItemDetail = () => {
const breadcrumbLinks = [
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: t`Applications`,
@@ -52,7 +52,7 @@ export const SettingsApplicationCommandMenuItemDetail = () => {
];
return (
-
@@ -76,6 +76,6 @@ export const SettingsApplicationCommandMenuItemDetail = () => {
/>
)}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationConnectionDetail.tsx b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationConnectionDetail.tsx
index 04b7a9b14d2b9..fa0ca66a6516c 100644
--- a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationConnectionDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationConnectionDetail.tsx
@@ -23,7 +23,7 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain
import { SettingsSectionSkeletonLoader } from '@/settings/components/SettingsSectionSkeletonLoader';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { Table } from '@/ui/layout/table/components/Table';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
@@ -283,12 +283,12 @@ export const SettingsApplicationConnectionDetail = () => {
: [];
return (
- {
>
)}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationDetails.tsx b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationDetails.tsx
index 8d4ce446ee5c5..770df562cb2d8 100644
--- a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationDetails.tsx
+++ b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationDetails.tsx
@@ -8,7 +8,7 @@ import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMeta
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import type { SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps';
@@ -325,7 +325,7 @@ export const SettingsApplicationDetails = () => {
return (
- {
links={[
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: t`Applications`,
@@ -349,7 +349,7 @@ export const SettingsApplicationDetails = () => {
{renderActiveTabContent()}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationFrontComponentDetail.tsx b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationFrontComponentDetail.tsx
index dcee044fdea37..c64e49a9fc060 100644
--- a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationFrontComponentDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationFrontComponentDetail.tsx
@@ -1,6 +1,6 @@
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsSectionSkeletonLoader } from '@/settings/components/SettingsSectionSkeletonLoader';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
@@ -52,7 +52,7 @@ export const SettingsApplicationFrontComponentDetail = () => {
const breadcrumbLinks = [
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: t`Applications`,
@@ -97,7 +97,7 @@ export const SettingsApplicationFrontComponentDetail = () => {
};
return (
-
@@ -105,6 +105,6 @@ export const SettingsApplicationFrontComponentDetail = () => {
{loading ? : renderActiveTabContent()}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationRegistrationDetails.tsx b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationRegistrationDetails.tsx
index 5dfa07d69057e..22904aff3ae0b 100644
--- a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationRegistrationDetails.tsx
+++ b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationRegistrationDetails.tsx
@@ -1,4 +1,4 @@
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useQuery } from '@apollo/client/react';
import { useParams } from 'react-router-dom';
import { SettingsPath } from 'twenty-shared/types';
@@ -94,7 +94,7 @@ export const SettingsApplicationRegistrationDetails = () => {
};
return (
-
{
links={[
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: t`Applications - Developer`,
@@ -132,6 +132,6 @@ export const SettingsApplicationRegistrationDetails = () => {
/>
{renderActiveTabContent()}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/applications/SettingsApplications.tsx b/packages/twenty-front/src/pages/settings/applications/SettingsApplications.tsx
index d788ae11c233a..8eb4b2067f3fc 100644
--- a/packages/twenty-front/src/pages/settings/applications/SettingsApplications.tsx
+++ b/packages/twenty-front/src/pages/settings/applications/SettingsApplications.tsx
@@ -1,10 +1,9 @@
import { SettingsDiscoveryHeroCard } from '@/settings/components/SettingsDiscoveryHeroCard';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
-import { TabList } from '@/ui/layout/tab-list/components/TabList';
-import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
-import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
+import { SettingsTabBar } from '@/settings/components/layout/SettingsTabBar';
+import { useSettingsActiveTabId } from '@/settings/components/layout/useSettingsActiveTabId';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useLingui } from '@lingui/react/macro';
import { SettingsPath } from 'twenty-shared/types';
@@ -35,11 +34,6 @@ export const SettingsApplications = () => {
FeatureFlagKey.IS_MARKETPLACE_SETTING_TAB_VISIBLE,
);
- const activeTabId = useAtomComponentStateValue(
- activeTabIdComponentState,
- APPLICATIONS_TAB_LIST_ID,
- );
-
const tabs = [
...(isMarketplaceSettingTabVisible
? [{ id: 'marketplace', title: t`Marketplace`, Icon: IconDownload }]
@@ -50,6 +44,11 @@ export const SettingsApplications = () => {
: []),
];
+ const activeTabId = useSettingsActiveTabId(
+ APPLICATIONS_TAB_LIST_ID,
+ tabs.map((tab) => tab.id),
+ );
+
const renderActiveTabContent = () => {
switch (activeTabId) {
case 'marketplace':
@@ -68,12 +67,18 @@ export const SettingsApplications = () => {
};
return (
-
+ }
links={[
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{ children: t`Applications` },
]}
@@ -107,9 +112,8 @@ export const SettingsApplications = () => {
playButtonAriaLabel={t`Watch apps demo`}
/>
-
{renderActiveTabContent()}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/applications/SettingsAvailableApplicationDetails.tsx b/packages/twenty-front/src/pages/settings/applications/SettingsAvailableApplicationDetails.tsx
index c1816f1941b04..43c284d1f54c5 100644
--- a/packages/twenty-front/src/pages/settings/applications/SettingsAvailableApplicationDetails.tsx
+++ b/packages/twenty-front/src/pages/settings/applications/SettingsAvailableApplicationDetails.tsx
@@ -4,7 +4,7 @@ import { useInstallMarketplaceAppWithPermissionValidation } from '@/marketplace/
import { useUpgradeApplication } from '@/marketplace/hooks/useUpgradeApplication';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
@@ -271,11 +271,11 @@ export const SettingsAvailableApplicationDetails = () => {
return (
- {
/>
{renderActiveTabContent()}
-
+
({
),
}));
-jest.mock('@/ui/layout/page/components/SubMenuTopBarContainer', () => ({
- SubMenuTopBarContainer: ({ children }: { children: ReactNode }) => (
+jest.mock('@/settings/components/layout/SettingsPageLayout', () => ({
+ SettingsPageLayout: ({ children }: { children: ReactNode }) => (
<>{children}>
),
}));
diff --git a/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationRegistrationConfigVariableDetail.tsx b/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationRegistrationConfigVariableDetail.tsx
index 72184c8ece51c..088c62fbd608c 100644
--- a/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationRegistrationConfigVariableDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationRegistrationConfigVariableDetail.tsx
@@ -6,7 +6,7 @@ import {
UpdateApplicationRegistrationVariableDocument,
} from '~/generated-metadata/graphql';
import { useMutation, useQuery } from '@apollo/client/react';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { getSettingsPath } from 'twenty-shared/utils';
import { SettingsPath } from 'twenty-shared/types';
import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader';
@@ -67,11 +67,11 @@ export const SettingsApplicationRegistrationConfigVariableDetail = () => {
};
return (
- {
variable={variable}
onUpdateVariable={onUpdateVariable}
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/SettingsBilling.tsx b/packages/twenty-front/src/pages/settings/billing/SettingsBilling.tsx
similarity index 81%
rename from packages/twenty-front/src/pages/settings/SettingsBilling.tsx
rename to packages/twenty-front/src/pages/settings/billing/SettingsBilling.tsx
index 3a566f18a8ee2..32e1cf538dfda 100644
--- a/packages/twenty-front/src/pages/settings/SettingsBilling.tsx
+++ b/packages/twenty-front/src/pages/settings/billing/SettingsBilling.tsx
@@ -1,7 +1,7 @@
import { Trans, useLingui } from '@lingui/react/macro';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { SettingsBillingContent } from '@/settings/billing/components/SettingsBillingContent';
import { getSettingsPath } from 'twenty-shared/utils';
import { SettingsPath } from 'twenty-shared/types';
@@ -15,17 +15,17 @@ export const SettingsBilling = () => {
const { isPlansLoaded } = usePlans();
return (
- Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{ children: Billing },
]}
>
{currentWorkspace && isPlansLoaded ? : <>>}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/SettingsUsage.tsx b/packages/twenty-front/src/pages/settings/billing/SettingsUsage.tsx
similarity index 79%
rename from packages/twenty-front/src/pages/settings/SettingsUsage.tsx
rename to packages/twenty-front/src/pages/settings/billing/SettingsUsage.tsx
index ff861926a3faf..7d4a400513af8 100644
--- a/packages/twenty-front/src/pages/settings/SettingsUsage.tsx
+++ b/packages/twenty-front/src/pages/settings/billing/SettingsUsage.tsx
@@ -1,7 +1,7 @@
import { Trans, useLingui } from '@lingui/react/macro';
import { SettingsUsageAnalyticsSection } from '@/settings/usage/components/SettingsUsageAnalyticsSection';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { getSettingsPath } from 'twenty-shared/utils';
import { SettingsPath } from 'twenty-shared/types';
@@ -9,12 +9,12 @@ export const SettingsUsage = () => {
const { t } = useLingui();
return (
- Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: Billing,
@@ -26,6 +26,6 @@ export const SettingsUsage = () => {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/SettingsUsageUserDetail.tsx b/packages/twenty-front/src/pages/settings/billing/SettingsUsageUserDetail.tsx
similarity index 92%
rename from packages/twenty-front/src/pages/settings/SettingsUsageUserDetail.tsx
rename to packages/twenty-front/src/pages/settings/billing/SettingsUsageUserDetail.tsx
index e8f984b6b9761..b3fc1bba69e07 100644
--- a/packages/twenty-front/src/pages/settings/SettingsUsageUserDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/billing/SettingsUsageUserDetail.tsx
@@ -6,7 +6,7 @@ import { UsageDailyChartSection } from '@/settings/usage/components/UsageDailyCh
import { UsageSectionSkeleton } from '@/settings/usage/components/UsageSectionSkeleton';
import { useUsageAnalyticsData } from '@/settings/usage/hooks/useUsageAnalyticsData';
import { useUsageValueFormatter } from '@/settings/usage/hooks/useUsageValueFormatter';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { styled } from '@linaria/react';
import { t } from '@lingui/core/macro';
import { Trans, useLingui } from '@lingui/react/macro';
@@ -74,7 +74,7 @@ export const SettingsUsageUserDetail = () => {
const breadcrumbLinks = [
{
children: Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: Billing,
@@ -89,10 +89,7 @@ export const SettingsUsageUserDetail = () => {
if (isInitialLoading) {
return (
-
+
{
-
+
);
}
return (
-
+
{
sectionId="user-type"
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/community/SettingsCommunity.tsx b/packages/twenty-front/src/pages/settings/community/SettingsCommunity.tsx
new file mode 100644
index 0000000000000..725c3ed1f1ff6
--- /dev/null
+++ b/packages/twenty-front/src/pages/settings/community/SettingsCommunity.tsx
@@ -0,0 +1,94 @@
+import { SettingsCard } from '@/settings/components/SettingsCard';
+import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
+import { SettingsLabContent } from '@/settings/lab/components/SettingsLabContent';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
+import { styled } from '@linaria/react';
+import { t } from '@lingui/core/macro';
+import { useContext } from 'react';
+import {
+ H2Title,
+ IconBriefcase,
+ type IconComponent,
+ IconMessage,
+ IconTransform,
+} from 'twenty-ui/display';
+import { Section } from 'twenty-ui/layout';
+import { ThemeContext } from 'twenty-ui/theme-constants';
+
+const StyledCardLink = styled.a`
+ text-decoration: none;
+`;
+
+type SettingsCommunityLink = {
+ title: string;
+ description: string;
+ href: string;
+ Icon: IconComponent;
+ cardTitle: string;
+};
+
+export const SettingsCommunity = () => {
+ const { theme } = useContext(ThemeContext);
+
+ const communityLinks: SettingsCommunityLink[] = [
+ {
+ title: t`Partners`,
+ description: t`Hire a partner to help you implement and customize Twenty.`,
+ href: 'https://twenty.com/partners/list',
+ Icon: IconBriefcase,
+ cardTitle: t`Browse partners`,
+ },
+ {
+ title: t`Discord`,
+ description: t`Join our community to get help and share feedback.`,
+ href: 'https://discord.com/invite/cx5n4Jzs57',
+ Icon: IconMessage,
+ cardTitle: t`Join our Discord`,
+ },
+ {
+ title: t`Releases`,
+ description: t`Check out our latest releases`,
+ href: 'https://twenty.com/releases',
+ Icon: IconTransform,
+ cardTitle: t`Read changelog`,
+ },
+ ];
+
+ return (
+
+
+ {communityLinks.map(({ title, description, href, Icon, cardTitle }) => (
+
+
+
+
+ }
+ title={cardTitle}
+ />
+
+
+ ))}
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsNewObject.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsNewObject.tsx
index 49c61f2961672..2d26f5f6d730b 100644
--- a/packages/twenty-front/src/pages/settings/data-model/SettingsNewObject.tsx
+++ b/packages/twenty-front/src/pages/settings/data-model/SettingsNewObject.tsx
@@ -10,7 +10,7 @@ import {
settingsDataModelObjectAboutFormSchema,
} from '@/settings/data-model/validation-schemas/settingsDataModelObjectAboutFormSchema';
import { isDDLLockedState } from '@/client-config/states/isDDLLockedState';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { zodResolver } from '@hookform/resolvers/zod';
import { useLingui } from '@lingui/react/macro';
@@ -77,12 +77,12 @@ export const SettingsNewObject = () => {
return (
// oxlint-disable-next-line react/jsx-props-no-spreading
- {
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx
index 11aec7d2a8293..f2c9f18b78399 100644
--- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx
+++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx
@@ -6,8 +6,8 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain
import { ObjectFields } from '@/settings/data-model/object-details/components/tabs/ObjectFields';
import { ObjectLayout } from '@/settings/data-model/object-details/components/tabs/ObjectLayout';
import { ObjectSettings } from '@/settings/data-model/object-details/components/tabs/ObjectSettings';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
-import { TabList } from '@/ui/layout/tab-list/components/TabList';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
+import { SettingsTabBar } from '@/settings/components/layout/SettingsTabBar';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { styled } from '@linaria/react';
@@ -64,10 +64,11 @@ export const SettingsObjectDetailPage = () => {
objectMetadataItem,
}) || isDDLLocked;
- const activeTabId = useAtomComponentStateValue(
- activeTabIdComponentState,
- SETTINGS_OBJECT_DETAIL_TABS.COMPONENT_INSTANCE_ID,
- );
+ const activeTabId =
+ useAtomComponentStateValue(
+ activeTabIdComponentState,
+ SETTINGS_OBJECT_DETAIL_TABS.COMPONENT_INSTANCE_ID,
+ ) ?? SETTINGS_OBJECT_DETAIL_TABS.TABS_IDS.FIELDS;
const [isDeleting, setIsDeleting] = useState(false);
@@ -132,60 +133,60 @@ export const SettingsObjectDetailPage = () => {
};
return (
- <>
-
-
-
- )
- }
- >
-
-
- }
+
+
-
- {renderActiveTabContent()}
-
-
-
- >
+ {!readonly &&
+ activeTabId === SETTINGS_OBJECT_DETAIL_TABS.TABS_IDS.FIELDS && (
+
+
+
+ )}
+ >
+ }
+ secondaryBar={
+
+ }
+ >
+
+
+ {renderActiveTabContent()}
+
+
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx
index 023d3d82931dd..e3a365ea2b647 100644
--- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx
+++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx
@@ -25,7 +25,7 @@ import { type SettingsFieldType } from '@/settings/data-model/types/SettingsFiel
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
import { shouldNavigateBackToMemorizedUrlOnSaveState } from '@/ui/navigation/states/shouldNavigateBackToMemorizedUrlOnSaveState';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
@@ -311,12 +311,12 @@ export const SettingsObjectFieldEdit = () => {
<>
{/* oxlint-disable-next-line react/jsx-props-no-spreading */}
- {
)}
-
+
{fieldMetadataItem?.isCustom && (
{
return (
- {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjects.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjects.tsx
index 4ad4d27b39b2a..ae270e3a693f7 100644
--- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjects.tsx
+++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjects.tsx
@@ -3,7 +3,7 @@ import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilte
import { SettingsDiscoveryHeroCard } from '@/settings/components/SettingsDiscoveryHeroCard';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useLingui } from '@lingui/react/macro';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
@@ -52,7 +52,7 @@ export const SettingsObjects = () => {
];
return (
- {
links={[
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{ children: t`Objects` },
]}
@@ -114,6 +114,6 @@ export const SettingsObjects = () => {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/data-model/new-field/SettingsObjectNewFieldConfigure.tsx b/packages/twenty-front/src/pages/settings/data-model/new-field/SettingsObjectNewFieldConfigure.tsx
index a13ce2b76d7ce..ee118d624036c 100644
--- a/packages/twenty-front/src/pages/settings/data-model/new-field/SettingsObjectNewFieldConfigure.tsx
+++ b/packages/twenty-front/src/pages/settings/data-model/new-field/SettingsObjectNewFieldConfigure.tsx
@@ -9,7 +9,7 @@ import { SettingsDataModelFieldIconLabelForm } from '@/settings/data-model/field
import { SettingsDataModelFieldSettingsFormCard } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard';
import { settingsFieldFormSchema } from '@/settings/data-model/fields/forms/validation-schemas/settingsFieldFormSchema';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { zodResolver } from '@hookform/resolvers/zod';
import { useLingui } from '@lingui/react/macro';
@@ -180,12 +180,12 @@ export const SettingsObjectNewFieldConfigure = () => {
- {
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/data-model/new-field/SettingsObjectNewFieldSelect.tsx b/packages/twenty-front/src/pages/settings/data-model/new-field/SettingsObjectNewFieldSelect.tsx
index be6a3df2a80c4..67eaa59e77fe9 100644
--- a/packages/twenty-front/src/pages/settings/data-model/new-field/SettingsObjectNewFieldSelect.tsx
+++ b/packages/twenty-front/src/pages/settings/data-model/new-field/SettingsObjectNewFieldSelect.tsx
@@ -5,7 +5,7 @@ import { SETTINGS_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/Set
import { SettingsObjectNewFieldSelector } from '@/settings/data-model/fields/forms/components/SettingsObjectNewFieldSelector';
import { type FieldType } from '@/settings/data-model/types/FieldType';
import { type SettingsFieldType } from '@/settings/data-model/types/SettingsFieldType';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { zodResolver } from '@hookform/resolvers/zod';
import { t } from '@lingui/core/macro';
import { useEffect } from 'react';
@@ -64,12 +64,12 @@ export const SettingsObjectNewFieldSelect = () => {
- {
excludedFieldTypes={excludedFieldTypes}
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/data-model/new-index/SettingsObjectNewIndex.tsx b/packages/twenty-front/src/pages/settings/data-model/new-index/SettingsObjectNewIndex.tsx
index 311861991d01b..06d57ef1d6b4a 100644
--- a/packages/twenty-front/src/pages/settings/data-model/new-index/SettingsObjectNewIndex.tsx
+++ b/packages/twenty-front/src/pages/settings/data-model/new-index/SettingsObjectNewIndex.tsx
@@ -8,7 +8,7 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain
import { SettingsObjectIndexFieldsForm } from '@/settings/data-model/indexes/forms/components/SettingsObjectIndexFieldsForm';
import { SettingsObjectIndexOptionsForm } from '@/settings/data-model/indexes/forms/components/SettingsObjectIndexOptionsForm';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { zodResolver } from '@hookform/resolvers/zod';
import { useLingui } from '@lingui/react/macro';
@@ -114,12 +114,12 @@ export const SettingsObjectNewIndex = () => {
- {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
index a187069907a9e..e776b4580e4b5 100644
--- a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
@@ -17,7 +17,7 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { Trans, useLingui } from '@lingui/react/macro';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath, isDefined } from 'twenty-shared/utils';
@@ -240,12 +240,12 @@ export const SettingsDevelopersApiKeyDetail = () => {
return (
<>
{isDefined(apiKey) && (
- {
/>
-
+
)}
{
}
return (
- {
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/developers/playground/SettingsGraphQLPlayground.tsx b/packages/twenty-front/src/pages/settings/developers/playground/SettingsGraphQLPlayground.tsx
index fbf75bb9dcb1c..d8e05d060c465 100644
--- a/packages/twenty-front/src/pages/settings/developers/playground/SettingsGraphQLPlayground.tsx
+++ b/packages/twenty-front/src/pages/settings/developers/playground/SettingsGraphQLPlayground.tsx
@@ -32,7 +32,7 @@ export const SettingsGraphQLPlayground = () => {
links={[
{
children: Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: APIs & Webhooks,
diff --git a/packages/twenty-front/src/pages/settings/developers/playground/SettingsRestPlayground.tsx b/packages/twenty-front/src/pages/settings/developers/playground/SettingsRestPlayground.tsx
index 6d8a9e602f6a6..f52c7695b0c24 100644
--- a/packages/twenty-front/src/pages/settings/developers/playground/SettingsRestPlayground.tsx
+++ b/packages/twenty-front/src/pages/settings/developers/playground/SettingsRestPlayground.tsx
@@ -28,7 +28,7 @@ export const SettingsRestPlayground = () => {
links={[
{
children: Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: APIs & Webhooks,
diff --git a/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsWebhooks.tsx b/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsWebhooks.tsx
index 7b54e84d400f8..3e2ae0b0babd2 100644
--- a/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsWebhooks.tsx
+++ b/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsWebhooks.tsx
@@ -1,6 +1,6 @@
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsWebhooksTable } from '@/settings/developers/components/SettingsWebhooksTable';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { styled } from '@linaria/react';
import { Trans, useLingui } from '@lingui/react/macro';
@@ -32,12 +32,12 @@ export const SettingsWebhooks = () => {
const { t } = useLingui();
return (
- Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{ children: Webhooks },
]}
@@ -62,6 +62,6 @@ export const SettingsWebhooks = () => {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/SettingsWorkspaceEmail.tsx b/packages/twenty-front/src/pages/settings/email/SettingsWorkspaceEmail.tsx
similarity index 87%
rename from packages/twenty-front/src/pages/settings/SettingsWorkspaceEmail.tsx
rename to packages/twenty-front/src/pages/settings/email/SettingsWorkspaceEmail.tsx
index d2b5d9bccc63e..37487080e27f2 100644
--- a/packages/twenty-front/src/pages/settings/SettingsWorkspaceEmail.tsx
+++ b/packages/twenty-front/src/pages/settings/email/SettingsWorkspaceEmail.tsx
@@ -4,7 +4,7 @@ import { isEmailGroupEnabledState } from '@/client-config/states/isEmailGroupEna
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsWorkspaceEmailGroupSection } from '@/settings/workspace/components/SettingsWorkspaceEmailGroupSection';
import { SettingsWorkspaceEmailingDomainsSection } from '@/settings/workspace/components/SettingsWorkspaceEmailingDomainsSection';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { FeatureFlagKey, SettingsPath } from 'twenty-shared/types';
@@ -25,12 +25,12 @@ export const SettingsWorkspaceEmail = () => {
const showEmailGroupSection = isEmailGroupEnabled;
return (
- {
{showEmailGroupSection && }
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/workspace/SettingsWorkspaceEmailGroupChannelDetail.tsx b/packages/twenty-front/src/pages/settings/email/SettingsWorkspaceEmailGroupChannelDetail.tsx
similarity index 96%
rename from packages/twenty-front/src/pages/settings/workspace/SettingsWorkspaceEmailGroupChannelDetail.tsx
rename to packages/twenty-front/src/pages/settings/email/SettingsWorkspaceEmailGroupChannelDetail.tsx
index 2e261fa94e93b..62fa8a60d40da 100644
--- a/packages/twenty-front/src/pages/settings/workspace/SettingsWorkspaceEmailGroupChannelDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/email/SettingsWorkspaceEmailGroupChannelDetail.tsx
@@ -8,7 +8,7 @@ import { useMyMessageChannels } from '@/settings/accounts/hooks/useMyMessageChan
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
import { MessageChannelType, SettingsPath } from 'twenty-shared/types';
@@ -85,12 +85,12 @@ export const SettingsWorkspaceEmailGroupChannelDetail = () => {
};
return (
- {
confirmButtonAccent="danger"
loading={deleting}
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/emailing-domains/SettingsEmailingDomainDetail.tsx b/packages/twenty-front/src/pages/settings/emailing-domains/SettingsEmailingDomainDetail.tsx
index 06beff5185fd5..ff9acf0649d8b 100644
--- a/packages/twenty-front/src/pages/settings/emailing-domains/SettingsEmailingDomainDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/emailing-domains/SettingsEmailingDomainDetail.tsx
@@ -9,7 +9,7 @@ import { SettingsEmailingDomainVerificationRecords } from '@/settings/emailing-d
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath, isDefined } from 'twenty-shared/utils';
import { IconTrash } from 'twenty-ui/display';
@@ -75,12 +75,12 @@ export const SettingsEmailingDomainDetail = () => {
};
return (
- Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: Email,
@@ -117,6 +117,6 @@ export const SettingsEmailingDomainDetail = () => {
confirmButtonAccent="danger"
loading={deleting}
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/emailing-domains/SettingsNewEmailingDomain.tsx b/packages/twenty-front/src/pages/settings/emailing-domains/SettingsNewEmailingDomain.tsx
index b29d8e1c08474..fec6fbb11650e 100644
--- a/packages/twenty-front/src/pages/settings/emailing-domains/SettingsNewEmailingDomain.tsx
+++ b/packages/twenty-front/src/pages/settings/emailing-domains/SettingsNewEmailingDomain.tsx
@@ -2,7 +2,7 @@ import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { CombinedGraphQLErrors } from '@apollo/client/errors';
import { Trans, useLingui } from '@lingui/react/macro';
import { useState } from 'react';
@@ -110,7 +110,7 @@ export const SettingsNewEmailingDomain = () => {
};
return (
- {
links={[
{
children: Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: Email,
@@ -149,6 +149,6 @@ export const SettingsNewEmailingDomain = () => {
/>
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/enterprise/SettingsEnterprise.tsx b/packages/twenty-front/src/pages/settings/enterprise/SettingsEnterprise.tsx
index 3f45b083ee9de..73249d61e9c44 100644
--- a/packages/twenty-front/src/pages/settings/enterprise/SettingsEnterprise.tsx
+++ b/packages/twenty-front/src/pages/settings/enterprise/SettingsEnterprise.tsx
@@ -16,7 +16,7 @@ import { ENTERPRISE_SUBSCRIPTION_STATUS } from '@/settings/enterprise/graphql/qu
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { useLoadCurrentUser } from '@/users/hooks/useLoadCurrentUser';
import { useLazyQuery, useMutation } from '@apollo/client/react';
@@ -668,17 +668,17 @@ export const SettingsEnterprise = ({
}
return (
- Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{ children: Enterprise },
]}
>
{innerContent}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/general/SettingsGeneral.tsx b/packages/twenty-front/src/pages/settings/general/SettingsGeneral.tsx
new file mode 100644
index 0000000000000..ec4c840c245e1
--- /dev/null
+++ b/packages/twenty-front/src/pages/settings/general/SettingsGeneral.tsx
@@ -0,0 +1,94 @@
+import { useLingui } from '@lingui/react/macro';
+
+import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
+import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
+import { SettingsTabBar } from '@/settings/components/layout/SettingsTabBar';
+import { useSettingsActiveTabId } from '@/settings/components/layout/useSettingsActiveTabId';
+import { SettingsWorkspaceDomainCard } from '@/settings/domains/components/SettingsWorkspaceDomainCard';
+import { DeleteWorkspace } from '@/settings/profile/components/DeleteWorkspace';
+import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
+import { SettingsSecuritySettings } from '@/settings/security/components/SettingsSecuritySettings';
+import { NameField } from '@/settings/workspace/components/NameField';
+import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader';
+import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
+import { H2Title, IconKey, IconSettings } from 'twenty-ui/display';
+import { Section } from 'twenty-ui/layout';
+import { PermissionFlagType } from '~/generated-metadata/graphql';
+
+const SETTINGS_GENERAL_TABS_INSTANCE_ID = 'settings-general-tabs';
+
+const GENERAL_TAB_GENERAL = 'general';
+const GENERAL_TAB_SECURITY = 'security';
+
+export const SettingsGeneral = () => {
+ const { t } = useLingui();
+
+ const isMultiWorkspaceEnabled = useAtomStateValue(
+ isMultiWorkspaceEnabledState,
+ );
+
+ const hasSecurityPermission = useHasPermissionFlag(
+ PermissionFlagType.SECURITY,
+ );
+
+ const tabs = [
+ { id: GENERAL_TAB_GENERAL, title: t`General`, Icon: IconSettings },
+ ...(hasSecurityPermission
+ ? [{ id: GENERAL_TAB_SECURITY, title: t`Security`, Icon: IconKey }]
+ : []),
+ ];
+
+ const activeTabId = useSettingsActiveTabId(
+ SETTINGS_GENERAL_TABS_INSTANCE_ID,
+ tabs.map((tab) => tab.id),
+ );
+
+ const renderActiveTabContent = () => {
+ if (hasSecurityPermission && activeTabId === GENERAL_TAB_SECURITY) {
+ return ;
+ }
+
+ return (
+ <>
+
+
+ {isMultiWorkspaceEnabled && (
+
+ )}
+
+ >
+ );
+ };
+
+ return (
+
+ ) : undefined
+ }
+ links={[{ children: t`Workspace` }, { children: t`General` }]}
+ >
+ {renderActiveTabContent()}
+
+ );
+};
diff --git a/packages/twenty-front/src/pages/settings/layout/SettingsLayout.tsx b/packages/twenty-front/src/pages/settings/layout/SettingsLayout.tsx
index 39945292080de..bd47ad2e493a3 100644
--- a/packages/twenty-front/src/pages/settings/layout/SettingsLayout.tsx
+++ b/packages/twenty-front/src/pages/settings/layout/SettingsLayout.tsx
@@ -2,7 +2,7 @@ import { useEnterLayoutCustomizationMode } from '@/layout-customization/hooks/us
import { SettingsDiscoveryHeroCard } from '@/settings/components/SettingsDiscoveryHeroCard';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsLayoutItemsStats } from '@/settings/layout/components/SettingsLayoutItemsStats';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useLingui } from '@lingui/react/macro';
import { useNavigate } from 'react-router-dom';
import { AppPath, SettingsPath } from 'twenty-shared/types';
@@ -68,7 +68,7 @@ export const SettingsLayout = () => {
];
return (
- {
links={[
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{ children: t`Layout` },
]}
@@ -106,6 +106,6 @@ export const SettingsLayout = () => {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/layout/components/SettingsLayoutDetailScaffold.tsx b/packages/twenty-front/src/pages/settings/layout/components/SettingsLayoutDetailScaffold.tsx
index 04f14061c7565..82445476c8d35 100644
--- a/packages/twenty-front/src/pages/settings/layout/components/SettingsLayoutDetailScaffold.tsx
+++ b/packages/twenty-front/src/pages/settings/layout/components/SettingsLayoutDetailScaffold.tsx
@@ -5,7 +5,7 @@ import { TableBody } from '@/ui/layout/table/components/TableBody';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
import { TableRow } from '@/ui/layout/table/components/TableRow';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { styled } from '@linaria/react';
import { t } from '@lingui/core/macro';
import { type ReactNode } from 'react';
@@ -57,7 +57,7 @@ export const SettingsLayoutDetailScaffold = ({
);
const breadcrumbLinks = [
- { children: t`Workspace`, href: getSettingsPath(SettingsPath.Workspace) },
+ { children: t`Workspace`, href: getSettingsPath(SettingsPath.General) },
{
children: t`Applications`,
href: getSettingsPath(SettingsPath.Applications),
@@ -68,7 +68,7 @@ export const SettingsLayoutDetailScaffold = ({
];
return (
-
+
{isLoading ? (
@@ -111,6 +111,6 @@ export const SettingsLayoutDetailScaffold = ({
>
)}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/logic-functions/SettingsLogicFunctionDetail.tsx b/packages/twenty-front/src/pages/settings/logic-functions/SettingsLogicFunctionDetail.tsx
index 3bfea560b4446..e3d5e73adb475 100644
--- a/packages/twenty-front/src/pages/settings/logic-functions/SettingsLogicFunctionDetail.tsx
+++ b/packages/twenty-front/src/pages/settings/logic-functions/SettingsLogicFunctionDetail.tsx
@@ -6,7 +6,7 @@ import { SettingsLogicFunctionLabelContainer } from '@/settings/logic-functions/
import { SettingsLogicFunctionSettingsTab } from '@/settings/logic-functions/components/tabs/SettingsLogicFunctionSettingsTab';
import { SettingsLogicFunctionTestTab } from '@/settings/logic-functions/components/tabs/SettingsLogicFunctionTestTab';
import { SettingsLogicFunctionTriggersTab } from '@/settings/logic-functions/components/tabs/SettingsLogicFunctionTriggersTab';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
@@ -104,7 +104,7 @@ export const SettingsLogicFunctionDetail = () => {
return [
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: t`Applications`,
@@ -118,7 +118,7 @@ export const SettingsLogicFunctionDetail = () => {
: [
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: t`AI`,
@@ -139,7 +139,7 @@ export const SettingsLogicFunctionDetail = () => {
return (
!loading &&
!applicationLoading && (
- {
/>
)}
-
+
)
);
};
diff --git a/packages/twenty-front/src/pages/settings/members/SettingsWorkspaceMember.tsx b/packages/twenty-front/src/pages/settings/members/SettingsWorkspaceMember.tsx
index a977878d43d67..e57f074c5d35d 100644
--- a/packages/twenty-front/src/pages/settings/members/SettingsWorkspaceMember.tsx
+++ b/packages/twenty-front/src/pages/settings/members/SettingsWorkspaceMember.tsx
@@ -10,7 +10,7 @@ import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFla
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
@@ -167,12 +167,12 @@ export const SettingsWorkspaceMember = () => {
<>
{isLoading ? null : (
- {
confirmButtonText={t`Remove member`}
loading={isDeleting}
/>
-
+
)}
>
);
diff --git a/packages/twenty-front/src/pages/settings/members/SettingsWorkspaceMembers.tsx b/packages/twenty-front/src/pages/settings/members/SettingsWorkspaceMembers.tsx
index e3c839233cfc7..00758153bc44d 100644
--- a/packages/twenty-front/src/pages/settings/members/SettingsWorkspaceMembers.tsx
+++ b/packages/twenty-front/src/pages/settings/members/SettingsWorkspaceMembers.tsx
@@ -6,10 +6,9 @@ import { IconLock, IconUserPlus, IconUsers } from 'twenty-ui/display';
import { SettingsDiscoveryHeroCard } from '@/settings/components/SettingsDiscoveryHeroCard';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
-import { TabList } from '@/ui/layout/tab-list/components/TabList';
-import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
-import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
+import { SettingsTabBar } from '@/settings/components/layout/SettingsTabBar';
+import { useSettingsActiveTabId } from '@/settings/components/layout/useSettingsActiveTabId';
import { Section } from 'twenty-ui/layout';
import { PermissionFlagType } from '~/generated-metadata/graphql';
import { SettingsWorkspaceMembersInviteTab } from '~/pages/settings/members/tabs/SettingsWorkspaceMembersInviteTab';
@@ -31,11 +30,6 @@ export const SettingsWorkspaceMembers = () => {
const hasRolesPermission = useHasPermissionFlag(PermissionFlagType.ROLES);
- const activeTabId = useAtomComponentStateValue(
- activeTabIdComponentState,
- MEMBERS_TAB_LIST_ID,
- );
-
const tabs = [
{ id: MEMBERS_TAB_TEAM_ID, title: t`Team`, Icon: IconUsers },
{ id: MEMBERS_TAB_INVITE_ID, title: t`Invite`, Icon: IconUserPlus },
@@ -44,6 +38,11 @@ export const SettingsWorkspaceMembers = () => {
: []),
];
+ const activeTabId = useSettingsActiveTabId(
+ MEMBERS_TAB_LIST_ID,
+ tabs.map((tab) => tab.id),
+ );
+
const renderActiveTabContent = () => {
switch (activeTabId) {
case MEMBERS_TAB_INVITE_ID:
@@ -60,12 +59,15 @@ export const SettingsWorkspaceMembers = () => {
};
return (
-
+ }
links={[
{
children: Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{ children: Members },
]}
@@ -103,9 +105,8 @@ export const SettingsWorkspaceMembers = () => {
playButtonAriaLabel={t`Watch members demo`}
/>
-
{renderActiveTabContent()}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/members/roles/SettingsRoleAddObjectLevel.tsx b/packages/twenty-front/src/pages/settings/members/roles/SettingsRoleAddObjectLevel.tsx
index a9de81ca06b20..2e7064c827d6f 100644
--- a/packages/twenty-front/src/pages/settings/members/roles/SettingsRoleAddObjectLevel.tsx
+++ b/packages/twenty-front/src/pages/settings/members/roles/SettingsRoleAddObjectLevel.tsx
@@ -2,7 +2,8 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain
import { SettingsRolesQueryEffect } from '@/settings/roles/components/SettingsRolesQueryEffect';
import { SettingsRolePermissionsObjectLevelObjectPicker } from '@/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelObjectPicker';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
+import { SettingsWizardStepBar } from '@/settings/components/layout/SettingsWizardStepBar';
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
import { t } from '@lingui/core/macro';
import { Navigate, useParams, useSearchParams } from 'react-router-dom';
@@ -37,7 +38,7 @@ export const SettingsRoleAddObjectLevel = () => {
? [
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: t`AI`,
@@ -56,7 +57,7 @@ export const SettingsRoleAddObjectLevel = () => {
: [
{
children: t`Workspace`,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: t`Members`,
@@ -73,17 +74,23 @@ export const SettingsRoleAddObjectLevel = () => {
},
];
+ const headerTitle =
+ fromAgentId && isDefined(agent)
+ ? agent.label
+ : (settingsDraftRole.label ?? '');
+
return (
<>
- }
>
-
+
>
);
};
diff --git a/packages/twenty-front/src/pages/settings/SettingsProfile.tsx b/packages/twenty-front/src/pages/settings/profile/SettingsProfile.tsx
similarity index 96%
rename from packages/twenty-front/src/pages/settings/SettingsProfile.tsx
rename to packages/twenty-front/src/pages/settings/profile/SettingsProfile.tsx
index 075064b719440..840f858b709e6 100644
--- a/packages/twenty-front/src/pages/settings/SettingsProfile.tsx
+++ b/packages/twenty-front/src/pages/settings/profile/SettingsProfile.tsx
@@ -8,7 +8,7 @@ import { NameFields } from '@/settings/profile/components/NameFields';
import { WorkspaceMemberPictureUploader } from '@/settings/workspace-member/components/WorkspaceMemberPictureUploader';
import { useCanChangePassword } from '@/settings/profile/hooks/useCanChangePassword';
import { useCurrentUserWorkspaceTwoFactorAuthentication } from '@/settings/two-factor-authentication/hooks/useCurrentUserWorkspaceTwoFactorAuthentication';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { Trans, useLingui } from '@lingui/react/macro';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { SettingsPath } from 'twenty-shared/types';
@@ -35,7 +35,7 @@ export const SettingsProfile = () => {
}
return (
- {
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/SettingsTwoFactorAuthenticationMethod.tsx b/packages/twenty-front/src/pages/settings/profile/SettingsTwoFactorAuthenticationMethod.tsx
similarity index 97%
rename from packages/twenty-front/src/pages/settings/SettingsTwoFactorAuthenticationMethod.tsx
rename to packages/twenty-front/src/pages/settings/profile/SettingsTwoFactorAuthenticationMethod.tsx
index f30ad05db3d51..742ce9f2dd601 100644
--- a/packages/twenty-front/src/pages/settings/SettingsTwoFactorAuthenticationMethod.tsx
+++ b/packages/twenty-front/src/pages/settings/profile/SettingsTwoFactorAuthenticationMethod.tsx
@@ -12,7 +12,7 @@ import { TwoFactorAuthenticationVerificationForSettings } from '@/settings/two-f
import { useCurrentUserWorkspaceTwoFactorAuthentication } from '@/settings/two-factor-authentication/hooks/useCurrentUserWorkspaceTwoFactorAuthentication';
import { useTwoFactorVerificationForSettings } from '@/settings/two-factor-authentication/hooks/useTwoFactorVerificationForSettings';
import { extractSecretFromOtpUri } from '@/settings/two-factor-authentication/utils/extractSecretFromOtpUri';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
import { H2Title } from 'twenty-ui/display';
@@ -110,7 +110,7 @@ export const SettingsTwoFactorAuthenticationMethod = () => {
return (
// oxlint-disable-next-line react/jsx-props-no-spreading
- {
)}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/profile/appearance/components/SettingsExperience.tsx b/packages/twenty-front/src/pages/settings/profile/appearance/components/SettingsExperience.tsx
index 11a76a82cc762..12e55b301b4e8 100644
--- a/packages/twenty-front/src/pages/settings/profile/appearance/components/SettingsExperience.tsx
+++ b/packages/twenty-front/src/pages/settings/profile/appearance/components/SettingsExperience.tsx
@@ -1,6 +1,6 @@
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { FormatPreferencesSettings } from '@/settings/experience/components/FormatPreferencesSettings';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useColorScheme } from '@/ui/theme/hooks/useColorScheme';
import { Trans, useLingui } from '@lingui/react/macro';
import { SettingsPath } from 'twenty-shared/types';
@@ -15,7 +15,7 @@ export const SettingsExperience = () => {
const { t } = useLingui();
return (
- {
{/* Unified into FormatPreferencesSettings */}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx b/packages/twenty-front/src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
index 7656eebcb473c..29d8b41cab1d0 100644
--- a/packages/twenty-front/src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
+++ b/packages/twenty-front/src/pages/settings/security/SettingsSecurityApprovedAccessDomain.tsx
@@ -2,7 +2,7 @@ import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { CombinedGraphQLErrors } from '@apollo/client/errors';
import { zodResolver } from '@hookform/resolvers/zod';
import { Trans, useLingui } from '@lingui/react/macro';
@@ -83,7 +83,7 @@ export const SettingsSecurityApprovedAccessDomain = () => {
return (
);
};
diff --git a/packages/twenty-front/src/pages/settings/security/SettingsSecuritySSOIdentifyProvider.tsx b/packages/twenty-front/src/pages/settings/security/SettingsSecuritySSOIdentifyProvider.tsx
index e4c521d985f4f..0434251047fc2 100644
--- a/packages/twenty-front/src/pages/settings/security/SettingsSecuritySSOIdentifyProvider.tsx
+++ b/packages/twenty-front/src/pages/settings/security/SettingsSecuritySSOIdentifyProvider.tsx
@@ -7,7 +7,7 @@ import { type SettingSecurityNewSSOIdentityFormValues } from '@/settings/securit
import { sSOIdentityProviderDefaultValues } from '@/settings/security/utils/sSOIdentityProviderDefaultValues';
import { SSOIdentitiesProvidersParamsSchema } from '@/settings/security/validation-schemas/SSOIdentityProviderSchema';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
+import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { CombinedGraphQLErrors } from '@apollo/client/errors';
import { zodResolver } from '@hookform/resolvers/zod';
import { t } from '@lingui/core/macro';
@@ -63,7 +63,7 @@ export const SettingsSecuritySSOIdentifyProvider = () => {
// oxlint-disable-next-line react/jsx-props-no-spreading
{...form}
>
- {
links={[
{
children: Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: Security,
@@ -84,7 +84,7 @@ export const SettingsSecuritySSOIdentifyProvider = () => {
]}
>
-
+
);
diff --git a/packages/twenty-front/src/pages/settings/security/event-logs/SettingsEventLogs.tsx b/packages/twenty-front/src/pages/settings/security/event-logs/SettingsEventLogs.tsx
index 2d8010341f50f..000f92164dadc 100644
--- a/packages/twenty-front/src/pages/settings/security/event-logs/SettingsEventLogs.tsx
+++ b/packages/twenty-front/src/pages/settings/security/event-logs/SettingsEventLogs.tsx
@@ -181,7 +181,7 @@ export const SettingsEventLogs = () => {
links={[
{
children: Workspace,
- href: getSettingsPath(SettingsPath.Workspace),
+ href: getSettingsPath(SettingsPath.General),
},
{
children: Security,
diff --git a/packages/twenty-front/src/pages/settings/updates/SettingsUpdates.tsx b/packages/twenty-front/src/pages/settings/updates/SettingsUpdates.tsx
deleted file mode 100644
index 07f6475a187ac..0000000000000
--- a/packages/twenty-front/src/pages/settings/updates/SettingsUpdates.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import { SettingsCard } from '@/settings/components/SettingsCard';
-import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { SettingsLabContent } from '@/settings/lab/components/SettingsLabContent';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
-import { styled } from '@linaria/react';
-import { t } from '@lingui/core/macro';
-import { SettingsPath } from 'twenty-shared/types';
-import { getSettingsPath } from 'twenty-shared/utils';
-import { H2Title, IconTransform } from 'twenty-ui/display';
-import { Section } from 'twenty-ui/layout';
-import { useContext } from 'react';
-import { ThemeContext } from 'twenty-ui/theme-constants';
-const StyledCardLink = styled.a`
- text-decoration: none;
-`;
-
-export const SettingsUpdates = () => {
- const { theme } = useContext(ThemeContext);
- return (
-
-
-
-
-
-
- }
- title={t`Read changelog`}
- />
-
-
-
-
-
-
- );
-};
diff --git a/packages/twenty-front/src/utils/title-utils.ts b/packages/twenty-front/src/utils/title-utils.ts
index 8b67ccf0696fc..618816949cfa1 100644
--- a/packages/twenty-front/src/utils/title-utils.ts
+++ b/packages/twenty-front/src/utils/title-utils.ts
@@ -10,7 +10,8 @@ enum SettingsPathPrefixes {
ApiWebhooks = `${AppBasePath.Settings}/${SettingsPath.ApiWebhooks}`,
LogicFunctions = `${AppBasePath.Settings}/${SettingsPath.LogicFunctions}`,
Integration = `${AppBasePath.Settings}/${SettingsPath.Integrations}`,
- General = `${AppBasePath.Settings}/${SettingsPath.Workspace}`,
+ General = `${AppBasePath.Settings}/${SettingsPath.General}`,
+ Community = `${AppBasePath.Settings}/${SettingsPath.Community}`,
}
const getPathnameOrPrefix = (pathname: string) => {
@@ -53,6 +54,8 @@ export const getPageTitleFromPath = (pathname: string): string => {
return t`Integrations - Settings`;
case SettingsPathPrefixes.General:
return t`General - Settings`;
+ case SettingsPathPrefixes.Community:
+ return t`Community - Settings`;
default:
return 'Twenty';
}
diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-command-menu-item.constant.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-command-menu-item.constant.ts
index ef5195855ff3e..88f291f49cf31 100644
--- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-command-menu-item.constant.ts
+++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-command-menu-item.constant.ts
@@ -936,18 +936,18 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
},
goToSettingsUpdates: {
universalIdentifier: '5d1ba354-0090-4a42-9a43-601461b26068',
- label: 'Go to Updates Settings',
- icon: 'IconRocket',
+ label: 'Go to Community Settings',
+ icon: 'IconUsers',
isPinned: false,
position: 62,
- shortLabel: 'Updates',
+ shortLabel: 'Community',
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
conditionalAvailabilityExpression: null,
availabilityObjectMetadataUniversalIdentifier: null,
frontComponentUniversalIdentifier: null,
engineComponentKey: EngineComponentKey.NAVIGATION,
hotKeys: null,
- payload: { path: '/settings/updates' },
+ payload: { path: '/settings/community' },
},
composeEmailToPerson: {
universalIdentifier: 'f01d4b8b-2b4e-4ae0-9c6f-0b9a9a3e5b21',
diff --git a/packages/twenty-shared/src/types/SettingsPath.ts b/packages/twenty-shared/src/types/SettingsPath.ts
index fb53776806afc..5afc307606678 100644
--- a/packages/twenty-shared/src/types/SettingsPath.ts
+++ b/packages/twenty-shared/src/types/SettingsPath.ts
@@ -24,17 +24,17 @@ export enum SettingsPath {
Layout = 'layout',
WorkspaceMembersPage = 'members',
WorkspaceMemberPage = 'members/:workspaceMemberId',
- Workspace = 'general',
+ General = 'general',
Subdomain = 'general/subdomain',
CustomDomain = 'general/custom-domain',
WorkspaceEmail = 'email',
EmailGroupChannelDetail = 'email/email-group/:messageChannelId',
NewEmailGroupChannel = 'email/new-email-group',
PublicDomain = 'applications/public-domain',
- NewApprovedAccessDomain = 'members/approved-access-domain/new',
+ NewApprovedAccessDomain = 'security/approved-access-domain/new',
NewEmailingDomain = 'email/emailing-domain/new',
EmailingDomainDetail = 'email/emailing-domain/:domainId',
- Updates = 'updates',
+ Community = 'community',
AI = 'ai',
AiUsageUserDetail = 'ai/usage/user/:userWorkspaceId',
AiPrompts = 'ai/prompts',
@@ -66,7 +66,7 @@ export enum SettingsPath {
NewWebhook = 'api-webhooks/webhooks/new',
WebhookDetail = 'api-webhooks/webhooks/:webhookId',
Integrations = 'integrations',
- Security = 'security',
+ Security = 'general#security',
NewSSOIdentityProvider = 'security/sso/new',
EventLogs = 'security/event-logs',
diff --git a/packages/twenty-shared/src/utils/navigation/__tests__/getSettingsPath.test.ts b/packages/twenty-shared/src/utils/navigation/__tests__/getSettingsPath.test.ts
index 2cd71d29a3f0d..f8335c92caf7f 100644
--- a/packages/twenty-shared/src/utils/navigation/__tests__/getSettingsPath.test.ts
+++ b/packages/twenty-shared/src/utils/navigation/__tests__/getSettingsPath.test.ts
@@ -4,7 +4,7 @@ import { getSettingsPath } from '../getSettingsPath';
describe('getSettingsPath', () => {
it('should return settings path with correct prefix when no params or query params provided', () => {
expect(getSettingsPath(SettingsPath.ProfilePage)).toBe('/settings/profile');
- expect(getSettingsPath(SettingsPath.Workspace)).toBe('/settings/general');
+ expect(getSettingsPath(SettingsPath.General)).toBe('/settings/general');
expect(getSettingsPath(SettingsPath.Accounts)).toBe('/settings/accounts');
});
@@ -68,7 +68,7 @@ describe('getSettingsPath', () => {
).toBe('/settings/profile#section1');
expect(
- getSettingsPath(SettingsPath.Workspace, undefined, undefined, 'general'),
+ getSettingsPath(SettingsPath.General, undefined, undefined, 'general'),
).toBe('/settings/general#general');
});