Commit 8c34f595 by Hugo Häggmark Committed by Leonard Gram

teams: disable new team button if user is viewer

parent e3fc61b3
import React from 'react'; import React from 'react';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import { Props, TeamList } from './TeamList'; import { Props, TeamList } from './TeamList';
import { NavModel, Team } from '../../types'; import { NavModel, Team, OrgRole } from '../../types';
import { getMockTeam, getMultipleMockTeams } from './__mocks__/teamMocks'; import { getMockTeam, getMultipleMockTeams } from './__mocks__/teamMocks';
import { User } from 'app/core/services/context_srv';
const setup = (propOverrides?: object) => { const setup = (propOverrides?: object) => {
const props: Props = { const props: Props = {
...@@ -21,6 +22,11 @@ const setup = (propOverrides?: object) => { ...@@ -21,6 +22,11 @@ const setup = (propOverrides?: object) => {
searchQuery: '', searchQuery: '',
teamsCount: 0, teamsCount: 0,
hasFetched: false, hasFetched: false,
editorsCanAdmin: false,
signedInUser: {
id: 1,
orgRole: OrgRole.Viewer,
} as User,
}; };
Object.assign(props, propOverrides); Object.assign(props, propOverrides);
...@@ -49,6 +55,42 @@ describe('Render', () => { ...@@ -49,6 +55,42 @@ describe('Render', () => {
expect(wrapper).toMatchSnapshot(); expect(wrapper).toMatchSnapshot();
}); });
describe('when feature toggle editorsCanAdmin is turned on', () => {
describe('and signedin user is not viewer', () => {
it('should enable the new team button', () => {
const { wrapper } = setup({
teams: getMultipleMockTeams(1),
teamsCount: 1,
hasFetched: true,
editorsCanAdmin: true,
signedInUser: {
id: 1,
orgRole: OrgRole.Editor,
} as User,
});
expect(wrapper).toMatchSnapshot();
});
});
describe('and signedin user is a viewer', () => {
it('should disable the new team button', () => {
const { wrapper } = setup({
teams: getMultipleMockTeams(1),
teamsCount: 1,
hasFetched: true,
editorsCanAdmin: true,
signedInUser: {
id: 1,
orgRole: OrgRole.Viewer,
} as User,
});
expect(wrapper).toMatchSnapshot();
});
});
});
}); });
describe('Life cycle', () => { describe('Life cycle', () => {
......
...@@ -4,11 +4,13 @@ import { hot } from 'react-hot-loader'; ...@@ -4,11 +4,13 @@ import { hot } from 'react-hot-loader';
import Page from 'app/core/components/Page/Page'; import Page from 'app/core/components/Page/Page';
import { DeleteButton } from '@grafana/ui'; import { DeleteButton } from '@grafana/ui';
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA'; import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
import { NavModel, Team } from 'app/types'; import { NavModel, Team, OrgRole } from 'app/types';
import { loadTeams, deleteTeam, setSearchQuery } from './state/actions'; import { loadTeams, deleteTeam, setSearchQuery } from './state/actions';
import { getSearchQuery, getTeams, getTeamsCount } from './state/selectors'; import { getSearchQuery, getTeams, getTeamsCount } from './state/selectors';
import { getNavModel } from 'app/core/selectors/navModel'; import { getNavModel } from 'app/core/selectors/navModel';
import { FilterInput } from 'app/core/components/FilterInput/FilterInput'; import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
import { config } from 'app/core/config';
import { contextSrv, User } from 'app/core/services/context_srv';
export interface Props { export interface Props {
navModel: NavModel; navModel: NavModel;
...@@ -19,6 +21,8 @@ export interface Props { ...@@ -19,6 +21,8 @@ export interface Props {
loadTeams: typeof loadTeams; loadTeams: typeof loadTeams;
deleteTeam: typeof deleteTeam; deleteTeam: typeof deleteTeam;
setSearchQuery: typeof setSearchQuery; setSearchQuery: typeof setSearchQuery;
editorsCanAdmin?: boolean;
signedInUser?: User;
} }
export class TeamList extends PureComponent<Props, any> { export class TeamList extends PureComponent<Props, any> {
...@@ -84,7 +88,8 @@ export class TeamList extends PureComponent<Props, any> { ...@@ -84,7 +88,8 @@ export class TeamList extends PureComponent<Props, any> {
} }
renderTeamList() { renderTeamList() {
const { teams, searchQuery } = this.props; const { teams, searchQuery, editorsCanAdmin, signedInUser } = this.props;
const disabledClass = editorsCanAdmin && signedInUser.orgRole === OrgRole.Viewer ? ' disabled' : '';
return ( return (
<> <>
...@@ -101,7 +106,7 @@ export class TeamList extends PureComponent<Props, any> { ...@@ -101,7 +106,7 @@ export class TeamList extends PureComponent<Props, any> {
<div className="page-action-bar__spacer" /> <div className="page-action-bar__spacer" />
<a className="btn btn-primary" href="org/teams/new"> <a className={`btn btn-primary${disabledClass}`} href="org/teams/new">
New team New team
</a> </a>
</div> </div>
...@@ -152,6 +157,8 @@ function mapStateToProps(state) { ...@@ -152,6 +157,8 @@ function mapStateToProps(state) {
searchQuery: getSearchQuery(state.teams), searchQuery: getSearchQuery(state.teams),
teamsCount: getTeamsCount(state.teams), teamsCount: getTeamsCount(state.teams),
hasFetched: state.teams.hasFetched, hasFetched: state.teams.hasFetched,
editorsCanAdmin: config.editorsCanAdmin, // this makes the feature toggle mockable/controllable from tests,
signedInUser: contextSrv.user, // this makes the feature toggle mockable/controllable from tests,
}; };
} }
......
...@@ -343,3 +343,253 @@ exports[`Render should render teams table 1`] = ` ...@@ -343,3 +343,253 @@ exports[`Render should render teams table 1`] = `
</PageContents> </PageContents>
</Page> </Page>
`; `;
exports[`Render when feature toggle editorsCanAdmin is turned on and signedin user is a viewer should disable the new team button 1`] = `
<Page
navModel={
Object {
"main": Object {
"text": "Configuration",
},
"node": Object {
"text": "Team List",
},
}
}
>
<PageContents
isLoading={false}
>
<div
className="page-action-bar"
>
<div
className="gf-form gf-form--grow"
>
<ForwardRef
inputClassName="gf-form-input"
labelClassName="gf-form--has-input-icon gf-form--grow"
onChange={[Function]}
placeholder="Search teams"
value=""
/>
</div>
<div
className="page-action-bar__spacer"
/>
<a
className="btn btn-primary disabled"
href="org/teams/new"
>
New team
</a>
</div>
<div
className="admin-list-table"
>
<table
className="filter-table filter-table--hover form-inline"
>
<thead>
<tr>
<th />
<th>
Name
</th>
<th>
Email
</th>
<th>
Members
</th>
<th
style={
Object {
"width": "1%",
}
}
/>
</tr>
</thead>
<tbody>
<tr
key="1"
>
<td
className="width-4 text-center link-td"
>
<a
href="org/teams/edit/1"
>
<img
className="filter-table__avatar"
src="some/url/"
/>
</a>
</td>
<td
className="link-td"
>
<a
href="org/teams/edit/1"
>
test-1
</a>
</td>
<td
className="link-td"
>
<a
href="org/teams/edit/1"
>
test-1@test.com
</a>
</td>
<td
className="link-td"
>
<a
href="org/teams/edit/1"
>
1
</a>
</td>
<td
className="text-right"
>
<DeleteButton
onConfirm={[Function]}
/>
</td>
</tr>
</tbody>
</table>
</div>
</PageContents>
</Page>
`;
exports[`Render when feature toggle editorsCanAdmin is turned on and signedin user is not viewer should enable the new team button 1`] = `
<Page
navModel={
Object {
"main": Object {
"text": "Configuration",
},
"node": Object {
"text": "Team List",
},
}
}
>
<PageContents
isLoading={false}
>
<div
className="page-action-bar"
>
<div
className="gf-form gf-form--grow"
>
<ForwardRef
inputClassName="gf-form-input"
labelClassName="gf-form--has-input-icon gf-form--grow"
onChange={[Function]}
placeholder="Search teams"
value=""
/>
</div>
<div
className="page-action-bar__spacer"
/>
<a
className="btn btn-primary"
href="org/teams/new"
>
New team
</a>
</div>
<div
className="admin-list-table"
>
<table
className="filter-table filter-table--hover form-inline"
>
<thead>
<tr>
<th />
<th>
Name
</th>
<th>
Email
</th>
<th>
Members
</th>
<th
style={
Object {
"width": "1%",
}
}
/>
</tr>
</thead>
<tbody>
<tr
key="1"
>
<td
className="width-4 text-center link-td"
>
<a
href="org/teams/edit/1"
>
<img
className="filter-table__avatar"
src="some/url/"
/>
</a>
</td>
<td
className="link-td"
>
<a
href="org/teams/edit/1"
>
test-1
</a>
</td>
<td
className="link-td"
>
<a
href="org/teams/edit/1"
>
test-1@test.com
</a>
</td>
<td
className="link-td"
>
<a
href="org/teams/edit/1"
>
1
</a>
</td>
<td
className="text-right"
>
<DeleteButton
onConfirm={[Function]}
/>
</td>
</tr>
</tbody>
</table>
</div>
</PageContents>
</Page>
`;
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