From e8b6b1b94148fd890b9cd90ca5970bc0ba77cf75 Mon Sep 17 00:00:00 2001 From: Antoine Moreaux Date: Mon, 3 Mar 2025 17:06:16 +0100 Subject: [PATCH] fix(): several ui improvements (#10556) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Close #10531 --------- Co-authored-by: Lucas Bordeau Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com> Co-authored-by: Raphaƫl Bosi <71827178+bosiraphael@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Crowdin Bot Co-authored-by: github-actions --- .../twenty-front/src/generated/graphql.tsx | 5 +- packages/twenty-front/src/index.css | 2 +- .../auth/states/currentWorkspaceState.ts | 1 + ...ColumnDefinitionsFromFieldMetadata.test.ts | 2 + .../settings/components/SettingsCard.tsx | 9 ++-- .../components/SettingsPageContainer.tsx | 1 + .../ui/input/components/TextInputV2.tsx | 16 +------ .../graphql/fragments/userQueryFragment.ts | 1 + .../src/pages/settings/SettingsWorkspace.tsx | 5 +- .../workspace/SettingsCustomDomain.tsx | 24 ++++++++-- .../workspace/SettingsCustomDomainEffect.tsx | 48 ------------------- .../workspace/SettingsCustomDomainRecords.tsx | 16 ++++--- .../settings/workspace/SettingsDomain.tsx | 8 +--- .../settings/workspace/SettingsSubdomain.tsx | 19 ++------ .../hooks/useCheckCustomDomainValidRecords.ts | 32 +++++++++++++ 15 files changed, 88 insertions(+), 101 deletions(-) delete mode 100644 packages/twenty-front/src/pages/settings/workspace/SettingsCustomDomainEffect.tsx create mode 100644 packages/twenty-front/src/pages/settings/workspace/hooks/useCheckCustomDomainValidRecords.ts diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index c3bfd0269..ac5865902 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -2482,7 +2482,7 @@ export type GetSsoIdentityProvidersQueryVariables = Exact<{ [key: string]: never export type GetSsoIdentityProvidersQuery = { __typename?: 'Query', getSSOIdentityProviders: Array<{ __typename?: 'FindAvailableSSOIDPOutput', type: IdentityProviderType, id: string, name: string, issuer: string, status: SsoIdentityProviderStatus }> }; -export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, analyticsTinybirdJwts?: { __typename?: 'AnalyticsTinybirdJwtMap', getWebhookAnalytics: string, getPageviewsAnalytics: string, getUsersAnalytics: string, getServerlessFunctionDuration: string, getServerlessFunctionSuccessRate: string, getServerlessFunctionErrorCount: string } | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array | null, objectRecordsPermissions?: Array | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, metadataVersion: number, workspaceMembersCount?: number | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, subdomain: string, customDomain?: string | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null } } | null }> }; +export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, analyticsTinybirdJwts?: { __typename?: 'AnalyticsTinybirdJwtMap', getWebhookAnalytics: string, getPageviewsAnalytics: string, getUsersAnalytics: string, getServerlessFunctionDuration: string, getServerlessFunctionSuccessRate: string, getServerlessFunctionErrorCount: string } | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array | null, objectRecordsPermissions?: Array | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, subdomain: string, customDomain?: string | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null } } | null }> }; export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>; @@ -2499,7 +2499,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>; -export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, analyticsTinybirdJwts?: { __typename?: 'AnalyticsTinybirdJwtMap', getWebhookAnalytics: string, getPageviewsAnalytics: string, getUsersAnalytics: string, getServerlessFunctionDuration: string, getServerlessFunctionSuccessRate: string, getServerlessFunctionErrorCount: string } | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array | null, objectRecordsPermissions?: Array | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, metadataVersion: number, workspaceMembersCount?: number | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, subdomain: string, customDomain?: string | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null } } | null }> } }; +export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, analyticsTinybirdJwts?: { __typename?: 'AnalyticsTinybirdJwtMap', getWebhookAnalytics: string, getPageviewsAnalytics: string, getUsersAnalytics: string, getServerlessFunctionDuration: string, getServerlessFunctionSuccessRate: string, getServerlessFunctionErrorCount: string } | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array | null, objectRecordsPermissions?: Array | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, subdomain: string, customDomain?: string | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null } } | null }> } }; export type ActivateWorkflowVersionMutationVariables = Exact<{ workflowVersionId: Scalars['String']; @@ -2793,6 +2793,7 @@ export const UserQueryFragmentFragmentDoc = gql` subdomain hasValidEnterpriseKey customDomain + isCustomDomainEnabled workspaceUrls { subdomainUrl customUrl diff --git a/packages/twenty-front/src/index.css b/packages/twenty-front/src/index.css index 927b31a09..e7b2dce9b 100644 --- a/packages/twenty-front/src/index.css +++ b/packages/twenty-front/src/index.css @@ -14,7 +14,7 @@ button { } form { - width: 100%; + display: contents; } /* https://stackoverflow.com/questions/44543157/how-to-hide-the-google-invisible-recaptcha-badge */ diff --git a/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts b/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts index 7fa96d5ea..2a8dd59cf 100644 --- a/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts +++ b/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts @@ -19,6 +19,7 @@ export type CurrentWorkspace = Pick< | 'isMicrosoftAuthEnabled' | 'isPasswordAuthEnabled' | 'hasValidEnterpriseKey' + | 'isCustomDomainEnabled' | 'subdomain' | 'customDomain' | 'workspaceUrls' diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useColumnDefinitionsFromFieldMetadata.test.ts b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useColumnDefinitionsFromFieldMetadata.test.ts index 97dff2dc5..1edaf1d60 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useColumnDefinitionsFromFieldMetadata.test.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useColumnDefinitionsFromFieldMetadata.test.ts @@ -28,6 +28,8 @@ const Wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({ isGoogleAuthEnabled: true, isMicrosoftAuthEnabled: false, isPasswordAuthEnabled: true, + customDomain: 'my-custom-domain.com', + isCustomDomainEnabled: true, workspaceUrls: { subdomainUrl: 'https://twenty.twenty.com', customUrl: 'https://my-custom-domain.com', diff --git a/packages/twenty-front/src/modules/settings/components/SettingsCard.tsx b/packages/twenty-front/src/modules/settings/components/SettingsCard.tsx index 5d2b100f3..9e659c7bd 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsCard.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsCard.tsx @@ -24,10 +24,6 @@ const StyledCard = styled(Card)<{ cursor: ${({ disabled, onClick }) => disabled ? 'not-allowed' : onClick ? 'pointer' : 'default'}; width: 100%; - & :hover { - background-color: ${({ theme }) => theme.background.quaternary}; - cursor: pointer; - } `; const StyledCardContent = styled(CardContent)` @@ -35,6 +31,11 @@ const StyledCardContent = styled(CardContent)` flex-direction: column; gap: ${({ theme }) => theme.spacing(2)}; padding: ${({ theme }) => theme.spacing(2, 2)}; + + &:hover { + background-color: ${({ theme }) => theme.background.quaternary}; + cursor: pointer; + } `; const StyledHeader = styled.div` diff --git a/packages/twenty-front/src/modules/settings/components/SettingsPageContainer.tsx b/packages/twenty-front/src/modules/settings/components/SettingsPageContainer.tsx index f2f1a7300..b9ba3c4e2 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsPageContainer.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsPageContainer.tsx @@ -23,6 +23,7 @@ const StyledSettingsPageContainer = styled.div<{ return OBJECT_SETTINGS_WIDTH + 'px'; }}; padding-bottom: ${({ theme }) => theme.spacing(20)}; + height: 100%; `; export const SettingsPageContainer = ({ diff --git a/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx b/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx index a152959e0..c1e74c582 100644 --- a/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx @@ -11,13 +11,7 @@ import { useRef, useState, } from 'react'; -import { - AutogrowWrapper, - IconComponent, - IconEye, - IconEyeOff, - Loader, -} from 'twenty-ui'; +import { AutogrowWrapper, IconComponent, IconEye, IconEyeOff } from 'twenty-ui'; import { useCombinedRefs } from '~/hooks/useCombinedRefs'; import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly'; @@ -202,7 +196,6 @@ export type TextInputV2ComponentProps = Omit< dataTestId?: string; sizeVariant?: TextInputV2Size; inheritFontStyles?: boolean; - loading?: boolean; rightAdornment?: string; leftAdornment?: string; }; @@ -240,7 +233,6 @@ const TextInputV2Component = forwardRef< inheritFontStyles = false, dataTestId, autoGrow = false, - loading = false, rightAdornment, leftAdornment, }, @@ -349,12 +341,6 @@ const TextInputV2Component = forwardRef< )} - - {!error && type !== INPUT_TYPE_PASSWORD && !!loading && ( - - - - )} {!noErrorHelper && error && ( diff --git a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts index 6ce9779eb..6831cf64c 100644 --- a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts +++ b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts @@ -45,6 +45,7 @@ export const USER_QUERY_FRAGMENT = gql` subdomain hasValidEnterpriseKey customDomain + isCustomDomainEnabled workspaceUrls { subdomainUrl customUrl diff --git a/packages/twenty-front/src/pages/settings/SettingsWorkspace.tsx b/packages/twenty-front/src/pages/settings/SettingsWorkspace.tsx index c7cb7ab74..183b95408 100644 --- a/packages/twenty-front/src/pages/settings/SettingsWorkspace.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsWorkspace.tsx @@ -56,8 +56,11 @@ export const SettingsWorkspace = () => { title={t`Customize Domain`} Icon={} Status={ - currentWorkspace?.customDomain ? ( + currentWorkspace?.customDomain && + currentWorkspace?.isCustomDomainEnabled ? ( + ) : currentWorkspace?.customDomain ? ( + ) : undefined } /> diff --git a/packages/twenty-front/src/pages/settings/workspace/SettingsCustomDomain.tsx b/packages/twenty-front/src/pages/settings/workspace/SettingsCustomDomain.tsx index a07420c3f..908c67544 100644 --- a/packages/twenty-front/src/pages/settings/workspace/SettingsCustomDomain.tsx +++ b/packages/twenty-front/src/pages/settings/workspace/SettingsCustomDomain.tsx @@ -3,16 +3,21 @@ import { TextInputV2 } from '@/ui/input/components/TextInputV2'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; import { Controller, useFormContext } from 'react-hook-form'; -import { H2Title, Section } from 'twenty-ui'; +import { Button, H2Title, IconReload, Section } from 'twenty-ui'; import { SettingsCustomDomainRecords } from '~/pages/settings/workspace/SettingsCustomDomainRecords'; import { SettingsCustomDomainRecordsStatus } from '~/pages/settings/workspace/SettingsCustomDomainRecordsStatus'; import { customDomainRecordsState } from '~/pages/settings/workspace/states/customDomainRecordsState'; import { useRecoilValue } from 'recoil'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; +import { useCheckCustomDomainValidRecords } from '~/pages/settings/workspace/hooks/useCheckCustomDomainValidRecords'; const StyledDomainFormWrapper = styled.div` - align-items: center; display: flex; + gap: ${({ theme }) => theme.spacing(2)}; +`; + +const StyledButton = styled(Button)` + align-self: flex-start; `; const StyledRecordsWrapper = styled.div` @@ -28,6 +33,12 @@ export const SettingsCustomDomain = () => { customDomainRecordsState, ); + const { checkCustomDomainRecords } = useCheckCustomDomainValidRecords(); + + if (!customDomainRecords && !loading) { + checkCustomDomainRecords(); + } + const currentWorkspace = useRecoilValue(currentWorkspaceState); const { t } = useLingui(); @@ -53,11 +64,18 @@ export const SettingsCustomDomain = () => { onChange={onChange} placeholder="crm.yourdomain.com" error={error?.message} - loading={!!loading} fullWidth /> )} /> + {currentWorkspace?.customDomain && ( diff --git a/packages/twenty-front/src/pages/settings/workspace/SettingsCustomDomainEffect.tsx b/packages/twenty-front/src/pages/settings/workspace/SettingsCustomDomainEffect.tsx deleted file mode 100644 index e007e40e7..000000000 --- a/packages/twenty-front/src/pages/settings/workspace/SettingsCustomDomainEffect.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; -import { useEffect, useCallback } from 'react'; -import { useSetRecoilState, useRecoilValue } from 'recoil'; -import { isDefined } from 'twenty-shared'; -import { useCheckCustomDomainValidRecordsMutation } from '~/generated/graphql'; -import { customDomainRecordsState } from '~/pages/settings/workspace/states/customDomainRecordsState'; - -export const SettingsCustomDomainEffect = () => { - const [checkCustomDomainValidRecords] = - useCheckCustomDomainValidRecordsMutation(); - - const setCustomDomainRecords = useSetRecoilState(customDomainRecordsState); - - const currentWorkspace = useRecoilValue(currentWorkspaceState); - - const checkCustomDomainValidRecordsPolling = useCallback(async () => { - setCustomDomainRecords((currentState) => ({ - ...currentState, - loading: true, - })); - checkCustomDomainValidRecords({ - onCompleted: (data) => { - if (isDefined(data.checkCustomDomainValidRecords)) { - setCustomDomainRecords({ - loading: false, - customDomainRecords: data.checkCustomDomainValidRecords, - }); - } - }, - }); - }, [checkCustomDomainValidRecords, setCustomDomainRecords]); - - useEffect(() => { - let pollIntervalFn: null | ReturnType = null; - if (isDefined(currentWorkspace?.customDomain)) { - checkCustomDomainValidRecordsPolling(); - pollIntervalFn = setInterval(checkCustomDomainValidRecordsPolling, 6000); - } - - return () => { - if (isDefined(pollIntervalFn)) { - clearInterval(pollIntervalFn); - } - }; - }, [checkCustomDomainValidRecordsPolling, currentWorkspace?.customDomain]); - - return <>; -}; diff --git a/packages/twenty-front/src/pages/settings/workspace/SettingsCustomDomainRecords.tsx b/packages/twenty-front/src/pages/settings/workspace/SettingsCustomDomainRecords.tsx index bba788b03..6877f7ad4 100644 --- a/packages/twenty-front/src/pages/settings/workspace/SettingsCustomDomainRecords.tsx +++ b/packages/twenty-front/src/pages/settings/workspace/SettingsCustomDomainRecords.tsx @@ -18,17 +18,21 @@ const StyledTable = styled(Table)` const StyledTableCell = styled(TableCell)` overflow: hidden; + + padding: 0 ${({ theme }) => theme.spacing(3)} 0 0; + + &:first-child { + padding-left: 0; + } + + &:last-child { + padding-right: 0; + } `; const StyledButton = styled(Button)` - -moz-user-select: text; - -ms-user-select: text; - -webkit-user-select: text; - background-color: ${({ theme }) => theme.background.transparent.lighter}; border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.sm}; color: ${({ theme }) => theme.font.color.tertiary}; - font-family: ${({ theme }) => theme.font.family}; font-weight: ${({ theme }) => theme.font.weight.regular}; height: ${({ theme }) => theme.spacing(6)}; overflow: hidden; diff --git a/packages/twenty-front/src/pages/settings/workspace/SettingsDomain.tsx b/packages/twenty-front/src/pages/settings/workspace/SettingsDomain.tsx index 10bbf4a2b..8030c3b5f 100644 --- a/packages/twenty-front/src/pages/settings/workspace/SettingsDomain.tsx +++ b/packages/twenty-front/src/pages/settings/workspace/SettingsDomain.tsx @@ -24,7 +24,6 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { SettingsPath } from '@/types/SettingsPath'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; -import { SettingsCustomDomainEffect } from '~/pages/settings/workspace/SettingsCustomDomainEffect'; import { isDefined } from 'twenty-shared'; export const SettingsDomain = () => { @@ -229,12 +228,7 @@ export const SettingsDomain = () => { > - {isCustomDomainEnabled && ( - <> - - - - )} + {isCustomDomainEnabled && } diff --git a/packages/twenty-front/src/pages/settings/workspace/SettingsSubdomain.tsx b/packages/twenty-front/src/pages/settings/workspace/SettingsSubdomain.tsx index dfc725c66..1f1437d58 100644 --- a/packages/twenty-front/src/pages/settings/workspace/SettingsSubdomain.tsx +++ b/packages/twenty-front/src/pages/settings/workspace/SettingsSubdomain.tsx @@ -14,15 +14,6 @@ const StyledDomainFormWrapper = styled.div` display: flex; `; -const StyledDomain = styled.h2` - align-self: flex-start; - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - margin: ${({ theme }) => theme.spacing(2)}; - white-space: nowrap; -`; - export const SettingsSubdomain = () => { const domainConfiguration = useRecoilValue(domainConfigurationState); const { t } = useLingui(); @@ -51,13 +42,13 @@ export const SettingsSubdomain = () => { onChange={onChange} error={error?.message} disabled={!!currentWorkspace?.customDomain} + rightAdornment={ + isDefined(domainConfiguration.frontDomain) + ? `.${domainConfiguration.frontDomain}` + : undefined + } fullWidth /> - {isDefined(domainConfiguration.frontDomain) && ( - - {`.${domainConfiguration.frontDomain}`} - - )} )} /> diff --git a/packages/twenty-front/src/pages/settings/workspace/hooks/useCheckCustomDomainValidRecords.ts b/packages/twenty-front/src/pages/settings/workspace/hooks/useCheckCustomDomainValidRecords.ts new file mode 100644 index 000000000..e1e08d665 --- /dev/null +++ b/packages/twenty-front/src/pages/settings/workspace/hooks/useCheckCustomDomainValidRecords.ts @@ -0,0 +1,32 @@ +import { customDomainRecordsState } from '~/pages/settings/workspace/states/customDomainRecordsState'; +import { useCheckCustomDomainValidRecordsMutation } from '~/generated/graphql'; +import { isDefined } from 'twenty-shared'; +import { useSetRecoilState } from 'recoil'; + +export const useCheckCustomDomainValidRecords = () => { + const [checkCustomDomainValidRecords] = + useCheckCustomDomainValidRecordsMutation(); + + const setCustomDomainRecords = useSetRecoilState(customDomainRecordsState); + + const checkCustomDomainRecords = () => { + setCustomDomainRecords((currentState) => ({ + ...currentState, + loading: true, + })); + checkCustomDomainValidRecords({ + onCompleted: (data) => { + if (isDefined(data.checkCustomDomainValidRecords)) { + setCustomDomainRecords({ + loading: false, + customDomainRecords: data.checkCustomDomainValidRecords, + }); + } + }, + }); + }; + + return { + checkCustomDomainRecords, + }; +};