From b65642564a311f07b572ce2e1d63e4b83cb20903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 8 Oct 2016 10:06:47 +0200 Subject: [PATCH] poc for new metric segment --- .../form_dropdown/form_dropdown.html | 13 ++ .../components/form_dropdown/form_dropdown.ts | 182 ++++++++++++++++++ public/app/core/core.ts | 2 + public/app/core/directives/metric_segment.js | 2 - .../elasticsearch/partials/bucket_agg.html | 3 +- .../elasticsearch/partials/metric_agg.html | 6 +- 6 files changed, 202 insertions(+), 6 deletions(-) create mode 100644 public/app/core/components/form_dropdown/form_dropdown.html create mode 100644 public/app/core/components/form_dropdown/form_dropdown.ts diff --git a/public/app/core/components/form_dropdown/form_dropdown.html b/public/app/core/components/form_dropdown/form_dropdown.html new file mode 100644 index 00000000000..34737eab27e --- /dev/null +++ b/public/app/core/components/form_dropdown/form_dropdown.html @@ -0,0 +1,13 @@ + + + + diff --git a/public/app/core/components/form_dropdown/form_dropdown.ts b/public/app/core/components/form_dropdown/form_dropdown.ts new file mode 100644 index 00000000000..fd363d3b75e --- /dev/null +++ b/public/app/core/components/form_dropdown/form_dropdown.ts @@ -0,0 +1,182 @@ +/// + +import config from 'app/core/config'; +import _ from 'lodash'; +import $ from 'jquery'; +import coreModule from '../../core_module'; + +function typeaheadMatcher(item) { + var str = this.query; + if (str[0] === '/') { str = str.substring(1); } + if (str[str.length - 1] === '/') { str = str.substring(0, str.length-1); } + return item.toLowerCase().match(str.toLowerCase()); +} + +export class FormDropdownCtrl { + inputElement: any; + linkElement: any; + value: any; + text: any; + display: any; + options: any; + cssClass: any; + allowCustom: any; + linkMode: boolean; + cancelBlur: any; + onChange: any; + + constructor(private $scope, $element, private $sce, private templateSrv) { + this.inputElement = $element.find('input').first(); + this.linkElement = $element.find('a').first(); + this.linkMode = true; + this.cancelBlur = null; + + if (this.options) { + var item = _.find(this.options, {value: this.value}); + this.updateDisplay(item ? item.text : this.value); + } + + this.inputElement.attr('data-provide', 'typeahead'); + this.inputElement.typeahead({ + source: this.typeaheadSource.bind(this), + minLength: 0, + items: 10000, + updater: this.typeaheadUpdater.bind(this), + matcher: typeaheadMatcher, + }); + + // modify typeahead lookup + // this = typeahead + var typeahead = this.inputElement.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; + }; + + this.linkElement.keydown(evt => { + // trigger typeahead on down arrow or enter key + if (evt.keyCode === 40 || evt.keyCode === 13) { + this.linkElement.click(); + } + }); + + this.inputElement.blur(this.inputBlur.bind(this)); + } + + typeaheadSource(query, callback) { + if (this.options) { + var typeaheadOptions = _.map(this.options, 'text'); + + // add current custom value + if (this.allowCustom) { + if (_.indexOf(typeaheadOptions, this.text) === -1) { + typeaheadOptions.unshift(this.text); + } + } + + callback(typeaheadOptions); + } + } + + typeaheadUpdater(text) { + if (text === this.text) { + clearTimeout(this.cancelBlur); + this.inputElement.focus(); + return text; + } + + this.inputElement.val(text); + this.switchToLink(true); + return text; + } + + switchToLink(fromClick) { + if (this.linkMode && !fromClick) { return; } + + clearTimeout(this.cancelBlur); + this.cancelBlur = null; + this.linkMode = true; + this.inputElement.hide(); + this.linkElement.show(); + this.updateValue(this.inputElement.val()); + } + + inputBlur() { + // happens long before the click event on the typeahead options + // need to have long delay because the blur + this.cancelBlur = setTimeout(this.switchToLink.bind(this), 200); + } + + updateValue(text) { + if (text === '' || this.text === text) { + return; + } + + this.$scope.$apply(() => { + var option = _.find(this.options, {text: text}); + + if (option) { + this.value = option.value; + this.updateDisplay(option.text); + } else if (this.allowCustom) { + this.value = text; + this.updateDisplay(text); + } + + // needs to call this after digest so + // property is synced with outerscope + this.$scope.$$postDigest(() => { + this.$scope.$apply(() => { + this.onChange(); + }); + }); + + }); + } + + updateDisplay(text) { + this.text = text; + this.display = this.$sce.trustAsHtml(this.templateSrv.highlightVariablesAsHtml(text)); + } + + open() { + this.inputElement.show(); + + this.inputElement.css('width', (Math.max(this.linkElement.width(), 80) + 16) + 'px'); + this.inputElement.focus(); + + this.linkElement.hide(); + this.linkMode = false; + + var typeahead = this.inputElement.data('typeahead'); + if (typeahead) { + this.inputElement.val(''); + typeahead.lookup(); + } + } +} + + + +export function formDropdownDirective() { + return { + restrict: 'E', + templateUrl: 'public/app/core/components/form_dropdown/form_dropdown.html', + controller: FormDropdownCtrl, + bindToController: true, + controllerAs: 'ctrl', + scope: { + value: "=", + options: "=", + getOptions: "&", + onChange: "&", + cssClass: "@", + allowCustom: "@", + }, + link: function() { + } + }; +} + +coreModule.directive('gfFormDropdown', formDropdownDirective); diff --git a/public/app/core/core.ts b/public/app/core/core.ts index d44cbf4dbfb..ea55c22be8f 100644 --- a/public/app/core/core.ts +++ b/public/app/core/core.ts @@ -35,6 +35,7 @@ import {switchDirective} from './components/switch'; import {dashboardSelector} from './components/dashboard_selector'; import {queryPartEditorDirective} from './components/query_part/query_part_editor'; import {WizardFlow} from './components/wizard/wizard'; +import {formDropdownDirective} from './components/form_dropdown/form_dropdown'; import 'app/core/controllers/all'; import 'app/core/services/all'; import 'app/core/routes/routes'; @@ -62,4 +63,5 @@ export { queryPartEditorDirective, WizardFlow, colors, + formDropdownDirective, }; diff --git a/public/app/core/directives/metric_segment.js b/public/app/core/directives/metric_segment.js index 2001073ed80..62805161155 100644 --- a/public/app/core/directives/metric_segment.js +++ b/public/app/core/directives/metric_segment.js @@ -143,7 +143,6 @@ function (_, $, coreModule) { $input.focus(); linkMode = false; - var typeahead = $input.data('typeahead'); if (typeahead) { $input.val(''); @@ -152,7 +151,6 @@ function (_, $, coreModule) { }); $input.blur($scope.inputBlur); - $compile(elem.contents())($scope); } }; diff --git a/public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html b/public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html index 36e914d06e0..2b674a9fdf9 100644 --- a/public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html +++ b/public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html @@ -5,7 +5,8 @@ Then by - + + diff --git a/public/app/plugins/datasource/elasticsearch/partials/metric_agg.html b/public/app/plugins/datasource/elasticsearch/partials/metric_agg.html index faa12b5693d..472cfca37fa 100644 --- a/public/app/plugins/datasource/elasticsearch/partials/metric_agg.html +++ b/public/app/plugins/datasource/elasticsearch/partials/metric_agg.html @@ -11,9 +11,9 @@
- - - + + +