mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Access control: Reduce number of API calls for role picker (#44905)
* Restucture state for TeamRolePicker and UserRolePicker Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
This commit is contained in:
parent
61533a3cb4
commit
3cf31451ec
@ -1,38 +1,29 @@
|
|||||||
import React, { FC, useState } from 'react';
|
import React, { FC, useState } from 'react';
|
||||||
import { useAsync } from 'react-use';
|
import { useAsync } from 'react-use';
|
||||||
import { contextSrv } from 'app/core/core';
|
import { Role } from 'app/types';
|
||||||
import { AccessControlAction, Role } from 'app/types';
|
|
||||||
import { RolePicker } from './RolePicker';
|
import { RolePicker } from './RolePicker';
|
||||||
import { fetchRoleOptions, fetchTeamRoles, updateTeamRoles } from './api';
|
import { fetchTeamRoles, updateTeamRoles } from './api';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
teamId: number;
|
teamId: number;
|
||||||
orgId?: number;
|
orgId?: number;
|
||||||
getRoleOptions?: () => Promise<Role[]>;
|
roleOptions: Role[];
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
builtinRolesDisabled?: boolean;
|
builtinRolesDisabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TeamRolePicker: FC<Props> = ({ teamId, orgId, getRoleOptions, disabled, builtinRolesDisabled }) => {
|
export const TeamRolePicker: FC<Props> = ({ teamId, orgId, roleOptions, disabled, builtinRolesDisabled }) => {
|
||||||
const [roleOptions, setRoleOptions] = useState<Role[]>([]);
|
|
||||||
const [appliedRoles, setAppliedRoles] = useState<Role[]>([]);
|
const [appliedRoles, setAppliedRoles] = useState<Role[]>([]);
|
||||||
|
|
||||||
const { loading } = useAsync(async () => {
|
const { loading } = useAsync(async () => {
|
||||||
try {
|
try {
|
||||||
if (contextSrv.hasPermission(AccessControlAction.ActionRolesList)) {
|
|
||||||
let options = await (getRoleOptions ? getRoleOptions() : fetchRoleOptions(orgId));
|
|
||||||
setRoleOptions(options.filter((option) => !option.name?.startsWith('managed:')));
|
|
||||||
} else {
|
|
||||||
setRoleOptions([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const teamRoles = await fetchTeamRoles(teamId, orgId);
|
const teamRoles = await fetchTeamRoles(teamId, orgId);
|
||||||
setAppliedRoles(teamRoles);
|
setAppliedRoles(teamRoles);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// TODO handle error
|
// TODO handle error
|
||||||
console.error('Error loading options');
|
console.error('Error loading options');
|
||||||
}
|
}
|
||||||
}, [getRoleOptions, orgId, teamId]);
|
}, [orgId, teamId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RolePicker
|
<RolePicker
|
||||||
|
@ -3,15 +3,15 @@ import { useAsync } from 'react-use';
|
|||||||
import { contextSrv } from 'app/core/core';
|
import { contextSrv } from 'app/core/core';
|
||||||
import { Role, OrgRole, AccessControlAction } from 'app/types';
|
import { Role, OrgRole, AccessControlAction } from 'app/types';
|
||||||
import { RolePicker } from './RolePicker';
|
import { RolePicker } from './RolePicker';
|
||||||
import { fetchBuiltinRoles, fetchRoleOptions, fetchUserRoles, updateUserRoles } from './api';
|
import { fetchUserRoles, updateUserRoles } from './api';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
builtInRole: OrgRole;
|
builtInRole: OrgRole;
|
||||||
userId: number;
|
userId: number;
|
||||||
orgId?: number;
|
orgId?: number;
|
||||||
onBuiltinRoleChange: (newRole: OrgRole) => void;
|
onBuiltinRoleChange: (newRole: OrgRole) => void;
|
||||||
getRoleOptions?: () => Promise<Role[]>;
|
roleOptions: Role[];
|
||||||
getBuiltinRoles?: () => Promise<{ [key: string]: Role[] }>;
|
builtInRoles?: { [key: string]: Role[] };
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
builtinRolesDisabled?: boolean;
|
builtinRolesDisabled?: boolean;
|
||||||
}
|
}
|
||||||
@ -21,31 +21,15 @@ export const UserRolePicker: FC<Props> = ({
|
|||||||
userId,
|
userId,
|
||||||
orgId,
|
orgId,
|
||||||
onBuiltinRoleChange,
|
onBuiltinRoleChange,
|
||||||
getRoleOptions,
|
roleOptions,
|
||||||
getBuiltinRoles,
|
builtInRoles,
|
||||||
disabled,
|
disabled,
|
||||||
builtinRolesDisabled,
|
builtinRolesDisabled,
|
||||||
}) => {
|
}) => {
|
||||||
const [roleOptions, setRoleOptions] = useState<Role[]>([]);
|
|
||||||
const [appliedRoles, setAppliedRoles] = useState<Role[]>([]);
|
const [appliedRoles, setAppliedRoles] = useState<Role[]>([]);
|
||||||
const [builtInRoles, setBuiltinRoles] = useState<Record<string, Role[]>>({});
|
|
||||||
|
|
||||||
const { loading } = useAsync(async () => {
|
const { loading } = useAsync(async () => {
|
||||||
try {
|
try {
|
||||||
if (contextSrv.hasPermission(AccessControlAction.ActionRolesList)) {
|
|
||||||
let options = await (getRoleOptions ? getRoleOptions() : fetchRoleOptions(orgId));
|
|
||||||
setRoleOptions(options.filter((option) => !option.name?.startsWith('managed:')));
|
|
||||||
} else {
|
|
||||||
setRoleOptions([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contextSrv.hasPermission(AccessControlAction.ActionBuiltinRolesList)) {
|
|
||||||
const builtInRoles = await (getBuiltinRoles ? getBuiltinRoles() : fetchBuiltinRoles(orgId));
|
|
||||||
setBuiltinRoles(builtInRoles);
|
|
||||||
} else {
|
|
||||||
setBuiltinRoles({});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contextSrv.hasPermission(AccessControlAction.ActionUserRolesList)) {
|
if (contextSrv.hasPermission(AccessControlAction.ActionUserRolesList)) {
|
||||||
const userRoles = await fetchUserRoles(userId, orgId);
|
const userRoles = await fetchUserRoles(userId, orgId);
|
||||||
setAppliedRoles(userRoles);
|
setAppliedRoles(userRoles);
|
||||||
@ -56,7 +40,7 @@ export const UserRolePicker: FC<Props> = ({
|
|||||||
// TODO handle error
|
// TODO handle error
|
||||||
console.error('Error loading options');
|
console.error('Error loading options');
|
||||||
}
|
}
|
||||||
}, [getBuiltinRoles, getRoleOptions, orgId, userId]);
|
}, [orgId, userId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RolePicker
|
<RolePicker
|
||||||
|
@ -20,6 +20,7 @@ import { OrgPicker, OrgSelectItem } from 'app/core/components/Select/OrgPicker';
|
|||||||
import { OrgRolePicker } from './OrgRolePicker';
|
import { OrgRolePicker } from './OrgRolePicker';
|
||||||
import { contextSrv } from 'app/core/core';
|
import { contextSrv } from 'app/core/core';
|
||||||
import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker';
|
import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker';
|
||||||
|
import { fetchRoleOptions } from 'app/core/components/RolePicker/api';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
orgs: UserOrg[];
|
orgs: UserOrg[];
|
||||||
@ -133,8 +134,25 @@ class UnThemedOrgRow extends PureComponent<OrgRowProps> {
|
|||||||
state = {
|
state = {
|
||||||
currentRole: this.props.org.role,
|
currentRole: this.props.org.role,
|
||||||
isChangingRole: false,
|
isChangingRole: false,
|
||||||
|
roleOptions: [],
|
||||||
|
builtInRoles: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (contextSrv.licensedAccessControlEnabled()) {
|
||||||
|
if (contextSrv.hasPermission(AccessControlAction.ActionRolesList)) {
|
||||||
|
fetchRoleOptions(this.props.org.orgId)
|
||||||
|
.then((roles) => this.setState({ roleOptions: roles }))
|
||||||
|
.catch((e) => console.error(e));
|
||||||
|
}
|
||||||
|
if (contextSrv.hasPermission(AccessControlAction.ActionBuiltinRolesList)) {
|
||||||
|
fetchRoleOptions(this.props.org.orgId)
|
||||||
|
.then((roles) => this.setState({ builtInRoles: roles }))
|
||||||
|
.catch((e) => console.error(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onOrgRemove = () => {
|
onOrgRemove = () => {
|
||||||
const { org } = this.props;
|
const { org } = this.props;
|
||||||
this.props.onOrgRemove(org.orgId);
|
this.props.onOrgRemove(org.orgId);
|
||||||
@ -184,6 +202,8 @@ class UnThemedOrgRow extends PureComponent<OrgRowProps> {
|
|||||||
userId={user?.id || 0}
|
userId={user?.id || 0}
|
||||||
orgId={org.orgId}
|
orgId={org.orgId}
|
||||||
builtInRole={org.role}
|
builtInRole={org.role}
|
||||||
|
roleOptions={this.state.roleOptions}
|
||||||
|
builtInRoles={this.state.builtInRoles}
|
||||||
onBuiltinRoleChange={this.onBuiltinRoleChange}
|
onBuiltinRoleChange={this.onBuiltinRoleChange}
|
||||||
builtinRolesDisabled={rolePickerDisabled}
|
builtinRolesDisabled={rolePickerDisabled}
|
||||||
/>
|
/>
|
||||||
|
@ -28,10 +28,15 @@ const ServiceAccountsTable: FC<Props> = (props) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchOptions() {
|
async function fetchOptions() {
|
||||||
try {
|
try {
|
||||||
|
if (contextSrv.hasPermission(AccessControlAction.ActionRolesList)) {
|
||||||
let options = await fetchRoleOptions(orgId);
|
let options = await fetchRoleOptions(orgId);
|
||||||
setRoleOptions(options);
|
setRoleOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contextSrv.hasPermission(AccessControlAction.ActionBuiltinRolesList)) {
|
||||||
const builtInRoles = await fetchBuiltinRoles(orgId);
|
const builtInRoles = await fetchBuiltinRoles(orgId);
|
||||||
setBuiltinRoles(builtInRoles);
|
setBuiltinRoles(builtInRoles);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error loading options');
|
console.error('Error loading options');
|
||||||
}
|
}
|
||||||
@ -41,9 +46,6 @@ const ServiceAccountsTable: FC<Props> = (props) => {
|
|||||||
}
|
}
|
||||||
}, [orgId]);
|
}, [orgId]);
|
||||||
|
|
||||||
const getRoleOptions = async () => roleOptions;
|
|
||||||
const getBuiltinRoles = async () => builtinRoles;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<table className="filter-table form-inline">
|
<table className="filter-table form-inline">
|
||||||
@ -89,8 +91,8 @@ const ServiceAccountsTable: FC<Props> = (props) => {
|
|||||||
orgId={orgId}
|
orgId={orgId}
|
||||||
builtInRole={serviceAccount.role}
|
builtInRole={serviceAccount.role}
|
||||||
onBuiltinRoleChange={(newRole) => onRoleChange(newRole, serviceAccount)}
|
onBuiltinRoleChange={(newRole) => onRoleChange(newRole, serviceAccount)}
|
||||||
getRoleOptions={getRoleOptions}
|
roleOptions={roleOptions}
|
||||||
getBuiltinRoles={getBuiltinRoles}
|
builtInRoles={builtinRoles}
|
||||||
disabled={rolePickerDisabled}
|
disabled={rolePickerDisabled}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
@ -43,7 +43,7 @@ export class TeamList extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.fetchTeams();
|
this.fetchTeams();
|
||||||
if (contextSrv.licensedAccessControlEnabled()) {
|
if (contextSrv.licensedAccessControlEnabled() && contextSrv.hasPermission(AccessControlAction.ActionRolesList)) {
|
||||||
this.fetchRoleOptions();
|
this.fetchRoleOptions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,7 +95,7 @@ export class TeamList extends PureComponent<Props, State> {
|
|||||||
</td>
|
</td>
|
||||||
{contextSrv.licensedAccessControlEnabled() && (
|
{contextSrv.licensedAccessControlEnabled() && (
|
||||||
<td>
|
<td>
|
||||||
<TeamRolePicker teamId={team.id} getRoleOptions={async () => this.state.roleOptions} />
|
<TeamRolePicker teamId={team.id} roleOptions={this.state.roleOptions} />
|
||||||
</td>
|
</td>
|
||||||
)}
|
)}
|
||||||
<td className="text-right">
|
<td className="text-right">
|
||||||
|
@ -26,15 +26,11 @@ const UsersTable: FC<Props> = (props) => {
|
|||||||
if (contextSrv.hasPermission(AccessControlAction.ActionRolesList)) {
|
if (contextSrv.hasPermission(AccessControlAction.ActionRolesList)) {
|
||||||
let options = await fetchRoleOptions(orgId);
|
let options = await fetchRoleOptions(orgId);
|
||||||
setRoleOptions(options);
|
setRoleOptions(options);
|
||||||
} else {
|
|
||||||
setRoleOptions([]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contextSrv.hasPermission(AccessControlAction.ActionBuiltinRolesList)) {
|
if (contextSrv.hasPermission(AccessControlAction.ActionBuiltinRolesList)) {
|
||||||
const builtInRoles = await fetchBuiltinRoles(orgId);
|
const builtInRoles = await fetchBuiltinRoles(orgId);
|
||||||
setBuiltinRoles(builtInRoles);
|
setBuiltinRoles(builtInRoles);
|
||||||
} else {
|
|
||||||
setBuiltinRoles({});
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error loading options');
|
console.error('Error loading options');
|
||||||
@ -45,9 +41,6 @@ const UsersTable: FC<Props> = (props) => {
|
|||||||
}
|
}
|
||||||
}, [orgId]);
|
}, [orgId]);
|
||||||
|
|
||||||
const getRoleOptions = async () => roleOptions;
|
|
||||||
const getBuiltinRoles = async () => builtinRoles;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<table className="filter-table form-inline">
|
<table className="filter-table form-inline">
|
||||||
@ -94,8 +87,8 @@ const UsersTable: FC<Props> = (props) => {
|
|||||||
orgId={orgId}
|
orgId={orgId}
|
||||||
builtInRole={user.role}
|
builtInRole={user.role}
|
||||||
onBuiltinRoleChange={(newRole) => onRoleChange(newRole, user)}
|
onBuiltinRoleChange={(newRole) => onRoleChange(newRole, user)}
|
||||||
getRoleOptions={getRoleOptions}
|
roleOptions={roleOptions}
|
||||||
getBuiltinRoles={getBuiltinRoles}
|
builtInRoles={builtinRoles}
|
||||||
disabled={!contextSrv.hasPermissionInMetadata(AccessControlAction.OrgUsersRoleUpdate, user)}
|
disabled={!contextSrv.hasPermissionInMetadata(AccessControlAction.OrgUsersRoleUpdate, user)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
Loading…
Reference in New Issue
Block a user