Merge remote-tracking branch 'upstream/master' into add_permissions_10676

This commit is contained in:
Daniel Lee
2018-02-01 14:02:14 +01:00
99 changed files with 2406 additions and 695 deletions

View File

@@ -6,41 +6,33 @@ import { shallow } from 'enzyme';
describe('AddPermissions', () => {
let wrapper;
let store;
let instance;
beforeAll(() => {
backendSrv.get.mockReturnValue(
Promise.resolve([
{ id: 2, dashboardId: 1, role: 'Viewer', permission: 1, permissionName: 'View' },
{ id: 3, dashboardId: 1, role: 'Editor', permission: 1, permissionName: 'Edit' },
{
id: 4,
dashboardId: 1,
userId: 2,
userLogin: 'danlimerick',
userEmail: 'dan.limerick@gmail.com',
permission: 4,
permissionName: 'Admin',
},
])
);
backendSrv.post = jest.fn();
const store = RootStore.create(
store = RootStore.create(
{},
{
backendSrv: backendSrv,
}
);
// wrapper = shallow(<Permissions backendSrv={backendSrv} isFolder={true} dashboardId={1} {...store} />);
wrapper = shallow(<AddPermissions permissions={store.permissions} backendSrv={backendSrv} dashboardId={1} />);
//<AddPermissions permissions={permissions} backendSrv={backendSrv} dashboardId={dashboardId} />
// return wrapper.instance().loadStore(1, true);
instance = wrapper.instance();
return store.permissions.load(1, true, false);
});
describe('when permission for a user is added', () => {
it('should save permission to db', async () => {
it('should save permission to db', () => {
const evt = {
target: {
value: 'User',
@@ -51,29 +43,48 @@ describe('AddPermissions', () => {
login: 'user2',
};
const instance = wrapper.instance();
instance.typeChanged(evt);
instance.userPicked(userItem);
wrapper.find('[data-save-permission]').simulate('click');
wrapper.update();
expect(wrapper.find('[data-save-permission]').prop('disabled')).toBe(false);
wrapper.find('form').simulate('submit', { preventDefault() {} });
expect(backendSrv.post.mock.calls.length).toBe(1);
expect(backendSrv.post.mock.calls[0][0]).toBe('/api/dashboards/id/1/acl');
});
});
// describe('when permission for team is added', () => {
// it('should save permission to db', () => {
// const teamItem = {
// id: 2,
// name: 'ug1',
// };
describe('when permission for team is added', () => {
it('should save permission to db', () => {
const evt = {
target: {
value: 'Group',
},
};
// wrapper
// .instance()
// .teamPicked(teamItem)
// .then(() => {
// expect(backendSrv.post.mock.calls.length).toBe(1);
// expect(backendSrv.post.mock.calls[0][0]).toBe('/api/dashboards/id/1/acl');
// });
// });
// });
const teamItem = {
id: 2,
name: 'ug1',
};
instance.typeChanged(evt);
instance.teamPicked(teamItem);
wrapper.update();
expect(wrapper.find('[data-save-permission]').prop('disabled')).toBe(false);
wrapper.find('form').simulate('submit', { preventDefault() {} });
expect(backendSrv.post.mock.calls.length).toBe(1);
expect(backendSrv.post.mock.calls[0][0]).toBe('/api/dashboards/id/1/acl');
});
});
afterEach(() => {
backendSrv.post.mockClear();
});
});

View File

@@ -46,8 +46,7 @@ class AddPermissions extends Component<IProps, any> {
permissions.newItem.setUser(null, null);
return;
}
permissions.newItem.setUser(user.id, user.login);
// return permissions.addStoreItem({ userId: user.id, userLogin: user.login, permission: 1 });
return permissions.newItem.setUser(user.id, user.login);
}
teamPicked(team: Team) {
@@ -56,17 +55,17 @@ class AddPermissions extends Component<IProps, any> {
permissions.newItem.setTeam(null, null);
return;
}
permissions.newItem.setTeam(team.id, team.name);
return permissions.newItem.setTeam(team.id, team.name);
}
permissionPicked(permission: OptionWithDescription) {
const { permissions } = this.props;
permissions.newItem.setPermission(permission.value);
return permissions.newItem.setPermission(permission.value);
}
resetNewType() {
const { permissions } = this.props;
permissions.resetNewType();
return permissions.resetNewType();
}
handleSubmit(evt) {
@@ -80,6 +79,8 @@ class AddPermissions extends Component<IProps, any> {
const newItem = permissions.newItem;
const pickerClassName = 'width-20';
const isValid = newItem.isValid();
return (
<div className="gf-form-inline cta-form">
<button className="cta-form__close btn btn-transparent" onClick={permissions.hideAddPermissions}>
@@ -135,7 +136,7 @@ class AddPermissions extends Component<IProps, any> {
</div>
<div className="gf-form">
<button data-save-permission className="btn btn-success" type="submit" disabled={!newItem.isValid()}>
<button data-save-permission className="btn btn-success" type="submit" disabled={!isValid}>
Save
</button>
</div>

View File

@@ -35,7 +35,7 @@ class DashboardPermissions extends Component<IProps, any> {
permissions={this.permissions}
isFolder={false}
dashboardId={dashboardId}
folderInfo={{ title: folderTitle, slug: folderSlug, id: folderId }}
folderInfo={{ title: folderTitle, slug: folderSlug, id: folderId }}
backendSrv={backendSrv}
/>
</div>

View File

@@ -1,4 +1,4 @@
import React, { Component } from 'react';
import React, { Component } from 'react';
import PermissionsList from './PermissionsList';
import { observer } from 'mobx-react';
import { FolderInfo } from './FolderInfo';
@@ -33,15 +33,15 @@ export interface IProps {
class Permissions extends Component<IProps, any> {
constructor(props) {
super(props);
const { dashboardId, isFolder } = this.props;
const { dashboardId, isFolder, folderInfo } = this.props;
this.permissionChanged = this.permissionChanged.bind(this);
this.typeChanged = this.typeChanged.bind(this);
this.removeItem = this.removeItem.bind(this);
this.loadStore(dashboardId, isFolder);
this.loadStore(dashboardId, isFolder, folderInfo && folderInfo.id === 0);
}
loadStore(dashboardId, isFolder) {
return this.props.permissions.load(dashboardId, isFolder);
loadStore(dashboardId, isFolder, isInRoot = false) {
return this.props.permissions.load(dashboardId, isFolder, isInRoot);
}
permissionChanged(index: number, permission: number, permissionName: string) {

View File

@@ -17,6 +17,8 @@ export default observer(({ item, removeItem, permissionChanged, itemIndex, folde
permissionChanged(itemIndex, permissionOption.value, permissionOption.label);
};
const inheritedFromRoot = item.dashboardId === -1 && folderInfo && folderInfo.id === 0;
return (
<tr className={setClassNameHelper(item.inherited)}>
<td style={{ width: '100%' }}>
@@ -24,14 +26,16 @@ export default observer(({ item, removeItem, permissionChanged, itemIndex, folde
<span dangerouslySetInnerHTML={{ __html: item.nameHtml }} />
</td>
<td>
{item.inherited && folderInfo ? (
<em className="muted no-wrap">
Inherited from folder{' '}
<a className="text-link" href={`dashboards/folder/${folderInfo.id}/${folderInfo.slug}/permissions`}>
{folderInfo.title}
</a>{' '}
</em>
) : null}
{item.inherited &&
folderInfo && (
<em className="muted no-wrap">
Inherited from folder{' '}
<a className="text-link" href={`dashboards/folder/${folderInfo.id}/${folderInfo.slug}/permissions`}>
{folderInfo.title}
</a>{' '}
</em>
)}
{inheritedFromRoot && <em className="muted no-wrap">Default Permission</em>}
</td>
<td className="query-keyword">Can</td>
<td>

View File

@@ -41,18 +41,12 @@ class DescriptionOption extends Component<IProps, any> {
onMouseEnter={this.handleMouseEnter}
onMouseMove={this.handleMouseMove}
title={option.title}
className={`user-picker-option__button btn btn-link ${className} width-19`}
style={{
whiteSpace: 'normal',
// height: '55px',
}}
className={`description-picker-option__button btn btn-link ${className} width-19`}
>
<div className="gf-form">{children}</div>
<div className="gf-form">
<div className="muted width-17">{option.description}</div>
{className.indexOf('is-selected') > -1 && (
<i style={{ paddingLeft: '2px' }} className="fa fa-check" aria-hidden="true" />
)}
{className.indexOf('is-selected') > -1 && <i className="fa fa-check" aria-hidden="true" />}
</div>
</button>
);

View File

@@ -71,6 +71,7 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
body.toggleClass('sidemenu-open', sidemenuOpen);
appEvents.on('toggle-sidemenu', () => {
sidemenuOpen = scope.contextSrv.sidemenu;
body.toggleClass('sidemenu-open');
});
@@ -167,6 +168,8 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
// mouse and keyboard is user activity
body.mousemove(userActivityDetected);
body.keydown(userActivityDetected);
// set useCapture = true to catch event here
document.addEventListener('wheel', userActivityDetected, true);
// treat tab change as activity
document.addEventListener('visibilitychange', userActivityDetected);

View File

@@ -111,7 +111,7 @@
buttonIcon: 'gicon gicon-dashboard-new',
buttonLink: 'dashboard/new?folderId={{ctrl.folderId}}',
buttonTitle: 'Create Dashboard',
proTip: 'Add dashboards into your folder at ->',
proTip: 'Add/move dashboards to your folder at ->',
proTipLink: 'dashboards',
proTipLinkTitle: 'Manage dashboards',
proTipTarget: ''