Merge branch 'develop-settings' into develop

This commit is contained in:
Torkel Ödegaard
2017-12-12 12:03:10 +01:00
52 changed files with 1139 additions and 1072 deletions
@@ -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 = `
+12 -13
View File
@@ -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': {
+10 -8
View File
@@ -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);
}
});
}
}
+7
View File
@@ -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 {
+5 -14
View File
@@ -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'">&gt; New</span>
<span ng-show="ctrl.mode === 'edit'">&gt; 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> &nbsp;
{{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> &nbsp;
<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>&nbsp;&nbsp;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 &amp; 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>
+2 -1
View File
@@ -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');
}
+107 -135
View File
@@ -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'">
&gt; 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&hellip;</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>&nbsp;&nbsp;Restore
</a>
<a class="btn btn-outline-disabled btn-small" ng-show="revision.version === ctrl.dashboard.version">
<i class="fa fa-check"></i>&nbsp;&nbsp;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&hellip;</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>&nbsp;&nbsp;Restore
</a>
<a class="btn btn-outline-disabled btn-small" ng-show="revision.version === ctrl.dashboard.version">
<i class="fa fa-check"></i>&nbsp;&nbsp;Latest
</a>
</td>
</tr>
</tbody>
</table>
<div ng-if="ctrl.appending">
<i class="fa fa-spinner fa-spin"></i>
<em>Fetching more entries&hellip;</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>&nbsp;&nbsp;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&hellip;</em>
<em>Fetching more entries&hellip;</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>&nbsp;&nbsp;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>&nbsp;&nbsp;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&hellip;</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>&nbsp;&nbsp;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);
+57 -60
View File
@@ -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>
+11 -4
View File
@@ -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'">&gt; New</span>
<span ng-show="mode === 'edit'">&gt; 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>&nbsp;&nbsp;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>
-1
View File
@@ -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>
+5 -3
View File
@@ -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>
-2
View File
@@ -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';
+1
View File
@@ -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";
+4 -4
View File
@@ -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;
+1
View File
@@ -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);
+1 -1
View File
@@ -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
//
+1
View File
@@ -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;
}
}
+15 -12
View File
@@ -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;
}
+9 -3
View File
@@ -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;
-10
View File
@@ -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;
+62 -21
View File
@@ -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 {
+1 -1
View File
@@ -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 {
+2 -1
View File
@@ -6,7 +6,8 @@
padding: 0;
.tabbed-view-header {
padding: 1.5em 1rem 0 1rem;
padding: 0px 25px;
background: none;
}
}
}
+6
View File
@@ -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;
+8 -7
View File
@@ -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 -15
View File
@@ -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;
}
+2 -16
View File
@@ -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);
}