chore: remove draft email feature flag (#19842)

This commit is contained in:
neo773 2026-04-19 00:42:01 +05:30 committed by GitHub
parent c28c20143b
commit be9616db60
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 18 additions and 95 deletions

View file

@ -1596,7 +1596,6 @@ enum FeatureFlagKey {
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

View file

@ -1294,7 +1294,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_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_CONNECTED_ACCOUNT_MIGRATED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_DATASOURCE_MIGRATED'
export interface WorkspaceUrls {
customUrl?: Scalars['String']
@ -9516,7 +9516,6 @@ export const enumFeatureFlagKey = {
IS_PUBLIC_DOMAIN_ENABLED: 'IS_PUBLIC_DOMAIN_ENABLED' as const,
IS_EMAILING_DOMAIN_ENABLED: 'IS_EMAILING_DOMAIN_ENABLED' as const,
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_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,

View file

@ -1819,7 +1819,6 @@ export enum FeatureFlagKey {
IS_COMMAND_MENU_ITEM_ENABLED = 'IS_COMMAND_MENU_ITEM_ENABLED',
IS_CONNECTED_ACCOUNT_MIGRATED = 'IS_CONNECTED_ACCOUNT_MIGRATED',
IS_DATASOURCE_MIGRATED = 'IS_DATASOURCE_MIGRATED',
IS_DRAFT_EMAIL_ENABLED = 'IS_DRAFT_EMAIL_ENABLED',
IS_EMAILING_DOMAIN_ENABLED = 'IS_EMAILING_DOMAIN_ENABLED',
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED',

View file

@ -27,9 +27,6 @@ export const SidePanelWorkflowSelectAction = ({
onActionSelected: (selection: WorkflowActionSelection) => void;
}) => {
const isAiEnabled = useIsFeatureEnabled(FeatureFlagKey.IS_AI_ENABLED);
const isDraftEmailEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_DRAFT_EMAIL_ENABLED,
);
const { t } = useLingui();
@ -37,10 +34,6 @@ export const SidePanelWorkflowSelectAction = ({
const toolFunctions = logicFunctions.filter((fn) => fn.isTool === true);
const coreActions = isDraftEmailEnabled
? CORE_ACTIONS
: CORE_ACTIONS.filter((action) => action.type !== 'DRAFT_EMAIL');
const handleActionClick = (actionType: WorkflowActionType) => {
onActionSelected({ type: actionType });
};
@ -88,7 +81,7 @@ export const SidePanelWorkflowSelectAction = ({
{t`Core`}
</SidePanelWorkflowSelectStepTitle>
<WorkflowActionMenuItems
actions={coreActions}
actions={CORE_ACTIONS}
onClick={handleActionClick}
/>

View file

@ -3,8 +3,6 @@ import { AuthGuard } from '@nestjs/passport';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { FeatureFlagKey } from 'twenty-shared/types';
import {
AuthException,
AuthExceptionCode,
@ -13,7 +11,6 @@ import { GoogleAPIsOauthExchangeCodeForTokenStrategy } from 'src/engine/core-mod
import { TransientTokenService } from 'src/engine/core-modules/auth/token/services/transient-token.service';
import { setRequestExtraParams } from 'src/engine/core-modules/auth/utils/google-apis-set-request-extra-params.util';
import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
@ -29,7 +26,6 @@ export class GoogleAPIsOauthExchangeCodeForTokenGuard extends AuthGuard(
@InjectRepository(WorkspaceEntity)
private readonly workspaceRepository: Repository<WorkspaceEntity>,
private readonly workspaceDomainsService: WorkspaceDomainsService,
private readonly featureFlagService: FeatureFlagService,
) {
super();
}
@ -49,22 +45,12 @@ export class GoogleAPIsOauthExchangeCodeForTokenGuard extends AuthGuard(
);
}
const { workspaceId } =
await this.transientTokenService.verifyTransientToken(
state.transientToken,
);
const isDraftEmailEnabled =
await this.featureFlagService.isFeatureEnabled(
FeatureFlagKey.IS_DRAFT_EMAIL_ENABLED,
workspaceId,
);
new GoogleAPIsOauthExchangeCodeForTokenStrategy(
this.twentyConfigService,
isDraftEmailEnabled,
await this.transientTokenService.verifyTransientToken(
state.transientToken,
);
new GoogleAPIsOauthExchangeCodeForTokenStrategy(this.twentyConfigService);
setRequestExtraParams(request, {
transientToken: state.transientToken,
redirectLocation: state.redirectLocation,

View file

@ -3,8 +3,6 @@ import { AuthGuard } from '@nestjs/passport';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { FeatureFlagKey } from 'twenty-shared/types';
import {
AuthException,
AuthExceptionCode,
@ -13,7 +11,6 @@ import { GoogleAPIsOauthRequestCodeStrategy } from 'src/engine/core-modules/auth
import { TransientTokenService } from 'src/engine/core-modules/auth/token/services/transient-token.service';
import { setRequestExtraParams } from 'src/engine/core-modules/auth/utils/google-apis-set-request-extra-params.util';
import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
@ -27,7 +24,6 @@ export class GoogleAPIsOauthRequestCodeGuard extends AuthGuard('google-apis') {
@InjectRepository(WorkspaceEntity)
private readonly workspaceRepository: Repository<WorkspaceEntity>,
private readonly workspaceDomainsService: WorkspaceDomainsService,
private readonly featureFlagService: FeatureFlagService,
) {
super({
prompt: 'select_account',
@ -71,16 +67,7 @@ export class GoogleAPIsOauthRequestCodeGuard extends AuthGuard('google-apis') {
);
}
const isDraftEmailEnabled =
await this.featureFlagService.isFeatureEnabled(
FeatureFlagKey.IS_DRAFT_EMAIL_ENABLED,
workspaceId,
);
new GoogleAPIsOauthRequestCodeStrategy(
this.twentyConfigService,
isDraftEmailEnabled,
);
new GoogleAPIsOauthRequestCodeStrategy(this.twentyConfigService);
return (await super.canActivate(context)) as boolean;
} catch (err) {

View file

@ -92,24 +92,7 @@ describe('GoogleAPIScopesService', () => {
expect(result).toBe(false);
});
it('should work with the current Google API scopes when draft email is disabled', () => {
const actualGoogleScopes = [
'https://www.googleapis.com/auth/calendar.events',
'https://www.googleapis.com/auth/gmail.readonly',
'https://www.googleapis.com/auth/gmail.send',
'https://www.googleapis.com/auth/profile.emails.read',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'openid',
];
const expectedScopes = getGoogleApisOauthScopes(false);
const result = includesExpectedScopes(actualGoogleScopes, expectedScopes);
expect(result).toBe(true);
});
it('should work with the current Google API scopes when draft email is enabled', () => {
it('should work with the current Google API scopes', () => {
const actualGoogleScopes = [
'https://www.googleapis.com/auth/calendar.events',
'https://www.googleapis.com/auth/gmail.readonly',
@ -120,7 +103,7 @@ describe('GoogleAPIScopesService', () => {
'https://www.googleapis.com/auth/userinfo.profile',
'openid',
];
const expectedScopes = getGoogleApisOauthScopes(true);
const expectedScopes = getGoogleApisOauthScopes();
const result = includesExpectedScopes(actualGoogleScopes, expectedScopes);

View file

@ -30,7 +30,6 @@ export class GoogleAPIScopesService {
public async getScopesFromGoogleAccessTokenAndCheckIfExpectedScopesArePresent(
accessToken: string,
isDraftEmailEnabled = false,
): Promise<{ scopes: string[]; isValid: boolean }> {
try {
const httpClient = this.secureHttpClientService.getHttpClient();
@ -41,7 +40,7 @@ export class GoogleAPIScopesService {
);
const scopes = response.data.scope.split(' ');
const expectedScopes = getGoogleApisOauthScopes(isDraftEmailEnabled);
const expectedScopes = getGoogleApisOauthScopes();
return {
scopes,

View file

@ -5,7 +5,6 @@ import {
CalendarChannelSyncStage,
type CalendarChannelVisibility,
ConnectedAccountProvider,
FeatureFlagKey,
MessageChannelSyncStage,
MessageChannelSyncStatus,
type MessageChannelVisibility,
@ -23,7 +22,6 @@ import { CreateMessageChannelService } from 'src/engine/core-modules/auth/servic
import { GoogleAPIScopesService } from 'src/engine/core-modules/auth/services/google-apis-scopes';
import { GoogleApisServiceAvailabilityService } from 'src/engine/core-modules/auth/services/google-apis-service-availability.service';
import { UpdateConnectedAccountOnReconnectService } from 'src/engine/core-modules/auth/services/update-connected-account-on-reconnect.service';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { SyncMessageFoldersService } from 'src/modules/messaging/message-folder-manager/services/sync-message-folders.service';
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
@ -67,7 +65,6 @@ export class GoogleAPIsService {
private readonly updateConnectedAccountOnReconnectService: UpdateConnectedAccountOnReconnectService,
private readonly googleAPIScopesService: GoogleAPIScopesService,
private readonly googleApisServiceAvailabilityService: GoogleApisServiceAvailabilityService,
private readonly featureFlagService: FeatureFlagService,
private readonly syncMessageFoldersService: SyncMessageFoldersService,
@InjectRepository(ConnectedAccountEntity)
private readonly connectedAccountRepository: Repository<ConnectedAccountEntity>,
@ -108,15 +105,9 @@ export class GoogleAPIsService {
'MESSAGING_PROVIDER_GMAIL_ENABLED',
);
const isDraftEmailEnabled = await this.featureFlagService.isFeatureEnabled(
FeatureFlagKey.IS_DRAFT_EMAIL_ENABLED,
workspaceId,
);
const { scopes, isValid } =
await this.googleAPIScopesService.getScopesFromGoogleAccessTokenAndCheckIfExpectedScopesArePresent(
input.accessToken,
isDraftEmailEnabled,
);
if (!isValid) {

View file

@ -14,11 +14,8 @@ export abstract class GoogleAPIsOauthCommonStrategy extends PassportStrategy(
Strategy,
'google-apis',
) {
constructor(
twentyConfigService: TwentyConfigService,
isDraftEmailEnabled = false,
) {
const scopes = getGoogleApisOauthScopes(isDraftEmailEnabled);
constructor(twentyConfigService: TwentyConfigService) {
const scopes = getGoogleApisOauthScopes();
super({
clientID: twentyConfigService.get('AUTH_GOOGLE_CLIENT_ID'),

View file

@ -13,11 +13,8 @@ import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twent
@Injectable()
export class GoogleAPIsOauthExchangeCodeForTokenStrategy extends GoogleAPIsOauthCommonStrategy {
constructor(
twentyConfigService: TwentyConfigService,
isDraftEmailEnabled = false,
) {
super(twentyConfigService, isDraftEmailEnabled);
constructor(twentyConfigService: TwentyConfigService) {
super(twentyConfigService);
}
async validate(

View file

@ -12,11 +12,8 @@ export type GoogleAPIScopeConfig = {
@Injectable()
export class GoogleAPIsOauthRequestCodeStrategy extends GoogleAPIsOauthCommonStrategy {
constructor(
twentyConfigService: TwentyConfigService,
isDraftEmailEnabled = false,
) {
super(twentyConfigService, isDraftEmailEnabled);
constructor(twentyConfigService: TwentyConfigService) {
super(twentyConfigService);
}
// oxlint-disable-next-line @typescripttypescript/no-explicit-any

View file

@ -1,7 +1,7 @@
/** email, profile and openid permission can be called without the https://www.googleapis.com/auth/ prefix
* see https://developers.google.com/identity/protocols/oauth2/scopes
*/
export const getGoogleApisOauthScopes = (isDraftEmailEnabled = false) => {
export const getGoogleApisOauthScopes = () => {
return [
'email',
'profile',
@ -9,8 +9,6 @@ export const getGoogleApisOauthScopes = (isDraftEmailEnabled = false) => {
'https://www.googleapis.com/auth/calendar.events',
'https://www.googleapis.com/auth/profile.emails.read',
'https://www.googleapis.com/auth/gmail.send',
...(isDraftEmailEnabled
? ['https://www.googleapis.com/auth/gmail.compose']
: []),
'https://www.googleapis.com/auth/gmail.compose',
];
};

View file

@ -238,7 +238,6 @@ describe('WorkspaceEntityManager', () => {
IS_PUBLIC_DOMAIN_ENABLED: false,
IS_EMAILING_DOMAIN_ENABLED: false,
IS_JUNCTION_RELATIONS_ENABLED: false,
IS_DRAFT_EMAIL_ENABLED: false,
IS_CONNECTED_ACCOUNT_MIGRATED: false,
IS_RICH_TEXT_V1_MIGRATED: false,
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: false,

View file

@ -8,7 +8,6 @@ export enum FeatureFlagKey {
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
IS_EMAILING_DOMAIN_ENABLED = 'IS_EMAILING_DOMAIN_ENABLED',
IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED',
IS_DRAFT_EMAIL_ENABLED = 'IS_DRAFT_EMAIL_ENABLED',
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',