Deprecate IS_RECORD_TABLE_WIDGET_ENABLED feature flag (#19662)

## Summary
- Removes the `IS_RECORD_TABLE_WIDGET_ENABLED` feature flag, making the
record table widget unconditionally available in dashboard widget type
selection
- The flag was already seeded as `true` for all new workspaces and only
gated UI visibility in one component
(`SidePanelPageLayoutDashboardWidgetTypeSelect`)
- Cleans up the flag from `FeatureFlagKey` enum, dev seeder, and test
mocks

## Analysis
The flag only controlled whether the "View" (Record Table) widget option
appeared in the dashboard widget type selector. The entire record table
widget infrastructure (rendering, creation hooks, GraphQL types,
`RECORD_TABLE` enum in `WidgetType`) is independent of the flag and
fully implemented. No backend logic depends on this flag.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Félix Malfait 2026-04-13 23:13:15 +02:00 committed by GitHub
parent 455022f652
commit 69d228d8a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 18 additions and 38 deletions

View file

@ -69,13 +69,14 @@ jobs:
- name: Server / Start
run: |
npx nx start twenty-server &
npx nx run twenty-server:start:ci &
echo "Waiting for server to be ready..."
timeout 60 bash -c 'until curl -s http://localhost:3000/health; do sleep 2; done'
timeout 60 bash -c 'until curl -sf http://localhost:3000/healthz; do sleep 2; done'
- name: Start worker
working-directory: packages/twenty-server
run: |
npx nx run twenty-server:worker &
NODE_ENV=development node dist/queue-worker/queue-worker.js &
echo "Worker started"
- name: Zapier / Build

View file

@ -1592,7 +1592,6 @@ enum FeatureFlagKey {
IS_CONNECTED_ACCOUNT_MIGRATED
IS_RICH_TEXT_V1_MIGRATED
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED
IS_RECORD_TABLE_WIDGET_ENABLED
IS_DATASOURCE_MIGRATED
}

View file

@ -1289,7 +1289,7 @@ export interface FeatureFlag {
__typename: 'FeatureFlag'
}
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 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_DATASOURCE_MIGRATED'
export interface WorkspaceUrls {
customUrl?: Scalars['String']
@ -9470,7 +9470,6 @@ export const enumFeatureFlagKey = {
IS_CONNECTED_ACCOUNT_MIGRATED: 'IS_CONNECTED_ACCOUNT_MIGRATED' 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,
IS_DATASOURCE_MIGRATED: 'IS_DATASOURCE_MIGRATED' as const
}

View file

@ -1823,7 +1823,6 @@ 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_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED'
}

View file

@ -22,7 +22,6 @@ import { isExistingWidgetMissingOrDifferentType } from '@/side-panel/pages/page-
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useQuery } from '@apollo/client/react';
import { t } from '@lingui/core/macro';
import { CoreObjectNameSingular, SidePanelPages } from 'twenty-shared/types';
@ -34,11 +33,7 @@ import {
IconFrame,
IconTable,
} from 'twenty-ui/display';
import {
FeatureFlagKey,
type FrontComponent,
WidgetType,
} from '~/generated-metadata/graphql';
import { type FrontComponent, WidgetType } from '~/generated-metadata/graphql';
export const SidePanelPageLayoutDashboardWidgetTypeSelect = () => {
const { pageLayoutId, recordId } = usePageLayoutIdFromContextStore();
@ -101,10 +96,6 @@ export const SidePanelPageLayoutDashboardWidgetTypeSelect = () => {
first.labelPlural.localeCompare(second.labelPlural),
)[0];
const isRecordTableWidgetEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_RECORD_TABLE_WIDGET_ENABLED,
);
const { data: frontComponentsData } = useQuery<{
frontComponents: FrontComponent[];
}>(FIND_MANY_FRONT_COMPONENTS);
@ -246,7 +237,7 @@ export const SidePanelPageLayoutDashboardWidgetTypeSelect = () => {
const selectableItemIds = [
'chart',
...(isRecordTableWidgetEnabled ? ['record-table'] : []),
'record-table',
'iframe',
'rich-text',
...frontComponentsWithSelectItemId.map(({ selectItemId }) => selectItemId),
@ -266,19 +257,17 @@ export const SidePanelPageLayoutDashboardWidgetTypeSelect = () => {
onClick={handleNavigateToGraphTypeSelect}
/>
</SelectableListItem>
{isRecordTableWidgetEnabled && (
<SelectableListItem
itemId="record-table"
onEnter={handleNavigateToRecordTableSettings}
>
<CommandMenuItem
Icon={IconTable}
label={t`View`}
id="record-table"
onClick={handleNavigateToRecordTableSettings}
/>
</SelectableListItem>
)}
<SelectableListItem
itemId="record-table"
onEnter={handleNavigateToRecordTableSettings}
>
<CommandMenuItem
Icon={IconTable}
label={t`View`}
id="record-table"
onClick={handleNavigateToRecordTableSettings}
/>
</SelectableListItem>
<SelectableListItem
itemId="iframe"
onEnter={handleNavigateToIframeSettings}

View file

@ -242,7 +242,6 @@ describe('WorkspaceEntityManager', () => {
IS_CONNECTED_ACCOUNT_MIGRATED: false,
IS_RICH_TEXT_V1_MIGRATED: false,
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: false,
IS_RECORD_TABLE_WIDGET_ENABLED: false,
IS_DATASOURCE_MIGRATED: false,
IS_COMMAND_MENU_ITEM_ENABLED: false,
},

View file

@ -60,11 +60,6 @@ export const seedFeatureFlags = async ({
workspaceId: workspaceId,
value: true,
},
{
key: FeatureFlagKey.IS_RECORD_TABLE_WIDGET_ENABLED,
workspaceId: workspaceId,
value: true,
},
])
.execute();
};

View file

@ -12,7 +12,6 @@ export enum FeatureFlagKey {
IS_CONNECTED_ACCOUNT_MIGRATED = 'IS_CONNECTED_ACCOUNT_MIGRATED',
IS_RICH_TEXT_V1_MIGRATED = 'IS_RICH_TEXT_V1_MIGRATED',
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED = 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED',
IS_RECORD_TABLE_WIDGET_ENABLED = 'IS_RECORD_TABLE_WIDGET_ENABLED',
// @deprecated - Migration is complete. Kept for backward compatibility
// until all workspaces have the flag and the flag can be removed entirely.
IS_DATASOURCE_MIGRATED = 'IS_DATASOURCE_MIGRATED',