/// 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 '='; } } }