Add record table widget feature flag (#18960)

Introduce a new feature flag for the record table widget, enabling
conditional rendering and state management based on its status. Update
related components and tests accordingly.

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
This commit is contained in:
Lucas Bordeau
2026-03-25 17:47:20 +01:00
committed by GitHub
parent cc247c2e8e
commit 33a474c8e6
9 changed files with 46 additions and 26 deletions
@@ -1746,6 +1746,7 @@ enum FeatureFlagKey {
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED
IS_CONNECTED_ACCOUNT_MIGRATED
IS_GRAPHQL_QUERY_TIMING_ENABLED
IS_RECORD_TABLE_WIDGET_ENABLED
}
type ClientConfig {
@@ -1427,7 +1427,7 @@ export interface PublicFeatureFlag {
__typename: 'PublicFeatureFlag'
}
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_APPLICATION_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_DASHBOARD_V2_ENABLED' | 'IS_ATTACHMENT_MIGRATED' | 'IS_NOTE_TARGET_MIGRATED' | 'IS_TASK_TARGET_MIGRATED' | 'IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_NAVIGATION_MENU_ITEM_ENABLED' | 'IS_DATE_TIME_WHOLE_DAY_FILTER_ENABLED' | 'IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_USAGE_ANALYTICS_ENABLED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_DIRECT_GRAPHQL_EXECUTION_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_GRAPHQL_QUERY_TIMING_ENABLED'
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_APPLICATION_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_DASHBOARD_V2_ENABLED' | 'IS_ATTACHMENT_MIGRATED' | 'IS_NOTE_TARGET_MIGRATED' | 'IS_TASK_TARGET_MIGRATED' | 'IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_NAVIGATION_MENU_ITEM_ENABLED' | 'IS_DATE_TIME_WHOLE_DAY_FILTER_ENABLED' | 'IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_USAGE_ANALYTICS_ENABLED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_DIRECT_GRAPHQL_EXECUTION_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_GRAPHQL_QUERY_TIMING_ENABLED' | 'IS_RECORD_TABLE_WIDGET_ENABLED'
export interface ClientConfig {
appVersion?: Scalars['String']
@@ -9154,7 +9154,8 @@ export const enumFeatureFlagKey = {
IS_DIRECT_GRAPHQL_EXECUTION_ENABLED: 'IS_DIRECT_GRAPHQL_EXECUTION_ENABLED' as const,
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' as const,
IS_CONNECTED_ACCOUNT_MIGRATED: 'IS_CONNECTED_ACCOUNT_MIGRATED' as const,
IS_GRAPHQL_QUERY_TIMING_ENABLED: 'IS_GRAPHQL_QUERY_TIMING_ENABLED' as const
IS_GRAPHQL_QUERY_TIMING_ENABLED: 'IS_GRAPHQL_QUERY_TIMING_ENABLED' as const,
IS_RECORD_TABLE_WIDGET_ENABLED: 'IS_RECORD_TABLE_WIDGET_ENABLED' as const
}
export const enumConfigSource = {
@@ -1720,6 +1720,7 @@ export enum FeatureFlagKey {
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED',
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_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED = 'IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED',
IS_TASK_TARGET_MIGRATED = 'IS_TASK_TARGET_MIGRATED',
@@ -1,12 +1,16 @@
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { userLookupResultState } from '@/settings/admin-panel/states/userLookupResultState';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
import { type FeatureFlagKey } from '~/generated-metadata/graphql';
import { isDefined } from 'twenty-shared/utils';
import { type FeatureFlagKey } from '~/generated-metadata/graphql';
export const useFeatureFlagState = () => {
const [userLookupResult, setUserLookupResult] = useAtomState(
userLookupResultState,
);
const [currentWorkspace, setCurrentWorkspace] = useAtomState(
currentWorkspaceState,
);
const updateFeatureFlagState = (
workspaceId: string,
@@ -28,6 +32,15 @@ export const useFeatureFlagState = () => {
: workspace,
),
});
if (isDefined(currentWorkspace) && currentWorkspace.id === workspaceId) {
setCurrentWorkspace({
...currentWorkspace,
featureFlags: currentWorkspace.featureFlags?.map((flag) =>
flag.key === featureFlag ? { ...flag, value } : flag,
),
});
}
};
return {
@@ -90,6 +90,10 @@ export const SidePanelPageLayoutWidgetTypeSelect = () => {
FeatureFlagKey.IS_APPLICATION_ENABLED,
);
const isRecordTableWidgetEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_RECORD_TABLE_WIDGET_ENABLED,
);
const { data: frontComponentsData } = useQuery<{
frontComponents: FrontComponent[];
}>(FIND_MANY_FRONT_COMPONENTS, {
@@ -226,7 +230,7 @@ export const SidePanelPageLayoutWidgetTypeSelect = () => {
const selectableItemIds = [
'chart',
'record-table',
...(isRecordTableWidgetEnabled ? ['record-table'] : []),
'iframe',
'rich-text',
...frontComponentsWithSelectItemId.map(({ selectItemId }) => selectItemId),
@@ -246,17 +250,19 @@ export const SidePanelPageLayoutWidgetTypeSelect = () => {
onClick={handleNavigateToGraphTypeSelect}
/>
</SelectableListItem>
<SelectableListItem
itemId="record-table"
onEnter={handleNavigateToRecordTableSettings}
>
<CommandMenuItem
Icon={IconTable}
label={t`Record Table`}
id="record-table"
onClick={handleNavigateToRecordTableSettings}
/>
</SelectableListItem>
{isRecordTableWidgetEnabled && (
<SelectableListItem
itemId="record-table"
onEnter={handleNavigateToRecordTableSettings}
>
<CommandMenuItem
Icon={IconTable}
label={t`Record Table`}
id="record-table"
onClick={handleNavigateToRecordTableSettings}
/>
</SelectableListItem>
)}
<SelectableListItem
itemId="iframe"
onEnter={handleNavigateToIframeSettings}
@@ -5,21 +5,19 @@ import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomState
import { useQuery } from '@apollo/client/react';
import { styled } from '@linaria/react';
import { useLingui } from '@lingui/react/macro';
import { useContext } from 'react';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
import { Tag } from 'twenty-ui/components';
import {
CommandBlock,
H2Title,
IconApps,
IconChevronRight,
IconCopy,
IconFileInfo,
} from 'twenty-ui/display';
import { Button } from 'twenty-ui/input';
import { Section } from 'twenty-ui/layout';
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
import { Tag } from 'twenty-ui/components';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
type ApplicationRegistrationFragmentFragment,
ApplicationRegistrationSourceType,
@@ -31,12 +29,6 @@ const StyledButtonContainer = styled.div`
margin: ${themeCssVariables.spacing[2]} 0;
`;
const StyledRowRightContainer = styled.div`
align-items: center;
display: flex;
gap: ${themeCssVariables.spacing[2]};
`;
const SOURCE_TYPE_BADGE_CONFIG: Record<
ApplicationRegistrationSourceType,
{ label: string; color: 'gray' | 'blue' | 'green' }
@@ -60,7 +52,6 @@ const SOURCE_TYPE_BADGE_CONFIG: Record<
};
export const SettingsApplicationsDeveloperTab = () => {
const { theme } = useContext(ThemeContext);
const { t } = useLingui();
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
@@ -251,6 +251,7 @@ describe('WorkspaceEntityManager', () => {
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: false,
IS_CONNECTED_ACCOUNT_MIGRATED: false,
IS_GRAPHQL_QUERY_TIMING_ENABLED: false,
IS_RECORD_TABLE_WIDGET_ENABLED: false,
},
userWorkspaceRoleMap: {},
eventEmitterService: {
@@ -115,6 +115,11 @@ export const seedFeatureFlags = async ({
workspaceId: workspaceId,
value: true,
},
{
key: FeatureFlagKey.IS_RECORD_TABLE_WIDGET_ENABLED,
workspaceId: workspaceId,
value: true,
},
])
.execute();
};
@@ -24,4 +24,5 @@ export enum FeatureFlagKey {
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED = 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED',
IS_CONNECTED_ACCOUNT_MIGRATED = 'IS_CONNECTED_ACCOUNT_MIGRATED',
IS_GRAPHQL_QUERY_TIMING_ENABLED = 'IS_GRAPHQL_QUERY_TIMING_ENABLED',
IS_RECORD_TABLE_WIDGET_ENABLED = 'IS_RECORD_TABLE_WIDGET_ENABLED',
}