From 00e5770273ef323a17db711f258dafa6a67f2499 Mon Sep 17 00:00:00 2001 From: Benny Joo Date: Tue, 30 Dec 2025 09:51:06 +0900 Subject: [PATCH] refactor: Move attribute and routing-forms code from `app-store`/`lib` to `features` (#26025) * mv * wip * wip * wip * wip * plural * fix: resolve TypeScript type errors for attribute refactoring - Add TransformedAttributeOption type to handle transformed contains field - Update imports to use routing-forms Attribute type where needed - Fix getValueOfAttributeOption to use TransformedAttributeOption type - Update AttributeOptionValueWithType to use TransformedAttributeOption - Fix pre-existing lint warnings (any -> unknown, proper type casting) Co-Authored-By: benny@cal.com * fix * cleanup * cleanup * fix * fix * fix * fix * fix * fix: add explicit type annotation to reduce callback in getAttributes.ts Co-Authored-By: benny@cal.com * fix: use RouterOutputs from @calcom/trpc/react for consistent type inference - Update AppPage.tsx to use RouterOutputs from @calcom/trpc/react instead of inferRouterOutputs - Update MultiDisconnectIntegration.tsx to use the same RouterOutputs type source - Add eslint-disable comments for pre-existing warnings (useEffect deps, img elements) Co-Authored-By: benny@cal.com * fix: explicitly type attribute property in AttributeOptionAssignment The attribute property from Pick was typed as 'unknown' because Prisma relations don't have explicit types when picked. This explicitly defines the attribute shape with id, type, and isLocked properties that are used in assignValueToUser.ts. Co-Authored-By: benny@cal.com * fix: remove unused assignedUsers from AttributeOptionAssignment Pick The assignedUsers property was not being used in the code but was required by the Pick type, causing a type mismatch when the actual data from the database query didn't include it. Co-Authored-By: benny@cal.com * fix: update import path for AttributeOptionAssignment and BulkAttributeAssigner types The types.d.ts file was moved from packages/lib/service/attribute/ to packages/app-store/routing-forms/types/. Updated the import path in utils.ts to point to the new location. Co-Authored-By: benny@cal.com * fix --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../teams/[id]/members/page.tsx | 2 +- .../(org-user-only)/members/page.tsx | 2 +- apps/web/components/apps/AppPage.tsx | 10 ++--- .../apps/MultiDisconnectIntegration.tsx | 8 +--- .../utils/bookingScenario/bookingScenario.ts | 9 ++-- .../app-store/_utils/raqb/raqbUtils.server.ts | 14 +++---- .../app-store/_utils/raqb/raqbUtils.test.ts | 2 +- .../lib}/resolveQueryValue.test.ts | 4 +- .../routing-forms/lib}/resolveQueryValue.ts | 5 +-- .../app-store/routing-forms/types/types.d.ts | 34 ++++++++++++++- .../attributes/lib}/getAttributes.test.ts | 4 +- .../attributes/lib}/getAttributes.ts | 42 ++++--------------- .../attributes/lib}/utils.ts | 2 +- .../PrismaAttributeOptionRepository.ts | 2 +- .../PrismaAttributeRepository.ts | 0 .../PrismaAttributeToUserRepository.ts | 2 +- .../features/bookings/lib/getLuckyUser.ts | 2 +- packages/features/di/modules/Attribute.ts | 4 +- .../ee/dsync/lib/assignValueToUser.ts | 19 +++++---- .../ee/dsync/lib/assignValueToUserUtils.ts} | 6 ++- .../AssignmentReasonRecorder.ts | 2 +- ...dTeamMembersMatchingAttributeLogic.test.ts | 13 +++--- .../findTeamMembersMatchingAttributeLogic.ts | 7 ++-- .../routing-forms/lib/getRoutedUrl.test.ts | 4 +- .../routing-forms/lib/getRoutedUrl.ts | 2 +- .../routing-forms/lib/handleResponse.test.ts | 18 ++++---- .../routing-forms/lib/handleResponse.ts | 11 +++-- packages/features/users/lib/getRoutedUsers.ts | 2 +- packages/lib/service/attribute/types.d.ts | 18 -------- packages/platform/libraries/index.ts | 2 +- packages/platform/libraries/repositories.ts | 2 +- .../getAttributesForTeam.handler.ts | 2 +- .../assignUserToAttribute.handler.ts | 2 +- ...amMembersMatchingAttributeLogic.handler.ts | 2 +- .../routers/viewer/attributes/list.handler.ts | 2 +- ...rsMatchingAttributeLogicOfRoute.handler.ts | 2 +- .../viewer/routing-forms/response.handler.ts | 2 +- 37 files changed, 130 insertions(+), 136 deletions(-) rename packages/{lib/raqb => app-store/routing-forms/lib}/resolveQueryValue.test.ts (99%) rename packages/{lib/raqb => app-store/routing-forms/lib}/resolveQueryValue.ts (98%) rename packages/{lib/service/attribute/server => features/attributes/lib}/getAttributes.test.ts (99%) rename packages/{lib/service/attribute/server => features/attributes/lib}/getAttributes.ts (93%) rename packages/{lib/service/attribute/server => features/attributes/lib}/utils.ts (84%) rename packages/{lib/server/repository => features/attributes/repositories}/PrismaAttributeOptionRepository.ts (94%) rename packages/{lib/server/repository => features/attributes/repositories}/PrismaAttributeRepository.ts (100%) rename packages/{lib/server/repository => features/attributes/repositories}/PrismaAttributeToUserRepository.ts (96%) rename packages/{lib/service/attribute/utils.ts => features/ee/dsync/lib/assignValueToUserUtils.ts} (94%) rename packages/{app-store/_utils/raqb => features/routing-forms/lib}/findTeamMembersMatchingAttributeLogic.test.ts (99%) rename packages/{app-store/_utils/raqb => features/routing-forms/lib}/findTeamMembersMatchingAttributeLogic.ts (98%) rename packages/{app-store => features}/routing-forms/lib/handleResponse.test.ts (92%) rename packages/{app-store => features}/routing-forms/lib/handleResponse.ts (94%) delete mode 100644 packages/lib/service/attribute/types.d.ts diff --git a/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/teams/[id]/members/page.tsx b/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/teams/[id]/members/page.tsx index 965db9892a..61763e299a 100644 --- a/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/teams/[id]/members/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/teams/[id]/members/page.tsx @@ -4,11 +4,11 @@ import { unstable_cache } from "next/cache"; import { headers, cookies } from "next/headers"; import { redirect } from "next/navigation"; +import { PrismaAttributeRepository } from "@calcom/features/attributes/repositories/PrismaAttributeRepository"; import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import { getTeamMemberPermissions } from "@calcom/features/pbac/lib/team-member-permissions"; import { RoleManagementFactory } from "@calcom/features/pbac/services/role-management.factory"; import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader"; -import { PrismaAttributeRepository } from "@calcom/lib/server/repository/PrismaAttributeRepository"; import { prisma } from "@calcom/prisma"; import { viewerTeamsRouter } from "@calcom/trpc/server/routers/viewer/teams/_router"; import { TeamMembersView } from "@calcom/web/modules/ee/teams/views/team-members-view"; diff --git a/apps/web/app/(use-page-wrapper)/settings/organizations/(org-user-only)/members/page.tsx b/apps/web/app/(use-page-wrapper)/settings/organizations/(org-user-only)/members/page.tsx index 97ded33368..98147f9277 100644 --- a/apps/web/app/(use-page-wrapper)/settings/organizations/(org-user-only)/members/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/organizations/(org-user-only)/members/page.tsx @@ -4,11 +4,11 @@ import { unstable_cache } from "next/cache"; import { headers, cookies } from "next/headers"; import { redirect } from "next/navigation"; +import { PrismaAttributeRepository } from "@calcom/features/attributes/repositories/PrismaAttributeRepository"; import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import { Resource, CustomAction, CrudAction } from "@calcom/features/pbac/domain/types/permission-registry"; import { getSpecificPermissions } from "@calcom/features/pbac/lib/resource-permissions"; import { RoleManagementFactory } from "@calcom/features/pbac/services/role-management.factory"; -import { PrismaAttributeRepository } from "@calcom/lib/server/repository/PrismaAttributeRepository"; import { prisma } from "@calcom/prisma"; import { MembershipRole } from "@calcom/prisma/enums"; import { viewerOrganizationsRouter } from "@calcom/trpc/server/routers/viewer/organizations/_router"; diff --git a/apps/web/components/apps/AppPage.tsx b/apps/web/components/apps/AppPage.tsx index 948b472970..06f9593130 100644 --- a/apps/web/components/apps/AppPage.tsx +++ b/apps/web/components/apps/AppPage.tsx @@ -14,10 +14,8 @@ import { getAppOnboardingUrl } from "@calcom/lib/apps/getAppOnboardingUrl"; import { APP_NAME, COMPANY_NAME, SUPPORT_MAIL_ADDRESS, WEBAPP_URL } from "@calcom/lib/constants"; import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { trpc } from "@calcom/trpc/react"; -import type { AppRouter } from "@calcom/trpc/types/server/routers/_app"; +import { trpc, type RouterOutputs } from "@calcom/trpc/react"; import type { App as AppType } from "@calcom/types/App"; -import type { inferRouterOutputs } from "@trpc/server"; import classNames from "@calcom/ui/classNames"; import { Badge } from "@calcom/ui/components/badge"; import { Button } from "@calcom/ui/components/button"; @@ -147,8 +145,7 @@ export const AppPage = ({ useGrouping: false, }).format(price); - type RouterOutput = inferRouterOutputs; - type Credentials = RouterOutput["viewer"]["apps"]["appCredentialsByType"]["credentials"]; + type Credentials = RouterOutputs["viewer"]["apps"]["appCredentialsByType"]["credentials"]; const [existingCredentials, setExistingCredentials] = useState([]); @@ -199,6 +196,7 @@ export const AppPage = ({ if (searchParams?.get("defaultInstall") === "true") { mutation.mutate({ type, variant, slug, defaultInstall: true }); } + // eslint-disable-next-line react-hooks/exhaustive-deps -- intentionally run only once on mount }, []); const installOrDisconnectAppButton = () => { @@ -317,6 +315,7 @@ export const AppPage = ({