From eecf844ca2ae2ca574973d4f68b7e4af11c21395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 2 Feb 2016 22:58:37 +0100 Subject: [PATCH] feat(plugins): migrated influxdb query editor to new plugin model --- .../app/core/directives/plugin_component.ts | 2 +- .../app/features/panel/metrics_panel_ctrl.ts | 25 +- public/app/features/panel/partials/panel.html | 2 +- .../panel/partials/query_editor_row.html | 4 +- public/app/features/panel/query_ctrl.ts | 1 + .../plugins/datasource/graphite/query_ctrl.ts | 15 +- .../plugins/datasource/influxdb/datasource.js | 220 ------------ .../plugins/datasource/influxdb/datasource.ts | 213 ++++++++++++ .../app/plugins/datasource/influxdb/module.js | 30 -- .../app/plugins/datasource/influxdb/module.ts | 53 +++ .../influxdb/partials/query.editor.html | 134 +++----- .../plugins/datasource/influxdb/query_ctrl.js | 322 ------------------ .../plugins/datasource/influxdb/query_ctrl.ts | 318 +++++++++++++++++ .../influxdb/specs/query_ctrl_specs.ts | 138 ++++---- 14 files changed, 713 insertions(+), 764 deletions(-) delete mode 100644 public/app/plugins/datasource/influxdb/datasource.js create mode 100644 public/app/plugins/datasource/influxdb/datasource.ts delete mode 100644 public/app/plugins/datasource/influxdb/module.js create mode 100644 public/app/plugins/datasource/influxdb/module.ts delete mode 100644 public/app/plugins/datasource/influxdb/query_ctrl.js create mode 100644 public/app/plugins/datasource/influxdb/query_ctrl.ts diff --git a/public/app/core/directives/plugin_component.ts b/public/app/core/directives/plugin_component.ts index 32b80cc0966..065a0be0392 100644 --- a/public/app/core/directives/plugin_component.ts +++ b/public/app/core/directives/plugin_component.ts @@ -60,7 +60,7 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope) { }); }); } - // QueryOptionsCtrl + // Annotations case "annotations-query-ctrl": { return System.import(scope.currentDatasource.meta.module).then(function(dsModule) { return { diff --git a/public/app/features/panel/metrics_panel_ctrl.ts b/public/app/features/panel/metrics_panel_ctrl.ts index 14f5a59490b..47f2393c4c0 100644 --- a/public/app/features/panel/metrics_panel_ctrl.ts +++ b/public/app/features/panel/metrics_panel_ctrl.ts @@ -38,13 +38,6 @@ class MetricsPanelCtrl extends PanelCtrl { if (!this.panel.targets) { this.panel.targets = [{}]; } - - // hookup initial data fetch - this.$timeout(() => { - if (!this.skipDataOnInit) { - this.refresh(); - } - }, 30);; } initEditMode() { @@ -182,15 +175,19 @@ class MetricsPanelCtrl extends PanelCtrl { }; this.setTimeQueryStart(); - return datasource.query(metricsQuery).then(results => { - this.setTimeQueryEnd(); + try { + return datasource.query(metricsQuery).then(results => { + this.setTimeQueryEnd(); - if (this.dashboard.snapshot) { - this.panel.snapshotData = results; - } + if (this.dashboard.snapshot) { + this.panel.snapshotData = results; + } - return results; - }); + return results; + }); + } catch (err) { + return this.$q.reject(err); + } } setDatasource(datasource) { diff --git a/public/app/features/panel/partials/panel.html b/public/app/features/panel/partials/panel.html index 13c2178e0b4..06132c107a4 100644 --- a/public/app/features/panel/partials/panel.html +++ b/public/app/features/panel/partials/panel.html @@ -1,6 +1,6 @@
- + diff --git a/public/app/features/panel/partials/query_editor_row.html b/public/app/features/panel/partials/query_editor_row.html index 9df0dcdbc51..4cf21b32e17 100644 --- a/public/app/features/panel/partials/query_editor_row.html +++ b/public/app/features/panel/partials/query_editor_row.html @@ -1,7 +1,7 @@
    -
  • - +
  • +
  • diff --git a/public/app/features/panel/query_ctrl.ts b/public/app/features/panel/query_ctrl.ts index 236d55e3bda..016f675dd0f 100644 --- a/public/app/features/panel/query_ctrl.ts +++ b/public/app/features/panel/query_ctrl.ts @@ -9,6 +9,7 @@ export class QueryCtrl { panelCtrl: any; panel: any; hasRawMode: boolean; + error: string; constructor(public $scope, private $injector) { this.panel = this.panelCtrl.panel; diff --git a/public/app/plugins/datasource/graphite/query_ctrl.ts b/public/app/plugins/datasource/graphite/query_ctrl.ts index 01c61ad2a40..23c6c2aa6d6 100644 --- a/public/app/plugins/datasource/graphite/query_ctrl.ts +++ b/public/app/plugins/datasource/graphite/query_ctrl.ts @@ -15,7 +15,6 @@ export class GraphiteQueryCtrl extends QueryCtrl { functions: any[]; segments: any[]; - parserError: string; /** @ngInject **/ constructor($scope, $injector, private uiSegmentSrv, private templateSrv) { @@ -35,7 +34,7 @@ export class GraphiteQueryCtrl extends QueryCtrl { parseTarget() { this.functions = []; this.segments = []; - delete this.parserError; + this.error = null; if (this.target.textEditor) { return; @@ -49,7 +48,7 @@ export class GraphiteQueryCtrl extends QueryCtrl { } if (astNode.type === 'error') { - this.parserError = astNode.message + " at position: " + astNode.pos; + this.error = astNode.message + " at position: " + astNode.pos; this.target.textEditor = true; return; } @@ -58,7 +57,7 @@ export class GraphiteQueryCtrl extends QueryCtrl { this.parseTargeRecursive(astNode, null, 0); } catch (err) { console.log('error parsing target:', err.message); - this.parserError = err.message; + this.error = err.message; this.target.textEditor = true; } @@ -142,7 +141,7 @@ export class GraphiteQueryCtrl extends QueryCtrl { } } }).catch(err => { - this.parserError = err.message || 'Failed to issue metric query'; + this.error = err.message || 'Failed to issue metric query'; }); } @@ -179,13 +178,13 @@ export class GraphiteQueryCtrl extends QueryCtrl { altSegments.unshift(this.uiSegmentSrv.newSegment('*')); return altSegments; }).catch(err => { - this.parserError = err.message || 'Failed to issue metric query'; + this.error = err.message || 'Failed to issue metric query'; return []; }); } segmentValueChanged(segment, segmentIndex) { - delete this.parserError; + this.error = null; if (this.functions.length > 0 && this.functions[0].def.fake) { this.functions = []; @@ -210,7 +209,7 @@ export class GraphiteQueryCtrl extends QueryCtrl { } targetChanged() { - if (this.parserError) { + if (this.error) { return; } diff --git a/public/app/plugins/datasource/influxdb/datasource.js b/public/app/plugins/datasource/influxdb/datasource.js deleted file mode 100644 index 984d32ab035..00000000000 --- a/public/app/plugins/datasource/influxdb/datasource.js +++ /dev/null @@ -1,220 +0,0 @@ -define([ - 'angular', - 'lodash', - 'app/core/utils/datemath', - './influx_series', - './influx_query', -], -function (angular, _, dateMath, InfluxSeries, InfluxQuery) { - 'use strict'; - - InfluxQuery = InfluxQuery.default; - - /** @ngInject */ - function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) { - this.type = 'influxdb'; - this.urls = _.map(instanceSettings.url.split(','), function(url) { - return url.trim(); - }); - - this.username = instanceSettings.username; - this.password = instanceSettings.password; - this.name = instanceSettings.name; - this.database = instanceSettings.database; - this.basicAuth = instanceSettings.basicAuth; - - this.supportAnnotations = true; - this.supportMetrics = true; - - this.query = function(options) { - var timeFilter = getTimeFilter(options); - var queryTargets = []; - var i, y; - - var allQueries = _.map(options.targets, function(target) { - if (target.hide) { return []; } - - queryTargets.push(target); - - // build query - var queryModel = new InfluxQuery(target); - var query = queryModel.render(); - query = query.replace(/\$interval/g, (target.interval || options.interval)); - return query; - - }).join("\n"); - - // replace grafana variables - allQueries = allQueries.replace(/\$timeFilter/g, timeFilter); - - // replace templated variables - allQueries = templateSrv.replace(allQueries, options.scopedVars); - - return this._seriesQuery(allQueries).then(function(data) { - if (!data || !data.results) { - return []; - } - - var seriesList = []; - for (i = 0; i < data.results.length; i++) { - var result = data.results[i]; - if (!result || !result.series) { continue; } - - var target = queryTargets[i]; - var alias = target.alias; - if (alias) { - alias = templateSrv.replace(target.alias, options.scopedVars); - } - - var influxSeries = new InfluxSeries({ series: data.results[i].series, alias: alias }); - - switch(target.resultFormat) { - case 'table': { - seriesList.push(influxSeries.getTable()); - break; - } - default: { - var timeSeries = influxSeries.getTimeSeries(); - for (y = 0; y < timeSeries.length; y++) { - seriesList.push(timeSeries[y]); - } - break; - } - } - } - - return { data: seriesList }; - }); - }; - - this.annotationQuery = function(options) { - var timeFilter = getTimeFilter({rangeRaw: options.rangeRaw}); - var query = options.annotation.query.replace('$timeFilter', timeFilter); - query = templateSrv.replace(query); - - return this._seriesQuery(query).then(function(data) { - if (!data || !data.results || !data.results[0]) { - throw { message: 'No results in response from InfluxDB' }; - } - return new InfluxSeries({series: data.results[0].series, annotation: options.annotation}).getAnnotations(); - }); - }; - - this.metricFindQuery = function (query) { - var interpolated; - try { - interpolated = templateSrv.replace(query); - } - catch (err) { - return $q.reject(err); - } - - return this._seriesQuery(interpolated).then(function (results) { - if (!results || results.results.length === 0) { return []; } - - var influxResults = results.results[0]; - if (!influxResults.series) { - return []; - } - - var series = influxResults.series[0]; - return _.map(series.values, function(value) { - if (_.isArray(value)) { - return { text: value[0] }; - } else { - return { text: value }; - } - }); - }); - }; - - this._seriesQuery = function(query) { - return this._influxRequest('GET', '/query', {q: query, epoch: 'ms'}); - }; - - this.testDatasource = function() { - return this.metricFindQuery('SHOW MEASUREMENTS LIMIT 1').then(function () { - return { status: "success", message: "Data source is working", title: "Success" }; - }); - }; - - this._influxRequest = function(method, url, data) { - var self = this; - - var currentUrl = self.urls.shift(); - self.urls.push(currentUrl); - - var params = { - u: self.username, - p: self.password, - }; - - if (self.database) { - params.db = self.database; - } - - if (method === 'GET') { - _.extend(params, data); - data = null; - } - - var options = { - method: method, - url: currentUrl + url, - params: params, - data: data, - precision: "ms", - inspect: { type: 'influxdb' }, - }; - - options.headers = options.headers || {}; - if (self.basicAuth) { - options.headers.Authorization = self.basicAuth; - } - - return backendSrv.datasourceRequest(options).then(function(result) { - return result.data; - }, function(err) { - if (err.status !== 0 || err.status >= 300) { - if (err.data && err.data.error) { - throw { message: 'InfluxDB Error Response: ' + err.data.error, data: err.data, config: err.config }; - } - else { - throw { message: 'InfluxDB Error: ' + err.message, data: err.data, config: err.config }; - } - } - }); - }; - - function getTimeFilter(options) { - var from = getInfluxTime(options.rangeRaw.from, false); - var until = getInfluxTime(options.rangeRaw.to, true); - var fromIsAbsolute = from[from.length-1] === 's'; - - if (until === 'now()' && !fromIsAbsolute) { - return 'time > ' + from; - } - - return 'time > ' + from + ' and time < ' + until; - } - - function getInfluxTime(date, roundUp) { - if (_.isString(date)) { - if (date === 'now') { - return 'now()'; - } - - var parts = /^now-(\d+)([d|h|m|s])$/.exec(date); - if (parts) { - var amount = parseInt(parts[1]); - var unit = parts[2]; - return 'now() - ' + amount + unit; - } - date = dateMath.parse(date, roundUp); - } - return (date.valueOf() / 1000).toFixed(0) + 's'; - } - } - - return InfluxDatasource; -}); diff --git a/public/app/plugins/datasource/influxdb/datasource.ts b/public/app/plugins/datasource/influxdb/datasource.ts new file mode 100644 index 00000000000..2ef73dc8f2d --- /dev/null +++ b/public/app/plugins/datasource/influxdb/datasource.ts @@ -0,0 +1,213 @@ +/// + +import angular from 'angular'; +import _ from 'lodash'; + +import * as dateMath from 'app/core/utils/datemath'; +import InfluxSeries from './influx_series'; +import InfluxQuery from './influx_query'; + +/** @ngInject */ +export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) { + this.type = 'influxdb'; + this.urls = _.map(instanceSettings.url.split(','), function(url) { + return url.trim(); + }); + + this.username = instanceSettings.username; + this.password = instanceSettings.password; + this.name = instanceSettings.name; + this.database = instanceSettings.database; + this.basicAuth = instanceSettings.basicAuth; + + this.supportAnnotations = true; + this.supportMetrics = true; + + this.query = function(options) { + var timeFilter = getTimeFilter(options); + var queryTargets = []; + var i, y; + + var allQueries = _.map(options.targets, function(target) { + if (target.hide) { return []; } + + queryTargets.push(target); + + // build query + var queryModel = new InfluxQuery(target); + var query = queryModel.render(); + query = query.replace(/\$interval/g, (target.interval || options.interval)); + return query; + + }).join("\n"); + + // replace grafana variables + allQueries = allQueries.replace(/\$timeFilter/g, timeFilter); + + // replace templated variables + allQueries = templateSrv.replace(allQueries, options.scopedVars); + + return this._seriesQuery(allQueries).then(function(data): any { + if (!data || !data.results) { + return []; + } + + var seriesList = []; + for (i = 0; i < data.results.length; i++) { + var result = data.results[i]; + if (!result || !result.series) { continue; } + + var target = queryTargets[i]; + var alias = target.alias; + if (alias) { + alias = templateSrv.replace(target.alias, options.scopedVars); + } + + var influxSeries = new InfluxSeries({ series: data.results[i].series, alias: alias }); + + switch (target.resultFormat) { + case 'table': { + seriesList.push(influxSeries.getTable()); + break; + } + default: { + var timeSeries = influxSeries.getTimeSeries(); + for (y = 0; y < timeSeries.length; y++) { + seriesList.push(timeSeries[y]); + } + break; + } + } + } + + return { data: seriesList }; + }); + }; + + this.annotationQuery = function(options) { + var timeFilter = getTimeFilter({rangeRaw: options.rangeRaw}); + var query = options.annotation.query.replace('$timeFilter', timeFilter); + query = templateSrv.replace(query); + + return this._seriesQuery(query).then(function(data) { + if (!data || !data.results || !data.results[0]) { + throw { message: 'No results in response from InfluxDB' }; + } + return new InfluxSeries({series: data.results[0].series, annotation: options.annotation}).getAnnotations(); + }); + }; + + this.metricFindQuery = function (query) { + var interpolated; + try { + interpolated = templateSrv.replace(query); + } catch (err) { + return $q.reject(err); + } + + return this._seriesQuery(interpolated).then(function (results) { + if (!results || results.results.length === 0) { return []; } + + var influxResults = results.results[0]; + if (!influxResults.series) { + return []; + } + + var series = influxResults.series[0]; + return _.map(series.values, function(value) { + if (_.isArray(value)) { + return { text: value[0] }; + } else { + return { text: value }; + } + }); + }); + }; + + this._seriesQuery = function(query) { + return this._influxRequest('GET', '/query', {q: query, epoch: 'ms'}); + }; + + this.testDatasource = function() { + return this.metricFindQuery('SHOW MEASUREMENTS LIMIT 1').then(function () { + return { status: "success", message: "Data source is working", title: "Success" }; + }); + }; + + this._influxRequest = function(method, url, data) { + var self = this; + + var currentUrl = self.urls.shift(); + self.urls.push(currentUrl); + + var params: any = { + u: self.username, + p: self.password, + }; + + if (self.database) { + params.db = self.database; + } + + if (method === 'GET') { + _.extend(params, data); + data = null; + } + + var options: any = { + method: method, + url: currentUrl + url, + params: params, + data: data, + precision: "ms", + inspect: { type: 'influxdb' }, + }; + + options.headers = options.headers || {}; + if (self.basicAuth) { + options.headers.Authorization = self.basicAuth; + } + + return backendSrv.datasourceRequest(options).then(function(result) { + return result.data; + }, function(err) { + if (err.status !== 0 || err.status >= 300) { + if (err.data && err.data.error) { + throw { message: 'InfluxDB Error Response: ' + err.data.error, data: err.data, config: err.config }; + } else { + throw { message: 'InfluxDB Error: ' + err.message, data: err.data, config: err.config }; + } + } + }); + }; + + function getTimeFilter(options) { + var from = getInfluxTime(options.rangeRaw.from, false); + var until = getInfluxTime(options.rangeRaw.to, true); + var fromIsAbsolute = from[from.length-1] === 's'; + + if (until === 'now()' && !fromIsAbsolute) { + return 'time > ' + from; + } + + return 'time > ' + from + ' and time < ' + until; + } + + function getInfluxTime(date, roundUp) { + if (_.isString(date)) { + if (date === 'now') { + return 'now()'; + } + + var parts = /^now-(\d+)([d|h|m|s])$/.exec(date); + if (parts) { + var amount = parseInt(parts[1]); + var unit = parts[2]; + return 'now() - ' + amount + unit; + } + date = dateMath.parse(date, roundUp); + } + return (date.valueOf() / 1000).toFixed(0) + 's'; + } +} + diff --git a/public/app/plugins/datasource/influxdb/module.js b/public/app/plugins/datasource/influxdb/module.js deleted file mode 100644 index b7f266f9f89..00000000000 --- a/public/app/plugins/datasource/influxdb/module.js +++ /dev/null @@ -1,30 +0,0 @@ -define([ - './datasource', -], -function (InfluxDatasource) { - 'use strict'; - - function influxMetricsQueryEditor() { - return {controller: 'InfluxQueryCtrl', templateUrl: 'public/app/plugins/datasource/influxdb/partials/query.editor.html'}; - } - - function influxMetricsQueryOptions() { - return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/query.options.html'}; - } - - function influxAnnotationsQueryEditor() { - return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/annotations.editor.html'}; - } - - function influxConfigView() { - return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/config.html'}; - } - - return { - Datasource: InfluxDatasource, - metricsQueryEditor: influxMetricsQueryEditor, - metricsQueryOptions: influxMetricsQueryOptions, - annotationsQueryEditor: influxAnnotationsQueryEditor, - configView: influxConfigView, - }; -}); diff --git a/public/app/plugins/datasource/influxdb/module.ts b/public/app/plugins/datasource/influxdb/module.ts new file mode 100644 index 00000000000..a8acffe6695 --- /dev/null +++ b/public/app/plugins/datasource/influxdb/module.ts @@ -0,0 +1,53 @@ +import {InfluxDatasource} from './datasource'; +import {InfluxQueryCtrl} from './query_ctrl'; + +class InfluxConfigCtrl { + static templateUrl = 'public/app/plugins/datasource/influxdb/partials/config.html'; +} + +class InfluxQueryOptionsCtrl { + static templateUrl = 'public/app/plugins/datasource/influxdb/partials/query.options.html'; +} + +class InfluxAnnotationsQueryCtrl { + static templateUrl = 'public/app/plugins/datasource/influxdb/partials/annotations.editor.html'; +} + +export { + InfluxDatasource as Datasource, + InfluxQueryCtrl as QueryCtrl, + InfluxConfigCtrl as ConfigCtrl, + InfluxQueryOptionsCtrl as QueryOptionsCtrl, + InfluxAnnotationsQueryCtrl as AnnotationsQueryCtrl, +}; + +// define([ +// './datasource', +// ], +// function (InfluxDatasource) { +// 'use strict'; +// +// function influxMetricsQueryEditor() { +// return {controller: 'InfluxQueryCtrl', templateUrl: 'public/app/plugins/datasource/influxdb/partials/query.editor.html'}; +// } +// +// function influxMetricsQueryOptions() { +// return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/query.options.html'}; +// } +// +// function influxAnnotationsQueryEditor() { +// return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/annotations.editor.html'}; +// } +// +// function influxConfigView() { +// return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/config.html'}; +// } +// +// return { +// Datasource: InfluxDatasource, +// metricsQueryEditor: influxMetricsQueryEditor, +// metricsQueryOptions: influxMetricsQueryOptions, +// annotationsQueryEditor: influxAnnotationsQueryEditor, +// configView: influxConfigView, +// }; +// }); diff --git a/public/app/plugins/datasource/influxdb/partials/query.editor.html b/public/app/plugins/datasource/influxdb/partials/query.editor.html index 3322be6c423..8e5546573d7 100644 --- a/public/app/plugins/datasource/influxdb/partials/query.editor.html +++ b/public/app/plugins/datasource/influxdb/partials/query.editor.html @@ -1,119 +1,73 @@ -
    -
    - - -
      -
    • - {{target.refId}} -
    • -
    • - - - -
    • -
    - -
      + +
      • FROM
      • - +
      • - +
      • WHERE
      • -
      • - +
      • +
      - +
      +
      +
      +
      +
        +
      • + SELECT +
      • +
      • + +
      • + +
      -
      - -
      -
        -
      • - SELECT -
      • -
      • - -
      • - -
      -
      -
      - -
      -
        -
      • - GROUP BY -
      • -
      • - -
      • -
      • - -
      • -
      -
      -
      -
      -
      • - ALIAS BY + GROUP BY +
      • +
      • +
      • - -
      • -
      • - Format as -
      • -
      • - +
      -
      + +
      +
        +
      • + ALIAS BY +
      • +
      • + +
      • +
      • + Format as +
      • +
      • + +
      • +
      +
      +
      + diff --git a/public/app/plugins/datasource/influxdb/query_ctrl.js b/public/app/plugins/datasource/influxdb/query_ctrl.js deleted file mode 100644 index fee1d5d1c77..00000000000 --- a/public/app/plugins/datasource/influxdb/query_ctrl.js +++ /dev/null @@ -1,322 +0,0 @@ -define([ - 'angular', - 'lodash', - './query_builder', - './influx_query', - './query_part', - './query_part_editor', -], -function (angular, _, InfluxQueryBuilder, InfluxQuery, queryPart) { - 'use strict'; - - var module = angular.module('grafana.controllers'); - - InfluxQuery = InfluxQuery.default; - queryPart = queryPart.default; - - module.controller('InfluxQueryCtrl', function($scope, templateSrv, $q, uiSegmentSrv) { - var panelCtrl = $scope.ctrl; - var datasource = $scope.datasource; - $scope.panelCtrl = panelCtrl; - - $scope.init = function() { - if (!$scope.target) { return; } - - $scope.target = $scope.target; - $scope.queryModel = new InfluxQuery($scope.target); - $scope.queryBuilder = new InfluxQueryBuilder($scope.target, datasource.database); - $scope.groupBySegment = uiSegmentSrv.newPlusButton(); - $scope.resultFormats = [ - {text: 'Time series', value: 'time_series'}, - {text: 'Table', value: 'table'}, - ]; - - $scope.policySegment = uiSegmentSrv.newSegment($scope.target.policy); - - if (!$scope.target.measurement) { - $scope.measurementSegment = uiSegmentSrv.newSelectMeasurement(); - } else { - $scope.measurementSegment = uiSegmentSrv.newSegment($scope.target.measurement); - } - - $scope.tagSegments = []; - _.each($scope.target.tags, function(tag) { - if (!tag.operator) { - if (/^\/.*\/$/.test(tag.value)) { - tag.operator = "=~"; - } else { - tag.operator = '='; - } - } - - if (tag.condition) { - $scope.tagSegments.push(uiSegmentSrv.newCondition(tag.condition)); - } - - $scope.tagSegments.push(uiSegmentSrv.newKey(tag.key)); - $scope.tagSegments.push(uiSegmentSrv.newOperator(tag.operator)); - $scope.tagSegments.push(uiSegmentSrv.newKeyValue(tag.value)); - }); - - $scope.fixTagSegments(); - $scope.buildSelectMenu(); - $scope.removeTagFilterSegment = uiSegmentSrv.newSegment({fake: true, value: '-- remove tag filter --'}); - }; - - $scope.buildSelectMenu = function() { - var categories = queryPart.getCategories(); - $scope.selectMenu = _.reduce(categories, function(memo, cat, key) { - var menu = {text: key}; - menu.submenu = _.map(cat, function(item) { - return {text: item.type, value: item.type}; - }); - memo.push(menu); - return memo; - }, []); - }; - - $scope.getGroupByOptions = function() { - var query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS'); - - return datasource.metricFindQuery(query) - .then(function(tags) { - var options = []; - if (!$scope.queryModel.hasFill()) { - options.push(uiSegmentSrv.newSegment({value: 'fill(null)'})); - } - if (!$scope.queryModel.hasGroupByTime()) { - options.push(uiSegmentSrv.newSegment({value: 'time($interval)'})); - } - _.each(tags, function(tag) { - options.push(uiSegmentSrv.newSegment({value: 'tag(' + tag.text + ')'})); - }); - return options; - }) - .then(null, $scope.handleQueryError); - }; - - $scope.groupByAction = function() { - $scope.queryModel.addGroupBy($scope.groupBySegment.value); - var plusButton = uiSegmentSrv.newPlusButton(); - $scope.groupBySegment.value = plusButton.value; - $scope.groupBySegment.html = plusButton.html; - panelCtrl.refresh(); - }; - - $scope.removeGroupByPart = function(part, index) { - $scope.queryModel.removeGroupByPart(part, index); - panelCtrl.refresh(); - }; - - $scope.addSelectPart = function(selectParts, cat, subitem) { - $scope.queryModel.addSelectPart(selectParts, subitem.value); - panelCtrl.refresh(); - }; - - $scope.removeSelectPart = function(selectParts, part) { - $scope.queryModel.removeSelectPart(selectParts, part); - panelCtrl.refresh(); - }; - - $scope.selectPartUpdated = function() { - panelCtrl.refresh(); - }; - - $scope.fixTagSegments = function() { - var count = $scope.tagSegments.length; - var lastSegment = $scope.tagSegments[Math.max(count-1, 0)]; - - if (!lastSegment || lastSegment.type !== 'plus-button') { - $scope.tagSegments.push(uiSegmentSrv.newPlusButton()); - } - }; - - $scope.measurementChanged = function() { - $scope.target.measurement = $scope.measurementSegment.value; - panelCtrl.refresh(); - }; - - $scope.getPolicySegments = function() { - var policiesQuery = $scope.queryBuilder.buildExploreQuery('RETENTION POLICIES'); - return datasource.metricFindQuery(policiesQuery) - .then($scope.transformToSegments(false)) - .then(null, $scope.handleQueryError); - }; - - $scope.policyChanged = function() { - $scope.target.policy = $scope.policySegment.value; - panelCtrl.refresh(); - }; - - $scope.toggleQueryMode = function () { - $scope.target.rawQuery = !$scope.target.rawQuery; - }; - - $scope.getMeasurements = function () { - var query = $scope.queryBuilder.buildExploreQuery('MEASUREMENTS'); - return datasource.metricFindQuery(query) - .then($scope.transformToSegments(true), $scope.handleQueryError); - }; - - $scope.getPartOptions = function(part) { - if (part.def.type === 'field') { - var fieldsQuery = $scope.queryBuilder.buildExploreQuery('FIELDS'); - return datasource.metricFindQuery(fieldsQuery) - .then($scope.transformToSegments(true), $scope.handleQueryError); - } - if (part.def.type === 'tag') { - var tagsQuery = $scope.queryBuilder.buildExploreQuery('TAG_KEYS'); - return datasource.metricFindQuery(tagsQuery) - .then($scope.transformToSegments(true), $scope.handleQueryError); - } - }; - - $scope.handleQueryError = function(err) { - $scope.parserError = err.message || 'Failed to issue metric query'; - return []; - }; - - $scope.transformToSegments = function(addTemplateVars) { - return function(results) { - var segments = _.map(results, function(segment) { - return uiSegmentSrv.newSegment({ value: segment.text, expandable: segment.expandable }); - }); - - if (addTemplateVars) { - _.each(templateSrv.variables, function(variable) { - segments.unshift(uiSegmentSrv.newSegment({ type: 'template', value: '/$' + variable.name + '$/', expandable: true })); - }); - } - - return segments; - }; - }; - - $scope.getTagsOrValues = function(segment, index) { - if (segment.type === 'condition') { - return $q.when([uiSegmentSrv.newSegment('AND'), uiSegmentSrv.newSegment('OR')]); - } - if (segment.type === 'operator') { - var nextValue = $scope.tagSegments[index+1].value; - if (/^\/.*\/$/.test(nextValue)) { - return $q.when(uiSegmentSrv.newOperators(['=~', '!~'])); - } else { - return $q.when(uiSegmentSrv.newOperators(['=', '<>', '<', '>'])); - } - } - - var query, addTemplateVars; - if (segment.type === 'key' || segment.type === 'plus-button') { - query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS'); - addTemplateVars = false; - } else if (segment.type === 'value') { - query = $scope.queryBuilder.buildExploreQuery('TAG_VALUES', $scope.tagSegments[index-2].value); - addTemplateVars = true; - } - - return datasource.metricFindQuery(query) - .then($scope.transformToSegments(addTemplateVars)) - .then(function(results) { - if (segment.type === 'key') { - results.splice(0, 0, angular.copy($scope.removeTagFilterSegment)); - } - return results; - }) - .then(null, $scope.handleQueryError); - }; - - $scope.getFieldSegments = function() { - var fieldsQuery = $scope.queryBuilder.buildExploreQuery('FIELDS'); - return datasource.metricFindQuery(fieldsQuery) - .then($scope.transformToSegments(false)) - .then(null, $scope.handleQueryError); - }; - - $scope.getTagOptions = function() { - }; - - $scope.setFill = function(fill) { - $scope.target.fill = fill; - panelCtrl.refresh(); - }; - - $scope.tagSegmentUpdated = function(segment, index) { - $scope.tagSegments[index] = segment; - - // handle remove tag condition - if (segment.value === $scope.removeTagFilterSegment.value) { - $scope.tagSegments.splice(index, 3); - if ($scope.tagSegments.length === 0) { - $scope.tagSegments.push(uiSegmentSrv.newPlusButton()); - } else if ($scope.tagSegments.length > 2) { - $scope.tagSegments.splice(Math.max(index-1, 0), 1); - if ($scope.tagSegments[$scope.tagSegments.length-1].type !== 'plus-button') { - $scope.tagSegments.push(uiSegmentSrv.newPlusButton()); - } - } - } - else { - if (segment.type === 'plus-button') { - if (index > 2) { - $scope.tagSegments.splice(index, 0, uiSegmentSrv.newCondition('AND')); - } - $scope.tagSegments.push(uiSegmentSrv.newOperator('=')); - $scope.tagSegments.push(uiSegmentSrv.newFake('select tag value', 'value', 'query-segment-value')); - segment.type = 'key'; - segment.cssClass = 'query-segment-key'; - } - - if ((index+1) === $scope.tagSegments.length) { - $scope.tagSegments.push(uiSegmentSrv.newPlusButton()); - } - } - - $scope.rebuildTargetTagConditions(); - }; - - $scope.rebuildTargetTagConditions = function() { - var tags = []; - var tagIndex = 0; - var tagOperator = ""; - _.each($scope.tagSegments, function(segment2, index) { - if (segment2.type === 'key') { - if (tags.length === 0) { - tags.push({}); - } - tags[tagIndex].key = segment2.value; - } - else if (segment2.type === 'value') { - tagOperator = $scope.getTagValueOperator(segment2.value, tags[tagIndex].operator); - if (tagOperator) { - $scope.tagSegments[index-1] = uiSegmentSrv.newOperator(tagOperator); - tags[tagIndex].operator = tagOperator; - } - tags[tagIndex].value = segment2.value; - } - else if (segment2.type === 'condition') { - tags.push({ condition: segment2.value }); - tagIndex += 1; - } - else if (segment2.type === 'operator') { - tags[tagIndex].operator = segment2.value; - } - }); - - $scope.target.tags = tags; - panelCtrl.refresh(); - }; - - $scope.getTagValueOperator = function(tagValue, tagOperator) { - if (tagOperator !== '=~' && tagOperator !== '!~' && /^\/.*\/$/.test(tagValue)) { - return '=~'; - } - else if ((tagOperator === '=~' || tagOperator === '!~') && /^(?!\/.*\/$)/.test(tagValue)) { - return '='; - } - }; - - $scope.init(); - - }); - -}); diff --git a/public/app/plugins/datasource/influxdb/query_ctrl.ts b/public/app/plugins/datasource/influxdb/query_ctrl.ts new file mode 100644 index 00000000000..8c32ff36b0b --- /dev/null +++ b/public/app/plugins/datasource/influxdb/query_ctrl.ts @@ -0,0 +1,318 @@ +/// + +import './query_part_editor'; +import './query_part_editor'; + +import angular from 'angular'; +import _ from 'lodash'; +import InfluxQueryBuilder from './query_builder'; +import InfluxQuery from './influx_query'; +import queryPart from './query_part'; +import {QueryCtrl} from 'app/features/panel/panel'; + +export class InfluxQueryCtrl extends QueryCtrl { + static templateUrl = 'public/app/plugins/datasource/influxdb/partials/query.editor.html'; + + queryModel: InfluxQuery; + queryBuilder: any; + groupBySegment: any; + resultFormats: any[]; + policySegment: any; + tagSegments: any[]; + selectMenu: any; + measurementSegment: any; + removeTagFilterSegment: any; + + constructor($scope, $injector, private templateSrv, private $q, private uiSegmentSrv) { + super($scope, $injector); + + this.target = this.target; + this.queryModel = new InfluxQuery(this.target); + this.queryBuilder = new InfluxQueryBuilder(this.target, this.datasource.database); + this.groupBySegment = this.uiSegmentSrv.newPlusButton(); + this.resultFormats = [ + {text: 'Time series', value: 'time_series'}, + {text: 'Table', value: 'table'}, + ]; + + this.policySegment = uiSegmentSrv.newSegment(this.target.policy); + + if (!this.target.measurement) { + this.measurementSegment = uiSegmentSrv.newSelectMeasurement(); + } else { + this.measurementSegment = uiSegmentSrv.newSegment(this.target.measurement); + } + + this.tagSegments = []; + for (let tag of this.target.tags) { + if (!tag.operator) { + if (/^\/.*\/$/.test(tag.value)) { + tag.operator = "=~"; + } else { + tag.operator = '='; + } + } + + if (tag.condition) { + this.tagSegments.push(uiSegmentSrv.newCondition(tag.condition)); + } + + this.tagSegments.push(uiSegmentSrv.newKey(tag.key)); + this.tagSegments.push(uiSegmentSrv.newOperator(tag.operator)); + this.tagSegments.push(uiSegmentSrv.newKeyValue(tag.value)); + } + + this.fixTagSegments(); + this.buildSelectMenu(); + this.removeTagFilterSegment = uiSegmentSrv.newSegment({fake: true, value: '-- remove tag filter --'}); + } + + buildSelectMenu() { + var categories = queryPart.getCategories(); + this.selectMenu = _.reduce(categories, function(memo, cat, key) { + var menu = { + text: key, + submenu: cat.map(item => { + return {text: item.type, value: item.type}; + }), + }; + memo.push(menu); + return memo; + }, []); + } + + getGroupByOptions() { + var query = this.queryBuilder.buildExploreQuery('TAG_KEYS'); + + return this.datasource.metricFindQuery(query).then(tags => { + var options = []; + if (!this.queryModel.hasFill()) { + options.push(this.uiSegmentSrv.newSegment({value: 'fill(null)'})); + } + if (!this.queryModel.hasGroupByTime()) { + options.push(this.uiSegmentSrv.newSegment({value: 'time($interval)'})); + } + for (let tag of tags) { + options.push(this.uiSegmentSrv.newSegment({value: 'tag(' + tag.text + ')'})); + } + return options; + }).catch(this.handleQueryError.bind(this)); + } + + groupByAction() { + this.queryModel.addGroupBy(this.groupBySegment.value); + var plusButton = this.uiSegmentSrv.newPlusButton(); + this.groupBySegment.value = plusButton.value; + this.groupBySegment.html = plusButton.html; + this.panelCtrl.refresh(); + } + + removeGroupByPart(part, index) { + this.queryModel.removeGroupByPart(part, index); + this.panelCtrl.refresh(); + } + + addSelectPart(selectParts, cat, subitem) { + this.queryModel.addSelectPart(selectParts, subitem.value); + this.panelCtrl.refresh(); + } + + removeSelectPart(selectParts, part) { + this.queryModel.removeSelectPart(selectParts, part); + this.panelCtrl.refresh(); + } + + selectPartUpdated() { + this.panelCtrl.refresh(); + } + + fixTagSegments() { + var count = this.tagSegments.length; + var lastSegment = this.tagSegments[Math.max(count-1, 0)]; + + if (!lastSegment || lastSegment.type !== 'plus-button') { + this.tagSegments.push(this.uiSegmentSrv.newPlusButton()); + } + } + + measurementChanged() { + this.target.measurement = this.measurementSegment.value; + this.panelCtrl.refresh(); + } + + getPolicySegments() { + var policiesQuery = this.queryBuilder.buildExploreQuery('RETENTION POLICIES'); + return this.datasource.metricFindQuery(policiesQuery) + .then(this.transformToSegments(false)) + .catch(this.handleQueryError.bind(this)); + } + + policyChanged() { + this.target.policy = this.policySegment.value; + this.panelCtrl.refresh(); + } + + toggleQueryMode() { + this.target.rawQuery = !this.target.rawQuery; + } + + getMeasurements() { + var query = this.queryBuilder.buildExploreQuery('MEASUREMENTS'); + return this.datasource.metricFindQuery(query) + .then(this.transformToSegments(true)) + .catch(this.handleQueryError.bind(this)); + } + + getPartOptions(part) { + if (part.def.type === 'field') { + var fieldsQuery = this.queryBuilder.buildExploreQuery('FIELDS'); + return this.datasource.metricFindQuery(fieldsQuery) + .then(this.transformToSegments(true)) + .catch(this.handleQueryError.bind(this)); + } + if (part.def.type === 'tag') { + var tagsQuery = this.queryBuilder.buildExploreQuery('TAG_KEYS'); + return this.datasource.metricFindQuery(tagsQuery) + .then(this.transformToSegments(true)) + .catch(this.handleQueryError.bind(true)); + } + } + + handleQueryError(err) { + this.error = err.message || 'Failed to issue metric query'; + return []; + } + + transformToSegments(addTemplateVars) { + return (results) => { + var segments = _.map(results, segment => { + return this.uiSegmentSrv.newSegment({ value: segment.text, expandable: segment.expandable }); + }); + + if (addTemplateVars) { + for (let variable of this.templateSrv.variables) { + segments.unshift(this.uiSegmentSrv.newSegment({ type: 'template', value: '/$' + variable.name + '$/', expandable: true })); + } + } + + return segments; + }; + } + + getTagsOrValues(segment, index) { + if (segment.type === 'condition') { + return this.$q.when([this.uiSegmentSrv.newSegment('AND'), this.uiSegmentSrv.newSegment('OR')]); + } + if (segment.type === 'operator') { + var nextValue = this.tagSegments[index+1].value; + if (/^\/.*\/$/.test(nextValue)) { + return this.$q.when(this.uiSegmentSrv.newOperators(['=~', '!~'])); + } else { + return this.$q.when(this.uiSegmentSrv.newOperators(['=', '<>', '<', '>'])); + } + } + + var query, addTemplateVars; + if (segment.type === 'key' || segment.type === 'plus-button') { + query = this.queryBuilder.buildExploreQuery('TAG_KEYS'); + addTemplateVars = false; + } else if (segment.type === 'value') { + query = this.queryBuilder.buildExploreQuery('TAG_VALUES', this.tagSegments[index-2].value); + addTemplateVars = true; + } + + return this.datasource.metricFindQuery(query) + .then(this.transformToSegments(addTemplateVars)) + .then(results => { + if (segment.type === 'key') { + results.splice(0, 0, angular.copy(this.removeTagFilterSegment)); + } + return results; + }) + .catch(this.handleQueryError.bind(this)); + } + + getFieldSegments() { + var fieldsQuery = this.queryBuilder.buildExploreQuery('FIELDS'); + return this.datasource.metricFindQuery(fieldsQuery) + .then(this.transformToSegments(false)) + .catch(this.handleQueryError); + } + + setFill(fill) { + this.target.fill = fill; + this.panelCtrl.refresh(); + } + + tagSegmentUpdated(segment, index) { + this.tagSegments[index] = segment; + + // handle remove tag condition + if (segment.value === this.removeTagFilterSegment.value) { + this.tagSegments.splice(index, 3); + if (this.tagSegments.length === 0) { + this.tagSegments.push(this.uiSegmentSrv.newPlusButton()); + } else if (this.tagSegments.length > 2) { + this.tagSegments.splice(Math.max(index-1, 0), 1); + if (this.tagSegments[this.tagSegments.length-1].type !== 'plus-button') { + this.tagSegments.push(this.uiSegmentSrv.newPlusButton()); + } + } + } else { + if (segment.type === 'plus-button') { + if (index > 2) { + this.tagSegments.splice(index, 0, this.uiSegmentSrv.newCondition('AND')); + } + this.tagSegments.push(this.uiSegmentSrv.newOperator('=')); + this.tagSegments.push(this.uiSegmentSrv.newFake('select tag value', 'value', 'query-segment-value')); + segment.type = 'key'; + segment.cssClass = 'query-segment-key'; + } + + if ((index+1) === this.tagSegments.length) { + this.tagSegments.push(this.uiSegmentSrv.newPlusButton()); + } + } + + this.rebuildTargetTagConditions(); + } + + rebuildTargetTagConditions() { + var tags = []; + var tagIndex = 0; + var tagOperator = ""; + + _.each(this.tagSegments, (segment2, index) => { + if (segment2.type === 'key') { + if (tags.length === 0) { + tags.push({}); + } + tags[tagIndex].key = segment2.value; + } else if (segment2.type === 'value') { + tagOperator = this.getTagValueOperator(segment2.value, tags[tagIndex].operator); + if (tagOperator) { + this.tagSegments[index-1] = this.uiSegmentSrv.newOperator(tagOperator); + tags[tagIndex].operator = tagOperator; + } + tags[tagIndex].value = segment2.value; + } else if (segment2.type === 'condition') { + tags.push({ condition: segment2.value }); + tagIndex += 1; + } else if (segment2.type === 'operator') { + tags[tagIndex].operator = segment2.value; + } + }); + + this.target.tags = tags; + this.panelCtrl.refresh(); + } + + getTagValueOperator(tagValue, tagOperator) { + if (tagOperator !== '=~' && tagOperator !== '!~' && /^\/.*\/$/.test(tagValue)) { + return '=~'; + } else if ((tagOperator === '=~' || tagOperator === '!~') && /^(?!\/.*\/$)/.test(tagValue)) { + return '='; + } + } +} + diff --git a/public/app/plugins/datasource/influxdb/specs/query_ctrl_specs.ts b/public/app/plugins/datasource/influxdb/specs/query_ctrl_specs.ts index 778f08e1352..427869c1d10 100644 --- a/public/app/plugins/datasource/influxdb/specs/query_ctrl_specs.ts +++ b/public/app/plugins/datasource/influxdb/specs/query_ctrl_specs.ts @@ -2,6 +2,7 @@ import '../query_ctrl'; import 'app/core/services/segment_srv'; import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; import helpers from 'test/specs/helpers'; +import {InfluxQueryCtrl} from '../query_ctrl'; describe('InfluxDBQueryCtrl', function() { var ctx = new helpers.ControllerTestContext(); @@ -14,179 +15,164 @@ describe('InfluxDBQueryCtrl', function() { beforeEach(angularMocks.inject(($rootScope, $controller, $q) => { ctx.$q = $q; ctx.scope = $rootScope.$new(); - ctx.scope.ctrl = {panel: ctx.panel}; - ctx.scope.datasource = ctx.datasource; - ctx.scope.datasource.metricFindQuery = sinon.stub().returns(ctx.$q.when([])); - ctx.panelCtrl = ctx.scope.ctrl; - ctx.controller = $controller('InfluxQueryCtrl', {$scope: ctx.scope}); + ctx.datasource.metricFindQuery = sinon.stub().returns(ctx.$q.when([])); + ctx.panelCtrl = {panel: {}}; + ctx.panelCtrl.refresh = sinon.spy(); + ctx.target = {target: {}}; + ctx.ctrl = $controller(InfluxQueryCtrl, {$scope: ctx.scope}, { + panelCtrl: ctx.panelCtrl, + target: ctx.target, + datasource: ctx.datasource + }); })); - beforeEach(function() { - ctx.scope.target = {}; - ctx.panelCtrl.refresh = sinon.spy(); - }); - describe('init', function() { - beforeEach(function() { - ctx.scope.init(); - }); - it('should init tagSegments', function() { - expect(ctx.scope.tagSegments.length).to.be(1); + expect(ctx.ctrl.tagSegments.length).to.be(1); }); it('should init measurementSegment', function() { - expect(ctx.scope.measurementSegment.value).to.be('select measurement'); + expect(ctx.ctrl.measurementSegment.value).to.be('select measurement'); }); }); describe('when first tag segment is updated', function() { beforeEach(function() { - ctx.scope.init(); - ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button'}, 0); + ctx.ctrl.tagSegmentUpdated({value: 'asd', type: 'plus-button'}, 0); }); it('should update tag key', function() { - expect(ctx.scope.target.tags[0].key).to.be('asd'); - expect(ctx.scope.tagSegments[0].type).to.be('key'); + expect(ctx.ctrl.target.tags[0].key).to.be('asd'); + expect(ctx.ctrl.tagSegments[0].type).to.be('key'); }); it('should add tagSegments', function() { - expect(ctx.scope.tagSegments.length).to.be(3); + expect(ctx.ctrl.tagSegments.length).to.be(3); }); }); describe('when last tag value segment is updated', function() { beforeEach(function() { - ctx.scope.init(); - ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button'}, 0); - ctx.scope.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); + ctx.ctrl.tagSegmentUpdated({value: 'asd', type: 'plus-button'}, 0); + ctx.ctrl.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); }); it('should update tag value', function() { - expect(ctx.scope.target.tags[0].value).to.be('server1'); + expect(ctx.ctrl.target.tags[0].value).to.be('server1'); }); it('should set tag operator', function() { - expect(ctx.scope.target.tags[0].operator).to.be('='); + expect(ctx.ctrl.target.tags[0].operator).to.be('='); }); it('should add plus button for another filter', function() { - expect(ctx.scope.tagSegments[3].fake).to.be(true); + expect(ctx.ctrl.tagSegments[3].fake).to.be(true); }); }); describe('when last tag value segment is updated to regex', function() { beforeEach(function() { - ctx.scope.init(); - ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button'}, 0); - ctx.scope.tagSegmentUpdated({value: '/server.*/', type: 'value'}, 2); + ctx.ctrl.tagSegmentUpdated({value: 'asd', type: 'plus-button'}, 0); + ctx.ctrl.tagSegmentUpdated({value: '/server.*/', type: 'value'}, 2); }); it('should update operator', function() { - expect(ctx.scope.tagSegments[1].value).to.be('=~'); - expect(ctx.scope.target.tags[0].operator).to.be('=~'); + expect(ctx.ctrl.tagSegments[1].value).to.be('=~'); + expect(ctx.ctrl.target.tags[0].operator).to.be('=~'); }); }); describe('when second tag key is added', function() { beforeEach(function() { - ctx.scope.init(); - ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0); - ctx.scope.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); - ctx.scope.tagSegmentUpdated({value: 'key2', type: 'plus-button'}, 3); + ctx.ctrl.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0); + ctx.ctrl.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); + ctx.ctrl.tagSegmentUpdated({value: 'key2', type: 'plus-button'}, 3); }); it('should update tag key', function() { - expect(ctx.scope.target.tags[1].key).to.be('key2'); + expect(ctx.ctrl.target.tags[1].key).to.be('key2'); }); it('should add AND segment', function() { - expect(ctx.scope.tagSegments[3].value).to.be('AND'); + expect(ctx.ctrl.tagSegments[3].value).to.be('AND'); }); }); describe('when condition is changed', function() { beforeEach(function() { - ctx.scope.init(); - ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0); - ctx.scope.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); - ctx.scope.tagSegmentUpdated({value: 'key2', type: 'plus-button'}, 3); - ctx.scope.tagSegmentUpdated({value: 'OR', type: 'condition'}, 3); + ctx.ctrl.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0); + ctx.ctrl.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); + ctx.ctrl.tagSegmentUpdated({value: 'key2', type: 'plus-button'}, 3); + ctx.ctrl.tagSegmentUpdated({value: 'OR', type: 'condition'}, 3); }); it('should update tag condition', function() { - expect(ctx.scope.target.tags[1].condition).to.be('OR'); + expect(ctx.ctrl.target.tags[1].condition).to.be('OR'); }); it('should update AND segment', function() { - expect(ctx.scope.tagSegments[3].value).to.be('OR'); - expect(ctx.scope.tagSegments.length).to.be(7); + expect(ctx.ctrl.tagSegments[3].value).to.be('OR'); + expect(ctx.ctrl.tagSegments.length).to.be(7); }); }); describe('when deleting first tag filter after value is selected', function() { beforeEach(function() { - ctx.scope.init(); - ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0); - ctx.scope.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); - ctx.scope.tagSegmentUpdated(ctx.scope.removeTagFilterSegment, 0); + ctx.ctrl.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0); + ctx.ctrl.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); + ctx.ctrl.tagSegmentUpdated(ctx.ctrl.removeTagFilterSegment, 0); }); it('should remove tags', function() { - expect(ctx.scope.target.tags.length).to.be(0); + expect(ctx.ctrl.target.tags.length).to.be(0); }); it('should remove all segment after 2 and replace with plus button', function() { - expect(ctx.scope.tagSegments.length).to.be(1); - expect(ctx.scope.tagSegments[0].type).to.be('plus-button'); + expect(ctx.ctrl.tagSegments.length).to.be(1); + expect(ctx.ctrl.tagSegments[0].type).to.be('plus-button'); }); }); describe('when deleting second tag value before second tag value is complete', function() { beforeEach(function() { - ctx.scope.init(); - ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0); - ctx.scope.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); - ctx.scope.tagSegmentUpdated({value: 'key2', type: 'plus-button'}, 3); - ctx.scope.tagSegmentUpdated(ctx.scope.removeTagFilterSegment, 4); + ctx.ctrl.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0); + ctx.ctrl.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); + ctx.ctrl.tagSegmentUpdated({value: 'key2', type: 'plus-button'}, 3); + ctx.ctrl.tagSegmentUpdated(ctx.ctrl.removeTagFilterSegment, 4); }); it('should remove all segment after 2 and replace with plus button', function() { - expect(ctx.scope.tagSegments.length).to.be(4); - expect(ctx.scope.tagSegments[3].type).to.be('plus-button'); + expect(ctx.ctrl.tagSegments.length).to.be(4); + expect(ctx.ctrl.tagSegments[3].type).to.be('plus-button'); }); }); describe('when deleting second tag value before second tag value is complete', function() { beforeEach(function() { - ctx.scope.init(); - ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0); - ctx.scope.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); - ctx.scope.tagSegmentUpdated({value: 'key2', type: 'plus-button'}, 3); - ctx.scope.tagSegmentUpdated(ctx.scope.removeTagFilterSegment, 4); + ctx.ctrl.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0); + ctx.ctrl.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); + ctx.ctrl.tagSegmentUpdated({value: 'key2', type: 'plus-button'}, 3); + ctx.ctrl.tagSegmentUpdated(ctx.ctrl.removeTagFilterSegment, 4); }); it('should remove all segment after 2 and replace with plus button', function() { - expect(ctx.scope.tagSegments.length).to.be(4); - expect(ctx.scope.tagSegments[3].type).to.be('plus-button'); + expect(ctx.ctrl.tagSegments.length).to.be(4); + expect(ctx.ctrl.tagSegments[3].type).to.be('plus-button'); }); }); describe('when deleting second tag value after second tag filter is complete', function() { beforeEach(function() { - ctx.scope.init(); - ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0); - ctx.scope.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); - ctx.scope.tagSegmentUpdated({value: 'key2', type: 'plus-button'}, 3); - ctx.scope.tagSegmentUpdated({value: 'value', type: 'value'}, 6); - ctx.scope.tagSegmentUpdated(ctx.scope.removeTagFilterSegment, 4); + ctx.ctrl.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0); + ctx.ctrl.tagSegmentUpdated({value: 'server1', type: 'value'}, 2); + ctx.ctrl.tagSegmentUpdated({value: 'key2', type: 'plus-button'}, 3); + ctx.ctrl.tagSegmentUpdated({value: 'value', type: 'value'}, 6); + ctx.ctrl.tagSegmentUpdated(ctx.ctrl.removeTagFilterSegment, 4); }); it('should remove all segment after 2 and replace with plus button', function() { - expect(ctx.scope.tagSegments.length).to.be(4); - expect(ctx.scope.tagSegments[3].type).to.be('plus-button'); + expect(ctx.ctrl.tagSegments.length).to.be(4); + expect(ctx.ctrl.tagSegments[3].type).to.be('plus-button'); }); }); - });