Skip to content

Comments

refactor: migrate TeamEventTypeForm to use PBAC instead of isTeamAdminOrOwner#24034

Merged
eunjae-lee merged 12 commits intomainfrom
devin/1758705269-pbac-team-event-type-form
Sep 26, 2025
Merged

refactor: migrate TeamEventTypeForm to use PBAC instead of isTeamAdminOrOwner#24034
eunjae-lee merged 12 commits intomainfrom
devin/1758705269-pbac-team-event-type-form

Conversation

@eunjae-lee
Copy link
Contributor

What does this PR do?

This PR refactors the TeamEventTypeForm component to prepare for Permission-Based Access Control (PBAC) migration by replacing the isTeamAdminOrOwner prop with a permissions object structure. This is preparatory work that updates the component interface while maintaining backward compatibility with existing role-based logic.

Key Changes:

  • Interface Update: Replace isTeamAdminOrOwner: boolean prop with permissions: { canCreateEventType: boolean }
  • Component Logic: Update all conditional rendering to use permissions.canCreateEventType instead of isTeamAdminOrOwner
  • Parent Components: Update all consumers (CreateEventTypeDialog, event-types-view, CreateEventTypePlatformWrapper) to pass permissions object

⚠️ Important: This PR implements only the interface changes for PBAC migration. Actual server-side permission checking using PermissionCheckService and eventType.create permission strings is not yet implemented. The underlying permission logic remains role-based for now.

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A - Interface changes only, no user-facing behavior changes.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works. Note: Existing tests should pass as behavior is unchanged.

How should this be tested?

  1. Functional Testing: Verify that team event type creation still works as before:

    • Test creating collective, round-robin, and managed event types
    • Verify that managed event type option is only visible to team admins/owners
    • Test both team and personal event type creation flows
  2. Permission Validation:

    • Verify team admins/owners can still create all event type variants
    • Verify team members cannot create managed event types
    • Test behavior in event-types-view.tsx (currently hardcoded to true)
  3. No Breaking Changes: Ensure no regressions in existing event type creation workflows

Human Review Checklist

Critical Items to Review:

  • Hardcoded Permissions: event-types-view.tsx has canCreateEventType: true hardcoded - is this intentional?
  • Incomplete PBAC: Verify this is intended as preparatory work only, not full PBAC implementation
  • Interface Consistency: All parent components correctly pass permissions object with expected structure
  • Backward Compatibility: Existing role-based logic is preserved under new interface
  • Missing Server-Side Checks: Confirm that actual PermissionCheckService integration is planned for future PR

Link to Devin run: https://app.devin.ai/sessions/255f23adbea242aca3357be92000df37
Requested by: @eunjae-lee

…nOrOwner

- Replace isTeamAdminOrOwner prop with permissions.canCreateEventType
- Move permission checks to server-side using PermissionCheckService
- Use eventType.create permission string as specified in PBAC guide
- Update all parent components: CreateEventTypeDialog, event-types-view, CreateEventTypePlatformWrapper
- Follow existing PBAC patterns from event-types-listing-view.tsx
- Maintain backward compatibility with role-based fallback

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 24, 2025

Walkthrough

Adds server-side session validation and params parsing to the team event-type page (redirects to login or returns 404 on invalid/missing data). Integrates PermissionCheckService to compute per-team canCreateEventType permissions, exposes those permissions from the backend (getUserEventGroups → teamPermissions), and threads them through UI: profileOptions now include permissions, CreateEventTypeDialog is a named export with a ProfileOption type, CreateTeamEventType and TeamEventTypeForm accept a permissions prop, and page/component signatures/exports were updated accordingly.

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly captures the main change of migrating the TeamEventTypeForm component to use Permission-Based Access Control instead of the isTeamAdminOrOwner flag, which directly reflects the core refactoring performed in this pull request. It is clear, specific, and concise, enabling a quick understanding of the primary change by scanning teammates.
Description Check ✅ Passed The description clearly outlines the interface update replacing isTeamAdminOrOwner with a permissions object, details the scope and testing instructions, and correctly emphasizes that this PR is preparatory work without server-side PBAC implementation, all of which directly relate to the changeset.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch devin/1758705269-pbac-team-event-type-form

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5b8f1fb and 659c2ea.

📒 Files selected for processing (1)
  • packages/trpc/server/routers/viewer/eventTypes/getUserEventGroups.handler.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/trpc/server/routers/viewer/eventTypes/getUserEventGroups.handler.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Tests / Unit
  • GitHub Check: Production builds / Build Atoms
  • GitHub Check: Production builds / Build API v2
  • GitHub Check: Production builds / Build Docs
  • GitHub Check: Linters / lint
  • GitHub Check: Type check / check-types
  • GitHub Check: Production builds / Build API v1
  • GitHub Check: Production builds / Build Web App

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@keithwillcode keithwillcode added consumer core area: core, team members only labels Sep 24, 2025
devin-ai-integration bot and others added 2 commits September 24, 2025 09:41
- Add eventType.create permission checks to TRPC teams.get handler
- Add PBAC permission checks to platform /organizations/{orgId}/teams/me endpoint
- Update all three components to use server-side permission data instead of client-side async calls
- Add canCreateEventTypes property to platform team types
- Maintain backward compatibility with role-based fallbacks
- Remove unused imports and variables

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
- Update event-types-view.tsx to use team.canCreateEventTypes from server
- Update CreateEventTypeDialog.tsx to use team.canCreateEventTypes with fallback
- Update CreateEventTypePlatformWrapper.tsx to use team.canCreateEventTypes with fallback
- Remove hardcoded permission values and role-based checks
- Maintain backward compatibility with existing role-based logic as fallback

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
@vercel
Copy link

vercel bot commented Sep 24, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
cal Ignored Ignored Sep 26, 2025 9:16am
cal-eu Ignored Ignored Sep 26, 2025 9:16am

@pull-request-size pull-request-size bot added size/L and removed size/M labels Sep 24, 2025
@eunjae-lee eunjae-lee marked this pull request as ready for review September 24, 2025 21:16
@eunjae-lee eunjae-lee requested a review from a team September 24, 2025 21:16
@eunjae-lee eunjae-lee requested a review from a team as a code owner September 24, 2025 21:16
@graphite-app graphite-app bot requested a review from a team September 24, 2025 21:16
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/web/modules/event-types/views/event-types-listing-view.tsx (1)

947-985: Guard teamPermissions access, unify permission prop naming, and update server transform/tests

  • In apps/web/modules/event-types/views/event-types-listing-view.tsx, change the filter/map to use
    userEventGroupsData.teamPermissions?.[profile.teamId]?.canCreateEventType with a fallback to role-based logic, and always return a { canCreateEventType: boolean } object.
  • In packages/trpc/server/routers/viewer/eventTypes/utils/transformUtils.ts, rename the output field canCreateEventTypescanCreateEventType (and similarly for update/delete), and adjust all references accordingly.
  • Update tests in packages/trpc/server/routers/viewer/eventTypes/__tests__/getUserEventGroups.test.ts to expect the singular canCreateEventType property.
apps/web/modules/settings/teams/[id]/event-types-view.tsx (1)

46-49: Fix: Query enable condition can fire for invalid teamId (-1).

!!teamId is true for -1. This calls the query with an invalid id. Use a positive check.

-  const { data: team } = trpc.viewer.teams.get.useQuery(
-    { teamId: teamId ?? -1, isOrg: false },
-    { enabled: !!teamId }
-  );
+  const { data: team } = trpc.viewer.teams.get.useQuery(
+    { teamId: teamId ?? -1, isOrg: false },
+    { enabled: Number.isFinite(teamId) && teamId > 0 }
+  );
🧹 Nitpick comments (7)
packages/features/eventtypes/components/CreateEventTypeDialog.tsx (1)

79-80: Align fallback permissions with role-based logic to avoid accidental denials.

If server PBAC is missing for a team, defaulting to canCreateEventType: false may unnecessarily restrict authorized admins/owners. Mirror the filter’s role-based fallback here.

-  const permissions = teamProfile?.permissions ?? { canCreateEventType: false };
+  const permissions =
+    teamProfile?.permissions ??
+    {
+      canCreateEventType:
+        teamProfile?.membershipRole === MembershipRole.ADMIN ||
+        teamProfile?.membershipRole === MembershipRole.OWNER,
+    };

Additionally ensure MembershipRole is a value import (not type-only) to use it at runtime:

- import type { MembershipRole } from "@calcom/prisma/enums";
+ import { MembershipRole } from "@calcom/prisma/enums";
packages/trpc/server/routers/viewer/eventTypes/getUserEventGroups.handler.ts (2)

64-82: De-dupe teamIds to avoid redundant permission checks (N+1 pattern).

filteredEventTypeGroups can contain multiple groups per team. This performs duplicate checkPermission calls and wastes queries. De‑duplicate teamIds before Promise.all.

Apply this diff:

-  const teamPermissionsArray = await Promise.all(
-    filteredEventTypeGroups
-      .map((group) => group.teamId)
-      .filter((teamId): teamId is number => teamId !== null && teamId !== undefined)
-      .map(async (teamId) => {
-        const canCreateEventType = await permissionCheckService.checkPermission({
-          userId: user.id,
-          teamId: teamId,
-          permission: "eventType.create",
-          fallbackRoles: [MembershipRole.OWNER, MembershipRole.ADMIN],
-        });
-        return [teamId, { canCreateEventType }] as const;
-      })
-  );
+  const teamIds = Array.from(
+    new Set(
+      filteredEventTypeGroups
+        .map((group) => group.teamId)
+        .filter((teamId): teamId is number => teamId != null)
+    )
+  );
+
+  const teamPermissionsArray = await Promise.all(
+    teamIds.map(async (teamId) => {
+      const canCreateEventType = await permissionCheckService.checkPermission({
+        userId: user.id,
+        teamId,
+        permission: "eventType.create",
+        fallbackRoles: [MembershipRole.OWNER, MembershipRole.ADMIN],
+      });
+      return [teamId, { canCreateEventType }] as const;
+    })
+  );

64-82: Optional: Batch permission check to one query.

PermissionCheckService exposes getTeamIdsWithPermission(). You can fetch all allowed teamIds once and derive the map, reducing DB roundtrips.

Example replacement for this block:

const teamIds = Array.from(new Set(/* as above */));
const allowedTeamIds = await permissionCheckService.getTeamIdsWithPermission(user.id, "eventType.create");
const allowedSet = new Set(allowedTeamIds);
const teamPermissions = Object.fromEntries(
  teamIds.map((id) => [id, { canCreateEventType: allowedSet.has(id) }])
);

Then remove teamPermissionsArray and Object.fromEntries usage.

packages/features/ee/teams/components/TeamEventTypeForm.tsx (2)

71-71: Localize the “Slug” label.

Frontend code should use t() for text. Replace the hardcoded "Slug" with a localized key.

-              label={isPlatform ? "Slug" : `${t("url")}: ${urlPrefix}`}
+              label={isPlatform ? t("slug") : `${t("url")}: ${urlPrefix}`}
-              label={isPlatform ? "Slug" : t("url")}
+              label={isPlatform ? t("slug") : t("url")}

Also applies to: 95-95


16-28: Nit: Use PascalCase for type name.

Type aliases should be PascalCase for consistency.

-type props = {
+type Props = {
   permissions: {
     canCreateEventType: boolean;
   };
   // ...
 };
 
 export const TeamEventTypeForm = ({
   permissions,
   // ...
-}: props) => {
+}: Props) => {

Also applies to: 29-39

packages/platform/atoms/event-types/wrappers/CreateEventTypePlatformWrapper.tsx (1)

80-82: Use enum for role checks to prevent string drift.

Compare against MembershipRole to avoid typos and improve type safety.

+import { MembershipRole } from "@calcom/prisma/enums";
...
-  const permissions = {
-    canCreateEventType: team?.role === "ADMIN" || team?.role === "OWNER",
-  };
+  const permissions = {
+    canCreateEventType: [MembershipRole.ADMIN, MembershipRole.OWNER].includes(
+      (team?.role as MembershipRole) ?? ("" as MembershipRole)
+    ),
+  };
apps/web/modules/settings/teams/[id]/event-types-view.tsx (1)

23-24: Harden teamId parsing to avoid NaN.

If id is present but non-numeric, Number(...) yields NaN and propagates. Add a safe fallback.

-  const teamId = searchParams?.get("id") ? Number(searchParams.get("id")) : -1;
+  const idParam = searchParams?.get("id");
+  const parsedId = idParam != null ? Number(idParam) : -1;
+  const teamId = Number.isFinite(parsedId) ? parsedId : -1;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f11c4dd and 1f099ab.

📒 Files selected for processing (7)
  • apps/web/app/(use-page-wrapper)/settings/teams/[id]/event-type/page.tsx (2 hunks)
  • apps/web/modules/event-types/views/event-types-listing-view.tsx (4 hunks)
  • apps/web/modules/settings/teams/[id]/event-types-view.tsx (2 hunks)
  • packages/features/ee/teams/components/TeamEventTypeForm.tsx (4 hunks)
  • packages/features/eventtypes/components/CreateEventTypeDialog.tsx (4 hunks)
  • packages/platform/atoms/event-types/wrappers/CreateEventTypePlatformWrapper.tsx (1 hunks)
  • packages/trpc/server/routers/viewer/eventTypes/getUserEventGroups.handler.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Always use t() for text localization in frontend code; direct text embedding should trigger a warning

Files:

  • packages/platform/atoms/event-types/wrappers/CreateEventTypePlatformWrapper.tsx
  • apps/web/modules/settings/teams/[id]/event-types-view.tsx
  • packages/features/ee/teams/components/TeamEventTypeForm.tsx
  • apps/web/modules/event-types/views/event-types-listing-view.tsx
  • packages/features/eventtypes/components/CreateEventTypeDialog.tsx
  • apps/web/app/(use-page-wrapper)/settings/teams/[id]/event-type/page.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/platform/atoms/event-types/wrappers/CreateEventTypePlatformWrapper.tsx
  • packages/trpc/server/routers/viewer/eventTypes/getUserEventGroups.handler.ts
  • apps/web/modules/settings/teams/[id]/event-types-view.tsx
  • packages/features/ee/teams/components/TeamEventTypeForm.tsx
  • apps/web/modules/event-types/views/event-types-listing-view.tsx
  • packages/features/eventtypes/components/CreateEventTypeDialog.tsx
  • apps/web/app/(use-page-wrapper)/settings/teams/[id]/event-type/page.tsx
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/platform/atoms/event-types/wrappers/CreateEventTypePlatformWrapper.tsx
  • packages/trpc/server/routers/viewer/eventTypes/getUserEventGroups.handler.ts
  • apps/web/modules/settings/teams/[id]/event-types-view.tsx
  • packages/features/ee/teams/components/TeamEventTypeForm.tsx
  • apps/web/modules/event-types/views/event-types-listing-view.tsx
  • packages/features/eventtypes/components/CreateEventTypeDialog.tsx
  • apps/web/app/(use-page-wrapper)/settings/teams/[id]/event-type/page.tsx
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/trpc/server/routers/viewer/eventTypes/getUserEventGroups.handler.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-08-27T16:39:38.192Z
Learning: anglerfishlyy successfully implemented CAL-3076 email invitation feature for Cal.com team event-types in PR #23312. The feature allows inviting people via email directly from assignment flow, with automatic team invitation if email doesn't belong to existing team member. Implementation includes Host type modifications (userId?: number, email?: string, isPending?: boolean), CheckedTeamSelect component updates with CreatableSelect, TRPC schema validation with zod email validation, and integration with existing teamInvite system.
Learnt from: SinghaAnirban005
PR: calcom/cal.com#23343
File: packages/features/insights/server/trpc-router.ts:1080-1101
Timestamp: 2025-08-26T08:08:23.395Z
Learning: In packages/features/insights/server/trpc-router.ts, when filtering personal event types (userId provided, no teamId, not isAll), the query correctly uses user.id (authenticated user) instead of the input userId parameter for security reasons. This prevents users from accessing other users' personal event types by passing arbitrary user IDs.
📚 Learning: 2025-08-26T08:08:23.395Z
Learnt from: SinghaAnirban005
PR: calcom/cal.com#23343
File: packages/features/insights/server/trpc-router.ts:1080-1101
Timestamp: 2025-08-26T08:08:23.395Z
Learning: In packages/features/insights/server/trpc-router.ts, when filtering personal event types (userId provided, no teamId, not isAll), the query correctly uses user.id (authenticated user) instead of the input userId parameter for security reasons. This prevents users from accessing other users' personal event types by passing arbitrary user IDs.

Applied to files:

  • packages/trpc/server/routers/viewer/eventTypes/getUserEventGroups.handler.ts
  • apps/web/app/(use-page-wrapper)/settings/teams/[id]/event-type/page.tsx
📚 Learning: 2025-08-05T07:42:06.335Z
Learnt from: sean-brydon
PR: calcom/cal.com#22618
File: packages/trpc/server/routers/viewer/eventTypes/utils/transformUtils.ts:113-113
Timestamp: 2025-08-05T07:42:06.335Z
Learning: In Cal.com's getUserEventGroups handler refactor (PR #22618), the membershipCount field for team event groups is intentionally set to 0 in the new createTeamEventGroup function, as confirmed by sean-brydon (PR author). This preserves the same behavior as the old implementation that was being refactored, maintaining backward compatibility. While other parts of the codebase may use actual member counts, this specific implementation maintains the previous behavior.

Applied to files:

  • packages/trpc/server/routers/viewer/eventTypes/getUserEventGroups.handler.ts
📚 Learning: 2025-09-08T09:34:46.661Z
Learnt from: CarinaWolli
PR: calcom/cal.com#23421
File: packages/features/ee/workflows/components/AddActionDialog.tsx:171-174
Timestamp: 2025-09-08T09:34:46.661Z
Learning: In packages/features/ee/workflows/components/AddActionDialog.tsx, the actionOptions prop is guaranteed to never be empty according to maintainer CarinaWolli, so defensive checks for empty arrays are not necessary.

Applied to files:

  • packages/features/eventtypes/components/CreateEventTypeDialog.tsx
🧬 Code graph analysis (5)
packages/platform/atoms/event-types/wrappers/CreateEventTypePlatformWrapper.tsx (1)
packages/features/ee/teams/components/TeamEventTypeForm.tsx (1)
  • TeamEventTypeForm (29-164)
packages/trpc/server/routers/viewer/eventTypes/getUserEventGroups.handler.ts (2)
packages/features/pbac/services/permission-check.service.ts (1)
  • PermissionCheckService (19-290)
packages/platform/libraries/index.ts (1)
  • MembershipRole (34-34)
apps/web/modules/event-types/views/event-types-listing-view.tsx (1)
packages/features/eventtypes/components/CreateEventTypeDialog.tsx (1)
  • ProfileOption (30-39)
packages/features/eventtypes/components/CreateEventTypeDialog.tsx (1)
packages/platform/libraries/index.ts (1)
  • MembershipRole (34-34)
apps/web/app/(use-page-wrapper)/settings/teams/[id]/event-type/page.tsx (5)
packages/features/auth/lib/getServerSession.ts (1)
  • getServerSession (32-136)
apps/web/lib/buildLegacyCtx.ts (1)
  • buildLegacyRequest (47-49)
packages/features/pbac/services/permission-check.service.ts (1)
  • PermissionCheckService (19-290)
packages/platform/libraries/index.ts (1)
  • MembershipRole (34-34)
apps/web/modules/settings/teams/[id]/event-types-view.tsx (2)
  • LayoutWrapper (73-88)
  • CreateTeamEventType (19-71)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Install dependencies / Yarn install & cache
  • GitHub Check: Install dependencies / Yarn install & cache
🔇 Additional comments (10)
apps/web/modules/event-types/views/event-types-listing-view.tsx (2)

15-18: Good switch to named export and shared type.

Importing CreateEventTypeDialog as a named export and reusing the shared ProfileOption type is aligned with our guidelines and improves API clarity.


852-864: CTA prop shape update looks correct.

The CreateButton integration matches the new ProfileOption[] and passes it through to the dialog as expected.

packages/features/eventtypes/components/CreateEventTypeDialog.tsx (3)

30-39: Public ProfileOption type LGTM.

Fields align with consumers, and the permissions object is explicit and minimal.


68-68: Signature update to accept ProfileOption[] is correct.

Matches upstream consumers and removes ad-hoc typing.


128-129: Prop change to pass permissions into TeamEventTypeForm looks correct.

This completes the PBAC prop plumbing for team creation.

packages/trpc/server/routers/viewer/eventTypes/getUserEventGroups.handler.ts (1)

1-1: API extension looks good; ensure client types updated.

Importing PermissionCheckService/MembershipRole and returning teamPermissions aligns with the PBAC prep and UI needs.

Confirm all API consumers expect { eventTypeGroups, profiles, teamPermissions }. If you use a shared type for this handler’s return shape, update it accordingly to avoid implicit any.

Also applies to: 6-6, 86-86

packages/features/ee/teams/components/TeamEventTypeForm.tsx (2)

16-19: Prop migration to permissions is consistent.

Switching from isTeamAdminOrOwner to permissions.canCreateEventType is clear and aligns with the PR goal.

Also applies to: 30-31, 45-45


130-136: Managed option gating via permissions looks correct.

Conditional layout/classes and rendering based on canCreateEventType read well and keep UX consistent.

Please verify e2e/visual tests that assert visibility of the Managed option now use the new permissions prop.

Also applies to: 142-144, 147-157

packages/platform/atoms/event-types/wrappers/CreateEventTypePlatformWrapper.tsx (1)

87-91: Prop pass-through to TeamEventTypeForm is correct.

New permissions prop is wired correctly.

apps/web/modules/settings/teams/[id]/event-types-view.tsx (1)

15-17: Props and wiring to TeamEventTypeForm look good.

New CreateTeamEventType signature and permissions passthrough are consistent with the PBAC migration.

Confirm upstream caller(s) now pass the new permissions prop to CreateTeamEventType.

Also applies to: 19-20, 56-69, 58-61

@github-actions
Copy link
Contributor

github-actions bot commented Sep 25, 2025

E2E results are ready!

const canCreateEventType = await permissionCheckService.checkPermission({
userId: user.id,
teamId: teamId,
permission: "eventType.create",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use constants here

const CREATE_EVENT_TYPE_PERMISSION = "eventType.create";

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already fully typed, so if you put evnetType.create, TypeScript will throw an error :)

Comment on lines 66 to 69
const teamPermissionsArray = await Promise.all(
filteredEventTypeGroups
.map((group) => group.teamId)
.filter((teamId): teamId is number => teamId !== null && teamId !== undefined)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just more readable and easily understandable

  const teamIdsToCheck = [...new Set(
    filteredEventTypeGroups
      .map(group => group.teamId)
      .filter((id): id is number => id != null)
  )];

  const teamPermissionChecks = teamIdsToCheck.map(async (teamId) => {
    const hasPermission = await permissionCheckService.checkPermission({
      userId: user.id,
      teamId,
      permission: CREATE_EVENT_TYPE_PERMISSION,
      fallbackRoles: [MembershipRole.OWNER, MembershipRole.ADMIN],
    });

    return {
      teamId,
      permissions: { canCreateEventType: hasPermission }
    };
  });

const permissionResults = await Promise.all(teamPermissionChecks);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applied !

Copy link
Contributor

@Udit-takkar Udit-takkar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some automated tests?

@eunjae-lee
Copy link
Contributor Author

Can you add some automated tests?

In this case, the existing tests cover this refactoring.

@eunjae-lee eunjae-lee merged commit 43dd24c into main Sep 26, 2025
40 checks passed
@eunjae-lee eunjae-lee deleted the devin/1758705269-pbac-team-event-type-form branch September 26, 2025 11:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants