diff --git a/conf/defaults.ini b/conf/defaults.ini
index 47406027387..ceb916917ab 100644
--- a/conf/defaults.ini
+++ b/conf/defaults.ini
@@ -204,6 +204,11 @@ login_hint = email or username
# Default UI theme ("dark" or "light")
default_theme = dark
+# External user management
+external_manage_link_url =
+external_manage_link_name =
+external_manage_info =
+
[auth]
# Set to true to disable (hide) the login form, useful if you use OAuth
disable_login_form = false
diff --git a/conf/sample.ini b/conf/sample.ini
index b863f26bdb1..e33f408ecad 100644
--- a/conf/sample.ini
+++ b/conf/sample.ini
@@ -191,6 +191,11 @@
# Default UI theme ("dark" or "light")
;default_theme = dark
+# External user management, these options affect the organization users view
+;external_manage_link_url =
+;external_manage_link_name =
+;external_manage_info =
+
[auth]
# Set to true to disable (hide) the login form, useful if you use OAuth, defaults to false
;disable_login_form = false
diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go
index 4d84480a208..2693d5f9683 100644
--- a/pkg/api/frontendsettings.go
+++ b/pkg/api/frontendsettings.go
@@ -131,17 +131,20 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
}
jsonObj := map[string]interface{}{
- "defaultDatasource": defaultDatasource,
- "datasources": datasources,
- "panels": panels,
- "appSubUrl": setting.AppSubUrl,
- "allowOrgCreate": (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin,
- "authProxyEnabled": setting.AuthProxyEnabled,
- "ldapEnabled": setting.LdapEnabled,
- "alertingEnabled": setting.AlertingEnabled,
- "googleAnalyticsId": setting.GoogleAnalyticsId,
- "disableLoginForm": setting.DisableLoginForm,
- "disableSignoutMenu": setting.DisableSignoutMenu,
+ "defaultDatasource": defaultDatasource,
+ "datasources": datasources,
+ "panels": panels,
+ "appSubUrl": setting.AppSubUrl,
+ "allowOrgCreate": (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin,
+ "authProxyEnabled": setting.AuthProxyEnabled,
+ "ldapEnabled": setting.LdapEnabled,
+ "alertingEnabled": setting.AlertingEnabled,
+ "googleAnalyticsId": setting.GoogleAnalyticsId,
+ "disableLoginForm": setting.DisableLoginForm,
+ "disableSignoutMenu": setting.DisableSignoutMenu,
+ "externalUserMngInfo": setting.ExternalUserMngInfo,
+ "externalUserMngLinkUrl": setting.ExternalUserMngLinkUrl,
+ "externalUserMngLinkName": setting.ExternalUserMngLinkName,
"buildInfo": map[string]interface{}{
"version": setting.BuildVersion,
"commit": setting.BuildCommit,
diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go
index 9ec995dd96e..c29512ce5f0 100644
--- a/pkg/setting/setting.go
+++ b/pkg/setting/setting.go
@@ -90,15 +90,18 @@ var (
SnapShotRemoveExpired bool
// User settings
- AllowUserSignUp bool
- AllowUserOrgCreate bool
- AutoAssignOrg bool
- AutoAssignOrgRole string
- VerifyEmailEnabled bool
- LoginHint string
- DefaultTheme string
- DisableLoginForm bool
- DisableSignoutMenu bool
+ AllowUserSignUp bool
+ AllowUserOrgCreate bool
+ AutoAssignOrg bool
+ AutoAssignOrgRole string
+ VerifyEmailEnabled bool
+ LoginHint string
+ DefaultTheme string
+ DisableLoginForm bool
+ DisableSignoutMenu bool
+ ExternalUserMngLinkUrl string
+ ExternalUserMngLinkName string
+ ExternalUserMngInfo string
// Http auth
AdminUser string
@@ -531,6 +534,9 @@ func NewConfigContext(args *CommandLineArgs) error {
VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false)
LoginHint = users.Key("login_hint").String()
DefaultTheme = users.Key("default_theme").String()
+ ExternalUserMngLinkUrl = users.Key("external_manage_link_url").String()
+ ExternalUserMngLinkName = users.Key("external_manage_link_name").String()
+ ExternalUserMngInfo = users.Key("external_manage_info").String()
// auth
auth := Cfg.Section("auth")
diff --git a/public/app/features/org/org_users_ctrl.ts b/public/app/features/org/org_users_ctrl.ts
index fb746307ee9..1ecde875a5a 100644
--- a/public/app/features/org/org_users_ctrl.ts
+++ b/public/app/features/org/org_users_ctrl.ts
@@ -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,
diff --git a/public/app/features/org/partials/orgUsers.html b/public/app/features/org/partials/orgUsers.html
index 0a10a4324cd..6f73f0f2f09 100644
--- a/public/app/features/org/partials/orgUsers.html
+++ b/public/app/features/org/partials/orgUsers.html
@@ -5,11 +5,17 @@
Organization users
-
+
+
+
-
+
diff --git a/public/app/plugins/datasource/graphite/partials/query.options.html b/public/app/plugins/datasource/graphite/partials/query.options.html
index 22c7d8c0be8..649f7aa3987 100644
--- a/public/app/plugins/datasource/graphite/partials/query.options.html
+++ b/public/app/plugins/datasource/graphite/partials/query.options.html
@@ -63,64 +63,61 @@
-
+
+
Shorter legend names
+
+ - alias() function to specify a custom series name
+ - aliasByNode(2) to alias by a specific part of your metric path
+ - aliasByNode(2, -1) you can add multiple segment paths, and use negative index
+ - groupByNode(2, 'sum') is useful if you have 2 wildcards in your metric path and want to sumSeries and group by
+
+
-
-
Shorter legend names
-
- - alias() function to specify a custom series name
- - aliasByNode(2) to alias by a specific part of your metric path
- - aliasByNode(2, -1) you can add multiple segment paths, and use negative index
- - groupByNode(2, 'sum') is useful if you have 2 wildcards in your metric path and want to sumSeries and group by
-
-
+
+
Series as parameter
+
+ - Some graphite functions allow you to have many series arguments
+ - Use #[A-Z] to use a graphite query as parameter to a function
+ -
+ Examples:
+
+ - asPercent(#A, #B)
+ - prod.srv-01.counters.count - asPercent(#A) : percentage of count in comparison with A query
+ - prod.srv-01.counters.count - sumSeries(#A) : sum count and series A
+ - divideSeries(#A, #B)
+
+
+ - If a query is added only to be used as a parameter, hide it from the graph with the eye icon
+
+
-
-
Series as parameter
-
- - Some graphite functions allow you to have many series arguments
- - Use #[A-Z] to use a graphite query as parameter to a function
- -
- Examples:
-
- - asPercent(#A, #B)
- - prod.srv-01.counters.count - asPercent(#A) : percentage of count in comparison with A query
- - prod.srv-01.counters.count - sumSeries(#A) : sum count and series A
- - divideSeries(#A, #B)
-
-
- - If a query is added only to be used as a parameter, hide it from the graph with the eye icon
-
-
+
+
Stacking
+
+ - You find the stacking option under Display Styles tab
+ - When stacking is enabled make sure null point mode is set to 'null as zero'
+
+
-
-
Stacking
-
- - You find the stacking option under Display Styles tab
- - When stacking is enabled make sure null point mode is set to 'null as zero'
-
-
+
+
Templating
+
+ - You can use a template variable in place of metric names
+ - You can use a template variable in place of function parameters
+ - You enable the templating feature in Dashboard settings / Feature toggles
+
+
-
-
Templating
-
- - You can use a template variable in place of metric names
- - You can use a template variable in place of function parameters
- - You enable the templating feature in Dashboard settings / Feature toggles
-
-
-
-
-
Max data points
-
- - Every graphite request is issued with a maxDataPoints parameter
- - Graphite uses this parameter to consolidate the real number of values down to this number
- - If there are more real values, then by default they will be consolidated using averages
- - This could hide real peaks and max values in your series
- - You can change how point consolidation is made using the consolidateBy graphite function
- - Point consolidation will effect series legend values (min,max,total,current)
- - If you override maxDataPoint and set a high value performance can be severely effected
-
-
+
+
Max data points
+
+ - Every graphite request is issued with a maxDataPoints parameter
+ - Graphite uses this parameter to consolidate the real number of values down to this number
+ - If there are more real values, then by default they will be consolidated using averages
+ - This could hide real peaks and max values in your series
+ - You can change how point consolidation is made using the consolidateBy graphite function
+ - Point consolidation will effect series legend values (min,max,total,current)
+ - If you override maxDataPoint and set a high value performance can be severely effected
+
diff --git a/public/app/plugins/datasource/influxdb/partials/query.options.html b/public/app/plugins/datasource/influxdb/partials/query.options.html
index 68293b69f70..2bdf84dddeb 100644
--- a/public/app/plugins/datasource/influxdb/partials/query.options.html
+++ b/public/app/plugins/datasource/influxdb/partials/query.options.html
@@ -37,42 +37,39 @@
-
+
+
Alias patterns
+
+ - $m = replaced with measurement name
+ - $measurement = replaced with measurement name
+ - $1 - $9 = replaced with part of measurement name (if you separate your measurement name with dots)
+ - $col = replaced with column name
+ - $tag_exampletag = replaced with the value of the exampletag tag
+ - You can also use [[tag_exampletag]] pattern replacement syntax
+
+
-
-
Alias patterns
-
- - $m = replaced with measurement name
- - $measurement = replaced with measurement name
- - $1 - $9 = replaced with part of measurement name (if you separate your measurement name with dots)
- - $col = replaced with column name
- - $tag_exampletag = replaced with the value of the exampletag tag
- - You can also use [[tag_exampletag]] pattern replacement syntax
-
-
+
+
Stacking and fill
+
+ - When stacking is enabled it is important that points align
+ - If there are missing points for one series it can cause gaps or missing bars
+ - You must use fill(0), and select a group by time low limit
+ - Use the group by time option below your queries and specify for example >10s if your metrics are written every 10 seconds
+ - This will insert zeros for series that are missing measurements and will make stacking work properly
+
+
-
-
Stacking and fill
-
- - When stacking is enabled it is important that points align
- - If there are missing points for one series it can cause gaps or missing bars
- - You must use fill(0), and select a group by time low limit
- - Use the group by time option below your queries and specify for example >10s if your metrics are written every 10 seconds
- - This will insert zeros for series that are missing measurements and will make stacking work properly
-
-
-
-
-
Group by time
-
- - Group by time is important, otherwise the query could return many thousands of datapoints that will slow down Grafana
- - 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
- - If you use fill(0) or fill(null) set a low limit for the auto group by time interval
- - The low limit can only be set in the group by time option below your queries
- - You set a low limit by adding a greater sign before the interval
- - Example: >60s if you write metrics to InfluxDB every 60 seconds
-
-
+
+
Group by time
+
+ - Group by time is important, otherwise the query could return many thousands of datapoints that will slow down Grafana
+ - 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
+ - If you use fill(0) or fill(null) set a low limit for the auto group by time interval
+ - The low limit can only be set in the group by time option below your queries
+ - You set a low limit by adding a greater sign before the interval
+ - Example: >60s if you write metrics to InfluxDB every 60 seconds
+
diff --git a/public/sass/_variables.dark.scss b/public/sass/_variables.dark.scss
index 871252248ae..9ce6b2fd93f 100644
--- a/public/sass/_variables.dark.scss
+++ b/public/sass/_variables.dark.scss
@@ -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;
diff --git a/public/sass/_variables.light.scss b/public/sass/_variables.light.scss
index f44072d2b83..19751887fa5 100644
--- a/public/sass/_variables.light.scss
+++ b/public/sass/_variables.light.scss
@@ -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;
diff --git a/public/sass/components/_infobox.scss b/public/sass/components/_infobox.scss
index 63b334a273e..cb80187f655 100644
--- a/public/sass/components/_infobox.scss
+++ b/public/sass/components/_infobox.scss
@@ -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;
+ }
}