mirror of
https://github.com/grafana/grafana.git
synced 2025-01-19 13:03:32 -06:00
dashfolder: wip: More wip on acl.html2permissions.tsx #10275
This commit is contained in:
parent
7616cfb5f0
commit
c8193e10b9
@ -91,7 +91,7 @@
|
||||
"typescript": "^2.6.2",
|
||||
"webpack": "^3.10.0",
|
||||
"webpack-bundle-analyzer": "^2.9.0",
|
||||
"webpack-cleanup-plugin": "^0.5.1",
|
||||
"webpack-cleanup-plugin": "^0.5.1",
|
||||
"webpack-merge": "^4.1.0",
|
||||
"zone.js": "^0.7.2"
|
||||
},
|
||||
@ -140,6 +140,7 @@
|
||||
"lodash": "^4.17.4",
|
||||
"mobx": "^3.4.1",
|
||||
"mobx-react": "^4.3.5",
|
||||
"mobx-react-devtools": "^4.2.15",
|
||||
"mobx-state-tree": "^1.3.1",
|
||||
"moment": "^2.18.1",
|
||||
"mousetrap": "^1.6.0",
|
||||
@ -148,8 +149,8 @@
|
||||
"react": "^16.2.0",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-grid-layout": "^0.16.2",
|
||||
"react-popper": "^0.7.5",
|
||||
"react-highlight-words": "^0.10.0",
|
||||
"react-popper": "^0.7.5",
|
||||
"react-select": "^1.1.0",
|
||||
"react-sizeme": "^2.3.6",
|
||||
"remarkable": "^1.7.1",
|
||||
|
@ -1,6 +1,10 @@
|
||||
import React, { Component } from 'react';
|
||||
import PermissionsList from './PermissionsList';
|
||||
import _ from 'lodash';
|
||||
import DevTools from 'mobx-react-devtools';
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import { Provider } from 'mobx-react';
|
||||
import { store } from 'app/stores/store';
|
||||
|
||||
export interface DashboardAcl {
|
||||
id?: number;
|
||||
@ -24,12 +28,25 @@ export interface IProps {
|
||||
error: any;
|
||||
newType: any;
|
||||
aclTypes: any;
|
||||
typeChanged: any;
|
||||
backendSrv: any;
|
||||
dashboardId: number;
|
||||
permissions: any;
|
||||
}
|
||||
|
||||
class Permissions extends Component<IProps, any> {
|
||||
render() {
|
||||
return (
|
||||
<Provider {...store}>
|
||||
<PermissionsInner {...this.props} />
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@inject('permissions')
|
||||
@observer
|
||||
class PermissionsInner extends Component<IProps, any> {
|
||||
// TODO Remove Inner from Name when we get access via ReactContainer
|
||||
dashboardId: any;
|
||||
meta: any;
|
||||
items: DashboardAcl[];
|
||||
@ -50,58 +67,34 @@ class Permissions extends Component<IProps, any> {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.dashboardId = this.props.dashboardId;
|
||||
this.backendSrv = this.props.backendSrv;
|
||||
|
||||
const { dashboardId, backendSrv, permissions } = this.props;
|
||||
|
||||
this.dashboardId = dashboardId;
|
||||
this.backendSrv = backendSrv;
|
||||
this.permissionChanged = this.permissionChanged.bind(this);
|
||||
console.log('this.setState', this.setState);
|
||||
this.typeChanged = this.typeChanged.bind(this);
|
||||
this.removeItem = this.removeItem.bind(this);
|
||||
permissions.load(this.dashboardId);
|
||||
|
||||
this.state = {
|
||||
items: [],
|
||||
newType: '',
|
||||
newType: 'Group',
|
||||
canUpdate: false,
|
||||
error: '',
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.getAcl(this.props.dashboardId);
|
||||
}
|
||||
|
||||
getAcl(dashboardId: number) {
|
||||
return this.backendSrv.get(`/api/dashboards/id/${dashboardId}/acl`).then(result => {
|
||||
console.log('this', this.setState);
|
||||
const items = result.map(this.prepareViewModel.bind(this));
|
||||
// this.items = _.map(result, this.prepareViewModel.bind(this));
|
||||
this.setState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
items: this.sortItems(items),
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
sortItems(items) {
|
||||
return _.orderBy(items, ['sortRank', 'sortName'], ['desc', 'asc']);
|
||||
}
|
||||
|
||||
permissionChanged() {
|
||||
this.setState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
canUpdate: true,
|
||||
};
|
||||
});
|
||||
permissionChanged(evt) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
removeItem(index) {
|
||||
this.setState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
items: this.state.items.splice(index, 1),
|
||||
canUpdate: true,
|
||||
};
|
||||
});
|
||||
const { permissions } = this.props;
|
||||
permissions.removeStoreItem(index);
|
||||
}
|
||||
|
||||
update() {
|
||||
@ -168,29 +161,91 @@ class Permissions extends Component<IProps, any> {
|
||||
return item;
|
||||
}
|
||||
|
||||
// componentWillUpdate(nextProps, nextState) {
|
||||
// console.log('nextProps', nextProps);
|
||||
// console.log('nextState', nextState);
|
||||
// }
|
||||
isDuplicate(origItem, newItem) {
|
||||
if (origItem.inherited) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// componentWillReceiveProps(nextProps) {
|
||||
// console.log('nextPropzzzz', nextProps);
|
||||
// }
|
||||
return (
|
||||
(origItem.role && newItem.role && origItem.role === newItem.role) ||
|
||||
(origItem.userId && newItem.userId && origItem.userId === newItem.userId) ||
|
||||
(origItem.teamId && newItem.teamId && origItem.teamId === newItem.teamId)
|
||||
);
|
||||
}
|
||||
|
||||
isValid(item) {
|
||||
const dupe = _.find(this.items, it => {
|
||||
return this.isDuplicate(it, item);
|
||||
});
|
||||
|
||||
if (dupe) {
|
||||
this.error = this.duplicateError;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
addNewItem(item) {
|
||||
if (!this.isValid(item)) {
|
||||
return;
|
||||
}
|
||||
this.error = '';
|
||||
|
||||
item.dashboardId = this.dashboardId;
|
||||
|
||||
let newItems = this.state.items;
|
||||
newItems.push(this.prepareViewModel(item));
|
||||
|
||||
this.setState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
items: this.sortItems(newItems),
|
||||
canUpdate: true,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
resetNewType() {
|
||||
this.setState(prevState => {
|
||||
return {
|
||||
newType: 'Group',
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
typeChanged(evt) {
|
||||
const { value } = evt.target;
|
||||
this.setState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
newType: value,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
typeChanged___() {
|
||||
const { newType } = this.state;
|
||||
if (newType === 'Viewer' || newType === 'Editor') {
|
||||
this.addNewItem({ permission: 1, role: newType });
|
||||
this.resetNewType();
|
||||
this.setState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
canUpdate: true,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { error, newType, aclTypes, typeChanged } = this.props;
|
||||
|
||||
const { items, canUpdate } = this.state;
|
||||
|
||||
const handleTypeChange = () => {
|
||||
typeChanged();
|
||||
};
|
||||
const { error, aclTypes, permissions } = this.props;
|
||||
const { newType } = this.state;
|
||||
|
||||
return (
|
||||
<div className="gf-form-group">
|
||||
asd
|
||||
<PermissionsList
|
||||
permissions={items}
|
||||
permissions={permissions.items.toJS()}
|
||||
permissionsOptions={this.permissionOptions}
|
||||
removeItem={this.removeItem}
|
||||
permissionChanged={this.permissionChanged}
|
||||
@ -202,7 +257,7 @@ class Permissions extends Component<IProps, any> {
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<div className="gf-form-select-wrapper">
|
||||
<select className="gf-form-input gf-size-auto" onChange={handleTypeChange}>
|
||||
<select className="gf-form-input gf-size-auto" onChange={this.typeChanged}>
|
||||
{aclTypes.map((option, idx) => {
|
||||
return (
|
||||
<option key={idx} value={option.value}>
|
||||
@ -222,12 +277,16 @@ class Permissions extends Component<IProps, any> {
|
||||
</div>
|
||||
{newType === 'User' ? (
|
||||
<div className="gf-form">
|
||||
{' '}
|
||||
User picker
|
||||
<user-picker user-picked="ctrl.userPicked($user)" />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{newType === 'Group' ? (
|
||||
<div className="gf-form">
|
||||
{' '}
|
||||
Team picker
|
||||
<team-picker team-picked="ctrl.groupPicked($group)" />
|
||||
</div>
|
||||
) : null}
|
||||
@ -243,11 +302,12 @@ class Permissions extends Component<IProps, any> {
|
||||
) : null}
|
||||
</div>
|
||||
<div className="gf-form-button-row">
|
||||
<button type="button" className="btn btn-danger" onClick={this.update} disabled={!canUpdate}>
|
||||
<button type="button" className="btn btn-danger" onClick={this.update} disabled={!permissions.canUpdate}>
|
||||
Update Permissions
|
||||
</button>
|
||||
</div>
|
||||
asd3
|
||||
<DevTools />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -9,18 +9,8 @@ export interface IProps {
|
||||
}
|
||||
|
||||
class PermissionsList extends Component<IProps, any> {
|
||||
// componentWillUpdate(nextProps, nextState) {
|
||||
// console.log('nextProps', nextProps);
|
||||
// console.log('nextState', nextState);
|
||||
// }
|
||||
|
||||
// componentWillReceiveProps(nextProps) {
|
||||
// console.log('nextPropzzzz', nextProps);
|
||||
// }
|
||||
|
||||
render() {
|
||||
const { permissions, permissionsOptions, removeItem, permissionChanged } = this.props;
|
||||
|
||||
return (
|
||||
<table className="filter-table gf-form-group">
|
||||
<tbody>
|
||||
|
@ -12,7 +12,7 @@ export default ({ item, permissionsOptions, removeItem, permissionChanged, itemI
|
||||
|
||||
const handleChangePermission = evt => {
|
||||
evt.preventDefault();
|
||||
permissionChanged();
|
||||
permissionChanged(itemIndex, evt.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -6,21 +6,6 @@
|
||||
dashboardId="ctrl.dashboard.id"
|
||||
backendSrv="ctrl.backendSrv" />
|
||||
|
||||
|
||||
<per m i s sions
|
||||
permissions="{{ctrl.dummyItems}}"
|
||||
permissionsOptions="{{ctrl.permissionOptions}}"
|
||||
removeItem="ctrl.removeItem"
|
||||
permissionChanged="ctrl.permissionChanged"
|
||||
error="{{ctrl.error}}"
|
||||
newType="ctrl.newType"
|
||||
aclTypes="{{ctrl.aclTypes}}"
|
||||
typeChanged="ctrl.typeChanged"
|
||||
dashboardId="ctrl.dashboard.id"
|
||||
backendSrv="ctrl.backendSrv"/>
|
||||
|
||||
|
||||
|
||||
<div class="gf-form-group">
|
||||
<table class="filter-table gf-form-group">
|
||||
<tr ng-repeat="acl in ctrl.items" ng-class="{'gf-form-disabled': acl.inherited}">
|
||||
|
74
public/app/stores/PermissionsStore/PermissionsStore.ts
Normal file
74
public/app/stores/PermissionsStore/PermissionsStore.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { types, getEnv, flow } from 'mobx-state-tree';
|
||||
import { PermissionsStoreItem } from './PermissionsStoreItem';
|
||||
|
||||
export const PermissionsStore = types
|
||||
.model('PermissionsStore', {
|
||||
fetching: types.boolean,
|
||||
canUpdate: types.boolean,
|
||||
items: types.optional(types.array(PermissionsStoreItem), []),
|
||||
originalItems: types.optional(types.array(PermissionsStoreItem), []),
|
||||
})
|
||||
// .views(self => ({
|
||||
// canUpdate: () => {
|
||||
// const itemsSnapshot = getSnapshot(self.items);
|
||||
// const originalItemsSnapshot = getSnapshot(self.originalItems);
|
||||
// console.log('itemsSnapshot', itemsSnapshot);
|
||||
// console.log('editItemsSnapshot', originalItemsSnapshot);
|
||||
// return true;
|
||||
// }
|
||||
// }))
|
||||
.actions(self => ({
|
||||
load: flow(function* load(dashboardId: number) {
|
||||
self.fetching = true;
|
||||
const backendSrv = getEnv(self).backendSrv;
|
||||
const res = yield backendSrv.get(`/api/dashboards/id/${dashboardId}/acl`);
|
||||
const items = prepareServerResponse(res, dashboardId);
|
||||
self.items = items;
|
||||
self.originalItems = items;
|
||||
self.fetching = false;
|
||||
}),
|
||||
addStoreItem: () => {
|
||||
self.canUpdate = true;
|
||||
},
|
||||
removeStoreItem: idx => {
|
||||
self.items.splice(idx, 1);
|
||||
self.canUpdate = true;
|
||||
},
|
||||
}));
|
||||
|
||||
const prepareServerResponse = (response, dashboardId: number) => {
|
||||
return response.map(item => {
|
||||
// TODO: this.meta
|
||||
// item.inherited = !this.meta.isFolder && this.dashboardId !== item.dashboardId;
|
||||
item.inherited = dashboardId !== item.dashboardId;
|
||||
item.sortRank = 0;
|
||||
if (item.userId > 0) {
|
||||
item.icon = 'fa fa-fw fa-user';
|
||||
// item.nameHtml = this.$sce.trustAsHtml(item.userLogin);
|
||||
item.nameHtml = item.userLogin;
|
||||
item.sortName = item.userLogin;
|
||||
item.sortRank = 10;
|
||||
} else if (item.teamId > 0) {
|
||||
item.icon = 'fa fa-fw fa-users';
|
||||
// item.nameHtml = this.$sce.trustAsHtml(item.team);
|
||||
item.nameHtml = item.team;
|
||||
item.sortName = item.team;
|
||||
item.sortRank = 20;
|
||||
} else if (item.role) {
|
||||
item.icon = 'fa fa-fw fa-street-view';
|
||||
// item.nameHtml = this.$sce.trustAsHtml(`Everyone with <span class="query-keyword">${item.role}</span> Role`);
|
||||
item.nameHtml = `Everyone with <span class="query-keyword">${item.role}</span> Role`;
|
||||
item.sortName = item.role;
|
||||
item.sortRank = 30;
|
||||
if (item.role === 'Viewer') {
|
||||
item.sortRank += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.inherited) {
|
||||
item.sortRank += 100;
|
||||
}
|
||||
|
||||
return item;
|
||||
});
|
||||
};
|
25
public/app/stores/PermissionsStore/PermissionsStoreItem.ts
Normal file
25
public/app/stores/PermissionsStore/PermissionsStoreItem.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { types } from 'mobx-state-tree';
|
||||
|
||||
export const PermissionsStoreItem = types
|
||||
.model('PermissionsStoreItem', {
|
||||
dashboardId: types.number,
|
||||
id: types.number,
|
||||
permission: types.number,
|
||||
permissionName: types.string,
|
||||
role: types.maybe(types.string),
|
||||
team: types.string,
|
||||
teamId: types.number,
|
||||
userEmail: types.string,
|
||||
userId: types.number,
|
||||
userLogin: types.string,
|
||||
inherited: types.maybe(types.boolean),
|
||||
sortRank: types.maybe(types.number),
|
||||
icon: types.maybe(types.string),
|
||||
nameHtml: types.maybe(types.string),
|
||||
sortName: types.maybe(types.string),
|
||||
})
|
||||
.actions(self => ({
|
||||
updateRole: role => {
|
||||
self.role = role;
|
||||
},
|
||||
}));
|
@ -5,6 +5,7 @@ import { NavStore } from './../NavStore/NavStore';
|
||||
import { AlertListStore } from './../AlertListStore/AlertListStore';
|
||||
import { ViewStore } from './../ViewStore/ViewStore';
|
||||
import { FolderStore } from './../FolderStore/FolderStore';
|
||||
import { PermissionsStore } from './../PermissionsStore/PermissionsStore';
|
||||
|
||||
export const RootStore = types.model({
|
||||
search: types.optional(SearchStore, {
|
||||
@ -17,6 +18,11 @@ export const RootStore = types.model({
|
||||
alertList: types.optional(AlertListStore, {
|
||||
rules: [],
|
||||
}),
|
||||
permissions: types.optional(PermissionsStore, {
|
||||
fetching: false,
|
||||
canUpdate: false,
|
||||
items: [],
|
||||
}),
|
||||
view: types.optional(ViewStore, {
|
||||
path: '',
|
||||
query: {},
|
||||
|
@ -6467,6 +6467,10 @@ mkdirp@0.5.1, mkdirp@0.x.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdi
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
mobx-react-devtools@^4.2.15:
|
||||
version "4.2.15"
|
||||
resolved "https://registry.yarnpkg.com/mobx-react-devtools/-/mobx-react-devtools-4.2.15.tgz#881c038fb83db4dffd1e72bbaf5374d26b2fdebb"
|
||||
|
||||
mobx-react@^4.3.5:
|
||||
version "4.3.5"
|
||||
resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-4.3.5.tgz#76853f2f2ef4a6f960c374bcd9f01e875929c04c"
|
||||
|
Loading…
Reference in New Issue
Block a user