mirror of
https://github.com/grafana/grafana.git
synced 2026-07-30 00:08:10 -05:00
Merge branch 'develop-settings' into develop
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { Component } from 'react';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
export interface IProps {
|
||||
model: any;
|
||||
@@ -17,7 +17,7 @@ class EmptyListCTA extends Component<IProps, any> {
|
||||
proTipTarget
|
||||
} = this.props.model;
|
||||
return (
|
||||
<div className="empty-list-cta p-t-2 p-b-1">
|
||||
<div className="empty-list-cta">
|
||||
<div className="empty-list-cta__title">{title}</div>
|
||||
<a href={buttonLink} className="empty-list-cta__button btn btn-xlarge btn-success"><i className={buttonIcon} />{buttonTitle}</a>
|
||||
<div className="empty-list-cta__pro-tip">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
exports[`CollorPalette renders correctly 1`] = `
|
||||
<div
|
||||
className="empty-list-cta p-t-2 p-b-1"
|
||||
className="empty-list-cta"
|
||||
>
|
||||
<div
|
||||
className="empty-list-cta__title"
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
///<reference path="../../headers/common.d.ts" />
|
||||
|
||||
import coreModule from 'app/core/core_module';
|
||||
|
||||
var template = `
|
||||
|
||||
@@ -18,22 +18,21 @@ function (_, $, coreModule) {
|
||||
elem.toggleClass('panel-in-fullscreen', false);
|
||||
});
|
||||
|
||||
var lastHideControlsVal;
|
||||
$scope.$watch('ctrl.dashboard.hideControls', function() {
|
||||
if (!$scope.dashboard) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hideControls = $scope.dashboard.hideControls;
|
||||
if (lastHideControlsVal !== hideControls) {
|
||||
elem.toggleClass('hide-controls', hideControls);
|
||||
lastHideControlsVal = hideControls;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('ctrl.playlistSrv.isPlaying', function(newValue) {
|
||||
elem.toggleClass('playlist-active', newValue === true);
|
||||
});
|
||||
|
||||
$scope.$watch('ctrl.dashboardViewState.state.editview', function(newValue) {
|
||||
if (newValue) {
|
||||
elem.toggleClass('dashboard-page--settings-opening', _.isString(newValue));
|
||||
setTimeout(function() {
|
||||
elem.toggleClass('dashboard-page--settings-open', _.isString(newValue));
|
||||
}, 10);
|
||||
} else {
|
||||
elem.removeClass('dashboard-page--settings-opening');
|
||||
elem.removeClass('dashboard-page--settings-open');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -13,7 +13,6 @@ function ($, angular, coreModule, _) {
|
||||
'templating': { src: 'public/app/features/templating/partials/editor.html'},
|
||||
'history': { html: '<gf-dashboard-history dashboard="dashboard"></gf-dashboard-history>'},
|
||||
'timepicker': { src: 'public/app/features/dashboard/timepicker/dropdown.html' },
|
||||
'add-panel': { html: '<add-panel></add-panel>' },
|
||||
'import': { html: '<dash-import dismiss="dismiss()"></dash-import>', isModal: true },
|
||||
'permissions': { html: '<dash-acl-modal dismiss="dismiss()"></dash-acl-modal>', isModal: true },
|
||||
'new-folder': {
|
||||
|
||||
@@ -72,8 +72,8 @@ export class KeybindingSrv {
|
||||
}, 'keydown');
|
||||
}
|
||||
|
||||
showDashEditView(view) {
|
||||
var search = _.extend(this.$location.search(), {editview: view});
|
||||
showDashEditView() {
|
||||
var search = _.extend(this.$location.search(), {editview: 'settings'});
|
||||
this.$location.search(search);
|
||||
}
|
||||
|
||||
@@ -84,10 +84,6 @@ export class KeybindingSrv {
|
||||
scope.broadcastRefresh();
|
||||
});
|
||||
|
||||
this.bind('mod+h', () => {
|
||||
dashboard.hideControls = !dashboard.hideControls;
|
||||
});
|
||||
|
||||
this.bind('mod+s', e => {
|
||||
scope.appEvent('save-dashboard');
|
||||
});
|
||||
@@ -197,7 +193,7 @@ export class KeybindingSrv {
|
||||
});
|
||||
|
||||
this.bind('d s', () => {
|
||||
this.showDashEditView('settings');
|
||||
this.showDashEditView();
|
||||
});
|
||||
|
||||
this.bind('d k', () => {
|
||||
@@ -215,8 +211,14 @@ export class KeybindingSrv {
|
||||
}
|
||||
|
||||
scope.appEvent('hide-modal');
|
||||
scope.appEvent('hide-dash-editor');
|
||||
scope.appEvent('panel-change-view', {fullscreen: false, edit: false});
|
||||
|
||||
// close settings view
|
||||
var search = this.$location.search();
|
||||
if (search.editview) {
|
||||
delete search.editview;
|
||||
this.$location.search(search);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,13 @@ function popoverSrv($compile, $rootScope, $timeout) {
|
||||
openDrop = drop;
|
||||
openDrop.open();
|
||||
}, 100);
|
||||
|
||||
// return close function
|
||||
return function() {
|
||||
if (drop) {
|
||||
drop.close();
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import coreModule from 'app/core/core_module';
|
||||
import alertDef from '../alerting/alert_def';
|
||||
|
||||
/** @ngInject **/
|
||||
export function annotationTooltipDirective($sanitize, dashboardSrv, contextSrv, popoverSrv, $compile) {
|
||||
export function annotationTooltipDirective($sanitize, dashboardSrv, contextSrv, $compile) {
|
||||
|
||||
function sanitizeString(str) {
|
||||
try {
|
||||
|
||||
@@ -26,7 +26,7 @@ export class AnnotationsEditorCtrl {
|
||||
];
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private $scope, private datasourceSrv) {
|
||||
constructor($scope, private datasourceSrv) {
|
||||
$scope.ctrl = this;
|
||||
|
||||
this.mode = 'list';
|
||||
@@ -62,7 +62,6 @@ export class AnnotationsEditorCtrl {
|
||||
update() {
|
||||
this.reset();
|
||||
this.mode = 'list';
|
||||
this.$scope.broadcastRefresh();
|
||||
}
|
||||
|
||||
setupNew() {
|
||||
@@ -70,32 +69,24 @@ export class AnnotationsEditorCtrl {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
backToList() {
|
||||
this.mode = 'list';
|
||||
}
|
||||
|
||||
add() {
|
||||
this.annotations.push(this.currentAnnotation);
|
||||
this.reset();
|
||||
this.mode = 'list';
|
||||
this.$scope.broadcastRefresh();
|
||||
this.$scope.dashboard.updateSubmenuVisibility();
|
||||
}
|
||||
|
||||
removeAnnotation(annotation) {
|
||||
var index = _.indexOf(this.annotations, annotation);
|
||||
this.annotations.splice(index, 1);
|
||||
this.$scope.dashboard.updateSubmenuVisibility();
|
||||
this.$scope.broadcastRefresh();
|
||||
}
|
||||
|
||||
onColorChange(newColor) {
|
||||
this.currentAnnotation.iconColor = newColor;
|
||||
}
|
||||
|
||||
annotationEnabledChange() {
|
||||
this.$scope.broadcastRefresh();
|
||||
}
|
||||
|
||||
annotationHiddenChanged() {
|
||||
this.$scope.dashboard.updateSubmenuVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
coreModule.controller('AnnotationsEditorCtrl', AnnotationsEditorCtrl);
|
||||
|
||||
@@ -1,145 +1,113 @@
|
||||
|
||||
<div ng-controller="AnnotationsEditorCtrl">
|
||||
<div class="tabbed-view-header">
|
||||
<h2 class="tabbed-view-title">
|
||||
Annotations
|
||||
</h2>
|
||||
<h3 class="dashboard-settings__header">
|
||||
<a ng-click="ctrl.backToList()">Annotations</a>
|
||||
<span ng-show="ctrl.mode === 'new'">> New</span>
|
||||
<span ng-show="ctrl.mode === 'edit'">> Edit</span>
|
||||
</h3>
|
||||
|
||||
<ul class="gf-tabs">
|
||||
<li class="gf-tabs-item" >
|
||||
<a class="gf-tabs-link" ng-click="ctrl.mode = 'list';" ng-class="{active: ctrl.mode === 'list'}">
|
||||
Queries
|
||||
</a>
|
||||
</li>
|
||||
<li class="gf-tabs-item" ng-show="ctrl.mode === 'edit'">
|
||||
<a class="gf-tabs-link" ng-class="{active: ctrl.mode === 'edit'}">
|
||||
Edit Query
|
||||
</a>
|
||||
</li>
|
||||
<li class="gf-tabs-item" ng-show="ctrl.mode === 'new'">
|
||||
<span class="active gf-tabs-link">New Query</span>
|
||||
</li>
|
||||
|
||||
<li class="gf-tabs-item" >
|
||||
<a class="gf-tabs-link" ng-click="ctrl.mode = 'help';" ng-class="{active: ctrl.mode === 'help'}">
|
||||
Help
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<button class="tabbed-view-close-btn" ng-click="dismiss();">
|
||||
<i class="fa fa-remove"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="tabbed-view-body">
|
||||
|
||||
<div ng-show="ctrl.mode === 'help'">
|
||||
<div class="grafana-info-box col-lg-8">
|
||||
<h5>What are Annotations?</h5>
|
||||
<p>
|
||||
Annotations provide a way to integrate event data into your graphs. They are visualized as vertical lines and icons
|
||||
on all graph panels. When you hover over an annotation icon you can get title, tags, and text information for the event.
|
||||
In the <i>Queries</i> tab you can add queries that return annotation events.
|
||||
</p>
|
||||
<p>
|
||||
You can add annotations directly from grafana by holding CTRL or CMD + click on graph (or drag region). These will be stored in Grafana's annotation database.
|
||||
</p>
|
||||
Checkout the <a class="external-link" target="_blank" href="http://docs.grafana.org/reference/annotations/">Annotations documentation</a> for more information.
|
||||
</div>
|
||||
<div ng-if="ctrl.mode === 'list'">
|
||||
<div class="page-action-bar" ng-if="ctrl.annotations.length > 1">
|
||||
<div class="page-action-bar__spacer"></div>
|
||||
<a type="button" class="btn btn-success" ng-click="ctrl.setupNew();"><i class="fa fa-plus" ></i> New</a>
|
||||
</div>
|
||||
|
||||
<div class="editor-row row" ng-if="ctrl.mode === 'list'">
|
||||
<div ng-if="ctrl.annotations.length === 0">
|
||||
<em>No annotation queries defined</em>
|
||||
</div>
|
||||
<table class="grafana-options-table">
|
||||
<table class="filter-table filter-table--hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Query name</th>
|
||||
<th>Data source</th>
|
||||
<th colspan="3"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="annotation in ctrl.annotations">
|
||||
<td style="width:90%" ng-hide="annotation.builtIn">
|
||||
<td style="width:90%" ng-hide="annotation.builtIn" class="pointer" ng-click="ctrl.edit(annotation)">
|
||||
<i class="fa fa-comment" style="color:{{annotation.iconColor}}"></i>
|
||||
{{annotation.name}}
|
||||
</td>
|
||||
<td style="width:90%" ng-show="annotation.builtIn">
|
||||
<td style="width:90%" ng-show="annotation.builtIn" class="pointer" ng-click="ctrl.edit(annotation)">
|
||||
<i class="fa fa-comment"></i>
|
||||
<em class="muted">{{annotation.name}} (Built-in)</em>
|
||||
</td>
|
||||
<td class="pointer" ng-click="ctrl.edit(annotation)">
|
||||
{{annotation.datasource || 'Default'}}
|
||||
</td>
|
||||
<td style="width: 1%"><i ng-click="_.move(ctrl.annotations,$index,$index-1)" ng-hide="$first" class="pointer fa fa-arrow-up"></i></td>
|
||||
<td style="width: 1%"><i ng-click="_.move(ctrl.annotations,$index,$index+1)" ng-hide="$last" class="pointer fa fa-arrow-down"></i></td>
|
||||
<td style="width: 1%">
|
||||
<a ng-click="ctrl.edit(annotation)" class="btn btn-inverse btn-mini">
|
||||
<i class="fa fa-edit"></i>
|
||||
Edit
|
||||
</a>
|
||||
</td>
|
||||
<td style="width: 1%">
|
||||
<a ng-click="ctrl.removeAnnotation(annotation)" class="btn btn-danger btn-mini" ng-hide="annotation.builtIn">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="gf-form" ng-show="ctrl.mode === 'list'">
|
||||
<div class="gf-form-button-row">
|
||||
<a type="button" class="btn gf-form-button btn-success" ng-click="ctrl.setupNew()"><i class="fa fa-plus" ></i> New</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="annotations-basic-settings" ng-if="ctrl.mode === 'edit' || ctrl.mode === 'new'">
|
||||
<div>
|
||||
<div class="gf-form-group">
|
||||
<h5 class="section-heading">General</h5>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">Name</span>
|
||||
<input type="text" class="gf-form-input width-20" ng-model='ctrl.currentAnnotation.name' placeholder="name"></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">Data source</span>
|
||||
<div class="gf-form-select-wrapper">
|
||||
<select class="gf-form-input" ng-model="ctrl.currentAnnotation.datasource" ng-options="f.name as f.name for f in ctrl.datasources" ng-change="ctrl.datasourceChanged()"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline">
|
||||
<gf-form-switch class="gf-form"
|
||||
label="Enabled"
|
||||
checked="ctrl.currentAnnotation.enable"
|
||||
on-change="ctrl.annotationEnabledChange()"
|
||||
label-class="width-7">
|
||||
</gf-form-switch>
|
||||
<gf-form-switch class="gf-form"
|
||||
label="Hidden"
|
||||
tooltip="Hides the annotation query toggle from showing at the top of the dashboard"
|
||||
checked="ctrl.currentAnnotation.hide"
|
||||
on-change="ctrl.annotationHiddenChanged()"
|
||||
label-class="width-7">
|
||||
</gf-form-switch>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-9">Color</label>
|
||||
<span class="gf-form-label">
|
||||
<color-picker color="ctrl.currentAnnotation.iconColor" onChange="ctrl.onColorChange"></color-picker>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="section-heading">Query</h5>
|
||||
<rebuild-on-change property="ctrl.currentDatasource">
|
||||
<plugin-component type="annotations-query-ctrl">
|
||||
</plugin-component>
|
||||
</rebuild-on-change>
|
||||
|
||||
<div class="gf-form">
|
||||
<div class="gf-form-button-row p-y-0">
|
||||
<button ng-show="ctrl.mode === 'new'" type="button" class="btn gf-form-button btn-success" ng-click="ctrl.add()">Add</button>
|
||||
<button ng-show="ctrl.mode === 'edit'" type="button" class="btn btn-success pull-left" ng-click="ctrl.update()">Update</button>
|
||||
<!-- empty list cta, there is always one built in query -->
|
||||
<div ng-if="ctrl.annotations.length === 1" class="p-t-2">
|
||||
<div class="empty-list-cta">
|
||||
<div class="empty-list-cta__title">There are no custom annotation queries added yet</div>
|
||||
<a ng-click="ctrl.setupNew()" class="empty-list-cta__button btn btn-xlarge btn-success">
|
||||
<i class="gicon gicon-dashboard-new"></i>
|
||||
Add Annotation Query
|
||||
</a>
|
||||
<div class="grafana-info-box">
|
||||
<h5>What are Annotations?</h5>
|
||||
<p>
|
||||
Annotations provide a way to integrate event data into your graphs. They are visualized as vertical lines and icons
|
||||
on all graph panels. When you hover over an annotation icon you can get event text & tags for the event. You can add annotation events
|
||||
directly from grafana by holding CTRL or CMD + click on graph (or drag region). These will be stored in Grafana's annotation database.
|
||||
</p>
|
||||
Checkout the <a class="external-link" target="_blank" href="http://docs.grafana.org/reference/annotations/">Annotations documentation</a> for more information.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="annotations-basic-settings" ng-if="ctrl.mode === 'edit' || ctrl.mode === 'new'">
|
||||
<div class="gf-form-group">
|
||||
<h5 class="section-heading">General</h5>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">Name</span>
|
||||
<input type="text" class="gf-form-input width-20" ng-model='ctrl.currentAnnotation.name' placeholder="name"></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">Data source</span>
|
||||
<div class="gf-form-select-wrapper">
|
||||
<select class="gf-form-input" ng-model="ctrl.currentAnnotation.datasource" ng-options="f.name as f.name for f in ctrl.datasources" ng-change="ctrl.datasourceChanged()"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline">
|
||||
<gf-form-switch class="gf-form" label="Enabled" checked="ctrl.currentAnnotation.enable" label-class="width-7">
|
||||
</gf-form-switch>
|
||||
<gf-form-switch class="gf-form" label="Hidden" tooltip="Hides the annotation query toggle from showing at the top of the dashboard" checked="ctrl.currentAnnotation.hide" label-class="width-7">
|
||||
</gf-form-switch>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-9">Color</label>
|
||||
<span class="gf-form-label">
|
||||
<color-picker color="ctrl.currentAnnotation.iconColor" onChange="ctrl.onColorChange"></color-picker>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="section-heading">Query</h5>
|
||||
<rebuild-on-change property="ctrl.currentDatasource">
|
||||
<plugin-component type="annotations-query-ctrl">
|
||||
</plugin-component>
|
||||
</rebuild-on-change>
|
||||
|
||||
<div class="gf-form">
|
||||
<div class="gf-form-button-row p-y-0">
|
||||
<button ng-show="ctrl.mode === 'new'" type="button" class="btn gf-form-button btn-success" ng-click="ctrl.add()">Add</button>
|
||||
<button ng-show="ctrl.mode === 'edit'" type="button" class="btn btn-success pull-left" ng-click="ctrl.update()">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -26,8 +26,9 @@ import './acl/acl';
|
||||
import './folder_picker/picker';
|
||||
import './folder_modal/folder';
|
||||
import './move_to_folder_modal/move_to_folder';
|
||||
import coreModule from 'app/core/core_module';
|
||||
import './settings/settings';
|
||||
|
||||
import coreModule from 'app/core/core_module';
|
||||
import {DashboardListCtrl} from './dashboard_list_ctrl';
|
||||
import {FolderDashboardsCtrl} from './folder_dashboards_ctrl';
|
||||
import {FolderPermissionsCtrl} from './folder_permissions_ctrl';
|
||||
|
||||
@@ -122,12 +122,6 @@ export class DashboardCtrl implements PanelContainer {
|
||||
this.$rootScope.$broadcast("refresh");
|
||||
}
|
||||
|
||||
onFolderChange(folder) {
|
||||
this.dashboard.folderId = folder.id;
|
||||
this.dashboard.meta.folderId = folder.id;
|
||||
this.dashboard.meta.folderTitle= folder.title;
|
||||
}
|
||||
|
||||
getPanelContainer() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ export class DashboardModel {
|
||||
graphTooltip: any;
|
||||
time: any;
|
||||
timepicker: any;
|
||||
hideControls: any;
|
||||
templating: any;
|
||||
annotations: any;
|
||||
refresh: any;
|
||||
@@ -67,7 +66,6 @@ export class DashboardModel {
|
||||
this.timezone = data.timezone || '';
|
||||
this.editable = data.editable !== false;
|
||||
this.graphTooltip = data.graphTooltip || 0;
|
||||
this.hideControls = data.hideControls || false;
|
||||
this.time = data.time || {from: 'now-6h', to: 'now'};
|
||||
this.timepicker = data.timepicker || {};
|
||||
this.templating = this.ensureListExist(data.templating);
|
||||
|
||||
@@ -27,40 +27,35 @@
|
||||
<i class="gicon gicon-add-panel"></i>
|
||||
</button>
|
||||
|
||||
<button class="btn navbar-button" ng-show="::ctrl.dashboard.meta.canStar" ng-click="ctrl.starDashboard()" bs-tooltip="'Mark as favorite'" data-placement="bottom">
|
||||
<button class="btn navbar-button navbar-button--star" ng-show="::ctrl.dashboard.meta.canStar" ng-click="ctrl.starDashboard()" bs-tooltip="'Mark as favorite'" data-placement="bottom">
|
||||
<i class="fa" ng-class="{'fa-star-o': !ctrl.dashboard.meta.isStarred, 'fa-star': ctrl.dashboard.meta.isStarred}"></i>
|
||||
</button>
|
||||
|
||||
<button class="btn navbar-button" ng-show="::ctrl.dashboard.meta.canShare" ng-click="ctrl.shareDashboard(0)" bs-tooltip="'Share dashboard'" data-placement="bottom">
|
||||
<button class="btn navbar-button navbar-button--share" ng-show="::ctrl.dashboard.meta.canShare" ng-click="ctrl.shareDashboard(0)" bs-tooltip="'Share dashboard'" data-placement="bottom">
|
||||
<i class="fa fa-share-square-o"></i></a>
|
||||
</button>
|
||||
|
||||
<button class="btn navbar-button" ng-show="::ctrl.dashboard.meta.canSave" ng-click="ctrl.saveDashboard()" bs-tooltip="'Save dashboard <br> CTRL+S'" data-placement="bottom">
|
||||
<button class="btn navbar-button navbar-button--save" ng-show="::ctrl.dashboard.meta.canSave" ng-click="ctrl.saveDashboard()" bs-tooltip="'Save dashboard <br> CTRL+S'" data-placement="bottom">
|
||||
<i class="fa fa-save"></i>
|
||||
</button>
|
||||
|
||||
<button class="btn navbar-button" ng-if="::ctrl.dashboard.snapshot.originalUrl" ng-href="{{ctrl.dashboard.snapshot.originalUrl}}" bs-tooltip="'Open original dashboard'" data-placement="bottom">
|
||||
<button class="btn navbar-button navbar-button--snapshot-origin" ng-if="::ctrl.dashboard.snapshot.originalUrl" ng-href="{{ctrl.dashboard.snapshot.originalUrl}}" bs-tooltip="'Open original dashboard'" data-placement="bottom">
|
||||
<i class="fa fa-link"></i>
|
||||
</button>
|
||||
|
||||
<div class="dropdown">
|
||||
<button class="btn navbar-button" data-toggle="dropdown" bs-tooltip="'Settings'" data-placement="bottom">
|
||||
<i class="fa fa-cog"></i>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu dropdown-menu--navbar">
|
||||
<li ng-repeat="navItem in ::ctrl.navModel.menu" ng-class="{active: navItem.active}">
|
||||
<a class="pointer" ng-href="{{::navItem.url}}" ng-click="ctrl.navItemClicked(navItem, $event)">
|
||||
<i class="{{::navItem.icon}}" ng-show="::navItem.icon"></i>
|
||||
{{::navItem.title}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button class="btn navbar-button navbar-button--settings" ng-click="ctrl.toggleSettings()" bs-tooltip="'Settings'" data-placement="bottom">
|
||||
<i class="fa fa-cog"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<gf-time-picker class="gf-timepicker-nav" dashboard="ctrl.dashboard" ng-if="!ctrl.dashboard.timepicker.hidden"></gf-time-picker>
|
||||
|
||||
<div class="navbar-buttons navbar-buttons--close">
|
||||
<button class="btn navbar-button navbar-button--primary" ng-click="ctrl.close()" bs-tooltip="'Back to dashboard'" data-placement="bottom">
|
||||
<i class="fa fa-reply"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<dashboard-search></dashboard-search>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import angular from 'angular';
|
||||
import {appEvents, NavModel} from 'app/core/core';
|
||||
@@ -15,13 +14,11 @@ export class DashNavCtrl {
|
||||
private $rootScope,
|
||||
private dashboardSrv,
|
||||
private $location,
|
||||
private backendSrv,
|
||||
public playlistSrv,
|
||||
navModelSrv) {
|
||||
this.navModel = navModelSrv.getDashboardNav(this.dashboard, this);
|
||||
|
||||
appEvents.on('save-dashboard', this.saveDashboard.bind(this), $scope);
|
||||
appEvents.on('delete-dashboard', this.deleteDashboard.bind(this), $scope);
|
||||
|
||||
if (this.dashboard.meta.isSnapshot) {
|
||||
var meta = this.dashboard.meta;
|
||||
@@ -32,13 +29,26 @@ export class DashNavCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
openEditView(editview) {
|
||||
var search = _.extend(this.$location.search(), {editview: editview});
|
||||
toggleSettings() {
|
||||
let search = this.$location.search();
|
||||
if (search.editview) {
|
||||
delete search.editview;
|
||||
} else {
|
||||
search.editview = 'settings';
|
||||
}
|
||||
this.$location.search(search);
|
||||
}
|
||||
|
||||
showHelpModal() {
|
||||
appEvents.emit('show-modal', {templateHtml: '<help-modal></help-modal>'});
|
||||
close() {
|
||||
let search = this.$location.search();
|
||||
if (search.editview) {
|
||||
delete search.editview;
|
||||
}
|
||||
if (search.fullscreen) {
|
||||
delete search.fullscreen;
|
||||
delete search.edit;
|
||||
}
|
||||
this.$location.search(search);
|
||||
}
|
||||
|
||||
starDashboard() {
|
||||
@@ -63,73 +73,10 @@ export class DashNavCtrl {
|
||||
angular.element(evt.currentTarget).tooltip('hide');
|
||||
}
|
||||
|
||||
makeEditable() {
|
||||
this.dashboard.editable = true;
|
||||
|
||||
return this.dashboardSrv.saveDashboard({makeEditable: true, overwrite: false}).then(() => {
|
||||
// force refresh whole page
|
||||
window.location.href = window.location.href;
|
||||
});
|
||||
}
|
||||
|
||||
exitFullscreen() {
|
||||
this.$rootScope.appEvent('panel-change-view', {fullscreen: false, edit: false});
|
||||
}
|
||||
|
||||
saveDashboard() {
|
||||
return this.dashboardSrv.saveDashboard();
|
||||
}
|
||||
|
||||
deleteDashboard() {
|
||||
var confirmText = '';
|
||||
var text2 = this.dashboard.title;
|
||||
|
||||
const alerts = _.sumBy(this.dashboard.panels, panel => {
|
||||
return panel.alert ? 1 : 0;
|
||||
});
|
||||
|
||||
if (alerts > 0) {
|
||||
confirmText = 'DELETE';
|
||||
text2 = `This dashboard contains ${alerts} alerts. Deleting this dashboard will also delete those alerts`;
|
||||
}
|
||||
|
||||
appEvents.emit('confirm-modal', {
|
||||
title: 'Delete',
|
||||
text: 'Do you want to delete this dashboard?',
|
||||
text2: text2,
|
||||
icon: 'fa-trash',
|
||||
confirmText: confirmText,
|
||||
yesText: 'Delete',
|
||||
onConfirm: () => {
|
||||
this.dashboard.meta.canSave = false;
|
||||
this.deleteDashboardConfirmed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
deleteDashboardConfirmed() {
|
||||
this.backendSrv.delete('/api/dashboards/db/' + this.dashboard.meta.slug).then(() => {
|
||||
appEvents.emit('alert-success', ['Dashboard Deleted', this.dashboard.title + ' has been deleted']);
|
||||
this.$location.url('/');
|
||||
});
|
||||
}
|
||||
|
||||
saveDashboardAs() {
|
||||
return this.dashboardSrv.showSaveAsModal();
|
||||
}
|
||||
|
||||
viewJson() {
|
||||
var clone = this.dashboard.getSaveModelClone();
|
||||
|
||||
this.$rootScope.appEvent('show-json-editor', {
|
||||
object: clone,
|
||||
});
|
||||
}
|
||||
|
||||
onFolderChange(folderId) {
|
||||
this.dashboard.folderId = folderId;
|
||||
}
|
||||
|
||||
showSearch() {
|
||||
this.$rootScope.appEvent('show-dash-search');
|
||||
}
|
||||
|
||||
@@ -1,146 +1,118 @@
|
||||
<div class="tabbed-view-header">
|
||||
<h2 class="tabbed-view-title">
|
||||
Version history
|
||||
</h2>
|
||||
<h3 class="dashboard-settings__header">
|
||||
<a ng-click="ctrl.switchMode('list')">Versions</a>
|
||||
<span ng-show="ctrl.mode === 'compare'">
|
||||
> Comparing {{ctrl.baseInfo.version}}
|
||||
<i class="fa fa-arrows-h"></i>
|
||||
{{ctrl.newInfo.version}}
|
||||
<cite class="muted" ng-if="ctrl.isNewLatest">(Latest)</cite>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<ul class="gf-tabs">
|
||||
<li class="gf-tabs-item" >
|
||||
<a class="gf-tabs-link" ng-click="ctrl.switchMode('list');" ng-class="{active: ctrl.mode === 'list'}">
|
||||
List
|
||||
</a>
|
||||
</li>
|
||||
<li class="gf-tabs-item" ng-show="ctrl.mode === 'compare'">
|
||||
<span class="active gf-tabs-link">
|
||||
Version Comparison
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div ng-if="ctrl.mode === 'list'">
|
||||
<div ng-if="ctrl.loading">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
<em>Fetching history list…</em>
|
||||
</div>
|
||||
|
||||
<button class="tabbed-view-close-btn" ng-click="ctrl.dismiss();">
|
||||
<i class="fa fa-remove"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div ng-if="!ctrl.loading">
|
||||
<div class="gf-form-group">
|
||||
<table class="filter-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="width-4"></th>
|
||||
<th class="width-4">Version</th>
|
||||
<th class="width-14">Date</th>
|
||||
<th class="width-10">Updated By</th>
|
||||
<th>Notes</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="revision in ctrl.revisions">
|
||||
<td class="filter-table__switch-cell" bs-tooltip="!revision.checked && ctrl.canCompare ? 'You can only compare 2 versions at a time' : ''" data-placement="right">
|
||||
<gf-form-switch switch-class="gf-form-switch--table-cell" checked="revision.checked" on-change="ctrl.revisionSelectionChanged()" ng-disabled="!revision.checked && ctrl.canCompare">
|
||||
</gf-form-switch>
|
||||
</td>
|
||||
<td class="text-center">{{revision.version}}</td>
|
||||
<td>{{revision.createdDateString}}</td>
|
||||
<td>{{revision.createdBy}}</td>
|
||||
<td>{{revision.message}}</td>
|
||||
<td class="text-right">
|
||||
<a class="btn btn-inverse btn-small" ng-show="revision.version !== ctrl.dashboard.version" ng-click="ctrl.restore(revision.version)">
|
||||
<i class="fa fa-history"></i> Restore
|
||||
</a>
|
||||
<a class="btn btn-outline-disabled btn-small" ng-show="revision.version === ctrl.dashboard.version">
|
||||
<i class="fa fa-check"></i> Latest
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="tabbed-view-body">
|
||||
|
||||
<div ng-if="ctrl.mode === 'list'">
|
||||
<div ng-if="ctrl.loading">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
<em>Fetching history list…</em>
|
||||
</div>
|
||||
|
||||
<div ng-if="!ctrl.loading">
|
||||
<div class="gf-form-group">
|
||||
<table class="filter-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="width-4"></th>
|
||||
<th class="width-4">Version</th>
|
||||
<th class="width-14">Date</th>
|
||||
<th class="width-10">Updated By</th>
|
||||
<th>Notes</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="revision in ctrl.revisions">
|
||||
<td class="filter-table__switch-cell" bs-tooltip="!revision.checked && ctrl.canCompare ? 'You can only compare 2 versions at a time' : ''" data-placement="right">
|
||||
<gf-form-switch switch-class="gf-form-switch--table-cell"
|
||||
checked="revision.checked"
|
||||
on-change="ctrl.revisionSelectionChanged()"
|
||||
ng-disabled="!revision.checked && ctrl.canCompare">
|
||||
</gf-form-switch>
|
||||
</td>
|
||||
<td class="text-center">{{revision.version}}</td>
|
||||
<td>{{revision.createdDateString}}</td>
|
||||
<td>{{revision.createdBy}}</td>
|
||||
<td>{{revision.message}}</td>
|
||||
<td class="text-right">
|
||||
<a class="btn btn-inverse btn-small" ng-show="revision.version !== ctrl.dashboard.version" ng-click="ctrl.restore(revision.version)">
|
||||
<i class="fa fa-history"></i> Restore
|
||||
</a>
|
||||
<a class="btn btn-outline-disabled btn-small" ng-show="revision.version === ctrl.dashboard.version">
|
||||
<i class="fa fa-check"></i> Latest
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div ng-if="ctrl.appending">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
<em>Fetching more entries…</em>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-group" ng-show="ctrl.mode === 'list'">
|
||||
<div class="gf-form-button-row">
|
||||
<button type="button"
|
||||
class="btn gf-form-button btn-secondary"
|
||||
ng-if="ctrl.revisions.length > 1"
|
||||
ng-disabled="!ctrl.canCompare"
|
||||
ng-click="ctrl.getDiff(ctrl.diff)"
|
||||
bs-tooltip="ctrl.canCompare ? '' : 'Select 2 versions to start comparing'" data-placement="bottom">
|
||||
<i class="fa fa-code-fork" ></i> Compare versions
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn gf-form-button btn-inverse"
|
||||
ng-if="ctrl.revisions.length >= ctrl.limit"
|
||||
ng-click="ctrl.addToLog()"
|
||||
ng-disabled="ctrl.isLastPage()">
|
||||
Show more versions
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="edit-tab-with-sidemenu" ng-if="ctrl.mode === 'compare'">
|
||||
<aside class="edit-sidemenu-aside">
|
||||
<ul class="edit-sidemenu">
|
||||
<li ng-class="{active: ctrl.diff === 'basic'}"><a ng-click="ctrl.getDiff('basic')" href="">Change Summary</a></li>
|
||||
<li ng-class="{active: ctrl.diff === 'html'}"><a ng-click="ctrl.getDiff('json')" href="">JSON Diff</a></li>
|
||||
</ul>
|
||||
</aside>
|
||||
|
||||
<div class="edit-tab-content">
|
||||
<div ng-if="ctrl.loading">
|
||||
<div ng-if="ctrl.appending">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
<em>Fetching changes…</em>
|
||||
<em>Fetching more entries…</em>
|
||||
</div>
|
||||
|
||||
<div ng-if="!ctrl.loading">
|
||||
<a type="button"
|
||||
class="btn gf-form-button btn-secondary pull-right"
|
||||
ng-click="ctrl.restore(ctrl.baseInfo.version)"
|
||||
ng-if="ctrl.isNewLatest">
|
||||
<i class="fa fa-history" ></i> Restore to version {{ctrl.baseInfo.version}}
|
||||
</a>
|
||||
<h4>
|
||||
Comparing Version {{ctrl.baseInfo.version}}
|
||||
<i class="fa fa-arrows-h"></i>
|
||||
Version {{ctrl.newInfo.version}}
|
||||
<cite class="muted" ng-if="ctrl.isNewLatest">(Latest)</cite>
|
||||
</h4>
|
||||
<section>
|
||||
<p class="small muted">
|
||||
<strong>Version {{ctrl.newInfo.version}}</strong> updated by
|
||||
<span>{{ctrl.newInfo.createdBy}} </span>
|
||||
<span>{{ctrl.newInfo.ageString}}</span>
|
||||
<span> - {{ctrl.newInfo.message}}</span>
|
||||
</p>
|
||||
<p class="small muted">
|
||||
<strong>Version {{ctrl.baseInfo.version}}</strong> updated by
|
||||
<span>{{ctrl.baseInfo.createdBy}} </span>
|
||||
<span>{{ctrl.baseInfo.ageString}}</span>
|
||||
<span> - {{ctrl.baseInfo.message}}</span>
|
||||
</p>
|
||||
</section>
|
||||
<div id="delta" diff-delta>
|
||||
<div class="delta-basic" ng-show="ctrl.diff === 'basic'" compile="ctrl.delta.basic"></div>
|
||||
<div class="delta-html" ng-show="ctrl.diff === 'json'" compile="ctrl.delta.json"></div>
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-button-row">
|
||||
<button type="button"
|
||||
class="btn gf-form-button btn-inverse"
|
||||
ng-if="ctrl.revisions.length >= ctrl.limit"
|
||||
ng-click="ctrl.addToLog()"
|
||||
ng-disabled="ctrl.isLastPage()">
|
||||
Show more versions
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-success"
|
||||
ng-if="ctrl.revisions.length > 1"
|
||||
ng-disabled="!ctrl.canCompare"
|
||||
ng-click="ctrl.getDiff(ctrl.diff)"
|
||||
bs-tooltip="ctrl.canCompare ? '' : 'Select 2 versions to start comparing'" data-placement="bottom">
|
||||
<i class="fa fa-code-fork" ></i> Compare versions
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="ctrl.mode === 'compare'">
|
||||
<div ng-if="ctrl.loading">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
<em>Fetching changes…</em>
|
||||
</div>
|
||||
|
||||
<div ng-if="!ctrl.loading">
|
||||
<button type="button"
|
||||
class="btn btn-danger pull-right"
|
||||
ng-click="ctrl.restore(ctrl.baseInfo.version)"
|
||||
ng-if="ctrl.isNewLatest">
|
||||
<i class="fa fa-history" ></i> Restore to version {{ctrl.baseInfo.version}}
|
||||
</button>
|
||||
<section>
|
||||
<p class="small muted">
|
||||
<strong>Version {{ctrl.newInfo.version}}</strong> updated by
|
||||
<span>{{ctrl.newInfo.createdBy}} </span>
|
||||
<span>{{ctrl.newInfo.ageString}}</span>
|
||||
<span> - {{ctrl.newInfo.message}}</span>
|
||||
</p>
|
||||
<p class="small muted">
|
||||
<strong>Version {{ctrl.baseInfo.version}}</strong> updated by
|
||||
<span>{{ctrl.baseInfo.createdBy}} </span>
|
||||
<span>{{ctrl.baseInfo.ageString}}</span>
|
||||
<span> - {{ctrl.baseInfo.message}}</span>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<div id="delta" diff-delta>
|
||||
<div class="delta-basic" compile="ctrl.delta.basic"></div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-button-row">
|
||||
<button class="btn btn-secondary" ng-click="ctrl.getDiff('json')">View JSON Diff</button>
|
||||
</div>
|
||||
|
||||
<div class="delta-html" ng-show="ctrl.diff === 'json'" compile="ctrl.delta.json"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
///<reference path="../../../headers/common.d.ts" />
|
||||
|
||||
import './history_srv';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
<div class="modal-body" ng-controller="AddAnnotationModalCtrl">
|
||||
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-header-title">
|
||||
Add Annotation
|
||||
</h2>
|
||||
|
||||
<a class="modal-header-close" ng-click="ctrl.close()">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal-content">
|
||||
<div class="share-modal-body">
|
||||
<div class="share-modal-header">
|
||||
|
||||
<div class="share-modal-big-icon">
|
||||
<i class="fa fa-tag"></i>
|
||||
</div>
|
||||
|
||||
<div class="share-modal-content">
|
||||
|
||||
<div class="gf-form-group share-modal-options">
|
||||
<p class="share-modal-info-text">
|
||||
Add annotation details.
|
||||
</p>
|
||||
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-8">Title</span>
|
||||
<input type="text" ng-model="ctrl.annotation.title" class="gf-form-input max-width-20">
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-8" ng-if="!ctrl.annotation.timeTo">Time</span>
|
||||
<span class="gf-form-label width-8" ng-if="ctrl.annotation.timeTo">Time Start</span>
|
||||
<input type="text" ng-model="ctrl.annotation.time" class="gf-form-input max-width-20">
|
||||
</div>
|
||||
<div class="gf-form" ng-if="ctrl.annotation.timeTo">
|
||||
<span class="gf-form-label width-8">Time Stop</span>
|
||||
<input type="text" ng-model="ctrl.annotation.timeTo" class="gf-form-input max-width-20">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h6>Description</h6>
|
||||
</div>
|
||||
<div class="gf-form-group share-modal-options">
|
||||
<div class="gf-form">
|
||||
<textarea rows="3" class="gf-form-input width-27" ng-model="ctrl.annotation.text"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-button-row">
|
||||
<button class="btn gf-form-btn width-10 btn-success" ng-click="ctrl.addAnnotation()">
|
||||
<i class="fa fa-pencil"></i>
|
||||
Add Annotation
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,95 +0,0 @@
|
||||
<div class="tabbed-view-header">
|
||||
<h2 class="tabbed-view-title">
|
||||
Settings
|
||||
</h2>
|
||||
|
||||
<ul class="gf-tabs">
|
||||
<li class="gf-tabs-item" ng-repeat="tab in ::['General', 'Links', 'Time picker']">
|
||||
<a class="gf-tabs-link" ng-click="ctrl.editTab = $index" ng-class="{active: ctrl.editTab === $index}">
|
||||
{{::tab}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<button class="tabbed-view-close-btn" ng-click="dismiss();">
|
||||
<i class="fa fa-remove"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="tabbed-view-body">
|
||||
<div ng-if="ctrl.editTab == 0">
|
||||
|
||||
<div class="gf-form-group section">
|
||||
<h5 class="section-heading">Details</h5>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-7">Name</label>
|
||||
<input type="text" class="gf-form-input width-30" ng-model='ctrl.dashboard.title'></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-7">Description</label>
|
||||
<input type="text" class="gf-form-input width-30" ng-model='ctrl.dashboard.description'></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-7">
|
||||
Tags
|
||||
<info-popover mode="right-normal">Press enter to add a tag</info-popover>
|
||||
</label>
|
||||
<bootstrap-tagsinput ng-model="ctrl.dashboard.tags" tagclass="label label-tag" placeholder="add tags">
|
||||
</bootstrap-tagsinput>
|
||||
</div>
|
||||
<folder-picker ng-if="!ctrl.dashboard.meta.isFolder"
|
||||
initial-folder-id="ctrl.dashboard.folderId"
|
||||
on-change="ctrl.onFolderChange($folder)"
|
||||
label-class="width-7">
|
||||
</folder-picker>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h5 class="section-heading">Options</h5>
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-11">Timezone</label>
|
||||
<div class="gf-form-select-wrapper">
|
||||
<select ng-model="ctrl.dashboard.timezone" class='gf-form-input' ng-options="f.value as f.text for f in [{value: '', text: 'Default'}, {value: 'browser', text: 'Local browser time'},{value: 'utc', text: 'UTC'}]" ng-change="timezoneChanged()"></select>
|
||||
</div>
|
||||
</div>
|
||||
<gf-form-switch class="gf-form"
|
||||
label="Editable"
|
||||
tooltip="Uncheck, then save and reload to disable all dashboard editing"
|
||||
checked="ctrl.dashboard.editable"
|
||||
label-class="width-11">
|
||||
</gf-form-switch>
|
||||
<gf-form-switch class="gf-form"
|
||||
label="Hide Controls"
|
||||
tooltip="Hide row controls. Shortcut: CTRL+H or CMD+H"
|
||||
checked="ctrl.dashboard.hideControls"
|
||||
label-class="width-11">
|
||||
</gf-form-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h5 class="section-heading">Panel Options</h5>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-11">
|
||||
Graph Tooltip
|
||||
<info-popover mode="right-normal">
|
||||
Cycle between options using Shortcut: CTRL+O or CMD+O
|
||||
</info-popover>
|
||||
</label>
|
||||
<div class="gf-form-select-wrapper">
|
||||
<select ng-model="ctrl.dashboard.graphTooltip" class='gf-form-input' ng-options="f.value as f.text for f in [{value: 0, text: 'Default'}, {value: 1, text: 'Shared crosshair'},{value: 2, text: 'Shared Tooltip'}]"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="editor.index == 1">
|
||||
<dash-links-editor></dash-links-editor>
|
||||
</div>
|
||||
|
||||
<div ng-if="editor.index == 2">
|
||||
<gf-time-picker-settings dashboard="ctrl.dashboard"></gf-time-picker-settings>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,5 +1,3 @@
|
||||
///<reference path="../../headers/common.d.ts" />
|
||||
|
||||
import coreModule from 'app/core/core_module';
|
||||
|
||||
const template = `
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
<aside class="dashboard-settings__aside">
|
||||
<h2 class="dashboard-settings__aside-header">
|
||||
<i class="fa fa-cog"></i>
|
||||
Settings
|
||||
</h2>
|
||||
|
||||
<a href="{{::section.url}}" class="dashboard-settings__nav-item" ng-class="{active: ctrl.viewId === section.id}" ng-repeat="section in ctrl.sections">
|
||||
<i class="{{::section.icon}}"></i>
|
||||
{{::section.title}}
|
||||
</a>
|
||||
|
||||
<div class="dashboard-settings__aside-actions">
|
||||
<button class="btn btn-inverse" ng-click="ctrl.openSaveAsModal()" ng-show="ctrl.canSaveAs">
|
||||
<i class="fa fa-copy"></i>
|
||||
Save As...
|
||||
</button>
|
||||
|
||||
<button class="btn btn-danger" ng-click="ctrl.deleteDashboard()" ng-show="ctrl.canDelete">
|
||||
<i class="fa fa-trash"></i>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="dashboard-settings__content" ng-if="ctrl.viewId === 'settings'">
|
||||
<h3 class="dashboard-settings__header m-b-1">
|
||||
General
|
||||
</h3>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-7">Name</label>
|
||||
<input type="text" class="gf-form-input width-30" ng-model='ctrl.dashboard.title'></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-7">Description</label>
|
||||
<input type="text" class="gf-form-input width-30" ng-model='ctrl.dashboard.description'></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-7">
|
||||
Tags
|
||||
<info-popover mode="right-normal">Press enter to add a tag</info-popover>
|
||||
</label>
|
||||
<bootstrap-tagsinput ng-model="ctrl.dashboard.tags" tagclass="label label-tag" placeholder="add tags">
|
||||
</bootstrap-tagsinput>
|
||||
</div>
|
||||
<folder-picker initial-title="ctrl.dashboard.meta.folderTitle"
|
||||
initial-folder-id="ctrl.dashboard.folderId"
|
||||
on-change="ctrl.onFolderChange($folder)"
|
||||
label-class="width-7">
|
||||
</folder-picker>
|
||||
<gf-form-switch class="gf-form" label="Editable" tooltip="Uncheck, then save and reload to disable all dashboard editing" checked="ctrl.dashboard.editable" label-class="width-7">
|
||||
</gf-form-switch>
|
||||
</div>
|
||||
|
||||
<gf-time-picker-settings dashboard="ctrl.dashboard"></gf-time-picker-settings>
|
||||
|
||||
<h5 class="section-heading">Panel Options</h5>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-11">
|
||||
Graph Tooltip
|
||||
<info-popover mode="right-normal">
|
||||
Cycle between options using Shortcut: CTRL+O or CMD+O
|
||||
</info-popover>
|
||||
</label>
|
||||
<div class="gf-form-select-wrapper">
|
||||
<select ng-model="ctrl.dashboard.graphTooltip" class='gf-form-input' ng-options="f.value as f.text for f in [{value: 0, text: 'Default'}, {value: 1, text: 'Shared crosshair'},{value: 2, text: 'Shared Tooltip'}]"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-settings__content" ng-if="ctrl.viewId === 'annotations'" ng-include="'public/app/features/annotations/partials/editor.html'">
|
||||
</div>
|
||||
|
||||
<div class="dashboard-settings__content" ng-if="ctrl.viewId === 'templating'" ng-include="'public/app/features/templating/partials/editor.html'">
|
||||
</div>
|
||||
|
||||
<div class="dashboard-settings__content" ng-if="ctrl.viewId === 'links'" >
|
||||
<dash-links-editor></dash-links-editor>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-settings__content" ng-if="ctrl.viewId === 'versions'" >
|
||||
<gf-dashboard-history dashboard="dashboard"></gf-dashboard-history>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-settings__content" ng-if="ctrl.viewId === 'view_json'" >
|
||||
<h3 class="dashboard-settings__header">View JSON</h3>
|
||||
|
||||
<div class="gf-form">
|
||||
<textarea class="gf-form-input" ng-model="ctrl.json" rows="30" spellcheck="false"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-settings__content" ng-if="ctrl.viewId === '404'">
|
||||
<h3 class="dashboard-settings__header">Settings view not found</h3>
|
||||
|
||||
<div>
|
||||
<h5>The settings page could not be found or you do not have permission to access it</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-settings__content" ng-if="ctrl.viewId === 'make_editable'">
|
||||
<h3 class="dashboard-settings__header">Make Editable</h3>
|
||||
|
||||
<button class="btn btn-success" ng-click="ctrl.makeEditable()">
|
||||
Make Editable
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
import { coreModule, appEvents, contextSrv } from 'app/core/core';
|
||||
import { DashboardModel } from '../dashboard_model';
|
||||
import $ from 'jquery';
|
||||
import _ from 'lodash';
|
||||
|
||||
export class SettingsCtrl {
|
||||
dashboard: DashboardModel;
|
||||
isOpen: boolean;
|
||||
viewId: string;
|
||||
json: string;
|
||||
alertCount: number;
|
||||
canSaveAs: boolean;
|
||||
canDelete: boolean;
|
||||
sections: any[];
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private $scope, private $location, private $rootScope, private backendSrv, private dashboardSrv) {
|
||||
// temp hack for annotations and variables editors
|
||||
// that rely on inherited scope
|
||||
$scope.dashboard = this.dashboard;
|
||||
|
||||
this.$scope.$on('$destroy', () => {
|
||||
this.dashboard.updateSubmenuVisibility();
|
||||
this.$rootScope.$broadcast('refresh');
|
||||
});
|
||||
|
||||
this.canSaveAs = contextSrv.isEditor;
|
||||
this.canDelete = this.dashboard.meta.canSave;
|
||||
|
||||
this.buildSectionList();
|
||||
this.onRouteUpdated();
|
||||
|
||||
$rootScope.onAppEvent('$routeUpdate', this.onRouteUpdated.bind(this), $scope);
|
||||
}
|
||||
|
||||
buildSectionList() {
|
||||
this.sections = [];
|
||||
if (this.dashboard.meta.canEdit) {
|
||||
this.sections.push({ title: 'General', id: 'settings', icon: 'fa fa-fw fa-sliders' });
|
||||
this.sections.push({ title: 'Annotations', id: 'annotations', icon: 'fa fa-fw fa-comment-o' });
|
||||
this.sections.push({ title: 'Variables', id: 'templating', icon: 'fa fa-fw fa-dollar' });
|
||||
this.sections.push({ title: 'Links', id: 'links', icon: 'fa fa-fw fa-external-link' });
|
||||
|
||||
if (this.dashboard.id) {
|
||||
this.sections.push({ title: 'Versions', id: 'versions', icon: 'fa fa-fw fa-history' });
|
||||
}
|
||||
}
|
||||
|
||||
if (contextSrv.isEditor && !this.dashboard.editable) {
|
||||
this.sections.push({ title: 'Make Editable', icon: 'fa fa-fw fa-edit', id: 'make_editable' });
|
||||
this.viewId = 'make_editable';
|
||||
}
|
||||
|
||||
this.sections.push({ title: 'View JSON', id: 'view_json', icon: 'fa fa-fw fa-code' });
|
||||
|
||||
const params = this.$location.search();
|
||||
const url = this.$location.path();
|
||||
|
||||
for (let section of this.sections) {
|
||||
const sectionParams = _.defaults({ editview: section.id }, params);
|
||||
section.url = url + '?' + $.param(sectionParams);
|
||||
}
|
||||
}
|
||||
|
||||
onRouteUpdated() {
|
||||
this.viewId = this.$location.search().editview;
|
||||
|
||||
if (this.viewId) {
|
||||
this.json = JSON.stringify(this.dashboard.getSaveModelClone(), null, 2);
|
||||
}
|
||||
|
||||
const currentSection = _.find(this.sections, { id: this.viewId });
|
||||
if (!currentSection) {
|
||||
this.sections.unshift({ title: 'Not found', id: '404', icon: 'fa fa-fw fa-warning' });
|
||||
this.viewId = '404';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
openSaveAsModal() {
|
||||
this.dashboardSrv.showSaveAsModal();
|
||||
}
|
||||
|
||||
hideSettings() {
|
||||
var urlParams = this.$location.search();
|
||||
delete urlParams.editview;
|
||||
setTimeout(() => {
|
||||
this.$rootScope.$apply(() => {
|
||||
this.$location.search(urlParams);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
makeEditable() {
|
||||
this.dashboard.editable = true;
|
||||
|
||||
return this.dashboardSrv.saveDashboard({ makeEditable: true, overwrite: false }).then(() => {
|
||||
// force refresh whole page
|
||||
window.location.href = window.location.href;
|
||||
});
|
||||
}
|
||||
|
||||
deleteDashboard() {
|
||||
var confirmText = '';
|
||||
var text2 = this.dashboard.title;
|
||||
|
||||
const alerts = _.sumBy(this.dashboard.panels, panel => {
|
||||
return panel.alert ? 1 : 0;
|
||||
});
|
||||
|
||||
if (alerts > 0) {
|
||||
confirmText = 'DELETE';
|
||||
text2 = `This dashboard contains ${alerts} alerts. Deleting this dashboard will also delete those alerts`;
|
||||
}
|
||||
|
||||
appEvents.emit('confirm-modal', {
|
||||
title: 'Delete',
|
||||
text: 'Do you want to delete this dashboard?',
|
||||
text2: text2,
|
||||
icon: 'fa-trash',
|
||||
confirmText: confirmText,
|
||||
yesText: 'Delete',
|
||||
onConfirm: () => {
|
||||
this.dashboard.meta.canSave = false;
|
||||
this.deleteDashboardConfirmed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
deleteDashboardConfirmed() {
|
||||
this.backendSrv.delete('/api/dashboards/db/' + this.dashboard.meta.slug).then(() => {
|
||||
appEvents.emit('alert-success', ['Dashboard Deleted', this.dashboard.title + ' has been deleted']);
|
||||
this.$location.url('/');
|
||||
});
|
||||
}
|
||||
|
||||
onFolderChange(folder) {
|
||||
this.dashboard.folderId = folder.id;
|
||||
this.dashboard.meta.folderId = folder.id;
|
||||
this.dashboard.meta.folderTitle = folder.title;
|
||||
}
|
||||
}
|
||||
|
||||
export function dashboardSettings() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'public/app/features/dashboard/settings/settings.html',
|
||||
controller: SettingsCtrl,
|
||||
bindToController: true,
|
||||
controllerAs: 'ctrl',
|
||||
transclude: true,
|
||||
scope: { dashboard: '=' },
|
||||
};
|
||||
}
|
||||
|
||||
coreModule.directive('dashboardSettings', dashboardSettings);
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SaveDashboardAsModalCtrl } from '../save_as_modal';
|
||||
import { SaveDashboardAsModalCtrl } from '../save_as_modal;
|
||||
import { describe, it, expect } from 'test/lib/common';
|
||||
|
||||
describe('saving dashboard as', () => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<div class="submenu-controls">
|
||||
|
||||
<div ng-repeat="variable in ctrl.variables" ng-hide="variable.hide === 2" class="submenu-item gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label template-variable" ng-hide="variable.hide === 1">
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
<div class="row pull-right">
|
||||
<form name="timeForm" class="gf-timepicker-absolute-section">
|
||||
<h3>Time range</h3>
|
||||
|
||||
<label class="small">From:</label>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-28">
|
||||
<input type="text" class="gf-form-input input-large" ng-model="ctrl.editTimeRaw.from" input-datetime>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<button class="btn gf-form-btn btn-primary" type="button" ng-click="openFromPicker=!openFromPicker">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="openFromPicker">
|
||||
<datepicker ng-model="ctrl.absolute.fromJs" class="gf-timepicker-component" show-weeks="false" starting-day="ctrl.firstDayOfWeek" ng-change="ctrl.absoluteFromChanged()"></datepicker>
|
||||
</div>
|
||||
|
||||
|
||||
<label class="small">To:</label>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-28">
|
||||
<input type="text" class="gf-form-input input-large" ng-model="ctrl.editTimeRaw.to" input-datetime>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<button class="btn gf-form-btn btn-primary" type="button" ng-click="openToPicker=!openToPicker">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="openToPicker">
|
||||
<datepicker ng-model="ctrl.absolute.toJs" class="gf-timepicker-component" show-weeks="false" starting-day="ctrl.firstDayOfWeek" ng-change="ctrl.absoluteToChanged()"></datepicker>
|
||||
</div>
|
||||
|
||||
<label class="small">Refreshing every:</label>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-28">
|
||||
<select ng-model="ctrl.refresh.value" class="gf-form-input input-medium" ng-options="f.value as f.text for f in ctrl.refresh.options"></select>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<button type="submit" class="btn gf-form-btn btn-secondary" ng-click="ctrl.applyCustom();" ng-disabled="!timeForm.$valid">Apply</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<div class="gf-timepicker-relative-section">
|
||||
<h3>Quick ranges</h3>
|
||||
<ul ng-repeat="group in ctrl.timeOptions">
|
||||
<li bindonce ng-repeat='option in group' ng-class="{active: option.active}">
|
||||
<a ng-click="ctrl.setRelativeFilter(option)" bo-text="option.display"></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
<div class="editor-row">
|
||||
<h5 class="section-heading">Time Options</h5>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Auto-refresh</span>
|
||||
<input type="text" class="gf-form-input max-width-25" ng-model="ctrl.panel.refresh_intervals" array-join>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Now delay now-</span>
|
||||
<input type="text" class="gf-form-input max-width-25" ng-model="ctrl.panel.nowDelay" placeholder="0m" valid-time-span bs-tooltip="'Enter 1m to ignore the last minute (because it can contain incomplete metrics)'"
|
||||
data-placement="right">
|
||||
</div>
|
||||
<gf-form-switch class="gf-form" label="Hide time picker" checked="ctrl.panel.hidden" label-class="width-10"></gf-form-switch>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-10">Timezone</label>
|
||||
<div class="gf-form-select-wrapper">
|
||||
<select ng-model="ctrl.dashboard.timezone" class='gf-form-input' ng-options="f.value as f.text for f in [{value: '', text: 'Default'}, {value: 'browser', text: 'Local browser time'},{value: 'utc', text: 'UTC'}]" ng-change="timezoneChanged()"></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Auto-refresh</span>
|
||||
<input type="text" class="gf-form-input max-width-25" ng-model="ctrl.panel.refresh_intervals" array-join>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Now delay now-</span>
|
||||
<input type="text" class="gf-form-input max-width-25" ng-model="ctrl.panel.nowDelay" placeholder="0m" valid-time-span bs-tooltip="'Enter 1m to ignore the last minute (because it can contain incomplete metrics)'"
|
||||
data-placement="right">
|
||||
</div>
|
||||
|
||||
<gf-form-switch class="gf-form" label="Hide time picker" checked="ctrl.panel.hidden" label-class="width-10"></gf-form-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,3 +24,62 @@
|
||||
<i class="fa fa-refresh"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div ng-if="ctrl.isOpen" class="gf-timepicker-dropdown">
|
||||
<form name="timeForm" class="gf-timepicker-absolute-section">
|
||||
<h3 class="section-heading">Custom range</h3>
|
||||
|
||||
<label class="small">From:</label>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-28">
|
||||
<input type="text" class="gf-form-input input-large" ng-model="ctrl.editTimeRaw.from" input-datetime>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<button class="btn gf-form-btn btn-primary" type="button" ng-click="openFromPicker=!openFromPicker">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="openFromPicker">
|
||||
<datepicker ng-model="ctrl.absolute.fromJs" class="gf-timepicker-component" show-weeks="false" starting-day="ctrl.firstDayOfWeek" ng-change="ctrl.absoluteFromChanged()"></datepicker>
|
||||
</div>
|
||||
|
||||
|
||||
<label class="small">To:</label>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-28">
|
||||
<input type="text" class="gf-form-input input-large" ng-model="ctrl.editTimeRaw.to" input-datetime>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<button class="btn gf-form-btn btn-primary" type="button" ng-click="openToPicker=!openToPicker">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="openToPicker">
|
||||
<datepicker ng-model="ctrl.absolute.toJs" class="gf-timepicker-component" show-weeks="false" starting-day="ctrl.firstDayOfWeek" ng-change="ctrl.absoluteToChanged()"></datepicker>
|
||||
</div>
|
||||
|
||||
<label class="small">Refreshing every:</label>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-28">
|
||||
<select ng-model="ctrl.refresh.value" class="gf-form-input input-medium" ng-options="f.value as f.text for f in ctrl.refresh.options"></select>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<button type="submit" class="btn gf-form-btn btn-secondary" ng-click="ctrl.applyCustom();" ng-disabled="!timeForm.$valid">Apply</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="gf-timepicker-relative-section">
|
||||
<h3 class="section-heading">Quick ranges</h3>
|
||||
<ul ng-repeat="group in ctrl.timeOptions">
|
||||
<li bindonce ng-repeat='option in group' ng-class="{active: option.active}">
|
||||
<a ng-click="ctrl.setRelativeFilter(option)" bo-text="option.display"></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
///<reference path="../../../headers/common.d.ts" />
|
||||
|
||||
import _ from 'lodash';
|
||||
import angular from 'angular';
|
||||
import moment from 'moment';
|
||||
@@ -25,10 +23,12 @@ export class TimePickerCtrl {
|
||||
refresh: any;
|
||||
isUtc: boolean;
|
||||
firstDayOfWeek: number;
|
||||
closeDropdown: any;
|
||||
isOpen: boolean;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private $scope, private $rootScope, private timeSrv) {
|
||||
$scope.ctrl = this;
|
||||
this.$scope.ctrl = this;
|
||||
|
||||
$rootScope.onAppEvent('shift-time-forward', () => this.move(1), $scope);
|
||||
$rootScope.onAppEvent('shift-time-backward', () => this.move(-1), $scope);
|
||||
@@ -96,6 +96,11 @@ export class TimePickerCtrl {
|
||||
}
|
||||
|
||||
openDropdown() {
|
||||
if (this.isOpen) {
|
||||
this.isOpen = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.onRefresh();
|
||||
this.editTimeRaw = this.timeRaw;
|
||||
this.timeOptions = rangeUtil.getRelativeTimesList(this.panel, this.rangeString);
|
||||
@@ -107,12 +112,7 @@ export class TimePickerCtrl {
|
||||
};
|
||||
|
||||
this.refresh.options.unshift({text: 'off'});
|
||||
|
||||
this.$rootScope.appEvent('show-dash-editor', {
|
||||
editview: 'timepicker',
|
||||
scope: this.$scope,
|
||||
cssClass: 'gf-timepicker-dropdown',
|
||||
});
|
||||
this.isOpen = true;
|
||||
}
|
||||
|
||||
applyCustom() {
|
||||
@@ -121,7 +121,7 @@ export class TimePickerCtrl {
|
||||
}
|
||||
|
||||
this.timeSrv.setTime(this.editTimeRaw);
|
||||
this.$rootScope.appEvent('hide-dash-editor');
|
||||
this.isOpen = false;
|
||||
}
|
||||
|
||||
absoluteFromChanged() {
|
||||
@@ -144,7 +144,7 @@ export class TimePickerCtrl {
|
||||
}
|
||||
|
||||
this.timeSrv.setTime(range);
|
||||
this.$rootScope.appEvent('hide-dash-editor');
|
||||
this.isOpen = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -175,7 +175,6 @@ export function timePickerDirective() {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
angular.module('grafana.directives').directive('gfTimePickerSettings', settingsDirective);
|
||||
angular.module('grafana.directives').directive('gfTimePicker', timePickerDirective);
|
||||
|
||||
|
||||
@@ -1,80 +1,77 @@
|
||||
<div class="editor-row">
|
||||
<h5 class="section-heading">Links and Dash Navigation</h5>
|
||||
<h3 class="dashboard-settings__header">
|
||||
Dashboard Links
|
||||
</h3>
|
||||
|
||||
<div ng-repeat="link in dashboard.links">
|
||||
|
||||
<div class="gf-form-group gf-form-inline">
|
||||
<div class="section">
|
||||
<div ng-repeat="link in dashboard.links">
|
||||
<div class="gf-form-group gf-form-inline">
|
||||
<div class="section">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-8">Type</span>
|
||||
<div class="gf-form-select-wrapper width-10">
|
||||
<select class="gf-form-input" ng-model="link.type" ng-options="f for f in ['dashboards','link']" ng-change="updated()"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form" ng-show="link.type === 'dashboards'">
|
||||
<span class="gf-form-label width-8">With tags</span>
|
||||
<bootstrap-tagsinput ng-model="link.tags" tagclass="label label-tag" placeholder="add tags" style="margin-right: .25rem"></bootstrap-tagsinput>
|
||||
</div>
|
||||
<gf-form-switch ng-show="link.type === 'dashboards'" class="gf-form" label="As dropdown" checked="link.asDropdown" switch-class="max-width-4" label-class="width-8" on-change="updated()"></gf-form-switch>
|
||||
<div class="gf-form" ng-show="link.type === 'dashboards' && link.asDropdown">
|
||||
<span class="gf-form-label width-8">Title</span>
|
||||
<input type="text" ng-model="link.title" class="gf-form-input max-width-10" ng-model-onblur ng-change="updated()">
|
||||
</div>
|
||||
<div ng-show="link.type === 'link'">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-8">Type</span>
|
||||
<div class="gf-form-select-wrapper width-10">
|
||||
<select class="gf-form-input" ng-model="link.type" ng-options="f for f in ['dashboards','link']" ng-change="updated()"></select>
|
||||
</div>
|
||||
<li class="gf-form-label width-8">Url</li>
|
||||
<input type="text" ng-model="link.url" class="gf-form-input width-20" ng-model-onblur ng-change="updated()">
|
||||
</div>
|
||||
<div class="gf-form" ng-show="link.type === 'dashboards'">
|
||||
<span class="gf-form-label width-8">With tags</span>
|
||||
<bootstrap-tagsinput ng-model="link.tags" tagclass="label label-tag" placeholder="add tags" style="margin-right: .25rem"></bootstrap-tagsinput>
|
||||
</div>
|
||||
<gf-form-switch ng-show="link.type === 'dashboards'" class="gf-form" label="As dropdown" checked="link.asDropdown" switch-class="max-width-4" label-class="width-8" on-change="updated()"></gf-form-switch>
|
||||
<div class="gf-form" ng-show="link.type === 'dashboards' && link.asDropdown">
|
||||
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-8">Title</span>
|
||||
<input type="text" ng-model="link.title" class="gf-form-input max-width-10" ng-model-onblur ng-change="updated()">
|
||||
<input type="text" ng-model="link.title" class="gf-form-input width-20" ng-model-onblur ng-change="updated()">
|
||||
</div>
|
||||
<div ng-show="link.type === 'link'">
|
||||
<div class="gf-form">
|
||||
<li class="gf-form-label width-8">Url</li>
|
||||
<input type="text" ng-model="link.url" class="gf-form-input width-20" ng-model-onblur ng-change="updated()">
|
||||
</div>
|
||||
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-8">Title</span>
|
||||
<input type="text" ng-model="link.title" class="gf-form-input width-20" ng-model-onblur ng-change="updated()">
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-8">Tooltip</span>
|
||||
<input type="text" ng-model="link.tooltip" class="gf-form-input width-20" placeholder="Open dashboard" ng-model-onblur ng-change="updated()">
|
||||
</div>
|
||||
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-8">Tooltip</span>
|
||||
<input type="text" ng-model="link.tooltip" class="gf-form-input width-20" placeholder="Open dashboard" ng-model-onblur ng-change="updated()">
|
||||
</div>
|
||||
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-8">Icon</span>
|
||||
<div class="gf-form-select-wrapper width-20">
|
||||
<select class="gf-form-input" ng-model="link.icon" ng-options="k as k for (k, v) in iconMap" ng-change="updated()"></select>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-8">Icon</span>
|
||||
<div class="gf-form-select-wrapper width-20">
|
||||
<select class="gf-form-input" ng-model="link.icon" ng-options="k as k for (k, v) in iconMap" ng-change="updated()"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section gf-form-inline" style="display: flex">
|
||||
<div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-6">Include</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<gf-form-switch class="gf-form" label="Time range" checked="link.keepTime" switch-class="max-width-6" label-class="width-9"></gf-form-switch>
|
||||
<gf-form-switch class="gf-form" label="Variable values" checked="link.includeVars" switch-class="max-width-6" label-class="width-9"></gf-form-switch>
|
||||
<gf-form-switch class="gf-form" label="Open in new tab" checked="link.targetBlank" switch-class="max-width-6" label-class="width-9"></gf-form-switch>
|
||||
<div class="section gf-form-inline" style="display: flex">
|
||||
<div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-6">Include</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<gf-form-switch class="gf-form" label="Time range" checked="link.keepTime" switch-class="max-width-6" label-class="width-9"></gf-form-switch>
|
||||
<gf-form-switch class="gf-form" label="Variable values" checked="link.includeVars" switch-class="max-width-6" label-class="width-9"></gf-form-switch>
|
||||
<gf-form-switch class="gf-form" label="Open in new tab" checked="link.targetBlank" switch-class="max-width-6" label-class="width-9"></gf-form-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex; flex-direction:column; justify-content:flex-start">
|
||||
<div class="gf-form">
|
||||
<button class="btn btn-inverse gf-form-btn width-4" ng-click="deleteLink($index)">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<button class="btn btn-inverse gf-form-btn width-4" ng-click="moveLink($index, -1)" ng-hide="$first"><i class="fa fa-arrow-up"></i></button>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<button class="btn btn-inverse gf-form-btn width-4" ng-click="moveLink($index, 1)" ng-hide="$last"><i class="fa fa-arrow-down"></i></button>
|
||||
</div>
|
||||
<div style="display:flex; flex-direction:column; justify-content:flex-start">
|
||||
<div class="gf-form">
|
||||
<button class="btn btn-inverse gf-form-btn width-4" ng-click="deleteLink($index)">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<button class="btn btn-inverse gf-form-btn width-4" ng-click="moveLink($index, -1)" ng-hide="$first"><i class="fa fa-arrow-up"></i></button>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<button class="btn btn-inverse gf-form-btn width-4" ng-click="moveLink($index, 1)" ng-hide="$last"><i class="fa fa-arrow-down"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<button class="btn btn-inverse" ng-click="addLink()"><i class="fa fa-plus"></i> Add link</button>
|
||||
|
||||
@@ -134,20 +134,27 @@ export class PanelCtrl {
|
||||
getMenu() {
|
||||
let menu = [];
|
||||
menu.push({text: 'View', click: 'ctrl.viewPanel();', icon: "fa fa-fw fa-eye", shortcut: "v"});
|
||||
menu.push({text: 'Edit', click: 'ctrl.editPanel();', role: 'Editor', icon: "fa fa-fw fa-edit", shortcut: "e"});
|
||||
|
||||
if (this.dashboard.meta.canEdit) {
|
||||
menu.push({text: 'Edit', click: 'ctrl.editPanel();', role: 'Editor', icon: "fa fa-fw fa-edit", shortcut: "e"});
|
||||
}
|
||||
|
||||
menu.push({text: 'Share', click: 'ctrl.sharePanel();', icon: "fa fa-fw fa-share", shortcut: "p s"});
|
||||
|
||||
let extendedMenu = this.getExtendedMenu();
|
||||
menu.push({text: 'More ...', click: 'ctrl.removePanel();', icon: "fa fa-fw fa-cube", submenu: extendedMenu});
|
||||
|
||||
menu.push({divider: true, role: 'Editor'});
|
||||
menu.push({text: 'Remove', click: 'ctrl.removePanel();', role: 'Editor', icon: "fa fa-fw fa-trash", shortcut: "p r"});
|
||||
if (this.dashboard.meta.canEdit) {
|
||||
menu.push({divider: true, role: 'Editor'});
|
||||
menu.push({text: 'Remove', click: 'ctrl.removePanel();', role: 'Editor', icon: "fa fa-fw fa-trash", shortcut: "p r"});
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
getExtendedMenu() {
|
||||
let menu = [];
|
||||
if (!this.fullscreen) {
|
||||
if (!this.fullscreen && this.dashboard.meta.canEdit) {
|
||||
menu.push({ text: 'Duplicate', click: 'ctrl.duplicate()', role: 'Editor' });
|
||||
}
|
||||
menu.push({text: 'Panel JSON', click: 'ctrl.editPanelJson(); dismiss();' });
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
///<reference path="../../headers/common.d.ts" />
|
||||
|
||||
import _ from 'lodash';
|
||||
import coreModule from 'app/core/core_module';
|
||||
import {variableTypes} from './variable';
|
||||
@@ -45,6 +43,10 @@ export class VariableEditorCtrl {
|
||||
});
|
||||
};
|
||||
|
||||
$scope.setMode = function(mode) {
|
||||
$scope.mode = mode;
|
||||
};
|
||||
|
||||
$scope.add = function() {
|
||||
if ($scope.isValid()) {
|
||||
variableSrv.addVariable($scope.current);
|
||||
|
||||
@@ -1,45 +1,43 @@
|
||||
<div ng-controller="VariableEditorCtrl" ng-init="init()">
|
||||
<div class="tabbed-view-header">
|
||||
<h2 class="tabbed-view-title">
|
||||
Templating
|
||||
</h2>
|
||||
|
||||
<ul class="gf-tabs">
|
||||
<li class="gf-tabs-item" >
|
||||
<a class="gf-tabs-link" ng-click="mode = 'list';" ng-class="{active: mode === 'list'}">
|
||||
Variables
|
||||
</a>
|
||||
</li>
|
||||
<li class="gf-tabs-item" ng-show="mode === 'edit'">
|
||||
<a class="gf-tabs-link" ng-class="{active: mode === 'edit'}">
|
||||
Edit
|
||||
</a>
|
||||
</li>
|
||||
<li class="gf-tabs-item" ng-show="mode === 'new'">
|
||||
<span class="active gf-tabs-link">New</span>
|
||||
</li>
|
||||
<li class="gf-tabs-item" >
|
||||
<a class="gf-tabs-link" ng-click="mode = 'help';" ng-class="{active: mode === 'help'}">
|
||||
Help
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3 class="dashboard-settings__header">
|
||||
<a ng-click="setMode('list')">Variables</a>
|
||||
<span ng-show="mode === 'new'">> New</span>
|
||||
<span ng-show="mode === 'edit'">> Edit</span>
|
||||
</h3>
|
||||
|
||||
<button class="tabbed-view-close-btn" ng-click="dismiss();">
|
||||
<i class="fa fa-remove"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div ng-if="mode === 'list'">
|
||||
|
||||
<div class="tabbed-view-body">
|
||||
<div ng-if="variables.length === 0">
|
||||
<div class="empty-list-cta">
|
||||
<div class="empty-list-cta__title">There are no variables added yet</div>
|
||||
<a ng-click="setMode('new')" class="empty-list-cta__button btn btn-xlarge btn-success">
|
||||
<i class="gicon gicon-dashboard-new"></i>
|
||||
Add variable
|
||||
</a>
|
||||
<div class="grafana-info-box">
|
||||
<h5>What does variables do?</h5>
|
||||
<p>Variables enables more interactive and dynamic dashboards. Instead of hard-coding things like server or sensor names
|
||||
in your metric queries you can use variables in their place. Variables are shown as dropdown select boxes at the top of
|
||||
the dashboard. These dropdowns make it easy to change the data being displayed in your dashboard.
|
||||
|
||||
<div ng-if="mode === 'list'">
|
||||
<div ng-if="variables.length === 0">
|
||||
<em>No template variables defined</em>
|
||||
<br /> <br />
|
||||
Checkout the
|
||||
<a class="external-link" href="http://docs.grafana.org/reference/templating/" target="_blank">
|
||||
Templating documentation
|
||||
</a> for more information.
|
||||
</div>
|
||||
</div>
|
||||
<table class="filter-table filter-table--hover">
|
||||
<thead>
|
||||
<tr>
|
||||
</div>
|
||||
|
||||
<div ng-if="variables.length">
|
||||
<div class="page-action-bar">
|
||||
<div class="page-action-bar__spacer"></div>
|
||||
<a type="button" class="btn btn-success" ng-click="setMode('new');"><i class="fa fa-plus" ></i> New</a>
|
||||
</div>
|
||||
|
||||
<table class="filter-table filter-table--hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Variable</th>
|
||||
<th>Definition</th>
|
||||
<th colspan="5"></th>
|
||||
@@ -55,7 +53,6 @@
|
||||
<td style="max-width: 200px;" ng-click="edit(variable)" class="pointer max-width">
|
||||
{{variable.query}}
|
||||
</td>
|
||||
|
||||
<td style="width: 1%"><i ng-click="_.move(variables,$index,$index-1)" ng-hide="$first" class="pointer fa fa-arrow-up"></i></td>
|
||||
<td style="width: 1%"><i ng-click="_.move(variables,$index,$index+1)" ng-hide="$last" class="pointer fa fa-arrow-down"></i></td>
|
||||
<td style="width: 1%">
|
||||
@@ -70,256 +67,236 @@
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-show="mode === 'help'">
|
||||
<div class="grafana-info-box col-lg-8">
|
||||
<h5>What does templating do?</h5>
|
||||
<p>Templating allows for more interactive and dynamic dashboards. Instead of hard-coding things like server, application
|
||||
and sensor name in your metric queries you can use variables in their place. Variables are shown as dropdown select boxes at the top of
|
||||
the dashboard. These dropdowns make it easy to change the data being displayed in your dashboard.
|
||||
<br>
|
||||
<br>
|
||||
<form ng-if="mode === 'edit' || mode === 'new'" name="ctrl.form">
|
||||
<h5 class="section-heading">General</h5>
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-19">
|
||||
<span class="gf-form-label width-6">Name</span>
|
||||
<input type="text" class="gf-form-input" name="name" placeholder="name" ng-model='current.name' required ng-pattern="namePattern"></input>
|
||||
</div>
|
||||
<div class="gf-form max-width-19">
|
||||
<span class="gf-form-label width-6">
|
||||
Type
|
||||
<info-popover mode="right-normal">
|
||||
{{variableTypes[current.type].description}}
|
||||
</info-popover>
|
||||
</span>
|
||||
<div class="gf-form-select-wrapper max-width-17">
|
||||
<select class="gf-form-input" ng-model="current.type" ng-options="k as v.name for (k, v) in variableTypes" ng-change="typeChanged()"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Checkout the <a class="external-link" target="_blank" href="http://docs.grafana.org/reference/templating/">Templating documentation</a> for more information.
|
||||
</p>
|
||||
<div class="gf-form" ng-show="ctrl.form.name.$error.pattern">
|
||||
<span class="gf-form-label gf-form-label--error">Template names cannot begin with '__' that's reserved for Grafanas global variables</span>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-19">
|
||||
<span class="gf-form-label width-6">Label</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.label' placeholder="optional display name"></input>
|
||||
</div>
|
||||
<div class="gf-form max-width-19">
|
||||
<span class="gf-form-label width-6">Hide</span>
|
||||
<div class="gf-form-select-wrapper max-width-15">
|
||||
<select class="gf-form-input" ng-model="current.hide" ng-options="f.value as f.text for f in hideOptions"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form" ng-show="mode === 'list'">
|
||||
<div class="gf-form-button-row">
|
||||
<a type="button" class="btn gf-form-button btn-success" ng-click="mode = 'new';"><i class="fa fa-plus" ></i> New</a>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="current.type === 'interval'" class="gf-form-group">
|
||||
<h5 class="section-heading">Interval Options</h5>
|
||||
|
||||
<form ng-if="mode === 'edit' || mode === 'new'" name="ctrl.form">
|
||||
<h5 class="section-heading">Variable</h5>
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-19">
|
||||
<span class="gf-form-label width-6">Name</span>
|
||||
<input type="text" class="gf-form-input" name="name" placeholder="name" ng-model='current.name' required ng-pattern="namePattern"></input>
|
||||
</div>
|
||||
<div class="gf-form max-width-19">
|
||||
<span class="gf-form-label width-6">
|
||||
Type
|
||||
<info-popover mode="right-normal">
|
||||
{{variableTypes[current.type].description}}
|
||||
</info-popover>
|
||||
</span>
|
||||
<div class="gf-form-select-wrapper max-width-17">
|
||||
<select class="gf-form-input" ng-model="current.type" ng-options="k as v.name for (k, v) in variableTypes" ng-change="typeChanged()"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-9">Values</span>
|
||||
<input type="text" class="gf-form-input" placeholder="name" ng-model='current.query' placeholder="1m,10m,1h,6h,1d,7d" ng-model-onblur ng-change="runQuery()" required></input>
|
||||
</div>
|
||||
|
||||
<div class="gf-form" ng-show="ctrl.form.name.$error.pattern">
|
||||
<span class="gf-form-label gf-form-label--error">Template names cannot begin with '__' that's reserved for Grafanas global variables</span>
|
||||
</div>
|
||||
<div class="gf-form-inline">
|
||||
<gf-form-switch class="gf-form" label="Auto Option" label-class="width-9" checked="current.auto" on-change="runQuery()">
|
||||
</gf-form-switch>
|
||||
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-19">
|
||||
<span class="gf-form-label width-6">Label</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.label' placeholder="optional display name"></input>
|
||||
</div>
|
||||
<div class="gf-form max-width-19">
|
||||
<span class="gf-form-label width-6">Hide</span>
|
||||
<div class="gf-form-select-wrapper max-width-15">
|
||||
<select class="gf-form-input" ng-model="current.hide" ng-options="f.value as f.text for f in hideOptions"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-9" ng-show="current.auto">
|
||||
Step count <tip>How many times should the current time range be divided to calculate the value</tip>
|
||||
</span>
|
||||
<div class="gf-form-select-wrapper max-width-10" ng-show="current.auto">
|
||||
<select class="gf-form-input" ng-model="current.auto_count" ng-options="f for f in [1,2,3,4,5,10,20,30,40,50,100,200,300,400,500]" ng-change="runQuery()"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label" ng-show="current.auto">
|
||||
Min interval <tip>The calculated value will not go below this threshold</tip>
|
||||
</span>
|
||||
<input type="text" class="gf-form-input max-width-10" ng-show="current.auto" ng-model="current.auto_min" ng-change="runQuery()" placeholder="10s"></input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="current.type === 'interval'" class="gf-form-group">
|
||||
<h5 class="section-heading">Interval Options</h5>
|
||||
<div ng-if="current.type === 'custom'" class="gf-form-group">
|
||||
<h5 class="section-heading">Custom Options</h5>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-14">Values separated by comma</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.query' ng-blur="runQuery()" placeholder="1, 10, 20, myvalue" required></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-9">Values</span>
|
||||
<input type="text" class="gf-form-input" placeholder="name" ng-model='current.query' placeholder="1m,10m,1h,6h,1d,7d" ng-model-onblur ng-change="runQuery()" required></input>
|
||||
</div>
|
||||
<div ng-if="current.type === 'constant'" class="gf-form-group">
|
||||
<h5 class="section-heading">Constant options</h5>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label">Value</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.query' ng-blur="runQuery()" placeholder="your metric prefix"></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-inline">
|
||||
<gf-form-switch class="gf-form" label="Auto Option" label-class="width-9" checked="current.auto" on-change="runQuery()">
|
||||
</gf-form-switch>
|
||||
<div ng-if="current.type === 'query'" class="gf-form-group">
|
||||
<h5 class="section-heading">Query Options</h5>
|
||||
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-9" ng-show="current.auto">
|
||||
Step count <tip>How many times should the current time range be divided to calculate the value</tip>
|
||||
</span>
|
||||
<div class="gf-form-select-wrapper max-width-10" ng-show="current.auto">
|
||||
<select class="gf-form-input" ng-model="current.auto_count" ng-options="f for f in [1,2,3,4,5,10,20,30,40,50,100,200,300,400,500]" ng-change="runQuery()"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label" ng-show="current.auto">
|
||||
Min interval <tip>The calculated value will not go below this threshold</tip>
|
||||
</span>
|
||||
<input type="text" class="gf-form-input max-width-10" ng-show="current.auto" ng-model="current.auto_min" ng-change="runQuery()" placeholder="10s"></input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-21">
|
||||
<span class="gf-form-label width-7">Data source</span>
|
||||
<div class="gf-form-select-wrapper max-width-14">
|
||||
<select class="gf-form-input" ng-model="current.datasource" ng-options="f.value as f.name for f in datasources" required>
|
||||
<option value="" ng-if="false"></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form max-width-21">
|
||||
<span class="gf-form-label width-7">
|
||||
Refresh
|
||||
<info-popover mode="right-normal">
|
||||
When to update the values of this variable.
|
||||
</info-popover>
|
||||
</span>
|
||||
<div class="gf-form-select-wrapper max-width-14">
|
||||
<select class="gf-form-input" ng-model="current.refresh" ng-options="f.value as f.text for f in refreshOptions"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">Query</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.query' placeholder="metric name or tags query" ng-model-onblur ng-change="runQuery()" required></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">
|
||||
Regex
|
||||
<info-popover mode="right-normal">
|
||||
Optional, if you want to extract part of a series name or metric node segment.
|
||||
</info-popover>
|
||||
</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.regex' placeholder="/.*-(.*)-.*/" ng-model-onblur ng-change="runQuery()"></input>
|
||||
</div>
|
||||
<div class="gf-form max-width-21">
|
||||
<span class="gf-form-label width-7">
|
||||
Sort
|
||||
<info-popover mode="right-normal">
|
||||
How to sort the values of this variable.
|
||||
</info-popover>
|
||||
</span>
|
||||
<div class="gf-form-select-wrapper max-width-14">
|
||||
<select class="gf-form-input" ng-model="current.sort" ng-options="f.value as f.text for f in sortOptions" ng-change="runQuery()"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="current.type === 'custom'" class="gf-form-group">
|
||||
<h5 class="section-heading">Custom Options</h5>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-14">Values separated by comma</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.query' ng-blur="runQuery()" placeholder="1, 10, 20, myvalue" required></input>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="current.type === 'datasource'" class="gf-form-group">
|
||||
<h5 class="section-heading">Data source options</h5>
|
||||
|
||||
<div ng-if="current.type === 'constant'" class="gf-form-group">
|
||||
<h5 class="section-heading">Constant options</h5>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label">Value</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.query' ng-blur="runQuery()" placeholder="your metric prefix"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-12">Type</label>
|
||||
<div class="gf-form-select-wrapper max-width-18">
|
||||
<select class="gf-form-input" ng-model="current.query" ng-options="f.value as f.text for f in datasourceTypes" ng-change="runQuery()"></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="current.type === 'query'" class="gf-form-group">
|
||||
<h5 class="section-heading">Query Options</h5>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-12">
|
||||
Instance name filter
|
||||
<info-popover mode="right-normal">
|
||||
Regex filter for which data source instances to choose from in
|
||||
the variable value dropdown. Leave empty for all.
|
||||
<br><br>
|
||||
Example: <code>/^prod/</code>
|
||||
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-21">
|
||||
<span class="gf-form-label width-7">Data source</span>
|
||||
<div class="gf-form-select-wrapper max-width-14">
|
||||
<select class="gf-form-input" ng-model="current.datasource" ng-options="f.value as f.name for f in datasources" required>
|
||||
<option value="" ng-if="false"></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form max-width-21">
|
||||
<span class="gf-form-label width-7">
|
||||
Refresh
|
||||
<info-popover mode="right-normal">
|
||||
When to update the values of this variable.
|
||||
</info-popover>
|
||||
</span>
|
||||
<div class="gf-form-select-wrapper max-width-14">
|
||||
<select class="gf-form-input" ng-model="current.refresh" ng-options="f.value as f.text for f in refreshOptions"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">Query</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.query' placeholder="metric name or tags query" ng-model-onblur ng-change="runQuery()" required></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">
|
||||
Regex
|
||||
<info-popover mode="right-normal">
|
||||
Optional, if you want to extract part of a series name or metric node segment.
|
||||
</info-popover>
|
||||
</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.regex' placeholder="/.*-(.*)-.*/" ng-model-onblur ng-change="runQuery()"></input>
|
||||
</div>
|
||||
<div class="gf-form max-width-21">
|
||||
<span class="gf-form-label width-7">
|
||||
Sort
|
||||
<info-popover mode="right-normal">
|
||||
How to sort the values of this variable.
|
||||
</info-popover>
|
||||
</span>
|
||||
<div class="gf-form-select-wrapper max-width-14">
|
||||
<select class="gf-form-input" ng-model="current.sort" ng-options="f.value as f.text for f in sortOptions" ng-change="runQuery()"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</info-popover>
|
||||
</label>
|
||||
<input type="text" class="gf-form-input max-width-18" ng-model='current.regex' placeholder="/.*-(.*)-.*/" ng-model-onblur ng-change="runQuery()"></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-show="current.type === 'datasource'" class="gf-form-group">
|
||||
<h5 class="section-heading">Data source options</h5>
|
||||
<div ng-if="current.type === 'adhoc'" class="gf-form-group">
|
||||
<h5 class="section-heading">Options</h5>
|
||||
<div class="gf-form max-width-21">
|
||||
<span class="gf-form-label width-8">Data source</span>
|
||||
<div class="gf-form-select-wrapper max-width-14">
|
||||
<select class="gf-form-input" ng-model="current.datasource" ng-options="f.value as f.name for f in datasources" required ng-change="validate()">
|
||||
<option value="" ng-if="false"></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-12">Type</label>
|
||||
<div class="gf-form-select-wrapper max-width-18">
|
||||
<select class="gf-form-input" ng-model="current.query" ng-options="f.value as f.text for f in datasourceTypes" ng-change="runQuery()"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section gf-form-group" ng-show="variableTypes[current.type].supportsMulti">
|
||||
<h5 class="section-heading">Selection Options</h5>
|
||||
<div class="section">
|
||||
<gf-form-switch class="gf-form"
|
||||
label="Multi-value"
|
||||
label-class="width-10"
|
||||
tooltip="Enables multiple values to be selected at the same time"
|
||||
checked="current.multi"
|
||||
on-change="runQuery()">
|
||||
</gf-form-switch>
|
||||
<gf-form-switch class="gf-form"
|
||||
label="Include All option"
|
||||
label-class="width-10"
|
||||
checked="current.includeAll"
|
||||
on-change="runQuery()">
|
||||
</gf-form-switch>
|
||||
</div>
|
||||
<div class="gf-form" ng-if="current.includeAll">
|
||||
<span class="gf-form-label width-10">Custom all value</span>
|
||||
<input type="text" class="gf-form-input max-width-15" ng-model='current.allValue' placeholder="blank = auto"></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-12">
|
||||
Instance name filter
|
||||
<info-popover mode="right-normal">
|
||||
Regex filter for which data source instances to choose from in
|
||||
the variable value dropdown. Leave empty for all.
|
||||
<br><br>
|
||||
Example: <code>/^prod/</code>
|
||||
<div class="gf-form-group" ng-if="current.type === 'query'">
|
||||
<h5>Value groups/tags (Experimental feature)</h5>
|
||||
<gf-form-switch class="gf-form" label="Enabled" label-class="width-10" checked="current.useTags" on-change="runQuery()">
|
||||
</gf-form-switch>
|
||||
<div class="gf-form last" ng-if="current.useTags">
|
||||
<span class="gf-form-label width-10">Tags query</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.tagsQuery' placeholder="metric name or tags query" ng-model-onblur></input>
|
||||
</div>
|
||||
<div class="gf-form" ng-if="current.useTags">
|
||||
<li class="gf-form-label width-10">Tag values query</li>
|
||||
<input type="text" class="gf-form-input" ng-model='current.tagValuesQuery' placeholder="apps.$tag.*" ng-model-onblur></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</info-popover>
|
||||
</label>
|
||||
<input type="text" class="gf-form-input max-width-18" ng-model='current.regex' placeholder="/.*-(.*)-.*/" ng-model-onblur ng-change="runQuery()"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form-group" ng-show="current.options.length">
|
||||
<h5>Preview of values (shows max 20)</h5>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form" ng-repeat="option in current.options | limitTo: 20">
|
||||
<span class="gf-form-label">{{option.text}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="current.type === 'adhoc'" class="gf-form-group">
|
||||
<h5 class="section-heading">Options</h5>
|
||||
<div class="gf-form max-width-21">
|
||||
<span class="gf-form-label width-8">Data source</span>
|
||||
<div class="gf-form-select-wrapper max-width-14">
|
||||
<select class="gf-form-input" ng-model="current.datasource" ng-options="f.value as f.name for f in datasources" required ng-change="validate()">
|
||||
<option value="" ng-if="false"></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-info gf-form-group" ng-if="infoText">
|
||||
{{infoText}}
|
||||
</div>
|
||||
|
||||
<div class="section gf-form-group" ng-show="variableTypes[current.type].supportsMulti">
|
||||
<h5 class="section-heading">Selection Options</h5>
|
||||
<div class="section">
|
||||
<gf-form-switch class="gf-form"
|
||||
label="Multi-value"
|
||||
label-class="width-10"
|
||||
tooltip="Enables multiple values to be selected at the same time"
|
||||
checked="current.multi"
|
||||
on-change="runQuery()">
|
||||
</gf-form-switch>
|
||||
<gf-form-switch class="gf-form"
|
||||
label="Include All option"
|
||||
label-class="width-10"
|
||||
checked="current.includeAll"
|
||||
on-change="runQuery()">
|
||||
</gf-form-switch>
|
||||
</div>
|
||||
<div class="gf-form" ng-if="current.includeAll">
|
||||
<span class="gf-form-label width-10">Custom all value</span>
|
||||
<input type="text" class="gf-form-input max-width-15" ng-model='current.allValue' placeholder="blank = auto"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form-button-row p-y-0">
|
||||
<button type="submit" class="btn btn-success" ng-show="mode === 'edit'" ng-click="update();">Update</button>
|
||||
<button type="submit" class="btn btn-success" ng-show="mode === 'new'" ng-click="add();">Add</button>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-group" ng-if="current.type === 'query'">
|
||||
<h5>Value groups/tags (Experimental feature)</h5>
|
||||
<gf-form-switch class="gf-form" label="Enabled" label-class="width-10" checked="current.useTags" on-change="runQuery()">
|
||||
</gf-form-switch>
|
||||
<div class="gf-form last" ng-if="current.useTags">
|
||||
<span class="gf-form-label width-10">Tags query</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.tagsQuery' placeholder="metric name or tags query" ng-model-onblur></input>
|
||||
</div>
|
||||
<div class="gf-form" ng-if="current.useTags">
|
||||
<li class="gf-form-label width-10">Tag values query</li>
|
||||
<input type="text" class="gf-form-input" ng-model='current.tagValuesQuery' placeholder="apps.$tag.*" ng-model-onblur></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-group" ng-show="current.options.length">
|
||||
<h5>Preview of values (shows max 20)</h5>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form" ng-repeat="option in current.options | limitTo: 20">
|
||||
<span class="gf-form-label">{{option.text}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info gf-form-group" ng-if="infoText">
|
||||
{{infoText}}
|
||||
</div>
|
||||
|
||||
<div class="gf-form-button-row p-y-0">
|
||||
<button type="submit" class="btn btn-success" ng-show="mode === 'edit'" ng-click="update();">Update</button>
|
||||
<button type="submit" class="btn btn-success" ng-show="mode === 'new'" ng-click="add();">Add</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal-content-confirm-text" ng-if="confirmText">
|
||||
<input type="text" class="gf-form-input width-16" style="display: inline-block;" placeholder="Type {{confirmText}} to confirm" ng-model="confirmInput" ng-change="updateConfirmText(confirmInput)">
|
||||
</div>
|
||||
|
||||
@@ -2,15 +2,17 @@
|
||||
<dashnav dashboard="ctrl.dashboard"></dashnav>
|
||||
|
||||
<div class="scroll-canvas scroll-canvas--dashboard" grafana-scrollbar>
|
||||
<div dash-editor-view class="dash-edit-view"></div>
|
||||
<div class="dashboard-container">
|
||||
<dashboard-settings dashboard="ctrl.dashboard"
|
||||
ng-if="ctrl.dashboardViewState.state.editview"
|
||||
class="dashboard-settings">
|
||||
</dashboard-settings>
|
||||
|
||||
<div class="dashboard-container">
|
||||
<dashboard-submenu ng-if="ctrl.dashboard.meta.submenuEnabled" dashboard="ctrl.dashboard">
|
||||
</dashboard-submenu>
|
||||
|
||||
<dashboard-grid get-panel-container="ctrl.getPanelContainer">
|
||||
</dashboard-grid>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
///<reference path="../../../headers/common.d.ts" />
|
||||
|
||||
import 'vendor/flot/jquery.flot';
|
||||
import 'vendor/flot/jquery.flot.selection';
|
||||
import 'vendor/flot/jquery.flot.time';
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
@import "components/dashboard_grid";
|
||||
@import "components/dashboard_list";
|
||||
@import "components/page_header";
|
||||
@import "components/dashboard_settings";
|
||||
@import "components/empty_list_cta";
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ $gray-5: #ECECEC;
|
||||
$gray-6: #f4f5f8;
|
||||
$gray-7: #fbfbfb;
|
||||
|
||||
// $gray-blue: #292a2d;
|
||||
$gray-blue: #212327;
|
||||
$input-black: #09090B;
|
||||
|
||||
@@ -100,6 +99,7 @@ $panel-border: solid 1px $panel-border-color;
|
||||
$panel-drop-zone-bg: repeating-linear-gradient(-128deg, #111, #111 10px, #191919 10px, #222 20px);
|
||||
$panel-header-hover-bg: $dark-4;
|
||||
$panel-header-menu-hover-bg: $dark-5;
|
||||
$panel-edit-shadow: 0 -30px 30px -30px $black;
|
||||
|
||||
// page header
|
||||
$page-header-bg: linear-gradient(90deg, #292a2d, black);
|
||||
@@ -192,7 +192,7 @@ $input-label-border-color: $dark-3;
|
||||
$input-invalid-border-color: lighten($red, 5%);
|
||||
|
||||
// Search
|
||||
$search-shadow: 0 0 35px 0 $body-bg;
|
||||
$search-shadow: 0 0 30px 0 $black;
|
||||
$search-filter-box-bg: $gray-blue;
|
||||
|
||||
// Dropdowns
|
||||
@@ -229,10 +229,10 @@ $horizontalComponentOffset: 180px;
|
||||
// -------------------------
|
||||
$wellBackground: #131517;
|
||||
|
||||
$navbarHeight: 52px;
|
||||
$navbarHeight: 55px;
|
||||
$navbarBackgroundHighlight: $dark-3;
|
||||
$navbarBackground: $panel-bg;
|
||||
$navbarBorder: 1px solid $body-bg;
|
||||
$navbarBorder: 1px solid $dark-3;
|
||||
$navbarShadow: 0 0 20px black;
|
||||
|
||||
$navbarText: $gray-4;
|
||||
|
||||
@@ -103,6 +103,7 @@ $panel-border: solid 1px $panel-border-color;
|
||||
$panel-drop-zone-bg: repeating-linear-gradient(-128deg, $body-bg, $body-bg 10px, $gray-6 10px, $gray-6 20px);
|
||||
$panel-header-hover-bg: $gray-6;
|
||||
$panel-header-menu-hover-bg: $gray-4;
|
||||
$panel-edit-shadow: 0 0 30px 20px $black;
|
||||
|
||||
// Page header
|
||||
$page-header-bg: linear-gradient(90deg, $white, $gray-7);
|
||||
|
||||
@@ -199,11 +199,11 @@ $form-icon-danger: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www
|
||||
// Try to avoid customizing these :)
|
||||
$zindex-dropdown: 1000;
|
||||
$zindex-navbar-fixed: 1020;
|
||||
$zindex-sidemenu: 1025;
|
||||
$zindex-tooltip: 1030;
|
||||
$zindex-modal-backdrop: 1040;
|
||||
$zindex-modal: 1050;
|
||||
$zindex-typeahead: 1060;
|
||||
$zindex-sidemenu: $zindex-navbar-fixed;
|
||||
|
||||
// Buttons
|
||||
//
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
text-transform: none;
|
||||
line-height: 1;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
|
||||
/* Better Font Rendering =========== */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
.dashboard-settings {
|
||||
opacity: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dashboard-page--settings-opening {
|
||||
.dashboard-container {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-page--settings-open {
|
||||
.dashboard-settings {
|
||||
opacity: 1;
|
||||
transition: opacity 300ms ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-settings__content {
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.dashboard-settings__aside {
|
||||
padding: 30px 0 0 30px;
|
||||
background: $panel-bg;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.dashboard-settings__aside-header {
|
||||
color: $text-muted;
|
||||
font-size: $font-size-h3;
|
||||
padding-right: 60px;
|
||||
white-space: nowrap;
|
||||
|
||||
i {
|
||||
font-size: 25px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-settings__header {
|
||||
font-size: $font-size-h3;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.dashboard-settings__nav-item {
|
||||
padding: 7px 12px;
|
||||
color: $text-color;
|
||||
font-size: $font-size-md;
|
||||
@include left-brand-border;
|
||||
|
||||
&.active {
|
||||
@include left-brand-border-gradient();
|
||||
background: $page-bg;
|
||||
}
|
||||
|
||||
i {
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-settings__aside-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
flex-grow: 1;
|
||||
margin: $spacer*3 $spacer*2 0 0;
|
||||
|
||||
button {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,24 @@
|
||||
.empty-list-cta {
|
||||
background-color: $search-filter-box-bg;
|
||||
text-align: center;
|
||||
.empty-list-cta {
|
||||
background-color: $search-filter-box-bg;
|
||||
text-align: center;
|
||||
padding: $spacer*2;
|
||||
border-radius: $border-radius;
|
||||
|
||||
.grafana-info-box {
|
||||
max-width: 700px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-list-cta__title {
|
||||
padding-bottom: 30px;
|
||||
font-style: italic;
|
||||
padding-bottom: $spacer*3;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.empty-list-cta__button {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.empty-list-cta__pro-tip {
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: $spacer*3;
|
||||
}
|
||||
|
||||
.empty-list-cta__pro-tip-link {
|
||||
margin-left: 5px;
|
||||
}
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ $input-border: 1px solid $input-border-color;
|
||||
padding: $input-padding-y $input-padding-x;
|
||||
flex-shrink: 0;
|
||||
font-weight: $font-weight-semi-bold;
|
||||
font-size: $font-size-sm;
|
||||
|
||||
background-color: $input-label-bg;
|
||||
display: block;
|
||||
@@ -84,6 +85,14 @@ $input-border: 1px solid $input-border-color;
|
||||
}
|
||||
}
|
||||
|
||||
.gf-form-label + .gf-form-label {
|
||||
margin-right: $gf-form-margin;
|
||||
}
|
||||
|
||||
.gf-form + .gf-form {
|
||||
margin-right: $gf-form-margin;
|
||||
}
|
||||
|
||||
.gf-form-pre {
|
||||
display: block;
|
||||
flex-grow: 1;
|
||||
@@ -253,9 +262,6 @@ $input-border: 1px solid $input-border-color;
|
||||
margin-right: $gf-form-margin;
|
||||
line-height: $input-line-height;
|
||||
font-size: $font-size-sm;
|
||||
box-shadow: none;
|
||||
@include border-radius($label-border-radius-sm);
|
||||
border: $input-btn-border-width solid transparent;
|
||||
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
// .grafana-info-box::before {
|
||||
// content: "\f05a";
|
||||
// font-family:'FontAwesome';
|
||||
// position: absolute;
|
||||
// top: -13px;
|
||||
// left: -8px;
|
||||
// font-size: 20px;
|
||||
// color: $text-color;
|
||||
// }
|
||||
|
||||
.grafana-info-box {
|
||||
position: relative;
|
||||
background: $info-box-background;
|
||||
|
||||
@@ -2,13 +2,57 @@
|
||||
.navbar {
|
||||
position: relative;
|
||||
margin-left: 40px;
|
||||
// box-shadow: $navbarShadow;
|
||||
z-index: $zindex-navbar-fixed;
|
||||
// background: $navbarBackground;
|
||||
height: $navbarHeight;
|
||||
padding-right: $spacer;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
border-bottom: 1px solid transparent;
|
||||
transition: all 350ms ease-in-out;
|
||||
}
|
||||
|
||||
@mixin navbar-alt-look() {
|
||||
background: $page-header-bg;
|
||||
box-shadow: $search-shadow;
|
||||
border-bottom: $navbarBorder;
|
||||
}
|
||||
|
||||
|
||||
.dashboard-page--settings-open {
|
||||
.navbar {
|
||||
@include navbar-alt-look();
|
||||
}
|
||||
|
||||
.navbar-button--add-panel,
|
||||
.navbar-button--star,
|
||||
.navbar-button--share,
|
||||
.navbar-button--settings,
|
||||
.navbar-page-btn .fa-caret-down,
|
||||
.gf-timepicker-nav {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar-buttons--close {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.panel-in-fullscreen {
|
||||
.navbar {
|
||||
@include navbar-alt-look();
|
||||
}
|
||||
|
||||
.navbar-button--add-panel,
|
||||
.navbar-button--star,
|
||||
.navbar-button--save,
|
||||
.navbar-button--settings,
|
||||
.navbar-page-btn .fa-caret-down {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar-buttons--close {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-page-btn {
|
||||
@@ -19,8 +63,9 @@
|
||||
margin: 0;
|
||||
color: darken($link-color, 5%);
|
||||
font-size: $font-size-lg;
|
||||
padding: 1rem 1rem 0.75rem 1rem;
|
||||
padding-left: 1rem;
|
||||
min-height: $navbarHeight;
|
||||
line-height: $navbarHeight;
|
||||
|
||||
.fa-caret-down {
|
||||
font-size: 60%;
|
||||
@@ -43,26 +88,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-page-btn-wrapper {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.navbar-section-wrapper {
|
||||
position: relative;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.navbar-mini-btn-wrapper {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.navbar-buttons {
|
||||
height: $navbarHeight;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-right: $spacer;
|
||||
|
||||
&--close {
|
||||
display: none;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar__spacer {
|
||||
@@ -74,7 +110,7 @@
|
||||
|
||||
display: inline-block;
|
||||
font-weight: $btn-font-weight;
|
||||
padding: 8px 11px;
|
||||
padding: 6px 11px;
|
||||
line-height: 16px;
|
||||
color: $text-muted;
|
||||
border: 1px solid $navbar-button-border;
|
||||
@@ -90,7 +126,7 @@
|
||||
}
|
||||
|
||||
&--add-panel {
|
||||
padding: 5px 10px;
|
||||
padding: 3px 10px;
|
||||
|
||||
.gicon {
|
||||
font-size: 22px;
|
||||
@@ -98,7 +134,7 @@
|
||||
}
|
||||
|
||||
&--tight {
|
||||
padding: 9px 4px;
|
||||
padding: 7px 4px;
|
||||
|
||||
.fa {
|
||||
font-size: 14px;
|
||||
@@ -106,6 +142,10 @@
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
&--primary {
|
||||
@include buttonBackground($btn-secondary-bg, $btn-secondary-bg-hl);
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
@@ -115,7 +155,8 @@
|
||||
|
||||
.sidemenu-open {
|
||||
.navbar {
|
||||
margin-left: 15px;
|
||||
padding-left: 15px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
.gf-form-label {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.gf-form + .gf-form {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.gf-form-query-content {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
background: $input-bg;
|
||||
border: 1px solid $input-border-color;
|
||||
border-left: none;
|
||||
border-radius: $input-border-radius;
|
||||
}
|
||||
|
||||
input + label::before, input + label::after {
|
||||
@@ -45,7 +46,6 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
border-radius: $input-border-radius;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
padding: 0;
|
||||
|
||||
.tabbed-view-header {
|
||||
padding: 1.5em 1rem 0 1rem;
|
||||
padding: 0px 25px;
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,17 @@
|
||||
border: solid transparent;
|
||||
border-width: 0 1px 1px;
|
||||
border-radius: 3px 3px 0 0;
|
||||
color: $text-color;
|
||||
|
||||
i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.gicon {
|
||||
position: relative;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $link-hover-color;
|
||||
|
||||
@@ -13,17 +13,18 @@
|
||||
}
|
||||
|
||||
.gf-timepicker-dropdown {
|
||||
margin: -8px -10px 10px 5px;
|
||||
position: absolute;
|
||||
top: $navbarHeight;
|
||||
right: 0;
|
||||
padding: 10px 20px;
|
||||
float: right;
|
||||
background-color: $panel-bg;
|
||||
@include box-shadow($navbarDropdownShadow);
|
||||
background-color: $page-bg;
|
||||
border-radius: 0 0 0 4px;
|
||||
box-shadow: $search-shadow;
|
||||
}
|
||||
|
||||
.gf-timepicker-absolute-section {
|
||||
width: 290px;
|
||||
float: left;
|
||||
border-right: 1px solid $divider-border-color;
|
||||
padding: 0 10px;
|
||||
select {
|
||||
width: 183px;
|
||||
@@ -41,7 +42,7 @@
|
||||
font-size: 75%;
|
||||
padding: 3px;
|
||||
border-radius: 2px;
|
||||
font-weight: bold;
|
||||
font-weight: 500;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
@@ -59,7 +60,7 @@
|
||||
li.active {
|
||||
border-bottom: 1px solid $blue;
|
||||
margin: 3px 0;
|
||||
font-weight: bold;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,5 @@
|
||||
@mixin hide-controls() {
|
||||
.add-row-panel-hint,
|
||||
.dash-row-menu-container {
|
||||
display: none;
|
||||
}
|
||||
.panel-drop-zone {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.hide-controls {
|
||||
@include hide-controls();
|
||||
}
|
||||
|
||||
.page-kiosk-mode {
|
||||
@include hide-controls();
|
||||
dashnav {
|
||||
display: none;
|
||||
}
|
||||
@@ -45,7 +31,7 @@
|
||||
background: transparent;
|
||||
transform: translate3d(-40px, 0, 0);
|
||||
transition: all 1.5s ease-in-out 1s;
|
||||
.icon-gf {
|
||||
i {
|
||||
opacity: 0;
|
||||
transition: all 1.5s ease-in-out 1s;
|
||||
}
|
||||
|
||||
@@ -217,20 +217,6 @@ div.flot-text {
|
||||
}
|
||||
}
|
||||
|
||||
.dash-edit-view {
|
||||
opacity: 0;
|
||||
|
||||
&--open{
|
||||
opacity: 1;
|
||||
transition: opacity 200ms ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-nav-shadow {
|
||||
box-shadow: 0 0 20px black;
|
||||
height: 10px;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
top: -10px;
|
||||
.panel-full-edit {
|
||||
margin: $dashboard-padding (-$dashboard-padding) 0 (-$dashboard-padding);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user