2018-01-11 10:47:39 +01:00
|
|
|
|
import React, { Component } from 'react';
|
|
|
|
|
|
import PermissionsList from './PermissionsList';
|
2018-01-11 18:14:56 +01:00
|
|
|
|
import { inject, observer } from 'mobx-react';
|
2018-01-17 16:13:45 +01:00
|
|
|
|
import UserPicker, { User } from 'app/core/components/UserPicker/UserPicker';
|
2018-01-17 16:52:18 +01:00
|
|
|
|
import TeamPicker, { Team } from 'app/core/components/UserPicker/TeamPicker';
|
2018-01-11 10:47:39 +01:00
|
|
|
|
|
|
|
|
|
|
export interface DashboardAcl {
|
|
|
|
|
|
id?: number;
|
|
|
|
|
|
dashboardId?: number;
|
|
|
|
|
|
userId?: number;
|
|
|
|
|
|
userLogin?: string;
|
|
|
|
|
|
userEmail?: string;
|
|
|
|
|
|
teamId?: number;
|
|
|
|
|
|
team?: string;
|
|
|
|
|
|
permission?: number;
|
|
|
|
|
|
permissionName?: string;
|
|
|
|
|
|
role?: string;
|
|
|
|
|
|
icon?: string;
|
|
|
|
|
|
nameHtml?: string;
|
|
|
|
|
|
inherited?: boolean;
|
|
|
|
|
|
sortName?: string;
|
|
|
|
|
|
sortRank?: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface IProps {
|
2018-01-16 11:28:14 +01:00
|
|
|
|
error: string;
|
|
|
|
|
|
newType: string;
|
2018-01-11 10:47:39 +01:00
|
|
|
|
dashboardId: number;
|
2018-01-17 09:24:35 +01:00
|
|
|
|
permissions?: any;
|
2018-01-16 11:28:14 +01:00
|
|
|
|
isFolder: boolean;
|
2018-01-17 16:13:45 +01:00
|
|
|
|
backendSrv: any;
|
2018-01-11 10:47:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-01-11 18:14:56 +01:00
|
|
|
|
@inject('permissions')
|
|
|
|
|
|
@observer
|
2018-01-17 09:29:58 +01:00
|
|
|
|
class Permissions extends Component<IProps, any> {
|
2018-01-11 18:14:56 +01:00
|
|
|
|
// TODO Remove Inner from Name when we get access via ReactContainer
|
2018-01-11 10:47:39 +01:00
|
|
|
|
dashboardId: any;
|
|
|
|
|
|
meta: any;
|
|
|
|
|
|
items: DashboardAcl[];
|
|
|
|
|
|
dummyItems: DashboardAcl[];
|
|
|
|
|
|
permissionOptions = [{ value: 1, text: 'View' }, { value: 2, text: 'Edit' }, { value: 4, text: 'Admin' }];
|
|
|
|
|
|
aclTypes = [
|
|
|
|
|
|
{ value: 'Group', text: 'Team' },
|
|
|
|
|
|
{ value: 'User', text: 'User' },
|
|
|
|
|
|
{ value: 'Viewer', text: 'Everyone With Viewer Role' },
|
|
|
|
|
|
{ value: 'Editor', text: 'Everyone With Editor Role' },
|
|
|
|
|
|
];
|
|
|
|
|
|
newType: string;
|
|
|
|
|
|
canUpdate: boolean;
|
|
|
|
|
|
error: string;
|
2018-01-17 16:13:45 +01:00
|
|
|
|
refreshList: any;
|
2018-01-11 10:47:39 +01:00
|
|
|
|
|
|
|
|
|
|
readonly duplicateError = 'This permission exists already.';
|
|
|
|
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
|
|
super(props);
|
2018-01-16 11:28:14 +01:00
|
|
|
|
const { dashboardId, permissions, isFolder } = this.props;
|
2018-01-11 10:47:39 +01:00
|
|
|
|
this.permissionChanged = this.permissionChanged.bind(this);
|
2018-01-11 18:14:56 +01:00
|
|
|
|
this.typeChanged = this.typeChanged.bind(this);
|
|
|
|
|
|
this.removeItem = this.removeItem.bind(this);
|
2018-01-15 21:12:46 +01:00
|
|
|
|
this.update = this.update.bind(this);
|
2018-01-17 16:13:45 +01:00
|
|
|
|
this.userPicked = this.userPicked.bind(this);
|
2018-01-17 16:52:18 +01:00
|
|
|
|
this.teamPicked = this.teamPicked.bind(this);
|
2018-01-16 11:28:14 +01:00
|
|
|
|
permissions.load(dashboardId, isFolder);
|
2018-01-11 10:47:39 +01:00
|
|
|
|
|
|
|
|
|
|
this.state = {
|
2018-01-11 18:14:56 +01:00
|
|
|
|
newType: 'Group',
|
2018-01-11 10:47:39 +01:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-01-15 21:12:46 +01:00
|
|
|
|
componentWillReceiveProps(nextProps) {
|
|
|
|
|
|
console.log('nextProps', nextProps);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
permissionChanged(index: number, permission: number, permissionName: string) {
|
|
|
|
|
|
const { permissions } = this.props;
|
|
|
|
|
|
permissions.updatePermissionOnIndex(index, permission, permissionName);
|
2018-01-11 10:47:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-01-15 21:12:46 +01:00
|
|
|
|
removeItem(index: number) {
|
2018-01-11 18:14:56 +01:00
|
|
|
|
const { permissions } = this.props;
|
|
|
|
|
|
permissions.removeStoreItem(index);
|
2018-01-11 10:47:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
update() {
|
2018-01-15 21:12:46 +01:00
|
|
|
|
const { permissions, dashboardId } = this.props;
|
|
|
|
|
|
permissions.update(dashboardId);
|
2018-01-11 18:14:56 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
resetNewType() {
|
|
|
|
|
|
this.setState(prevState => {
|
|
|
|
|
|
return {
|
2018-01-15 21:12:46 +01:00
|
|
|
|
...prevState,
|
2018-01-11 18:14:56 +01:00
|
|
|
|
newType: 'Group',
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
typeChanged(evt) {
|
|
|
|
|
|
const { value } = evt.target;
|
2018-01-16 09:45:22 +01:00
|
|
|
|
const { permissions, dashboardId } = this.props;
|
2018-01-15 21:12:46 +01:00
|
|
|
|
|
|
|
|
|
|
if (value === 'Viewer' || value === 'Editor') {
|
2018-01-16 09:45:22 +01:00
|
|
|
|
permissions.addStoreItem({ permission: 1, role: value, dashboardId: dashboardId }, dashboardId);
|
2018-01-15 21:12:46 +01:00
|
|
|
|
this.resetNewType();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-01-11 18:14:56 +01:00
|
|
|
|
this.setState(prevState => {
|
|
|
|
|
|
return {
|
|
|
|
|
|
...prevState,
|
|
|
|
|
|
newType: value,
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-01-17 16:13:45 +01:00
|
|
|
|
userPicked(user: User) {
|
|
|
|
|
|
const { permissions } = this.props;
|
|
|
|
|
|
permissions.addStoreItem({ userId: user.id, userLogin: user.login, permission: 1 });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-01-17 16:52:18 +01:00
|
|
|
|
teamPicked(team: Team) {
|
|
|
|
|
|
const { permissions } = this.props;
|
|
|
|
|
|
permissions.addStoreItem({ teamId: team.id, team: team.name, permission: 1 });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-01-11 18:14:56 +01:00
|
|
|
|
render() {
|
2018-01-17 09:29:58 +01:00
|
|
|
|
console.log('Permissions render');
|
2018-01-17 16:13:45 +01:00
|
|
|
|
const { error, permissions, backendSrv } = this.props;
|
2018-01-11 18:14:56 +01:00
|
|
|
|
const { newType } = this.state;
|
2018-01-11 10:47:39 +01:00
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className="gf-form-group">
|
|
|
|
|
|
<PermissionsList
|
2018-01-15 21:12:46 +01:00
|
|
|
|
permissions={permissions.items}
|
2018-01-11 10:47:39 +01:00
|
|
|
|
permissionsOptions={this.permissionOptions}
|
|
|
|
|
|
removeItem={this.removeItem}
|
|
|
|
|
|
permissionChanged={this.permissionChanged}
|
2018-01-15 21:12:46 +01:00
|
|
|
|
fetching={permissions.fetching}
|
2018-01-11 10:47:39 +01:00
|
|
|
|
/>
|
|
|
|
|
|
<div className="gf-form-inline">
|
|
|
|
|
|
<form name="addPermission" className="gf-form-group">
|
|
|
|
|
|
<h6 className="muted">Add Permission For</h6>
|
|
|
|
|
|
<div className="gf-form-inline">
|
|
|
|
|
|
<div className="gf-form">
|
|
|
|
|
|
<div className="gf-form-select-wrapper">
|
2018-01-15 21:12:46 +01:00
|
|
|
|
<select className="gf-form-input gf-size-auto" value={newType} onChange={this.typeChanged}>
|
2018-01-16 11:28:14 +01:00
|
|
|
|
{this.aclTypes.map((option, idx) => {
|
2018-01-11 10:47:39 +01:00
|
|
|
|
return (
|
|
|
|
|
|
<option key={idx} value={option.value}>
|
|
|
|
|
|
{option.text}
|
|
|
|
|
|
</option>
|
|
|
|
|
|
);
|
|
|
|
|
|
})}
|
|
|
|
|
|
</select>
|
|
|
|
|
|
|
|
|
|
|
|
{/* <select
|
|
|
|
|
|
className="gf-form-input gf-size-auto"
|
|
|
|
|
|
ng-model="ctrl.newType"
|
|
|
|
|
|
ng-options="p.value as p.text for p in ctrl.aclTypes"
|
|
|
|
|
|
ng-change="ctrl.typeChanged()"
|
|
|
|
|
|
/> */}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2018-01-17 16:13:45 +01:00
|
|
|
|
|
2018-01-11 10:47:39 +01:00
|
|
|
|
{newType === 'User' ? (
|
|
|
|
|
|
<div className="gf-form">
|
2018-01-17 16:13:45 +01:00
|
|
|
|
{/* <user-picker user-picked="ctrl.userPicked($user)" />
|
2018-01-15 21:12:46 +01:00
|
|
|
|
<select-user-picker
|
|
|
|
|
|
backendSrv="ctrl.backendSrv"
|
|
|
|
|
|
teamId="ctrl.$routeParams.id"
|
|
|
|
|
|
refreshList="ctrl.get"
|
|
|
|
|
|
teamMembers="ctrl.teamMembers"
|
2018-01-17 16:13:45 +01:00
|
|
|
|
/> */}
|
2018-01-17 16:52:18 +01:00
|
|
|
|
<UserPicker backendSrv={backendSrv} handlePicked={this.userPicked} />
|
2018-01-11 10:47:39 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
|
|
|
|
|
|
{newType === 'Group' ? (
|
|
|
|
|
|
<div className="gf-form">
|
2018-01-17 16:52:18 +01:00
|
|
|
|
<TeamPicker backendSrv={backendSrv} handlePicked={this.teamPicked} />
|
2018-01-11 10:47:39 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
{error ? (
|
|
|
|
|
|
<div className="gf-form width-17">
|
|
|
|
|
|
<span ng-if="ctrl.error" className="text-error p-l-1">
|
|
|
|
|
|
<i className="fa fa-warning" />
|
|
|
|
|
|
{error}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div className="gf-form-button-row">
|
2018-01-11 18:14:56 +01:00
|
|
|
|
<button type="button" className="btn btn-danger" onClick={this.update} disabled={!permissions.canUpdate}>
|
2018-01-11 10:47:39 +01:00
|
|
|
|
Update Permissions
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
2018-01-18 10:12:11 +01:00
|
|
|
|
<div className="empty-list-cta m-t-3">
|
|
|
|
|
|
<div className="grafana-info-box">
|
|
|
|
|
|
<h5>What are Permissions?</h5>
|
|
|
|
|
|
<p>
|
|
|
|
|
|
An Access Control List (ACL) model is used for to limit access to Dashboard Folders. A user or a Team can
|
|
|
|
|
|
be assigned permissions for a folder or for a single dashboard.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>The permissions that can be assigned for a folder/dashboard are:</p>
|
|
|
|
|
|
<p>View, Edit and Admin.</p>
|
|
|
|
|
|
Checkout the{' '}
|
|
|
|
|
|
<a className="external-link" target="_blank" href="http://docs.grafana.org/reference/dashboard_folders/">
|
|
|
|
|
|
Dashboard Folders documentation
|
|
|
|
|
|
</a>{' '}
|
|
|
|
|
|
for more information.
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2018-01-11 10:47:39 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default Permissions;
|