Performance improvement to dev xp (#9294)
The DX is not great when you need to do a lot of database resets/command. Should we disable Typescript validation to speed things up? With this and caching database:reset takes 1min instead of 2 on my machine. See also: https://github.com/typeorm/typeorm/issues/4136 And #9291 / #9293 --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -302,7 +302,7 @@ export type ExecuteServerlessFunctionInput = {
|
|||||||
export type FeatureFlag = {
|
export type FeatureFlag = {
|
||||||
__typename?: 'FeatureFlag';
|
__typename?: 'FeatureFlag';
|
||||||
id: Scalars['UUID'];
|
id: Scalars['UUID'];
|
||||||
key: Scalars['String'];
|
key: FeatureFlagKey;
|
||||||
value: Scalars['Boolean'];
|
value: Scalars['Boolean'];
|
||||||
workspaceId: Scalars['String'];
|
workspaceId: Scalars['String'];
|
||||||
};
|
};
|
||||||
@ -313,6 +313,29 @@ export type FeatureFlagFilter = {
|
|||||||
or?: InputMaybe<Array<FeatureFlagFilter>>;
|
or?: InputMaybe<Array<FeatureFlagFilter>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum FeatureFlagKey {
|
||||||
|
IsAdvancedFiltersEnabled = 'IsAdvancedFiltersEnabled',
|
||||||
|
IsAggregateQueryEnabled = 'IsAggregateQueryEnabled',
|
||||||
|
IsAirtableIntegrationEnabled = 'IsAirtableIntegrationEnabled',
|
||||||
|
IsAnalyticsV2Enabled = 'IsAnalyticsV2Enabled',
|
||||||
|
IsCopilotEnabled = 'IsCopilotEnabled',
|
||||||
|
IsCrmMigrationEnabled = 'IsCrmMigrationEnabled',
|
||||||
|
IsEventObjectEnabled = 'IsEventObjectEnabled',
|
||||||
|
IsFreeAccessEnabled = 'IsFreeAccessEnabled',
|
||||||
|
IsFunctionSettingsEnabled = 'IsFunctionSettingsEnabled',
|
||||||
|
IsGmailSendEmailScopeEnabled = 'IsGmailSendEmailScopeEnabled',
|
||||||
|
IsJsonFilterEnabled = 'IsJsonFilterEnabled',
|
||||||
|
IsMessageThreadSubscriberEnabled = 'IsMessageThreadSubscriberEnabled',
|
||||||
|
IsMicrosoftSyncEnabled = 'IsMicrosoftSyncEnabled',
|
||||||
|
IsPageHeaderV2Enabled = 'IsPageHeaderV2Enabled',
|
||||||
|
IsPostgreSqlIntegrationEnabled = 'IsPostgreSQLIntegrationEnabled',
|
||||||
|
IsSsoEnabled = 'IsSSOEnabled',
|
||||||
|
IsStripeIntegrationEnabled = 'IsStripeIntegrationEnabled',
|
||||||
|
IsUniqueIndexesEnabled = 'IsUniqueIndexesEnabled',
|
||||||
|
IsViewGroupsEnabled = 'IsViewGroupsEnabled',
|
||||||
|
IsWorkflowEnabled = 'IsWorkflowEnabled'
|
||||||
|
}
|
||||||
|
|
||||||
export type FeatureFlagSort = {
|
export type FeatureFlagSort = {
|
||||||
direction: SortDirection;
|
direction: SortDirection;
|
||||||
field: FeatureFlagSortFields;
|
field: FeatureFlagSortFields;
|
||||||
@ -2068,7 +2091,7 @@ export type UserLookupAdminPanelMutationVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type UserLookupAdminPanelMutation = { __typename?: 'Mutation', userLookupAdminPanel: { __typename?: 'UserLookup', user: { __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null }, workspaces: Array<{ __typename?: 'WorkspaceInfo', id: string, name: string, logo?: string | null, totalUsers: number, allowImpersonation: boolean, users: Array<{ __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null }>, featureFlags: Array<{ __typename?: 'FeatureFlag', key: string, value: boolean }> }> } };
|
export type UserLookupAdminPanelMutation = { __typename?: 'Mutation', userLookupAdminPanel: { __typename?: 'UserLookup', user: { __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null }, workspaces: Array<{ __typename?: 'WorkspaceInfo', id: string, name: string, logo?: string | null, totalUsers: number, allowImpersonation: boolean, users: Array<{ __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null }>, featureFlags: Array<{ __typename?: 'FeatureFlag', key: FeatureFlagKey, value: boolean }> }> } };
|
||||||
|
|
||||||
export type CreateOidcIdentityProviderMutationVariables = Exact<{
|
export type CreateOidcIdentityProviderMutationVariables = Exact<{
|
||||||
input: SetupOidcSsoInput;
|
input: SetupOidcSsoInput;
|
||||||
@ -2103,7 +2126,7 @@ export type ListSsoIdentityProvidersByWorkspaceIdQueryVariables = Exact<{ [key:
|
|||||||
|
|
||||||
export type ListSsoIdentityProvidersByWorkspaceIdQuery = { __typename?: 'Query', listSSOIdentityProvidersByWorkspaceId: Array<{ __typename?: 'FindAvailableSSOIDPOutput', type: IdentityProviderType, id: string, name: string, issuer: string, status: SsoIdentityProviderStatus }> };
|
export type ListSsoIdentityProvidersByWorkspaceIdQuery = { __typename?: 'Query', listSSOIdentityProvidersByWorkspaceId: 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, 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, 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, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEntrepriseKey: boolean, metadataVersion: number, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null, subdomain: string } | null }> };
|
export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, 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, 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, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEntrepriseKey: boolean, metadataVersion: number, workspaceMembersCount?: number | 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 } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null, subdomain: string } | null }> };
|
||||||
|
|
||||||
export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>;
|
export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
@ -2120,7 +2143,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf
|
|||||||
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
|
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, 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, 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, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEntrepriseKey: boolean, metadataVersion: number, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null, subdomain: string } | null }> } };
|
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, 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, 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, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEntrepriseKey: boolean, metadataVersion: number, workspaceMembersCount?: number | 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 } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null, subdomain: string } | null }> } };
|
||||||
|
|
||||||
export type ActivateWorkflowVersionMutationVariables = Exact<{
|
export type ActivateWorkflowVersionMutationVariables = Exact<{
|
||||||
workflowVersionId: Scalars['String'];
|
workflowVersionId: Scalars['String'];
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
|
|||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-ui';
|
import { isDefined } from 'twenty-ui';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const RecordActionMenuEntriesSetter = () => {
|
export const RecordActionMenuEntriesSetter = () => {
|
||||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
||||||
@ -53,7 +54,9 @@ const ActionEffects = ({
|
|||||||
contextStoreCurrentViewTypeComponentState,
|
contextStoreCurrentViewTypeComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED');
|
const isWorkflowEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import { useWorkflowRunActions } from '@/action-menu/actions/record-agnostic-actions/workflow-run-actions/hooks/useWorkflowRunActions';
|
import { useWorkflowRunActions } from '@/action-menu/actions/record-agnostic-actions/workflow-run-actions/hooks/useWorkflowRunActions';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const useRecordAgnosticActions = () => {
|
export const useRecordAgnosticActions = () => {
|
||||||
const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED');
|
const isWorkflowEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
);
|
||||||
|
|
||||||
const { addWorkflowRunActions, removeWorkflowRunActions } =
|
const { addWorkflowRunActions, removeWorkflowRunActions } =
|
||||||
useWorkflowRunActions();
|
useWorkflowRunActions();
|
||||||
|
|||||||
@ -8,10 +8,13 @@ import { useRunWorkflowVersion } from '@/workflow/hooks/useRunWorkflowVersion';
|
|||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
|
||||||
import { IconSettingsAutomation, isDefined } from 'twenty-ui';
|
import { IconSettingsAutomation, isDefined } from 'twenty-ui';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { capitalize } from '~/utils/string/capitalize';
|
import { capitalize } from '~/utils/string/capitalize';
|
||||||
|
|
||||||
export const useWorkflowRunActions = () => {
|
export const useWorkflowRunActions = () => {
|
||||||
const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED');
|
const isWorkflowEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
);
|
||||||
|
|
||||||
const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries();
|
const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries();
|
||||||
|
|
||||||
|
|||||||
@ -14,16 +14,19 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
|
|||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useIsMobile } from 'twenty-ui';
|
import { useIsMobile } from 'twenty-ui';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const RecordIndexActionMenu = ({ indexId }: { indexId: string }) => {
|
export const RecordIndexActionMenu = ({ indexId }: { indexId: string }) => {
|
||||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
contextStoreCurrentObjectMetadataIdComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED');
|
const isWorkflowEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
);
|
||||||
|
|
||||||
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
||||||
'IS_PAGE_HEADER_V2_ENABLED',
|
FeatureFlagKey.IsPageHeaderV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
|||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { RecordShowPageBaseHeader } from '~/pages/object-record/RecordShowPageBaseHeader';
|
import { RecordShowPageBaseHeader } from '~/pages/object-record/RecordShowPageBaseHeader';
|
||||||
|
|
||||||
export const RecordShowActionMenu = ({
|
export const RecordShowActionMenu = ({
|
||||||
@ -28,10 +29,12 @@ export const RecordShowActionMenu = ({
|
|||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
contextStoreCurrentObjectMetadataIdComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED');
|
const isWorkflowEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
);
|
||||||
|
|
||||||
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
||||||
'IS_PAGE_HEADER_V2_ENABLED',
|
FeatureFlagKey.IsPageHeaderV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: refactor RecordShowPageBaseHeader to use the context store
|
// TODO: refactor RecordShowPageBaseHeader to use the context store
|
||||||
|
|||||||
@ -7,13 +7,16 @@ import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
|||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const RecordShowRightDrawerActionMenu = () => {
|
export const RecordShowRightDrawerActionMenu = () => {
|
||||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
contextStoreCurrentObjectMetadataIdComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED');
|
const isWorkflowEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -8,13 +8,14 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
|
|||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { isDefined } from 'twenty-ui';
|
import { isDefined } from 'twenty-ui';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const useActionMenuEntriesWithCallbacks = (
|
export const useActionMenuEntriesWithCallbacks = (
|
||||||
objectMetadataItem: ObjectMetadataItem,
|
objectMetadataItem: ObjectMetadataItem,
|
||||||
viewType: ActionViewType,
|
viewType: ActionViewType,
|
||||||
) => {
|
) => {
|
||||||
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
||||||
'IS_PAGE_HEADER_V2_ENABLED',
|
FeatureFlagKey.IsPageHeaderV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
const actionConfig = getActionConfig(
|
const actionConfig = getActionConfig(
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import { viewableRecordIdState } from '@/object-record/record-right-drawer/state
|
|||||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { isDefined } from 'twenty-ui';
|
import { isDefined } from 'twenty-ui';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const useRightDrawerEmailThread = () => {
|
export const useRightDrawerEmailThread = () => {
|
||||||
const viewableRecordId = useRecoilValue(viewableRecordIdState);
|
const viewableRecordId = useRecoilValue(viewableRecordIdState);
|
||||||
@ -38,7 +39,7 @@ export const useRightDrawerEmailThread = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const isMessageThreadSubscribersEnabled = useIsFeatureEnabled(
|
const isMessageThreadSubscribersEnabled = useIsFeatureEnabled(
|
||||||
'IS_MESSAGE_THREAD_SUBSCRIBER_ENABLED',
|
FeatureFlagKey.IsMessageThreadSubscriberEnabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
const FETCH_ALL_MESSAGES_OPERATION_SIGNATURE =
|
const FETCH_ALL_MESSAGES_OPERATION_SIGNATURE =
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { EmailThreadMembersChip } from '@/activities/emails/components/EmailThre
|
|||||||
import { messageThreadState } from '@/ui/layout/right-drawer/states/messageThreadState';
|
import { messageThreadState } from '@/ui/layout/right-drawer/states/messageThreadState';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { isDefined } from 'twenty-ui';
|
import { isDefined } from 'twenty-ui';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
const StyledButtonContainer = styled.div`
|
const StyledButtonContainer = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -15,7 +16,7 @@ const StyledButtonContainer = styled.div`
|
|||||||
|
|
||||||
export const MessageThreadSubscribersTopBar = () => {
|
export const MessageThreadSubscribersTopBar = () => {
|
||||||
const isMessageThreadSubscriberEnabled = useIsFeatureEnabled(
|
const isMessageThreadSubscriberEnabled = useIsFeatureEnabled(
|
||||||
'IS_MESSAGE_THREAD_SUBSCRIBER_ENABLED',
|
FeatureFlagKey.IsMessageThreadSubscriberEnabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
const messageThread = useRecoilValue(messageThreadState);
|
const messageThread = useRecoilValue(messageThreadState);
|
||||||
|
|||||||
@ -4,14 +4,19 @@ import { billingState } from '@/client-config/states/billingState';
|
|||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { RouterProvider } from 'react-router-dom';
|
import { RouterProvider } from 'react-router-dom';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const AppRouter = () => {
|
export const AppRouter = () => {
|
||||||
const billing = useRecoilValue(billingState);
|
const billing = useRecoilValue(billingState);
|
||||||
const isFreeAccessEnabled = useIsFeatureEnabled('IS_FREE_ACCESS_ENABLED');
|
const isFreeAccessEnabled = useIsFeatureEnabled(
|
||||||
const isCRMMigrationEnabled = useIsFeatureEnabled('IS_CRM_MIGRATION_ENABLED');
|
FeatureFlagKey.IsFreeAccessEnabled,
|
||||||
const isSSOEnabled = useIsFeatureEnabled('IS_SSO_ENABLED');
|
);
|
||||||
|
const isCRMMigrationEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsCrmMigrationEnabled,
|
||||||
|
);
|
||||||
|
const isSSOEnabled = useIsFeatureEnabled(FeatureFlagKey.IsSsoEnabled);
|
||||||
const isServerlessFunctionSettingsEnabled = useIsFeatureEnabled(
|
const isServerlessFunctionSettingsEnabled = useIsFeatureEnabled(
|
||||||
'IS_FUNCTION_SETTINGS_ENABLED',
|
FeatureFlagKey.IsFunctionSettingsEnabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isBillingPageEnabled =
|
const isBillingPageEnabled =
|
||||||
|
|||||||
@ -12,12 +12,15 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
|||||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const CommandMenuContainer = () => {
|
export const CommandMenuContainer = () => {
|
||||||
const { toggleCommandMenu } = useCommandMenu();
|
const { toggleCommandMenu } = useCommandMenu();
|
||||||
const { closeKeyboardShortcutMenu } = useKeyboardShortcutMenu();
|
const { closeKeyboardShortcutMenu } = useKeyboardShortcutMenu();
|
||||||
|
|
||||||
const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED');
|
const isWorkflowEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
);
|
||||||
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
|
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
|
||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import { useMemo } from 'react';
|
|||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
import { Avatar, IconCheckbox, IconNotes, IconSparkles } from 'twenty-ui';
|
import { Avatar, IconCheckbox, IconNotes, IconSparkles } from 'twenty-ui';
|
||||||
import { useDebounce } from 'use-debounce';
|
import { useDebounce } from 'use-debounce';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { getLogoUrlFromDomainName } from '~/utils';
|
import { getLogoUrlFromDomainName } from '~/utils';
|
||||||
|
|
||||||
export const useCommandMenuCommands = () => {
|
export const useCommandMenuCommands = () => {
|
||||||
@ -44,7 +45,7 @@ export const useCommandMenuCommands = () => {
|
|||||||
const commandMenuSearch = useRecoilValue(commandMenuSearchState);
|
const commandMenuSearch = useRecoilValue(commandMenuSearchState);
|
||||||
const [deferredCommandMenuSearch] = useDebounce(commandMenuSearch, 300); // 200ms - 500ms
|
const [deferredCommandMenuSearch] = useDebounce(commandMenuSearch, 300); // 200ms - 500ms
|
||||||
|
|
||||||
const isCopilotEnabled = useIsFeatureEnabled('IS_COPILOT_ENABLED');
|
const isCopilotEnabled = useIsFeatureEnabled(FeatureFlagKey.IsCopilotEnabled);
|
||||||
const setCopilotQuery = useSetRecoilState(copilotQueryState);
|
const setCopilotQuery = useSetRecoilState(copilotQueryState);
|
||||||
const openCopilotRightDrawer = useOpenCopilotRightDrawer();
|
const openCopilotRightDrawer = useOpenCopilotRightDrawer();
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { Button, IconButton, IconHeart, IconHeartOff } from 'twenty-ui';
|
import { Button, IconButton, IconHeart, IconHeartOff } from 'twenty-ui';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
type PageFavoriteButtonProps = {
|
type PageFavoriteButtonProps = {
|
||||||
isFavorite: boolean;
|
isFavorite: boolean;
|
||||||
@ -13,7 +14,7 @@ export const PageFavoriteButton = ({
|
|||||||
const title = isFavorite ? 'Remove from favorites' : 'Add to favorites';
|
const title = isFavorite ? 'Remove from favorites' : 'Add to favorites';
|
||||||
|
|
||||||
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
||||||
'IS_PAGE_HEADER_V2_ENABLED',
|
FeatureFlagKey.IsPageHeaderV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefin
|
|||||||
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
||||||
|
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { formatFieldMetadataItemAsColumnDefinition } from '../utils/formatFieldMetadataItemAsColumnDefinition';
|
import { formatFieldMetadataItemAsColumnDefinition } from '../utils/formatFieldMetadataItemAsColumnDefinition';
|
||||||
import { formatFieldMetadataItemsAsFilterDefinitions } from '../utils/formatFieldMetadataItemsAsFilterDefinitions';
|
import { formatFieldMetadataItemsAsFilterDefinitions } from '../utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { formatFieldMetadataItemsAsSortDefinitions } from '../utils/formatFieldMetadataItemsAsSortDefinitions';
|
import { formatFieldMetadataItemsAsSortDefinitions } from '../utils/formatFieldMetadataItemsAsSortDefinitions';
|
||||||
@ -24,7 +25,9 @@ export const useColumnDefinitionsFromFieldMetadata = (
|
|||||||
[objectMetadataItem],
|
[objectMetadataItem],
|
||||||
);
|
);
|
||||||
|
|
||||||
const isJsonFilterEnabled = useIsFeatureEnabled('IS_JSON_FILTER_ENABLED');
|
const isJsonFilterEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsJsonFilterEnabled,
|
||||||
|
);
|
||||||
|
|
||||||
const filterDefinitions = formatFieldMetadataItemsAsFilterDefinitions({
|
const filterDefinitions = formatFieldMetadataItemsAsFilterDefinitions({
|
||||||
fields: activeFieldMetadataItems,
|
fields: activeFieldMetadataItems,
|
||||||
|
|||||||
@ -12,6 +12,12 @@ jest.mock('@/workspace/hooks/useIsFeatureEnabled', () => ({
|
|||||||
useIsFeatureEnabled: jest.fn(),
|
useIsFeatureEnabled: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('~/generated/graphql', () => ({
|
||||||
|
FeatureFlagKey: {
|
||||||
|
IsAggregateQueryEnabled: 'IsAggregateQueryEnabled',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
describe('useRefetchAggregateQueries', () => {
|
describe('useRefetchAggregateQueries', () => {
|
||||||
const mockRefetchQueries = jest.fn();
|
const mockRefetchQueries = jest.fn();
|
||||||
const mockApolloClient = {
|
const mockApolloClient = {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { getAggregateQueryName } from '@/object-record/utils/getAggregateQueryName';
|
import { getAggregateQueryName } from '@/object-record/utils/getAggregateQueryName';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useApolloClient } from '@apollo/client';
|
import { useApolloClient } from '@apollo/client';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const useRefetchAggregateQueries = ({
|
export const useRefetchAggregateQueries = ({
|
||||||
objectMetadataNamePlural,
|
objectMetadataNamePlural,
|
||||||
@ -9,7 +10,7 @@ export const useRefetchAggregateQueries = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const apolloClient = useApolloClient();
|
const apolloClient = useApolloClient();
|
||||||
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
||||||
'IS_AGGREGATE_QUERY_ENABLED',
|
FeatureFlagKey.IsAggregateQueryEnabled,
|
||||||
);
|
);
|
||||||
const refetchAggregateQueries = async () => {
|
const refetchAggregateQueries = async () => {
|
||||||
if (isAggregateQueryEnabled) {
|
if (isAggregateQueryEnabled) {
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import { availableFilterDefinitionsComponentState } from '@/views/states/availab
|
|||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-ui';
|
import { isDefined } from 'twenty-ui';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const StyledInput = styled.input`
|
export const StyledInput = styled.input`
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -146,7 +147,7 @@ export const ObjectFilterDropdownFilterSelect = ({
|
|||||||
useGetCurrentView();
|
useGetCurrentView();
|
||||||
|
|
||||||
const isAdvancedFiltersEnabled = useIsFeatureEnabled(
|
const isAdvancedFiltersEnabled = useIsFeatureEnabled(
|
||||||
'IS_ADVANCED_FILTERS_ENABLED',
|
FeatureFlagKey.IsAdvancedFiltersEnabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
const shouldShowAdvancedFilterButton =
|
const shouldShowAdvancedFilterButton =
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
|
|||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const ObjectOptionsDropdownMenuContent = () => {
|
export const ObjectOptionsDropdownMenuContent = () => {
|
||||||
const {
|
const {
|
||||||
@ -41,7 +42,9 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
|||||||
closeDropdown,
|
closeDropdown,
|
||||||
} = useOptionsDropdown();
|
} = useOptionsDropdown();
|
||||||
|
|
||||||
const isViewGroupEnabled = useIsFeatureEnabled('IS_VIEW_GROUPS_ENABLED');
|
const isViewGroupEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsViewGroupsEnabled,
|
||||||
|
);
|
||||||
|
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
const { currentViewWithCombinedFiltersAndSorts: currentView } =
|
const { currentViewWithCombinedFiltersAndSorts: currentView } =
|
||||||
|
|||||||
@ -24,9 +24,12 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
|
|||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||||
const isViewGroupEnabled = useIsFeatureEnabled('IS_VIEW_GROUPS_ENABLED');
|
const isViewGroupEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsViewGroupsEnabled,
|
||||||
|
);
|
||||||
|
|
||||||
const { currentContentId, recordIndexId, onContentChange, resetContent } =
|
const { currentContentId, recordIndexId, onContentChange, resetContent } =
|
||||||
useOptionsDropdown();
|
useOptionsDropdown();
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { RecordGroupDefinitionType } from '@/object-record/record-group/types/Re
|
|||||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { IconDotsVertical, IconPlus, LightIconButton, Tag } from 'twenty-ui';
|
import { IconDotsVertical, IconPlus, LightIconButton, Tag } from 'twenty-ui';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
const StyledHeader = styled.div`
|
const StyledHeader = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -103,7 +104,7 @@ export const RecordBoardColumnHeader = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
||||||
'IS_AGGREGATE_QUERY_ENABLED',
|
FeatureFlagKey.IsAggregateQueryEnabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { isOpportunitiesCompanyFieldDisabled } =
|
const { isOpportunitiesCompanyFieldDisabled } =
|
||||||
|
|||||||
@ -12,11 +12,12 @@ import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/s
|
|||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
export const useAggregateRecordsForRecordBoardColumn = () => {
|
export const useAggregateRecordsForRecordBoardColumn = () => {
|
||||||
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
||||||
'IS_AGGREGATE_QUERY_ENABLED',
|
FeatureFlagKey.IsAggregateQueryEnabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { columnDefinition, recordCount } = useContext(
|
const { columnDefinition, recordCount } = useContext(
|
||||||
|
|||||||
@ -24,16 +24,18 @@ export default meta;
|
|||||||
|
|
||||||
type Story = StoryObj<typeof FormDateFieldInput>;
|
type Story = StoryObj<typeof FormDateFieldInput>;
|
||||||
|
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
label: 'Created At',
|
label: 'Created At',
|
||||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
defaultValue: `${currentYear}-12-09T13:20:19.631Z`,
|
||||||
},
|
},
|
||||||
play: async ({ canvasElement }) => {
|
play: async ({ canvasElement }) => {
|
||||||
const canvas = within(canvasElement);
|
const canvas = within(canvasElement);
|
||||||
|
|
||||||
await canvas.findByText('Created At');
|
await canvas.findByText('Created At');
|
||||||
await canvas.findByDisplayValue('12/09/2024');
|
await canvas.findByDisplayValue('12/09/' + currentYear);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,10 +69,12 @@ export const SetsDateWithInput: Story = {
|
|||||||
const dialog = await canvas.findByRole('dialog');
|
const dialog = await canvas.findByRole('dialog');
|
||||||
expect(dialog).toBeVisible();
|
expect(dialog).toBeVisible();
|
||||||
|
|
||||||
await userEvent.type(input, '12/08/2024{enter}');
|
await userEvent.type(input, `12/08/${currentYear}{enter}`);
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(args.onPersist).toHaveBeenCalledWith('2024-12-08T00:00:00.000Z');
|
expect(args.onPersist).toHaveBeenCalledWith(
|
||||||
|
`${currentYear}-12-08T00:00:00.000Z`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(dialog).toBeVisible();
|
expect(dialog).toBeVisible();
|
||||||
@ -80,7 +84,7 @@ export const SetsDateWithInput: Story = {
|
|||||||
export const SetsDateWithDatePicker: Story = {
|
export const SetsDateWithDatePicker: Story = {
|
||||||
args: {
|
args: {
|
||||||
label: 'Created At',
|
label: 'Created At',
|
||||||
defaultValue: undefined,
|
defaultValue: `2024-12-09T13:20:19.631Z`,
|
||||||
onPersist: fn(),
|
onPersist: fn(),
|
||||||
},
|
},
|
||||||
play: async ({ canvasElement, args }) => {
|
play: async ({ canvasElement, args }) => {
|
||||||
@ -95,7 +99,7 @@ export const SetsDateWithDatePicker: Story = {
|
|||||||
expect(datePicker).toBeVisible();
|
expect(datePicker).toBeVisible();
|
||||||
|
|
||||||
const dayToChoose = await within(datePicker).findByRole('option', {
|
const dayToChoose = await within(datePicker).findByRole('option', {
|
||||||
name: 'Choose Saturday, December 7th, 2024',
|
name: `Choose Saturday, December 7th, 2024`,
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
@ -104,11 +108,11 @@ export const SetsDateWithDatePicker: Story = {
|
|||||||
waitForElementToBeRemoved(datePicker),
|
waitForElementToBeRemoved(datePicker),
|
||||||
waitFor(() => {
|
waitFor(() => {
|
||||||
expect(args.onPersist).toHaveBeenCalledWith(
|
expect(args.onPersist).toHaveBeenCalledWith(
|
||||||
expect.stringMatching(/^2024-12-07/),
|
expect.stringMatching(new RegExp(`^2024-12-07`)),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
waitFor(() => {
|
waitFor(() => {
|
||||||
expect(canvas.getByDisplayValue('12/07/2024')).toBeVisible();
|
expect(canvas.getByDisplayValue(`12/07/2024`)).toBeVisible();
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
@ -117,7 +121,7 @@ export const SetsDateWithDatePicker: Story = {
|
|||||||
export const ResetsDateByClickingButton: Story = {
|
export const ResetsDateByClickingButton: Story = {
|
||||||
args: {
|
args: {
|
||||||
label: 'Created At',
|
label: 'Created At',
|
||||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
defaultValue: `${currentYear}-12-09T13:20:19.631Z`,
|
||||||
onPersist: fn(),
|
onPersist: fn(),
|
||||||
},
|
},
|
||||||
play: async ({ canvasElement, args }) => {
|
play: async ({ canvasElement, args }) => {
|
||||||
@ -150,7 +154,7 @@ export const ResetsDateByClickingButton: Story = {
|
|||||||
export const ResetsDateByErasingInputContent: Story = {
|
export const ResetsDateByErasingInputContent: Story = {
|
||||||
args: {
|
args: {
|
||||||
label: 'Created At',
|
label: 'Created At',
|
||||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
defaultValue: `${currentYear}-12-09T13:20:19.631Z`,
|
||||||
onPersist: fn(),
|
onPersist: fn(),
|
||||||
},
|
},
|
||||||
play: async ({ canvasElement, args }) => {
|
play: async ({ canvasElement, args }) => {
|
||||||
@ -159,7 +163,7 @@ export const ResetsDateByErasingInputContent: Story = {
|
|||||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||||
expect(input).toBeVisible();
|
expect(input).toBeVisible();
|
||||||
|
|
||||||
expect(input).toHaveDisplayValue('12/09/2024');
|
expect(input).toHaveDisplayValue(`12/09/${currentYear}`);
|
||||||
|
|
||||||
await userEvent.clear(input);
|
await userEvent.clear(input);
|
||||||
|
|
||||||
@ -336,7 +340,7 @@ export const SwitchesToStandaloneVariable: Story = {
|
|||||||
export const ClickingOutsideDoesNotResetInputState: Story = {
|
export const ClickingOutsideDoesNotResetInputState: Story = {
|
||||||
args: {
|
args: {
|
||||||
label: 'Created At',
|
label: 'Created At',
|
||||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
defaultValue: `${currentYear}-12-09T13:20:19.631Z`,
|
||||||
onPersist: fn(),
|
onPersist: fn(),
|
||||||
},
|
},
|
||||||
play: async ({ canvasElement, args }) => {
|
play: async ({ canvasElement, args }) => {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { FormDateTimeFieldInput } from '@/object-record/record-field/form-types/components/FormDateTimeFieldInput';
|
||||||
import { MAX_DATE } from '@/ui/input/components/internal/date/constants/MaxDate';
|
import { MAX_DATE } from '@/ui/input/components/internal/date/constants/MaxDate';
|
||||||
import { MIN_DATE } from '@/ui/input/components/internal/date/constants/MinDate';
|
import { MIN_DATE } from '@/ui/input/components/internal/date/constants/MinDate';
|
||||||
import { parseDateToString } from '@/ui/input/components/internal/date/utils/parseDateToString';
|
import { parseDateToString } from '@/ui/input/components/internal/date/utils/parseDateToString';
|
||||||
@ -11,7 +12,6 @@ import {
|
|||||||
within,
|
within,
|
||||||
} from '@storybook/test';
|
} from '@storybook/test';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { FormDateTimeFieldInput } from '@/object-record/record-field/form-types/components/FormDateTimeFieldInput';
|
|
||||||
|
|
||||||
const meta: Meta<typeof FormDateTimeFieldInput> = {
|
const meta: Meta<typeof FormDateTimeFieldInput> = {
|
||||||
title: 'UI/Data/Field/Form/Input/FormDateTimeFieldInput',
|
title: 'UI/Data/Field/Form/Input/FormDateTimeFieldInput',
|
||||||
@ -24,16 +24,20 @@ export default meta;
|
|||||||
|
|
||||||
type Story = StoryObj<typeof FormDateTimeFieldInput>;
|
type Story = StoryObj<typeof FormDateTimeFieldInput>;
|
||||||
|
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
label: 'Created At',
|
label: 'Created At',
|
||||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
defaultValue: `${currentYear}-12-09T13:20:19.631Z`,
|
||||||
},
|
},
|
||||||
play: async ({ canvasElement }) => {
|
play: async ({ canvasElement }) => {
|
||||||
const canvas = within(canvasElement);
|
const canvas = within(canvasElement);
|
||||||
|
|
||||||
await canvas.findByText('Created At');
|
await canvas.findByText('Created At');
|
||||||
await canvas.findByDisplayValue(/12\/09\/2024 \d{2}:20/);
|
await canvas.findByDisplayValue(
|
||||||
|
new RegExp(`12/09/${currentYear} \\d{2}:20`),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,11 +71,11 @@ export const SetsDateTimeWithInput: Story = {
|
|||||||
const dialog = await canvas.findByRole('dialog');
|
const dialog = await canvas.findByRole('dialog');
|
||||||
expect(dialog).toBeVisible();
|
expect(dialog).toBeVisible();
|
||||||
|
|
||||||
await userEvent.type(input, '12/08/2024 12:10{enter}');
|
await userEvent.type(input, `12/08/${currentYear} 12:10{enter}`);
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(args.onPersist).toHaveBeenCalledWith(
|
expect(args.onPersist).toHaveBeenCalledWith(
|
||||||
expect.stringMatching(/2024-12-08T\d{2}:10:00.000Z/),
|
expect.stringMatching(new RegExp(`^${currentYear}-12-08`)),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -95,7 +99,7 @@ export const DoesNotSetDateWithoutTime: Story = {
|
|||||||
const dialog = await canvas.findByRole('dialog');
|
const dialog = await canvas.findByRole('dialog');
|
||||||
expect(dialog).toBeVisible();
|
expect(dialog).toBeVisible();
|
||||||
|
|
||||||
await userEvent.type(input, '12/08/2024{enter}');
|
await userEvent.type(input, `12/08/${currentYear}{enter}`);
|
||||||
|
|
||||||
expect(args.onPersist).not.toHaveBeenCalled();
|
expect(args.onPersist).not.toHaveBeenCalled();
|
||||||
expect(dialog).toBeVisible();
|
expect(dialog).toBeVisible();
|
||||||
@ -105,7 +109,7 @@ export const DoesNotSetDateWithoutTime: Story = {
|
|||||||
export const SetsDateTimeWithDatePicker: Story = {
|
export const SetsDateTimeWithDatePicker: Story = {
|
||||||
args: {
|
args: {
|
||||||
label: 'Created At',
|
label: 'Created At',
|
||||||
defaultValue: undefined,
|
defaultValue: `2024-12-09T13:20:19.631Z`,
|
||||||
onPersist: fn(),
|
onPersist: fn(),
|
||||||
},
|
},
|
||||||
play: async ({ canvasElement, args }) => {
|
play: async ({ canvasElement, args }) => {
|
||||||
@ -134,7 +138,7 @@ export const SetsDateTimeWithDatePicker: Story = {
|
|||||||
}),
|
}),
|
||||||
waitFor(() => {
|
waitFor(() => {
|
||||||
expect(
|
expect(
|
||||||
canvas.getByDisplayValue(/12\/07\/2024 \d{2}:\d{2}/),
|
canvas.getByDisplayValue(new RegExp(`12/07/2024 \\d{2}:\\d{2}`)),
|
||||||
).toBeVisible();
|
).toBeVisible();
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
@ -144,7 +148,7 @@ export const SetsDateTimeWithDatePicker: Story = {
|
|||||||
export const ResetsDateByClickingButton: Story = {
|
export const ResetsDateByClickingButton: Story = {
|
||||||
args: {
|
args: {
|
||||||
label: 'Created At',
|
label: 'Created At',
|
||||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
defaultValue: `${currentYear}-12-09T13:20:19.631Z`,
|
||||||
onPersist: fn(),
|
onPersist: fn(),
|
||||||
},
|
},
|
||||||
play: async ({ canvasElement, args }) => {
|
play: async ({ canvasElement, args }) => {
|
||||||
@ -177,7 +181,7 @@ export const ResetsDateByClickingButton: Story = {
|
|||||||
export const ResetsDateByErasingInputContent: Story = {
|
export const ResetsDateByErasingInputContent: Story = {
|
||||||
args: {
|
args: {
|
||||||
label: 'Created At',
|
label: 'Created At',
|
||||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
defaultValue: `${currentYear}-12-09T13:20:19.631Z`,
|
||||||
onPersist: fn(),
|
onPersist: fn(),
|
||||||
},
|
},
|
||||||
play: async ({ canvasElement, args }) => {
|
play: async ({ canvasElement, args }) => {
|
||||||
@ -186,7 +190,9 @@ export const ResetsDateByErasingInputContent: Story = {
|
|||||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||||
expect(input).toBeVisible();
|
expect(input).toBeVisible();
|
||||||
|
|
||||||
expect(input).toHaveDisplayValue(/12\/09\/2024 \d{2}:\d{2}/);
|
expect(input).toHaveDisplayValue(
|
||||||
|
new RegExp(`12/09/${currentYear} \\d{2}:\\d{2}`),
|
||||||
|
);
|
||||||
|
|
||||||
await userEvent.clear(input);
|
await userEvent.clear(input);
|
||||||
|
|
||||||
@ -363,7 +369,7 @@ export const SwitchesToStandaloneVariable: Story = {
|
|||||||
export const ClickingOutsideDoesNotResetInputState: Story = {
|
export const ClickingOutsideDoesNotResetInputState: Story = {
|
||||||
args: {
|
args: {
|
||||||
label: 'Created At',
|
label: 'Created At',
|
||||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
defaultValue: `${currentYear}-12-09T13:20:19.631Z`,
|
||||||
onPersist: fn(),
|
onPersist: fn(),
|
||||||
},
|
},
|
||||||
play: async ({ canvasElement, args }) => {
|
play: async ({ canvasElement, args }) => {
|
||||||
|
|||||||
@ -42,6 +42,7 @@ import { mapViewGroupsToRecordGroupDefinitions } from '@/views/utils/mapViewGrou
|
|||||||
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
@ -162,7 +163,7 @@ export const RecordIndexContainer = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
||||||
'IS_PAGE_HEADER_V2_ENABLED',
|
FeatureFlagKey.IsPageHeaderV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import { ViewType } from '@/views/types/ViewType';
|
|||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined, useIcons } from 'twenty-ui';
|
import { isDefined, useIcons } from 'twenty-ui';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { capitalize } from '~/utils/string/capitalize';
|
import { capitalize } from '~/utils/string/capitalize';
|
||||||
|
|
||||||
export const RecordIndexPageHeader = () => {
|
export const RecordIndexPageHeader = () => {
|
||||||
@ -36,7 +37,7 @@ export const RecordIndexPageHeader = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
||||||
'IS_PAGE_HEADER_V2_ENABLED',
|
FeatureFlagKey.IsPageHeaderV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isObjectMetadataItemReadOnly =
|
const isObjectMetadataItemReadOnly =
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import {
|
|||||||
IconSettings,
|
IconSettings,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
import { FeatureFlag, FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FeatureFlag, FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const useRecordShowContainerTabs = (
|
export const useRecordShowContainerTabs = (
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
@ -149,7 +150,7 @@ export const useRecordShowContainerTabs = (
|
|||||||
ifMobile: false,
|
ifMobile: false,
|
||||||
ifDesktop: false,
|
ifDesktop: false,
|
||||||
ifInRightDrawer: false,
|
ifInRightDrawer: false,
|
||||||
ifFeaturesDisabled: ['IS_WORKFLOW_ENABLED'],
|
ifFeaturesDisabled: [FeatureFlagKey.IsWorkflowEnabled],
|
||||||
ifRequiredObjectsInactive: [],
|
ifRequiredObjectsInactive: [],
|
||||||
ifRelationsMissing: [],
|
ifRelationsMissing: [],
|
||||||
},
|
},
|
||||||
@ -169,7 +170,7 @@ export const useRecordShowContainerTabs = (
|
|||||||
ifMobile: false,
|
ifMobile: false,
|
||||||
ifDesktop: false,
|
ifDesktop: false,
|
||||||
ifInRightDrawer: false,
|
ifInRightDrawer: false,
|
||||||
ifFeaturesDisabled: ['IS_WORKFLOW_ENABLED'],
|
ifFeaturesDisabled: [FeatureFlagKey.IsWorkflowEnabled],
|
||||||
ifRequiredObjectsInactive: [],
|
ifRequiredObjectsInactive: [],
|
||||||
ifRelationsMissing: [],
|
ifRelationsMissing: [],
|
||||||
},
|
},
|
||||||
@ -188,7 +189,7 @@ export const useRecordShowContainerTabs = (
|
|||||||
ifMobile: false,
|
ifMobile: false,
|
||||||
ifDesktop: false,
|
ifDesktop: false,
|
||||||
ifInRightDrawer: false,
|
ifInRightDrawer: false,
|
||||||
ifFeaturesDisabled: ['IS_WORKFLOW_ENABLED'],
|
ifFeaturesDisabled: [FeatureFlagKey.IsWorkflowEnabled],
|
||||||
ifRequiredObjectsInactive: [],
|
ifRequiredObjectsInactive: [],
|
||||||
ifRelationsMissing: [],
|
ifRelationsMissing: [],
|
||||||
},
|
},
|
||||||
@ -202,7 +203,7 @@ export const useRecordShowContainerTabs = (
|
|||||||
ifMobile: false,
|
ifMobile: false,
|
||||||
ifDesktop: false,
|
ifDesktop: false,
|
||||||
ifInRightDrawer: false,
|
ifInRightDrawer: false,
|
||||||
ifFeaturesDisabled: ['IS_WORKFLOW_ENABLED'],
|
ifFeaturesDisabled: [FeatureFlagKey.IsWorkflowEnabled],
|
||||||
ifRequiredObjectsInactive: [],
|
ifRequiredObjectsInactive: [],
|
||||||
ifRelationsMissing: [],
|
ifRelationsMissing: [],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useC
|
|||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
const StyledTable = styled.table`
|
const StyledTable = styled.table`
|
||||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||||
@ -36,7 +37,7 @@ export const RecordTable = () => {
|
|||||||
const tableBodyRef = useRef<HTMLTableElement>(null);
|
const tableBodyRef = useRef<HTMLTableElement>(null);
|
||||||
|
|
||||||
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
||||||
'IS_AGGREGATE_QUERY_ENABLED',
|
FeatureFlagKey.IsAggregateQueryEnabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { toggleClickOutsideListener } = useClickOutsideListener(
|
const { toggleClickOutsideListener } = useClickOutsideListener(
|
||||||
|
|||||||
@ -12,10 +12,11 @@ import { RecordTableRecordGroupSection } from '@/object-record/record-table/reco
|
|||||||
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
|
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const RecordTableRecordGroupsBody = () => {
|
export const RecordTableRecordGroupsBody = () => {
|
||||||
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
||||||
'IS_AGGREGATE_QUERY_ENABLED',
|
FeatureFlagKey.IsAggregateQueryEnabled,
|
||||||
);
|
);
|
||||||
const allRecordIds = useRecoilComponentValueV2(
|
const allRecordIds = useRecoilComponentValueV2(
|
||||||
recordIndexAllRecordIdsComponentSelector,
|
recordIndexAllRecordIdsComponentSelector,
|
||||||
|
|||||||
@ -11,13 +11,14 @@ import { viewFieldAggregateOperationState } from '@/object-record/record-table/r
|
|||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
export const useAggregateRecordsForRecordTableColumnFooter = (
|
export const useAggregateRecordsForRecordTableColumnFooter = (
|
||||||
fieldMetadataId: string,
|
fieldMetadataId: string,
|
||||||
) => {
|
) => {
|
||||||
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
||||||
'IS_AGGREGATE_QUERY_ENABLED',
|
FeatureFlagKey.IsAggregateQueryEnabled,
|
||||||
);
|
);
|
||||||
const { objectMetadataItem } = useRecordTableContextOrThrow();
|
const { objectMetadataItem } = useRecordTableContextOrThrow();
|
||||||
const { recordGroupFilter } = useRecordGroupFilter(objectMetadataItem.fields);
|
const { recordGroupFilter } = useRecordGroupFilter(objectMetadataItem.fields);
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
|
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
@ -9,8 +11,7 @@ import {
|
|||||||
IconGoogle,
|
IconGoogle,
|
||||||
IconMicrosoft,
|
IconMicrosoft,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
const StyledHeader = styled(CardHeader)`
|
const StyledHeader = styled(CardHeader)`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -34,7 +35,7 @@ export const SettingsAccountsListEmptyStateCard = ({
|
|||||||
const { triggerApisOAuth } = useTriggerApisOAuth();
|
const { triggerApisOAuth } = useTriggerApisOAuth();
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
const isMicrosoftSyncEnabled = useIsFeatureEnabled(
|
const isMicrosoftSyncEnabled = useIsFeatureEnabled(
|
||||||
'IS_MICROSOFT_SYNC_ENABLED',
|
FeatureFlagKey.IsMicrosoftSyncEnabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -41,6 +41,7 @@ import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { AnimatePresence, motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import { matchPath, resolvePath, useLocation } from 'react-router-dom';
|
import { matchPath, resolvePath, useLocation } from 'react-router-dom';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
type SettingsNavigationItem = {
|
type SettingsNavigationItem = {
|
||||||
label: string;
|
label: string;
|
||||||
@ -80,10 +81,14 @@ export const SettingsNavigationDrawerItems = () => {
|
|||||||
|
|
||||||
const billing = useRecoilValue(billingState);
|
const billing = useRecoilValue(billingState);
|
||||||
const isFunctionSettingsEnabled = useIsFeatureEnabled(
|
const isFunctionSettingsEnabled = useIsFeatureEnabled(
|
||||||
'IS_FUNCTION_SETTINGS_ENABLED',
|
FeatureFlagKey.IsFunctionSettingsEnabled,
|
||||||
|
);
|
||||||
|
const isFreeAccessEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsFreeAccessEnabled,
|
||||||
|
);
|
||||||
|
const isCRMMigrationEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsCrmMigrationEnabled,
|
||||||
);
|
);
|
||||||
const isFreeAccessEnabled = useIsFeatureEnabled('IS_FREE_ACCESS_ENABLED');
|
|
||||||
const isCRMMigrationEnabled = useIsFeatureEnabled('IS_CRM_MIGRATION_ENABLED');
|
|
||||||
const isBillingPageEnabled =
|
const isBillingPageEnabled =
|
||||||
billing?.isBillingEnabled && !isFreeAccessEnabled;
|
billing?.isBillingEnabled && !isFreeAccessEnabled;
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
const getFeatureKey = (databaseKey: string) => {
|
const getFeatureKey = (databaseKey: string): FeatureFlagKey | null => {
|
||||||
switch (databaseKey) {
|
switch (databaseKey) {
|
||||||
case 'airtable':
|
case 'airtable':
|
||||||
return 'IS_AIRTABLE_INTEGRATION_ENABLED';
|
return FeatureFlagKey.IsAirtableIntegrationEnabled;
|
||||||
case 'postgresql':
|
case 'postgresql':
|
||||||
return 'IS_POSTGRESQL_INTEGRATION_ENABLED';
|
return FeatureFlagKey.IsPostgreSqlIntegrationEnabled;
|
||||||
case 'stripe':
|
case 'stripe':
|
||||||
return 'IS_STRIPE_INTEGRATION_ENABLED';
|
return FeatureFlagKey.IsStripeIntegrationEnabled;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,25 +5,26 @@ import { SETTINGS_INTEGRATION_ZAPIER_CATEGORY } from '@/settings/integrations/co
|
|||||||
import { SettingsIntegrationCategory } from '@/settings/integrations/types/SettingsIntegrationCategory';
|
import { SettingsIntegrationCategory } from '@/settings/integrations/types/SettingsIntegrationCategory';
|
||||||
import { getSettingsIntegrationAll } from '@/settings/integrations/utils/getSettingsIntegrationAll';
|
import { getSettingsIntegrationAll } from '@/settings/integrations/utils/getSettingsIntegrationAll';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const useSettingsIntegrationCategories =
|
export const useSettingsIntegrationCategories =
|
||||||
(): SettingsIntegrationCategory[] => {
|
(): SettingsIntegrationCategory[] => {
|
||||||
const isAirtableIntegrationEnabled = useIsFeatureEnabled(
|
const isAirtableIntegrationEnabled = useIsFeatureEnabled(
|
||||||
'IS_AIRTABLE_INTEGRATION_ENABLED',
|
FeatureFlagKey.IsAirtableIntegrationEnabled,
|
||||||
);
|
);
|
||||||
const isAirtableIntegrationActive = !!MOCK_REMOTE_DATABASES.find(
|
const isAirtableIntegrationActive = !!MOCK_REMOTE_DATABASES.find(
|
||||||
({ name }) => name === 'airtable',
|
({ name }) => name === 'airtable',
|
||||||
)?.isActive;
|
)?.isActive;
|
||||||
|
|
||||||
const isPostgresqlIntegrationEnabled = useIsFeatureEnabled(
|
const isPostgresqlIntegrationEnabled = useIsFeatureEnabled(
|
||||||
'IS_POSTGRESQL_INTEGRATION_ENABLED',
|
FeatureFlagKey.IsPostgreSqlIntegrationEnabled,
|
||||||
);
|
);
|
||||||
const isPostgresqlIntegrationActive = !!MOCK_REMOTE_DATABASES.find(
|
const isPostgresqlIntegrationActive = !!MOCK_REMOTE_DATABASES.find(
|
||||||
({ name }) => name === 'postgresql',
|
({ name }) => name === 'postgresql',
|
||||||
)?.isActive;
|
)?.isActive;
|
||||||
|
|
||||||
const isStripeIntegrationEnabled = useIsFeatureEnabled(
|
const isStripeIntegrationEnabled = useIsFeatureEnabled(
|
||||||
'IS_STRIPE_INTEGRATION_ENABLED',
|
FeatureFlagKey.IsStripeIntegrationEnabled,
|
||||||
);
|
);
|
||||||
const isStripeIntegrationActive = !!MOCK_REMOTE_DATABASES.find(
|
const isStripeIntegrationActive = !!MOCK_REMOTE_DATABASES.find(
|
||||||
({ name }) => name === 'stripe',
|
({ name }) => name === 'stripe',
|
||||||
|
|||||||
@ -2,12 +2,13 @@ import { Button, IconButton, IconDotsVertical, useIsMobile } from 'twenty-ui';
|
|||||||
|
|
||||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const PageHeaderOpenCommandMenuButton = () => {
|
export const PageHeaderOpenCommandMenuButton = () => {
|
||||||
const { openCommandMenu } = useCommandMenu();
|
const { openCommandMenu } = useCommandMenu();
|
||||||
|
|
||||||
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
||||||
'IS_PAGE_HEADER_V2_ENABLED',
|
FeatureFlagKey.IsPageHeaderV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { Button, IconButton, IconPlus, useIsMobile } from 'twenty-ui';
|
import { Button, IconButton, IconPlus, useIsMobile } from 'twenty-ui';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
type PageAddButtonProps = {
|
type PageAddButtonProps = {
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
@ -7,7 +8,7 @@ type PageAddButtonProps = {
|
|||||||
|
|
||||||
export const PageAddButton = ({ onClick }: PageAddButtonProps) => {
|
export const PageAddButton = ({ onClick }: PageAddButtonProps) => {
|
||||||
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
||||||
'IS_PAGE_HEADER_V2_ENABLED',
|
FeatureFlagKey.IsPageHeaderV2Enabled,
|
||||||
);
|
);
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import { NavigationDrawerCollapseButton } from '@/ui/navigation/navigation-drawe
|
|||||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const PAGE_BAR_MIN_HEIGHT = 40;
|
export const PAGE_BAR_MIN_HEIGHT = 40;
|
||||||
|
|
||||||
@ -111,7 +112,7 @@ export const PageHeader = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
||||||
'IS_PAGE_HEADER_V2_ENABLED',
|
FeatureFlagKey.IsPageHeaderV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import { SHOW_PAGE_ADD_BUTTON_DROPDOWN_ID } from '@/ui/layout/show-page/constant
|
|||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
|
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { Dropdown } from '../../dropdown/components/Dropdown';
|
import { Dropdown } from '../../dropdown/components/Dropdown';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
@ -53,7 +54,7 @@ export const ShowPageAddButton = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
||||||
'IS_PAGE_HEADER_V2_ENABLED',
|
FeatureFlagKey.IsPageHeaderV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { FeatureFlagKey } from '@/workspace/types/FeatureFlagKey';
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export type TabVisibilityConfig = {
|
export type TabVisibilityConfig = {
|
||||||
ifMobile: boolean;
|
ifMobile: boolean;
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/
|
|||||||
import { useViewOrDefaultViewFromPrefetchedViews } from '@/views/hooks/useViewOrDefaultViewFromPrefetchedViews';
|
import { useViewOrDefaultViewFromPrefetchedViews } from '@/views/hooks/useViewOrDefaultViewFromPrefetchedViews';
|
||||||
import { getQueryVariablesFromView } from '@/views/utils/getQueryVariablesFromView';
|
import { getQueryVariablesFromView } from '@/views/utils/getQueryVariablesFromView';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const useQueryVariablesFromActiveFieldsOfViewOrDefaultView = ({
|
export const useQueryVariablesFromActiveFieldsOfViewOrDefaultView = ({
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
@ -21,7 +22,9 @@ export const useQueryVariablesFromActiveFieldsOfViewOrDefaultView = ({
|
|||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
});
|
});
|
||||||
|
|
||||||
const isJsonFilterEnabled = useIsFeatureEnabled('IS_JSON_FILTER_ENABLED');
|
const isJsonFilterEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsJsonFilterEnabled,
|
||||||
|
);
|
||||||
|
|
||||||
const { filterValueDependencies } = useFilterValueDependencies();
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { FeatureFlagKey } from '@/workspace/types/FeatureFlagKey';
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const useIsFeatureEnabled = (featureKey: FeatureFlagKey | null) => {
|
export const useIsFeatureEnabled = (featureKey: FeatureFlagKey | null) => {
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
|
|||||||
@ -1,21 +0,0 @@
|
|||||||
export type FeatureFlagKey =
|
|
||||||
| 'IS_EVENT_OBJECT_ENABLED'
|
|
||||||
| 'IS_AIRTABLE_INTEGRATION_ENABLED'
|
|
||||||
| 'IS_POSTGRESQL_INTEGRATION_ENABLED'
|
|
||||||
| 'IS_STRIPE_INTEGRATION_ENABLED'
|
|
||||||
| 'IS_FUNCTION_SETTINGS_ENABLED'
|
|
||||||
| 'IS_COPILOT_ENABLED'
|
|
||||||
| 'IS_CRM_MIGRATION_ENABLED'
|
|
||||||
| 'IS_FREE_ACCESS_ENABLED'
|
|
||||||
| 'IS_MESSAGE_THREAD_SUBSCRIBER_ENABLED'
|
|
||||||
| 'IS_WORKFLOW_ENABLED'
|
|
||||||
| 'IS_GMAIL_SEND_EMAIL_SCOPE_ENABLED'
|
|
||||||
| 'IS_ANALYTICS_V2_ENABLED'
|
|
||||||
| 'IS_SSO_ENABLED'
|
|
||||||
| 'IS_UNIQUE_INDEXES_ENABLED'
|
|
||||||
| 'IS_JSON_FILTER_ENABLED'
|
|
||||||
| 'IS_MICROSOFT_SYNC_ENABLED'
|
|
||||||
| 'IS_ADVANCED_FILTERS_ENABLED'
|
|
||||||
| 'IS_AGGREGATE_QUERY_ENABLED'
|
|
||||||
| 'IS_VIEW_GROUPS_ENABLED'
|
|
||||||
| 'IS_PAGE_HEADER_V2_ENABLED';
|
|
||||||
@ -15,6 +15,7 @@ import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle';
|
|||||||
import { RecordShowPageWorkflowHeader } from '@/workflow/components/RecordShowPageWorkflowHeader';
|
import { RecordShowPageWorkflowHeader } from '@/workflow/components/RecordShowPageWorkflowHeader';
|
||||||
import { RecordShowPageWorkflowVersionHeader } from '@/workflow/components/RecordShowPageWorkflowVersionHeader';
|
import { RecordShowPageWorkflowVersionHeader } from '@/workflow/components/RecordShowPageWorkflowVersionHeader';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { RecordShowPageHeader } from '~/pages/object-record/RecordShowPageHeader';
|
import { RecordShowPageHeader } from '~/pages/object-record/RecordShowPageHeader';
|
||||||
|
|
||||||
export const RecordShowPage = () => {
|
export const RecordShowPage = () => {
|
||||||
@ -40,7 +41,7 @@ export const RecordShowPage = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
||||||
'IS_PAGE_HEADER_V2_ENABLED',
|
FeatureFlagKey.IsPageHeaderV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import {
|
|||||||
UndecoratedLink,
|
UndecoratedLink,
|
||||||
isDefined,
|
isDefined,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { SETTINGS_OBJECT_DETAIL_TABS } from '~/pages/settings/data-model/constants/SettingsObjectDetailTabs';
|
import { SETTINGS_OBJECT_DETAIL_TABS } from '~/pages/settings/data-model/constants/SettingsObjectDetailTabs';
|
||||||
import { updatedObjectSlugState } from '~/pages/settings/data-model/states/updatedObjectSlugState';
|
import { updatedObjectSlugState } from '~/pages/settings/data-model/states/updatedObjectSlugState';
|
||||||
|
|
||||||
@ -69,7 +70,7 @@ export const SettingsObjectDetailPage = () => {
|
|||||||
|
|
||||||
const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState);
|
const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState);
|
||||||
const isUniqueIndexesEnabled = useIsFeatureEnabled(
|
const isUniqueIndexesEnabled = useIsFeatureEnabled(
|
||||||
'IS_UNIQUE_INDEXES_ENABLED',
|
FeatureFlagKey.IsUniqueIndexesEnabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -29,7 +29,11 @@ export const WithStandardSelected: Story = {
|
|||||||
play: async () => {
|
play: async () => {
|
||||||
const canvas = within(document.body);
|
const canvas = within(document.body);
|
||||||
|
|
||||||
await canvas.findByText('New Object', undefined, { timeout: 5000 });
|
await canvas.findByRole(
|
||||||
|
'heading',
|
||||||
|
{ name: 'New Object', level: 3 },
|
||||||
|
{ timeout: 5000 },
|
||||||
|
);
|
||||||
|
|
||||||
const listingInput = await canvas.findByPlaceholderText('Listing');
|
const listingInput = await canvas.findByPlaceholderText('Listing');
|
||||||
const pluralInput = await canvas.findByPlaceholderText('Listings');
|
const pluralInput = await canvas.findByPlaceholderText('Listings');
|
||||||
|
|||||||
@ -37,6 +37,7 @@ import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModa
|
|||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { WEBHOOK_EMPTY_OPERATION } from '~/pages/settings/developers/webhooks/constants/WebhookEmptyOperation';
|
import { WEBHOOK_EMPTY_OPERATION } from '~/pages/settings/developers/webhooks/constants/WebhookEmptyOperation';
|
||||||
import { WebhookOperationType } from '~/pages/settings/developers/webhooks/types/WebhookOperationsType';
|
import { WebhookOperationType } from '~/pages/settings/developers/webhooks/types/WebhookOperationsType';
|
||||||
|
|
||||||
@ -114,7 +115,9 @@ export const SettingsDevelopersWebhooksDetail = () => {
|
|||||||
navigate(developerPath);
|
navigate(developerPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isAnalyticsV2Enabled = useIsFeatureEnabled('IS_ANALYTICS_V2_ENABLED');
|
const isAnalyticsV2Enabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsAnalyticsV2Enabled,
|
||||||
|
);
|
||||||
|
|
||||||
const fieldTypeOptions: SelectOption<string>[] = useMemo(
|
const fieldTypeOptions: SelectOption<string>[] = useMemo(
|
||||||
() => [
|
() => [
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import { SettingsPath } from '@/types/SettingsPath';
|
|||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -30,7 +31,7 @@ const StyledSSOSection = styled(Section)`
|
|||||||
export const SettingsSecurity = () => {
|
export const SettingsSecurity = () => {
|
||||||
const isSSOEnabled = useRecoilValue(isSSOEnabledState);
|
const isSSOEnabled = useRecoilValue(isSSOEnabledState);
|
||||||
const isSSOSectionDisplay =
|
const isSSOSectionDisplay =
|
||||||
useIsFeatureEnabled('IS_SSO_ENABLED') && isSSOEnabled;
|
useIsFeatureEnabled(FeatureFlagKey.IsSsoEnabled) && isSSOEnabled;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { isAnalyticsEnabledState } from '@/client-config/states/isAnalyticsEnabledState';
|
import { isAnalyticsEnabledState } from '@/client-config/states/isAnalyticsEnabledState';
|
||||||
|
import { useTestServerlessFunction } from '@/serverless-functions/hooks/useTestServerlessFunction';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { SettingsServerlessFunctionCodeEditorTab } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionCodeEditorTab';
|
import { SettingsServerlessFunctionCodeEditorTab } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionCodeEditorTab';
|
||||||
import { SettingsServerlessFunctionMonitoringTab } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionMonitoringTab';
|
import { SettingsServerlessFunctionMonitoringTab } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionMonitoringTab';
|
||||||
@ -20,10 +21,10 @@ import { useState } from 'react';
|
|||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { IconCode, IconGauge, IconSettings, IconTestPipe } from 'twenty-ui';
|
import { IconCode, IconGauge, IconSettings, IconTestPipe } from 'twenty-ui';
|
||||||
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
import { useTestServerlessFunction } from '@/serverless-functions/hooks/useTestServerlessFunction';
|
|
||||||
import { useDebouncedCallback } from 'use-debounce';
|
|
||||||
|
|
||||||
const TAB_LIST_COMPONENT_ID = 'serverless-function-detail';
|
const TAB_LIST_COMPONENT_ID = 'serverless-function-detail';
|
||||||
|
|
||||||
@ -122,7 +123,9 @@ export const SettingsServerlessFunctionDetail = () => {
|
|||||||
|
|
||||||
const isAnalyticsEnabled = useRecoilValue(isAnalyticsEnabledState);
|
const isAnalyticsEnabled = useRecoilValue(isAnalyticsEnabledState);
|
||||||
|
|
||||||
const isAnalyticsV2Enabled = useIsFeatureEnabled('IS_ANALYTICS_V2_ENABLED');
|
const isAnalyticsV2Enabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsAnalyticsV2Enabled,
|
||||||
|
);
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{ id: 'editor', title: 'Editor', Icon: IconCode },
|
{ id: 'editor', title: 'Editor', Icon: IconCode },
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||||
import {
|
import {
|
||||||
|
FeatureFlagKey,
|
||||||
OnboardingStatus,
|
OnboardingStatus,
|
||||||
SubscriptionInterval,
|
SubscriptionInterval,
|
||||||
SubscriptionStatus,
|
SubscriptionStatus,
|
||||||
@ -52,19 +53,13 @@ export const mockDefaultWorkspace: Workspace = {
|
|||||||
featureFlags: [
|
featureFlags: [
|
||||||
{
|
{
|
||||||
id: '1492de61-5018-4368-8923-4f1eeaf988c4',
|
id: '1492de61-5018-4368-8923-4f1eeaf988c4',
|
||||||
key: 'IS_AIRTABLE_INTEGRATION_ENABLED',
|
key: FeatureFlagKey.IsAirtableIntegrationEnabled,
|
||||||
value: true,
|
value: true,
|
||||||
workspaceId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6w',
|
workspaceId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6w',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '1492de61-5018-4368-8923-4f1eeaf988c5',
|
id: '1492de61-5018-4368-8923-4f1eeaf988c5',
|
||||||
key: 'IS_POSTGRESQL_INTEGRATION_ENABLED',
|
key: FeatureFlagKey.IsPostgreSqlIntegrationEnabled,
|
||||||
value: true,
|
|
||||||
workspaceId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6w',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1492de61-5018-4368-8923-4f1eeaf988c6',
|
|
||||||
key: 'IS_CALENDER_ENABLED',
|
|
||||||
value: true,
|
value: true,
|
||||||
workspaceId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6w',
|
workspaceId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6w',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"sourceRoot": "src",
|
"sourceRoot": "src",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"builder": "swc",
|
"builder": "swc",
|
||||||
"typeCheck": true,
|
"typeCheck": false,
|
||||||
"assets": [
|
"assets": [
|
||||||
{
|
{
|
||||||
"include": "**/serverless/drivers/constants/base-typescript-project/**",
|
"include": "**/serverless/drivers/constants/base-typescript-project/**",
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
"targets": {
|
"targets": {
|
||||||
"build": {
|
"build": {
|
||||||
"executor": "nx:run-commands",
|
"executor": "nx:run-commands",
|
||||||
|
"cache": true,
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": "packages/twenty-server",
|
"cwd": "packages/twenty-server",
|
||||||
"commands": ["rimraf dist", "nest build --path ./tsconfig.build.json"]
|
"commands": ["rimraf dist", "nest build --path ./tsconfig.build.json"]
|
||||||
@ -99,7 +100,7 @@
|
|||||||
"executor": "nx:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": "packages/twenty-server",
|
"cwd": "packages/twenty-server",
|
||||||
"command": "ts-node ../../node_modules/typeorm/cli.js"
|
"command": "ts-node --transpile-only -P tsconfig.json ../../node_modules/typeorm/cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ts-node": {
|
"ts-node": {
|
||||||
@ -117,6 +118,13 @@
|
|||||||
"command": "ts-node"
|
"command": "ts-node"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ts-node-no-deps-transpile-only": {
|
||||||
|
"executor": "nx:run-commands",
|
||||||
|
"options": {
|
||||||
|
"cwd": "packages/twenty-server",
|
||||||
|
"command": "ts-node --transpile-only"
|
||||||
|
}
|
||||||
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": ["{projectRoot}/src/**/*.{ts,json}"]
|
"lintFilePatterns": ["{projectRoot}/src/**/*.{ts,json}"]
|
||||||
@ -149,8 +157,7 @@
|
|||||||
"commands": [
|
"commands": [
|
||||||
"nx typeorm -- migration:run -d src/database/typeorm/metadata/metadata.datasource",
|
"nx typeorm -- migration:run -d src/database/typeorm/metadata/metadata.datasource",
|
||||||
"nx typeorm -- migration:run -d src/database/typeorm/core/core.datasource"
|
"nx typeorm -- migration:run -d src/database/typeorm/core/core.datasource"
|
||||||
],
|
]
|
||||||
"parallel": false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"database:migrate:revert": {
|
"database:migrate:revert": {
|
||||||
@ -161,8 +168,7 @@
|
|||||||
"commands": [
|
"commands": [
|
||||||
"nx typeorm -- migration:revert -d src/database/typeorm/metadata/metadata.datasource",
|
"nx typeorm -- migration:revert -d src/database/typeorm/metadata/metadata.datasource",
|
||||||
"nx typeorm -- migration:revert -d src/database/typeorm/core/core.datasource"
|
"nx typeorm -- migration:revert -d src/database/typeorm/core/core.datasource"
|
||||||
],
|
]
|
||||||
"parallel": false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generate:integration-test": {
|
"generate:integration-test": {
|
||||||
@ -182,8 +188,8 @@
|
|||||||
"no-seed": {
|
"no-seed": {
|
||||||
"cwd": "packages/twenty-server",
|
"cwd": "packages/twenty-server",
|
||||||
"commands": [
|
"commands": [
|
||||||
"nx ts-node-no-deps -- ./scripts/truncate-db.ts",
|
"nx ts-node-no-deps-transpile-only -- ./scripts/truncate-db.ts",
|
||||||
"nx ts-node-no-deps -- ./scripts/setup-db.ts",
|
"nx ts-node-no-deps-transpile-only -- ./scripts/setup-db.ts",
|
||||||
"nx database:migrate",
|
"nx database:migrate",
|
||||||
"nx command-no-deps -- cache:flush"
|
"nx command-no-deps -- cache:flush"
|
||||||
],
|
],
|
||||||
@ -192,8 +198,8 @@
|
|||||||
"seed": {
|
"seed": {
|
||||||
"cwd": "packages/twenty-server",
|
"cwd": "packages/twenty-server",
|
||||||
"commands": [
|
"commands": [
|
||||||
"nx ts-node-no-deps -- ./scripts/truncate-db.ts",
|
"nx ts-node-no-deps-transpile-only -- ./scripts/truncate-db.ts",
|
||||||
"nx ts-node-no-deps -- ./scripts/setup-db.ts",
|
"nx ts-node-no-deps-transpile-only -- ./scripts/setup-db.ts",
|
||||||
"nx database:migrate",
|
"nx database:migrate",
|
||||||
"nx command-no-deps -- cache:flush",
|
"nx command-no-deps -- cache:flush",
|
||||||
"nx command-no-deps -- workspace:seed:dev"
|
"nx command-no-deps -- workspace:seed:dev"
|
||||||
|
|||||||
@ -30,6 +30,11 @@ rawDataSource
|
|||||||
'create extension "uuid-ossp"',
|
'create extension "uuid-ossp"',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// We paused the work on FDW
|
||||||
|
if (process.env.IS_FDW_ENABLED !== 'true') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await performQuery(
|
await performQuery(
|
||||||
'CREATE EXTENSION IF NOT EXISTS "postgres_fdw"',
|
'CREATE EXTENSION IF NOT EXISTS "postgres_fdw"',
|
||||||
'create extension "postgres_fdw"',
|
'create extension "postgres_fdw"',
|
||||||
|
|||||||
@ -8,32 +8,30 @@ async function dropSchemasSequentially() {
|
|||||||
try {
|
try {
|
||||||
await rawDataSource.initialize();
|
await rawDataSource.initialize();
|
||||||
|
|
||||||
// Fetch all schemas
|
// Fetch all schemas excluding the ones we want to keep
|
||||||
const schemas = await performQuery(
|
const schemas = await performQuery(
|
||||||
`
|
`
|
||||||
SELECT n.nspname AS "schema_name"
|
SELECT n.nspname AS "schema_name"
|
||||||
FROM pg_catalog.pg_namespace n
|
FROM pg_catalog.pg_namespace n
|
||||||
WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'
|
WHERE n.nspname !~ '^pg_'
|
||||||
|
AND n.nspname <> 'information_schema'
|
||||||
|
AND n.nspname NOT IN ('metric_helpers', 'user_management', 'public')
|
||||||
`,
|
`,
|
||||||
'Fetching schemas...',
|
'Fetching schemas...',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Iterate over each schema and drop it
|
const batchSize = 10;
|
||||||
// This is to avoid dropping all schemas at once, which would cause an out of shared memory error
|
|
||||||
for (const schema of schemas) {
|
|
||||||
if (
|
|
||||||
schema.schema_name === 'metric_helpers' ||
|
|
||||||
schema.schema_name === 'user_management' ||
|
|
||||||
schema.schema_name === 'public'
|
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
await performQuery(
|
for (let i = 0; i < schemas.length; i += batchSize) {
|
||||||
`
|
const batch = schemas.slice(i, i + batchSize);
|
||||||
DROP SCHEMA IF EXISTS "${schema.schema_name}" CASCADE;
|
|
||||||
`,
|
await Promise.all(
|
||||||
`Dropping schema ${schema.schema_name}...`,
|
batch.map((schema) =>
|
||||||
|
performQuery(
|
||||||
|
`DROP SCHEMA IF EXISTS "${schema.schema_name}" CASCADE;`,
|
||||||
|
`Dropping schema ${schema.schema_name}...`,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,4 +17,6 @@ export enum FeatureFlagKey {
|
|||||||
IsAggregateQueryEnabled = 'IS_AGGREGATE_QUERY_ENABLED',
|
IsAggregateQueryEnabled = 'IS_AGGREGATE_QUERY_ENABLED',
|
||||||
IsViewGroupsEnabled = 'IS_VIEW_GROUPS_ENABLED',
|
IsViewGroupsEnabled = 'IS_VIEW_GROUPS_ENABLED',
|
||||||
IsPageHeaderV2Enabled = 'IS_PAGE_HEADER_V2_ENABLED',
|
IsPageHeaderV2Enabled = 'IS_PAGE_HEADER_V2_ENABLED',
|
||||||
|
IsCrmMigrationEnabled = 'IS_CRM_MIGRATION_ENABLED',
|
||||||
|
IsJsonFilterEnabled = 'IS_JSON_FILTER_ENABLED',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Field, ObjectType } from '@nestjs/graphql';
|
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql';
|
||||||
|
|
||||||
import { IDField } from '@ptc-org/nestjs-query-graphql';
|
import { IDField } from '@ptc-org/nestjs-query-graphql';
|
||||||
import {
|
import {
|
||||||
@ -24,7 +24,7 @@ export class FeatureFlagEntity {
|
|||||||
@PrimaryGeneratedColumn('uuid')
|
@PrimaryGeneratedColumn('uuid')
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
@Field(() => String)
|
@Field(() => FeatureFlagKey)
|
||||||
@Column({ nullable: false, type: 'text' })
|
@Column({ nullable: false, type: 'text' })
|
||||||
key: FeatureFlagKey;
|
key: FeatureFlagKey;
|
||||||
|
|
||||||
@ -47,3 +47,7 @@ export class FeatureFlagEntity {
|
|||||||
@UpdateDateColumn({ type: 'timestamptz' })
|
@UpdateDateColumn({ type: 'timestamptz' })
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerEnumType(FeatureFlagKey, {
|
||||||
|
name: 'FeatureFlagKey',
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user