project access_dropdown.vue - fetch and display custom roles section
## Context | | | |---|---| | **Phase** | 5 of 6 | | **Parallel with** | https://gitlab.com/gitlab-org/gitlab/-/work_items/594888+ <br> https://gitlab.com/gitlab-org/gitlab/-/work_items/594889+ <br> https://gitlab.com/gitlab-org/gitlab/-/work_items/594890+ | | **Blocked by** | https://gitlab.com/gitlab-org/gitlab/-/work_items/594886+ | | **Unblocks** | https://gitlab.com/gitlab-org/gitlab/-/work_items/594891+ | ## Summary Update the project-level `access_levels_drawer.vue` component to fetch custom roles from the API and display them as a new "Custom Roles" section in the dropdown, between the Roles and Groups sections. ## Background `app/assets/javascripts/projects/settings/components/access_dropdown.vue` is the **legacy** shared dropdown for configuring who can push, merge, and unprotect protected branches. It currently supports four sections: Roles, Groups, Users, and Deploy Keys. `app/assets/javascripts/projects/settings/branch_rules/components/access_levels_drawer.vue` is the corresponding component in the branch rules details view. This is an EE-only feature. The component changes should be added in an EE override or via a slot/prop mechanism. ~~However, given the complexity of the component and the fact that the `MEMBER_ROLE` constant addition in Issue 12 is already in the CE file, the cleanest approach is to add the custom roles data and section within the CE component guarded by `hasLicense` (which is already the gate for users/groups).~~ > [!NOTE] > @psjakubowska: Branch rules components have been recently refactored to use named slots for EE extensions: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/227127/diffs. Let's follow this pattern here as well. The ~~`getMemberRoles` API function (Issue 11) and~~ `MEMBER_ROLE` constant (Issue 12) must be available before starting this issue. > [!NOTE] > We don't need the `getMemberRoles` API function for the project level. Let's move `ee/app/assets/javascripts/invite_members/graphql/queries/project_member_roles.query.graphql` to `graphql_shared` directory and reuse it directly for this. ## Relevant file ~~`app/assets/javascripts/projects/settings/components/access_dropdown.vue`~~ `app/assets/javascripts/projects/settings/branch_rules/components/access_levels_drawer.vue` ## Changes required ### Props Add a new optional prop to pass the `projectPath` for fetching custom roles: ```javascript projectPath: { type: String, required: false, default: null, }, ``` This is injected in `app/assets/javascripts/projects/settings/branch_rules/components/index.vue` ### Data Fetch custom roles with Apollo upon `isOpen` change to `true`. Reuse `ee/app/assets/javascripts/invite_members/graphql/queries/project_member_roles.query.graphql`. ### `getRuleEditData()` method Include in `getRuleEditData()` ```javascript const ruleEditRoles = [ // ...existing roles ...this.formatItemsData(this.updatedCustomRoles, 'id', 'CustomRoles'), ]; let ruleEditAccessLevels = []; // ...existing logic if (this.isCustomRolesSelected) { ruleEditAccessLevels.push({ accessLevel: ACCESS_LEVEL_CUSTOM_ROLES_INTEGER }); } return [...ruleEditRoles, ...ruleEditAccessLevels]; ``` ### i18n Use `accessLevelConfig` from `app/assets/javascripts/projects/settings/branch_rules/components/constants.js` with previously defined integer from https://gitlab.com/gitlab-org/gitlab/-/work_items/594886+ ### Template Add a new section between Roles and Groups: ```html <template v-if="customRoles.length"> <gl-dropdown-section-header>{{ $options.i18n.customRolesSectionHeader }}</gl-dropdown-section-header> <gl-dropdown-item v-for="role in customRoles" :key="`member-role-${role.id}`" data-testid="member-role-dropdown-item" is-check-item :is-checked="isSelected(role)" @click.capture.native.stop="onItemClick(role)" > {{ role.name }} </gl-dropdown-item> <gl-dropdown-divider v-if="groups.length || users.length || showDeployKeys" /> </template> ``` > [!NOTE] > The component is getting rather long. Let's extract the checkboxes to a presentational component, while leaving the logic in side `access_levels_drawer.vue` ## Notes - Custom roles should only display when `hasLicense` is true (EE-only feature) - If the namespace has no custom roles, the section is hidden (already handled by `v-if="customRoles.length"`) - Search/filter: custom roles should not be filtered by the search query (they are a finite list, not paginated like users). Include all roles regardless of query, similar to how groups work ## Testing - Jest: custom roles section renders when `customRoles` has items - Jest: custom roles section hidden when `customRoles` is empty - Jest: `getProjectMemberRoles` is fetched when drawer is open - Jest: `getProjectMemberRoles` does not fetch on initial mount - Jest: clicking a custom role item calls `handleAccessLevelSelected` with the correct item - Jest: custom role items show as checked when selected ## Dependencies - Issue 12 (`MEMBER_ROLE` constant)
issue