feat: add toggle to opt out of booking title translation in instant meetings (#25547)

* feat: add toggle to opt out of booking title translation in instant meetings

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add autoTranslateTitleEnabled to test builder

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: respect autoTranslateTitleEnabled toggle in InstantBookingCreateService

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: fetch autoTranslateTitleEnabled directly in InstantBookingCreateService

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* refactor: rename autoTranslateTitleEnabled to autoTranslateInstantMeetingTitleEnabled

- Renamed field to clarify it only applies to instant meeting title translation
- Moved Prisma query to EventTypeRepository.findInstantMeetingConfigById()
- Removed title translation logic from update.handler.ts (flag only controls instant meeting title)
- Updated all references across the codebase
- Added new i18n translation keys for the renamed field

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add autoTranslateInstantMeetingTitleEnabled to test destructuring patterns

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: use Prisma.TeamCreateInput type for metadata in test helper

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add autoTranslateInstantMeetingTitleEnabled to mockUpdatedEventType in test

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* refactor: use generic findByIdMinimal instead of business-specific method

- Add autoTranslateInstantMeetingTitleEnabled to eventTypeSelect constant
- Remove findInstantMeetingConfigById from EventTypeRepository
- Update InstantBookingCreateService to use findByIdMinimal

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* refactor: remove autoTranslateInstantMeetingTitleEnabled from eventTypeSelect (not needed for findByIdMinimal)

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* feat: add autoTranslateInstantMeetingTitleEnabled to event type form defaults

- Rename shouldTranslateTitle to shouldAutoTranslateInstantMeetingTitle for clarity
- Add autoTranslateInstantMeetingTitleEnabled to findById and findByIdForOrgAdmin selects
- Add autoTranslateInstantMeetingTitleEnabled to useEventTypeForm defaultValues

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: only update autoTranslateInstantMeetingTitleEnabled when explicitly provided

Fixes issue where omitting the field in update requests would overwrite
the saved opt-out setting with the default value (true). Now the field
is only included in the update payload when explicitly provided.

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Joe Au-Yeung
2025-12-09 13:51:51 +00:00
committed by GitHub
co-authored by joe@cal.com <j.auyeung419@gmail.com> Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
parent 6ae2ce8ed9
commit 3a59cd41cc
14 changed files with 57 additions and 17 deletions
@@ -93,6 +93,7 @@ export const updateHandler = async ({ ctx, input }: UpdateOptions) => {
aiPhoneCallConfig,
isRRWeightsEnabled,
autoTranslateDescriptionEnabled,
autoTranslateInstantMeetingTitleEnabled,
description: newDescription,
title: newTitle,
seatsPerTimeSlot,
@@ -231,7 +232,8 @@ export const updateHandler = async ({ ctx, input }: UpdateOptions) => {
const data: Prisma.EventTypeUpdateInput = {
...rest,
// autoTranslate feature is allowed for org users only
// Only update autoTranslateInstantMeetingTitleEnabled when explicitly provided to avoid overwriting saved opt-out
...(autoTranslateInstantMeetingTitleEnabled !== undefined && { autoTranslateInstantMeetingTitleEnabled }),
// Only set if explicitly provided to avoid overwriting existing value with false
...(autoTranslateDescriptionEnabled !== undefined && {
autoTranslateDescriptionEnabled: Boolean(ctx.user.organizationId && autoTranslateDescriptionEnabled),
@@ -1,10 +1,9 @@
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { prisma } from "@calcom/prisma";
import type { Team, User, Membership, Profile } from "@calcom/prisma/client";
import type { Prisma, Team, User, Membership, Profile } from "@calcom/prisma/client";
import { MembershipRole } from "@calcom/prisma/enums";
import type { TrpcSessionUser } from "@calcom/trpc/server/types";
import type { JsonValue } from "@calcom/types/Json";
import inviteMemberHandler, { inviteMembersWithNoInviterPermissionCheck } from "./inviteMember.handler";
@@ -66,7 +65,7 @@ async function createTestTeam(data: {
slug: string;
isOrganization?: boolean;
parentId?: number;
metadata?: JsonValue;
metadata?: Prisma.TeamCreateInput["metadata"];
organizationSettings?: {
orgAutoAcceptEmail: string;
isOrganizationVerified?: boolean;