Authorization: Add group to role DisplayName to make filtered list more clear (#102950)
* add group to role DisplayName to make searching easier * clean up more role names; add filtered display text when fetching * pass filter state into role menu to decide how to display role name * prop name better describes what it does
This commit is contained in:
+10
-10
@@ -99,7 +99,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
builtInDatasourceReader := ac.RoleRegistration{
|
||||
Role: ac.RoleDTO{
|
||||
Name: "fixed:datasources.builtin:reader",
|
||||
DisplayName: "Built in reader",
|
||||
DisplayName: "Built in data source reader",
|
||||
Description: "Read and query Grafana's built in test data sources.",
|
||||
Group: "Data sources",
|
||||
Permissions: []ac.Permission{
|
||||
@@ -321,7 +321,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
dashboardAnnotationsWriterRole := ac.RoleRegistration{
|
||||
Role: ac.RoleDTO{
|
||||
Name: "fixed:annotations.dashboard:writer",
|
||||
DisplayName: "Dashboard annotation writer",
|
||||
DisplayName: "Writer (dashboard)",
|
||||
Description: "Update annotations associated with dashboards.",
|
||||
Group: "Annotations",
|
||||
Permissions: []ac.Permission{
|
||||
@@ -353,7 +353,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
annotationsReaderRole = ac.RoleRegistration{
|
||||
Role: ac.RoleDTO{
|
||||
Name: "fixed:annotations:reader",
|
||||
DisplayName: "Organization annotation reader",
|
||||
DisplayName: "Reader (organization)",
|
||||
Description: "Read organization annotations and annotation tags",
|
||||
Group: "Annotations",
|
||||
Permissions: []ac.Permission{
|
||||
@@ -370,7 +370,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
annotationsWriterRole = ac.RoleRegistration{
|
||||
Role: ac.RoleDTO{
|
||||
Name: "fixed:annotations:writer",
|
||||
DisplayName: "Organization annotation writer",
|
||||
DisplayName: "Writer (organization)",
|
||||
Description: "Update organization annotations.",
|
||||
Group: "Annotations",
|
||||
Permissions: []ac.Permission{
|
||||
@@ -463,7 +463,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
generalFolderReaderRole := ac.RoleRegistration{
|
||||
Role: ac.RoleDTO{
|
||||
Name: "fixed:folders.general:reader",
|
||||
DisplayName: "General folder reader",
|
||||
DisplayName: "Reader (root)",
|
||||
Description: "Access the general (root) folder.",
|
||||
Group: "Folders",
|
||||
Hidden: true,
|
||||
@@ -526,7 +526,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
libraryPanelsGeneralReaderRole := ac.RoleRegistration{
|
||||
Role: ac.RoleDTO{
|
||||
Name: "fixed:library.panels:general.reader",
|
||||
DisplayName: "General reader",
|
||||
DisplayName: "Reader (root)",
|
||||
Description: "Read all library panels under the root folder.",
|
||||
Group: "Library panels",
|
||||
Permissions: []ac.Permission{
|
||||
@@ -554,7 +554,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
libraryPanelsGeneralWriterRole := ac.RoleRegistration{
|
||||
Role: ac.RoleDTO{
|
||||
Name: "fixed:library.panels:general.writer",
|
||||
DisplayName: "Root level writer",
|
||||
DisplayName: "Writer (root)",
|
||||
Group: "Library panels",
|
||||
Description: "Create, read, write or delete all library panels and their permissions under the root folder.",
|
||||
Permissions: ac.ConcatPermissions(libraryPanelsGeneralReaderRole.Role.Permissions, []ac.Permission{
|
||||
@@ -569,7 +569,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
publicDashboardsWriterRole := ac.RoleRegistration{
|
||||
Role: ac.RoleDTO{
|
||||
Name: "fixed:dashboards.public:writer",
|
||||
DisplayName: "Public Dashboard writer",
|
||||
DisplayName: "Writer (public)",
|
||||
Description: "Create, write or disable a public dashboard.",
|
||||
Group: "Dashboards",
|
||||
Permissions: []ac.Permission{
|
||||
@@ -658,7 +658,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
allAnnotationsReaderRole := ac.RoleRegistration{
|
||||
Role: ac.RoleDTO{
|
||||
Name: "fixed:annotations.all:reader",
|
||||
DisplayName: "Reader",
|
||||
DisplayName: "Reader (all)",
|
||||
Description: "Read all annotations and tags",
|
||||
Group: "Annotations",
|
||||
Permissions: []ac.Permission{
|
||||
@@ -672,7 +672,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
allAnnotationsWriterRole := ac.RoleRegistration{
|
||||
Role: ac.RoleDTO{
|
||||
Name: "fixed:annotations.all:writer",
|
||||
DisplayName: "Writer",
|
||||
DisplayName: "Writer (all)",
|
||||
Description: "Update all annotations.",
|
||||
Group: "Annotations",
|
||||
Permissions: []ac.Permission{
|
||||
|
||||
@@ -163,8 +163,8 @@ func ProvideDashboardPermissions(
|
||||
"Edit": getDashboardEditActions(features),
|
||||
"Admin": getDashboardAdminActions(features),
|
||||
},
|
||||
ReaderRoleName: "Dashboard permission reader",
|
||||
WriterRoleName: "Dashboard permission writer",
|
||||
ReaderRoleName: "Permission reader",
|
||||
WriterRoleName: "Permission writer",
|
||||
RoleGroup: "Dashboards",
|
||||
}
|
||||
|
||||
|
||||
@@ -126,8 +126,8 @@ func ProvideFolderPermissions(
|
||||
"Edit": append(getDashboardEditActions(features), FolderEditActions...),
|
||||
"Admin": append(getDashboardAdminActions(features), FolderAdminActions...),
|
||||
},
|
||||
ReaderRoleName: "Folder permission reader",
|
||||
WriterRoleName: "Folder permission writer",
|
||||
ReaderRoleName: "Permission reader",
|
||||
WriterRoleName: "Permission writer",
|
||||
RoleGroup: "Folders",
|
||||
}
|
||||
srv, err := resourcepermissions.New(cfg, options, features, router, license, accesscontrol, service, sql, teamService, userService, actionSetService)
|
||||
|
||||
@@ -67,8 +67,8 @@ func ProvideServiceAccountPermissions(
|
||||
"Edit": ServiceAccountEditActions,
|
||||
"Admin": ServiceAccountAdminActions,
|
||||
},
|
||||
ReaderRoleName: "Service account permission reader",
|
||||
WriterRoleName: "Service account permission writer",
|
||||
ReaderRoleName: "Permission reader",
|
||||
WriterRoleName: "Permission writer",
|
||||
RoleGroup: "Service accounts",
|
||||
}
|
||||
|
||||
|
||||
@@ -78,8 +78,8 @@ func ProvideTeamPermissions(
|
||||
"Member": TeamMemberActions,
|
||||
"Admin": TeamAdminActions,
|
||||
},
|
||||
ReaderRoleName: "Team permission reader",
|
||||
WriterRoleName: "Team permission writer",
|
||||
ReaderRoleName: "Permission reader",
|
||||
WriterRoleName: "Permission writer",
|
||||
RoleGroup: "Teams",
|
||||
OnSetUser: func(session *db.Session, orgID int64, user accesscontrol.User, resourceID, permission string) error {
|
||||
teamId, err := strconv.ParseInt(resourceID, 10, 64)
|
||||
|
||||
@@ -43,7 +43,7 @@ const (
|
||||
var (
|
||||
ldapReaderRole = RoleDTO{
|
||||
Name: "fixed:ldap:reader",
|
||||
DisplayName: "LDAP reader",
|
||||
DisplayName: "Reader",
|
||||
Description: "Read LDAP configuration and status.",
|
||||
Group: "LDAP",
|
||||
Permissions: []Permission{
|
||||
@@ -58,7 +58,7 @@ var (
|
||||
|
||||
ldapWriterRole = RoleDTO{
|
||||
Name: "fixed:ldap:writer",
|
||||
DisplayName: "LDAP writer",
|
||||
DisplayName: "Writer",
|
||||
Description: "Read and update LDAP configuration and read LDAP status.",
|
||||
Group: "LDAP",
|
||||
Permissions: ConcatPermissions(ldapReaderRole.Permissions, []Permission{
|
||||
@@ -73,9 +73,9 @@ var (
|
||||
|
||||
orgUsersWriterRole = RoleDTO{
|
||||
Name: "fixed:org.users:writer",
|
||||
DisplayName: "Organization user writer",
|
||||
DisplayName: "Writer (organizational)",
|
||||
Description: "Within a single organization, add a user, invite a user, read information about a user and their role, remove a user from that organization, or change the role of a user.",
|
||||
Group: "User administration (organizational)",
|
||||
Group: "User administration",
|
||||
Permissions: ConcatPermissions(orgUsersReaderRole.Permissions, []Permission{
|
||||
{
|
||||
Action: ActionOrgUsersAdd,
|
||||
@@ -94,9 +94,9 @@ var (
|
||||
|
||||
orgUsersReaderRole = RoleDTO{
|
||||
Name: "fixed:org.users:reader",
|
||||
DisplayName: "Organization user reader",
|
||||
DisplayName: "Reader (organizational)",
|
||||
Description: "Read users within a single organization.",
|
||||
Group: "User administration (organizational)",
|
||||
Group: "User administration",
|
||||
Permissions: []Permission{
|
||||
{
|
||||
Action: ActionOrgUsersRead,
|
||||
@@ -111,7 +111,7 @@ var (
|
||||
|
||||
SettingsReaderRole = RoleDTO{
|
||||
Name: "fixed:settings:reader",
|
||||
DisplayName: "Setting reader",
|
||||
DisplayName: "Reader",
|
||||
Description: "Read Grafana instance settings.",
|
||||
Group: "Settings",
|
||||
Permissions: []Permission{
|
||||
@@ -124,7 +124,7 @@ var (
|
||||
|
||||
statsReaderRole = RoleDTO{
|
||||
Name: "fixed:stats:reader",
|
||||
DisplayName: "Statistics reader",
|
||||
DisplayName: "Reader",
|
||||
Description: "Read Grafana instance statistics.",
|
||||
Group: "Statistics",
|
||||
Permissions: []Permission{
|
||||
@@ -136,9 +136,9 @@ var (
|
||||
|
||||
usersReaderRole = RoleDTO{
|
||||
Name: "fixed:users:reader",
|
||||
DisplayName: "User reader",
|
||||
DisplayName: "Reader (global)",
|
||||
Description: "Read all users and their information, such as team memberships, authentication tokens, and quotas.",
|
||||
Group: "User administration (global)",
|
||||
Group: "User administration",
|
||||
Permissions: []Permission{
|
||||
{
|
||||
Action: ActionUsersRead,
|
||||
@@ -157,9 +157,9 @@ var (
|
||||
|
||||
usersWriterRole = RoleDTO{
|
||||
Name: "fixed:users:writer",
|
||||
DisplayName: "User writer",
|
||||
DisplayName: "Writer (global)",
|
||||
Description: "Read and update all attributes and settings for all users in Grafana: update user information, read user information, create or enable or disable a user, make a user a Grafana administrator, sign out a user, update a user’s authentication token, or update quotas for all users.",
|
||||
Group: "User administration (global)",
|
||||
Group: "User administration",
|
||||
Permissions: ConcatPermissions(usersReaderRole.Permissions, []Permission{
|
||||
{
|
||||
Action: ActionUsersPasswordUpdate,
|
||||
@@ -295,7 +295,7 @@ var (
|
||||
|
||||
usagestatsReaderRole = RoleDTO{
|
||||
Name: "fixed:usagestats:reader",
|
||||
DisplayName: "Usage stats report reader",
|
||||
DisplayName: "Usage report reader",
|
||||
Description: "View usage statistics report",
|
||||
Group: "Statistics",
|
||||
Permissions: []Permission{
|
||||
|
||||
@@ -60,7 +60,7 @@ func DeclareRBACRoles(service ac.Service, cfg *setting.Cfg, features featuremgmt
|
||||
PluginsWriter := ac.RoleRegistration{
|
||||
Role: ac.RoleDTO{
|
||||
Name: ac.FixedRolePrefix + "plugins:writer",
|
||||
DisplayName: "Plugin Writer",
|
||||
DisplayName: "Writer",
|
||||
Description: "Enable and disable plugins and edit plugins' settings",
|
||||
Group: "Plugins",
|
||||
Permissions: []ac.Permission{
|
||||
@@ -72,7 +72,7 @@ func DeclareRBACRoles(service ac.Service, cfg *setting.Cfg, features featuremgmt
|
||||
PluginsMaintainer := ac.RoleRegistration{
|
||||
Role: ac.RoleDTO{
|
||||
Name: ac.FixedRolePrefix + "plugins:maintainer",
|
||||
DisplayName: "Plugin Maintainer",
|
||||
DisplayName: "Maintainer",
|
||||
Description: "Install, uninstall plugins. Needs to be assigned globally.",
|
||||
Group: "Plugins",
|
||||
Permissions: []ac.Permission{
|
||||
|
||||
@@ -10,7 +10,7 @@ func RegisterRoles(service accesscontrol.Service) error {
|
||||
saReader := accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: "fixed:serviceaccounts:reader",
|
||||
DisplayName: "Service accounts reader",
|
||||
DisplayName: "Reader",
|
||||
Description: "Read service accounts and service account tokens.",
|
||||
Group: "Service accounts",
|
||||
Permissions: []accesscontrol.Permission{
|
||||
@@ -26,7 +26,7 @@ func RegisterRoles(service accesscontrol.Service) error {
|
||||
saCreator := accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: "fixed:serviceaccounts:creator",
|
||||
DisplayName: "Service accounts creator",
|
||||
DisplayName: "Creator",
|
||||
Description: "Create service accounts.",
|
||||
Group: "Service accounts",
|
||||
Permissions: []accesscontrol.Permission{
|
||||
@@ -41,7 +41,7 @@ func RegisterRoles(service accesscontrol.Service) error {
|
||||
saWriter := accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: "fixed:serviceaccounts:writer",
|
||||
DisplayName: "Service accounts writer",
|
||||
DisplayName: "Writer",
|
||||
Description: "Create, delete and read service accounts, manage service account permissions.",
|
||||
Group: "Service accounts",
|
||||
Permissions: accesscontrol.ConcatPermissions(saReader.Role.Permissions, []accesscontrol.Permission{
|
||||
|
||||
@@ -14,7 +14,7 @@ const (
|
||||
var (
|
||||
bundleReaderRole = accesscontrol.RoleDTO{
|
||||
Name: "fixed:support.bundles:reader",
|
||||
DisplayName: "Support bundle reader",
|
||||
DisplayName: "Reader",
|
||||
Description: "List and download support bundles",
|
||||
Group: "Support bundles",
|
||||
Permissions: []accesscontrol.Permission{
|
||||
@@ -24,7 +24,7 @@ var (
|
||||
|
||||
bundleWriterRole = accesscontrol.RoleDTO{
|
||||
Name: "fixed:support.bundles:writer",
|
||||
DisplayName: "Support bundle writer",
|
||||
DisplayName: "Writer",
|
||||
Description: "Create, delete, list and download support bundles",
|
||||
Group: "Support bundles",
|
||||
Permissions: []accesscontrol.Permission{
|
||||
|
||||
@@ -11,6 +11,7 @@ import { isNotDelegatable } from './utils';
|
||||
|
||||
interface RoleMenuGroupsSectionProps {
|
||||
roles: Role[];
|
||||
isFiltered?: boolean;
|
||||
renderedName: string;
|
||||
showGroups?: boolean;
|
||||
optionGroups: Array<{
|
||||
@@ -33,6 +34,7 @@ export const RoleMenuGroupsSection = forwardRef<HTMLDivElement, RoleMenuGroupsSe
|
||||
(
|
||||
{
|
||||
roles,
|
||||
isFiltered,
|
||||
renderedName,
|
||||
showGroups,
|
||||
optionGroups,
|
||||
@@ -101,6 +103,7 @@ export const RoleMenuGroupsSection = forwardRef<HTMLDivElement, RoleMenuGroupsSe
|
||||
))
|
||||
: roles.map((option) => (
|
||||
<RoleMenuOption
|
||||
useFilteredDisplayName={isFiltered}
|
||||
data={option}
|
||||
key={option.uid}
|
||||
isSelected={!!(option.uid && !!selectedOptions.find((opt) => opt.uid === option.uid))}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { getStyles } from './styles';
|
||||
interface RoleMenuOptionProps {
|
||||
data: Role;
|
||||
onChange: (value: Role) => void;
|
||||
useFilteredDisplayName?: boolean;
|
||||
isSelected?: boolean;
|
||||
isFocused?: boolean;
|
||||
disabled?: boolean;
|
||||
@@ -20,7 +21,7 @@ interface RoleMenuOptionProps {
|
||||
}
|
||||
|
||||
export const RoleMenuOption = forwardRef<HTMLDivElement, React.PropsWithChildren<RoleMenuOptionProps>>(
|
||||
({ data, isFocused, isSelected, disabled, mapped, onChange, hideDescription }, ref) => {
|
||||
({ data, isFocused, isSelected, useFilteredDisplayName, disabled, mapped, onChange, hideDescription }, ref) => {
|
||||
const theme = useTheme2();
|
||||
const styles = getSelectStyles(theme);
|
||||
const customStyles = useStyles2(getStyles);
|
||||
@@ -64,7 +65,7 @@ export const RoleMenuOption = forwardRef<HTMLDivElement, React.PropsWithChildren
|
||||
disabled={disabled}
|
||||
/>
|
||||
<div className={cx(styles.optionBody, customStyles.menuOptionBody)}>
|
||||
<span>{data.displayName || data.name}</span>
|
||||
<span>{(useFilteredDisplayName && data.filteredDisplayName) || data.displayName || data.name}</span>
|
||||
{!hideDescription && data.description && <div className={styles.optionDescription}>{data.description}</div>}
|
||||
</div>
|
||||
{disabledMessage && (
|
||||
|
||||
@@ -173,6 +173,7 @@ export const RolePicker = ({
|
||||
const options = roleOptions.map((r) => ({ ...r, delegatable: canUpdateRoles && r.delegatable }));
|
||||
|
||||
if (query && query.trim() !== '') {
|
||||
// TODO should this filter on `displayName` not (or in addition to) `name`?
|
||||
return options.filter((option) => option.name?.toLowerCase().includes(query.toLowerCase()));
|
||||
}
|
||||
return options;
|
||||
@@ -210,6 +211,7 @@ export const RolePicker = ({
|
||||
<div onClick={(e) => e.stopPropagation()}>
|
||||
<RolePickerMenu
|
||||
options={getOptions()}
|
||||
isFiltered={query.trim() !== ''}
|
||||
basicRole={selectedBuiltInRole}
|
||||
appliedRoles={appliedRoles}
|
||||
onBasicRoleSelect={onBasicRoleSelect}
|
||||
|
||||
@@ -53,6 +53,7 @@ const tooltipMessage = (
|
||||
interface RolePickerMenuProps {
|
||||
basicRole?: OrgRole;
|
||||
options: Role[];
|
||||
isFiltered?: boolean;
|
||||
appliedRoles: Role[];
|
||||
showGroups?: boolean;
|
||||
basicRoleDisabled?: boolean;
|
||||
@@ -70,6 +71,7 @@ interface RolePickerMenuProps {
|
||||
export const RolePickerMenu = ({
|
||||
basicRole,
|
||||
options,
|
||||
isFiltered,
|
||||
appliedRoles,
|
||||
showGroups,
|
||||
basicRoleDisabled,
|
||||
@@ -259,6 +261,7 @@ export const RolePickerMenu = ({
|
||||
<RoleMenuGroupsSection
|
||||
key={groupId}
|
||||
roles={collection.roles}
|
||||
isFiltered={isFiltered}
|
||||
renderedName={collection.renderedName}
|
||||
showGroups={showGroups}
|
||||
optionGroups={collection.optionGroup}
|
||||
|
||||
@@ -47,6 +47,7 @@ export const RolePickerSubMenu = ({
|
||||
{options.map((option, i) => (
|
||||
<RoleMenuOption
|
||||
data={option}
|
||||
useFilteredDisplayName={false}
|
||||
key={i}
|
||||
isSelected={
|
||||
!!(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { getBackendSrv, isFetchError } from '@grafana/runtime';
|
||||
import { Role } from 'app/types';
|
||||
|
||||
import { addDisplayNameForFixedRole } from './utils';
|
||||
import { addDisplayNameForFixedRole, addFilteredDisplayName } from './utils';
|
||||
|
||||
export const fetchRoleOptions = async (orgId?: number): Promise<Role[]> => {
|
||||
let rolesUrl = '/api/access-control/roles?delegatable=true';
|
||||
@@ -12,7 +12,7 @@ export const fetchRoleOptions = async (orgId?: number): Promise<Role[]> => {
|
||||
if (!roles || !roles.length) {
|
||||
return [];
|
||||
}
|
||||
return roles.map(addDisplayNameForFixedRole);
|
||||
return roles.map(addDisplayNameForFixedRole).map(addFilteredDisplayName);
|
||||
};
|
||||
|
||||
export const fetchUserRoles = async (userId: number, orgId?: number): Promise<Role[]> => {
|
||||
@@ -25,7 +25,7 @@ export const fetchUserRoles = async (userId: number, orgId?: number): Promise<Ro
|
||||
if (!roles || !roles.length) {
|
||||
return [];
|
||||
}
|
||||
return roles.map(addDisplayNameForFixedRole);
|
||||
return roles.map(addDisplayNameForFixedRole).map(addFilteredDisplayName);
|
||||
} catch (error) {
|
||||
if (isFetchError(error)) {
|
||||
error.isHandled = true;
|
||||
@@ -57,7 +57,7 @@ export const fetchTeamRoles = async (teamId: number, orgId?: number): Promise<Ro
|
||||
if (!roles || !roles.length) {
|
||||
return [];
|
||||
}
|
||||
return roles.map(addDisplayNameForFixedRole);
|
||||
return roles.map(addDisplayNameForFixedRole).map(addFilteredDisplayName);
|
||||
} catch (error) {
|
||||
if (isFetchError(error)) {
|
||||
error.isHandled = true;
|
||||
|
||||
@@ -19,3 +19,9 @@ export const addDisplayNameForFixedRole = (role: Role) => {
|
||||
}
|
||||
return role;
|
||||
};
|
||||
|
||||
// Adds a display name for use when the list of roles is filtered
|
||||
export const addFilteredDisplayName = (role: Role) => {
|
||||
role.filteredDisplayName = role.group + ':' + role.displayName;
|
||||
return role;
|
||||
};
|
||||
|
||||
@@ -22,6 +22,7 @@ const props = {
|
||||
uid: 'uid',
|
||||
name: 'admin',
|
||||
displayName: 'Admin',
|
||||
filteredDisplayName: 'group:Admin',
|
||||
description: 'description',
|
||||
group: 'group',
|
||||
global: true,
|
||||
|
||||
@@ -173,6 +173,7 @@ export interface Role {
|
||||
uid: string;
|
||||
name: string;
|
||||
displayName: string;
|
||||
filteredDisplayName: string; // name to be shown in filtered role list
|
||||
description: string;
|
||||
group: string;
|
||||
global: boolean;
|
||||
|
||||
Reference in New Issue
Block a user