diff --git a/public/app/core/components/Permissions/Permissions.tsx b/public/app/core/components/Permissions/Permissions.tsx index 5d32ce5b08a..25fefcd05f7 100644 --- a/public/app/core/components/Permissions/Permissions.tsx +++ b/public/app/core/components/Permissions/Permissions.tsx @@ -34,14 +34,17 @@ export interface IProps { class Permissions extends Component { constructor(props) { super(props); - const { dashboardId, permissions, isFolder } = this.props; + const { dashboardId, isFolder } = this.props; this.permissionChanged = this.permissionChanged.bind(this); this.typeChanged = this.typeChanged.bind(this); this.removeItem = this.removeItem.bind(this); - this.update = this.update.bind(this); this.userPicked = this.userPicked.bind(this); this.teamPicked = this.teamPicked.bind(this); - permissions.load(dashboardId, isFolder); + this.loadStore(dashboardId, isFolder); + } + + loadStore(dashboardId, isFolder) { + return this.props.permissions.load(dashboardId, isFolder); } permissionChanged(index: number, permission: number, permissionName: string) { @@ -54,11 +57,6 @@ class Permissions extends Component { permissions.removeStoreItem(index); } - update() { - const { permissions, dashboardId } = this.props; - permissions.update(dashboardId); - } - resetNewType() { const { permissions } = this.props; permissions.resetNewType(); @@ -142,11 +140,6 @@ class Permissions extends Component { ) : null} -
- -
What are Permissions?
diff --git a/public/app/routes/routes.ts b/public/app/routes/routes.ts index be6fd39e511..e533f68606f 100644 --- a/public/app/routes/routes.ts +++ b/public/app/routes/routes.ts @@ -69,11 +69,6 @@ export function setupAngularRoutes($routeProvider, $locationProvider) { controller: 'CreateFolderCtrl', controllerAs: 'ctrl', }) - // .when('/dashboards/folder/:folderId/:slug/permissions', { - // templateUrl: 'public/app/features/dashboard/partials/folder_permissions.html', - // controller: 'FolderPermissionsCtrl', - // controllerAs: 'ctrl', - // }) .when('/dashboards/folder/:folderId/:slug/permissions', { template: '', resolve: { diff --git a/public/app/stores/PermissionsStore/PermissionsStore.jest.ts b/public/app/stores/PermissionsStore/PermissionsStore.jest.ts new file mode 100644 index 00000000000..98b601ecc18 --- /dev/null +++ b/public/app/stores/PermissionsStore/PermissionsStore.jest.ts @@ -0,0 +1,76 @@ +import { PermissionsStore } from './PermissionsStore'; +import { backendSrv } from 'test/mocks/common'; + +describe('PermissionsStore', () => { + let store; + + beforeEach(() => { + 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(); + + store = PermissionsStore.create( + { + fetching: false, + canUpdate: false, + items: [], + }, + { + backendSrv: backendSrv, + } + ); + + return store.load(1, true); + }); + + it('should save update on permission change', () => { + expect(store.items[0].permission).toBe(1); + expect(store.items[0].permissionName).toBe('View'); + + store.updatePermissionOnIndex(0, 2, 'Edit'); + + expect(store.items[0].permission).toBe(2); + expect(store.items[0].permissionName).toBe('Edit'); + expect(backendSrv.post.mock.calls.length).toBe(1); + expect(backendSrv.post.mock.calls[0][0]).toBe('/api/dashboards/id/1/acl'); + }); + + it('should save newly added permissions automatically', () => { + expect(store.items.length).toBe(3); + + const newItem = { + userId: 10, + userLogin: 'tester1', + permission: 1, + }; + store.addStoreItem(newItem); + + expect(store.items.length).toBe(4); + expect(backendSrv.post.mock.calls.length).toBe(1); + expect(backendSrv.post.mock.calls[0][0]).toBe('/api/dashboards/id/1/acl'); + }); + + it('should save removed permissions automatically', () => { + expect(store.items.length).toBe(3); + + store.removeStoreItem(2); + + expect(store.items.length).toBe(2); + expect(backendSrv.post.mock.calls.length).toBe(1); + expect(backendSrv.post.mock.calls[0][0]).toBe('/api/dashboards/id/1/acl'); + }); +}); diff --git a/public/app/stores/PermissionsStore/PermissionsStore.ts b/public/app/stores/PermissionsStore/PermissionsStore.ts index 52f96ceb2c6..54078051d4b 100644 --- a/public/app/stores/PermissionsStore/PermissionsStore.ts +++ b/public/app/stores/PermissionsStore/PermissionsStore.ts @@ -19,7 +19,6 @@ export const PermissionsStore = types fetching: types.boolean, isFolder: types.maybe(types.boolean), dashboardId: types.maybe(types.number), - canUpdate: types.boolean, items: types.optional(types.array(PermissionsStoreItem), []), error: types.maybe(types.string), originalItems: types.optional(types.array(PermissionsStoreItem), []), @@ -51,62 +50,67 @@ export const PermissionsStore = types self.originalItems = items; self.fetching = false; }), - addStoreItem: item => { + addStoreItem: flow(function* addStoreItem(item) { self.error = null; if (!self.isValid(item)) { - return; + return undefined; } self.items.push(prepareItem(item, self.dashboardId, self.isFolder)); - self.canUpdate = true; - }, - removeStoreItem: idx => { + updateItems(self); + }), + removeStoreItem: flow(function* removeStoreItem(idx: number) { self.error = null; self.items.splice(idx, 1); - self.canUpdate = true; - }, - updatePermissionOnIndex(idx: number, permission: number, permissionName: string) { + updateItems(self); + }), + updatePermissionOnIndex: flow(function* updatePermissionOnIndex( + idx: number, + permission: number, + permissionName: string + ) { self.error = null; self.items[idx].updatePermission(permission, permissionName); - self.canUpdate = true; - }, + updateItems(self); + }), setNewType(newType: string) { self.newType = newType; }, resetNewType() { self.newType = defaultNewType; }, - update: flow(function* update(dashboardId: number) { - self.error = null; - 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 updateItems = self => { + self.error = null; + + 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/${self.dashboardId}/acl`, { + items: updated, + }); + } catch (error) { + console.error(error); + } + + return res; +}; + const prepareServerResponse = (response, dashboardId: number, isFolder: boolean) => { return response.map(item => { return prepareItem(item, dashboardId, isFolder); diff --git a/public/app/stores/RootStore/RootStore.ts b/public/app/stores/RootStore/RootStore.ts index c1da118057f..c3bfe75d59c 100644 --- a/public/app/stores/RootStore/RootStore.ts +++ b/public/app/stores/RootStore/RootStore.ts @@ -20,7 +20,6 @@ export const RootStore = types.model({ }), permissions: types.optional(PermissionsStore, { fetching: false, - canUpdate: false, items: [], }), view: types.optional(ViewStore, {