From 65b2baca7ac10b119cbab14d929035dbc8798d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Fri, 10 Apr 2026 19:12:33 +0200 Subject: [PATCH] Remove IS_USAGE_ANALYTICS_ENABLED feature flag (#19566) ## Summary This PR removes the `IS_USAGE_ANALYTICS_ENABLED` feature flag and makes usage analytics features universally available. The feature flag guard has been removed from the usage analytics resolver and all conditional rendering based on this flag has been eliminated. ## Key Changes - **Removed feature flag dependency**: Deleted `IS_USAGE_ANALYTICS_ENABLED` from the `FeatureFlagKey` enum in `twenty-shared` - **Updated AI Usage tab**: Simplified `SettingsAIUsageTab` to remove enterprise access checks and feature flag conditionals, now only checks if ClickHouse is configured - **Updated Usage Analytics section**: Removed feature flag guard from `SettingsUsageAnalyticsSection` and added loading/empty state handling - **Updated AI settings navigation**: Made the Usage tab always visible in the AI settings tabs, removing conditional rendering based on feature flag - **Updated Billing Credits section**: Removed feature flag check before showing the "View usage" button - **Updated Settings routes**: Removed `SettingsProtectedRouteWrapper` with feature flag requirement from usage routes - **Updated GraphQL resolver**: Removed `@RequireFeatureFlag` decorator and `FeatureFlagGuard` from the `getUsageAnalytics` query - **Updated dev seeder**: Removed the feature flag seed entry for `IS_USAGE_ANALYTICS_ENABLED` ## Implementation Details - Usage analytics now gracefully handles loading states with `UsageSectionSkeleton` - Empty state messaging is shown when no usage data is available yet - ClickHouse configuration remains the only requirement for usage analytics functionality - All enterprise-specific gating for AI usage analytics has been removed in favor of ClickHouse availability checks https://claude.ai/code/session_01MRFVXtquL3wS7qmQkDU3AT --------- Co-authored-by: Claude --- .../src/metadata/generated/schema.graphql | 1 - .../src/metadata/generated/schema.ts | 3 +- .../src/generated-metadata/graphql.ts | 3 +- .../modules/app/components/SettingsRoutes.tsx | 21 +++-------- .../SettingsBillingCreditsSection.tsx | 30 +++++---------- .../SettingsUsageAnalyticsSection.tsx | 33 +++++++++++++++++ .../src/pages/settings/ai/SettingsAI.tsx | 20 +++------- .../ai/components/SettingsAIUsageTab.tsx | 37 +++++++++++++++++++ .../core-modules/usage/usage.resolver.ts | 7 ---- .../workspace-entity-manager.spec.ts | 1 - .../core/utils/seed-feature-flags.util.ts | 5 --- .../twenty-shared/src/types/FeatureFlagKey.ts | 1 - 12 files changed, 92 insertions(+), 70 deletions(-) diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql index d14922c0815..6a05e4f1690 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql @@ -1741,7 +1741,6 @@ enum FeatureFlagKey { IS_JUNCTION_RELATIONS_ENABLED IS_DRAFT_EMAIL_ENABLED IS_CONNECTED_ACCOUNT_MIGRATED - IS_USAGE_ANALYTICS_ENABLED IS_RICH_TEXT_V1_MIGRATED IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED IS_RECORD_TABLE_WIDGET_ENABLED diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.ts b/packages/twenty-client-sdk/src/metadata/generated/schema.ts index 1d99496c36d..b99a7eb632b 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.ts +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.ts @@ -1437,7 +1437,7 @@ export interface PublicFeatureFlag { __typename: 'PublicFeatureFlag' } -export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_USAGE_ANALYTICS_ENABLED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_RECORD_TABLE_WIDGET_ENABLED' | 'IS_DATASOURCE_MIGRATED' +export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_RECORD_TABLE_WIDGET_ENABLED' | 'IS_DATASOURCE_MIGRATED' export interface ClientConfigMaintenanceMode { startAt: Scalars['DateTime'] @@ -9321,7 +9321,6 @@ export const enumFeatureFlagKey = { IS_JUNCTION_RELATIONS_ENABLED: 'IS_JUNCTION_RELATIONS_ENABLED' as const, IS_DRAFT_EMAIL_ENABLED: 'IS_DRAFT_EMAIL_ENABLED' as const, IS_CONNECTED_ACCOUNT_MIGRATED: 'IS_CONNECTED_ACCOUNT_MIGRATED' as const, - IS_USAGE_ANALYTICS_ENABLED: 'IS_USAGE_ANALYTICS_ENABLED' as const, IS_RICH_TEXT_V1_MIGRATED: 'IS_RICH_TEXT_V1_MIGRATED' as const, IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' as const, IS_RECORD_TABLE_WIDGET_ENABLED: 'IS_RECORD_TABLE_WIDGET_ENABLED' as const, diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 7bc85642e3f..705dbfb46bd 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1767,8 +1767,7 @@ export enum FeatureFlagKey { IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED = 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED', IS_RECORD_TABLE_WIDGET_ENABLED = 'IS_RECORD_TABLE_WIDGET_ENABLED', IS_RICH_TEXT_V1_MIGRATED = 'IS_RICH_TEXT_V1_MIGRATED', - IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED', - IS_USAGE_ANALYTICS_ENABLED = 'IS_USAGE_ANALYTICS_ENABLED' + IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED' } export type Field = { diff --git a/packages/twenty-front/src/modules/app/components/SettingsRoutes.tsx b/packages/twenty-front/src/modules/app/components/SettingsRoutes.tsx index f13f24d4141..be5c5dec0d0 100644 --- a/packages/twenty-front/src/modules/app/components/SettingsRoutes.tsx +++ b/packages/twenty-front/src/modules/app/components/SettingsRoutes.tsx @@ -6,10 +6,7 @@ import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLo import { SettingPublicDomain } from '@/settings/domains/components/SettingPublicDomain'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; -import { - FeatureFlagKey, - PermissionFlagType, -} from '~/generated-metadata/graphql'; +import { PermissionFlagType } from '~/generated-metadata/graphql'; const SettingsGraphQLPlayground = lazy(() => import( @@ -561,19 +558,11 @@ export const SettingsRoutes = ({ isAdminPageEnabled }: SettingsRoutesProps) => ( element={} /> } /> + } /> - } - > - } /> - } - /> - + path={SettingsPath.UsageUserDetail} + element={} + /> } diff --git a/packages/twenty-front/src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx b/packages/twenty-front/src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx index bd34339ff5b..8631fed8135 100644 --- a/packages/twenty-front/src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx +++ b/packages/twenty-front/src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx @@ -7,7 +7,6 @@ import { useBillingWording } from '@/settings/billing/hooks/useBillingWording'; import { useCurrentBillingFlags } from '@/settings/billing/hooks/useCurrentBillingFlags'; import { useCurrentMetered } from '@/settings/billing/hooks/useCurrentMetered'; import { useGetWorkflowNodeExecutionUsage } from '@/settings/billing/hooks/useGetWorkflowNodeExecutionUsage'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; @@ -20,10 +19,7 @@ import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; import { UndecoratedLink } from 'twenty-ui/navigation'; import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants'; -import { - FeatureFlagKey, - SubscriptionStatus, -} from '~/generated-metadata/graphql'; +import { SubscriptionStatus } from '~/generated-metadata/graphql'; const StyledCreditUsageFooterActions = styled.div` margin-top: ${themeCssVariables.spacing[4]}; @@ -44,10 +40,6 @@ export const SettingsBillingCreditsSection = ({ const { getCurrentMeteredPricesByInterval } = useCurrentMetered(); - const isUsageAnalyticsEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_USAGE_ANALYTICS_ENABLED, - ); - const { getIntervalLabel } = useBillingWording(); const isTrialing = subscriptionStatus === SubscriptionStatus.Trialing; @@ -143,17 +135,15 @@ export const SettingsBillingCreditsSection = ({ )} - {isUsageAnalyticsEnabled && ( - - -