mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
ux: org user management changes
This commit is contained in:
parent
cacbcb9c99
commit
ccbd18006e
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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', {
|
||||
|
@ -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);
|
||||
}
|
||||
@ -90,22 +86,6 @@ export class OrgUsersCtrl {
|
||||
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
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
coreModule.controller('OrgUsersCtrl', OrgUsersCtrl);
|
||||
|
@ -1,55 +0,0 @@
|
||||
<div class="modal-body" ng-controller="UserInviteCtrl" ng-init="init()">
|
||||
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-header-title">
|
||||
Add Users
|
||||
</h2>
|
||||
<a class="modal-header-close" ng-click="dismiss();">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-tagline p-b-2">
|
||||
Add existing Grafana users to the organization
|
||||
<span class="highlight-word">{{contextSrv.user.orgName}}</span>
|
||||
</div>
|
||||
|
||||
<form name="inviteForm">
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline" ng-repeat="invite in invites">
|
||||
<div class="gf-form max-width-21">
|
||||
<span class="gf-form-label">Email or Username</span>
|
||||
<input type="text" ng-model="invite.loginOrEmail" required class="gf-form-input" placeholder="email@test.com">
|
||||
</div>
|
||||
<div class="gf-form max-width-10">
|
||||
<span class="gf-form-label">Role</span>
|
||||
<select ng-model="invite.role" class="gf-form-input" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']">
|
||||
</select>
|
||||
</div>
|
||||
<div class="gf-form gf-size-auto">
|
||||
<a class="gf-form-label pointer" tabindex="1" ng-click="removeInvite(invite)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-inline gf-form-group">
|
||||
<div class="gf-form">
|
||||
<a class="btn btn-inverse btn-small" ng-click="addInvite()">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add another
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-button-row">
|
||||
<button type="submit" class="btn btn-success" ng-click="sendInvites();">Add Users</button>
|
||||
<a class="btn-text" ng-click="dismiss()">Cancel</a>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -1,49 +1,35 @@
|
||||
<page-header model="navModel"></page-header>
|
||||
<page-header model="ctrl.navModel"></page-header>
|
||||
|
||||
<div class="page-container page-body" ng-cloak>
|
||||
|
||||
<h2 class="page-sub-heading">Invite User</h2>
|
||||
|
||||
<div class="p-b-2">
|
||||
Send invite or add existing Grafana users to the organization
|
||||
Send invite or add existing Grafana user to the organization
|
||||
<span class="highlight-word">{{contextSrv.user.orgName}}</span>
|
||||
</div>
|
||||
|
||||
<form name="inviteForm">
|
||||
<form name="ctrl.inviteForm">
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline" ng-repeat="invite in invites">
|
||||
<div class="gf-form max-width-21">
|
||||
<span class="gf-form-label">Email or Username</span>
|
||||
<input type="text" ng-model="invite.loginOrEmail" required class="gf-form-input" placeholder="email@test.com">
|
||||
<div class="gf-form max-width-30">
|
||||
<span class="gf-form-label width-10">Email or Username</span>
|
||||
<input type="text" ng-model="ctrl.invite.loginOrEmail" required class="gf-form-input" placeholder="email@test.com">
|
||||
</div>
|
||||
<div class="gf-form max-width-14">
|
||||
<span class="gf-form-label">Name</span>
|
||||
<input type="text" ng-model="invite.name" class="gf-form-input" placeholder="name (optional)">
|
||||
<div class="gf-form max-width-30">
|
||||
<span class="gf-form-label width-10">Name</span>
|
||||
<input type="text" ng-model="ctrl.invite.name" class="gf-form-input" placeholder="name (optional)">
|
||||
</div>
|
||||
<div class="gf-form max-width-10">
|
||||
<span class="gf-form-label">Role</span>
|
||||
<select ng-model="invite.role" class="gf-form-input" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']">
|
||||
<div class="gf-form max-width-30">
|
||||
<span class="gf-form-label width-10">Role</span>
|
||||
<select ng-model="ctrl.invite.role" class="gf-form-input" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']">
|
||||
</select>
|
||||
</div>
|
||||
<div class="gf-form gf-size-auto">
|
||||
<a class="gf-form-label pointer" tabindex="1" ng-click="removeInvite(invite)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-inline gf-form-group">
|
||||
<div class="gf-form" style="margin-right:.25rem">
|
||||
<a class="btn btn-inverse gf-form-button" ng-click="addInvite()">
|
||||
<i class="fa fa-plus"></i>
|
||||
Invite another
|
||||
</a>
|
||||
</div>
|
||||
<gf-form-switch class="gf-form" label="Skip sending invite email" checked="options.skipEmails" switch-class="max-width-6"></gf-form-switch>
|
||||
</div>
|
||||
<gf-form-switch class="gf-form" label="Send invite email" checked="ctrl.invite.sendEmail" label-class="width-10"></gf-form-switch>
|
||||
|
||||
<div class="gf-form-button-row">
|
||||
<button type="submit" class="btn btn-success" ng-click="sendInvites();">Invite Users</button>
|
||||
<a class="btn-text" href="org/users">Cancel</a>
|
||||
<button type="submit" class="btn btn-success" ng-click="ctrl.sendInvite();">Invite</button>
|
||||
<a class="btn btn-inverse" href="org/users">Back</a>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -1,50 +1,26 @@
|
||||
<!-- <navbar model="ctrl.navModel"></navbar> -->
|
||||
<!-- -->
|
||||
<!-- <div class="page-container"> -->
|
||||
<!-- <div class="page-header"> -->
|
||||
<!-- <page-h1 model="ctrl.navModel"></page-h1> -->
|
||||
<!-- -->
|
||||
<!-- <button class="btn btn-success" ng-click="ctrl.openAddUsersView()" ng-hide="ctrl.externalUserMngLinkUrl"> -->
|
||||
<!-- <span>{{ctrl.addUsersBtnName}}</span> -->
|
||||
<!-- </button> -->
|
||||
<!-- -->
|
||||
<!-- <div class="page-header-tabs"> -->
|
||||
<!-- -->
|
||||
<!-- <a class="btn btn-inverse" ng-href="{{ctrl.externalUserMngLinkUrl}}" target="_blank" ng-if="ctrl.externalUserMngLinkUrl"> -->
|
||||
<!-- <i class="fa fa-external-link-square"></i> -->
|
||||
<!-- {{ctrl.addUsersBtnName}} -->
|
||||
<!-- </a> -->
|
||||
<!-- -->
|
||||
<!-- <ul class="gf-tabs"> -->
|
||||
<!-- <li class="gf-tabs-item"> -->
|
||||
<!-- <a class="gf-tabs-link" ng-click="ctrl.editor.index = 0" ng-class="{active: ctrl.editor.index === 0}"> -->
|
||||
<!-- Users ({{ctrl.users.length}}) -->
|
||||
<!-- </a> -->
|
||||
<!-- </li> -->
|
||||
<!-- <li class="gf-tabs-item" ng-show="ctrl.pendingInvites.length"> -->
|
||||
<!-- <a class="gf-tabs-link" ng-click="ctrl.editor.index = 1" ng-class="{active: ctrl.editor.index === 1}"> -->
|
||||
<!-- Pending Invites ({{ctrl.pendingInvites.length}}) -->
|
||||
<!-- </a> -->
|
||||
<!-- </li> -->
|
||||
<!-- </ul> -->
|
||||
<!-- </div> -->
|
||||
<!-- </div> -->
|
||||
|
||||
<page-header model="ctrl.navModel"></page-header>
|
||||
|
||||
<div class="page-container page-body">
|
||||
<div class="page-action-bar">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label">Search</label>
|
||||
<input type="text" class="gf-form-input width-20" ng-model="ctrl.searchQuery" ng-change="ctrl.onQueryUpdated()" give-focus="true" placeholder="Filter by username or email" />
|
||||
</div>
|
||||
|
||||
<div class="page-action-bar__spacer"></div>
|
||||
<button class="btn btn-inverse" ng-show="ctrl.pendingInvites.length" ng-click="ctrl.editor.index = 1">
|
||||
|
||||
<button class="btn btn-inverse" ng-show="ctrl.pendingInvites.length" ng-click="ctrl.showInvites = true">
|
||||
Pending Invites ({{ctrl.pendingInvites.length}})
|
||||
</button>
|
||||
<a class="btn btn-success" href="org/users/new" ng-hide="ctrl.externalUserMngLinkUrl">
|
||||
|
||||
<a class="btn btn-success" href="org/users/invite" ng-show="ctrl.canInvite">
|
||||
<i class="fa fa-plus"></i>
|
||||
<span>{{ctrl.addUsersBtnName}}</span>
|
||||
<span>Invite</span>
|
||||
</a>
|
||||
<a class="btn btn-inverse" ng-href="{{ctrl.externalUserMngLinkUrl}}" target="_blank" ng-if="ctrl.externalUserMngLinkUrl">
|
||||
|
||||
<a class="btn btn-success" ng-href="{{ctrl.externalUserMngLinkUrl}}" target="_blank" ng-if="ctrl.externalUserMngLinkUrl">
|
||||
<i class="fa fa-external-link-square"></i>
|
||||
{{ctrl.addUsersBtnName}}
|
||||
{{ctrl.externalUserMngLinkName}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -52,7 +28,7 @@
|
||||
<span ng-bind-html="ctrl.externalUserMngInfo"></span>
|
||||
</div>
|
||||
|
||||
<div ng-if="ctrl.editor.index === 0" class="tab-content">
|
||||
<div ng-hide="ctrl.showInvites">
|
||||
<table class="filter-table form-inline">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -89,17 +65,17 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div ng-if="ctrl.editor.index === 1">
|
||||
<div ng-if="ctrl.showInvites">
|
||||
<table class="filter-table form-inline">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Email</th>
|
||||
<th>Name</th>
|
||||
<th></th>
|
||||
<th style="width: 34px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ng-repeat="invite in ctrl.pendingInvites">
|
||||
<tr ng-click="invite.expanded = !invite.expanded" ng-class="{'expanded': invite.expanded}">
|
||||
<tr ng-repeat="invite in ctrl.pendingInvites">
|
||||
<td>{{invite.email}}</td>
|
||||
<td>{{invite.name}}</td>
|
||||
<td class="text-right">
|
||||
@ -107,28 +83,14 @@
|
||||
<i class="fa fa-clipboard"></i> Copy Invite
|
||||
</button>
|
||||
|
||||
<button class="btn btn-inverse btn-mini">
|
||||
Details
|
||||
<i ng-show="!invite.expanded" class="fa fa-caret-right"></i>
|
||||
<i ng-show="invite.expanded" class="fa fa-caret-down"></i>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-danger btn-mini" ng-click="ctrl.revokeInvite(invite, $event)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-show="invite.expanded">
|
||||
<td colspan="3">
|
||||
<a href="{{invite.url}}">{{invite.url}}</a><br><br>
|
||||
|
||||
<button class="btn btn-inverse btn-mini" ng-click="ctrl.revokeInvite(invite, $event)">
|
||||
<i class="fa fa-remove" style="color: red"></i> Revoke invite
|
||||
</button>
|
||||
<span style="padding-left: 15px">
|
||||
Invited: <em> {{invite.createdOn | date: 'shortDate'}} by {{invite.invitedBy}} </em>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
sendInvite() {
|
||||
if (!this.inviteForm.$valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.backendSrv.post('/api/org/invites', this.invite).then(() => {
|
||||
this.$location.path('org/users/');
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
<div class="page-action-bar">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label">Search</label>
|
||||
<input type="text" class="gf-form-input width-20" ng-model="ctrl.searchQuery" ng-change="ctrl.onQueryUpdated()" />
|
||||
<input type="text" class="gf-form-input width-20" ng-model="ctrl.searchQuery" ng-change="ctrl.onQueryUpdated()" placeholder="Filter by name or type" />
|
||||
</div>
|
||||
|
||||
<div class="page-action-bar__spacer"></div>
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
.page-body {
|
||||
padding-top: $spacer*2;
|
||||
min-height: 500px;
|
||||
}
|
||||
|
||||
.page-heading {
|
||||
|
Loading…
Reference in New Issue
Block a user