From 44ea8e58e2520e5da58228dbcb11b3a65dfb37db Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Mon, 15 Jan 2018 21:12:46 +0100 Subject: [PATCH] wip: More on the permissions. Left are team picker and user picker, tests and error messages #10275 --- .../components/Permissions/Permissions.tsx | 164 ++++-------------- .../Permissions/PermissionsList.tsx | 18 +- .../Permissions/PermissionsListItem.tsx | 10 +- .../PermissionsStore/PermissionsStore.ts | 149 +++++++++++----- .../PermissionsStore/PermissionsStoreItem.ts | 20 ++- 5 files changed, 174 insertions(+), 187 deletions(-) diff --git a/public/app/core/components/Permissions/Permissions.tsx b/public/app/core/components/Permissions/Permissions.tsx index 0109bd5ddf6..cf779210000 100644 --- a/public/app/core/components/Permissions/Permissions.tsx +++ b/public/app/core/components/Permissions/Permissions.tsx @@ -5,6 +5,7 @@ import DevTools from 'mobx-react-devtools'; import { inject, observer } from 'mobx-react'; import { Provider } from 'mobx-react'; import { store } from 'app/stores/store'; +import UserPicker from 'app/core/components/UserPicker/UserPicker'; export interface DashboardAcl { id?: number; @@ -75,140 +76,42 @@ class PermissionsInner extends Component { this.permissionChanged = this.permissionChanged.bind(this); this.typeChanged = this.typeChanged.bind(this); this.removeItem = this.removeItem.bind(this); + this.update = this.update.bind(this); permissions.load(this.dashboardId); this.state = { newType: 'Group', - canUpdate: false, - error: '', }; } + componentWillReceiveProps(nextProps) { + console.log('nextProps', nextProps); + } + sortItems(items) { return _.orderBy(items, ['sortRank', 'sortName'], ['desc', 'asc']); } - permissionChanged(evt) { - // TODO + permissionChanged(index: number, permission: number, permissionName: string) { + const { permissions } = this.props; + // permissions.items[index].updatePermission(permission, permissionName); + permissions.updatePermissionOnIndex(index, permission, permissionName); } - removeItem(index) { + removeItem(index: number) { const { permissions } = this.props; permissions.removeStoreItem(index); } update() { - var updated = []; - for (let item of this.state.items) { - if (item.inherited) { - continue; - } - updated.push({ - id: item.id, - userId: item.userId, - teamId: item.teamId, - role: item.role, - permission: item.permission, - }); - } - - return this.backendSrv - .post(`/api/dashboards/id/${this.dashboardId}/acl`, { - items: updated, - }) - .then(() => { - this.setState(prevState => { - return { - ...prevState, - canUpdate: false, - }; - }); - }); - } - - prepareViewModel(item: DashboardAcl): DashboardAcl { - // TODO: this.meta - // item.inherited = !this.meta.isFolder && this.dashboardId !== item.dashboardId; - item.inherited = this.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 ${item.role} Role`); - item.nameHtml = `Everyone with ${item.role} Role`; - item.sortName = item.role; - item.sortRank = 30; - if (item.role === 'Viewer') { - item.sortRank += 1; - } - } - - if (item.inherited) { - item.sortRank += 100; - } - - return item; - } - - isDuplicate(origItem, newItem) { - if (origItem.inherited) { - return false; - } - - 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, - }; - }); + const { permissions, dashboardId } = this.props; + permissions.update(dashboardId); } resetNewType() { this.setState(prevState => { return { + ...prevState, newType: 'Group', }; }); @@ -216,6 +119,14 @@ class PermissionsInner extends Component { typeChanged(evt) { const { value } = evt.target; + const { permissions } = this.props; + + if (value === 'Viewer' || value === 'Editor') { + permissions.addStoreItem({ permission: 1, role: value, dashboardId: this.dashboardId }, this.dashboardId); + this.resetNewType(); + return; + } + this.setState(prevState => { return { ...prevState, @@ -224,40 +135,27 @@ class PermissionsInner extends Component { }); } - 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, aclTypes, permissions } = this.props; + console.log('PermissionsInner render'); + const { error, aclTypes, permissions, backendSrv } = this.props; const { newType } = this.state; return (
- asd2
Add Permission For
- {aclTypes.map((option, idx) => { return (
) : null} @@ -306,7 +211,6 @@ class PermissionsInner extends Component { Update Permissions
- asd3
); diff --git a/public/app/core/components/Permissions/PermissionsList.tsx b/public/app/core/components/Permissions/PermissionsList.tsx index 995653dd263..21fa6778458 100644 --- a/public/app/core/components/Permissions/PermissionsList.tsx +++ b/public/app/core/components/Permissions/PermissionsList.tsx @@ -1,23 +1,27 @@ import React, { Component } from 'react'; import PermissionsListItem from './PermissionsListItem'; +import { observer } from 'mobx-react'; export interface IProps { permissions: any[]; permissionsOptions: any[]; removeItem: any; permissionChanged: any; + fetching: boolean; } +@observer class PermissionsList extends Component { render() { - const { permissions, permissionsOptions, removeItem, permissionChanged } = this.props; + const { permissions, permissionsOptions, removeItem, permissionChanged, fetching } = this.props; + return ( {permissions.map((item, idx) => { return ( { No permissions are set. Will only be accessible by admins. */} - {permissions.length < 1 ? ( + {fetching === true && permissions.length < 1 ? ( + + + + ) : null} + + {fetching === false && permissions.length < 1 ? ( ); -}; +}); diff --git a/public/app/stores/PermissionsStore/PermissionsStore.ts b/public/app/stores/PermissionsStore/PermissionsStore.ts index 82193e92593..9b0443f63d6 100644 --- a/public/app/stores/PermissionsStore/PermissionsStore.ts +++ b/public/app/stores/PermissionsStore/PermissionsStore.ts @@ -1,6 +1,8 @@ import { types, getEnv, flow } from 'mobx-state-tree'; import { PermissionsStoreItem } from './PermissionsStoreItem'; +const duplicateError = 'This permission exists already.'; + export const PermissionsStore = types .model('PermissionsStore', { fetching: types.boolean, @@ -8,67 +10,128 @@ export const PermissionsStore = types 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; - // } - // })) + .views(self => ({ + isValid: item => { + const dupe = self.items.find(it => { + return isDuplicate(it, item); + }); + + if (dupe) { + this.error = duplicateError; + return false; + } + + return true; + }, + })) .actions(self => ({ load: flow(function* load(dashboardId: number) { - self.fetching = true; const backendSrv = getEnv(self).backendSrv; + self.fetching = true; 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: () => { + addStoreItem: (item, dashboardId: number) => { + if (!self.isValid(item)) { + return; + } + + self.items.push(prepareItem(item, dashboardId)); self.canUpdate = true; }, removeStoreItem: idx => { self.items.splice(idx, 1); self.canUpdate = true; }, + updatePermissionOnIndex(idx: number, permission: number, permissionName: string) { + // self.items[idx].permission = permission; + // self.items[idx].permissionName = permissionName; + self.items[idx].updatePermission(permission, permissionName); + self.canUpdate = true; + }, + // load: flow(function* load(dashboardId: number) { + + update: flow(function* update(dashboardId: number) { + const backendSrv = getEnv(self).backendSrv; + const updated = []; + for (let item of self.items) { + if (item.inherited) { + continue; + } + updated.push({ + id: item.id, + userId: item.userId, + teamId: item.teamId, + role: item.role, + permission: item.permission, + }); + } + + let res; + try { + res = backendSrv.post(`/api/dashboards/id/${dashboardId}/acl`, { + items: updated, + }); + } catch (error) { + console.error(error); + } + + self.canUpdate = false; + return res; + }), })); 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 ${item.role} Role`); - item.nameHtml = `Everyone with ${item.role} Role`; - item.sortName = item.role; - item.sortRank = 30; - if (item.role === 'Viewer') { - item.sortRank += 1; - } - } - - if (item.inherited) { - item.sortRank += 100; - } - - return item; + return prepareItem(item, dashboardId); }); }; + +const prepareItem = (item, dashboardId: number) => { + // 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 ${item.role} Role`); + item.nameHtml = `Everyone with ${item.role} Role`; + item.sortName = item.role; + item.sortRank = 30; + if (item.role === 'Viewer') { + item.sortRank += 1; + } + } + + if (item.inherited) { + item.sortRank += 100; + } + return item; +}; + +const isDuplicate = (origItem, newItem) => { + if (origItem.inherited) { + return false; + } + + 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) + ); +}; diff --git a/public/app/stores/PermissionsStore/PermissionsStoreItem.ts b/public/app/stores/PermissionsStore/PermissionsStoreItem.ts index 1f418913086..74769891256 100644 --- a/public/app/stores/PermissionsStore/PermissionsStoreItem.ts +++ b/public/app/stores/PermissionsStore/PermissionsStoreItem.ts @@ -2,16 +2,16 @@ export const PermissionsStoreItem = types .model('PermissionsStoreItem', { - dashboardId: types.number, - id: types.number, + dashboardId: types.optional(types.number, -1), + id: types.maybe(types.number), permission: types.number, - permissionName: types.string, + permissionName: types.maybe(types.string), role: types.maybe(types.string), - team: types.string, - teamId: types.number, - userEmail: types.string, - userId: types.number, - userLogin: types.string, + team: types.optional(types.string, ''), + teamId: types.optional(types.number, 0), + userEmail: types.optional(types.string, ''), + userId: types.optional(types.number, 0), + userLogin: types.optional(types.string, ''), inherited: types.maybe(types.boolean), sortRank: types.maybe(types.number), icon: types.maybe(types.string), @@ -22,4 +22,8 @@ export const PermissionsStoreItem = types updateRole: role => { self.role = role; }, + updatePermission(permission: number, permissionName: string) { + self.permission = permission; + self.permissionName = permissionName; + }, }));
+ Loading permissions... +
No permissions are set. Will only be accessible by admins. diff --git a/public/app/core/components/Permissions/PermissionsListItem.tsx b/public/app/core/components/Permissions/PermissionsListItem.tsx index e06553e13bd..d5c1e7b4b04 100644 --- a/public/app/core/components/Permissions/PermissionsListItem.tsx +++ b/public/app/core/components/Permissions/PermissionsListItem.tsx @@ -1,10 +1,11 @@ import React from 'react'; +import { observer } from 'mobx-react'; const setClassNameHelper = inherited => { return inherited ? 'gf-form-disabled' : ''; }; -export default ({ item, permissionsOptions, removeItem, permissionChanged, itemIndex }) => { +export default observer(({ item, permissionsOptions, removeItem, permissionChanged, itemIndex }) => { const handleRemoveItem = evt => { evt.preventDefault(); removeItem(itemIndex); @@ -12,7 +13,10 @@ export default ({ item, permissionsOptions, removeItem, permissionChanged, itemI const handleChangePermission = evt => { evt.preventDefault(); - permissionChanged(itemIndex, evt.target.value); + const value = evt.target.value; + const valueAsInt = parseInt(value, 10); + const newPermission = permissionsOptions.find(opt => opt.value === valueAsInt); + permissionChanged(itemIndex, newPermission.value, newPermission.text); }; return ( @@ -57,4 +61,4 @@ export default ({ item, permissionsOptions, removeItem, permissionChanged, itemI