mirror of https://github.com/grafana/grafana
commit
4a26797cdd
@ -0,0 +1,41 @@ |
||||
import coreModule from 'app/core/core_module'; |
||||
import appEvents from 'app/core/app_events'; |
||||
|
||||
export function pageScrollbar() { |
||||
return { |
||||
restrict: 'A', |
||||
link: function(scope, elem, attrs) { |
||||
let lastPos = 0; |
||||
|
||||
appEvents.on( |
||||
'dash-scroll', |
||||
evt => { |
||||
if (evt.restore) { |
||||
elem[0].scrollTop = lastPos; |
||||
return; |
||||
} |
||||
|
||||
lastPos = elem[0].scrollTop; |
||||
|
||||
if (evt.animate) { |
||||
elem.animate({ scrollTop: evt.pos }, 500); |
||||
} else { |
||||
elem[0].scrollTop = evt.pos; |
||||
} |
||||
}, |
||||
scope |
||||
); |
||||
|
||||
scope.$on('$routeChangeSuccess', () => { |
||||
lastPos = 0; |
||||
elem[0].scrollTop = 0; |
||||
elem[0].focus(); |
||||
}); |
||||
|
||||
elem[0].tabIndex = -1; |
||||
elem[0].focus(); |
||||
}, |
||||
}; |
||||
} |
||||
|
||||
coreModule.directive('pageScrollbar', pageScrollbar); |
@ -1,36 +0,0 @@ |
||||
define([ |
||||
'lodash', |
||||
'jquery', |
||||
'../core_module', |
||||
], |
||||
function (_, $, coreModule) { |
||||
'use strict'; |
||||
|
||||
coreModule.default.directive('dashClass', function() { |
||||
return { |
||||
link: function($scope, elem) { |
||||
|
||||
$scope.onAppEvent('panel-fullscreen-enter', function() { |
||||
elem.toggleClass('panel-in-fullscreen', true); |
||||
}); |
||||
|
||||
$scope.onAppEvent('panel-fullscreen-exit', function() { |
||||
elem.toggleClass('panel-in-fullscreen', false); |
||||
}); |
||||
|
||||
$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'); |
||||
} |
||||
}); |
||||
} |
||||
}; |
||||
}); |
||||
|
||||
}); |
@ -0,0 +1,31 @@ |
||||
import _ from 'lodash'; |
||||
import coreModule from '../core_module'; |
||||
|
||||
/** @ngInject */ |
||||
export function dashClass() { |
||||
return { |
||||
link: function($scope, elem) { |
||||
$scope.onAppEvent('panel-fullscreen-enter', function() { |
||||
elem.toggleClass('panel-in-fullscreen', true); |
||||
}); |
||||
|
||||
$scope.onAppEvent('panel-fullscreen-exit', function() { |
||||
elem.toggleClass('panel-in-fullscreen', false); |
||||
}); |
||||
|
||||
$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'); |
||||
} |
||||
}); |
||||
}, |
||||
}; |
||||
} |
||||
|
||||
coreModule.directive('dashClass', dashClass); |
@ -1,246 +0,0 @@ |
||||
define([ |
||||
'lodash', |
||||
'jquery', |
||||
'../core_module', |
||||
], |
||||
function (_, $, coreModule) { |
||||
'use strict'; |
||||
|
||||
coreModule.default.directive('metricSegment', function($compile, $sce) { |
||||
var inputTemplate = '<input type="text" data-provide="typeahead" ' + |
||||
' class="gf-form-input input-medium"' + |
||||
' spellcheck="false" style="display:none"></input>'; |
||||
|
||||
var linkTemplate = '<a class="gf-form-label" ng-class="segment.cssClass" ' + |
||||
'tabindex="1" give-focus="segment.focus" ng-bind-html="segment.html"></a>'; |
||||
|
||||
var selectTemplate = '<a class="gf-form-input gf-form-input--dropdown" ng-class="segment.cssClass" ' + |
||||
'tabindex="1" give-focus="segment.focus" ng-bind-html="segment.html"></a>'; |
||||
|
||||
return { |
||||
scope: { |
||||
segment: "=", |
||||
getOptions: "&", |
||||
onChange: "&", |
||||
debounce: "@", |
||||
}, |
||||
link: function($scope, elem) { |
||||
var $input = $(inputTemplate); |
||||
var segment = $scope.segment; |
||||
var $button = $(segment.selectMode ? selectTemplate : linkTemplate); |
||||
var options = null; |
||||
var cancelBlur = null; |
||||
var linkMode = true; |
||||
var debounceLookup = $scope.debounce; |
||||
|
||||
$input.appendTo(elem); |
||||
$button.appendTo(elem); |
||||
|
||||
$scope.updateVariableValue = function(value) { |
||||
if (value === '' || segment.value === value) { |
||||
return; |
||||
} |
||||
|
||||
value = _.unescape(value); |
||||
|
||||
$scope.$apply(function() { |
||||
var selected = _.find($scope.altSegments, {value: value}); |
||||
if (selected) { |
||||
segment.value = selected.value; |
||||
segment.html = selected.html || selected.value; |
||||
segment.fake = false; |
||||
segment.expandable = selected.expandable; |
||||
|
||||
if (selected.type) { |
||||
segment.type = selected.type; |
||||
} |
||||
} |
||||
else if (segment.custom !== 'false') { |
||||
segment.value = value; |
||||
segment.html = $sce.trustAsHtml(value); |
||||
segment.expandable = true; |
||||
segment.fake = false; |
||||
} |
||||
|
||||
$scope.onChange(); |
||||
}); |
||||
}; |
||||
|
||||
$scope.switchToLink = function(fromClick) { |
||||
if (linkMode && !fromClick) { return; } |
||||
|
||||
clearTimeout(cancelBlur); |
||||
cancelBlur = null; |
||||
linkMode = true; |
||||
$input.hide(); |
||||
$button.show(); |
||||
$scope.updateVariableValue($input.val()); |
||||
}; |
||||
|
||||
$scope.inputBlur = function() { |
||||
// happens long before the click event on the typeahead options
|
||||
// need to have long delay because the blur
|
||||
cancelBlur = setTimeout($scope.switchToLink, 200); |
||||
}; |
||||
|
||||
$scope.source = function(query, callback) { |
||||
$scope.$apply(function() { |
||||
$scope.getOptions({ $query: query }).then(function(altSegments) { |
||||
$scope.altSegments = altSegments; |
||||
options = _.map($scope.altSegments, function(alt) { |
||||
return _.escape(alt.value); |
||||
}); |
||||
|
||||
// add custom values
|
||||
if (segment.custom !== 'false') { |
||||
if (!segment.fake && _.indexOf(options, segment.value) === -1) { |
||||
options.unshift(segment.value); |
||||
} |
||||
} |
||||
|
||||
callback(options); |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
$scope.updater = function(value) { |
||||
if (value === segment.value) { |
||||
clearTimeout(cancelBlur); |
||||
$input.focus(); |
||||
return value; |
||||
} |
||||
|
||||
$input.val(value); |
||||
$scope.switchToLink(true); |
||||
|
||||
return value; |
||||
}; |
||||
|
||||
$scope.matcher = function(item) { |
||||
var str = this.query; |
||||
if (str[0] === '/') { str = str.substring(1); } |
||||
if (str[str.length - 1] === '/') { str = str.substring(0, str.length-1); } |
||||
try { |
||||
return item.toLowerCase().match(str.toLowerCase()); |
||||
} catch(e) { |
||||
return false; |
||||
} |
||||
}; |
||||
|
||||
$input.attr('data-provide', 'typeahead'); |
||||
$input.typeahead({ source: $scope.source, minLength: 0, items: 10000, updater: $scope.updater, matcher: $scope.matcher }); |
||||
|
||||
var typeahead = $input.data('typeahead'); |
||||
typeahead.lookup = function () { |
||||
this.query = this.$element.val() || ''; |
||||
var items = this.source(this.query, $.proxy(this.process, this)); |
||||
return items ? this.process(items) : items; |
||||
}; |
||||
|
||||
if (debounceLookup) { |
||||
typeahead.lookup = _.debounce(typeahead.lookup, 500, {leading: true}); |
||||
} |
||||
|
||||
$button.keydown(function(evt) { |
||||
// trigger typeahead on down arrow or enter key
|
||||
if (evt.keyCode === 40 || evt.keyCode === 13) { |
||||
$button.click(); |
||||
} |
||||
}); |
||||
|
||||
$button.click(function() { |
||||
options = null; |
||||
$input.css('width', (Math.max($button.width(), 80) + 16) + 'px'); |
||||
|
||||
$button.hide(); |
||||
$input.show(); |
||||
$input.focus(); |
||||
|
||||
linkMode = false; |
||||
|
||||
var typeahead = $input.data('typeahead'); |
||||
if (typeahead) { |
||||
$input.val(''); |
||||
typeahead.lookup(); |
||||
} |
||||
}); |
||||
|
||||
$input.blur($scope.inputBlur); |
||||
|
||||
$compile(elem.contents())($scope); |
||||
} |
||||
}; |
||||
}); |
||||
|
||||
coreModule.default.directive('metricSegmentModel', function(uiSegmentSrv, $q) { |
||||
return { |
||||
template: '<metric-segment segment="segment" get-options="getOptionsInternal()" on-change="onSegmentChange()"></metric-segment>', |
||||
restrict: 'E', |
||||
scope: { |
||||
property: "=", |
||||
options: "=", |
||||
getOptions: "&", |
||||
onChange: "&", |
||||
}, |
||||
link: { |
||||
pre: function postLink($scope, elem, attrs) { |
||||
var cachedOptions; |
||||
|
||||
$scope.valueToSegment = function(value) { |
||||
var option = _.find($scope.options, {value: value}); |
||||
var segment = { |
||||
cssClass: attrs.cssClass, |
||||
custom: attrs.custom, |
||||
value: option ? option.text : value, |
||||
selectMode: attrs.selectMode, |
||||
}; |
||||
|
||||
return uiSegmentSrv.newSegment(segment); |
||||
}; |
||||
|
||||
$scope.getOptionsInternal = function() { |
||||
if ($scope.options) { |
||||
cachedOptions = $scope.options; |
||||
return $q.when(_.map($scope.options, function(option) { |
||||
return {value: option.text}; |
||||
})); |
||||
} else { |
||||
return $scope.getOptions().then(function(options) { |
||||
cachedOptions = options; |
||||
return _.map(options, function(option) { |
||||
if (option.html) { |
||||
return option; |
||||
} |
||||
return {value: option.text}; |
||||
}); |
||||
}); |
||||
} |
||||
}; |
||||
|
||||
$scope.onSegmentChange = function() { |
||||
if (cachedOptions) { |
||||
var option = _.find(cachedOptions, {text: $scope.segment.value}); |
||||
if (option && option.value !== $scope.property) { |
||||
$scope.property = option.value; |
||||
} else if (attrs.custom !== 'false') { |
||||
$scope.property = $scope.segment.value; |
||||
} |
||||
} else { |
||||
$scope.property = $scope.segment.value; |
||||
} |
||||
|
||||
// needs to call this after digest so
|
||||
// property is synced with outerscope
|
||||
$scope.$$postDigest(function() { |
||||
$scope.$apply(function() { |
||||
$scope.onChange(); |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
$scope.segment = $scope.valueToSegment($scope.property); |
||||
} |
||||
} |
||||
}; |
||||
}); |
||||
}); |
@ -0,0 +1,263 @@ |
||||
import _ from 'lodash'; |
||||
import $ from 'jquery'; |
||||
import coreModule from '../core_module'; |
||||
|
||||
/** @ngInject */ |
||||
export function metricSegment($compile, $sce) { |
||||
let inputTemplate = |
||||
'<input type="text" data-provide="typeahead" ' + |
||||
' class="gf-form-input input-medium"' + |
||||
' spellcheck="false" style="display:none"></input>'; |
||||
|
||||
let linkTemplate = |
||||
'<a class="gf-form-label" ng-class="segment.cssClass" ' + |
||||
'tabindex="1" give-focus="segment.focus" ng-bind-html="segment.html"></a>'; |
||||
|
||||
let selectTemplate = |
||||
'<a class="gf-form-input gf-form-input--dropdown" ng-class="segment.cssClass" ' + |
||||
'tabindex="1" give-focus="segment.focus" ng-bind-html="segment.html"></a>'; |
||||
|
||||
return { |
||||
scope: { |
||||
segment: '=', |
||||
getOptions: '&', |
||||
onChange: '&', |
||||
debounce: '@', |
||||
}, |
||||
link: function($scope, elem) { |
||||
let $input = $(inputTemplate); |
||||
let segment = $scope.segment; |
||||
let $button = $(segment.selectMode ? selectTemplate : linkTemplate); |
||||
let options = null; |
||||
let cancelBlur = null; |
||||
let linkMode = true; |
||||
let debounceLookup = $scope.debounce; |
||||
|
||||
$input.appendTo(elem); |
||||
$button.appendTo(elem); |
||||
|
||||
$scope.updateVariableValue = function(value) { |
||||
if (value === '' || segment.value === value) { |
||||
return; |
||||
} |
||||
|
||||
value = _.unescape(value); |
||||
|
||||
$scope.$apply(function() { |
||||
let selected = _.find($scope.altSegments, { value: value }); |
||||
if (selected) { |
||||
segment.value = selected.value; |
||||
segment.html = selected.html || selected.value; |
||||
segment.fake = false; |
||||
segment.expandable = selected.expandable; |
||||
|
||||
if (selected.type) { |
||||
segment.type = selected.type; |
||||
} |
||||
} else if (segment.custom !== 'false') { |
||||
segment.value = value; |
||||
segment.html = $sce.trustAsHtml(value); |
||||
segment.expandable = true; |
||||
segment.fake = false; |
||||
} |
||||
|
||||
$scope.onChange(); |
||||
}); |
||||
}; |
||||
|
||||
$scope.switchToLink = function(fromClick) { |
||||
if (linkMode && !fromClick) { |
||||
return; |
||||
} |
||||
|
||||
clearTimeout(cancelBlur); |
||||
cancelBlur = null; |
||||
linkMode = true; |
||||
$input.hide(); |
||||
$button.show(); |
||||
$scope.updateVariableValue($input.val()); |
||||
}; |
||||
|
||||
$scope.inputBlur = function() { |
||||
// happens long before the click event on the typeahead options
|
||||
// need to have long delay because the blur
|
||||
cancelBlur = setTimeout($scope.switchToLink, 200); |
||||
}; |
||||
|
||||
$scope.source = function(query, callback) { |
||||
$scope.$apply(function() { |
||||
$scope.getOptions({ $query: query }).then(function(altSegments) { |
||||
$scope.altSegments = altSegments; |
||||
options = _.map($scope.altSegments, function(alt) { |
||||
return _.escape(alt.value); |
||||
}); |
||||
|
||||
// add custom values
|
||||
if (segment.custom !== 'false') { |
||||
if (!segment.fake && _.indexOf(options, segment.value) === -1) { |
||||
options.unshift(segment.value); |
||||
} |
||||
} |
||||
|
||||
callback(options); |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
$scope.updater = function(value) { |
||||
if (value === segment.value) { |
||||
clearTimeout(cancelBlur); |
||||
$input.focus(); |
||||
return value; |
||||
} |
||||
|
||||
$input.val(value); |
||||
$scope.switchToLink(true); |
||||
|
||||
return value; |
||||
}; |
||||
|
||||
$scope.matcher = function(item) { |
||||
let str = this.query; |
||||
if (str[0] === '/') { |
||||
str = str.substring(1); |
||||
} |
||||
if (str[str.length - 1] === '/') { |
||||
str = str.substring(0, str.length - 1); |
||||
} |
||||
try { |
||||
return item.toLowerCase().match(str.toLowerCase()); |
||||
} catch (e) { |
||||
return false; |
||||
} |
||||
}; |
||||
|
||||
$input.attr('data-provide', 'typeahead'); |
||||
$input.typeahead({ |
||||
source: $scope.source, |
||||
minLength: 0, |
||||
items: 10000, |
||||
updater: $scope.updater, |
||||
matcher: $scope.matcher, |
||||
}); |
||||
|
||||
let typeahead = $input.data('typeahead'); |
||||
typeahead.lookup = function() { |
||||
this.query = this.$element.val() || ''; |
||||
let items = this.source(this.query, $.proxy(this.process, this)); |
||||
return items ? this.process(items) : items; |
||||
}; |
||||
|
||||
if (debounceLookup) { |
||||
typeahead.lookup = _.debounce(typeahead.lookup, 500, { leading: true }); |
||||
} |
||||
|
||||
$button.keydown(function(evt) { |
||||
// trigger typeahead on down arrow or enter key
|
||||
if (evt.keyCode === 40 || evt.keyCode === 13) { |
||||
$button.click(); |
||||
} |
||||
}); |
||||
|
||||
$button.click(function() { |
||||
options = null; |
||||
$input.css('width', Math.max($button.width(), 80) + 16 + 'px'); |
||||
|
||||
$button.hide(); |
||||
$input.show(); |
||||
$input.focus(); |
||||
|
||||
linkMode = false; |
||||
|
||||
let typeahead = $input.data('typeahead'); |
||||
if (typeahead) { |
||||
$input.val(''); |
||||
typeahead.lookup(); |
||||
} |
||||
}); |
||||
|
||||
$input.blur($scope.inputBlur); |
||||
|
||||
$compile(elem.contents())($scope); |
||||
}, |
||||
}; |
||||
} |
||||
|
||||
/** @ngInject */ |
||||
export function metricSegmentModel(uiSegmentSrv, $q) { |
||||
return { |
||||
template: |
||||
'<metric-segment segment="segment" get-options="getOptionsInternal()" on-change="onSegmentChange()"></metric-segment>', |
||||
restrict: 'E', |
||||
scope: { |
||||
property: '=', |
||||
options: '=', |
||||
getOptions: '&', |
||||
onChange: '&', |
||||
}, |
||||
link: { |
||||
pre: function postLink($scope, elem, attrs) { |
||||
let cachedOptions; |
||||
|
||||
$scope.valueToSegment = function(value) { |
||||
let option = _.find($scope.options, { value: value }); |
||||
let segment = { |
||||
cssClass: attrs.cssClass, |
||||
custom: attrs.custom, |
||||
value: option ? option.text : value, |
||||
selectMode: attrs.selectMode, |
||||
}; |
||||
|
||||
return uiSegmentSrv.newSegment(segment); |
||||
}; |
||||
|
||||
$scope.getOptionsInternal = function() { |
||||
if ($scope.options) { |
||||
cachedOptions = $scope.options; |
||||
return $q.when( |
||||
_.map($scope.options, function(option) { |
||||
return { value: option.text }; |
||||
}) |
||||
); |
||||
} else { |
||||
return $scope.getOptions().then(function(options) { |
||||
cachedOptions = options; |
||||
return _.map(options, function(option) { |
||||
if (option.html) { |
||||
return option; |
||||
} |
||||
return { value: option.text }; |
||||
}); |
||||
}); |
||||
} |
||||
}; |
||||
|
||||
$scope.onSegmentChange = function() { |
||||
if (cachedOptions) { |
||||
let option = _.find(cachedOptions, { text: $scope.segment.value }); |
||||
if (option && option.value !== $scope.property) { |
||||
$scope.property = option.value; |
||||
} else if (attrs.custom !== 'false') { |
||||
$scope.property = $scope.segment.value; |
||||
} |
||||
} else { |
||||
$scope.property = $scope.segment.value; |
||||
} |
||||
|
||||
// needs to call this after digest so
|
||||
// property is synced with outerscope
|
||||
$scope.$$postDigest(function() { |
||||
$scope.$apply(function() { |
||||
$scope.onChange(); |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
$scope.segment = $scope.valueToSegment($scope.property); |
||||
}, |
||||
}, |
||||
}; |
||||
} |
||||
|
||||
coreModule.directive('metricSegment', metricSegment); |
||||
coreModule.directive('metricSegmentModel', metricSegmentModel); |
@ -1,111 +0,0 @@ |
||||
define([ |
||||
'angular', |
||||
'lodash', |
||||
'../core_module', |
||||
], |
||||
function (angular, _, coreModule) { |
||||
'use strict'; |
||||
|
||||
coreModule.default.service('uiSegmentSrv', function($sce, templateSrv) { |
||||
var self = this; |
||||
|
||||
function MetricSegment(options) { |
||||
if (options === '*' || options.value === '*') { |
||||
this.value = '*'; |
||||
this.html = $sce.trustAsHtml('<i class="fa fa-asterisk"><i>'); |
||||
this.type = options.type; |
||||
this.expandable = true; |
||||
return; |
||||
} |
||||
|
||||
if (_.isString(options)) { |
||||
this.value = options; |
||||
this.html = $sce.trustAsHtml(templateSrv.highlightVariablesAsHtml(this.value)); |
||||
return; |
||||
} |
||||
|
||||
// temp hack to work around legacy inconsistency in segment model
|
||||
this.text = options.value; |
||||
|
||||
this.cssClass = options.cssClass; |
||||
this.custom = options.custom; |
||||
this.type = options.type; |
||||
this.fake = options.fake; |
||||
this.value = options.value; |
||||
this.selectMode = options.selectMode; |
||||
this.type = options.type; |
||||
this.expandable = options.expandable; |
||||
this.html = options.html || $sce.trustAsHtml(templateSrv.highlightVariablesAsHtml(this.value)); |
||||
} |
||||
|
||||
this.getSegmentForValue = function(value, fallbackText) { |
||||
if (value) { |
||||
return this.newSegment(value); |
||||
} else { |
||||
return this.newSegment({value: fallbackText, fake: true}); |
||||
} |
||||
}; |
||||
|
||||
this.newSelectMeasurement = function() { |
||||
return new MetricSegment({value: 'select measurement', fake: true}); |
||||
}; |
||||
|
||||
this.newFake = function(text, type, cssClass) { |
||||
return new MetricSegment({value: text, fake: true, type: type, cssClass: cssClass}); |
||||
}; |
||||
|
||||
this.newSegment = function(options) { |
||||
return new MetricSegment(options); |
||||
}; |
||||
|
||||
this.newKey = function(key) { |
||||
return new MetricSegment({value: key, type: 'key', cssClass: 'query-segment-key' }); |
||||
}; |
||||
|
||||
this.newKeyValue = function(value) { |
||||
return new MetricSegment({value: value, type: 'value', cssClass: 'query-segment-value' }); |
||||
}; |
||||
|
||||
this.newCondition = function(condition) { |
||||
return new MetricSegment({value: condition, type: 'condition', cssClass: 'query-keyword' }); |
||||
}; |
||||
|
||||
this.newOperator = function(op) { |
||||
return new MetricSegment({value: op, type: 'operator', cssClass: 'query-segment-operator' }); |
||||
}; |
||||
|
||||
this.newOperators = function(ops) { |
||||
return _.map(ops, function(op) { |
||||
return new MetricSegment({value: op, type: 'operator', cssClass: 'query-segment-operator' }); |
||||
}); |
||||
}; |
||||
|
||||
this.transformToSegments = function(addTemplateVars, variableTypeFilter) { |
||||
return function(results) { |
||||
var segments = _.map(results, function(segment) { |
||||
return self.newSegment({value: segment.text, expandable: segment.expandable}); |
||||
}); |
||||
|
||||
if (addTemplateVars) { |
||||
_.each(templateSrv.variables, function(variable) { |
||||
if (variableTypeFilter === void 0 || variableTypeFilter === variable.type) { |
||||
segments.unshift(self.newSegment({ type: 'value', value: '$' + variable.name, expandable: true })); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
return segments; |
||||
}; |
||||
}; |
||||
|
||||
this.newSelectMetric = function() { |
||||
return new MetricSegment({value: 'select metric', fake: true}); |
||||
}; |
||||
|
||||
this.newPlusButton = function() { |
||||
return new MetricSegment({fake: true, html: '<i class="fa fa-plus "></i>', type: 'plus-button', cssClass: 'query-part' }); |
||||
}; |
||||
|
||||
}); |
||||
|
||||
}); |
@ -0,0 +1,111 @@ |
||||
import _ from 'lodash'; |
||||
import coreModule from '../core_module'; |
||||
|
||||
/** @ngInject */ |
||||
export function uiSegmentSrv($sce, templateSrv) { |
||||
let self = this; |
||||
|
||||
function MetricSegment(options) { |
||||
if (options === '*' || options.value === '*') { |
||||
this.value = '*'; |
||||
this.html = $sce.trustAsHtml('<i class="fa fa-asterisk"><i>'); |
||||
this.type = options.type; |
||||
this.expandable = true; |
||||
return; |
||||
} |
||||
|
||||
if (_.isString(options)) { |
||||
this.value = options; |
||||
this.html = $sce.trustAsHtml(templateSrv.highlightVariablesAsHtml(this.value)); |
||||
return; |
||||
} |
||||
|
||||
// temp hack to work around legacy inconsistency in segment model
|
||||
this.text = options.value; |
||||
|
||||
this.cssClass = options.cssClass; |
||||
this.custom = options.custom; |
||||
this.type = options.type; |
||||
this.fake = options.fake; |
||||
this.value = options.value; |
||||
this.selectMode = options.selectMode; |
||||
this.type = options.type; |
||||
this.expandable = options.expandable; |
||||
this.html = options.html || $sce.trustAsHtml(templateSrv.highlightVariablesAsHtml(this.value)); |
||||
} |
||||
|
||||
this.getSegmentForValue = function(value, fallbackText) { |
||||
if (value) { |
||||
return this.newSegment(value); |
||||
} else { |
||||
return this.newSegment({ value: fallbackText, fake: true }); |
||||
} |
||||
}; |
||||
|
||||
this.newSelectMeasurement = function() { |
||||
return new MetricSegment({ value: 'select measurement', fake: true }); |
||||
}; |
||||
|
||||
this.newFake = function(text, type, cssClass) { |
||||
return new MetricSegment({ value: text, fake: true, type: type, cssClass: cssClass }); |
||||
}; |
||||
|
||||
this.newSegment = function(options) { |
||||
return new MetricSegment(options); |
||||
}; |
||||
|
||||
this.newKey = function(key) { |
||||
return new MetricSegment({ value: key, type: 'key', cssClass: 'query-segment-key' }); |
||||
}; |
||||
|
||||
this.newKeyValue = function(value) { |
||||
return new MetricSegment({ value: value, type: 'value', cssClass: 'query-segment-value' }); |
||||
}; |
||||
|
||||
this.newCondition = function(condition) { |
||||
return new MetricSegment({ value: condition, type: 'condition', cssClass: 'query-keyword' }); |
||||
}; |
||||
|
||||
this.newOperator = function(op) { |
||||
return new MetricSegment({ value: op, type: 'operator', cssClass: 'query-segment-operator' }); |
||||
}; |
||||
|
||||
this.newOperators = function(ops) { |
||||
return _.map(ops, function(op) { |
||||
return new MetricSegment({ value: op, type: 'operator', cssClass: 'query-segment-operator' }); |
||||
}); |
||||
}; |
||||
|
||||
this.transformToSegments = function(addTemplateVars, variableTypeFilter) { |
||||
return function(results) { |
||||
let segments = _.map(results, function(segment) { |
||||
return self.newSegment({ value: segment.text, expandable: segment.expandable }); |
||||
}); |
||||
|
||||
if (addTemplateVars) { |
||||
_.each(templateSrv.variables, function(variable) { |
||||
if (variableTypeFilter === void 0 || variableTypeFilter === variable.type) { |
||||
segments.unshift(self.newSegment({ type: 'value', value: '$' + variable.name, expandable: true })); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
return segments; |
||||
}; |
||||
}; |
||||
|
||||
this.newSelectMetric = function() { |
||||
return new MetricSegment({ value: 'select metric', fake: true }); |
||||
}; |
||||
|
||||
this.newPlusButton = function() { |
||||
return new MetricSegment({ |
||||
fake: true, |
||||
html: '<i class="fa fa-plus "></i>', |
||||
type: 'plus-button', |
||||
cssClass: 'query-part', |
||||
}); |
||||
}; |
||||
} |
||||
|
||||
coreModule.service('uiSegmentSrv', uiSegmentSrv); |
@ -1,18 +1,18 @@ |
||||
<div dash-class ng-if="ctrl.dashboard"> |
||||
<dashnav dashboard="ctrl.dashboard"></dashnav> |
||||
|
||||
<div class="scroll-canvas scroll-canvas--dashboard" grafana-scrollbar> |
||||
<dashboard-settings dashboard="ctrl.dashboard" |
||||
ng-if="ctrl.dashboardViewState.state.editview" |
||||
class="dashboard-settings"> |
||||
</dashboard-settings> |
||||
<div class="scroll-canvas scroll-canvas--dashboard" page-scrollbar> |
||||
<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> |
||||
<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> |
||||
<dashboard-grid get-panel-container="ctrl.getPanelContainer"> |
||||
</dashboard-grid> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
@ -1,17 +1,19 @@ |
||||
<div class="dashlist" ng-repeat="group in ctrl.groups"> |
||||
<div class="dashlist-section" ng-if="group.show"> |
||||
<h6 class="dashlist-section-header" ng-show="ctrl.panel.headings"> |
||||
{{group.header}} |
||||
</h6> |
||||
<div class="dashlist-item" ng-repeat="dash in group.list"> |
||||
<a class="dashlist-link dashlist-link-{{dash.type}}" href="{{dash.url}}"> |
||||
<span class="dashlist-title"> |
||||
{{dash.title}} |
||||
</span> |
||||
<span class="dashlist-star" ng-click="ctrl.starDashboard(dash, $event)"> |
||||
<i class="fa" ng-class="{'fa-star': dash.isStarred, 'fa-star-o': dash.isStarred === false}"></i> |
||||
</span> |
||||
</a> |
||||
<div> |
||||
<div class="dashlist" ng-repeat="group in ctrl.groups"> |
||||
<div class="dashlist-section" ng-if="group.show"> |
||||
<h6 class="dashlist-section-header" ng-show="ctrl.panel.headings"> |
||||
{{group.header}} |
||||
</h6> |
||||
<div class="dashlist-item" ng-repeat="dash in group.list"> |
||||
<a class="dashlist-link dashlist-link-{{dash.type}}" href="{{dash.url}}"> |
||||
<span class="dashlist-title"> |
||||
{{dash.title}} |
||||
</span> |
||||
<span class="dashlist-star" ng-click="ctrl.starDashboard(dash, $event)"> |
||||
<i class="fa" ng-class="{'fa-star': dash.isStarred, 'fa-star-o': dash.isStarred === false}"></i> |
||||
</span> |
||||
</a> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
Loading…
Reference in new issue