Merge branch 'external-user-mng' into v4.4.x

This commit is contained in:
Torkel Ödegaard
2017-07-31 15:07:01 +02:00
11 changed files with 243 additions and 186 deletions

View File

@@ -3,6 +3,7 @@
import config from 'app/core/config';
import _ from 'lodash';
import coreModule from 'app/core/core_module';
import Remarkable from 'remarkable';
export class OrgUsersCtrl {
@@ -10,11 +11,14 @@ export class OrgUsersCtrl {
users: any;
pendingInvites: any;
editor: any;
showInviteUI: boolean;
navModel: any;
externalUserMngLinkUrl: string;
externalUserMngLinkName: string;
externalUserMngInfo: string;
addUsersBtnName: string;
/** @ngInject */
constructor(private $scope, private $http, private backendSrv, navModelSrv) {
constructor(private $scope, private $http, private backendSrv, navModelSrv, $sce) {
this.user = {
loginOrEmail: '',
role: 'Viewer',
@@ -23,7 +27,27 @@ export class OrgUsersCtrl {
this.get();
this.editor = { index: 0 };
this.showInviteUI = config.disableLoginForm === false;
this.externalUserMngLinkUrl = config.externalUserMngLinkUrl;
this.externalUserMngLinkName = config.externalUserMngLinkName;
// render external user management info markdown
if (config.externalUserMngInfo) {
this.externalUserMngInfo = new Remarkable({
linkTarget: '__blank',
}).render(config.externalUserMngInfo);
}
this.addUsersBtnName = this.getAddUserBtnName();
}
getAddUserBtnName(): string {
if (this.externalUserMngLinkName) {
return this.externalUserMngLinkName;
} else if (config.disableLoginForm) {
return "Add Users";
} else {
return "Add or Invite";
}
}
get() {
@@ -68,13 +92,13 @@ export class OrgUsersCtrl {
evt.stopPropagation();
}
openInviteModal() {
openAddUsersView() {
var modalScope = this.$scope.$new();
modalScope.invitesSent = this.get.bind(this);
var src = this.showInviteUI
? 'public/app/features/org/partials/invite.html'
: 'public/app/features/org/partials/add_user.html';
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,

View File

@@ -5,11 +5,17 @@
<h1>Organization users</h1>
<div class="page-header-tabs">
<button class="btn btn-success" ng-click="ctrl.openInviteModal()">
<button class="btn btn-success" ng-click="ctrl.openAddUsersView()" ng-hide="ctrl.externalUserMngLinkUrl">
<i class="fa fa-plus"></i>
Add <span ng-show="ctrl.showInviteUI"> or Invite</span>
<span>{{ctrl.addUsersBtnName}}</span>
</button>
<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}">
@@ -25,72 +31,76 @@
</div>
</div>
<div ng-if="ctrl.editor.index === 0" class="tab-content">
<table class="filter-table form-inline">
<thead>
<tr>
<th>Login</th>
<th>Email</th>
<th>Role</th>
<th style="width: 34px;"></th>
</tr>
</thead>
<tr ng-repeat="user in ctrl.users">
<td>{{user.login}}</td>
<td><span class="ellipsis">{{user.email}}</span></td>
<td>
<select type="text" ng-model="user.role" class="input-medium" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']" ng-change="ctrl.updateOrgUser(user)">
</select>
</td>
<td>
<a ng-click="ctrl.removeUser(user)" class="btn btn-danger btn-mini">
<i class="fa fa-remove"></i>
</a>
</td>
</tr>
</table>
</div>
<div class="grafana-info-box" ng-if="ctrl.externalUserMngInfo">
<span ng-bind-html="ctrl.externalUserMngInfo"></span>
</div>
<div ng-if="ctrl.editor.index === 1 && ctrl.showInviteUI">
<table class="filter-table form-inline">
<thead>
<tr>
<th>Email</th>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody ng-repeat="invite in ctrl.pendingInvites">
<tr ng-click="invite.expanded = !invite.expanded" ng-class="{'expanded': invite.expanded}">
<td>{{invite.email}}</td>
<td>{{invite.name}}</td>
<td class="text-right">
<button class="btn btn-inverse btn-mini " data-clipboard-text="{{invite.url}}" clipboard-button ng-click="ctrl.copyInviteToClipboard($event)">
<i class="fa fa-clipboard"></i> Copy Invite
</button>
&nbsp;
<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>
</button>
</td>
</tr>
<tr ng-show="invite.expanded">
<td colspan="3">
<a href="{{invite.url}}">{{invite.url}}</a><br><br>
&nbsp;
<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 ng-if="ctrl.editor.index === 0" class="tab-content">
<table class="filter-table form-inline">
<thead>
<tr>
<th>Login</th>
<th>Email</th>
<th>Role</th>
<th style="width: 34px;"></th>
</tr>
</thead>
<tr ng-repeat="user in ctrl.users">
<td>{{user.login}}</td>
<td><span class="ellipsis">{{user.email}}</span></td>
<td>
<select type="text" ng-model="user.role" class="input-medium" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']" ng-change="ctrl.updateOrgUser(user)">
</select>
</td>
<td>
<a ng-click="ctrl.removeUser(user)" class="btn btn-danger btn-mini">
<i class="fa fa-remove"></i>
</a>
</td>
</tr>
</table>
</div>
</div>
<div ng-if="ctrl.editor.index === 1 && ctrl.showInviteUI">
<table class="filter-table form-inline">
<thead>
<tr>
<th>Email</th>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody ng-repeat="invite in ctrl.pendingInvites">
<tr ng-click="invite.expanded = !invite.expanded" ng-class="{'expanded': invite.expanded}">
<td>{{invite.email}}</td>
<td>{{invite.name}}</td>
<td class="text-right">
<button class="btn btn-inverse btn-mini " data-clipboard-text="{{invite.url}}" clipboard-button ng-click="ctrl.copyInviteToClipboard($event)">
<i class="fa fa-clipboard"></i> Copy Invite
</button>
&nbsp;
<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>
</button>
</td>
</tr>
<tr ng-show="invite.expanded">
<td colspan="3">
<a href="{{invite.url}}">{{invite.url}}</a><br><br>
&nbsp;
<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>

View File

@@ -63,64 +63,61 @@
</section>
<div class="editor-row">
<div class="pull-left">
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 1">
<h5>Shorter legend names</h5>
<ul>
<li>alias() function to specify a custom series name</li>
<li>aliasByNode(2) to alias by a specific part of your metric path</li>
<li>aliasByNode(2, -1) you can add multiple segment paths, and use negative index</li>
<li>groupByNode(2, 'sum') is useful if you have 2 wildcards in your metric path and want to sumSeries and group by</li>
</ul>
</div>
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 1">
<h5>Shorter legend names</h5>
<ul>
<li>alias() function to specify a custom series name</li>
<li>aliasByNode(2) to alias by a specific part of your metric path</li>
<li>aliasByNode(2, -1) you can add multiple segment paths, and use negative index</li>
<li>groupByNode(2, 'sum') is useful if you have 2 wildcards in your metric path and want to sumSeries and group by</li>
</ul>
</div>
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 2">
<h5>Series as parameter</h5>
<ul>
<li>Some graphite functions allow you to have many series arguments</li>
<li>Use #[A-Z] to use a graphite query as parameter to a function</li>
<li>
Examples:
<ul>
<li>asPercent(#A, #B)</li>
<li>prod.srv-01.counters.count - asPercent(#A) : percentage of count in comparison with A query</li>
<li>prod.srv-01.counters.count - sumSeries(#A) : sum count and series A </li>
<li>divideSeries(#A, #B)</li>
</ul>
</li>
<li>If a query is added only to be used as a parameter, hide it from the graph with the eye icon</li>
</ul>
</div>
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 2">
<h5>Series as parameter</h5>
<ul>
<li>Some graphite functions allow you to have many series arguments</li>
<li>Use #[A-Z] to use a graphite query as parameter to a function</li>
<li>
Examples:
<ul>
<li>asPercent(#A, #B)</li>
<li>prod.srv-01.counters.count - asPercent(#A) : percentage of count in comparison with A query</li>
<li>prod.srv-01.counters.count - sumSeries(#A) : sum count and series A </li>
<li>divideSeries(#A, #B)</li>
</ul>
</li>
<li>If a query is added only to be used as a parameter, hide it from the graph with the eye icon</li>
</ul>
</div>
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 3">
<h5>Stacking</h5>
<ul>
<li>You find the stacking option under Display Styles tab</li>
<li>When stacking is enabled make sure null point mode is set to 'null as zero'</li>
</ul>
</div>
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 3">
<h5>Stacking</h5>
<ul>
<li>You find the stacking option under Display Styles tab</li>
<li>When stacking is enabled make sure null point mode is set to 'null as zero'</li>
</ul>
</div>
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 4">
<h5>Templating</h5>
<ul>
<li>You can use a template variable in place of metric names</li>
<li>You can use a template variable in place of function parameters</li>
<li>You enable the templating feature in Dashboard settings / Feature toggles </li>
</ul>
</div>
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 4">
<h5>Templating</h5>
<ul>
<li>You can use a template variable in place of metric names</li>
<li>You can use a template variable in place of function parameters</li>
<li>You enable the templating feature in Dashboard settings / Feature toggles </li>
</ul>
</div>
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 5">
<h5>Max data points</h5>
<ul>
<li>Every graphite request is issued with a maxDataPoints parameter</li>
<li>Graphite uses this parameter to consolidate the real number of values down to this number</li>
<li>If there are more real values, then by default they will be consolidated using averages</li>
<li>This could hide real peaks and max values in your series</li>
<li>You can change how point consolidation is made using the consolidateBy graphite function</li>
<li>Point consolidation will effect series legend values (min,max,total,current)</li>
<li>If you override maxDataPoint and set a high value performance can be severely effected</li>
</ul>
</div>
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 5">
<h5>Max data points</h5>
<ul>
<li>Every graphite request is issued with a maxDataPoints parameter</li>
<li>Graphite uses this parameter to consolidate the real number of values down to this number</li>
<li>If there are more real values, then by default they will be consolidated using averages</li>
<li>This could hide real peaks and max values in your series</li>
<li>You can change how point consolidation is made using the consolidateBy graphite function</li>
<li>Point consolidation will effect series legend values (min,max,total,current)</li>
<li>If you override maxDataPoint and set a high value performance can be severely effected</li>
</ul>
</div>
</div>

View File

@@ -37,42 +37,39 @@
</section>
<div class="editor-row">
<div class="pull-left">
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 1">
<h5>Alias patterns</h5>
<ul>
<li>$m = replaced with measurement name</li>
<li>$measurement = replaced with measurement name</li>
<li>$1 - $9 = replaced with part of measurement name (if you separate your measurement name with dots)</li>
<li>$col = replaced with column name</li>
<li>$tag_exampletag = replaced with the value of the <i>exampletag</i> tag</li>
<li>You can also use [[tag_exampletag]] pattern replacement syntax</li>
</ul>
</div>
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 1">
<h5>Alias patterns</h5>
<ul>
<li>$m = replaced with measurement name</li>
<li>$measurement = replaced with measurement name</li>
<li>$1 - $9 = replaced with part of measurement name (if you separate your measurement name with dots)</li>
<li>$col = replaced with column name</li>
<li>$tag_exampletag = replaced with the value of the <i>exampletag</i> tag</li>
<li>You can also use [[tag_exampletag]] pattern replacement syntax</li>
</ul>
</div>
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 2">
<h5>Stacking and fill</h5>
<ul>
<li>When stacking is enabled it is important that points align</li>
<li>If there are missing points for one series it can cause gaps or missing bars</li>
<li>You must use fill(0), and select a group by time low limit</li>
<li>Use the group by time option below your queries and specify for example &gt;10s if your metrics are written every 10 seconds</li>
<li>This will insert zeros for series that are missing measurements and will make stacking work properly</li>
</ul>
</div>
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 2">
<h5>Stacking and fill</h5>
<ul>
<li>When stacking is enabled it is important that points align</li>
<li>If there are missing points for one series it can cause gaps or missing bars</li>
<li>You must use fill(0), and select a group by time low limit</li>
<li>Use the group by time option below your queries and specify for example &gt;10s if your metrics are written every 10 seconds</li>
<li>This will insert zeros for series that are missing measurements and will make stacking work properly</li>
</ul>
</div>
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 3">
<h5>Group by time</h5>
<ul>
<li>Group by time is important, otherwise the query could return many thousands of datapoints that will slow down Grafana</li>
<li>Leave the group by time field empty for each query and it will be calculated based on time range and pixel width of the graph</li>
<li>If you use fill(0) or fill(null) set a low limit for the auto group by time interval</li>
<li>The low limit can only be set in the group by time option below your queries</li>
<li>You set a low limit by adding a greater sign before the interval</li>
<li>Example: &gt;60s if you write metrics to InfluxDB every 60 seconds</li>
</ul>
</div>
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 3">
<h5>Group by time</h5>
<ul>
<li>Group by time is important, otherwise the query could return many thousands of datapoints that will slow down Grafana</li>
<li>Leave the group by time field empty for each query and it will be calculated based on time range and pixel width of the graph</li>
<li>If you use fill(0) or fill(null) set a low limit for the auto group by time interval</li>
<li>The low limit can only be set in the group by time option below your queries</li>
<li>You set a low limit by adding a greater sign before the interval</li>
<li>Example: &gt;60s if you write metrics to InfluxDB every 60 seconds</li>
</ul>
</div>
</div>

View File

@@ -258,7 +258,6 @@ $popover-border-color: $gray-1;
$popover-help-bg: $btn-secondary-bg;
$popover-help-color: $text-color;
// Tooltips and popovers
// -------------------------
$tooltipColor: $popover-help-color;
@@ -276,6 +275,9 @@ $card-background: linear-gradient(135deg, #2f2f2f, #262626);
$card-background-hover: linear-gradient(135deg, #343434, #262626);
$card-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, .1), 1px 1px 0 0 rgba(0, 0, 0, .3);
// info box
$info-box-background: linear-gradient(120deg, #142749, #0e203e);
// footer
$footer-link-color: $gray-1;
$footer-link-hover: $gray-4;

View File

@@ -300,6 +300,9 @@ $card-background: linear-gradient(135deg, $gray-5, $gray-6);
$card-background-hover: linear-gradient(135deg, $gray-6, $gray-7);
$card-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, .1), 1px 1px 0 0 rgba(0, 0, 0, .1);
// info box
$info-box-background: linear-gradient(135deg, #f1fbff, #d7ebff);
// footer
$footer-link-color: $gray-3;
$footer-link-hover: $dark-5;

View File

@@ -5,15 +5,16 @@
top: -13px;
left: -8px;
font-size: 20px;
color: $blue;
color: $text-color;
}
.grafana-info-box {
position: relative;
background: $card-background;
background: $info-box-background;
box-shadow: $card-shadow;
padding: 1rem;
border-radius: 4px;
margin-bottom: $spacer;
h5 {
margin-bottom: $spacer;
@@ -21,5 +22,9 @@
ul {
padding-left: $spacer;
}
a {
@extend .external-link;
}
}