mirror of
https://github.com/lingble/twenty.git
synced 2025-11-02 13:47:55 +00:00
New Settings Layout (#6867)
#### \ Description - **Added "Exit Settings" Back Button**: Introduced a new back button labeled "Exit Settings" for easy navigation back to the app content. - **Implemented Settings Navbar Breadcrumb**: A breadcrumb navigation bar for each settings page has been added to improve navigation within the settings. This ensures users can easily trace their location within the settings. - **Persistent CTA Zone**: The Call-to-Action (CTA) zone at the top of the page now remains visible even when the user scrolls down, preventing unresponsive behavior and improving accessibility. - **Page Title**: The page title has been added to each settings page and separated from the breadcrumb, following the app's layout standards. - we could not reproduce the Billing and CMR Migrations settings on the app, but we updated the files according, please let's us know if is there any way to log in with access to these pages, or if is everything ok. - Some breadcrumbs are not following the Figma, are following the current app sections isntead, because we would need to change the sidebar structure, and we should not do it on this PR ### Demo <https://www.loom.com/share/21b20a2cd2f3471e94d61563c9901b19?sid=9dc49456-6cae-48e1-9149-8d706f00ab65> ### Refs: #6144 Fixes #6144 --------- Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com> Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
committed by
GitHub
parent
fe4ca2133d
commit
c42ea57b97
@@ -42,7 +42,7 @@ export const AppNavigationDrawer = ({
|
|||||||
const drawerProps: NavigationDrawerProps = isSettingsDrawer
|
const drawerProps: NavigationDrawerProps = isSettingsDrawer
|
||||||
? {
|
? {
|
||||||
isSubMenu: true,
|
isSubMenu: true,
|
||||||
title: 'Settings',
|
title: 'Exit Settings',
|
||||||
children: <SettingsNavigationDrawerItems />,
|
children: <SettingsNavigationDrawerItems />,
|
||||||
footer: <GithubVersionLink />,
|
footer: <GithubVersionLink />,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export const SettingsNavigationDrawerItems = () => {
|
|||||||
Icon={IconUserCircle}
|
Icon={IconUserCircle}
|
||||||
/>
|
/>
|
||||||
<SettingsNavigationDrawerItem
|
<SettingsNavigationDrawerItem
|
||||||
label="Appearance"
|
label="Experience"
|
||||||
path={SettingsPath.Appearance}
|
path={SettingsPath.Appearance}
|
||||||
Icon={IconColorSwatch}
|
Icon={IconColorSwatch}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const StyledSettingsPageContainer = styled.div<{ width?: number }>`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: ${({ theme }) => theme.spacing(8)};
|
gap: ${({ theme }) => theme.spacing(8)};
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: ${({ theme }) => theme.spacing(8)};
|
padding: ${({ theme }) => theme.spacing(6, 8, 8)};
|
||||||
width: ${({ width }) => {
|
width: ${({ width }) => {
|
||||||
if (isDefined(width)) {
|
if (isDefined(width)) {
|
||||||
return width + 'px';
|
return width + 'px';
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export const SettingsReadDocumentationButton = () => {
|
|||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
title="Read documentation"
|
title="Read documentation"
|
||||||
variant="primary"
|
variant="secondary"
|
||||||
accent="default"
|
accent="default"
|
||||||
size="small"
|
size="small"
|
||||||
Icon={IconBook2}
|
Icon={IconBook2}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ type PageHeaderProps = {
|
|||||||
hasNextRecord?: boolean;
|
hasNextRecord?: boolean;
|
||||||
navigateToPreviousRecord?: () => void;
|
navigateToPreviousRecord?: () => void;
|
||||||
navigateToNextRecord?: () => void;
|
navigateToNextRecord?: () => void;
|
||||||
Icon: IconComponent;
|
Icon?: IconComponent;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
width?: number;
|
width?: number;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ const StyledPanel = styled.div`
|
|||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
padding-bottom: ${({ theme }) => theme.spacing(10)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type PagePanelProps = {
|
type PagePanelProps = {
|
||||||
|
|||||||
@@ -2,48 +2,52 @@ import styled from '@emotion/styled';
|
|||||||
import { JSX, ReactNode } from 'react';
|
import { JSX, ReactNode } from 'react';
|
||||||
import { IconComponent } from 'twenty-ui';
|
import { IconComponent } from 'twenty-ui';
|
||||||
|
|
||||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
|
||||||
|
|
||||||
import { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper';
|
import { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper';
|
||||||
import { OBJECT_SETTINGS_WIDTH } from '@/settings/data-model/constants/ObjectSettings';
|
import {
|
||||||
|
Breadcrumb,
|
||||||
|
BreadcrumbProps,
|
||||||
|
} from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
||||||
import { PageBody } from './PageBody';
|
import { PageBody } from './PageBody';
|
||||||
import { PageHeader } from './PageHeader';
|
import { PageHeader } from './PageHeader';
|
||||||
|
|
||||||
type SubMenuTopBarContainerProps = {
|
type SubMenuTopBarContainerProps = {
|
||||||
children: JSX.Element | JSX.Element[];
|
children: JSX.Element | JSX.Element[];
|
||||||
title: string | ReactNode;
|
title?: string;
|
||||||
actionButton?: ReactNode;
|
actionButton?: ReactNode;
|
||||||
Icon: IconComponent;
|
Icon: IconComponent;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
links: BreadcrumbProps['links'];
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledContainer = styled.div<{ isMobile: boolean }>`
|
const StyledContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding-top: ${({ theme, isMobile }) => (!isMobile ? theme.spacing(3) : 0)};
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const StyledTitle = styled.h3`
|
||||||
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
|
font-size: ${({ theme }) => theme.font.size.lg};
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||||
|
line-height: 1.2;
|
||||||
|
margin: ${({ theme }) => theme.spacing(8, 8, 2)};
|
||||||
|
`;
|
||||||
|
|
||||||
export const SubMenuTopBarContainer = ({
|
export const SubMenuTopBarContainer = ({
|
||||||
children,
|
children,
|
||||||
title,
|
title,
|
||||||
actionButton,
|
actionButton,
|
||||||
Icon,
|
|
||||||
className,
|
className,
|
||||||
|
links,
|
||||||
}: SubMenuTopBarContainerProps) => {
|
}: SubMenuTopBarContainerProps) => {
|
||||||
const isMobile = useIsMobile();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer isMobile={isMobile} className={className}>
|
<StyledContainer className={className}>
|
||||||
<PageHeader
|
<PageHeader title={<Breadcrumb links={links} />}>
|
||||||
title={title}
|
|
||||||
Icon={Icon}
|
|
||||||
width={OBJECT_SETTINGS_WIDTH + 4 * 8}
|
|
||||||
>
|
|
||||||
{actionButton}
|
{actionButton}
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<PageBody>
|
<PageBody>
|
||||||
<InformationBannerWrapper />
|
<InformationBannerWrapper />
|
||||||
|
{title && <StyledTitle>{title}</StyledTitle>}
|
||||||
{children}
|
{children}
|
||||||
</PageBody>
|
</PageBody>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
|
|||||||
@@ -1,27 +1,22 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { CSSProperties, Fragment, ReactNode } from 'react';
|
import { Fragment, ReactNode } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
type BreadcrumbProps = {
|
export type BreadcrumbProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
links: {
|
links: { children: string | ReactNode; href?: string }[];
|
||||||
href?: string;
|
|
||||||
styles?: CSSProperties;
|
|
||||||
children?: string | ReactNode;
|
|
||||||
}[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledWrapper = styled.nav`
|
const StyledWrapper = styled.nav`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: ${({ theme }) => theme.font.color.secondary};
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
display: flex;
|
display: grid;
|
||||||
font-size: ${({ theme }) => theme.font.size.md};
|
font-size: ${({ theme }) => theme.font.size.md};
|
||||||
// font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
grid-auto-flow: column;
|
||||||
gap: ${({ theme }) => theme.spacing(2)};
|
grid-column-gap: ${({ theme }) => theme.spacing(1)};
|
||||||
line-height: ${({ theme }) => theme.text.lineHeight.lg};
|
|
||||||
white-space: nowrap;
|
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
height: ${({ theme }) => theme.spacing(8)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledLink = styled(Link)`
|
const StyledLink = styled(Link)`
|
||||||
@@ -39,7 +34,10 @@ const StyledText = styled.span`
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// TODO: not sure that passing styles to the link is a good idea
|
const StyledDivider = styled.span`
|
||||||
|
width: ${({ theme }) => theme.spacing(2)};
|
||||||
|
`;
|
||||||
|
|
||||||
export const Breadcrumb = ({ className, links }: BreadcrumbProps) => {
|
export const Breadcrumb = ({ className, links }: BreadcrumbProps) => {
|
||||||
return (
|
return (
|
||||||
<StyledWrapper className={className}>
|
<StyledWrapper className={className}>
|
||||||
@@ -49,15 +47,13 @@ export const Breadcrumb = ({ className, links }: BreadcrumbProps) => {
|
|||||||
return (
|
return (
|
||||||
<Fragment key={index}>
|
<Fragment key={index}>
|
||||||
{link.href ? (
|
{link.href ? (
|
||||||
<StyledLink style={link.styles} title={text} to={link.href}>
|
<StyledLink title={text} to={link.href}>
|
||||||
{link.children}
|
{link.children}
|
||||||
</StyledLink>
|
</StyledLink>
|
||||||
) : (
|
) : (
|
||||||
<StyledText style={link.styles} title={text}>
|
<StyledText title={text}>{link.children}</StyledText>
|
||||||
{link.children}
|
|
||||||
</StyledText>
|
|
||||||
)}
|
)}
|
||||||
{index < links.length - 1 && '/'}
|
{index < links.length - 1 && <StyledDivider>/</StyledDivider>}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ReactNode, useState } from 'react';
|
|
||||||
import { css, useTheme } from '@emotion/react';
|
import { css, useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
|
import { ReactNode, useState } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { MOBILE_VIEWPORT } from 'twenty-ui';
|
import { MOBILE_VIEWPORT } from 'twenty-ui';
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ const StyledContainer = styled.div<{ isSubMenu?: boolean }>`
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: ${({ theme }) => theme.spacing(3.5)};
|
gap: ${({ theme }) => theme.spacing(3)};
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-width: ${DESKTOP_NAV_DRAWER_WIDTHS.menu}px;
|
min-width: ${DESKTOP_NAV_DRAWER_WIDTHS.menu}px;
|
||||||
padding: ${({ theme }) => theme.spacing(3, 2, 4)};
|
padding: ${({ theme }) => theme.spacing(3, 2, 4)};
|
||||||
@@ -41,7 +41,6 @@ const StyledContainer = styled.div<{ isSubMenu?: boolean }>`
|
|||||||
isSubMenu
|
isSubMenu
|
||||||
? css`
|
? css`
|
||||||
padding-right: ${theme.spacing(8)};
|
padding-right: ${theme.spacing(8)};
|
||||||
padding-top: 41px;
|
|
||||||
`
|
`
|
||||||
: ''}
|
: ''}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { IconChevronLeft } from 'twenty-ui';
|
import { IconX } from 'twenty-ui';
|
||||||
|
|
||||||
import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink';
|
import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink';
|
||||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||||
@@ -18,17 +18,22 @@ const StyledIconAndButtonContainer = styled.button`
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
font-size: ${({ theme }) => theme.font.size.lg};
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
|
||||||
gap: ${({ theme }) => theme.spacing(2)};
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
line-height: ${({ theme }) => theme.text.lineHeight.md};
|
padding: ${({ theme }) => theme.spacing(1.5, 1)};
|
||||||
padding: ${({ theme }) => theme.spacing(1)};
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
font-family: ${({ theme }) => theme.font.family};
|
||||||
|
&:hover {
|
||||||
|
background: ${({ theme }) => theme.background.transparent.light};
|
||||||
|
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
height: ${({ theme }) => theme.spacing(8)};
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -42,9 +47,10 @@ export const NavigationDrawerBackButton = ({
|
|||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<UndecoratedLink to={navigationMemorizedUrl} replace>
|
<UndecoratedLink to={navigationMemorizedUrl} replace>
|
||||||
<StyledIconAndButtonContainer>
|
<StyledIconAndButtonContainer>
|
||||||
<IconChevronLeft
|
<IconX
|
||||||
size={theme.icon.size.md}
|
size={theme.icon.size.md}
|
||||||
stroke={theme.icon.stroke.lg}
|
stroke={theme.icon.stroke.lg}
|
||||||
|
color={theme.font.color.tertiary}
|
||||||
/>
|
/>
|
||||||
<span>{title}</span>
|
<span>{title}</span>
|
||||||
</StyledIconAndButtonContainer>
|
</StyledIconAndButtonContainer>
|
||||||
|
|||||||
@@ -3,18 +3,16 @@ import React, { useEffect, useState } from 'react';
|
|||||||
import rehypeStringify from 'rehype-stringify';
|
import rehypeStringify from 'rehype-stringify';
|
||||||
import remarkParse from 'remark-parse';
|
import remarkParse from 'remark-parse';
|
||||||
import remarkRehype from 'remark-rehype';
|
import remarkRehype from 'remark-rehype';
|
||||||
import { H1Title, IconRocket } from 'twenty-ui';
|
import { IconRocket } from 'twenty-ui';
|
||||||
import { unified } from 'unified';
|
import { unified } from 'unified';
|
||||||
import { visit } from 'unist-util-visit';
|
import { visit } from 'unist-util-visit';
|
||||||
|
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||||
|
|
||||||
const StyledH1Title = styled(H1Title)`
|
|
||||||
margin-bottom: 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
type ReleaseNote = {
|
type ReleaseNote = {
|
||||||
slug: string;
|
slug: string;
|
||||||
date: string;
|
date: string;
|
||||||
@@ -108,9 +106,20 @@ export const Releases = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer Icon={IconRocket} title="Releases">
|
<SubMenuTopBarContainer
|
||||||
|
Icon={IconRocket}
|
||||||
|
title="Releases"
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Others',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Releases),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: 'Releases',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<StyledH1Title title="Releases" />
|
|
||||||
<ScrollWrapper contextProviderName="releases">
|
<ScrollWrapper contextProviderName="releases">
|
||||||
<StyledReleaseContainer>
|
<StyledReleaseContainer>
|
||||||
{releases.map((release) => (
|
{releases.map((release) => (
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
|||||||
import { SettingsBillingCoverImage } from '@/billing/components/SettingsBillingCoverImage';
|
import { SettingsBillingCoverImage } from '@/billing/components/SettingsBillingCoverImage';
|
||||||
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
|
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { Info } from '@/ui/display/info/components/Info';
|
import { Info } from '@/ui/display/info/components/Info';
|
||||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
@@ -140,7 +142,17 @@ export const SettingsBilling = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer Icon={IconCurrencyDollar} title="Billing">
|
<SubMenuTopBarContainer
|
||||||
|
Icon={IconCurrencyDollar}
|
||||||
|
title="Billing"
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{ children: 'Billing' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<StyledH1Title title="Billing" />
|
<StyledH1Title title="Billing" />
|
||||||
<SettingsBillingCoverImage />
|
<SettingsBillingCoverImage />
|
||||||
|
|||||||
@@ -6,11 +6,23 @@ import { DeleteAccount } from '@/settings/profile/components/DeleteAccount';
|
|||||||
import { EmailField } from '@/settings/profile/components/EmailField';
|
import { EmailField } from '@/settings/profile/components/EmailField';
|
||||||
import { NameFields } from '@/settings/profile/components/NameFields';
|
import { NameFields } from '@/settings/profile/components/NameFields';
|
||||||
import { ProfilePictureUploader } from '@/settings/profile/components/ProfilePictureUploader';
|
import { ProfilePictureUploader } from '@/settings/profile/components/ProfilePictureUploader';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
|
|
||||||
export const SettingsProfile = () => (
|
export const SettingsProfile = () => (
|
||||||
<SubMenuTopBarContainer Icon={IconUserCircle} title="Profile">
|
<SubMenuTopBarContainer
|
||||||
|
Icon={IconUserCircle}
|
||||||
|
title="Profile"
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
children: 'User',
|
||||||
|
href: getSettingsPagePath(SettingsPath.ProfilePage),
|
||||||
|
},
|
||||||
|
{ children: 'Profile' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title title="Picture" />
|
<H2Title title="Picture" />
|
||||||
|
|||||||
@@ -2,14 +2,26 @@ import { H2Title, IconSettings } from 'twenty-ui';
|
|||||||
|
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { DeleteWorkspace } from '@/settings/profile/components/DeleteWorkspace';
|
import { DeleteWorkspace } from '@/settings/profile/components/DeleteWorkspace';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
import { NameField } from '@/settings/workspace/components/NameField';
|
import { NameField } from '@/settings/workspace/components/NameField';
|
||||||
import { ToggleImpersonate } from '@/settings/workspace/components/ToggleImpersonate';
|
import { ToggleImpersonate } from '@/settings/workspace/components/ToggleImpersonate';
|
||||||
import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader';
|
import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
|
|
||||||
export const SettingsWorkspace = () => (
|
export const SettingsWorkspace = () => (
|
||||||
<SubMenuTopBarContainer Icon={IconSettings} title="General">
|
<SubMenuTopBarContainer
|
||||||
|
Icon={IconSettings}
|
||||||
|
title="General"
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{ children: 'General' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title title="Picture" />
|
<H2Title title="Picture" />
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
|
|||||||
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { IconButton } from '@/ui/input/button/components/IconButton';
|
import { IconButton } from '@/ui/input/button/components/IconButton';
|
||||||
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
@@ -46,7 +48,17 @@ export const SettingsWorkspaceMembers = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer Icon={IconUsers} title="Members">
|
<SubMenuTopBarContainer
|
||||||
|
Icon={IconUsers}
|
||||||
|
title="Members"
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{ children: 'Members' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title
|
<H2Title
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export const Default: Story = {
|
|||||||
play: async ({ canvasElement }) => {
|
play: async ({ canvasElement }) => {
|
||||||
const canvas = within(canvasElement);
|
const canvas = within(canvasElement);
|
||||||
|
|
||||||
await canvas.findByText('Theme', undefined, {
|
await canvas.findByText('Appearance', undefined, {
|
||||||
timeout: 3000,
|
timeout: 3000,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import { SettingsAccountsBlocklistSection } from '@/settings/accounts/components
|
|||||||
import { SettingsAccountsConnectedAccountsListCard } from '@/settings/accounts/components/SettingsAccountsConnectedAccountsListCard';
|
import { SettingsAccountsConnectedAccountsListCard } from '@/settings/accounts/components/SettingsAccountsConnectedAccountsListCard';
|
||||||
import { SettingsAccountsSettingsSection } from '@/settings/accounts/components/SettingsAccountsSettingsSection';
|
import { SettingsAccountsSettingsSection } from '@/settings/accounts/components/SettingsAccountsSettingsSection';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
|
|
||||||
@@ -33,7 +35,17 @@ export const SettingsAccounts = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer Icon={IconAt} title="Account">
|
<SubMenuTopBarContainer
|
||||||
|
Icon={IconAt}
|
||||||
|
title="Account"
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
children: 'User',
|
||||||
|
href: getSettingsPagePath(SettingsPath.ProfilePage),
|
||||||
|
},
|
||||||
|
{ children: 'Account' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<SettingsAccountLoader />
|
<SettingsAccountLoader />
|
||||||
|
|||||||
@@ -4,24 +4,24 @@ import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
|||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { IconCalendarEvent } from 'twenty-ui';
|
import { IconCalendarEvent } from 'twenty-ui';
|
||||||
|
|
||||||
export const SettingsAccountsCalendars = () => {
|
export const SettingsAccountsCalendars = () => {
|
||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconCalendarEvent}
|
Icon={IconCalendarEvent}
|
||||||
title={
|
title="Calendars"
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
|
{
|
||||||
|
children: 'User',
|
||||||
|
href: getSettingsPagePath(SettingsPath.ProfilePage),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
children: 'Accounts',
|
children: 'Accounts',
|
||||||
href: getSettingsPagePath(SettingsPath.Accounts),
|
href: getSettingsPagePath(SettingsPath.Accounts),
|
||||||
},
|
},
|
||||||
{ children: 'Calendars' },
|
{ children: 'Calendars' },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<Section>
|
<Section>
|
||||||
|
|||||||
@@ -1,21 +1,26 @@
|
|||||||
import { SettingsAccountsMessageChannelsContainer } from '@/settings/accounts/components/SettingsAccountsMessageChannelsContainer';
|
import { SettingsAccountsMessageChannelsContainer } from '@/settings/accounts/components/SettingsAccountsMessageChannelsContainer';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { IconMail } from 'twenty-ui';
|
import { IconMail } from 'twenty-ui';
|
||||||
|
|
||||||
export const SettingsAccountsEmails = () => (
|
export const SettingsAccountsEmails = () => (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconMail}
|
Icon={IconMail}
|
||||||
title={
|
title="Emails"
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
{ children: 'Accounts', href: '/settings/accounts' },
|
{
|
||||||
|
children: 'User',
|
||||||
|
href: getSettingsPagePath(SettingsPath.ProfilePage),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: 'Accounts',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Accounts),
|
||||||
|
},
|
||||||
{ children: 'Emails' },
|
{ children: 'Emails' },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<Section>
|
<Section>
|
||||||
|
|||||||
@@ -1,21 +1,26 @@
|
|||||||
import { SettingsNewAccountSection } from '@/settings/accounts/components/SettingsNewAccountSection';
|
import { SettingsNewAccountSection } from '@/settings/accounts/components/SettingsNewAccountSection';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { IconAt } from 'twenty-ui';
|
import { IconAt } from 'twenty-ui';
|
||||||
|
|
||||||
export const SettingsNewAccount = () => {
|
export const SettingsNewAccount = () => {
|
||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconAt}
|
Icon={IconAt}
|
||||||
title={
|
title="New Account"
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
{ children: 'Accounts', href: '/settings/accounts' },
|
{
|
||||||
|
children: 'User',
|
||||||
|
href: getSettingsPagePath(SettingsPath.ProfilePage),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: 'Accounts',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Accounts),
|
||||||
|
},
|
||||||
{ children: `New` },
|
{ children: `New` },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<SettingsNewAccountSection />
|
<SettingsNewAccountSection />
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
|||||||
import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer';
|
import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { SettingsReadDocumentationButton } from '@/settings/developers/components/SettingsReadDocumentationButton';
|
import { SettingsReadDocumentationButton } from '@/settings/developers/components/SettingsReadDocumentationButton';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
const REVERT_PUBLIC_KEY = 'pk_live_a87fee8c-28c7-494f-99a3-996ff89f9918';
|
const REVERT_PUBLIC_KEY = 'pk_live_a87fee8c-28c7-494f-99a3-996ff89f9918';
|
||||||
@@ -18,7 +19,14 @@ export const SettingsCRMMigration = () => {
|
|||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconSettings}
|
Icon={IconSettings}
|
||||||
title={<Breadcrumb links={[{ children: 'Migrate' }]} />}
|
title="Migrate"
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{ children: 'Migrate' },
|
||||||
|
]}
|
||||||
actionButton={<SettingsReadDocumentationButton />}
|
actionButton={<SettingsReadDocumentationButton />}
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { z } from 'zod';
|
|||||||
import { useCreateOneObjectMetadataItem } from '@/object-metadata/hooks/useCreateOneObjectMetadataItem';
|
import { useCreateOneObjectMetadataItem } from '@/object-metadata/hooks/useCreateOneObjectMetadataItem';
|
||||||
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
|
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
|
||||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||||
import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer';
|
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import {
|
import {
|
||||||
SettingsDataModelObjectAboutForm,
|
SettingsDataModelObjectAboutForm,
|
||||||
@@ -20,7 +19,6 @@ import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/Snac
|
|||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
|
|
||||||
const newObjectFormSchema = settingsDataModelObjectAboutFormSchema;
|
const newObjectFormSchema = settingsDataModelObjectAboutFormSchema;
|
||||||
|
|
||||||
@@ -72,17 +70,18 @@ export const SettingsNewObject = () => {
|
|||||||
<FormProvider {...formConfig}>
|
<FormProvider {...formConfig}>
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconHierarchy2}
|
Icon={IconHierarchy2}
|
||||||
title={
|
title="New Object"
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
children: 'Objects',
|
children: 'Objects',
|
||||||
href: settingsObjectsPagePath,
|
href: settingsObjectsPagePath,
|
||||||
},
|
},
|
||||||
{ children: 'New' },
|
{ children: 'New' },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
actionButton={
|
actionButton={
|
||||||
<SaveAndCancelButtons
|
<SaveAndCancelButtons
|
||||||
isSaveDisabled={!canSave}
|
isSaveDisabled={!canSave}
|
||||||
@@ -93,7 +92,6 @@ export const SettingsNewObject = () => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<SettingsHeaderContainer></SettingsHeaderContainer>
|
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title
|
<H2Title
|
||||||
title="About"
|
title="About"
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { SettingsPath } from '@/types/SettingsPath';
|
|||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink';
|
import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { isNonEmptyArray } from '@sniptt/guards';
|
import { isNonEmptyArray } from '@sniptt/guards';
|
||||||
@@ -49,14 +48,15 @@ export const SettingsObjectDetailPageContent = ({
|
|||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconHierarchy2}
|
Icon={IconHierarchy2}
|
||||||
title={
|
title={objectMetadataItem.labelPlural}
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
{ children: 'Objects', href: '/settings/objects' },
|
{ children: 'Objects', href: '/settings/objects' },
|
||||||
{ children: objectMetadataItem.labelPlural },
|
{ children: objectMetadataItem.labelPlural },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<Section>
|
<Section>
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { useUpdateOneObjectMetadataItem } from '@/object-metadata/hooks/useUpdat
|
|||||||
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
|
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
|
||||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||||
import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer';
|
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import {
|
import {
|
||||||
SettingsDataModelObjectAboutForm,
|
SettingsDataModelObjectAboutForm,
|
||||||
@@ -30,7 +29,6 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
|||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
|
|
||||||
const objectEditFormSchema = z
|
const objectEditFormSchema = z
|
||||||
.object({})
|
.object({})
|
||||||
@@ -110,9 +108,12 @@ export const SettingsObjectEdit = () => {
|
|||||||
<FormProvider {...formConfig}>
|
<FormProvider {...formConfig}>
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconHierarchy2}
|
Icon={IconHierarchy2}
|
||||||
title={
|
title="Edit"
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
children: 'Objects',
|
children: 'Objects',
|
||||||
href: settingsObjectsPagePath,
|
href: settingsObjectsPagePath,
|
||||||
@@ -121,14 +122,10 @@ export const SettingsObjectEdit = () => {
|
|||||||
children: activeObjectMetadataItem.labelPlural,
|
children: activeObjectMetadataItem.labelPlural,
|
||||||
href: `${settingsObjectsPagePath}/${objectSlug}`,
|
href: `${settingsObjectsPagePath}/${objectSlug}`,
|
||||||
},
|
},
|
||||||
{ children: 'Edit' },
|
{ children: 'Edit Object' },
|
||||||
]}
|
]}
|
||||||
/>
|
actionButton={
|
||||||
}
|
activeObjectMetadataItem.isCustom && (
|
||||||
>
|
|
||||||
<SettingsPageContainer>
|
|
||||||
<SettingsHeaderContainer>
|
|
||||||
{activeObjectMetadataItem.isCustom && (
|
|
||||||
<SaveAndCancelButtons
|
<SaveAndCancelButtons
|
||||||
isSaveDisabled={!canSave}
|
isSaveDisabled={!canSave}
|
||||||
isCancelDisabled={isSubmitting}
|
isCancelDisabled={isSubmitting}
|
||||||
@@ -137,8 +134,10 @@ export const SettingsObjectEdit = () => {
|
|||||||
}
|
}
|
||||||
onSave={formConfig.handleSubmit(handleSave)}
|
onSave={formConfig.handleSubmit(handleSave)}
|
||||||
/>
|
/>
|
||||||
)}
|
)
|
||||||
</SettingsHeaderContainer>
|
}
|
||||||
|
>
|
||||||
|
<SettingsPageContainer>
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title
|
<H2Title
|
||||||
title="About"
|
title="About"
|
||||||
|
|||||||
@@ -26,13 +26,14 @@ import { SettingsDataModelFieldIconLabelForm } from '@/settings/data-model/field
|
|||||||
import { SettingsDataModelFieldSettingsFormCard } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard';
|
import { SettingsDataModelFieldSettingsFormCard } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard';
|
||||||
import { settingsFieldFormSchema } from '@/settings/data-model/fields/forms/validation-schemas/settingsFieldFormSchema';
|
import { settingsFieldFormSchema } from '@/settings/data-model/fields/forms/validation-schemas/settingsFieldFormSchema';
|
||||||
import { SettingsSupportedFieldType } from '@/settings/data-model/types/SettingsSupportedFieldType';
|
import { SettingsSupportedFieldType } from '@/settings/data-model/types/SettingsSupportedFieldType';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
@@ -173,23 +174,24 @@ export const SettingsObjectFieldEdit = () => {
|
|||||||
<FormProvider {...formConfig}>
|
<FormProvider {...formConfig}>
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconHierarchy2}
|
Icon={IconHierarchy2}
|
||||||
title={
|
title={activeMetadataField?.label}
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
children: 'Objects',
|
children: 'Objects',
|
||||||
href: '/settings/objects',
|
href: '/settings/objects',
|
||||||
styles: { minWidth: 'max-content' },
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
children: activeObjectMetadataItem.labelPlural,
|
children: activeObjectMetadataItem.labelPlural,
|
||||||
href: `/settings/objects/${objectSlug}`,
|
href: `/settings/objects/${objectSlug}`,
|
||||||
styles: { maxWidth: '60%' },
|
|
||||||
},
|
},
|
||||||
{ children: activeMetadataField.label },
|
{
|
||||||
|
children: activeMetadataField.label,
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
actionButton={
|
actionButton={
|
||||||
shouldDisplaySaveAndCancel && (
|
shouldDisplaySaveAndCancel && (
|
||||||
<SaveAndCancelButtons
|
<SaveAndCancelButtons
|
||||||
|
|||||||
@@ -9,11 +9,12 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain
|
|||||||
|
|
||||||
import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem';
|
import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem';
|
||||||
import { settingsObjectFieldsFamilyState } from '@/settings/data-model/object-details/states/settingsObjectFieldsFamilyState';
|
import { settingsObjectFieldsFamilyState } from '@/settings/data-model/object-details/states/settingsObjectFieldsFamilyState';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
import { SettingsObjectFieldTable } from '~/pages/settings/data-model/SettingsObjectFieldTable';
|
import { SettingsObjectFieldTable } from '~/pages/settings/data-model/SettingsObjectFieldTable';
|
||||||
|
|
||||||
@@ -86,9 +87,11 @@ export const SettingsObjectNewFieldStep1 = () => {
|
|||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconHierarchy2}
|
Icon={IconHierarchy2}
|
||||||
title={
|
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
{ children: 'Objects', href: '/settings/objects' },
|
{ children: 'Objects', href: '/settings/objects' },
|
||||||
{
|
{
|
||||||
children: activeObjectMetadataItem.labelPlural,
|
children: activeObjectMetadataItem.labelPlural,
|
||||||
@@ -96,8 +99,6 @@ export const SettingsObjectNewFieldStep1 = () => {
|
|||||||
},
|
},
|
||||||
{ children: 'New Field' },
|
{ children: 'New Field' },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
actionButton={
|
actionButton={
|
||||||
!activeObjectMetadataItem.isRemote && (
|
!activeObjectMetadataItem.isRemote && (
|
||||||
<SaveAndCancelButtons
|
<SaveAndCancelButtons
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/Snac
|
|||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { View } from '@/views/types/View';
|
import { View } from '@/views/types/View';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
import { useApolloClient } from '@apollo/client';
|
import { useApolloClient } from '@apollo/client';
|
||||||
@@ -41,6 +40,7 @@ type SettingsDataModelNewFieldFormValues = z.infer<
|
|||||||
|
|
||||||
const StyledH1Title = styled(H1Title)`
|
const StyledH1Title = styled(H1Title)`
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
padding-top: ${({ theme }) => theme.spacing(3)};
|
||||||
`;
|
`;
|
||||||
export const SettingsObjectNewFieldStep2 = () => {
|
export const SettingsObjectNewFieldStep2 = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -177,18 +177,14 @@ export const SettingsObjectNewFieldStep2 = () => {
|
|||||||
>
|
>
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconHierarchy2}
|
Icon={IconHierarchy2}
|
||||||
title={
|
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
{
|
{
|
||||||
children: 'Objects',
|
children: 'Objects',
|
||||||
href: '/settings/objects',
|
href: '/settings/objects',
|
||||||
styles: { minWidth: 'max-content' },
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
children: activeObjectMetadataItem.labelPlural,
|
children: activeObjectMetadataItem.labelPlural,
|
||||||
href: `/settings/objects/${objectSlug}`,
|
href: `/settings/objects/${objectSlug}`,
|
||||||
styles: { maxWidth: '50%' },
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
children: (
|
children: (
|
||||||
@@ -199,8 +195,6 @@ export const SettingsObjectNewFieldStep2 = () => {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
actionButton={
|
actionButton={
|
||||||
!activeObjectMetadataItem.isRemote && (
|
!activeObjectMetadataItem.isRemote && (
|
||||||
<SaveAndCancelButtons
|
<SaveAndCancelButtons
|
||||||
|
|||||||
@@ -1,24 +1,25 @@
|
|||||||
import { ReactFlowProvider } from 'reactflow';
|
import { ReactFlowProvider } from 'reactflow';
|
||||||
|
|
||||||
import { SettingsDataModelOverview } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverview';
|
import { SettingsDataModelOverview } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverview';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { IconHierarchy2 } from 'twenty-ui';
|
import { IconHierarchy2 } from 'twenty-ui';
|
||||||
|
|
||||||
export const SettingsObjectOverview = () => {
|
export const SettingsObjectOverview = () => {
|
||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconHierarchy2}
|
Icon={IconHierarchy2}
|
||||||
title={
|
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
{ children: 'Data model', href: '/settings/objects' },
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{ children: 'Objects', href: '/settings/objects' },
|
||||||
{
|
{
|
||||||
children: 'Overview',
|
children: 'Overview',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<SettingsDataModelOverview />
|
<SettingsDataModelOverview />
|
||||||
|
|||||||
@@ -145,6 +145,15 @@ export const SettingsObjects = () => {
|
|||||||
/>
|
/>
|
||||||
</UndecoratedLink>
|
</UndecoratedLink>
|
||||||
}
|
}
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: 'Objects',
|
||||||
|
},
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ export type Story = StoryObj<typeof SettingsObjectNewFieldStep1>;
|
|||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
play: async ({ canvasElement }) => {
|
play: async ({ canvasElement }) => {
|
||||||
const canvas = within(canvasElement);
|
const canvas = within(canvasElement);
|
||||||
await canvas.findByText('Settings');
|
|
||||||
await canvas.findByText('Objects');
|
await canvas.findByText('Objects');
|
||||||
await canvas.findByText('Companies');
|
await canvas.findByText('Companies');
|
||||||
await canvas.findByText('Check deactivated fields');
|
await canvas.findByText('Check deactivated fields');
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain
|
|||||||
import { SettingsApiKeysTable } from '@/settings/developers/components/SettingsApiKeysTable';
|
import { SettingsApiKeysTable } from '@/settings/developers/components/SettingsApiKeysTable';
|
||||||
import { SettingsReadDocumentationButton } from '@/settings/developers/components/SettingsReadDocumentationButton';
|
import { SettingsReadDocumentationButton } from '@/settings/developers/components/SettingsReadDocumentationButton';
|
||||||
import { SettingsWebhooksTable } from '@/settings/developers/components/SettingsWebhooksTable';
|
import { SettingsWebhooksTable } from '@/settings/developers/components/SettingsWebhooksTable';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
@@ -21,6 +23,13 @@ export const SettingsDevelopers = () => {
|
|||||||
Icon={IconCode}
|
Icon={IconCode}
|
||||||
title="Developers"
|
title="Developers"
|
||||||
actionButton={<SettingsReadDocumentationButton />}
|
actionButton={<SettingsReadDocumentationButton />}
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{ children: 'Developers' },
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<Section>
|
<Section>
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ export type Story = StoryObj<typeof SettingsDevelopersApiKeysNew>;
|
|||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
play: async ({ canvasElement }) => {
|
play: async ({ canvasElement }) => {
|
||||||
const canvas = within(canvasElement);
|
const canvas = within(canvasElement);
|
||||||
await canvas.findByText('Settings');
|
await canvas.findByText('New Key');
|
||||||
await canvas.findByText('New API Key');
|
|
||||||
await canvas.findByText('Name');
|
await canvas.findByText('Name');
|
||||||
await canvas.findByText('Expiration Date');
|
await canvas.findByText('Expiration Date');
|
||||||
|
|
||||||
|
|||||||
@@ -17,12 +17,13 @@ import { apiKeyTokenState } from '@/settings/developers/states/generatedApiKeyTo
|
|||||||
import { ApiKey } from '@/settings/developers/types/api-key/ApiKey';
|
import { ApiKey } from '@/settings/developers/types/api-key/ApiKey';
|
||||||
import { computeNewExpirationDate } from '@/settings/developers/utils/compute-new-expiration-date';
|
import { computeNewExpirationDate } from '@/settings/developers/utils/compute-new-expiration-date';
|
||||||
import { formatExpiration } from '@/settings/developers/utils/format-expiration';
|
import { formatExpiration } from '@/settings/developers/utils/format-expiration';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
import { TextInput } from '@/ui/input/components/TextInput';
|
import { TextInput } from '@/ui/input/components/TextInput';
|
||||||
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { useGenerateApiKeyTokenMutation } from '~/generated/graphql';
|
import { useGenerateApiKeyTokenMutation } from '~/generated/graphql';
|
||||||
|
|
||||||
const StyledInfo = styled.span`
|
const StyledInfo = styled.span`
|
||||||
@@ -65,6 +66,7 @@ export const SettingsDevelopersApiKeyDetail = () => {
|
|||||||
setApiKeyName(record.name);
|
setApiKeyName(record.name);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const developerPath = getSettingsPagePath(SettingsPath.Developers);
|
||||||
|
|
||||||
const deleteIntegration = async (redirect = true) => {
|
const deleteIntegration = async (redirect = true) => {
|
||||||
await updateApiKey?.({
|
await updateApiKey?.({
|
||||||
@@ -72,7 +74,7 @@ export const SettingsDevelopersApiKeyDetail = () => {
|
|||||||
updateOneRecordInput: { revokedAt: DateTime.now().toString() },
|
updateOneRecordInput: { revokedAt: DateTime.now().toString() },
|
||||||
});
|
});
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
navigate('/settings/developers');
|
navigate(developerPath);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -122,14 +124,15 @@ export const SettingsDevelopersApiKeyDetail = () => {
|
|||||||
{apiKeyData?.name && (
|
{apiKeyData?.name && (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconCode}
|
Icon={IconCode}
|
||||||
title={
|
title={apiKeyData?.name}
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
{ children: 'Developers', href: '/settings/developers' },
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{ children: 'Developers', href: developerPath },
|
||||||
{ children: `${apiKeyName} API Key` },
|
{ children: `${apiKeyName} API Key` },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<Section>
|
<Section>
|
||||||
|
|||||||
@@ -10,11 +10,12 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain
|
|||||||
import { EXPIRATION_DATES } from '@/settings/developers/constants/ExpirationDates';
|
import { EXPIRATION_DATES } from '@/settings/developers/constants/ExpirationDates';
|
||||||
import { apiKeyTokenState } from '@/settings/developers/states/generatedApiKeyTokenState';
|
import { apiKeyTokenState } from '@/settings/developers/states/generatedApiKeyTokenState';
|
||||||
import { ApiKey } from '@/settings/developers/types/api-key/ApiKey';
|
import { ApiKey } from '@/settings/developers/types/api-key/ApiKey';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { Select } from '@/ui/input/components/Select';
|
import { Select } from '@/ui/input/components/Select';
|
||||||
import { TextInput } from '@/ui/input/components/TextInput';
|
import { TextInput } from '@/ui/input/components/TextInput';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
import { useGenerateApiKeyTokenMutation } from '~/generated/graphql';
|
import { useGenerateApiKeyTokenMutation } from '~/generated/graphql';
|
||||||
@@ -65,14 +66,18 @@ export const SettingsDevelopersApiKeysNew = () => {
|
|||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconCode}
|
Icon={IconCode}
|
||||||
title={
|
title="New key"
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
{ children: 'Developers', href: '/settings/developers' },
|
{
|
||||||
{ children: 'New API Key' },
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: 'Developers',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Developers),
|
||||||
|
},
|
||||||
|
{ children: 'New Key' },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
actionButton={
|
actionButton={
|
||||||
<SaveAndCancelButtons
|
<SaveAndCancelButtons
|
||||||
isSaveDisabled={!canSave}
|
isSaveDisabled={!canSave}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
|||||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { Webhook } from '@/settings/developers/types/webhook/Webhook';
|
import { Webhook } from '@/settings/developers/types/webhook/Webhook';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
import { Select } from '@/ui/input/components/Select';
|
import { Select } from '@/ui/input/components/Select';
|
||||||
import { TextArea } from '@/ui/input/components/TextArea';
|
import { TextArea } from '@/ui/input/components/TextArea';
|
||||||
@@ -18,7 +20,6 @@ import { TextInput } from '@/ui/input/components/TextInput';
|
|||||||
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
|
|
||||||
const StyledFilterRow = styled.div`
|
const StyledFilterRow = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -55,9 +56,11 @@ export const SettingsDevelopersWebhooksDetail = () => {
|
|||||||
objectNameSingular: CoreObjectNameSingular.Webhook,
|
objectNameSingular: CoreObjectNameSingular.Webhook,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const developerPath = getSettingsPagePath(SettingsPath.Developers);
|
||||||
|
|
||||||
const deleteWebhook = () => {
|
const deleteWebhook = () => {
|
||||||
deleteOneWebhook(webhookId);
|
deleteOneWebhook(webhookId);
|
||||||
navigate('/settings/developers');
|
navigate(developerPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
const fieldTypeOptions = [
|
const fieldTypeOptions = [
|
||||||
@@ -81,7 +84,7 @@ export const SettingsDevelopersWebhooksDetail = () => {
|
|||||||
description: description,
|
description: description,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
navigate('/settings/developers');
|
navigate(developerPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -89,19 +92,23 @@ export const SettingsDevelopersWebhooksDetail = () => {
|
|||||||
{webhookData?.targetUrl && (
|
{webhookData?.targetUrl && (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconCode}
|
Icon={IconCode}
|
||||||
title={
|
title={webhookData.targetUrl}
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
{ children: 'Developers', href: '/settings/developers' },
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: 'Developers',
|
||||||
|
href: developerPath,
|
||||||
|
},
|
||||||
{ children: 'Webhook' },
|
{ children: 'Webhook' },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
actionButton={
|
actionButton={
|
||||||
<SaveAndCancelButtons
|
<SaveAndCancelButtons
|
||||||
isSaveDisabled={!isDirty}
|
isSaveDisabled={!isDirty}
|
||||||
onCancel={() => {
|
onCancel={() => {
|
||||||
navigate('/settings/developers');
|
navigate(developerPath);
|
||||||
}}
|
}}
|
||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
|||||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { Webhook } from '@/settings/developers/types/webhook/Webhook';
|
import { Webhook } from '@/settings/developers/types/webhook/Webhook';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { TextInput } from '@/ui/input/components/TextInput';
|
import { TextInput } from '@/ui/input/components/TextInput';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { isValidUrl } from '~/utils/url/isValidUrl';
|
import { isValidUrl } from '~/utils/url/isValidUrl';
|
||||||
|
|
||||||
export const SettingsDevelopersWebhooksNew = () => {
|
export const SettingsDevelopersWebhooksNew = () => {
|
||||||
@@ -49,19 +50,23 @@ export const SettingsDevelopersWebhooksNew = () => {
|
|||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconCode}
|
Icon={IconCode}
|
||||||
title={
|
title="New Webhook"
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
{ children: 'Developers', href: '/settings/developers' },
|
{
|
||||||
{ children: 'New webhook' },
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: 'Developers',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Developers),
|
||||||
|
},
|
||||||
|
{ children: 'New Webhook' },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
actionButton={
|
actionButton={
|
||||||
<SaveAndCancelButtons
|
<SaveAndCancelButtons
|
||||||
isSaveDisabled={!canSave}
|
isSaveDisabled={!canSave}
|
||||||
onCancel={() => {
|
onCancel={() => {
|
||||||
navigate('/settings/developers');
|
navigate(getSettingsPagePath(SettingsPath.Developers));
|
||||||
}}
|
}}
|
||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { AppPath } from '@/types/AppPath';
|
|||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
|
|
||||||
export const SettingsIntegrationDatabase = () => {
|
export const SettingsIntegrationDatabase = () => {
|
||||||
const { databaseKey = '' } = useParams();
|
const { databaseKey = '' } = useParams();
|
||||||
@@ -44,17 +43,18 @@ export const SettingsIntegrationDatabase = () => {
|
|||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconSettings}
|
Icon={IconSettings}
|
||||||
title={
|
title={integration.text}
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
children: 'Integrations',
|
children: 'Integrations',
|
||||||
href: getSettingsPagePath(SettingsPath.Integrations),
|
href: getSettingsPagePath(SettingsPath.Integrations),
|
||||||
},
|
},
|
||||||
{ children: integration.text },
|
{ children: integration.text },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<SettingsIntegrationPreview
|
<SettingsIntegrationPreview
|
||||||
|
|||||||
@@ -2,21 +2,26 @@ import { IconSettings } from 'twenty-ui';
|
|||||||
|
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { SettingsIntegrationEditDatabaseConnectionContainer } from '@/settings/integrations/database-connection/components/SettingsIntegrationEditDatabaseConnectionContainer';
|
import { SettingsIntegrationEditDatabaseConnectionContainer } from '@/settings/integrations/database-connection/components/SettingsIntegrationEditDatabaseConnectionContainer';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
|
|
||||||
export const SettingsIntegrationEditDatabaseConnection = () => {
|
export const SettingsIntegrationEditDatabaseConnection = () => {
|
||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconSettings}
|
Icon={IconSettings}
|
||||||
title={
|
title="Edit connection"
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
// TODO
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: 'Integrations',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Integrations),
|
||||||
|
},
|
||||||
{ children: 'Edit connection' },
|
{ children: 'Edit connection' },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<SettingsIntegrationEditDatabaseConnectionContainer />
|
<SettingsIntegrationEditDatabaseConnectionContainer />
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/Snac
|
|||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { CreateRemoteServerInput } from '~/generated-metadata/graphql';
|
import { CreateRemoteServerInput } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
const createRemoteServerInputPostgresSchema =
|
const createRemoteServerInputPostgresSchema =
|
||||||
@@ -133,9 +132,12 @@ export const SettingsIntegrationNewDatabaseConnection = () => {
|
|||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconSettings}
|
Icon={IconSettings}
|
||||||
title={
|
title="New"
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
children: 'Integrations',
|
children: 'Integrations',
|
||||||
href: settingsIntegrationsPagePath,
|
href: settingsIntegrationsPagePath,
|
||||||
@@ -146,8 +148,6 @@ export const SettingsIntegrationNewDatabaseConnection = () => {
|
|||||||
},
|
},
|
||||||
{ children: 'New' },
|
{ children: 'New' },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
actionButton={
|
actionButton={
|
||||||
<SaveAndCancelButtons
|
<SaveAndCancelButtons
|
||||||
isSaveDisabled={!canSave}
|
isSaveDisabled={!canSave}
|
||||||
|
|||||||
@@ -2,11 +2,27 @@ import { IconSettings } from 'twenty-ui';
|
|||||||
|
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { SettingsIntegrationDatabaseConnectionShowContainer } from '@/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionShowContainer';
|
import { SettingsIntegrationDatabaseConnectionShowContainer } from '@/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionShowContainer';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
|
|
||||||
export const SettingsIntegrationShowDatabaseConnection = () => {
|
export const SettingsIntegrationShowDatabaseConnection = () => {
|
||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer Icon={IconSettings} title="Settings">
|
<SubMenuTopBarContainer
|
||||||
|
Icon={IconSettings}
|
||||||
|
title="Database Connection"
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: 'Integrations',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Integrations),
|
||||||
|
},
|
||||||
|
{ children: 'Database Connection' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<SettingsIntegrationDatabaseConnectionShowContainer />
|
<SettingsIntegrationDatabaseConnectionShowContainer />
|
||||||
</SettingsPageContainer>
|
</SettingsPageContainer>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { SettingsIntegrationGroup } from '@/settings/integrations/components/SettingsIntegrationGroup';
|
import { SettingsIntegrationGroup } from '@/settings/integrations/components/SettingsIntegrationGroup';
|
||||||
import { useSettingsIntegrationCategories } from '@/settings/integrations/hooks/useSettingsIntegrationCategories';
|
import { useSettingsIntegrationCategories } from '@/settings/integrations/hooks/useSettingsIntegrationCategories';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { IconApps } from 'twenty-ui';
|
import { IconApps } from 'twenty-ui';
|
||||||
|
|
||||||
@@ -8,7 +10,17 @@ export const SettingsIntegrations = () => {
|
|||||||
const integrationCategories = useSettingsIntegrationCategories();
|
const integrationCategories = useSettingsIntegrationCategories();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer Icon={IconApps} title="Integrations">
|
<SubMenuTopBarContainer
|
||||||
|
Icon={IconApps}
|
||||||
|
title="Integrations"
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{ children: 'Integrations' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
{integrationCategories.map((group) => (
|
{integrationCategories.map((group) => (
|
||||||
<SettingsIntegrationGroup key={group.key} integrationGroup={group} />
|
<SettingsIntegrationGroup key={group.key} integrationGroup={group} />
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { H2Title, IconColorSwatch } from 'twenty-ui';
|
import { H2Title, IconColorSwatch } from 'twenty-ui';
|
||||||
|
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { ColorSchemePicker } from '@/ui/input/color-scheme/components/ColorSchemePicker';
|
import { ColorSchemePicker } from '@/ui/input/color-scheme/components/ColorSchemePicker';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
@@ -11,10 +13,20 @@ export const SettingsAppearance = () => {
|
|||||||
const { colorScheme, setColorScheme } = useColorScheme();
|
const { colorScheme, setColorScheme } = useColorScheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer Icon={IconColorSwatch} title="Appearance">
|
<SubMenuTopBarContainer
|
||||||
|
Icon={IconColorSwatch}
|
||||||
|
title="Experience"
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
children: 'User',
|
||||||
|
href: getSettingsPagePath(SettingsPath.ProfilePage),
|
||||||
|
},
|
||||||
|
{ children: 'Experience' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title title="Theme" />
|
<H2Title title="Appearance" />
|
||||||
<ColorSchemePicker value={colorScheme} onChange={setColorScheme} />
|
<ColorSchemePicker value={colorScheme} onChange={setColorScheme} />
|
||||||
</Section>
|
</Section>
|
||||||
<Section>
|
<Section>
|
||||||
|
|||||||
@@ -4,25 +4,26 @@ import { SettingsServerlessFunctionSettingsTab } from '@/settings/serverless-fun
|
|||||||
import { SettingsServerlessFunctionTestTab } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTab';
|
import { SettingsServerlessFunctionTestTab } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTab';
|
||||||
import { SettingsServerlessFunctionTestTabEffect } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTabEffect';
|
import { SettingsServerlessFunctionTestTabEffect } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTabEffect';
|
||||||
import { useExecuteOneServerlessFunction } from '@/settings/serverless-functions/hooks/useExecuteOneServerlessFunction';
|
import { useExecuteOneServerlessFunction } from '@/settings/serverless-functions/hooks/useExecuteOneServerlessFunction';
|
||||||
|
import { useGetOneServerlessFunctionSourceCode } from '@/settings/serverless-functions/hooks/useGetOneServerlessFunctionSourceCode';
|
||||||
|
import { usePublishOneServerlessFunction } from '@/settings/serverless-functions/hooks/usePublishOneServerlessFunction';
|
||||||
import { useServerlessFunctionUpdateFormState } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState';
|
import { useServerlessFunctionUpdateFormState } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState';
|
||||||
import { useUpdateOneServerlessFunction } from '@/settings/serverless-functions/hooks/useUpdateOneServerlessFunction';
|
import { useUpdateOneServerlessFunction } from '@/settings/serverless-functions/hooks/useUpdateOneServerlessFunction';
|
||||||
import { usePublishOneServerlessFunction } from '@/settings/serverless-functions/hooks/usePublishOneServerlessFunction';
|
|
||||||
import { settingsServerlessFunctionInputState } from '@/settings/serverless-functions/states/settingsServerlessFunctionInputState';
|
import { settingsServerlessFunctionInputState } from '@/settings/serverless-functions/states/settingsServerlessFunctionInputState';
|
||||||
import { settingsServerlessFunctionOutputState } from '@/settings/serverless-functions/states/settingsServerlessFunctionOutputState';
|
import { settingsServerlessFunctionOutputState } from '@/settings/serverless-functions/states/settingsServerlessFunctionOutputState';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { TabList } from '@/ui/layout/tab/components/TabList';
|
import { TabList } from '@/ui/layout/tab/components/TabList';
|
||||||
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
|
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
import { useState } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
import { IconCode, IconFunction, IconSettings, IconTestPipe } from 'twenty-ui';
|
import { IconCode, IconFunction, IconSettings, IconTestPipe } from 'twenty-ui';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
|
||||||
import { useGetOneServerlessFunctionSourceCode } from '@/settings/serverless-functions/hooks/useGetOneServerlessFunctionSourceCode';
|
|
||||||
import { useState } from 'react';
|
|
||||||
import { usePreventOverlapCallback } from '~/hooks/usePreventOverlapCallback';
|
import { usePreventOverlapCallback } from '~/hooks/usePreventOverlapCallback';
|
||||||
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
const TAB_LIST_COMPONENT_ID = 'serverless-function-detail';
|
const TAB_LIST_COMPONENT_ID = 'serverless-function-detail';
|
||||||
|
|
||||||
@@ -204,14 +205,18 @@ export const SettingsServerlessFunctionDetail = () => {
|
|||||||
!loading && (
|
!loading && (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconFunction}
|
Icon={IconFunction}
|
||||||
title={
|
title={formValues.name}
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
{ children: 'Functions', href: '/settings/functions' },
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: 'Functions',
|
||||||
|
href: getSettingsPagePath(SettingsPath.ServerlessFunctions),
|
||||||
|
},
|
||||||
{ children: `${formValues.name}` },
|
{ children: `${formValues.name}` },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<Section>
|
<Section>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer';
|
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { SettingsServerlessFunctionsTable } from '@/settings/serverless-functions/components/SettingsServerlessFunctionsTable';
|
import { SettingsServerlessFunctionsTable } from '@/settings/serverless-functions/components/SettingsServerlessFunctionsTable';
|
||||||
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
@@ -6,7 +5,6 @@ import { SettingsPath } from '@/types/SettingsPath';
|
|||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink';
|
import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink';
|
||||||
import { IconFunction, IconPlus } from 'twenty-ui';
|
import { IconFunction, IconPlus } from 'twenty-ui';
|
||||||
|
|
||||||
@@ -27,11 +25,17 @@ export const SettingsServerlessFunctions = () => {
|
|||||||
/>
|
/>
|
||||||
</UndecoratedLink>
|
</UndecoratedLink>
|
||||||
}
|
}
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: 'Functions',
|
||||||
|
},
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<SettingsHeaderContainer>
|
|
||||||
<Breadcrumb links={[{ children: 'Functions' }]} />
|
|
||||||
</SettingsHeaderContainer>
|
|
||||||
<Section>
|
<Section>
|
||||||
<SettingsServerlessFunctionsTable />
|
<SettingsServerlessFunctionsTable />
|
||||||
</Section>
|
</Section>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { SettingsServerlessFunctionNewForm } from '@/settings/serverless-functions/components/SettingsServerlessFunctionNewForm';
|
import { SettingsServerlessFunctionNewForm } from '@/settings/serverless-functions/components/SettingsServerlessFunctionNewForm';
|
||||||
@@ -81,14 +80,18 @@ export const SettingsServerlessFunctionsNew = () => {
|
|||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconFunction}
|
Icon={IconFunction}
|
||||||
title={
|
title="New Function"
|
||||||
<Breadcrumb
|
|
||||||
links={[
|
links={[
|
||||||
{ children: 'Functions', href: '/settings/functions' },
|
{
|
||||||
|
children: 'Workspace',
|
||||||
|
href: getSettingsPagePath(SettingsPath.Workspace),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: 'Functions',
|
||||||
|
href: getSettingsPagePath(SettingsPath.ServerlessFunctions),
|
||||||
|
},
|
||||||
{ children: 'New' },
|
{ children: 'New' },
|
||||||
]}
|
]}
|
||||||
/>
|
|
||||||
}
|
|
||||||
actionButton={
|
actionButton={
|
||||||
<SaveAndCancelButtons
|
<SaveAndCancelButtons
|
||||||
isSaveDisabled={!canSave}
|
isSaveDisabled={!canSave}
|
||||||
|
|||||||
Reference in New Issue
Block a user