Skip to content

[WEB-3964] refactor: permission layer#7094

Merged
sriramveeraghanta merged 6 commits intopreviewfrom
refactor-permission-layer
May 30, 2025
Merged

[WEB-3964] refactor: permission layer#7094
sriramveeraghanta merged 6 commits intopreviewfrom
refactor-permission-layer

Conversation

@prateekshourya29
Copy link
Member

@prateekshourya29 prateekshourya29 commented May 20, 2025

Description

  • Refactored permission layer to use computed methods for project and workspace access checks.
  • Replaced direct permission data access with the following methods across the platform:
    • getWorkspaceRoleByWorkspaceSlug
    • getProjectRolesByWorkspaceSlug
    • getProjectRoleByWorkspaceSlugAndProjectId

Also updated allowPermissions to rely on these methods internally for consistent permission handling.

Type of Change

  • Code refactoring

Summary by CodeRabbit

  • New Features

    • Added singular "member" translation key across all supported languages for improved localization.
    • Introduced new helper functions and UI components for project member management, including teamspace list placeholders.
  • Improvements

    • Enhanced project member role handling with more explicit and flexible role types, including preservation of original roles.
    • Refactored member and permission stores for better type safety, abstraction, and extensibility.
    • Updated project settings and member management components to use explicit props for workspace and project IDs.
    • Improved internationalization by updating translation keys and label handling in project settings and buttons.
    • Refined UI layouts and styling for member lists and loaders.
  • Bug Fixes

    • Improved error handling and type correctness in member role update flows.
  • Chores

    • Reorganized imports and code structure for better maintainability.
    • Added proxy files for module re-exports to streamline codebase structure.
  • Documentation

    • Added and updated JSDoc comments for new helper functions.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 20, 2025

Walkthrough

This update introduces a new singular "member" translation key across all supported locales, refactors project membership types for improved flexibility, and restructures member and permission store logic for better abstraction and extensibility. Several React components and hooks are updated to use explicit props, new helper functions, and revised permission retrieval methods. Minor UI and translation improvements are also included.

Changes

Files/Groups Change Summary
packages/i18n/src/locales/*/translations.json Added the "member" key with appropriate singular translations to the "common" section for all supported locales. No other content changed.
packages/types/src/project/projects.d.ts, packages/types/src/workspace.d.ts Removed IProjectMember and replaced IProjectMembership with a new discriminated union type TProjectMembership. Updated references in workspace types to use TProjectMembership[].
packages/utils/src/index.ts, packages/utils/src/permission.ts Added and exported a new utility function getHighestRole for determining the highest role in a list. Exported the permission module from the utils index.
web/ce/components/projects/settings/useProjectColumns.tsx, web/core/components/project/settings/member-columns.tsx Refactored hooks and components to use explicit projectId and workspaceSlug props, extended row data types to include original_role, updated role management logic, and improved type safety and error handling for member columns.
web/ce/components/projects/teamspaces/* Introduced a new ProjectTeamspaceList component and exported it, currently as a placeholder.
web/ce/constants/project/settings/tabs.ts, web/core/components/project/create/project-create-buttons.tsx Updated i18n label keys for project settings and cancel button to use the "common" namespace.
web/ce/helpers/project-settings.ts, web/ee/helpers/project-settings.ts Added a new helper for retrieving project settings page label i18n keys and re-exported it for EE.
web/ce/store/member/project-member.store.ts, web/ee/store/member/project-member.store.ts Added a new ProjectMemberStore class extending an abstract base, implementing role retrieval and member removal logic. EE version re-exports the CE implementation.
web/ce/store/user/permission.store.ts, web/ee/store/user/permission.store.ts Added a new UserPermissionStore class extending an abstract base, implementing project role retrieval by workspace slug and project ID. EE version re-exports the CE implementation.
web/core/components/auth-screens/project/join-project.tsx Refactored to accept projectId and isPrivateProject props, updated UI and join logic accordingly, and improved messaging for private projects.
web/core/components/inbox/content/root.tsx, web/core/components/issues/issue-detail/issue-activity/root.tsx, web/core/layouts/auth-layout/project-wrapper.tsx, web/core/lib/posthog-provider.tsx, web/core/local-db/utils/query-sanitizer.ts.ts, web/core/store/pages/project-page.store.ts, web/core/store/pages/project-page.ts Replaced direct permission object lookups with new getProjectRoleByWorkspaceSlugAndProjectId method for retrieving project roles.
web/core/components/project/member-list-item.tsx, web/core/components/project/member-list.tsx, web/core/components/project/send-project-invitation-modal.tsx, web/core/components/project/project-settings-member-defaults.tsx Refactored to use explicit projectId and workspaceSlug props, updated filtering and member retrieval logic, and improved structure and reusability of settings UI.
web/core/components/project/member-select.tsx Updated to use EUserProjectRoles for guest checks, adjusted UI class names.
web/core/components/project/multi-select-modal.tsx Localized button labels using the translation function.
web/core/components/ui/loader/settings/members.tsx Updated loader UI to use grid layout, reduced placeholders, and removed animation.
web/core/components/settings/project/sidebar/nav-item-children.tsx Switched to using a helper function for i18n key derivation in project settings sidebar.
web/core/components/workspace/settings/members-list.tsx Minor JSX formatting improvement for readability.
web/core/hooks/store/user/user-permissions.ts Updated import path for IUserPermissionStore type.
web/core/services/project/project-member.service.ts Updated all method signatures to use TProjectMembership instead of legacy types.
web/core/store/member/base-project-member.store.ts Refactored to an abstract base class with new computed helpers, abstract methods for role retrieval and member removal, and improved type safety with TProjectMembership.
web/core/store/member/index.ts Updated imports to new store paths and changed constructor parameter to new RootStore type.
web/core/store/root.store.ts Cast this to RootStore when instantiating UserStore and MemberRootStore.
web/core/store/user/base-permissions.store.ts Refactored to an abstract base class, renamed types, added new computed methods for role retrieval, page access, and improved type safety.
web/core/store/user/index.ts Updated imports, constructor parameter, and replaced direct property access with method call for project roles by workspace.
apiserver/plane/app/serializers/project.py Added original_role field to the ProjectMemberRoleSerializer, included it in serialized fields, and marked it as read-only.
web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/layout.tsx Replaced direct workspace role access with new method call and clarified authorization logic.
web/app/(all)/[workspaceSlug]/(settings)/settings/projects/[projectId]/members/page.tsx Used route params for IDs, localized title, and passed props to settings and member components. Added the new teamspace list component.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI_Component
    participant Store
    participant PermissionStore
    participant ProjectMemberStore

    User->>UI_Component: Interact with project members/settings
    UI_Component->>PermissionStore: getProjectRoleByWorkspaceSlugAndProjectId(workspaceSlug, projectId)
    PermissionStore-->>UI_Component: Returns user role
    UI_Component->>ProjectMemberStore: fetchProjectMembers(workspaceSlug, projectId)
    ProjectMemberStore-->>UI_Component: Returns member list with roles and original_role
    UI_Component->>ProjectMemberStore: updateMemberRole(workspaceSlug, projectId, userId, newRole)
    ProjectMemberStore-->>UI_Component: Updates member role, preserves original_role
    UI_Component-->>User: Renders updated member list and permissions
Loading

Suggested labels

🛠️refactor

Suggested reviewers

  • anmolsinghbhatia
  • sriramveeraghanta

Poem

A hop, a skip, a code refactor,
Roles and members now tracked with more exactor.
Translations bloom in every tongue,
Permissions checked, the right song sung.
Stores abstracted, logic neat,
This rabbit’s work is quite the feat!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@prateekshourya29 prateekshourya29 marked this pull request as draft May 20, 2025 12:27
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: 8

🔭 Outside diff range comments (3)
web/core/components/project/multi-select-modal.tsx (1)

87-87: 🛠️ Refactor suggestion

Translate the search placeholder
The placeholder text is still hardcoded ("Search for projects"). To complete the i18n coverage, wrap it in t() and add a corresponding key in your translations.

- placeholder="Search for projects"
+ placeholder={t("project_multi_select_modal.search_projects_placeholder")}

And in your locale JSON:

"project_multi_select_modal": {
  "search_projects_placeholder": "Search for projects"
}
web/core/components/project/settings/member-columns.tsx (1)

125-133: 🛠️ Refactor suggestion

checkCurrentOptionWorkspaceRole filters against workspace roles, not project roles

The helper again leverages the ROLE map and EUserPermissions.GUEST, which restricts the dropdown based on workspace membership, not project membership.
This may unintentionally hide valid project-specific roles (e.g., Viewer, Maintainer). Consider re-implementing with the project-role enum and label map.

web/core/store/member/base-project-member.store.ts (1)

108-113: ⚠️ Potential issue

toLowerCase can crash when display_name is undefined

projectMemberIds sorts by

(m) => this.memberRoot.memberMap?.[m.member]?.display_name.toLowerCase()

If the member exists in projectMemberMap but the corresponding memberMap entry has not been fetched yet, display_name is undefined, resulting in a runtime TypeError.

-(m) => this.memberRoot.memberMap?.[m.member]?.display_name.toLowerCase(),
+(m) => this.memberRoot.memberMap?.[m.member]?.display_name?.toLowerCase(),

The same safe-guard is already used in getProjectMemberIds; bringing the two in sync prevents hard-to-trace crashes.

🧹 Nitpick comments (7)
web/core/components/project/member-list-item.tsx (1)

85-85: Enhanced styling for table headers

Added the additional CSS class text-custom-text-400 font-medium to improve table header styling and consistency.

web/ce/store/user/permission.store.ts (1)

9-11: Remove unnecessary constructor

The constructor doesn't add any functionality beyond calling the parent constructor.

-  constructor(store: RootStore) {
-    super(store);
-  }
🧰 Tools
🪛 Biome (1.9.4)

[error] 9-11: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)

web/ce/store/member/project-member.store.ts (2)

13-15: Remove unnecessary constructor

The constructor doesn't add any functionality beyond calling the parent constructor.

-  constructor(_memberRoot: IMemberRootStore, rootStore: RootStore) {
-    super(_memberRoot, rootStore);
-  }
🧰 Tools
🪛 Biome (1.9.4)

[error] 13-15: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)


33-34: Simple pass-through method for role updates

The getProjectMemberRoleForUpdate method simply returns the role unchanged, which is fine if no transformations are needed. Consider adding a comment explaining why no transformation is needed here if that's the case.

web/core/components/project/project-settings-member-defaults.tsx (1)

131-131: Consider using translation keys for UI text

The component currently uses hardcoded English strings for titles and descriptions in the DefaultSettingItem components. Consider using translation keys from the i18n system to maintain consistency with the rest of the application.

-      <DefaultSettingItem title="Project Lead" description="Select the project lead for the project.">
+      <DefaultSettingItem title={t("project_settings.members.project_lead")} description={t("project_settings.members.project_lead_description")}>

And similarly for other hardcoded strings.

Also applies to: 152-152, 174-176

web/core/components/project/send-project-invitation-modal.tsx (2)

35-41: Avoid magic numbers – use the enum for default role instead of 5

5 is opaque and couples the component to the current numeric value of EUserPermissions.MEMBER (or whichever role index 5 represents). Relying on the literal makes future enum re-ordering risky and hurts readability.
Consider:

-      role: 5,
+      role: EUserPermissions.MEMBER,

and update the other occurrences (lines 123–124 & 132–133) similarly.


80-83: Redundant toString() calls

workspaceSlug and projectId are already typed as string; the extra .toString() is unnecessary and may hide unintended undefined/null propagation.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 2f4aa84 and 7919bcd.

📒 Files selected for processing (63)
  • packages/i18n/src/locales/cs/translations.json (1 hunks)
  • packages/i18n/src/locales/de/translations.json (2 hunks)
  • packages/i18n/src/locales/en/translations.json (1 hunks)
  • packages/i18n/src/locales/es/translations.json (1 hunks)
  • packages/i18n/src/locales/fr/translations.json (1 hunks)
  • packages/i18n/src/locales/id/translations.json (1 hunks)
  • packages/i18n/src/locales/it/translations.json (1 hunks)
  • packages/i18n/src/locales/ja/translations.json (1 hunks)
  • packages/i18n/src/locales/ko/translations.json (1 hunks)
  • packages/i18n/src/locales/pl/translations.json (1 hunks)
  • packages/i18n/src/locales/pt-BR/translations.json (1 hunks)
  • packages/i18n/src/locales/ro/translations.json (1 hunks)
  • packages/i18n/src/locales/ru/translations.json (1 hunks)
  • packages/i18n/src/locales/sk/translations.json (1 hunks)
  • packages/i18n/src/locales/tr-TR/translations.json (1 hunks)
  • packages/i18n/src/locales/ua/translations.json (1 hunks)
  • packages/i18n/src/locales/vi-VN/translations.json (1 hunks)
  • packages/i18n/src/locales/zh-CN/translations.json (1 hunks)
  • packages/i18n/src/locales/zh-TW/translations.json (1 hunks)
  • packages/types/src/project/projects.d.ts (2 hunks)
  • packages/types/src/workspace.d.ts (2 hunks)
  • packages/utils/src/index.ts (1 hunks)
  • packages/utils/src/permission.ts (1 hunks)
  • web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/members/page.tsx (2 hunks)
  • web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/sidebar.tsx (2 hunks)
  • web/app/[workspaceSlug]/(projects)/settings/(with-sidebar)/layout.tsx (2 hunks)
  • web/app/onboarding/page.tsx (0 hunks)
  • web/ce/components/projects/settings/useProjectColumns.tsx (2 hunks)
  • web/ce/components/projects/teamspaces/index.ts (1 hunks)
  • web/ce/components/projects/teamspaces/teamspace-list.tsx (1 hunks)
  • web/ce/constants/project/settings/tabs.ts (1 hunks)
  • web/ce/helpers/project-settings.ts (1 hunks)
  • web/ce/store/member/project-member.store.ts (1 hunks)
  • web/ce/store/user/permission.store.ts (1 hunks)
  • web/core/components/auth-screens/project/join-project.tsx (2 hunks)
  • web/core/components/inbox/content/root.tsx (2 hunks)
  • web/core/components/issues/issue-detail/issue-activity/root.tsx (1 hunks)
  • web/core/components/project/create/header.tsx (0 hunks)
  • web/core/components/project/create/project-create-buttons.tsx (1 hunks)
  • web/core/components/project/member-list-item.tsx (3 hunks)
  • web/core/components/project/member-list.tsx (4 hunks)
  • web/core/components/project/member-select.tsx (4 hunks)
  • web/core/components/project/multi-select-modal.tsx (2 hunks)
  • web/core/components/project/project-settings-member-defaults.tsx (5 hunks)
  • web/core/components/project/send-project-invitation-modal.tsx (3 hunks)
  • web/core/components/project/settings/member-columns.tsx (7 hunks)
  • web/core/components/ui/loader/settings/members.tsx (1 hunks)
  • web/core/components/workspace/settings/members-list.tsx (1 hunks)
  • web/core/hooks/store/user/user-permissions.ts (1 hunks)
  • web/core/layouts/auth-layout/project-wrapper.tsx (3 hunks)
  • web/core/lib/posthog-provider.tsx (1 hunks)
  • web/core/local-db/utils/query-sanitizer.ts.ts (1 hunks)
  • web/core/services/project/project-member.service.ts (4 hunks)
  • web/core/store/member/base-project-member.store.ts (10 hunks)
  • web/core/store/member/index.ts (2 hunks)
  • web/core/store/pages/project-page.store.ts (1 hunks)
  • web/core/store/pages/project-page.ts (1 hunks)
  • web/core/store/root.store.ts (2 hunks)
  • web/core/store/user/base-permissions.store.ts (5 hunks)
  • web/core/store/user/index.ts (3 hunks)
  • web/ee/helpers/project-settings.ts (1 hunks)
  • web/ee/store/member/project-member.store.ts (1 hunks)
  • web/ee/store/user/permission.store.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • web/core/components/project/create/header.tsx
  • web/app/onboarding/page.tsx
🧰 Additional context used
🧬 Code Graph Analysis (17)
web/core/components/project/create/project-create-buttons.tsx (1)
packages/i18n/src/store/index.ts (1)
  • t (233-254)
web/core/components/workspace/settings/members-list.tsx (1)
packages/i18n/src/store/index.ts (1)
  • t (233-254)
web/core/components/inbox/content/root.tsx (1)
web/core/hooks/store/user/user-permissions.ts (1)
  • useUserPermissions (7-12)
web/core/store/root.store.ts (2)
web/core/store/user/index.ts (1)
  • UserStore (57-304)
web/core/store/member/index.ts (1)
  • MemberRootStore (22-49)
web/core/layouts/auth-layout/project-wrapper.tsx (3)
web/core/hooks/store/user/user-permissions.ts (1)
  • useUserPermissions (7-12)
web/core/store/router.store.ts (2)
  • workspaceSlug (69-71)
  • projectId (85-87)
web/core/components/auth-screens/project/join-project.tsx (1)
  • JoinProject (18-68)
packages/types/src/workspace.d.ts (1)
packages/types/src/project/projects.d.ts (1)
  • TProjectMembership (85-97)
web/core/components/project/member-list-item.tsx (2)
web/core/store/member/base-project-member.store.ts (1)
  • IProjectMemberDetails (22-24)
web/ce/components/projects/settings/useProjectColumns.tsx (1)
  • useProjectColumns (19-83)
web/app/[workspaceSlug]/(projects)/settings/(with-sidebar)/layout.tsx (2)
web/core/store/router.store.ts (1)
  • workspaceSlug (69-71)
web/core/hooks/store/user/user-permissions.ts (1)
  • useUserPermissions (7-12)
web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/members/page.tsx (4)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
web/core/hooks/store/user/user-permissions.ts (1)
  • useUserPermissions (7-12)
web/ce/helpers/project-settings.ts (1)
  • getProjectSettingsPageLabelI18nKey (7-7)
web/ce/components/projects/teamspaces/teamspace-list.tsx (1)
  • ProjectTeamspaceList (6-6)
web/core/components/auth-screens/project/join-project.tsx (1)
web/core/hooks/store/user/user-permissions.ts (1)
  • useUserPermissions (7-12)
web/ce/store/user/permission.store.ts (2)
web/core/store/user/base-permissions.store.ts (1)
  • IBaseUserPermissionStore (28-54)
web/core/store/router.store.ts (2)
  • workspaceSlug (69-71)
  • projectId (85-87)
web/ce/store/member/project-member.store.ts (2)
web/core/store/member/base-project-member.store.ts (1)
  • IBaseProjectMemberStore (26-60)
web/core/store/member/index.ts (1)
  • IMemberRootStore (11-20)
packages/types/src/project/projects.d.ts (1)
packages/types/src/enums.ts (1)
  • TUserPermissions (7-7)
web/core/store/user/index.ts (1)
web/core/store/router.store.ts (1)
  • workspaceSlug (69-71)
web/core/components/project/settings/member-columns.tsx (7)
web/ce/components/projects/settings/useProjectColumns.tsx (1)
  • RowData (10-12)
packages/types/src/project/projects.d.ts (1)
  • TProjectMembership (85-97)
apiserver/plane/db/models/user.py (1)
  • avatar_url (124-132)
web/core/services/user.service.ts (1)
  • currentUser (48-55)
packages/ui/src/dropdowns/custom-menu.tsx (1)
  • CustomMenu (232-232)
web/core/hooks/store/user/user-permissions.ts (1)
  • useUserPermissions (7-12)
packages/constants/src/workspace.ts (1)
  • ROLE (145-149)
web/core/store/user/base-permissions.store.ts (4)
packages/types/src/workspace.d.ts (1)
  • IWorkspaceMemberMe (79-92)
packages/types/src/project/projects.d.ts (1)
  • TProjectMembership (85-97)
packages/types/src/users.d.ts (1)
  • IUserProjectsRole (166-168)
packages/constants/src/workspace.ts (1)
  • WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS_LINKS (297-303)
web/core/services/project/project-member.service.ts (2)
web/core/store/router.store.ts (2)
  • workspaceSlug (69-71)
  • projectId (85-87)
packages/types/src/project/projects.d.ts (1)
  • TProjectMembership (85-97)
🪛 Biome (1.9.4)
web/ce/store/user/permission.store.ts

[error] 9-11: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)

web/ce/store/member/project-member.store.ts

[error] 13-15: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)

web/core/store/user/base-permissions.store.ts

[error] 51-51: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

🔇 Additional comments (94)
packages/i18n/src/locales/fr/translations.json (1)

851-851: Added singular 'member' translation
The new "member": "Membre" entry in the common section correctly provides a singular form alongside the existing plural "members": "Membres". This aligns with updates across other locales and preserves valid JSON structure.

packages/i18n/src/locales/tr-TR/translations.json (1)

853-854: Added singular translation key for 'member'
The new "member": "Üye" entry in the "common" section correctly provides the singular form alongside the existing plural "members". This change aligns with the updates in other locales.

packages/i18n/src/locales/cs/translations.json (1)

850-851: Added singular translation key for 'member'
The new "member": "Člen" entry in the "common" section correctly provides the singular form alongside the existing plural "members". This change aligns with the updates in other locales.

packages/i18n/src/locales/de/translations.json (1)

850-850: Add singular "member" translation
The new "member": "Mitglied" entry aligns with the PR’s introduction of the singular translation key and matches updates in other locales.

packages/i18n/src/locales/ro/translations.json (1)

501-501: Add ICU pluralization for “member”.
The new entry

"member": "{count, plural, one{# membru} other{# membri}}"

correctly defines both singular and plural forms in Romanian. JSON syntax remains valid, and the placement at the root level follows the existing pattern for dynamic count-based translations.

packages/i18n/src/locales/zh-TW/translations.json (1)

852-852: Add singular “member” translation for Traditional Chinese.
The static key

"member": "成員"

introduces the singular form alongside the existing "members" entry. The JSON is well-formed with no trailing comma issues.

packages/i18n/src/locales/pl/translations.json (1)

852-852: Add singular form for "member"
This new key "member": "Członek" properly complements the existing "members" translation, ensuring the UI can handle both singular and plural forms.

packages/i18n/src/locales/es/translations.json (1)

853-853: Validate addition of singular “member” key
The new "member": "Miembro" entry in the common group correctly introduces the singular form alongside "members", matching the pattern in other locales.

packages/i18n/src/locales/it/translations.json (1)

847-853: Approve translation addition
The singular key "member": "Membro" is correctly inserted immediately before "members" and follows the same indentation and comma conventions as surrounding entries.

Please verify that the new "member" key is added to your i18n type definitions (e.g., the generated TS translation keys) so that consumers can reference it without type errors.

packages/i18n/src/locales/sk/translations.json (1)

852-852: Add singular member translation in Slovak.

The new key "member": "Člen" correctly provides the singular form alongside the existing "members" entry. Syntax and placement are consistent with other locale files.

packages/i18n/src/locales/ru/translations.json (1)

852-852: Add singular member translation in Russian.

The new key "member": "Участник" correctly provides the singular form alongside the existing "members" entry. JSON structure and positioning are correct.

packages/utils/src/permission.ts (1)

1-13: Well-structured utility function for role comparison.

This utility function getHighestRole is cleanly implemented with proper typing using generics to maintain the specific role type. The JSDoc documentation clearly explains the purpose and parameters. This function will provide consistent role comparison across the codebase.

The implementation is sound, using reduce() to find the maximum value in the roles array, which is efficient and readable.

packages/i18n/src/locales/zh-CN/translations.json (1)

851-851: Good addition of singular form translation key.

Adding the singular form "member" alongside the existing plural "members" improves translation consistency and allows for more precise UI text references. This matches the pattern seen in other parts of the translations file where both singular and plural forms are provided.

web/core/components/project/create/project-create-buttons.tsx (1)

28-28: Improved translation key namespace usage.

Changing the translation key from a likely top-level "cancel" to "common.cancel" improves organization of translation keys and maintains consistency with other UI components. This change aligns with the broader internationalization improvements in the codebase.

web/core/hooks/store/user/user-permissions.ts (1)

4-5: Updated import path for permission store.

This change updates the import path for IUserPermissionStore to use the new location in the "plane-web" directory. The refactoring aligns with the PR objectives of improving the permission layer structure. This change maintains the existing interface functionality while pointing to the refactored implementation.

packages/i18n/src/locales/ko/translations.json (1)

851-851: Add singular “member” key alongside plural “members”
Introduces the singular translation for “member” to match the existing plural key. This aligns with the PR’s goal of supporting both singular and plural forms across all locales.

packages/i18n/src/locales/ja/translations.json (1)

851-851: Add singular “member” key alongside plural “members”
Provides the Japanese singular form “メンバー” to complement the existing plural “メンバー,” ensuring consistent i18n support for member terminology.

packages/utils/src/index.ts (1)

18-18: Re-export new permission utilities
Including export * from "./permission"; exposes the getHighestRole and other permission helpers centrally, supporting the refactored permission layer.

web/ee/helpers/project-settings.ts (1)

1-1: Proxy CE helper for EE layer
Re-exporting ce/helpers/project-settings here maintains consistency with other EE modules that alias CE helpers, enabling enterprise builds to import the shared utility without path changes.

web/core/components/workspace/settings/members-list.tsx (1)

69-71: Improve JSX readability for the Collapsible title
Splitting the <h4> into multiple lines makes the JSX more maintainable without altering behavior.

web/ce/components/projects/teamspaces/index.ts (1)

1-1: Re-export of Teamspace List Component Looks Good
The index file cleanly re-exports everything from ./teamspace-list, making the ProjectTeamspaceList component available via this directory.

packages/i18n/src/locales/pt-BR/translations.json (1)

851-854:

Details

❓ Verification inconclusive

Ensure Translation Key Consistency Across Locales
You’ve correctly added the singular "member": "Membro" key alongside "members". Please verify that the same key has been added to all other locale files’ common sections to maintain parity.

Run this script from the repo root to catch any missing entries:


🏁 Script executed:

#!/bin/bash
# Check for missing "member" key in all locale JSON files
missing=$(rg -L '"member":' packages/i18n/src/locales/*/translations.json)
if [ -n "$missing" ]; then
  echo "Missing 'member' key in these locale files:"
  echo "$missing"
  exit 1
else
  echo "All locale files contain the 'member' key"
fi

Length of output: 19928


Ensure Translation Key Consistency Across Locales
The rg -L invocation is returning every file (it’s printing matches, not missing entries), so it won’t reliably surface any locales missing "member". Please manually confirm that each packages/i18n/src/locales/*/translations.json file includes the "member" key in its common section, or run this corrected script:

#!/usr/bin/env bash
# Report any locale missing the "member" key
for file in packages/i18n/src/locales/*/translations.json; do
  if ! grep -q '"member":' "$file"; then
    echo "Missing 'member' in locale: $(basename "$(dirname "$file")")"
  fi
done

If any locales are flagged above, add "member": "<translation>" alongside "members" under their common section to maintain parity across all languages.

web/core/components/project/multi-select-modal.tsx (2)

169-169: Approved: Button labels are now localized
Using t("cancel") for the Cancel button aligns with our i18n practices and ensures it will render correctly in all locales.


179-179: Approved: Submit button label uses translation keys
Toggling between t("confirm") and t("confirming") based on isSubmitting is a clear, consistent approach to localizing the confirm action.

packages/i18n/src/locales/vi-VN/translations.json (1)

851-851: Added singular translation key
The insertion of "member": "Thành viên" alongside the existing "members" key in the common section correctly provides a singular form. The Vietnamese term is identical for both singular and plural contexts, which is appropriate here.

packages/i18n/src/locales/ua/translations.json (1)

852-852: Singular translation key added correctly
The new "member": "Учасник" entry under the "common" section aligns with other locales and provides the singular form.

web/ee/store/member/project-member.store.ts (1)

1-1: Proxy module correctly re-exports CE store
This EE-specific file cleanly forwards all exports from the CE implementation to maintain consistency without duplication.

web/ee/store/user/permission.store.ts (1)

1-1: EE permission store proxy is consistent
This file correctly re-exports all members from the CE permission store, following the established pattern.

packages/i18n/src/locales/id/translations.json (1)

850-850: Added singular translation for "member"

The addition of the singular form "member" complements the existing plural form "members", both translated to "Anggota" in Indonesian. This addition ensures consistent internationalization support across the application.

web/core/store/pages/project-page.ts (1)

76-79: Updated to use new permission method

This change replaces direct access to project permissions with the new getProjectRoleByWorkspaceSlugAndProjectId method, aligning with the permission layer refactoring described in the PR objectives.

web/ce/constants/project/settings/tabs.ts (1)

19-19: Updated i18n label key to use common namespace

The i18n label for the members tab now uses the "common.members" path, aligning with the standardized approach for accessing member-related translations from the common namespace where both singular and plural forms are defined.

web/core/store/root.store.ts (3)

74-74: Updated type casting for UserStore instantiation

The code now correctly casts this to RootStore when instantiating UserStore, which expects a RootStore parameter, maintaining proper type relationships between stores.


78-78: Updated type casting for MemberRootStore instantiation

Similar to the UserStore change, this appropriately casts this to RootStore when instantiating MemberRootStore, which expects a RootStore parameter, maintaining type consistency.


109-109: Applied same type casting in resetOnSignOut method

The same type casting improvements were consistently applied in the resetOnSignOut method, ensuring proper typing when reinstantiating stores during user sign-out.

Also applies to: 112-112

web/core/local-db/utils/query-sanitizer.ts.ts (1)

15-15: Correctly refactored to use the new permission method

The change from direct property access to the getProjectRoleByWorkspaceSlugAndProjectId method aligns with the permission layer refactoring. This approach provides better encapsulation of permission logic and more consistent access patterns.

web/core/components/inbox/content/root.tsx (2)

41-41: Properly destructured the new permission method

The destructuring now includes getProjectRoleByWorkspaceSlugAndProjectId from the user permissions hook, correctly implementing the new permission access pattern.


70-70: Correctly implemented role-based permission check

The isGuest check now uses the new method to retrieve the project role, maintaining the same behavior while following the new permission access pattern.

packages/types/src/workspace.d.ts (2)

1-1: Updated import to use the new membership type

The import statement correctly uses TProjectMembership instead of the previous membership interface, aligning with the broader type system refactoring.


96-96: Updated to use the new membership type

The project_details property has been correctly typed to use TProjectMembership[] instead of the previous interface type. This change provides better type safety with the conditional properties in the new type.

web/core/components/project/member-select.tsx (4)

8-8: Updated to use the more specific project roles enum

Correctly replaced EUserPermissions with EUserProjectRoles which is more semantically appropriate for project member roles.


35-35: Updated role check to use project-specific enum

Properly changed the guest role check to use EUserProjectRoles.GUEST instead of EUserPermissions.GUEST, maintaining consistent behavior while using the more appropriate enum.


62-62: UI height adjustment for avatar container

Reduced the height from h-5 to h-3.5 for better visual alignment of the avatar and name in the selection component.


76-76: Enhanced button styling with background color

Added bg-custom-background-100 class to provide consistent background styling for the selection button.

web/core/lib/posthog-provider.tsx (1)

28-34: Well-structured permission access refactoring

The changes to retrieve workspace and project roles through dedicated methods (getWorkspaceRoleByWorkspaceSlug and getProjectRoleByWorkspaceSlugAndProjectId) from useUserPermissions hook is a good approach. This centralizes permission logic and improves encapsulation compared to directly accessing permission objects.

web/core/components/issues/issue-detail/issue-activity/root.tsx (1)

52-59: Clean permission handling refactoring

The change from direct permission object access to using the getProjectRoleByWorkspaceSlugAndProjectId method improves code maintainability. The role comparison is now more straightforward by directly comparing with enum values rather than complex object property access.

web/ce/components/projects/teamspaces/teamspace-list.tsx (1)

1-6: Placeholder component needs implementation

The component defines proper TypeScript types for props but currently only returns null. This appears to be a placeholder for future implementation.

Is this component intentionally returning null in the community edition, with actual implementation expected in enterprise edition? If not, it should be properly implemented or marked with a TODO comment explaining the future implementation plan.

web/core/store/pages/project-page.store.ts (1)

116-123: Consistent permission access pattern applied

The changes in the canCurrentUserCreatePage getter properly implement the new permission access pattern by using the getProjectRoleByWorkspaceSlugAndProjectId method. This maintains the same functionality while improving code consistency and maintainability.

web/ce/helpers/project-settings.ts (1)

1-7: Clean implementation of the i18n helper function

This new helper function follows good practices with comprehensive JSDoc comments. The function currently acts as a pass-through for the default label key, which seems intentional based on the underscore prefix for the unused parameter.

web/core/layouts/auth-layout/project-wrapper.tsx (3)

49-49: Implementation aligns with permission layer refactoring

The addition of getProjectRoleByWorkspaceSlugAndProjectId to the destructured import is consistent with the PR's objective to introduce computed methods for permission handling.


67-67: Good replacement of direct data access with computed method

Replacing direct access to projectUserInfo with the new getter method getProjectRoleByWorkspaceSlugAndProjectId improves encapsulation and maintainability, aligning with the permission layer refactoring.


182-182: Proper prop passing to JoinProject component

Updated to explicitly pass projectId as a prop to the JoinProject component, which makes the dependency clearer and aligns with the refactoring approach.

web/core/components/project/member-list-item.tsx (3)

13-15: Updated import organization and path

The import reorganization and updated path for IProjectMemberDetails reflects the store restructuring part of the permission layer refactoring.


19-20: Explicit props addition improves component contract

Adding explicit projectId and workspaceSlug props improves the component's contract, making dependencies clear and supporting the permission layer refactoring.


35-38: Proper prop passing to useProjectColumns hook

The hook now receives explicit projectId and workspaceSlug parameters, which is consistent with the refactoring approach to make data flow more explicit and dependencies clearer.

web/app/[workspaceSlug]/(projects)/settings/(with-sidebar)/layout.tsx (2)

28-28: Implementation aligns with permission layer refactoring

The addition of getWorkspaceRoleByWorkspaceSlug to the destructured imports from useUserPermissions is consistent with the PR's objective to introduce computed methods for permission handling.


30-30: Good replacement of direct data access with computed method

Replacing direct access to workspaceUserInfo[workspaceSlug]?.role with the new getter method getWorkspaceRoleByWorkspaceSlug improves encapsulation and maintainability, aligning with the permission layer refactoring.

web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/members/page.tsx (4)

4-7: Well-organized imports with clear separation of concerns

Good organization of imports with clear separation between Next.js, Plane imports, components, hooks, and plane-web imports. The addition of internationalization support is a nice improvement.


20-29: Clean parameter extraction and proper typing

Good practice to extract router parameters at the top of the component and convert them to strings. This ensures type safety when passing these values to child components and makes the data flow more explicit.


45-49: Well-structured header with i18n support

Good addition of a styled header with proper internationalization. Using the helper function getProjectSettingsPageLabelI18nKey enhances maintainability and consistency across the project.


50-52: Improved component props pattern

Excellent refactoring to explicitly pass projectId and workspaceSlug as props to child components rather than having them extract this information internally. This makes the component relationships clearer and improves reusability.

web/core/store/member/index.ts (2)

3-8: Well-organized imports with clear separation

Good organization of imports with clear separation between external libraries, Plane imports, Plane web imports, and local imports. This improves code readability and maintains consistent project structure.


29-29: Updated constructor parameter type

Good update to the constructor parameter type from CoreRootStore to RootStore. This change aligns with the broader store architecture refactoring and supports the new permission methods mentioned in the PR objectives.

web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/sidebar.tsx (3)

27-27: Using the new permission access method

Excellent adoption of the new getProjectRoleByWorkspaceSlugAndProjectId method from the permission refactoring. This is a key part of the permission layer improvements mentioned in the PR objectives.


29-32: Improved role retrieval with explicit parameters

Good implementation of the new permission access method with explicit parameters. This approach is more maintainable than direct access to projectUserInfo and aligns with the permission layer refactoring goals.


68-68: Consistent i18n implementation

Good use of the helper function getProjectSettingsPageLabelI18nKey for internationalization. This ensures consistent label handling across the project settings pages.

web/core/components/auth-screens/project/join-project.tsx (4)

13-16: Explicit props interface improves component reusability

Good addition of explicit props for projectId and isPrivateProject. This makes the component more reusable and follows the pattern of explicit parameter passing established in the permission layer refactoring.


18-19: Clean component signature with props destructuring

Good update to the component signature to accept and properly destructure the props. This makes the component's dependencies clearer and improves maintainability.


43-52: Improved user experience with conditional messaging

Good enhancement to provide different messages based on whether the project is private. This improves the user experience by providing relevant information in each context.


54-65: Conditional UI rendering based on project privacy

Excellent implementation of conditional rendering for the join button based on the project's privacy status. This provides appropriate user controls and messaging depending on the context.

web/ce/components/projects/settings/useProjectColumns.tsx (5)

10-11: Good update to the RowData interface.

The interface now correctly extends Pick<TProjectMembership, "original_role">, which aligns with the broader refactoring of project membership types. This change improves type safety by ensuring the component works with the new permission layer structure.


14-18: Proper props typing implementation.

Defining an explicit props interface for the hook is a good practice. This makes the hook's contract clearer and more maintainable.


19-20: Good refactoring to accept explicit parameters.

This change from using useParams() to accepting explicit parameters improves reusability and testability of the hook.


25-34: Correctly implementing the new permission layer methods.

The hook now properly uses the new permission methods allowPermissions and getProjectRoleByWorkspaceSlugAndProjectId which aligns with the permission layer refactoring goals. This ensures consistent permission handling across the system.


82-82: Clean return value.

The return object is now more focused, only including what's necessary. This is a good cleanup that follows the principle of minimizing exposed API surface.

web/core/store/user/index.ts (2)

72-72: Type update for constructor parameter.

Changing from CoreRootStore to RootStore aligns with the updated store typings used across the project.


269-269: Good implementation of the permission abstraction.

This is a key improvement that replaces direct property access with the new encapsulated method getProjectRolesByWorkspaceSlug. This change enhances maintainability by centralizing permission logic.

web/core/components/ui/loader/settings/members.tsx (1)

4-14: UI improvement for members settings loader.

The switch from flexbox to CSS grid with 5 columns creates a more consistent layout that better matches the actual data display. Reducing the number of placeholders from 4 to 3 and simplifying the layout improves the loading state appearance.

web/core/components/project/member-list.tsx (5)

16-20: Good props typing implementation.

Creating an explicit props interface improves type safety and code readability.


21-22: Improved component parameters.

Accepting explicit projectId and workspaceSlug props instead of extracting them from router parameters improves component reusability and testability.


35-38: Enhanced filtering logic.

The update to exclude members lacking an original_role in addition to missing member data reflects the improved type structure and prevents potential errors.


53-58: Consistent prop passing pattern.

Passing projectId and workspaceSlug as explicit props to child components maintains consistency throughout the component hierarchy.


89-94: Consistent prop passing to list items.

Passing projectId and workspaceSlug as explicit props to ProjectMemberListItem completes the consistent parameter passing pattern throughout the component tree.

web/ce/store/user/permission.store.ts (2)

8-22: Good implementation of the UserPermissionStore class

The implementation correctly extends BaseUserPermissionStore and adds the computed method getProjectRoleByWorkspaceSlugAndProjectId as mentioned in the PR objectives. This method serves as an access point to retrieve project role permissions by workspace slug and project ID.

🧰 Tools
🪛 Biome (1.9.4)

[error] 9-11: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)


19-22: Well-documented computed method for permission retrieval

The getProjectRoleByWorkspaceSlugAndProjectId method is properly implemented using computedFn for memoization and has clear JSDoc comments. This aligns with the PR objective of introducing computed methods for workspace and project access checks.

packages/types/src/project/projects.d.ts (1)

85-97: Good type definition for project membership

The new TProjectMembership discriminated union type improves type safety by clearly defining the structure of project membership data with mandatory fields and conditional type variations.

This type definition aligns with the PR's goal of refactoring the permission layer for better type safety and consistency.

web/ce/store/member/project-member.store.ts (3)

12-43: Well-structured implementation of ProjectMemberStore

The class properly extends BaseProjectMemberStore and implements all required methods with clear documentation and appropriate delegation to base class methods.

🧰 Tools
🪛 Biome (1.9.4)

[error] 13-15: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)


23-25: Well-implemented computed method for role retrieval

The getUserProjectRole method is properly implemented using computedFn for memoization and delegates to the base class method for retrieving the role from project membership.


42-42: Concise implementation of member removal

The processMemberRemoval method elegantly delegates to the base class method for member removal, maintaining clean separation of concerns.

web/core/components/project/project-settings-member-defaults.tsx (5)

24-38: Great component extraction for reusable UI pattern

The new DefaultSettingItem component nicely encapsulates the repeated UI pattern for settings, improving code reusability and consistency.


40-46: Good prop interface design with explicit parameters

The component now accepts explicit workspaceSlug and projectId props rather than extracting them via hooks, which aligns with the PR's objectives of refactoring permission access patterns.


54-59: Improved permission checking with explicit parameters

The allowPermissions call now uses the explicit props for workspace and project identification, aligning with the permission layer refactoring.


63-66: Updated data fetching with explicit parameters

The useSWR hook now correctly uses the passed props for the key and fetcher function, maintaining consistency with the rest of the refactoring.


130-187: Improved UI structure with consistent components

The UI structure now uses the DefaultSettingItem component consistently for all settings, resulting in cleaner and more maintainable code.

web/core/services/project/project-member.service.ts (1)

12-18: Type refactor looks good

Switching to TProjectMembership aligns this service with the new discriminated-union model – no issues spotted in this segment.

@prateekshourya29 prateekshourya29 marked this pull request as ready for review May 20, 2025 14:50
@prateekshourya29 prateekshourya29 marked this pull request as draft May 22, 2025 13:01
@prateekshourya29 prateekshourya29 marked this pull request as ready for review May 22, 2025 22:38
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: 4

♻️ Duplicate comments (1)
web/core/store/member/base-project-member.store.ts (1)

301-308: Rollback still writes original_role into the permission map

This is the same scalar-vs-object issue previously flagged – the rollback should
restore the current role, not original_role, to
workspaceProjectsPermissions.

-            membershipBeforeUpdate?.original_role
+            membershipBeforeUpdate?.role
🧹 Nitpick comments (1)
web/core/store/user/base-permissions.store.ts (1)

254-258: Docstring return type is outdated

The JSDoc still advertises Promise<void | undefined> while the
implementation (and interface) now correctly returns Promise<void>.
Update the comment for consistency.

-   * @returns { Promise<void | undefined> }
+   * @returns { Promise<void> }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 28a7bcb and a048da4.

📒 Files selected for processing (3)
  • web/core/components/project/settings/member-columns.tsx (7 hunks)
  • web/core/store/member/base-project-member.store.ts (10 hunks)
  • web/core/store/user/base-permissions.store.ts (8 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/core/components/project/settings/member-columns.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
web/core/store/user/base-permissions.store.ts (4)
packages/types/src/workspace.d.ts (1)
  • IWorkspaceMemberMe (79-92)
packages/types/src/project/projects.d.ts (1)
  • TProjectMembership (85-97)
packages/types/src/users.d.ts (1)
  • IUserProjectsRole (166-168)
packages/constants/src/workspace.ts (1)
  • WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS_LINKS (297-303)

@pushya22 pushya22 changed the title refactor: permission layer [WEB-3964] refactor: permission layer May 28, 2025
@makeplane makeplane deleted a comment from makeplane bot May 28, 2025
@makeplane
Copy link

makeplane bot commented May 28, 2025

Pull Request Linked with Plane Work Items

Comment Automatically Generated by Plane

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: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a048da4 and c3e3b01.

📒 Files selected for processing (21)
  • packages/i18n/src/locales/cs/translations.json (1 hunks)
  • packages/i18n/src/locales/de/translations.json (2 hunks)
  • packages/i18n/src/locales/en/translations.json (1 hunks)
  • packages/i18n/src/locales/es/translations.json (1 hunks)
  • packages/i18n/src/locales/fr/translations.json (1 hunks)
  • packages/i18n/src/locales/id/translations.json (1 hunks)
  • packages/i18n/src/locales/it/translations.json (1 hunks)
  • packages/i18n/src/locales/ja/translations.json (1 hunks)
  • packages/i18n/src/locales/ko/translations.json (1 hunks)
  • packages/i18n/src/locales/pl/translations.json (1 hunks)
  • packages/i18n/src/locales/pt-BR/translations.json (1 hunks)
  • packages/i18n/src/locales/ro/translations.json (1 hunks)
  • packages/i18n/src/locales/ru/translations.json (1 hunks)
  • packages/i18n/src/locales/sk/translations.json (1 hunks)
  • packages/i18n/src/locales/tr-TR/translations.json (1 hunks)
  • packages/i18n/src/locales/ua/translations.json (1 hunks)
  • packages/i18n/src/locales/vi-VN/translations.json (1 hunks)
  • packages/i18n/src/locales/zh-CN/translations.json (1 hunks)
  • packages/i18n/src/locales/zh-TW/translations.json (1 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/members/page.tsx (2 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/sidebar.tsx (2 hunks)
✅ Files skipped from review due to trivial changes (5)
  • packages/i18n/src/locales/zh-CN/translations.json
  • packages/i18n/src/locales/zh-TW/translations.json
  • packages/i18n/src/locales/ja/translations.json
  • packages/i18n/src/locales/ua/translations.json
  • packages/i18n/src/locales/pt-BR/translations.json
🚧 Files skipped from review as they are similar to previous changes (14)
  • packages/i18n/src/locales/en/translations.json
  • packages/i18n/src/locales/pl/translations.json
  • packages/i18n/src/locales/fr/translations.json
  • packages/i18n/src/locales/cs/translations.json
  • packages/i18n/src/locales/ro/translations.json
  • packages/i18n/src/locales/sk/translations.json
  • packages/i18n/src/locales/vi-VN/translations.json
  • packages/i18n/src/locales/ko/translations.json
  • packages/i18n/src/locales/ru/translations.json
  • packages/i18n/src/locales/tr-TR/translations.json
  • packages/i18n/src/locales/it/translations.json
  • packages/i18n/src/locales/es/translations.json
  • packages/i18n/src/locales/id/translations.json
  • packages/i18n/src/locales/de/translations.json
🧰 Additional context used
🧬 Code Graph Analysis (1)
web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/members/page.tsx (6)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
web/core/hooks/store/user/user-permissions.ts (1)
  • useUserPermissions (7-12)
web/ce/helpers/project-settings.ts (1)
  • getProjectSettingsPageLabelI18nKey (7-7)
web/core/components/project/project-settings-member-defaults.tsx (1)
  • ProjectSettingsMemberDefaults (45-190)
web/ce/components/projects/teamspaces/teamspace-list.tsx (1)
  • ProjectTeamspaceList (6-6)
web/core/components/project/member-list.tsx (1)
  • ProjectMemberList (21-102)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/sidebar.tsx (3)

27-27: LGTM: Proper destructuring of the new permission method.

Good addition of the getProjectRoleByWorkspaceSlugAndProjectId method from the permissions hook, aligning with the broader permission layer refactor.


29-32: LGTM: Correctly implemented role retrieval refactor.

The replacement of direct projectUserInfo access with the encapsulated getProjectRoleByWorkspaceSlugAndProjectId method improves type safety and follows the standardized permission handling pattern across the codebase.


68-68: LGTM: Standardized translation key generation.

The use of getProjectSettingsPageLabelI18nKey helper function centralizes label key generation and improves consistency across the project settings UI.

web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/members/page.tsx (4)

20-20: LGTM: Proper extraction of route parameters.

Good use of Next.js useParams hook with descriptive variable names to clearly indicate the source of the parameters.


27-28: LGTM: Safe parameter conversion to strings.

Proper use of optional chaining with toString() to safely convert route parameters to strings while handling potential undefined values.


45-49: LGTM: Enhanced header with internationalization.

The addition of a styled header with the translated label improves the UI consistency and supports the internationalization improvements.


50-52:

Details

✅ Verification successful

Verify that all components properly handle the new prop structure.

The explicit passing of projectId and workspaceSlug as props follows the standardized pattern. However, ensure that all these components have been updated to accept these props correctly.


🏁 Script executed:

#!/bin/bash
# Description: Verify that the components accept projectId and workspaceSlug props
# Expected: All components should have proper TypeScript interfaces defining these props

echo "Checking ProjectSettingsMemberDefaults props interface..."
ast-grep --pattern 'interface $_ {
  $$$
  projectId: $_
  $$$
  workspaceSlug: $_
  $$$
}'

echo "Checking ProjectTeamspaceList props interface..."
ast-grep --pattern 'interface $_ {
  $$$
  projectId: $_
  $$$
  workspaceSlug: $_
  $$$
}'

echo "Checking ProjectMemberList props interface..."
ast-grep --pattern 'interface $_ {
  $$$
  projectId: $_
  $$$
  workspaceSlug: $_
  $$$
}'

Length of output: 8690


🏁 Script executed:

#!/bin/bash
# Locate component definitions and inspect their props in the relevant files

echo "=== ProjectSettingsMemberDefaults ==="
files=$(rg -l "ProjectSettingsMemberDefaults" --glob "*.tsx")
echo "$files"
for f in $files; do
  echo "----- $f (first 50 lines) -----"
  head -n 50 "$f"
done

echo "=== ProjectTeamspaceList ==="
files=$(rg -l "ProjectTeamspaceList" --glob "*.tsx")
echo "$files"
for f in $files; do
  echo "----- $f (first 50 lines) -----"
  head -n 50 "$f"
done

echo "=== ProjectMemberList ==="
files=$(rg -l "ProjectMemberList" --glob "*.tsx")
echo "$files"
for f in $files; do
  echo "----- $f (first 50 lines) -----"
  head -n 50 "$f"
done

Length of output: 16548


All components correctly accept projectId and workspaceSlug props

Verified that each component defines the matching props interface:

  • web/core/components/project/project-settings-member-defaults.tsx
    ­­– TProjectSettingsMemberDefaultsProps includes projectId: string and workspaceSlug: string.
  • web/ce/components/projects/teamspaces/teamspace-list.tsx
    ­­– TProjectTeamspaceList includes projectId: string and workspaceSlug: string.
  • web/core/components/project/member-list.tsx
    ­­– TProjectMemberListProps includes projectId: string and workspaceSlug: string.

No further changes needed.

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: 1

♻️ Duplicate comments (3)
web/core/store/member/base-project-member.store.ts (3)

190-195: Use project-specific enum when filtering guest users.

The code uses EUserPermissions.GUEST (workspace-level) but should use EUserProjectRoles.GUEST for project context filtering.

-      members = members.filter((m) => m.role !== EUserPermissions.GUEST);
+      members = members.filter((m) => m.role !== EUserProjectRoles.GUEST);

282-291: Critical: Corrupting original_role destroys audit history.

Setting original_role to the new role parameter (line 282) overwrites the immutable backend value needed for audit trails and rollbacks. This breaks the audit history mechanism.

-        set(this.projectMemberMap, [projectId, userId, "original_role"], role);
-        set(this.projectMemberMap, [projectId, userId, "role"], updatedProjectRole);
+        // Preserve immutable original_role – only mutate the live `role`
+        set(this.projectMemberMap, [projectId, userId, "role"], updatedProjectRole);

Additionally, the permission update logic may have the scalar-object corruption issue mentioned in past reviews. The workspaceProjectsPermissions[workspaceSlug][projectId] should be a scalar (TUserPermissions) but the code structure suggests it might be treated as an object.

#!/bin/bash
# Verify the type definition of workspaceProjectsPermissions to understand the data structure
ast-grep --pattern 'workspaceProjectsPermissions: $_'

305-318: Critical: Rollback logic has the same audit history corruption.

The rollback sets original_role back to membershipBeforeUpdate?.original_role, but this only works if the original audit trail wasn't corrupted by the initial update. Since line 282 overwrites original_role, the rollback may not restore the true original value.

The same scalar-object corruption concern from the update logic applies here in the error handling path.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3e3b01 and d9e3a10.

📒 Files selected for processing (12)
  • apiserver/plane/app/serializers/project.py (1 hunks)
  • packages/i18n/src/locales/en/translations.json (1 hunks)
  • packages/types/src/project/projects.d.ts (2 hunks)
  • packages/utils/src/index.ts (1 hunks)
  • web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/layout.tsx (1 hunks)
  • web/app/(all)/[workspaceSlug]/(settings)/settings/projects/[projectId]/members/page.tsx (2 hunks)
  • web/ce/constants/project/settings/tabs.ts (1 hunks)
  • web/core/components/project/member-list-item.tsx (2 hunks)
  • web/core/components/project/member-list.tsx (3 hunks)
  • web/core/components/project/settings/member-columns.tsx (7 hunks)
  • web/core/components/settings/project/sidebar/nav-item-children.tsx (2 hunks)
  • web/core/store/member/base-project-member.store.ts (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • packages/utils/src/index.ts
  • web/ce/constants/project/settings/tabs.ts
  • packages/i18n/src/locales/en/translations.json
  • web/core/components/project/member-list-item.tsx
  • apiserver/plane/app/serializers/project.py
  • web/core/components/project/member-list.tsx
  • packages/types/src/project/projects.d.ts
  • web/core/components/project/settings/member-columns.tsx
🧰 Additional context used
🧬 Code Graph Analysis (2)
web/core/components/settings/project/sidebar/nav-item-children.tsx (2)
packages/i18n/src/store/index.ts (1)
  • t (211-232)
web/ce/helpers/project-settings.ts (1)
  • getProjectSettingsPageLabelI18nKey (7-7)
web/app/(all)/[workspaceSlug]/(settings)/settings/projects/[projectId]/members/page.tsx (6)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
web/core/hooks/store/user/user-permissions.ts (1)
  • useUserPermissions (7-12)
web/ce/helpers/project-settings.ts (1)
  • getProjectSettingsPageLabelI18nKey (7-7)
web/core/components/project/project-settings-member-defaults.tsx (1)
  • ProjectSettingsMemberDefaults (45-190)
web/ce/components/projects/teamspaces/teamspace-list.tsx (1)
  • ProjectTeamspaceList (6-6)
web/core/components/project/member-list.tsx (1)
  • ProjectMemberList (23-108)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (14)
web/core/components/settings/project/sidebar/nav-item-children.tsx (2)

11-11: LGTM: Clean import addition for i18n helper.

The import of getProjectSettingsPageLabelI18nKey helper function is correctly structured and follows the established import pattern.


69-69: LGTM: Excellent abstraction for i18n key management.

The refactoring to use getProjectSettingsPageLabelI18nKey(link.key, link.i18n_label) instead of direct link.i18n_label usage is well-executed. This change:

  • Maintains functional equivalence (the helper currently returns defaultLabelKey unchanged)
  • Provides a clean abstraction layer for future customization
  • Aligns with the broader i18n standardization effort mentioned in the PR objectives
  • Enables potential EE-specific or conditional key resolution logic

The implementation correctly passes both the settings key and default label, setting up for extensible i18n key resolution.

web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/layout.tsx (3)

24-24: LGTM! Good refactoring to use centralized permission methods.

The addition of getWorkspaceRoleByWorkspaceSlug aligns well with the PR objective of refactoring the permission layer to use computed methods instead of direct object access.


29-29: Improved encapsulation with the new getter method.

Using getWorkspaceRoleByWorkspaceSlug(workspaceSlug.toString()) instead of direct property access provides better abstraction and consistency with the refactored permission layer.


31-34: Enhanced defensive programming with explicit authorization checks.

The updated authorization logic is more robust:

  • Explicit initialization of isAuthorized to false
  • Conditional checks ensuring all required values are truthy before proceeding
  • Cleaner separation of concerns
web/core/store/member/base-project-member.store.ts (5)

4-4: LGTM! Good addition of unset utility.

Adding unset from lodash is appropriate for the member removal functionality implemented in this refactor.


9-20: Excellent architectural refactoring with abstract base class.

The introduction of BaseProjectMemberStore as an abstract class with defined interfaces provides better extensibility and separation of concerns. The updated imports and type definitions align well with the broader permission layer refactoring.


128-153: Well-designed computed functions for member access.

The new protected computed functions (getProjectMemberships, getProjectMembershipByUserId, getRoleFromProjectMembership) provide good encapsulation and reusability. The role precedence logic (original_role ?? role) is appropriate.


234-239: Preserve original roles when adding members.

Good implementation that maintains the original_role as the backend value while allowing the current role to be updated based on computed project role logic.


329-344: Well-abstracted member removal with clear separation of concerns.

The handleMemberRemoval and abstract processMemberRemoval methods provide good separation between common removal logic and implementation-specific cleanup. This pattern supports the extensible architecture introduced by the abstract base class.

web/app/(all)/[workspaceSlug]/(settings)/settings/projects/[projectId]/members/page.tsx (4)

4-4: LGTM! Import additions support the refactoring objectives.

The new imports align well with the permission layer refactoring and internationalization goals:

  • useParams enables explicit parameter extraction
  • useTranslation supports i18n implementation
  • ProjectTeamspaceList extends functionality (though currently a placeholder)
  • getProjectSettingsPageLabelI18nKey provides consistent label resolution

Also applies to: 7-7, 16-17


21-23: Good implementation of hooks, consider parameter validation.

The extraction of route parameters and translation setup is implemented correctly. The code properly uses Next.js useParams and the translation hook.

Consider adding validation to ensure route parameters exist:

+ if (!routerWorkspaceSlug || !routerProjectId) {
+   return <div>Invalid route parameters</div>;
+ }

However, this might be handled at a higher level in the routing system.


46-50: Excellent internationalization implementation.

The replacement of the hardcoded "Members" title with a translated version is well-implemented:

  • Uses proper fallback mechanism with "common.members"
  • Leverages the helper function for consistent label resolution
  • Follows i18n best practices

This change aligns perfectly with the broader internationalization effort across the platform.


51-53: Great improvement in component prop management.

Passing workspaceSlug and projectId as explicit props is an excellent refactoring that:

  • Improves component reusability and testability
  • Makes data flow more explicit and clear
  • Aligns with the broader permission layer refactoring objectives

The addition of ProjectTeamspaceList extends functionality appropriately, even though it's currently a placeholder.

Ensure child components handle potentially undefined props gracefully, or implement the parameter validation suggested earlier to prevent undefined values from being passed down.

@sriramveeraghanta sriramveeraghanta merged commit 67cbe94 into preview May 30, 2025
5 of 6 checks passed
@sriramveeraghanta sriramveeraghanta deleted the refactor-permission-layer branch May 30, 2025 14:27
lifeiscontent pushed a commit that referenced this pull request Aug 18, 2025
* refactor: permission layer

* refactor: add original_role to project member serializer

* chore: minor fixes related to permission layer

* fix: strict type checking while checking user permissions
@coderabbitai coderabbitai bot mentioned this pull request Sep 11, 2025
6 tasks
@coderabbitai coderabbitai bot mentioned this pull request Sep 24, 2025
6 tasks
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.

5 participants