Commit 96aa4ae1 by Hugo Häggmark Committed by Leonard Gram

teams: remov permission select for non admin users

parent b9cf09a2
......@@ -12,6 +12,7 @@ const setup = (propOverrides?: object) => {
{
link: {},
user: {
id: 1,
isGrafanaAdmin: false,
isSignedIn: false,
orgCount: 2,
......
......@@ -3,6 +3,7 @@ import _ from 'lodash';
import coreModule from 'app/core/core_module';
export class User {
id: number;
isGrafanaAdmin: any;
isSignedIn: any;
orgRole: any;
......
......@@ -4,8 +4,25 @@ import { TeamMembers, Props, State } from './TeamMembers';
import { TeamMember, TeamPermissionLevel } from '../../types';
import { getMockTeamMember, getMockTeamMembers } from './__mocks__/teamMocks';
import { SelectOptionItem } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv';
const setup = (propOverrides?: object) => {
jest.mock('app/core/services/context_srv', () => ({
contextSrv: {
isGrafanaAdmin: false,
hasRole: role => false,
user: { id: 1 },
},
}));
const originalContextSrv = contextSrv;
interface SetupProps {
propOverrides?: object;
isGrafanaAdmin?: boolean;
isOrgAdmin?: boolean;
}
const setup = (setupProps: SetupProps) => {
const props: Props = {
members: [] as TeamMember[],
searchMemberQuery: '',
......@@ -15,9 +32,13 @@ const setup = (propOverrides?: object) => {
removeTeamMember: jest.fn(),
updateTeamMember: jest.fn(),
syncEnabled: false,
editorsCanAdmin: false,
};
Object.assign(props, propOverrides);
contextSrv.isGrafanaAdmin = setupProps.isGrafanaAdmin || false;
contextSrv.hasRole = role => setupProps.isOrgAdmin || false;
Object.assign(props, setupProps.propOverrides);
const wrapper = shallow(<TeamMembers {...props} />);
const instance = wrapper.instance() as TeamMembers;
......@@ -29,15 +50,22 @@ const setup = (propOverrides?: object) => {
};
describe('Render', () => {
beforeEach(() => {
contextSrv.isGrafanaAdmin = originalContextSrv.isGrafanaAdmin;
contextSrv.hasRole = originalContextSrv.hasRole;
});
it('should render component', () => {
const { wrapper } = setup();
const { wrapper } = setup({});
expect(wrapper).toMatchSnapshot();
});
it('should render team members', () => {
const { wrapper } = setup({
members: getMockTeamMembers(5),
propOverrides: {
members: getMockTeamMembers(5),
},
});
expect(wrapper).toMatchSnapshot();
......@@ -45,18 +73,58 @@ describe('Render', () => {
it('should render team members when sync enabled', () => {
const { wrapper } = setup({
members: getMockTeamMembers(5),
syncEnabled: true,
propOverrides: {
members: getMockTeamMembers(5),
syncEnabled: true,
},
});
expect(wrapper).toMatchSnapshot();
});
describe('when feature toggle editorsCanAdmin is turned on', () => {
it('should render permissions select if user is Grafana Admin', () => {
const members = getMockTeamMembers(5);
members[4].permission = TeamPermissionLevel.Admin;
const { wrapper } = setup({
propOverrides: { members, editorsCanAdmin: true },
isGrafanaAdmin: true,
isOrgAdmin: false,
});
expect(wrapper).toMatchSnapshot();
});
it('should render permissions select if user is Org Admin', () => {
const members = getMockTeamMembers(5);
members[4].permission = TeamPermissionLevel.Admin;
const { wrapper } = setup({
propOverrides: { members, editorsCanAdmin: true },
isGrafanaAdmin: false,
isOrgAdmin: true,
});
expect(wrapper).toMatchSnapshot();
});
it('should render permissions select if user is team admin', () => {
const members = getMockTeamMembers(5);
members[0].permission = TeamPermissionLevel.Admin;
const { wrapper } = setup({
propOverrides: { members, editorsCanAdmin: true },
isGrafanaAdmin: false,
isOrgAdmin: false,
});
expect(wrapper).toMatchSnapshot();
});
});
});
describe('Functions', () => {
describe('on search member query change', () => {
it('it should call setSearchMemberQuery', () => {
const { instance } = setup();
const { instance } = setup({});
instance.onSearchQueryChange('member');
......@@ -65,7 +133,7 @@ describe('Functions', () => {
});
describe('on remove member', () => {
const { instance } = setup();
const { instance } = setup({});
const mockTeamMember = getMockTeamMember();
instance.onRemoveMember(mockTeamMember);
......@@ -74,7 +142,7 @@ describe('Functions', () => {
});
describe('on add user to team', () => {
const { wrapper, instance } = setup();
const { wrapper, instance } = setup({});
const state = wrapper.state() as State;
state.newTeamMember = {
......@@ -90,7 +158,7 @@ describe('Functions', () => {
});
describe('on update permision for user in team', () => {
const { instance } = setup();
const { instance } = setup({});
const permission = TeamPermissionLevel.Admin;
const item: SelectOptionItem = { value: permission };
const member: TeamMember = {
......
......@@ -4,7 +4,7 @@ import SlideDown from 'app/core/components/Animations/SlideDown';
import { UserPicker } from 'app/core/components/Select/UserPicker';
import { DeleteButton, Select, SelectOptionItem } from '@grafana/ui';
import { TagBadge } from 'app/core/components/TagFilter/TagBadge';
import { TeamMember, User, teamsPermissionLevels } from 'app/types';
import { TeamMember, User, teamsPermissionLevels, TeamPermissionLevel, OrgRole } from 'app/types';
import {
loadTeamMembers,
addTeamMember,
......@@ -16,6 +16,7 @@ import { getSearchMemberQuery, getTeamMembers } from './state/selectors';
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
import { WithFeatureToggle } from 'app/core/components/WithFeatureToggle';
import { config } from 'app/core/config';
import { contextSrv } from 'app/core/services/context_srv';
export interface Props {
members: TeamMember[];
......@@ -26,6 +27,7 @@ export interface Props {
setSearchMemberQuery: typeof setSearchMemberQuery;
updateTeamMember: typeof updateTeamMember;
syncEnabled: boolean;
editorsCanAdmin?: boolean;
}
export interface State {
......@@ -37,6 +39,7 @@ export class TeamMembers extends PureComponent<Props, State> {
constructor(props) {
super(props);
this.state = { isAdding: false, newTeamMember: null };
this.renderPermissionsSelect = this.renderPermissionsSelect.bind(this);
}
componentDidMount() {
......@@ -85,6 +88,35 @@ export class TeamMembers extends PureComponent<Props, State> {
this.props.updateTeamMember(updatedTeamMember);
};
renderPermissionsSelect(member: TeamMember) {
const { members, editorsCanAdmin } = this.props;
const userInMembers = members.find(m => m.userId === contextSrv.user.id);
const isUserTeamAdmin =
contextSrv.isGrafanaAdmin || contextSrv.hasRole(OrgRole.Admin)
? true
: userInMembers && userInMembers.permission === TeamPermissionLevel.Admin;
const value = teamsPermissionLevels.find(dp => dp.value === member.permission);
return (
<WithFeatureToggle featureToggle={editorsCanAdmin}>
<td>
<div className="gf-form">
{isUserTeamAdmin && (
<Select
isSearchable={false}
options={teamsPermissionLevels}
onChange={item => this.onPermissionChange(item, member)}
className="gf-form-select-box__control--menu-right"
value={value}
/>
)}
{!isUserTeamAdmin && <span>{value.label}</span>}
</div>
</td>
</WithFeatureToggle>
);
}
renderMember(member: TeamMember, syncEnabled: boolean) {
return (
<tr key={member.userId}>
......@@ -93,19 +125,7 @@ export class TeamMembers extends PureComponent<Props, State> {
</td>
<td>{member.login}</td>
<td>{member.email}</td>
<WithFeatureToggle featureToggle={config.editorsCanAdmin}>
<td>
<div className="gf-form">
<Select
isSearchable={false}
options={teamsPermissionLevels}
onChange={item => this.onPermissionChange(item, member)}
className="gf-form-select-box__control--menu-right"
value={teamsPermissionLevels.find(dp => dp.value === member.permission)}
/>
</div>
</td>
</WithFeatureToggle>
{this.renderPermissionsSelect(member)}
{syncEnabled && this.renderLabels(member.labels)}
<td className="text-right">
<DeleteButton onConfirm={() => this.onRemoveMember(member)} />
......@@ -116,7 +136,7 @@ export class TeamMembers extends PureComponent<Props, State> {
render() {
const { isAdding } = this.state;
const { searchMemberQuery, members, syncEnabled } = this.props;
const { searchMemberQuery, members, syncEnabled, editorsCanAdmin } = this.props;
return (
<div>
<div className="page-action-bar">
......@@ -161,7 +181,7 @@ export class TeamMembers extends PureComponent<Props, State> {
<th />
<th>Name</th>
<th>Email</th>
<WithFeatureToggle featureToggle={config.editorsCanAdmin}>
<WithFeatureToggle featureToggle={editorsCanAdmin}>
<th>Permission</th>
</WithFeatureToggle>
{syncEnabled && <th />}
......@@ -180,6 +200,7 @@ function mapStateToProps(state) {
return {
members: getTeamMembers(state.team),
searchMemberQuery: getSearchMemberQuery(state.team),
editorsCanAdmin: config.editorsCanAdmin, // this makes the feature toggle mockable/controllable from tests,
};
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment