Skip to content
代码片段 群组 项目
未验证 提交 ffca1e63 编辑于 作者: Aaron Huntsman's avatar Aaron Huntsman 提交者: GitLab
浏览文件

Merge branch '468386-add-custom-role-details-page' into 'master'

No related branches found
No related tags found
无相关合并请求
显示
230 个添加10 个删除
......@@ -81,6 +81,10 @@ export const BASE_ROLES = [
},
];
export const BASE_ROLES_WITHOUT_MINIMAL_ACCESS = BASE_ROLES.filter(
({ accessLevel }) => accessLevel !== ACCESS_LEVEL_MINIMAL_ACCESS_INTEGER,
);
export const ACCESS_LEVEL_LABELS = {
[ACCESS_LEVEL_NO_ACCESS_INTEGER]: ACCESS_LEVEL_NO_ACCESS,
[ACCESS_LEVEL_MINIMAL_ACCESS_INTEGER]: ACCESS_LEVEL_MINIMAL_ACCESS,
......
import { initRoleDetailsApp } from 'ee/roles_and_permissions/show';
initRoleDetailsApp();
import { initRoleDetailsApp } from 'ee/roles_and_permissions/show';
initRoleDetailsApp();
<script>
import { GlSprintf, GlAlert, GlButton, GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui';
import { s__ } from '~/locale';
import { localeDateFormat } from '~/lib/utils/datetime_utility';
import { BASE_ROLES_WITHOUT_MINIMAL_ACCESS } from '~/access_level/constants';
import { visitUrl } from '~/lib/utils/url_utility';
import { TYPENAME_MEMBER_ROLE } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import DeleteRoleModal from '../delete_role_modal.vue';
import memberRoleQuery from '../../graphql/member_role.query.graphql';
export default {
components: {
GlSprintf,
GlAlert,
GlButton,
GlLoadingIcon,
DeleteRoleModal,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
roleId: {
type: String,
required: true,
},
listPagePath: {
type: String,
required: true,
},
},
data() {
return {
memberRole: null,
roleToDelete: null,
errorMessage: '',
};
},
apollo: {
memberRole: {
query: memberRoleQuery,
errorPolicy: 'none', // This is needed to stop the result() block from being called when there's an error.
variables() {
return { id: convertToGraphQLId(TYPENAME_MEMBER_ROLE, this.roleId) };
},
skip() {
return Boolean(this.standardRole);
},
error() {
this.memberRole = null;
},
},
},
computed: {
standardRole() {
return BASE_ROLES_WITHOUT_MINIMAL_ACCESS.find(
({ value }) => value === this.roleId.toUpperCase(),
);
},
role() {
return this.memberRole || this.standardRole;
},
headerDescription() {
return this.memberRole
? s__('MemberRole|Custom role created on %{dateTime}')
: s__('MemberRole|This role is available by default and cannot be changed.');
},
createdDate() {
return localeDateFormat.asDate.format(this.role.createdAt);
},
deleteButtonTooltip() {
// The button will be disabled if there are assigned members, so we want to show the tooltip immediately on hover
// instead of the default 0.5-second delay.
return this.hasAssignedMembers
? { title: s__('MemberRole|To delete custom role, remove role from all users.'), delay: 0 }
: s__('MemberRole|Delete role');
},
hasAssignedMembers() {
return this.role.membersCount > 0;
},
},
methods: {
navigateToListPage() {
visitUrl(this.listPagePath);
},
},
};
</script>
<template>
<gl-loading-icon v-if="$apollo.queries.memberRole.loading" size="md" class="gl-mt-5" />
<gl-alert v-else-if="!role" variant="danger" class="gl-mt-5" :dismissible="false">
{{ s__('MemberRole|Failed to fetch role.') }}
</gl-alert>
<div v-else data-testid="role-details">
<header class="gl-flex gl-gap-3 gl-items-center gl-mt-6 gl-mb-4 gl-flex-wrap">
<h1 class="gl-m-0 gl-mr-auto">{{ role.name || role.text }}</h1>
<div v-if="memberRole" class="gl-flex gl-items-center gl-gap-3" data-testid="action-buttons">
<gl-button
v-gl-tooltip="s__('MemberRole|Edit role')"
icon="pencil"
:href="role.editPath"
class="gl-ml-2"
data-testid="edit-button"
/>
<div v-gl-tooltip="deleteButtonTooltip" data-testid="delete-button">
<gl-button
icon="remove"
category="secondary"
variant="danger"
:disabled="hasAssignedMembers"
@click="roleToDelete = role"
/>
</div>
<delete-role-modal
:role="roleToDelete"
@deleted="navigateToListPage"
@close="roleToDelete = null"
/>
</div>
</header>
<p class="gl-w-full">
<gl-sprintf :message="headerDescription">
<template #dateTime>{{ createdDate }}</template>
</gl-sprintf>
</p>
</div>
</template>
......@@ -3,8 +3,12 @@ query memberRole($id: MemberRoleID!) {
id
name
description
createdAt
editPath
membersCount
baseAccessLevel {
stringValue
humanAccess
}
enabledPermissions {
nodes {
......
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import RoleDetails from './components/role_details/role_details.vue';
Vue.use(VueApollo);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
export const initRoleDetailsApp = () => {
const el = document.querySelector('#js-role-details');
if (!el) {
return null;
}
return new Vue({
el,
name: 'RoleDetailsRoot',
apolloProvider,
render(createElement) {
return createElement(RoleDetails, {
props: {
roleId: el.dataset.id,
listPagePath: el.dataset.listPagePath,
},
});
},
});
};
......@@ -4,6 +4,7 @@ module Admin
module ApplicationSettings
class RolesAndPermissionsController < Admin::ApplicationController
include ::GitlabSubscriptions::SubscriptionHelper
include ::EE::RolesAndPermissions # rubocop: disable Cop/InjectEnterpriseEditionModule -- EE-only concern
feature_category :user_management
......
# frozen_string_literal: true
module EE
module RolesAndPermissions
extend ActiveSupport::Concern
include ::Gitlab::Utils::StrongMemoize
included do
before_action :ensure_role_exists!, only: [:show, :edit]
end
private
def ensure_role_exists!
render_404 unless member_role
end
def member_role
id = params.permit(:id)[:id]
if /\A\d+\z/.match?(id)
MemberRoles::RolesFinder.new(current_user, id: id).execute.first
else
access_level = ::Types::MemberAccessLevelEnum.enum[id.downcase]
name = ::Gitlab::Access.options_with_owner.key(access_level)
{ name: name } if name
end
end
strong_memoize_attr :member_role
end
end
......@@ -4,6 +4,7 @@ module Groups
module Settings
class RolesAndPermissionsController < Groups::ApplicationController
include ::GitlabSubscriptions::SubscriptionHelper
include ::EE::RolesAndPermissions # rubocop: disable Cop/InjectEnterpriseEditionModule -- EE-only concern
feature_category :user_management
......
- return unless License.feature_available?(:custom_roles)
- add_to_breadcrumbs _('Roles and Permissions'), admin_application_settings_roles_and_permissions_path
- page_title s_('MemberRole|Edit role')
......
- return unless License.feature_available?(:custom_roles)
- page_title _('Roles and Permissions')
#js-roles-and-permissions{ data: member_roles_data }
......
- return unless License.feature_available?(:custom_roles)
- add_to_breadcrumbs _('Roles and Permissions'), admin_application_settings_roles_and_permissions_path
- page_title s_('MemberRole|Create role')
......
- add_to_breadcrumbs _('Roles and Permissions'), admin_application_settings_roles_and_permissions_path
- breadcrumb_title @member_role[:name]
- page_title @member_role[:name], _('Roles and Permissions')
#js-role-details{ data: { id: params[:id], list_page_path: admin_application_settings_roles_and_permissions_path } }
= gl_loading_icon(css_class: 'gl-mt-5', size: 'md')
- return unless @group.licensed_feature_available?(:custom_roles)
- add_to_breadcrumbs _('Roles and Permissions'), group_settings_roles_and_permissions_path
- page_title s_('MemberRole|Edit role')
......
- return unless @group.licensed_feature_available?(:custom_roles)
- page_title _('Roles and Permissions')
#js-roles-and-permissions{ data: member_roles_data(@group) }
......
- return unless @group.licensed_feature_available?(:custom_roles)
- add_to_breadcrumbs _('Roles and Permissions'), group_settings_roles_and_permissions_path
- page_title s_('MemberRole|Create role')
......
- add_to_breadcrumbs _('Roles and Permissions'), group_settings_roles_and_permissions_path
- breadcrumb_title @member_role[:name]
- page_title @member_role[:name], _('Roles and Permissions')
#js-role-details{ data: { id: params[:id], list_page_path: group_settings_roles_and_permissions_path } }
= gl_loading_icon(css_class: 'gl-mt-5', size: 'md')
......@@ -65,7 +65,7 @@
resource :scim_oauth, only: [:create], controller: :scim_oauth, module: 'application_settings'
resources :roles_and_permissions, only: [:index, :new, :edit], module: 'application_settings'
resources :roles_and_permissions, only: [:index, :new, :edit, :show], module: 'application_settings'
end
namespace :geo do
......
......@@ -19,7 +19,7 @@
end
end
resource :merge_requests, only: [:update]
resources :roles_and_permissions, only: [:index, :new, :edit]
resources :roles_and_permissions, only: [:index, :new, :edit, :show]
resource :analytics, only: [:show, :update]
resources :gitlab_duo_usage, only: [:index]
......
......@@ -13,7 +13,7 @@ import memberRoleQuery from 'ee/roles_and_permissions/graphql/member_role.query.
import { visitUrl } from '~/lib/utils/url_utility';
import PermissionsSelector from 'ee/roles_and_permissions/components/permissions_selector.vue';
import { BASE_ROLES } from '~/access_level/constants';
import { mockMemberRoleQueryResponse } from '../mock_data';
import { getMemberRoleQueryResponse } from '../mock_data';
Vue.use(VueApollo);
......@@ -36,7 +36,7 @@ describe('CreateMemberRole', () => {
const createMutationSuccessHandler = jest.fn().mockResolvedValue(mutationSuccessData);
const updateMutationSuccessHandler = jest.fn().mockResolvedValue(mutationSuccessData);
const defaultMemberRoleHandler = jest.fn().mockResolvedValue(mockMemberRoleQueryResponse);
const defaultMemberRoleHandler = jest.fn().mockResolvedValue(getMemberRoleQueryResponse());
const createComponent = ({
stubs,
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册