diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 4af448020c..5379c6aba8 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -3028,6 +3028,7 @@ export type WorkspaceInviteHashValid = { export type WorkspaceMember = { __typename?: 'WorkspaceMember'; avatarUrl?: Maybe; + calendarStartDay?: Maybe; colorScheme: Scalars['String']; dateFormat?: Maybe; id: Scalars['UUID']; @@ -3729,7 +3730,7 @@ export type UpdateWorkspaceMemberRoleMutationVariables = Exact<{ }>; -export type UpdateWorkspaceMemberRoleMutation = { __typename?: 'Mutation', updateWorkspaceMemberRole: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, roles?: Array<{ __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean }> | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } }; +export type UpdateWorkspaceMemberRoleMutation = { __typename?: 'Mutation', updateWorkspaceMemberRole: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, calendarStartDay?: number | null, roles?: Array<{ __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean }> | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } }; export type UpsertObjectPermissionsMutationVariables = Exact<{ upsertObjectPermissionsInput: UpsertObjectPermissionsInput; @@ -3748,7 +3749,7 @@ export type UpsertPermissionFlagsMutation = { __typename?: 'Mutation', upsertPer export type GetRolesQueryVariables = Exact<{ [key: string]: never; }>; -export type GetRolesQuery = { __typename?: 'Query', getRoles: Array<{ __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, 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 } }>, permissionFlags?: Array<{ __typename?: 'PermissionFlag', id: string, flag: PermissionFlagType, roleId: string }> | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null, restrictedFields?: any | null }> | null }> }; +export type GetRolesQuery = { __typename?: 'Query', getRoles: Array<{ __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, 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, calendarStartDay?: number | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }>, permissionFlags?: Array<{ __typename?: 'PermissionFlag', id: string, flag: PermissionFlagType, roleId: string }> | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null, restrictedFields?: any | null }> | null }> }; export type CreateApprovedAccessDomainMutationVariables = Exact<{ input: CreateApprovedAccessDomainInput; @@ -3879,7 +3880,7 @@ export type VerifyTwoFactorAuthenticationMethodForAuthenticatedUserMutationVaria export type VerifyTwoFactorAuthenticationMethodForAuthenticatedUserMutation = { __typename?: 'Mutation', verifyTwoFactorAuthenticationMethodForAuthenticatedUser: { __typename?: 'VerifyTwoFactorAuthenticationMethodOutput', success: boolean } }; -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 | 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, deletedWorkspaceMembers?: Array<{ __typename?: 'DeletedWorkspaceMember', id: any, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', permissionFlags?: Array | null, objectRecordsPermissions?: Array | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null, restrictedFields?: any | null }> | null, twoFactorAuthenticationMethodSummary?: Array<{ __typename?: 'TwoFactorAuthenticationMethodDTO', twoFactorAuthenticationMethodId: any, status: string, strategy: string }> | 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, isTwoFactorAuthenticationEnforced: boolean, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null, metadata: any, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: any, hasReachedCurrentPeriodCap: boolean, quantity?: number | null, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, metadata: any }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null, defaultAgent?: { __typename?: 'Agent', id: any } | null } | null, availableWorkspaces: { __typename?: 'AvailableWorkspaces', availableWorkspacesForSignIn: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }>, availableWorkspacesForSignUp: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: 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 | 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, calendarStartDay?: number | 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, calendarStartDay?: number | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, deletedWorkspaceMembers?: Array<{ __typename?: 'DeletedWorkspaceMember', id: any, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', permissionFlags?: Array | null, objectRecordsPermissions?: Array | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null, restrictedFields?: any | null }> | null, twoFactorAuthenticationMethodSummary?: Array<{ __typename?: 'TwoFactorAuthenticationMethodDTO', twoFactorAuthenticationMethodId: any, status: string, strategy: string }> | 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, isTwoFactorAuthenticationEnforced: boolean, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null, metadata: any, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: any, hasReachedCurrentPeriodCap: boolean, quantity?: number | null, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, metadata: any }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null, defaultAgent?: { __typename?: 'Agent', id: any } | null } | null, availableWorkspaces: { __typename?: 'AvailableWorkspaces', availableWorkspacesForSignIn: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }>, availableWorkspacesForSignUp: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }> } }; export type WorkspaceUrlsFragmentFragment = { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }; @@ -3898,7 +3899,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 | 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, deletedWorkspaceMembers?: Array<{ __typename?: 'DeletedWorkspaceMember', id: any, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', permissionFlags?: Array | null, objectRecordsPermissions?: Array | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null, restrictedFields?: any | null }> | null, twoFactorAuthenticationMethodSummary?: Array<{ __typename?: 'TwoFactorAuthenticationMethodDTO', twoFactorAuthenticationMethodId: any, status: string, strategy: string }> | 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, isTwoFactorAuthenticationEnforced: boolean, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null, metadata: any, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: any, hasReachedCurrentPeriodCap: boolean, quantity?: number | null, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, metadata: any }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null, defaultAgent?: { __typename?: 'Agent', id: any } | null } | null, availableWorkspaces: { __typename?: 'AvailableWorkspaces', availableWorkspacesForSignIn: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }>, availableWorkspacesForSignUp: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }> } } }; +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 | 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, calendarStartDay?: number | 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, calendarStartDay?: number | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, deletedWorkspaceMembers?: Array<{ __typename?: 'DeletedWorkspaceMember', id: any, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', permissionFlags?: Array | null, objectRecordsPermissions?: Array | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null, restrictedFields?: any | null }> | null, twoFactorAuthenticationMethodSummary?: Array<{ __typename?: 'TwoFactorAuthenticationMethodDTO', twoFactorAuthenticationMethodId: any, status: string, strategy: string }> | 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, isTwoFactorAuthenticationEnforced: boolean, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null, metadata: any, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: any, hasReachedCurrentPeriodCap: boolean, quantity?: number | null, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, metadata: any }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null, defaultAgent?: { __typename?: 'Agent', id: any } | null } | null, availableWorkspaces: { __typename?: 'AvailableWorkspaces', availableWorkspacesForSignIn: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }>, availableWorkspacesForSignUp: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }> } } }; export type ActivateWorkflowVersionMutationVariables = Exact<{ workflowVersionId: Scalars['String']; @@ -3998,7 +3999,7 @@ export type GetWorkspaceInvitationsQuery = { __typename?: 'Query', findWorkspace export type DeletedWorkspaceMemberQueryFragmentFragment = { __typename?: 'DeletedWorkspaceMember', id: any, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }; -export type WorkspaceMemberQueryFragmentFragment = { __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 } }; +export type WorkspaceMemberQueryFragmentFragment = { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, calendarStartDay?: number | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }; export type ActivateWorkspaceMutationVariables = Exact<{ input: ActivateWorkspaceInput; @@ -4142,6 +4143,7 @@ export const WorkspaceMemberQueryFragmentFragmentDoc = gql` timeZone dateFormat timeFormat + calendarStartDay } `; export const DeletedWorkspaceMemberQueryFragmentFragmentDoc = gql` diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index a49a9d0d0d..7cdce583db 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -2856,6 +2856,7 @@ export type WorkspaceInviteHashValid = { export type WorkspaceMember = { __typename?: 'WorkspaceMember'; avatarUrl?: Maybe; + calendarStartDay?: Maybe; colorScheme: Scalars['String']; dateFormat?: Maybe; id: Scalars['UUID']; diff --git a/packages/twenty-front/src/modules/localization/constants/CalendarStartDay.ts b/packages/twenty-front/src/modules/localization/constants/CalendarStartDay.ts new file mode 100644 index 0000000000..740ed13ba2 --- /dev/null +++ b/packages/twenty-front/src/modules/localization/constants/CalendarStartDay.ts @@ -0,0 +1,6 @@ +export enum CalendarStartDay { + SYSTEM = 7, + SUNDAY = 0, + MONDAY = 1, + SATURDAY = 6, +} diff --git a/packages/twenty-front/src/modules/localization/utils/detectCalendarStartDay.ts b/packages/twenty-front/src/modules/localization/utils/detectCalendarStartDay.ts new file mode 100644 index 0000000000..30759ced0a --- /dev/null +++ b/packages/twenty-front/src/modules/localization/utils/detectCalendarStartDay.ts @@ -0,0 +1,74 @@ +import { CalendarStartDay } from '@/localization/constants/CalendarStartDay'; + +const MONDAY_KEY: keyof typeof CalendarStartDay = 'MONDAY'; +const SATURDAY_KEY: keyof typeof CalendarStartDay = 'SATURDAY'; +const SUNDAY_KEY: keyof typeof CalendarStartDay = 'SUNDAY'; + +export const detectCalendarStartDay = (): keyof typeof CalendarStartDay => { + // Use Intl.Locale to get the first day of the week from the user's locale + // This requires a modern browser that supports Intl.Locale + try { + const locale = new Intl.Locale(navigator.language); + + // Check if the weekInfo property is available (newer browsers) + if ( + 'weekInfo' in locale && + locale.weekInfo !== null && + locale.weekInfo !== undefined && + typeof locale.weekInfo === 'object' && + 'firstDay' in locale.weekInfo + ) { + const firstDay = locale.weekInfo.firstDay; + + // Map Intl.Locale firstDay values to our enum keys + // Intl.Locale uses 1=Monday, 7=Sunday, 6=Saturday + switch (firstDay) { + case 1: + return MONDAY_KEY; + case 6: + return SATURDAY_KEY; + case 7: + default: + return SUNDAY_KEY; + } + } + } catch (error) { + // Fallback if Intl.Locale is not supported or fails + } + + // Fallback: Use a heuristic based on common locale patterns + const language = navigator.language.toLowerCase(); + + // Most European countries, Australia, New Zealand start with Monday + if ( + language.startsWith('de') || // German + language.startsWith('fr') || // French + language.startsWith('es') || // Spanish + language.startsWith('it') || // Italian + language.startsWith('pt') || // Portuguese + language.startsWith('nl') || // Dutch + language.startsWith('sv') || // Swedish + language.startsWith('no') || // Norwegian + language.startsWith('da') || // Danish + language.startsWith('fi') || // Finnish + language.startsWith('pl') || // Polish + language.startsWith('ru') || // Russian + language.startsWith('en-gb') || // British English + language.startsWith('en-au') || // Australian English + language.startsWith('en-nz') // New Zealand English + ) { + return MONDAY_KEY; + } + + // Middle Eastern countries often start with Saturday + if ( + language.startsWith('ar') || // Arabic + language.startsWith('he') || // Hebrew + language.startsWith('fa') // Persian + ) { + return SATURDAY_KEY; + } + + // Default to Sunday (US, Canada, Japan, etc.) + return SUNDAY_KEY; +}; diff --git a/packages/twenty-front/src/modules/localization/utils/findAvailableTimeZoneOption.ts b/packages/twenty-front/src/modules/localization/utils/findAvailableTimeZoneOption.ts index a1ce9a26b8..ada7868b34 100644 --- a/packages/twenty-front/src/modules/localization/utils/findAvailableTimeZoneOption.ts +++ b/packages/twenty-front/src/modules/localization/utils/findAvailableTimeZoneOption.ts @@ -1,5 +1,5 @@ import { formatTimeZoneLabel } from '@/localization/utils/formatTimeZoneLabel'; -import { AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL } from '@/settings/accounts/constants/AvailableTimezoneOptionsByLabel'; +import { AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL } from '@/settings/experience/constants/AvailableTimezoneOptionsByLabel'; /** * Finds the matching available IANA time zone select option from a given IANA time zone. diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDateFormatSelect.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDateFormatSelect.tsx deleted file mode 100644 index 7555556c97..0000000000 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDateFormatSelect.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { formatInTimeZone } from 'date-fns-tz'; - -import { DateFormat } from '@/localization/constants/DateFormat'; -import { Select } from '@/ui/input/components/Select'; - -type SettingsAccountsCalendarDateFormatSelectProps = { - value: DateFormat; - onChange: (nextValue: DateFormat) => void; - timeZone: string; -}; - -export const SettingsAccountsCalendarDateFormatSelect = ({ - onChange, - timeZone, - value, -}: SettingsAccountsCalendarDateFormatSelectProps) => ( - -); diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarTimeZoneSelect.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarTimeZoneSelect.tsx deleted file mode 100644 index db3155a4ee..0000000000 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarTimeZoneSelect.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { detectTimeZone } from '@/localization/utils/detectTimeZone'; -import { findAvailableTimeZoneOption } from '@/localization/utils/findAvailableTimeZoneOption'; -import { AVAILABLE_TIMEZONE_OPTIONS } from '@/settings/accounts/constants/AvailableTimezoneOptions'; - -import { Select } from '@/ui/input/components/Select'; - -type SettingsAccountsCalendarTimeZoneSelectProps = { - value?: string; - onChange: (nextValue: string) => void; -}; - -export const SettingsAccountsCalendarTimeZoneSelect = ({ - value = detectTimeZone(), - onChange, -}: SettingsAccountsCalendarTimeZoneSelectProps) => ( - + ); +}; diff --git a/packages/twenty-front/src/modules/settings/experience/components/DateTimeSettingsTimeFormatSelect.tsx b/packages/twenty-front/src/modules/settings/experience/components/DateTimeSettingsTimeFormatSelect.tsx new file mode 100644 index 0000000000..aa9d329bbc --- /dev/null +++ b/packages/twenty-front/src/modules/settings/experience/components/DateTimeSettingsTimeFormatSelect.tsx @@ -0,0 +1,70 @@ +import { formatInTimeZone } from 'date-fns-tz'; + +import { TimeFormat } from '@/localization/constants/TimeFormat'; +import { detectTimeFormat } from '@/localization/utils/detectTimeFormat'; +import { detectTimeZone } from '@/localization/utils/detectTimeZone'; +import { Select } from '@/ui/input/components/Select'; +import { useLingui } from '@lingui/react/macro'; + +type DateTimeSettingsTimeFormatSelectProps = { + value: TimeFormat; + onChange: (nextValue: TimeFormat) => void; + timeZone: string; +}; + +export const DateTimeSettingsTimeFormatSelect = ({ + onChange, + timeZone, + value, +}: DateTimeSettingsTimeFormatSelectProps) => { + const { t } = useLingui(); + const systemTimeZone = detectTimeZone(); + + const usedTimeZone = timeZone === 'system' ? systemTimeZone : timeZone; + + const systemTimeFormat = TimeFormat[detectTimeFormat()]; + + const systemTimeFormatLabel = formatInTimeZone( + Date.now(), + usedTimeZone, + systemTimeFormat, + ); + + const hour24Label = formatInTimeZone( + Date.now(), + usedTimeZone, + TimeFormat.HOUR_24, + ); + + const hour12Label = formatInTimeZone( + Date.now(), + usedTimeZone, + TimeFormat.HOUR_12, + ); + + return ( + []), + ]} + onChange={onChange} + withSearchInput + /> + ); +}; diff --git a/packages/twenty-front/src/modules/settings/accounts/constants/AvailableTimezoneOptions.ts b/packages/twenty-front/src/modules/settings/experience/constants/AvailableTimezoneOptions.ts similarity index 90% rename from packages/twenty-front/src/modules/settings/accounts/constants/AvailableTimezoneOptions.ts rename to packages/twenty-front/src/modules/settings/experience/constants/AvailableTimezoneOptions.ts index 548b8261e3..b850d44919 100644 --- a/packages/twenty-front/src/modules/settings/accounts/constants/AvailableTimezoneOptions.ts +++ b/packages/twenty-front/src/modules/settings/experience/constants/AvailableTimezoneOptions.ts @@ -1,6 +1,6 @@ import { getTimezoneOffset } from 'date-fns-tz'; -import { AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL } from '@/settings/accounts/constants/AvailableTimezoneOptionsByLabel'; +import { AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL } from '@/settings/experience/constants/AvailableTimezoneOptionsByLabel'; export const AVAILABLE_TIMEZONE_OPTIONS = Object.values( AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL, diff --git a/packages/twenty-front/src/modules/settings/accounts/constants/AvailableTimezoneOptionsByLabel.ts b/packages/twenty-front/src/modules/settings/experience/constants/AvailableTimezoneOptionsByLabel.ts similarity index 100% rename from packages/twenty-front/src/modules/settings/accounts/constants/AvailableTimezoneOptionsByLabel.ts rename to packages/twenty-front/src/modules/settings/experience/constants/AvailableTimezoneOptionsByLabel.ts diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/DaySelect.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/DaySelect.tsx new file mode 100644 index 0000000000..7f199b7708 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/DaySelect.tsx @@ -0,0 +1,42 @@ +import { useMemo } from 'react'; + +import { SELECT_DAY_DROPDOWN_ID } from '@/ui/input/components/internal/date/constants/SelectDayDropdownId'; +import { DayNameWithIndex } from '@/ui/input/components/internal/date/types/DayNameWithIndex'; +import { Select } from '@/ui/input/components/Select'; +import { SelectOption } from 'twenty-ui/input'; + +export const DaySelect = ({ + label, + selectedDayIndex, + onChange, + dayList, +}: { + label: string; + selectedDayIndex: number; + onChange: (dayIndex: number | string) => void; + dayList: DayNameWithIndex[]; +}) => { + const options: SelectOption[] = useMemo(() => { + const days = dayList?.map>( + ({ day, index }) => ({ + label: day, + value: index, + }), + ); + + return days; + }, [dayList]); + + return ( + + ); +}; diff --git a/packages/twenty-front/src/pages/settings/profile/appearance/components/DateTimeSettingsTimeZoneSelect.tsx b/packages/twenty-front/src/pages/settings/profile/appearance/components/DateTimeSettingsTimeZoneSelect.tsx index b8baf88715..606c00cfef 100644 --- a/packages/twenty-front/src/pages/settings/profile/appearance/components/DateTimeSettingsTimeZoneSelect.tsx +++ b/packages/twenty-front/src/pages/settings/profile/appearance/components/DateTimeSettingsTimeZoneSelect.tsx @@ -1,9 +1,10 @@ import { detectTimeZone } from '@/localization/utils/detectTimeZone'; import { findAvailableTimeZoneOption } from '@/localization/utils/findAvailableTimeZoneOption'; -import { AVAILABLE_TIMEZONE_OPTIONS } from '@/settings/accounts/constants/AvailableTimezoneOptions'; +import { AVAILABLE_TIMEZONE_OPTIONS } from '@/settings/experience/constants/AvailableTimezoneOptions'; import { Select } from '@/ui/input/components/Select'; import { t } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; +import { SelectOption } from 'twenty-ui/input'; type DateTimeSettingsTimeZoneSelectProps = { value?: string; @@ -32,7 +33,7 @@ export const DateTimeSettingsTimeZoneSelect = ({ : t`System settings`, value: 'system', }, - ...AVAILABLE_TIMEZONE_OPTIONS, + ...(AVAILABLE_TIMEZONE_OPTIONS as SelectOption[]), ]} onChange={onChange} withSearchInput diff --git a/packages/twenty-front/src/pages/settings/profile/appearance/components/SettingsExperience.tsx b/packages/twenty-front/src/pages/settings/profile/appearance/components/SettingsExperience.tsx index 031b251695..5ca9e8fa86 100644 --- a/packages/twenty-front/src/pages/settings/profile/appearance/components/SettingsExperience.tsx +++ b/packages/twenty-front/src/pages/settings/profile/appearance/components/SettingsExperience.tsx @@ -4,12 +4,12 @@ import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBa import { useColorScheme } from '@/ui/theme/hooks/useColorScheme'; import { Trans, useLingui } from '@lingui/react/macro'; +import { H2Title } from 'twenty-ui/display'; +import { ColorSchemePicker } from 'twenty-ui/input'; +import { Section } from 'twenty-ui/layout'; import { DateTimeSettings } from '~/pages/settings/profile/appearance/components/DateTimeSettings'; import { LocalePicker } from '~/pages/settings/profile/appearance/components/LocalePicker'; import { getSettingsPath } from '~/utils/navigation/getSettingsPath'; -import { ColorSchemePicker } from 'twenty-ui/input'; -import { H2Title } from 'twenty-ui/display'; -import { Section } from 'twenty-ui/layout'; export const SettingsExperience = () => { const { colorScheme, setColorScheme } = useColorScheme(); @@ -38,13 +38,6 @@ export const SettingsExperience = () => { systemLabel={t`System settings`} /> -
- - -
{ />
+ +
+ + +
); diff --git a/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts b/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts index 78f3a1f8b4..ca88582ccf 100644 --- a/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts @@ -1,6 +1,7 @@ -import { Field, ObjectType } from '@nestjs/graphql'; +import { Field, Int, ObjectType } from '@nestjs/graphql'; import { IDField } from '@ptc-org/nestjs-query-graphql'; +import { Max, Min } from 'class-validator'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { RoleDTO } from 'src/engine/metadata-modules/role/dtos/role.dto'; @@ -38,6 +39,11 @@ export class WorkspaceMember { @Field({ nullable: true }) locale: string; + @Field(() => Int, { nullable: true }) + @Min(0) + @Max(7) + calendarStartDay: number; + @Field({ nullable: true }) timeZone: string; diff --git a/packages/twenty-server/src/engine/core-modules/user/services/workspace-member-transpiler.service.ts b/packages/twenty-server/src/engine/core-modules/user/services/workspace-member-transpiler.service.ts index 8331a424cb..a7b5c1c53a 100644 --- a/packages/twenty-server/src/engine/core-modules/user/services/workspace-member-transpiler.service.ts +++ b/packages/twenty-server/src/engine/core-modules/user/services/workspace-member-transpiler.service.ts @@ -60,6 +60,7 @@ export class WorkspaceMemberTranspiler { timeFormat, timeZone, dateFormat, + calendarStartDay, } = workspaceMemberEntity; const avatarUrl = this.generateSignedAvatarUrl({ @@ -84,6 +85,7 @@ export class WorkspaceMemberTranspiler { timeFormat: timeFormat as WorkspaceMemberTimeFormatEnum, timeZone, roles, + calendarStartDay, } satisfies WorkspaceMember; } diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts index ed3ffa2471..af40768f86 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts @@ -532,6 +532,7 @@ export const WORKSPACE_MEMBER_STANDARD_FIELD_IDS = { dateFormat: '20202020-af13-4e11-b1e7-b8cf5ea13dc0', timeFormat: '20202020-8acb-4cf8-a851-a6ed443c8d81', searchVector: '20202020-46d0-4e7f-bc26-74c0edaeb619', + calendarStartDay: '20202020-92d0-1d7f-a126-25ededa6b142', }; export const CUSTOM_OBJECT_STANDARD_FIELD_IDS = { diff --git a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts index 821caf972e..a31ff6156a 100644 --- a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts +++ b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts @@ -7,6 +7,7 @@ import { FieldMetadataType } from 'twenty-shared/types'; import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface'; import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface'; import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface'; +import { NumberDataType } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface'; import { SEARCH_VECTOR_FIELD } from 'src/engine/metadata-modules/constants/search-vector-field.constants'; import { FullNameMetadata } from 'src/engine/metadata-modules/field-metadata/composite-types/full-name.composite-type'; @@ -143,6 +144,19 @@ export class WorkspaceMemberWorkspaceEntity extends BaseWorkspaceEntity { @WorkspaceIsSystem() userEmail: string; + @WorkspaceField({ + standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.calendarStartDay, + type: FieldMetadataType.NUMBER, + label: msg`Start of the week`, + defaultValue: 7, + description: msg`User's preferred start day of the week`, + settings: { + dataType: NumberDataType.INT, + }, + }) + @WorkspaceIsSystem() + calendarStartDay: number; + @WorkspaceField({ standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.userId, type: FieldMetadataType.UUID, diff --git a/src/modules/ui/input/components/internal/date/DaySelect.tsx b/src/modules/ui/input/components/internal/date/DaySelect.tsx new file mode 100644 index 0000000000..44cadd527c --- /dev/null +++ b/src/modules/ui/input/components/internal/date/DaySelect.tsx @@ -0,0 +1,42 @@ +import { useMemo } from 'react'; + +import { SELECT_DAY_DROPDOWN_ID } from '@/ui/input/components/internal/date/constants/SelectDayDropdownId'; +import { DayNameWithIndex } from '@/ui/input/components/internal/date/types/DayNameWithIndex'; +import { Select } from '@/ui/input/components/Select'; +import { SelectOption } from 'twenty-ui/input'; + +export const DaySelect = ({ + label, + selectedDayIndex, + onChange, + dayList, +}: { + label: string; + selectedDayIndex: number; + onChange: (dayIndex: number | string) => void; + dayList: DayNameWithIndex[]; +}) => { + const options: SelectOption[] = useMemo(() => { + const days = dayList?.map>( + ({ day, index }) => ({ + label: day, + value: index, + }), + ); + + return days; + }, [dayList]); + + return ( +