diff --git a/public/app/core/routes/routes.ts b/public/app/core/routes/routes.ts
index 9faa7211da4..50f76c6af79 100644
--- a/public/app/core/routes/routes.ts
+++ b/public/app/core/routes/routes.ts
@@ -89,6 +89,12 @@ function setupAngularRoutes($routeProvider, $locationProvider) {
controllerAs: 'ctrl',
resolve: loadOrgBundle,
})
+ .when('/org/user-groups/edit/:id', {
+ templateUrl: 'public/app/features/org/partials/edit_user_group.html',
+ controller : 'UserGroupDetailsCtrl',
+ controllerAs: 'ctrl',
+ resolve: loadOrgBundle,
+ })
.when('/profile', {
templateUrl: 'public/app/features/org/partials/profile.html',
controller : 'ProfileCtrl',
diff --git a/public/app/features/org/all.js b/public/app/features/org/all.js
index 07328700a7a..0a81c375eb5 100644
--- a/public/app/features/org/all.js
+++ b/public/app/features/org/all.js
@@ -9,4 +9,5 @@ define([
'./orgDetailsCtrl',
'./prefs_control',
'./user_groups_ctrl',
+ './user_group_details_ctrl',
], function () {});
diff --git a/public/app/features/org/partials/create_user_group.html b/public/app/features/org/partials/create_user_group.html
new file mode 100644
index 00000000000..4a6911fe13d
--- /dev/null
+++ b/public/app/features/org/partials/create_user_group.html
@@ -0,0 +1,26 @@
+
+
+
diff --git a/public/app/features/org/partials/edit_user_group.html b/public/app/features/org/partials/edit_user_group.html
new file mode 100644
index 00000000000..454da4953fa
--- /dev/null
+++ b/public/app/features/org/partials/edit_user_group.html
@@ -0,0 +1,53 @@
+
+
+
+ User Groups
+
+
+
+
+
+
+
+
+
User Group Members
+
+
+
+
+
+ | Username |
+ Email |
+ |
+
+
+ | {{userGroup.login}} |
+ {{userGroup.email}} |
+
+
+
+
+ |
+
+
+
diff --git a/public/app/features/org/partials/user_groups.html b/public/app/features/org/partials/user_groups.html
index f38f8adf439..2ad6c41a50b 100644
--- a/public/app/features/org/partials/user_groups.html
+++ b/public/app/features/org/partials/user_groups.html
@@ -6,17 +6,10 @@
User Groups
diff --git a/public/app/features/org/specs/user_group_details_ctrl_specs.ts b/public/app/features/org/specs/user_group_details_ctrl_specs.ts
new file mode 100644
index 00000000000..ee1c32073a4
--- /dev/null
+++ b/public/app/features/org/specs/user_group_details_ctrl_specs.ts
@@ -0,0 +1,43 @@
+import '../user_group_details_ctrl';
+import {describe, beforeEach, it, expect, sinon, angularMocks} from 'test/lib/common';
+import UserGroupDetailsCtrl from '../user_group_details_ctrl';
+
+describe('UserGroupDetailsCtrl', () => {
+var ctx: any = {};
+var backendSrv = {
+ searchUsers: sinon.stub().returns(Promise.resolve([])),
+ get: sinon.stub().returns(Promise.resolve([])),
+ post: sinon.stub().returns(Promise.resolve([]))
+};
+
+ beforeEach(angularMocks.module('grafana.core'));
+ beforeEach(angularMocks.module('grafana.controllers'));
+
+ beforeEach(angularMocks.inject(($rootScope, $controller, $q) => {
+ ctx.$q = $q;
+ ctx.scope = $rootScope.$new();
+ ctx.ctrl = $controller(UserGroupDetailsCtrl, {
+ $scope: ctx.scope,
+ backendSrv: backendSrv,
+ $routeParams: {id: 1}
+ });
+ ctx.ctrl.user = {name: 'login - user@email.com'};
+ }));
+
+ describe('when user is chosen to be added to user group', () => {
+ beforeEach(() => {
+ ctx.scope.addMemberForm = {$valid: true};
+ ctx.ctrl.usersSearchCache = [{id: 1, login: 'login'}, {id: 2, login: 'login2'}];
+ ctx.ctrl.addMember();
+ });
+
+ it('should parse the result and save to db', () => {
+ expect(backendSrv.post.getCall(0).args[0]).to.eql('/api/user-groups/1/members');
+ });
+
+ it('should refresh the list after saving.', () => {
+ expect(backendSrv.get.getCall(0).args[0]).to.eql('/api/user-groups/1');
+ expect(backendSrv.get.getCall(1).args[0]).to.eql('/api/user-groups/1/members');
+ });
+ });
+});
diff --git a/public/app/features/org/user_group_details_ctrl.ts b/public/app/features/org/user_group_details_ctrl.ts
new file mode 100644
index 00000000000..292b4c24eb4
--- /dev/null
+++ b/public/app/features/org/user_group_details_ctrl.ts
@@ -0,0 +1,78 @@
+///
+
+import coreModule from 'app/core/core_module';
+import _ from 'lodash';
+
+export default class UserGroupDetailsCtrl {
+ userGroup: any;
+ userGroupMembers = [];
+ user: any;
+ usersSearchCache = [];
+ searchUsers: any;
+
+ constructor(private $scope, private $http, private backendSrv, private $routeParams) {
+ this.get();
+ this.usersSearchCache = [];
+ this.searchUsers = (queryStr, callback) => {
+ if (this.usersSearchCache.length > 0) {
+ callback(_.map(this.usersSearchCache, (user) => { return user.login + ' - ' + user.email; }));
+ return;
+ }
+
+ this.backendSrv.get('/api/users/search?perpage=10&page=1&query=' + queryStr).then(result => {
+ this.usersSearchCache = result.users;
+ callback(_.map(result.users, (user) => { return user.login + ' - ' + user.email; }));
+ });
+ };
+ }
+
+ get() {
+ if (this.$routeParams && this.$routeParams.id) {
+ this.backendSrv.get(`/api/user-groups/${this.$routeParams.id}`)
+ .then(result => {
+ this.userGroup = result;
+ });
+ this.backendSrv.get(`/api/user-groups/${this.$routeParams.id}/members`)
+ .then(result => {
+ this.userGroupMembers = result;
+ });
+ }
+ }
+
+ removeUserGroupMember(userGroupMember) {
+ this.$scope.appEvent('confirm-modal', {
+ title: 'Remove Member',
+ text: 'Are you sure you want to remove ' + userGroupMember.name + ' from this group?',
+ yesText: "Remove",
+ icon: "fa-warning",
+ onConfirm: () => {
+ this.removeMemberConfirmed(userGroupMember);
+ }
+ });
+ }
+
+ removeMemberConfirmed(userGroupMember) {
+ this.backendSrv.delete(`/api/user-groups/${this.$routeParams.id}/members/${userGroupMember.userId}`)
+ .then(this.get.bind(this));
+ }
+
+ update() {
+ if (!this.$scope.userGroupDetailsForm.$valid) { return; }
+
+ this.backendSrv.put('/api/user-groups/' + this.userGroup.id, {name: this.userGroup.name});
+ }
+
+ addMember() {
+ if (!this.$scope.addMemberForm.$valid) { return; }
+
+ const login = this.user.name.split(' - ')[0];
+ const memberToAdd = _.find(this.usersSearchCache, ['login', login]);
+ this.backendSrv.post(`/api/user-groups/${this.$routeParams.id}/members`, {userId: memberToAdd.id}).then(() => {
+ this.user.name = '';
+ this.get();
+ });
+ }
+}
+
+coreModule.controller('UserGroupDetailsCtrl', UserGroupDetailsCtrl);
+
diff --git a/public/app/features/org/user_groups_ctrl.ts b/public/app/features/org/user_groups_ctrl.ts
index 117e2d680bc..6143e7364a4 100644
--- a/public/app/features/org/user_groups_ctrl.ts
+++ b/public/app/features/org/user_groups_ctrl.ts
@@ -13,7 +13,7 @@ export default class UserGroupsCtrl {
userGroupName: any = '';
/** @ngInject */
- constructor(private $scope, private $http, private backendSrv) {
+ constructor(private $scope, private $http, private backendSrv, private $location) {
this.get();
}
@@ -39,9 +39,10 @@ export default class UserGroupsCtrl {
}
createUserGroup() {
- this.backendSrv.post('/api/user-groups', {name: this.userGroupName}).then(result => {
- this.get();
- this.userGroupName = '';
+ this.backendSrv.post('/api/user-groups', {name: this.userGroupName}).then((result) => {
+ if (result.userGroupId) {
+ this.$location.path('/org/user-groups/edit/' + result.userGroupId);
+ }
});
}
@@ -61,6 +62,17 @@ export default class UserGroupsCtrl {
this.backendSrv.delete('/api/user-groups/' + userGroup.id)
.then(this.get.bind(this));
}
+
+ openModal() {
+ var modalScope = this.$scope.$new();
+ modalScope.createUserGroup = this.createUserGroup.bind(this);
+
+ this.$scope.appEvent('show-modal', {
+ src: 'public/app/features/org/partials/create_user_group.html',
+ modalClass: 'user-group-modal',
+ scope: this.$scope
+ });
+ }
}
coreModule.controller('UserGroupsCtrl', UserGroupsCtrl);