diff --git a/pkg/api/api.go b/pkg/api/api.go index a37f200f9d1..4b570ce5b89 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -40,7 +40,8 @@ func (hs *HttpServer) registerRoutes() { r.Get("/datasources/", reqSignedIn, Index) r.Get("/datasources/new", reqSignedIn, Index) r.Get("/datasources/edit/*", reqSignedIn, Index) - r.Get("/org/users/", reqSignedIn, Index) + r.Get("/org/users/new", reqSignedIn, Index) + r.Get("/org/users/invite", reqSignedIn, Index) r.Get("/org/apikeys/", reqSignedIn, Index) r.Get("/dashboard/import/", reqSignedIn, Index) r.Get("/configuration", reqGrafanaAdmin, Index) diff --git a/pkg/api/dtos/invite.go b/pkg/api/dtos/invite.go index 3f002a8b157..09d53f576b4 100644 --- a/pkg/api/dtos/invite.go +++ b/pkg/api/dtos/invite.go @@ -6,7 +6,7 @@ type AddInviteForm struct { LoginOrEmail string `json:"loginOrEmail" binding:"Required"` Name string `json:"name"` Role m.RoleType `json:"role" binding:"Required"` - SkipEmails bool `json:"skipEmails"` + SendEmail bool `json:"sendEmail"` } type InviteInfo struct { diff --git a/pkg/api/org_invite.go b/pkg/api/org_invite.go index 864e464133d..57d9913d2eb 100644 --- a/pkg/api/org_invite.go +++ b/pkg/api/org_invite.go @@ -61,7 +61,7 @@ func AddOrgInvite(c *middleware.Context, inviteDto dtos.AddInviteForm) Response } // send invite email - if !inviteDto.SkipEmails && util.IsEmail(inviteDto.LoginOrEmail) { + if inviteDto.SendEmail && util.IsEmail(inviteDto.LoginOrEmail) { emailCmd := m.SendEmailCommand{ To: []string{inviteDto.LoginOrEmail}, Template: "new_user_invite.html", @@ -99,7 +99,7 @@ func inviteExistingUserToOrg(c *middleware.Context, user *m.User, inviteDto *dto return ApiError(500, "Error while trying to create org user", err) } else { - if !inviteDto.SkipEmails && util.IsEmail(user.Email) { + if inviteDto.SendEmail && util.IsEmail(user.Email) { emailCmd := m.SendEmailCommand{ To: []string{user.Email}, Template: "invited_to_org.html", diff --git a/public/app/core/nav_model_srv.ts b/public/app/core/nav_model_srv.ts index e77cfb8f09f..2807f8fc19c 100644 --- a/public/app/core/nav_model_srv.ts +++ b/public/app/core/nav_model_srv.ts @@ -27,9 +27,8 @@ export class NavModel { export class NavModelSrv { navItems: any; - /** @ngInject */ - constructor(private contextSrv) { + constructor() { this.navItems = config.bootData.navTree; } @@ -81,94 +80,6 @@ export class NavModelSrv { main: node }; } - - getDashboardNav(dashboard, dashNavCtrl) { - // special handling for snapshots - if (dashboard.meta.isSnapshot) { - return { - section: { - title: dashboard.title, - icon: 'icon-gf icon-gf-snapshot' - }, - menu: [ - { - title: 'Go to original dashboard', - icon: 'fa fa-fw fa-external-link', - url: dashboard.snapshot.originalUrl, - } - ] - }; - } - - var menu = []; - - if (dashboard.meta.canEdit) { - menu.push({ - title: 'Settings', - icon: 'fa fa-fw fa-cog', - clickHandler: () => dashNavCtrl.openEditView('settings') - }); - - menu.push({ - title: 'Templating', - icon: 'fa fa-fw fa-code', - clickHandler: () => dashNavCtrl.openEditView('templating') - }); - - menu.push({ - title: 'Annotations', - icon: 'fa fa-fw fa-comment', - clickHandler: () => dashNavCtrl.openEditView('annotations') - }); - - if (!dashboard.meta.isHome) { - menu.push({ - title: 'Version history', - icon: 'fa fa-fw fa-history', - clickHandler: () => dashNavCtrl.openEditView('history') - }); - } - - menu.push({ - title: 'View JSON', - icon: 'fa fa-fw fa-eye', - clickHandler: () => dashNavCtrl.viewJson() - }); - } - - if (this.contextSrv.isEditor && !dashboard.editable) { - menu.push({ - title: 'Make Editable', - icon: 'fa fa-fw fa-edit', - clickHandler: () => dashNavCtrl.makeEditable() - }); - } - - if (this.contextSrv.isEditor && !dashboard.meta.isFolder) { - menu.push({ - title: 'Save As...', - icon: 'fa fa-fw fa-save', - clickHandler: () => dashNavCtrl.saveDashboardAs() - }); - } - - if (dashboard.meta.canSave) { - menu.push({ - title: 'Delete', - icon: 'fa fa-fw fa-trash', - clickHandler: () => dashNavCtrl.deleteDashboard() - }); - - } - - return { - section: { - title: dashboard.title, - icon: 'icon-gf icon-gf-dashboard' - }, - menu: menu - }; - } } coreModule.service('navModelSrv', NavModelSrv); diff --git a/public/app/core/routes/routes.ts b/public/app/core/routes/routes.ts index 9c975f6465a..3f6d4916e77 100644 --- a/public/app/core/routes/routes.ts +++ b/public/app/core/routes/routes.ts @@ -109,9 +109,10 @@ function setupAngularRoutes($routeProvider, $locationProvider) { controllerAs: 'ctrl', resolve: loadOrgBundle, }) - .when('/org/users/new', { + .when('/org/users/invite', { templateUrl: 'public/app/features/org/partials/invite.html', controller : 'UserInviteCtrl', + controllerAs: 'ctrl', resolve: loadOrgBundle, }) .when('/org/apikeys', { diff --git a/public/app/features/org/org_users_ctrl.ts b/public/app/features/org/org_users_ctrl.ts index 4289860e742..0e6dec504c6 100644 --- a/public/app/features/org/org_users_ctrl.ts +++ b/public/app/features/org/org_users_ctrl.ts @@ -1,10 +1,10 @@ import config from 'app/core/config'; import coreModule from 'app/core/core_module'; import Remarkable from 'remarkable'; +import _ from 'lodash'; export class OrgUsersCtrl { - - user: any; + unfiltered: any; users: any; pendingInvites: any; editor: any; @@ -12,21 +12,18 @@ export class OrgUsersCtrl { externalUserMngLinkUrl: string; externalUserMngLinkName: string; externalUserMngInfo: string; - addUsersBtnName: string; + canInvite: boolean; + searchQuery: string; + showInvites: boolean; /** @ngInject */ constructor(private $scope, private backendSrv, navModelSrv, $sce) { - this.user = { - loginOrEmail: '', - role: 'Viewer', - }; - this.navModel = navModelSrv.getNav('cfg', 'users', 0); this.get(); - this.editor = { index: 0 }; this.externalUserMngLinkUrl = config.externalUserMngLinkUrl; this.externalUserMngLinkName = config.externalUserMngLinkName; + this.canInvite = !config.disableLoginForm && !config.externalUserMngLinkName; // render external user management info markdown if (config.externalUserMngInfo) { @@ -34,21 +31,13 @@ export class OrgUsersCtrl { linkTarget: '__blank', }).render(config.externalUserMngInfo); } - - this.addUsersBtnName = this.getAddUserBtnName(); - } - - getAddUserBtnName(): string { - if (this.externalUserMngLinkName) { - return this.externalUserMngLinkName; - } - return "Invite User"; } get() { this.backendSrv.get('/api/org/users') .then((users) => { this.users = users; + this.unfiltered = users; }); this.backendSrv.get('/api/org/invites') .then((pendingInvites) => { @@ -56,6 +45,13 @@ export class OrgUsersCtrl { }); } + onQueryUpdated() { + let regex = new RegExp(this.searchQuery, 'ig'); + this.users = _.filter(this.unfiltered, item => { + return regex.test(item.email) || regex.test(item.login); + }); + } + updateOrgUser(user) { this.backendSrv.patch('/api/org/users/' + user.userId, user); } @@ -74,38 +70,22 @@ export class OrgUsersCtrl { removeUserConfirmed(user) { this.backendSrv.delete('/api/org/users/' + user.userId) - .then(this.get.bind(this)); + .then(this.get.bind(this)); } revokeInvite(invite, evt) { evt.stopPropagation(); this.backendSrv.patch('/api/org/invites/' + invite.code + '/revoke') - .then(this.get.bind(this)); + .then(this.get.bind(this)); } copyInviteToClipboard(evt) { evt.stopPropagation(); } - getInviteUrl(invite) { - return invite.url; - } - - openAddUsersView() { - var modalScope = this.$scope.$new(); - modalScope.invitesSent = this.get.bind(this); - - var src = config.disableLoginForm - ? 'public/app/features/org/partials/add_user.html' - : 'public/app/features/org/partials/invite.html'; - - this.$scope.appEvent('show-modal', { - src: src, - modalClass: 'invite-modal', - scope: modalScope - }); - } - + getInviteUrl(invite) { + return invite.url; + } } coreModule.controller('OrgUsersCtrl', OrgUsersCtrl); diff --git a/public/app/features/org/partials/add_user.html b/public/app/features/org/partials/add_user.html deleted file mode 100644 index 53fe7884df9..00000000000 --- a/public/app/features/org/partials/add_user.html +++ /dev/null @@ -1,55 +0,0 @@ - diff --git a/public/app/features/org/partials/invite.html b/public/app/features/org/partials/invite.html index 330441fc88d..a35aa47a4ab 100644 --- a/public/app/features/org/partials/invite.html +++ b/public/app/features/org/partials/invite.html @@ -1,49 +1,35 @@ - +
-
- Send invite or add existing Grafana users to the organization - {{contextSrv.user.orgName}} -
-
-
-
-
- Email or Username - -
-
- Name - -
-
- Role - -
-
- - - -
-
-
+

Invite User

- +
+ Send invite or add existing Grafana user to the organization + {{contextSrv.user.orgName}} +
-
- - Cancel -
-
-
+
+
+
+ Email or Username + +
+
+ Name + +
+
+ Role + +
+ + + +
+ + Back +
+
diff --git a/public/app/features/org/partials/orgUsers.html b/public/app/features/org/partials/orgUsers.html index 7ab828562f0..28a2757fb2d 100644 --- a/public/app/features/org/partials/orgUsers.html +++ b/public/app/features/org/partials/orgUsers.html @@ -1,50 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -52,7 +28,7 @@
-
+
@@ -89,46 +65,32 @@
-
+
+ - - - - - - - - - - + + + + + +
Email Name
{{invite.email}}{{invite.name}} - -   - -
- {{invite.url}}

-   - - - Invited: {{invite.createdOn | date: 'shortDate'}} by {{invite.invitedBy}} - -
{{invite.email}}{{invite.name}} + +   + + +
-
diff --git a/public/app/features/org/user_invite_ctrl.ts b/public/app/features/org/user_invite_ctrl.ts index 85e4f7699e5..36dde418b2c 100644 --- a/public/app/features/org/user_invite_ctrl.ts +++ b/public/app/features/org/user_invite_ctrl.ts @@ -1,56 +1,30 @@ import coreModule from 'app/core/core_module'; -import _ from 'lodash'; export class UserInviteCtrl { + navModel: any; + invite: any; + inviteForm: any; /** @ngInject **/ - constructor($scope, backendSrv, navModelSrv) { - $scope.navModel = navModelSrv.getNav('cfg', 'users', 0); + constructor(private backendSrv, navModelSrv, private $location) { + this.navModel = navModelSrv.getNav('cfg', 'users', 0); - const defaultInvites = [ - {name: '', email: '', role: 'Editor'}, - ]; - - $scope.invites = _.cloneDeep(defaultInvites); - - $scope.options = {skipEmails: false}; - $scope.init = function() { }; - - $scope.addInvite = function() { - $scope.invites.push({name: '', email: '', role: 'Editor'}); + this.invite = { + name: '', + email: '', + role: 'Editor', + sendEmail: true, }; + } - $scope.removeInvite = function(invite) { - $scope.invites = _.without($scope.invites, invite); - }; + sendInvite() { + if (!this.inviteForm.$valid) { + return; + } - $scope.resetInvites = function() { - $scope.invites = _.cloneDeep(defaultInvites); - }; - - $scope.sendInvites = function() { - if (!$scope.inviteForm.$valid) { return; } - $scope.sendSingleInvite(0); - }; - - $scope.invitesSent = function() { - $scope.resetInvites(); - }; - - $scope.sendSingleInvite = function(index) { - var invite = $scope.invites[index]; - invite.skipEmails = $scope.options.skipEmails; - - return backendSrv.post('/api/org/invites', invite).finally(function() { - index += 1; - - if (index === $scope.invites.length) { - $scope.invitesSent(); - } else { - $scope.sendSingleInvite(index); - } - }); - }; + return this.backendSrv.post('/api/org/invites', this.invite).then(() => { + this.$location.path('org/users/'); + }); } } diff --git a/public/app/features/plugins/partials/plugin_list.html b/public/app/features/plugins/partials/plugin_list.html index eac4216d818..e4550171220 100644 --- a/public/app/features/plugins/partials/plugin_list.html +++ b/public/app/features/plugins/partials/plugin_list.html @@ -4,7 +4,7 @@
- +
diff --git a/public/sass/layout/_page.scss b/public/sass/layout/_page.scss index 35371cc35a9..9491f18537d 100644 --- a/public/sass/layout/_page.scss +++ b/public/sass/layout/_page.scss @@ -36,6 +36,7 @@ .page-body { padding-top: $spacer*2; + min-height: 500px; } .page-heading {