From fe943ac0e40c1e8a619246bab5ed98ff136a9641 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Fri, 4 Oct 2019 17:10:17 +0200 Subject: [PATCH 01/27] CI: fix shellcheck issues (#789) Signed-off-by: Mario Trangoni --- .circleci/deploy-docs.sh | 10 +++++----- .circleci/make-release.sh | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.circleci/deploy-docs.sh b/.circleci/deploy-docs.sh index ab919f2..e497ad0 100755 --- a/.circleci/deploy-docs.sh +++ b/.circleci/deploy-docs.sh @@ -10,15 +10,15 @@ set -o pipefail echo "current dir: $(pwd)" # Setup git env -git config --global user.email $CI_GIT_EMAIL -git config --global user.name $CI_GIT_USER +git config --global user.email "$CI_GIT_EMAIL" +git config --global user.name "$CI_GIT_USER" echo "git user is $CI_GIT_USER ($CI_GIT_EMAIL)" -git checkout -b $GH_PAGES_BRANCH -rm -rf * || true +git checkout -b "$GH_PAGES_BRANCH" +rm -rf ./* || true mv ../gh-pages/docs/site/* ./ git add --force . git commit -m "build docs from commit ${CIRCLE_SHA1:0:7} (branch $CIRCLE_BRANCH)" git log -n 3 -git push origin $GH_PAGES_BRANCH --force +git push origin "$GH_PAGES_BRANCH" --force diff --git a/.circleci/make-release.sh b/.circleci/make-release.sh index e0efc96..de0e8d9 100755 --- a/.circleci/make-release.sh +++ b/.circleci/make-release.sh @@ -8,13 +8,13 @@ set -o errexit set -o pipefail # Setup git env -git config --global user.email $CI_GIT_EMAIL -git config --global user.name $CI_GIT_USER +git config --global user.email "$CI_GIT_EMAIL" +git config --global user.name "$CI_GIT_USER" echo "git user is $CI_GIT_USER ($CI_GIT_EMAIL)" -RELEASE_VER=$(echo $CIRCLE_TAG | grep -Po "(?<=v)[0-9]+(\.[0-9]+){2}(-.+|[^-.]*)") +RELEASE_VER=$(echo "$CIRCLE_TAG" | grep -Po "(?<=v)[0-9]+(\.[0-9]+){2}(-.+|[^-.]*)") -if [ -z $RELEASE_VER ]; then +if [ -z "$RELEASE_VER" ]; then echo "No release version provided" exit 1 fi @@ -28,7 +28,7 @@ fi RELEASE_BRANCH=release-$RELEASE_VER # Build plugin -git checkout -b $RELEASE_BRANCH +git checkout -b "$RELEASE_BRANCH" yarn install --pure-lockfile && yarn build # Commit release @@ -36,7 +36,7 @@ git add --force dist/ git commit -m "release $RELEASE_VER" RELEASE_COMMIT_HASH=$(git log -n 1 | grep -Po "(?<=commit )[0-9a-z]{40}") -echo $RELEASE_COMMIT_HASH +echo "$RELEASE_COMMIT_HASH" # Push release branch -git push origin $RELEASE_BRANCH +git push origin "$RELEASE_BRANCH" From 9cf13230ebb64bafbff81388f12525439a10fa8e Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Tue, 8 Oct 2019 18:49:36 +0300 Subject: [PATCH 02/27] annotations: fix options in grafana 6.x, fix #813 --- .../partials/annotations.editor.html | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/datasource-zabbix/partials/annotations.editor.html b/src/datasource-zabbix/partials/annotations.editor.html index 6e2e495..16453e5 100644 --- a/src/datasource-zabbix/partials/annotations.editor.html +++ b/src/datasource-zabbix/partials/annotations.editor.html @@ -1,5 +1,4 @@
-
Filter Triggers
Group @@ -36,8 +35,9 @@
+
Options
- Minimum severity + Minimum severity
@@ -67,35 +67,35 @@
diff --git a/src/panel-triggers/specs/migrations.spec.js b/src/panel-triggers/specs/migrations.spec.ts similarity index 76% rename from src/panel-triggers/specs/migrations.spec.js rename to src/panel-triggers/specs/migrations.spec.ts index f411350..bd916e8 100644 --- a/src/panel-triggers/specs/migrations.spec.js +++ b/src/panel-triggers/specs/migrations.spec.ts @@ -5,16 +5,16 @@ import {DEFAULT_TARGET, DEFAULT_SEVERITY, PANEL_DEFAULTS} from '../triggers_pane import {CURRENT_SCHEMA_VERSION} from '../migrations'; describe('Triggers Panel schema migration', () => { - let ctx = {}; + let ctx: any = {}; let updatePanelCtrl; - let datasourceSrvMock = { + const datasourceSrvMock = { getMetricSources: () => { return [{ meta: {id: 'alexanderzobnin-zabbix-datasource'}, value: {}, name: 'zabbix_default' }]; }, get: () => Promise.resolve({}) }; - let timeoutMock = () => {}; + const timeoutMock = () => {}; beforeEach(() => { ctx = { @@ -47,14 +47,16 @@ describe('Triggers Panel schema migration', () => { }); it('should update old panel schema', () => { - let updatedPanelCtrl = updatePanelCtrl(ctx.scope); + const updatedPanelCtrl = updatePanelCtrl(ctx.scope); - let expected = _.defaultsDeep({ + const expected = _.defaultsDeep({ schemaVersion: CURRENT_SCHEMA_VERSION, - datasources: ['zabbix'], - targets: { - 'zabbix': DEFAULT_TARGET - }, + targets: [ + { + ...DEFAULT_TARGET, + datasource: 'zabbix', + } + ], ageField: true, statusField: false, severityField: false, @@ -68,29 +70,29 @@ describe('Triggers Panel schema migration', () => { it('should create new panel with default schema', () => { ctx.scope.panel = {}; - let updatedPanelCtrl = updatePanelCtrl(ctx.scope); + const updatedPanelCtrl = updatePanelCtrl(ctx.scope); - let expected = _.defaultsDeep({ + const expected = _.defaultsDeep({ schemaVersion: CURRENT_SCHEMA_VERSION, - datasources: ['zabbix_default'], - targets: { - 'zabbix_default': DEFAULT_TARGET - } + targets: [{ + ...DEFAULT_TARGET, + datasource: 'zabbix_default' + }] }, PANEL_DEFAULTS); expect(updatedPanelCtrl.panel).toEqual(expected); }); it('should set default targets for new panel with empty targets', () => { ctx.scope.panel = { - targets: [{}] + targets: [] }; - let updatedPanelCtrl = updatePanelCtrl(ctx.scope); + const updatedPanelCtrl = updatePanelCtrl(ctx.scope); - let expected = _.defaultsDeep({ - datasources: ['zabbix_default'], - targets: { - 'zabbix_default': DEFAULT_TARGET - }, + const expected = _.defaultsDeep({ + targets: [{ + ...DEFAULT_TARGET, + datasource: 'zabbix_default' + }] }, PANEL_DEFAULTS); expect(updatedPanelCtrl.panel).toEqual(expected); diff --git a/src/panel-triggers/specs/panel_ctrl.spec.js b/src/panel-triggers/specs/panel_ctrl.spec.ts similarity index 84% rename from src/panel-triggers/specs/panel_ctrl.spec.js rename to src/panel-triggers/specs/panel_ctrl.spec.ts index bdfa90b..67283c9 100644 --- a/src/panel-triggers/specs/panel_ctrl.spec.js +++ b/src/panel-triggers/specs/panel_ctrl.spec.ts @@ -5,9 +5,9 @@ import {PANEL_DEFAULTS, DEFAULT_TARGET} from '../triggers_panel_ctrl'; // import { create } from 'domain'; describe('TriggerPanelCtrl', () => { - let ctx = {}; + let ctx: any = {}; let datasourceSrvMock, zabbixDSMock; - let timeoutMock = () => {}; + const timeoutMock = () => {}; let createPanelCtrl; beforeEach(() => { @@ -61,7 +61,7 @@ describe('TriggerPanelCtrl', () => { describe('When adding new panel', () => { it('should suggest all zabbix data sources', () => { ctx.scope.panel = {}; - let panelCtrl = createPanelCtrl(); + const panelCtrl = createPanelCtrl(); expect(panelCtrl.available_datasources).toEqual([ 'zabbix_default', 'zabbix' ]); @@ -69,10 +69,8 @@ describe('TriggerPanelCtrl', () => { it('should load first zabbix data source as default', () => { ctx.scope.panel = {}; - let panelCtrl = createPanelCtrl(); - expect(panelCtrl.panel.datasources).toEqual([ - 'zabbix_default' - ]); + const panelCtrl = createPanelCtrl(); + expect(panelCtrl.panel.targets[0].datasource).toEqual('zabbix_default'); }); it('should rewrite default empty target', () => { @@ -82,7 +80,7 @@ describe('TriggerPanelCtrl', () => { "refId": "A" }], }; - let panelCtrl = createPanelCtrl(); + const panelCtrl = createPanelCtrl(); expect(panelCtrl.available_datasources).toEqual([ 'zabbix_default', 'zabbix' ]); @@ -92,16 +90,22 @@ describe('TriggerPanelCtrl', () => { describe('When refreshing panel', () => { beforeEach(() => { ctx.scope.panel.datasources = ['zabbix_default', 'zabbix']; - ctx.scope.panel.targets = { - 'zabbix_default': DEFAULT_TARGET, - 'zabbix': DEFAULT_TARGET - }; + ctx.scope.panel.targets = [ + { + ...DEFAULT_TARGET, + datasource: 'zabbix_default' + }, + { + ...DEFAULT_TARGET, + datasource: 'zabbix' + }, + ]; ctx.panelCtrl = createPanelCtrl(); }); it('should format triggers', (done) => { ctx.panelCtrl.onRefresh().then(() => { - let formattedTrigger = _.find(ctx.panelCtrl.triggerList, {triggerid: "1"}); + const formattedTrigger: any = _.find(ctx.panelCtrl.triggerList, {triggerid: "1"}); expect(formattedTrigger.host).toBe('backend01'); expect(formattedTrigger.hostTechName).toBe('backend01_tech'); expect(formattedTrigger.datasource).toBe('zabbix_default'); @@ -113,7 +117,7 @@ describe('TriggerPanelCtrl', () => { it('should sort triggers by time by default', (done) => { ctx.panelCtrl.onRefresh().then(() => { - let trigger_ids = _.map(ctx.panelCtrl.triggerList, 'triggerid'); + const trigger_ids = _.map(ctx.panelCtrl.triggerList, 'triggerid'); expect(trigger_ids).toEqual([ '2', '4', '3', '1' ]); @@ -124,7 +128,7 @@ describe('TriggerPanelCtrl', () => { it('should sort triggers by severity', (done) => { ctx.panelCtrl.panel.sortTriggersBy = { text: 'severity', value: 'priority' }; ctx.panelCtrl.onRefresh().then(() => { - let trigger_ids = _.map(ctx.panelCtrl.triggerList, 'triggerid'); + const trigger_ids = _.map(ctx.panelCtrl.triggerList, 'triggerid'); expect(trigger_ids).toEqual([ '1', '3', '2', '4' ]); @@ -134,7 +138,7 @@ describe('TriggerPanelCtrl', () => { it('should add acknowledges to trigger', (done) => { ctx.panelCtrl.onRefresh().then(() => { - let trigger = getTriggerById(1, ctx); + const trigger = getTriggerById(1, ctx); expect(trigger.acknowledges).toHaveLength(1); expect(trigger.acknowledges[0].message).toBe("event ack"); @@ -153,15 +157,15 @@ describe('TriggerPanelCtrl', () => { it('should handle new lines in trigger description', () => { ctx.panelCtrl.setTriggerSeverity = jest.fn((trigger) => trigger); - let trigger = {comments: "this is\ndescription"}; + const trigger = {comments: "this is\ndescription"}; const formattedTrigger = ctx.panelCtrl.formatTrigger(trigger); expect(formattedTrigger.comments).toBe("this is
description"); }); it('should format host name to display (default)', (done) => { ctx.panelCtrl.onRefresh().then(() => { - let trigger = getTriggerById(1, ctx); - let hostname = ctx.panelCtrl.formatHostName(trigger); + const trigger = getTriggerById(1, ctx); + const hostname = ctx.panelCtrl.formatHostName(trigger); expect(hostname).toBe('backend01'); done(); }); @@ -171,8 +175,8 @@ describe('TriggerPanelCtrl', () => { ctx.panelCtrl.panel.hostField = false; ctx.panelCtrl.panel.hostTechNameField = true; ctx.panelCtrl.onRefresh().then(() => { - let trigger = getTriggerById(1, ctx); - let hostname = ctx.panelCtrl.formatHostName(trigger); + const trigger = getTriggerById(1, ctx); + const hostname = ctx.panelCtrl.formatHostName(trigger); expect(hostname).toBe('backend01_tech'); done(); }); @@ -182,8 +186,8 @@ describe('TriggerPanelCtrl', () => { ctx.panelCtrl.panel.hostField = true; ctx.panelCtrl.panel.hostTechNameField = true; ctx.panelCtrl.onRefresh().then(() => { - let trigger = getTriggerById(1, ctx); - let hostname = ctx.panelCtrl.formatHostName(trigger); + const trigger = getTriggerById(1, ctx); + const hostname = ctx.panelCtrl.formatHostName(trigger); expect(hostname).toBe('backend01 (backend01_tech)'); done(); }); @@ -193,8 +197,8 @@ describe('TriggerPanelCtrl', () => { ctx.panelCtrl.panel.hostField = false; ctx.panelCtrl.panel.hostTechNameField = false; ctx.panelCtrl.onRefresh().then(() => { - let trigger = getTriggerById(1, ctx); - let hostname = ctx.panelCtrl.formatHostName(trigger); + const trigger = getTriggerById(1, ctx); + const hostname = ctx.panelCtrl.formatHostName(trigger); expect(hostname).toBe(""); done(); }); @@ -222,7 +226,7 @@ describe('TriggerPanelCtrl', () => { }); }); -const defaultTrigger = { +const defaultTrigger: any = { "triggerid": "13565", "value": "1", "groups": [{"groupid": "1", "name": "Backend"}] , @@ -248,7 +252,7 @@ const defaultTrigger = { "flags": "0", "type": "0", "items": [] , "error": "" }; -const defaultEvent = { +const defaultEvent: any = { "eventid": "11", "acknowledges": [ { @@ -272,8 +276,8 @@ const defaultEvent = { "objectid": "1", }; -function generateTrigger(id, timestamp, severity) { - let trigger = _.cloneDeep(defaultTrigger); +function generateTrigger(id, timestamp?, severity?): any { + const trigger = _.cloneDeep(defaultTrigger); trigger.triggerid = id.toString(); if (severity) { trigger.priority = severity.toString(); @@ -284,13 +288,13 @@ function generateTrigger(id, timestamp, severity) { return trigger; } -function createTrigger(props) { +function createTrigger(props): any { let trigger = _.cloneDeep(defaultTrigger); trigger = _.merge(trigger, props); trigger.lastEvent.objectid = trigger.triggerid; return trigger; } -function getTriggerById(id, ctx) { +function getTriggerById(id, ctx): any { return _.find(ctx.panelCtrl.triggerList, {triggerid: id.toString()}); } diff --git a/src/panel-triggers/triggers_panel_ctrl.js b/src/panel-triggers/triggers_panel_ctrl.js index d8d8247..dad0d7a 100644 --- a/src/panel-triggers/triggers_panel_ctrl.js +++ b/src/panel-triggers/triggers_panel_ctrl.js @@ -10,6 +10,7 @@ import { triggerPanelTriggersTab } from './triggers_tab'; import { migratePanelSchema, CURRENT_SCHEMA_VERSION } from './migrations'; import ProblemList from './components/Problems/Problems'; import AlertList from './components/AlertList/AlertList'; +import { getNextRefIdChar } from './utils'; const ZABBIX_DS_ID = 'alexanderzobnin-zabbix-datasource'; const PROBLEM_EVENTS_LIMIT = 100; @@ -23,7 +24,17 @@ export const DEFAULT_TARGET = { proxy: {filter: ""}, }; -export const getDefaultTarget = () => DEFAULT_TARGET; +export const getDefaultTarget = (targets) => { + return { + group: {filter: ""}, + host: {filter: ""}, + application: {filter: ""}, + trigger: {filter: ""}, + tags: {filter: ""}, + proxy: {filter: ""}, + refId: getNextRefIdChar(targets), + }; +}; export const DEFAULT_SEVERITY = [ { priority: 0, severity: 'Not classified', color: 'rgb(108, 108, 108)', show: true}, @@ -40,8 +51,7 @@ const DEFAULT_TIME_FORMAT = "DD MMM YYYY HH:mm:ss"; export const PANEL_DEFAULTS = { schemaVersion: CURRENT_SCHEMA_VERSION, - datasources: [], - targets: {}, + targets: [getDefaultTarget([])], // Fields hostField: true, hostTechNameField: false, @@ -108,11 +118,8 @@ export class TriggerPanelCtrl extends PanelCtrl { _.defaultsDeep(this.panel, _.cloneDeep(PANEL_DEFAULTS)); this.available_datasources = _.map(this.getZabbixDataSources(), 'name'); - if (this.panel.datasources.length === 0) { - this.panel.datasources.push(this.available_datasources[0]); - } - if (this.isEmptyTargets()) { - this.panel.targets[this.panel.datasources[0]] = getDefaultTarget(); + if (this.panel.targets && !this.panel.targets[0].datasource) { + this.panel.targets[0].datasource = this.available_datasources[0]; } this.initDatasources(); @@ -138,7 +145,11 @@ export class TriggerPanelCtrl extends PanelCtrl { } initDatasources() { - let promises = _.map(this.panel.datasources, (ds) => { + if (!this.panel.targets) { + return; + } + const targetDatasources = _.compact(this.panel.targets.map(target => target.datasource)); + let promises = targetDatasources.map(ds => { // Load datasource return this.datasourceSrv.get(ds) .then(datasource => { @@ -236,14 +247,15 @@ export class TriggerPanelCtrl extends PanelCtrl { const timeTo = Math.ceil(dateMath.parse(this.range.to) / 1000); const userIsEditor = this.contextSrv.isEditor || this.contextSrv.isGrafanaAdmin; - let promises = _.map(this.panel.datasources, (ds) => { + let promises = _.map(this.panel.targets, (target) => { + const ds = target.datasource; let proxies; let showAckButton = true; return this.datasourceSrv.get(ds) .then(datasource => { const zabbix = datasource.zabbix; const showEvents = this.panel.showEvents.value; - const triggerFilter = this.panel.targets[ds]; + const triggerFilter = target; const showProxy = this.panel.hostProxy; const getProxiesPromise = showProxy ? zabbix.getProxies() : () => []; showAckButton = !datasource.disableReadOnlyUsersAck || userIsEditor; @@ -284,8 +296,8 @@ export class TriggerPanelCtrl extends PanelCtrl { }) .then(triggers => this.setMaintenanceStatus(triggers)) .then(triggers => this.setAckButtonStatus(triggers, showAckButton)) - .then(triggers => this.filterTriggersPre(triggers, ds)) - .then(triggers => this.addTriggerDataSource(triggers, ds)) + .then(triggers => this.filterTriggersPre(triggers, target)) + .then(triggers => this.addTriggerDataSource(triggers, target)) .then(triggers => this.addTriggerHostProxy(triggers, proxies)); }); @@ -339,16 +351,17 @@ export class TriggerPanelCtrl extends PanelCtrl { return triggers; } - filterTriggersPre(triggerList, ds) { + filterTriggersPre(triggerList, target) { // Filter triggers by description - let triggerFilter = this.panel.targets[ds].trigger.filter; + const ds = target.datasource; + let triggerFilter = target.trigger.filter; triggerFilter = this.datasources[ds].replaceTemplateVars(triggerFilter); if (triggerFilter) { triggerList = filterTriggers(triggerList, triggerFilter); } // Filter by tags - const target = this.panel.targets[ds]; + // const target = this.panel.targets[ds]; if (target.tags.filter) { let tagsFilter = this.datasources[ds].replaceTemplateVars(target.tags.filter); // replaceTemplateVars() builds regex-like string, so we should trim it. @@ -406,9 +419,9 @@ export class TriggerPanelCtrl extends PanelCtrl { return triggers; } - addTriggerDataSource(triggers, ds) { + addTriggerDataSource(triggers, target) { _.each(triggers, (trigger) => { - trigger.datasource = ds; + trigger.datasource = target.datasource; }); return triggers; } @@ -479,24 +492,24 @@ export class TriggerPanelCtrl extends PanelCtrl { return _.map(tags, (tag) => `${tag.tag}:${tag.value}`).join(', '); } - addTagFilter(tag, ds) { - let tagFilter = this.panel.targets[ds].tags.filter; + addTagFilter(tag, target) { + let tagFilter = target.tags.filter; let targetTags = this.parseTags(tagFilter); let newTag = {tag: tag.tag, value: tag.value}; targetTags.push(newTag); targetTags = _.uniqWith(targetTags, _.isEqual); let newFilter = this.tagsToString(targetTags); - this.panel.targets[ds].tags.filter = newFilter; + target.tags.filter = newFilter; this.refresh(); } - removeTagFilter(tag, ds) { - let tagFilter = this.panel.targets[ds].tags.filter; + removeTagFilter(tag, target) { + let tagFilter = target.tags.filter; let targetTags = this.parseTags(tagFilter); _.remove(targetTags, t => t.tag === tag.tag && t.value === tag.value); targetTags = _.uniqWith(targetTags, _.isEqual); let newFilter = this.tagsToString(targetTags); - this.panel.targets[ds].tags.filter = newFilter; + target.tags.filter = newFilter; this.refresh(); } diff --git a/src/panel-triggers/triggers_tab.js b/src/panel-triggers/triggers_tab.js index db230a0..9b3032b 100644 --- a/src/panel-triggers/triggers_tab.js +++ b/src/panel-triggers/triggers_tab.js @@ -10,7 +10,7 @@ class TriggersTabCtrl { this.panelCtrl = $scope.ctrl; this.panel = this.panelCtrl.panel; this.templateSrv = templateSrv; - this.datasources = this.panelCtrl.datasources; + this.datasources = {}; // Load scope defaults var scopeDefaults = { @@ -21,6 +21,7 @@ class TriggersTabCtrl { oldTarget: _.cloneDeep(this.panel.targets) }; _.defaultsDeep(this, scopeDefaults); + this.selectedDatasources = this.getSelectedDatasources(); this.initDatasources(); this.panelCtrl.refresh(); @@ -30,6 +31,7 @@ class TriggersTabCtrl { return this.panelCtrl.initDatasources() .then((datasources) => { _.each(datasources, (datasource) => { + this.datasources[datasource.name] = datasource; this.bindSuggestionFunctions(datasource); }); }); @@ -44,6 +46,10 @@ class TriggersTabCtrl { this.getProxyNames[ds] = _.bind(this.suggestProxies, this, datasource); } + getSelectedDatasources() { + return _.compact(this.panel.targets.map(target => target.datasource)); + } + suggestGroups(datasource, query, callback) { return datasource.zabbix.getAllGroups() .then(groups => { @@ -53,7 +59,8 @@ class TriggersTabCtrl { } suggestHosts(datasource, query, callback) { - let groupFilter = datasource.replaceTemplateVars(this.panel.targets[datasource.name].group.filter); + const target = this.panel.targets.find(t => t.datasource === datasource.name); + let groupFilter = datasource.replaceTemplateVars(target.group.filter); return datasource.zabbix.getAllHosts(groupFilter) .then(hosts => { return _.map(hosts, 'name'); @@ -62,8 +69,9 @@ class TriggersTabCtrl { } suggestApps(datasource, query, callback) { - let groupFilter = datasource.replaceTemplateVars(this.panel.targets[datasource.name].group.filter); - let hostFilter = datasource.replaceTemplateVars(this.panel.targets[datasource.name].host.filter); + const target = this.panel.targets.find(t => t.datasource === datasource.name); + let groupFilter = datasource.replaceTemplateVars(target.group.filter); + let hostFilter = datasource.replaceTemplateVars(target.host.filter); return datasource.zabbix.getAllApps(groupFilter, hostFilter) .then(apps => { return _.map(apps, 'name'); @@ -78,16 +86,17 @@ class TriggersTabCtrl { } datasourcesChanged() { - _.each(this.panel.datasources, (ds) => { - if (!this.panel.targets[ds]) { - this.panel.targets[ds] = getDefaultTarget(); - } - }); - // Remove unchecked targets - _.each(this.panel.targets, (target, ds) => { - if (!_.includes(this.panel.datasources, ds)) { - delete this.panel.targets[ds]; + const newTargets = []; + _.each(this.selectedDatasources, (ds) => { + const dsTarget = this.panel.targets.find((target => target.datasource === ds)); + if (dsTarget) { + newTargets.push(dsTarget); + } else { + const newTarget = getDefaultTarget(this.panel.targets); + newTarget.datasource = ds; + newTargets.push(newTarget); } + this.panel.targets = newTargets; }); this.parseTarget(); } diff --git a/src/panel-triggers/types.ts b/src/panel-triggers/types.ts index 477d8fb..ffa9e65 100644 --- a/src/panel-triggers/types.ts +++ b/src/panel-triggers/types.ts @@ -1,7 +1,7 @@ export interface ProblemsPanelOptions { schemaVersion: number; datasources: any[]; - targets: Map; + targets: ProblemsPanelTarget[]; // Fields hostField?: boolean; hostTechNameField?: boolean; @@ -62,6 +62,7 @@ export interface ProblemsPanelTarget { proxy: { filter: string }; + datasource: string; } export interface TriggerSeverity { diff --git a/src/panel-triggers/utils.ts b/src/panel-triggers/utils.ts index d88661f..d9e2124 100644 --- a/src/panel-triggers/utils.ts +++ b/src/panel-triggers/utils.ts @@ -1,4 +1,6 @@ +import _ from 'lodash'; import moment from 'moment'; +import { DataQuery } from '@grafana/ui/'; import * as utils from '../datasource-zabbix/utils'; import { ZBXTrigger } from './types'; @@ -20,3 +22,13 @@ export function formatLastChange(lastchangeUnix: number, customFormat?: string) const lastchange = timestamp.format(format); return lastchange; } + +export const getNextRefIdChar = (queries: DataQuery[]): string => { + const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + return _.find(letters, refId => { + return _.every(queries, other => { + return other.refId !== refId; + }); + }); +}; diff --git a/tslint.json b/tslint.json index 4c7ea71..ab2614b 100644 --- a/tslint.json +++ b/tslint.json @@ -64,7 +64,6 @@ ], "variable-name": [ true, - "check-format", "ban-keywords", "allow-leading-underscore", "allow-trailing-underscore", From 68aa093cf3b0d16a0b37152c2c1380bc7c5a202f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Dec 2019 16:33:36 +0300 Subject: [PATCH 15/27] build(deps-dev): bump lodash from 4.17.10 to 4.17.13 (#852) Bumps [lodash](https://github.com/lodash/lodash) from 4.17.10 to 4.17.13. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.10...4.17.13) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index d93af81..fe5405e 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "jshint": "^2.9.6", "jshint-stylish": "^2.1.0", "load-grunt-tasks": "~3.2.0", - "lodash": "~4.17.5", + "lodash": "~4.17.13", "moment": "~2.21.0", "ng-annotate-webpack-plugin": "^0.3.0", "node-sass": "^4.9.4", diff --git a/yarn.lock b/yarn.lock index 48c3a5a..fd59423 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5833,7 +5833,7 @@ lodash.tail@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ= -lodash@4.17.15, lodash@>4.17.4, lodash@^4.0.1, lodash@^4.1.1, lodash@^4.17.11, lodash@^4.17.13: +lodash@4.17.15, lodash@>4.17.4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.1.1, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.4, lodash@~4.17.10, lodash@~4.17.5: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -5843,15 +5843,10 @@ lodash@^3.5.0, lodash@^3.7.0, lodash@~3.10.0: resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y= -lodash@^4.0.0: - version "4.17.11" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" - integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== - -lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.4, lodash@~4.17.10, lodash@~4.17.5: - version "4.17.10" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" - integrity sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg== +lodash@~4.17.13: + version "4.17.13" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.13.tgz#0bdc3a6adc873d2f4e0c4bac285df91b64fc7b93" + integrity sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA== log-symbols@^1.0.0: version "1.0.2" From 4fcef290a7a2e28197a20961b9563431cde70b8b Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 26 Dec 2019 16:51:02 +0300 Subject: [PATCH 16/27] fix packages security alerts --- package.json | 14 ++- yarn.lock | 280 ++++++++++++--------------------------------------- 2 files changed, 76 insertions(+), 218 deletions(-) diff --git a/package.json b/package.json index fe5405e..8b21a42 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "private": false, "version": "3.10.4", "description": "Zabbix plugin for Grafana", + "homepage": "http://grafana-zabbix.org", "scripts": { "build": "webpack --config webpack/webpack.prod.conf.js --progress --colors", "dev": "webpack --config webpack/webpack.dev.conf.js --progress --colors", @@ -46,7 +47,7 @@ "classnames": "^2.2.6", "clean-webpack-plugin": "^0.1.19", "codecov": "^3.1.0", - "copy-webpack-plugin": "^4.5.4", + "copy-webpack-plugin": "^5.1.1", "css-loader": "2.1.1", "extract-text-webpack-plugin": "^4.0.0-beta.0", "grunt": "^1.0.3", @@ -63,7 +64,7 @@ "lodash": "~4.17.13", "moment": "~2.21.0", "ng-annotate-webpack-plugin": "^0.3.0", - "node-sass": "^4.9.4", + "node-sass": "^4.13.0", "prop-types": "^15.6.2", "react": "^16.7.0", "react-dom": "^16.7.0", @@ -82,5 +83,12 @@ "webpack": "4.29.6", "webpack-cli": "3.2.3" }, - "homepage": "http://grafana-zabbix.org" + "resolutions": { + "js-yaml": "^3.13.1", + "lodash": "~4.17.13", + "set-value": "^2.0.1", + "mixin-deep": "^1.3.2", + "minimatch": "^3.0.2", + "fstream": "^1.0.12" + } } diff --git a/yarn.lock b/yarn.lock index fd59423..00ba26b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1433,6 +1433,11 @@ amdefine@>=0.0.4: resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= +ansi-colors@^3.0.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" + integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== + ansi-escapes@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" @@ -1491,7 +1496,7 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" -argparse@^1.0.2, argparse@^1.0.7: +argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== @@ -1951,11 +1956,6 @@ block-stream@*: dependencies: inherits "~2.0.0" -bluebird@^3.5.1: - version "3.7.0" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.0.tgz#56a6a886e03f6ae577cffedeb524f8f2450293cf" - integrity sha512-aBQ1FxIa7kSWCcmKHlcHFlT2jt6J/l4FzC7KcPELkOJOsPOb/bccdhmIrKDfXhwFrmc7vDoDrrepFvGqjyXGJg== - bluebird@^3.5.5: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" @@ -1966,7 +1966,7 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== -brace-expansion@^1.0.0, brace-expansion@^1.1.7: +brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== @@ -2118,26 +2118,7 @@ builtin-status-codes@^3.0.0: resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= -cacache@^10.0.4: - version "10.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" - integrity sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA== - dependencies: - bluebird "^3.5.1" - chownr "^1.0.1" - glob "^7.1.2" - graceful-fs "^4.1.11" - lru-cache "^4.1.1" - mississippi "^2.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.2" - ssri "^5.2.4" - unique-filename "^1.1.0" - y18n "^4.0.0" - -cacache@^12.0.2: +cacache@^12.0.2, cacache@^12.0.3: version "12.0.3" resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== @@ -2313,7 +2294,7 @@ chokidar@^2.0.2: optionalDependencies: fsevents "^1.2.2" -chownr@^1.0.1, chownr@^1.1.1: +chownr@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== @@ -2626,19 +2607,23 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -copy-webpack-plugin@^4.5.4: - version "4.5.4" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.5.4.tgz#f2b2782b3cd5225535c3dc166a80067e7d940f27" - integrity sha512-0lstlEyj74OAtYMrDxlNZsU7cwFijAI3Ofz2fD6Mpo9r4xCv4yegfa3uHIKvZY1NSuOtE9nvG6TAhJ+uz9gDaQ== +copy-webpack-plugin@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz#5481a03dea1123d88a988c6ff8b78247214f0b88" + integrity sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg== dependencies: - cacache "^10.0.4" - find-cache-dir "^1.0.0" + cacache "^12.0.3" + find-cache-dir "^2.1.0" + glob-parent "^3.1.0" globby "^7.1.1" - is-glob "^4.0.0" - loader-utils "^1.1.0" + is-glob "^4.0.1" + loader-utils "^1.2.3" minimatch "^3.0.4" - p-limit "^1.0.0" - serialize-javascript "^1.4.0" + normalize-path "^3.0.0" + p-limit "^2.2.1" + schema-utils "^1.0.0" + serialize-javascript "^2.1.2" + webpack-log "^2.0.0" core-js-compat@^3.6.0: version "3.6.0" @@ -3509,11 +3494,6 @@ eslint-scope@^4.0.0: esrecurse "^4.1.0" estraverse "^4.1.1" -esprima@^2.6.0: - version "2.7.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" - integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= - esprima@^3.1.3, esprima@~3.1.0: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" @@ -3772,15 +3752,6 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" -find-cache-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" - integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8= - dependencies: - commondir "^1.0.1" - make-dir "^1.0.0" - pkg-dir "^2.0.0" - find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" @@ -3803,13 +3774,6 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" @@ -3943,17 +3907,7 @@ fsevents@^1.2.2, fsevents@^1.2.7: bindings "^1.5.0" nan "^2.12.1" -fstream@^1.0.0: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" - -fstream@^1.0.12: +fstream@^1.0.0, fstream@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== @@ -4600,11 +4554,6 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherit@^2.2.2: - version "2.2.6" - resolved "https://registry.yarnpkg.com/inherit/-/inherit-2.2.6.tgz#f1614b06c8544e8128e4229c86347db73ad9788d" - integrity sha1-8WFLBshUToEo5CKchjR9tzrZeI0= - inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -4812,6 +4761,13 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" +is-glob@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + is-hotkey@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-hotkey/-/is-hotkey-0.1.4.tgz#c34d2c85d6ec8d09a871dcf71931c8067a824c7d" @@ -4829,7 +4785,7 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" -is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: +is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== @@ -5363,15 +5319,7 @@ js-tokens@^3.0.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= -js-yaml@^3.12.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" - integrity sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^3.13.1: +js-yaml@^3.12.0, js-yaml@^3.13.1, js-yaml@~3.4.0, js-yaml@~3.5.2: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -5379,23 +5327,6 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@~3.4.0: - version "3.4.6" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.4.6.tgz#6be1b23f6249f53d293370fd4d1aaa63ce1b4eb0" - integrity sha1-a+GyP2JJ9T0pM3D9TRqqY84bTrA= - dependencies: - argparse "^1.0.2" - esprima "^2.6.0" - inherit "^2.2.2" - -js-yaml@~3.5.2: - version "3.5.5" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.5.5.tgz#0377c38017cabc7322b0d1fbcd25a491641f2fbe" - integrity sha1-A3fDgBfKvHMisNH7zSWkkWQfL74= - dependencies: - argparse "^1.0.2" - esprima "^2.6.0" - jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -5768,14 +5699,6 @@ loader-utils@^1.0.2, loader-utils@^1.1.0: emojis-list "^2.0.0" json5 "^0.5.0" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -5833,17 +5756,7 @@ lodash.tail@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ= -lodash@4.17.15, lodash@>4.17.4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.1.1, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.4, lodash@~4.17.10, lodash@~4.17.5: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - -lodash@^3.5.0, lodash@^3.7.0, lodash@~3.10.0: - version "3.10.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" - integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y= - -lodash@~4.17.13: +lodash@4.17.15, lodash@>4.17.4, lodash@^3.5.0, lodash@^3.7.0, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.1.1, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.4, lodash@~3.10.0, lodash@~4.17.10, lodash@~4.17.13, lodash@~4.17.5: version "4.17.13" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.13.tgz#0bdc3a6adc873d2f4e0c4bac285df91b64fc7b93" integrity sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA== @@ -5875,7 +5788,7 @@ lower-case@^1.1.1: resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= -lru-cache@^4.0.1, lru-cache@^4.1.1: +lru-cache@^4.0.1: version "4.1.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" integrity sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA== @@ -5890,13 +5803,6 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -6069,20 +5975,13 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.0, minimatch@~3.0.2: +"minimatch@2 || 3", minimatch@^2.0.1, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.0, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" -minimatch@^2.0.1: - version "2.0.10" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" - integrity sha1-jQh8OcazjAAbl/ynzm0OHoCvusc= - dependencies: - brace-expansion "^1.0.0" - minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -6098,22 +5997,6 @@ minimist@~0.0.1: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= -mississippi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" - integrity sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^2.0.1" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - mississippi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" @@ -6130,10 +6013,10 @@ mississippi@^3.0.0: stream-each "^1.1.0" through2 "^2.0.0" -mixin-deep@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" - integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== +mixin-deep@^1.2.0, mixin-deep@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" @@ -6368,10 +6251,10 @@ node-releases@^1.1.42: dependencies: semver "^6.3.0" -node-sass@^4.9.4: - version "4.12.0" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.12.0.tgz#0914f531932380114a30cc5fa4fa63233a25f017" - integrity sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ== +node-sass@^4.13.0: + version "4.13.0" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.13.0.tgz#b647288babdd6a1cb726de4545516b31f90da066" + integrity sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA== dependencies: async-foreach "^0.1.3" chalk "^1.1.1" @@ -6380,7 +6263,7 @@ node-sass@^4.9.4: get-stdin "^4.0.1" glob "^7.0.3" in-publish "^2.0.0" - lodash "^4.17.11" + lodash "^4.17.15" meow "^3.7.0" mkdirp "^0.5.1" nan "^2.13.2" @@ -6659,13 +6542,6 @@ p-is-promise@^1.1.0: resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= -p-limit@^1.0.0, p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - p-limit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec" @@ -6673,12 +6549,12 @@ p-limit@^2.0.0: dependencies: p-try "^2.0.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= +p-limit@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== dependencies: - p-limit "^1.1.0" + p-try "^2.0.0" p-locate@^3.0.0: version "3.0.0" @@ -6692,11 +6568,6 @@ p-reduce@^1.0.0: resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - p-try@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" @@ -6934,13 +6805,6 @@ pirates@^4.0.1: dependencies: node-modules-regexp "^1.0.0" -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" @@ -7262,7 +7126,7 @@ public-encrypt@^4.0.0: randombytes "^2.0.1" safe-buffer "^5.1.2" -pump@^2.0.0, pump@^2.0.1: +pump@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== @@ -7928,7 +7792,7 @@ revalidator@0.1.x: resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" integrity sha1-/s5hv6DBtSoga9axgZgYS91SOjs= -rimraf@2, rimraf@2.x.x, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: +rimraf@2, rimraf@2.x.x, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -8113,11 +7977,6 @@ semver@~5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= -serialize-javascript@^1.4.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.9.1.tgz#cfc200aef77b600c47da9bb8149c943e798c2fdb" - integrity sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A== - serialize-javascript@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" @@ -8128,20 +7987,10 @@ set-blocking@^2.0.0, set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -set-value@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" - integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.1" - to-object-path "^0.3.0" - -set-value@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" - integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== +set-value@^0.4.3, set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -8447,13 +8296,6 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" -ssri@^5.2.4: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" - integrity sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ== - dependencies: - safe-buffer "^5.1.1" - ssri@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" @@ -9138,7 +8980,7 @@ uniq@^1.0.1: resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= -unique-filename@^1.1.0, unique-filename@^1.1.1: +unique-filename@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== @@ -9381,6 +9223,14 @@ webpack-core@^0.6.5: source-list-map "~0.1.7" source-map "~0.4.1" +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + webpack-sources@^1.1.0, webpack-sources@^1.3.0, webpack-sources@^1.4.0: version "1.4.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" From 1e6ca2d518d2af43afa932fb92d6321edb3d3f65 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 26 Dec 2019 17:06:15 +0300 Subject: [PATCH 17/27] problems: fix tags adding and removal --- src/panel-triggers/triggers_panel_ctrl.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/panel-triggers/triggers_panel_ctrl.js b/src/panel-triggers/triggers_panel_ctrl.js index dad0d7a..23c6011 100644 --- a/src/panel-triggers/triggers_panel_ctrl.js +++ b/src/panel-triggers/triggers_panel_ctrl.js @@ -492,7 +492,9 @@ export class TriggerPanelCtrl extends PanelCtrl { return _.map(tags, (tag) => `${tag.tag}:${tag.value}`).join(', '); } - addTagFilter(tag, target) { + addTagFilter(tag, datasource) { + const target = this.panel.targets.find(t => t.datasource === datasource); + console.log(target); let tagFilter = target.tags.filter; let targetTags = this.parseTags(tagFilter); let newTag = {tag: tag.tag, value: tag.value}; @@ -503,7 +505,8 @@ export class TriggerPanelCtrl extends PanelCtrl { this.refresh(); } - removeTagFilter(tag, target) { + removeTagFilter(tag, datasource) { + const target = this.panel.targets.find(t => t.datasource === datasource); let tagFilter = target.tags.filter; let targetTags = this.parseTags(tagFilter); _.remove(targetTags, t => t.tag === tag.tag && t.value === tag.value); From 90a9115958d7c048111cb2547740ce50a54494c6 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 26 Dec 2019 17:30:13 +0300 Subject: [PATCH 18/27] fix adding func from typeahead, closes #468 --- src/datasource-zabbix/add-metric-function.directive.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/datasource-zabbix/add-metric-function.directive.js b/src/datasource-zabbix/add-metric-function.directive.js index 64c2c41..17f9103 100644 --- a/src/datasource-zabbix/add-metric-function.directive.js +++ b/src/datasource-zabbix/add-metric-function.directive.js @@ -47,7 +47,7 @@ angular } $scope.$apply(function() { - $scope.addFunction(funcDef); + $scope.ctrl.addFunction(funcDef); }); $input.trigger('blur'); From 51ef6f70d3e4eea78a859bd611750b628ffc0b0b Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 26 Dec 2019 17:56:08 +0300 Subject: [PATCH 19/27] update change log --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83bf8e4..6d76c30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased + +## [3.10.5] - 2019-12-26 ### Added - SLA over time graphs, [#728](https://github.com/alexanderzobnin/grafana-zabbix/issues/728) +- Additional time ranges in functions, [#531](https://github.com/alexanderzobnin/grafana-zabbix/issues/531) + +### Fixed +- Problems panel: query editor broken in Grafana 6.4, [#817](https://github.com/alexanderzobnin/grafana-zabbix/issues/817) +- Datasource: function editor is not working, [#810](https://github.com/alexanderzobnin/grafana-zabbix/issues/810) +- Datasource: cannot add a function to query from typeahead, [#468](https://github.com/alexanderzobnin/grafana-zabbix/issues/468) +- Datasource: annotations editor broken in Grafana 6.x, [#813](https://github.com/alexanderzobnin/grafana-zabbix/issues/813) +- React plugins issue, [#823](https://github.com/alexanderzobnin/grafana-zabbix/issues/823) ## [3.10.4] - 2019-08-08 ### Fixed From 90b8bfa99c7fd9f8a7c2cb41576fc042d6e98750 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 26 Dec 2019 17:59:24 +0300 Subject: [PATCH 20/27] bump plugin version to 3.10.5 --- package.json | 2 +- src/plugin.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 8b21a42..e510d91 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "grafana-zabbix", "private": false, - "version": "3.10.4", + "version": "3.10.5", "description": "Zabbix plugin for Grafana", "homepage": "http://grafana-zabbix.org", "scripts": { diff --git a/src/plugin.json b/src/plugin.json index 25540d9..59d75a3 100644 --- a/src/plugin.json +++ b/src/plugin.json @@ -26,8 +26,8 @@ {"name": "Metric Editor", "path": "img/screenshot-metric_editor.png"}, {"name": "Triggers", "path": "img/screenshot-triggers.png"} ], - "version": "3.10.4", - "updated": "2019-08-08" + "version": "3.10.5", + "updated": "2019-12-26" }, "includes": [ From d54d6d29dc4e802d5cec37ac9a320182c2c96cb2 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Mon, 30 Dec 2019 10:36:36 +0300 Subject: [PATCH 21/27] problems: fix tag removal (list layout) --- src/panel-triggers/components/AlertList/AlertCard.tsx | 6 +++--- src/panel-triggers/components/AlertList/AlertList.tsx | 6 +++--- src/panel-triggers/components/Problems/Problems.tsx | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/panel-triggers/components/AlertList/AlertCard.tsx b/src/panel-triggers/components/AlertList/AlertCard.tsx index 46d9dd1..b893ac8 100644 --- a/src/panel-triggers/components/AlertList/AlertCard.tsx +++ b/src/panel-triggers/components/AlertList/AlertCard.tsx @@ -13,7 +13,7 @@ import AlertIcon from './AlertIcon'; interface AlertCardProps { problem: ZBXTrigger; panelOptions: ProblemsPanelOptions; - onTagClick?: (tag: ZBXTag, datasource: string) => void; + onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void; onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => Promise | any; } @@ -27,9 +27,9 @@ export default class AlertCard extends PureComponent { + handleTagClick = (tag: ZBXTag, ctrlKey?: boolean, shiftKey?: boolean) => { if (this.props.onTagClick) { - this.props.onTagClick(tag, this.props.problem.datasource); + this.props.onTagClick(tag, this.props.problem.datasource, ctrlKey, shiftKey); } } diff --git a/src/panel-triggers/components/AlertList/AlertList.tsx b/src/panel-triggers/components/AlertList/AlertList.tsx index 8d1d08b..a01c155 100644 --- a/src/panel-triggers/components/AlertList/AlertList.tsx +++ b/src/panel-triggers/components/AlertList/AlertList.tsx @@ -12,7 +12,7 @@ export interface AlertListProps { pageSize?: number; fontSize?: number; onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => void; - onTagClick?: (tag: ZBXTag, datasource: string) => void; + onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void; } interface AlertListState { @@ -45,9 +45,9 @@ export default class AlertList extends PureComponent { + handleTagClick = (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => { if (this.props.onTagClick) { - this.props.onTagClick(tag, datasource); + this.props.onTagClick(tag, datasource, ctrlKey, shiftKey); } } diff --git a/src/panel-triggers/components/Problems/Problems.tsx b/src/panel-triggers/components/Problems/Problems.tsx index c2a1d2d..7301f8d 100644 --- a/src/panel-triggers/components/Problems/Problems.tsx +++ b/src/panel-triggers/components/Problems/Problems.tsx @@ -260,13 +260,13 @@ function LastChangeCell(props: RTCell, customFormat?: string) { } interface TagCellProps extends RTCell { - onTagClick: (tag: ZBXTag, datasource: string) => void; + onTagClick: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void; } class TagCell extends PureComponent { - handleTagClick = (tag: ZBXTag) => { + handleTagClick = (tag: ZBXTag, ctrlKey?: boolean, shiftKey?: boolean) => { if (this.props.onTagClick) { - this.props.onTagClick(tag, this.props.original.datasource); + this.props.onTagClick(tag, this.props.original.datasource, ctrlKey, shiftKey); } } From dd28b28174f1db1a743987886ded6ee3e3de3f88 Mon Sep 17 00:00:00 2001 From: Mark Reibert Date: Sat, 11 Jan 2020 10:28:32 -0700 Subject: [PATCH 22/27] Fix percentile() function, closes #862 (#863) Like the other aggregation functions, the datapoints need to be sorted in time before calling groupBy_perf(). --- src/datasource-zabbix/dataProcessor.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/datasource-zabbix/dataProcessor.js b/src/datasource-zabbix/dataProcessor.js index e69ceda..eb5d1a1 100644 --- a/src/datasource-zabbix/dataProcessor.js +++ b/src/datasource-zabbix/dataProcessor.js @@ -121,9 +121,11 @@ function aggregateWrapper(groupByCallback, interval, datapoints) { } function percentile(interval, n, datapoints) { - var flattenedPoints = ts.flattenDatapoints(datapoints); - var groupByCallback = _.partial(PERCENTILE, n); - return groupBy(flattenedPoints, interval, groupByCallback); + const flattenedPoints = ts.flattenDatapoints(datapoints); + // groupBy_perf works with sorted series only + const sortedPoints = ts.sortByTime(flattenedPoints); + let groupByCallback = _.partial(PERCENTILE, n); + return groupBy(sortedPoints, interval, groupByCallback); } function timeShift(interval, range) { From fe0c5cf1fd2bd6573f2fc65687a89327f0a270d9 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Sat, 11 Jan 2020 20:31:00 +0300 Subject: [PATCH 23/27] Update copyright, happy New Year! --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 39687eb..bdeb701 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,6 @@ First, [configure](https://alexanderzobnin.github.io/grafana-zabbix/configuratio - Need additional support? Contact me for details [alexanderzobnin@gmail.com](mailto:alexanderzobnin@gmail.com) --- -:copyright: 2015-2019 Alexander Zobnin alexanderzobnin@gmail.com +:copyright: 2015-2020 Alexander Zobnin alexanderzobnin@gmail.com Licensed under the Apache 2.0 License From 4f24b2bf23339ce2667489eab1beda1dd37aa5f5 Mon Sep 17 00:00:00 2001 From: memfiz Date: Mon, 13 Jan 2020 09:58:01 +0200 Subject: [PATCH 24/27] fix not acknowledged problem color with a message (#858) * fix not acknowledged problem color with a message * fix not acknowledged problem color with a message, closes #857 --- src/panel-triggers/components/AlertList/AlertCard.tsx | 2 +- src/panel-triggers/components/Problems/Problems.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/panel-triggers/components/AlertList/AlertCard.tsx b/src/panel-triggers/components/AlertList/AlertCard.tsx index b893ac8..87eaf9d 100644 --- a/src/panel-triggers/components/AlertList/AlertCard.tsx +++ b/src/panel-triggers/components/AlertList/AlertCard.tsx @@ -72,7 +72,7 @@ export default class AlertCard extends PureComponent, problemSeverityDesc: TriggerSev color = severityDesc.color; // Mark acknowledged triggers with different color - if (markAckEvents && problem.acknowledges && problem.acknowledges.length) { + if (markAckEvents && problem.lastEvent.acknowledged === "1") { color = ackEventColor; } From 82cfda652418162eb50d1b1568c58b91218f8c06 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Mon, 13 Jan 2020 11:31:40 +0300 Subject: [PATCH 25/27] Variable query editor (#856) * refactor: convert module to typescript * refactor: covert utils to typescript * variable query editor WIP * variable editor: fix type error after grafana/ui update * variable editor: use FormLabel from grafana/ui * variable editor: refactor * variable editor: input validation and highlights * variable editor: fix tests * variable query: fix backward compatibility with empty queries * fix linter errors * variable editor: fix variable replacement in queries --- package.json | 1 + .../components/VariableQueryEditor.tsx | 157 ++++++++++++++++++ .../components/ZabbixInput.tsx | 69 ++++++++ src/datasource-zabbix/datasource.js | 66 ++++---- .../{module.js => module.ts} | 14 +- .../specs/datasource.spec.js | 13 +- src/datasource-zabbix/types.ts | 30 ++++ src/datasource-zabbix/{utils.js => utils.ts} | 116 +++++++++---- src/test-setup/jest-setup.js | 6 +- webpack/webpack.base.conf.js | 4 +- yarn.lock | 121 +++++++++++++- 11 files changed, 519 insertions(+), 78 deletions(-) create mode 100644 src/datasource-zabbix/components/VariableQueryEditor.tsx create mode 100644 src/datasource-zabbix/components/ZabbixInput.tsx rename src/datasource-zabbix/{module.js => module.ts} (67%) create mode 100644 src/datasource-zabbix/types.ts rename src/datasource-zabbix/{utils.js => utils.ts} (67%) diff --git a/package.json b/package.json index e510d91..64b90d2 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@babel/core": "^7.7.7", "@babel/preset-env": "^7.7.7", "@babel/preset-react": "^7.6.3", + "@emotion/core": "^10.0.27", "@grafana/data": "^6.4.2", "@grafana/ui": "^6.4.2", "@types/classnames": "^2.2.6", diff --git a/src/datasource-zabbix/components/VariableQueryEditor.tsx b/src/datasource-zabbix/components/VariableQueryEditor.tsx new file mode 100644 index 0000000..a9b5616 --- /dev/null +++ b/src/datasource-zabbix/components/VariableQueryEditor.tsx @@ -0,0 +1,157 @@ +import React, { PureComponent } from 'react'; +import { parseLegacyVariableQuery } from '../utils'; +import { Select, Input, AsyncSelect, FormLabel } from '@grafana/ui'; +import { SelectableValue } from '@grafana/data'; +import { VariableQuery, VariableQueryTypes, VariableQueryProps, VariableQueryData } from '../types'; +import { ZabbixInput } from './ZabbixInput'; + +export class ZabbixVariableQueryEditor extends PureComponent { + queryTypes: Array> = [ + { value: VariableQueryTypes.Group, label: 'Group'}, + { value: VariableQueryTypes.Host, label: 'Host' }, + { value: VariableQueryTypes.Application, label: 'Application' }, + { value: VariableQueryTypes.Item, label: 'Item' }, + ]; + + defaults: VariableQueryData = { + selectedQueryType: { value: VariableQueryTypes.Group, label: 'Group' }, + queryType: VariableQueryTypes.Group, + group: '/.*/', + host: '', + application: '', + item: '', + }; + + constructor(props: VariableQueryProps) { + super(props); + + if (this.props.query && typeof this.props.query === 'string') { + // Backward compatibility + const query = parseLegacyVariableQuery(this.props.query); + const selectedQueryType = this.getSelectedQueryType(query.queryType); + this.state = { + selectedQueryType, + legacyQuery: this.props.query, + ...query + }; + } else if (this.props.query) { + const query = (this.props.query as VariableQuery); + const selectedQueryType = this.getSelectedQueryType(query.queryType); + this.state = { + ...this.defaults, + ...query, + selectedQueryType, + }; + } else { + this.state = this.defaults; + } + } + + getSelectedQueryType(queryType: VariableQueryTypes) { + return this.queryTypes.find(q => q.value === queryType); + } + + handleQueryUpdate = (evt: React.ChangeEvent, prop: string) => { + const value = evt.currentTarget.value; + this.setState((prevState: VariableQueryData) => { + const newQuery = { + ...prevState, + }; + newQuery[prop] = value; + + return { + ...newQuery, + }; + }); + } + + handleQueryChange = () => { + const { queryType, group, host, application, item } = this.state; + const queryModel = { queryType, group, host, application, item }; + this.props.onChange(queryModel, `Zabbix - ${queryType}`); + } + + handleQueryTypeChange = (selectedItem: SelectableValue) => { + this.setState({ + ...this.state, + selectedQueryType: selectedItem, + queryType: selectedItem.value, + }); + + const { group, host, application, item } = this.state; + const queryType = selectedItem.value; + const queryModel = { queryType, group, host, application, item }; + this.props.onChange(queryModel, `Zabbix - ${queryType}`); + } + + render() { + const { selectedQueryType, legacyQuery, group, host, application, item } = this.state; + + return ( + <> +
+ Query Type + +
+ } + + ); + } +} diff --git a/src/datasource-zabbix/components/ZabbixInput.tsx b/src/datasource-zabbix/components/ZabbixInput.tsx new file mode 100644 index 0000000..35ae31b --- /dev/null +++ b/src/datasource-zabbix/components/ZabbixInput.tsx @@ -0,0 +1,69 @@ +import React, { FC } from 'react'; +import { css, cx } from 'emotion'; +import { Themeable, withTheme, Input, GrafanaTheme, EventsWithValidation, ValidationEvents } from '@grafana/ui'; +import { isRegex, variableRegex } from '../utils'; + +const variablePattern = RegExp(`^${variableRegex.source}`); + +const getStyles = (theme: GrafanaTheme) => ({ + inputRegex: css` + color: ${theme.colors.orange} + `, + inputVariable: css` + color: ${theme.colors.variable} + `, +}); + +const zabbixInputValidationEvents: ValidationEvents = { + [EventsWithValidation.onBlur]: [ + { + rule: value => { + if (!value) { + return true; + } + if (value.length > 1 && value[0] === '/') { + if (value[value.length - 1] !== '/') { + return false; + } + } + return true; + }, + errorMessage: 'Not a valid regex', + }, + { + rule: value => { + if (value === '*') { + return false; + } + return true; + }, + errorMessage: 'Wildcards not supported. Use /.*/ instead', + }, + ], +}; + +interface Props extends React.ComponentProps, Themeable { +} + +const UnthemedZabbixInput: FC = ({ theme, value, ref, validationEvents, ...restProps }) => { + const styles = getStyles(theme); + + let inputClass; + if (variablePattern.test(value as string)) { + inputClass = styles.inputVariable; + } + if (isRegex(value)) { + inputClass = styles.inputRegex; + } + + return ( + + ); +}; + +export const ZabbixInput = withTheme(UnthemedZabbixInput); diff --git a/src/datasource-zabbix/datasource.js b/src/datasource-zabbix/datasource.js index 94c29c8..d89e68c 100644 --- a/src/datasource-zabbix/datasource.js +++ b/src/datasource-zabbix/datasource.js @@ -9,6 +9,7 @@ import dataProcessor from './dataProcessor'; import responseHandler from './responseHandler'; import { Zabbix } from './zabbix/zabbix'; import { ZabbixAPIError } from './zabbix/connectors/zabbix_api/zabbixAPICore'; +import { VariableQueryTypes } from './types'; const DEFAULT_ZABBIX_VERSION = 3; @@ -432,42 +433,41 @@ export class ZabbixDatasource { * of metrics in "{metric1,metcic2,...,metricN}" format. */ metricFindQuery(query) { - let result; - let parts = []; + let resultPromise; + let queryModel = _.cloneDeep(query); - // Split query. Query structure: group.host.app.item - _.each(utils.splitTemplateQuery(query), part => { - part = this.replaceTemplateVars(part, {}); - - // Replace wildcard to regex - if (part === '*') { - part = '/.*/'; - } - parts.push(part); - }); - let template = _.zipObject(['group', 'host', 'app', 'item'], parts); - - // Get items - if (parts.length === 4) { - // Search for all items, even it's not belong to any application - if (template.app === '/.*/') { - template.app = ''; - } - result = this.zabbix.getItems(template.group, template.host, template.app, template.item); - } else if (parts.length === 3) { - // Get applications - result = this.zabbix.getApps(template.group, template.host, template.app); - } else if (parts.length === 2) { - // Get hosts - result = this.zabbix.getHosts(template.group, template.host); - } else if (parts.length === 1) { - // Get groups - result = this.zabbix.getGroups(template.group); - } else { - result = Promise.resolve([]); + if (!query) { + return Promise.resolve([]); } - return result.then(metrics => { + if (typeof query === 'string') { + // Backward compatibility + queryModel = utils.parseLegacyVariableQuery(query); + } + + for (const prop of ['group', 'host', 'application', 'item']) { + queryModel[prop] = this.replaceTemplateVars(queryModel[prop], {}); + } + + switch (queryModel.queryType) { + case VariableQueryTypes.Group: + resultPromise = this.zabbix.getGroups(queryModel.group); + break; + case VariableQueryTypes.Host: + resultPromise = this.zabbix.getHosts(queryModel.group, queryModel.host); + break; + case VariableQueryTypes.Application: + resultPromise = this.zabbix.getApps(queryModel.group, queryModel.host, queryModel.application); + break; + case VariableQueryTypes.Item: + resultPromise = this.zabbix.getItems(queryModel.group, queryModel.host, queryModel.application, queryModel.item); + break; + default: + resultPromise = Promise.resolve([]); + break; + } + + return resultPromise.then(metrics => { return _.map(metrics, formatMetric); }); } diff --git a/src/datasource-zabbix/module.js b/src/datasource-zabbix/module.ts similarity index 67% rename from src/datasource-zabbix/module.js rename to src/datasource-zabbix/module.ts index edddcdf..0ed81bd 100644 --- a/src/datasource-zabbix/module.js +++ b/src/datasource-zabbix/module.ts @@ -2,15 +2,18 @@ import { loadPluginCss } from 'grafana/app/plugins/sdk'; import { ZabbixDatasource } from './datasource'; import { ZabbixQueryController } from './query.controller'; import { ZabbixDSConfigController } from './config.controller'; +import { ZabbixVariableQueryEditor } from './components/VariableQueryEditor'; import './zabbixAlerting.service.js'; import './add-metric-function.directive'; import './metric-function-editor.directive'; -class ZabbixQueryOptionsController {} -ZabbixQueryOptionsController.templateUrl = 'datasource-zabbix/partials/query.options.html'; +class ZabbixQueryOptionsController { + static templateUrl = 'datasource-zabbix/partials/query.options.html'; +} -class ZabbixAnnotationsQueryController {} -ZabbixAnnotationsQueryController.templateUrl = 'datasource-zabbix/partials/annotations.editor.html'; +class ZabbixAnnotationsQueryController { + static templateUrl = 'datasource-zabbix/partials/annotations.editor.html'; +} ZabbixQueryController.templateUrl = 'datasource-zabbix/partials/query.editor.html'; ZabbixDSConfigController.templateUrl = 'datasource-zabbix/partials/config.html'; @@ -25,5 +28,6 @@ export { ZabbixDSConfigController as ConfigCtrl, ZabbixQueryController as QueryCtrl, ZabbixQueryOptionsController as QueryOptionsCtrl, - ZabbixAnnotationsQueryController as AnnotationsQueryCtrl + ZabbixAnnotationsQueryController as AnnotationsQueryCtrl, + ZabbixVariableQueryEditor as VariableQueryEditor, }; diff --git a/src/datasource-zabbix/specs/datasource.spec.js b/src/datasource-zabbix/specs/datasource.spec.js index dd99f26..a51a06b 100644 --- a/src/datasource-zabbix/specs/datasource.spec.js +++ b/src/datasource-zabbix/specs/datasource.spec.js @@ -231,7 +231,7 @@ describe('ZabbixDatasource', () => { }); }); - describe('When invoking metricFindQuery()', () => { + describe('When invoking metricFindQuery() with legacy query', () => { beforeEach(() => { ctx.ds.replaceTemplateVars = (str) => str; ctx.ds.zabbix = { @@ -245,7 +245,6 @@ describe('ZabbixDatasource', () => { it('should return groups', (done) => { const tests = [ {query: '*', expect: '/.*/'}, - {query: '', expect: ''}, {query: 'Backend', expect: 'Backend'}, {query: 'Back*', expect: 'Back*'}, ]; @@ -258,6 +257,16 @@ describe('ZabbixDatasource', () => { done(); }); + it('should return empty list for empty query', (done) => { + ctx.ds.metricFindQuery('').then(result => { + expect(ctx.ds.zabbix.getGroups).toBeCalledTimes(0); + ctx.ds.zabbix.getGroups.mockClear(); + + expect(result).toEqual([]); + done(); + }); + }); + it('should return hosts', (done) => { const tests = [ {query: '*.*', expect: ['/.*/', '/.*/']}, diff --git a/src/datasource-zabbix/types.ts b/src/datasource-zabbix/types.ts new file mode 100644 index 0000000..739e25f --- /dev/null +++ b/src/datasource-zabbix/types.ts @@ -0,0 +1,30 @@ +import { SelectableValue } from "@grafana/data"; + +export interface VariableQueryProps { + query: LegacyVariableQuery; + onChange: (query: VariableQuery, definition: string) => void; + datasource: any; + templateSrv: any; +} + +export interface VariableQueryData extends VariableQuery { + selectedQueryType: SelectableValue; + legacyQuery?: string; +} + +export interface VariableQuery { + queryType: VariableQueryTypes; + group?: string; + host?: string; + application?: string; + item?: string; +} + +export type LegacyVariableQuery = VariableQuery | string; + +export enum VariableQueryTypes { + Group = 'group', + Host = 'host', + Application = 'application', + Item = 'item', +} diff --git a/src/datasource-zabbix/utils.js b/src/datasource-zabbix/utils.ts similarity index 67% rename from src/datasource-zabbix/utils.js rename to src/datasource-zabbix/utils.ts index 454ebaa..44bc5a5 100644 --- a/src/datasource-zabbix/utils.js +++ b/src/datasource-zabbix/utils.ts @@ -2,6 +2,15 @@ import _ from 'lodash'; import moment from 'moment'; import kbn from 'grafana/app/core/utils/kbn'; import * as c from './constants'; +import { VariableQuery, VariableQueryTypes } from './types'; + +/* + * This regex matches 3 types of variable reference with an optional format specifier + * \$(\w+) $var1 + * \[\[([\s\S]+?)(?::(\w+))?\]\] [[var2]] or [[var2:fmt2]] + * \${(\w+)(?::(\w+))?} ${var3} or ${var3:fmt3} + */ +export const variableRegex = /\$(\w+)|\[\[([\s\S]+?)(?::(\w+))?\]\]|\${(\w+)(?:\.([^:^\}]+))?(?::(\w+))?}/g; /** * Expand Zabbix item name @@ -14,8 +23,8 @@ export function expandItemName(name, key) { // extract params from key: // "system.cpu.util[,system,avg1]" --> ["", "system", "avg1"] - let key_params_str = key.substring(key.indexOf('[') + 1, key.lastIndexOf(']')); - let key_params = splitKeyParams(key_params_str); + const key_params_str = key.substring(key.indexOf('[') + 1, key.lastIndexOf(']')); + const key_params = splitKeyParams(key_params_str); // replace item parameters for (let i = key_params.length; i >= 1; i--) { @@ -34,10 +43,10 @@ export function expandItems(items) { } function splitKeyParams(paramStr) { - let params = []; + const params = []; let quoted = false; let in_array = false; - let split_symbol = ','; + const split_symbol = ','; let param = ''; _.forEach(paramStr, symbol => { @@ -71,9 +80,9 @@ export function containsMacro(itemName) { export function replaceMacro(item, macros) { let itemName = item.name; - let item_macros = itemName.match(MACRO_PATTERN); + const item_macros = itemName.match(MACRO_PATTERN); _.forEach(item_macros, macro => { - let host_macros = _.filter(macros, m => { + const host_macros = _.filter(macros, m => { if (m.hostid) { return m.hostid === item.hostid; } else { @@ -82,10 +91,10 @@ export function replaceMacro(item, macros) { } }); - let macro_def = _.find(host_macros, { macro: macro }); + const macro_def = _.find(host_macros, { macro: macro }); if (macro_def && macro_def.value) { - let macro_value = macro_def.value; - let macro_regex = new RegExp(escapeMacro(macro)); + const macro_value = macro_def.value; + const macro_regex = new RegExp(escapeMacro(macro)); itemName = itemName.replace(macro_regex, macro_value); } }); @@ -98,17 +107,62 @@ function escapeMacro(macro) { return macro; } +export function parseLegacyVariableQuery(query: string): VariableQuery { + let queryType: VariableQueryTypes; + const parts = []; + + // Split query. Query structure: group.host.app.item + _.each(splitTemplateQuery(query), part => { + // Replace wildcard to regex + if (part === '*') { + part = '/.*/'; + } + parts.push(part); + }); + const template = _.zipObject(['group', 'host', 'app', 'item'], parts); + + if (parts.length === 4 && template.app === '/.*/') { + // Search for all items, even it's not belong to any application + template.app = ''; + } + + switch (parts.length) { + case 1: + queryType = VariableQueryTypes.Group; + break; + case 2: + queryType = VariableQueryTypes.Host; + break; + case 3: + queryType = VariableQueryTypes.Application; + break; + case 4: + queryType = VariableQueryTypes.Item; + break; + } + + const variableQuery: VariableQuery = { + queryType, + group: template.group || '', + host: template.host || '', + application: template.app || '', + item: template.item || '', + }; + + return variableQuery; +} + /** * Split template query to parts of zabbix entities * group.host.app.item -> [group, host, app, item] * {group}{host.com} -> [group, host.com] */ export function splitTemplateQuery(query) { - let splitPattern = /\{[^\{\}]*\}|\{\/.*\/\}/g; + const splitPattern = /\{[^\{\}]*\}|\{\/.*\/\}/g; let split; if (isContainsBraces(query)) { - let result = query.match(splitPattern); + const result = query.match(splitPattern); split = _.map(result, part => { return _.trim(part, '{}'); }); @@ -120,7 +174,7 @@ export function splitTemplateQuery(query) { } function isContainsBraces(query) { - let bracesPattern = /^\{.+\}$/; + const bracesPattern = /^\{.+\}$/; return bracesPattern.test(query); } @@ -132,9 +186,9 @@ export function isRegex(str) { } export function isTemplateVariable(str, templateVariables) { - var variablePattern = /^\$\w+/; + const variablePattern = /^\$\w+/; if (variablePattern.test(str)) { - var variables = _.map(templateVariables, variable => { + const variables = _.map(templateVariables, variable => { return '$' + variable.name; }); return _.includes(variables, str); @@ -156,9 +210,9 @@ export function getRangeScopedVars(range) { } export function buildRegex(str) { - var matches = str.match(regexPattern); - var pattern = matches[1]; - var flags = matches[2] !== "" ? matches[2] : undefined; + const matches = str.match(regexPattern); + const pattern = matches[1]; + const flags = matches[2] !== "" ? matches[2] : undefined; return new RegExp(pattern, flags); } @@ -169,18 +223,18 @@ export function escapeRegex(value) { } export function parseInterval(interval) { - var intervalPattern = /(^[\d]+)(y|M|w|d|h|m|s)/g; - var momentInterval = intervalPattern.exec(interval); + const intervalPattern = /(^[\d]+)(y|M|w|d|h|m|s)/g; + const momentInterval: any[] = intervalPattern.exec(interval); return moment.duration(Number(momentInterval[1]), momentInterval[2]).valueOf(); } export function parseTimeShiftInterval(interval) { - let intervalPattern = /^([\+\-]*)([\d]+)(y|M|w|d|h|m|s)/g; - let momentInterval = intervalPattern.exec(interval); - let duration = 0; + const intervalPattern = /^([\+\-]*)([\d]+)(y|M|w|d|h|m|s)/g; + const momentInterval: any[] = intervalPattern.exec(interval); + let duration: any = 0; if (momentInterval[1] === '+') { - duration = 0 - moment.duration(Number(momentInterval[2]), momentInterval[3]).valueOf(); + duration = 0 - (moment.duration(Number(momentInterval[2]), momentInterval[3]).valueOf() as any); } else { duration = moment.duration(Number(momentInterval[2]), momentInterval[3]).valueOf(); } @@ -196,13 +250,13 @@ export function parseTimeShiftInterval(interval) { */ export function formatAcknowledges(acknowledges) { if (acknowledges.length) { - var formatted_acknowledges = '

Acknowledges:
' + let formatted_acknowledges = '

Acknowledges:
Time
' + ''; - _.each(_.map(acknowledges, function (ack) { - var timestamp = moment.unix(ack.clock); + _.each(_.map(acknowledges, ack => { + const timestamp = moment.unix(ack.clock); return ''; - }), function (ack) { + }), ack => { formatted_acknowledges = formatted_acknowledges.concat(ack); }); formatted_acknowledges = formatted_acknowledges.concat('
TimeUserComments
' + timestamp.format("DD MMM YYYY HH:mm:ss") + '' + ack.alias + ' (' + ack.name + ' ' + ack.surname + ')' + '' + ack.message + '
'); @@ -213,8 +267,8 @@ export function formatAcknowledges(acknowledges) { } export function convertToZabbixAPIUrl(url) { - var zabbixAPIUrlPattern = /.*api_jsonrpc.php$/; - var trimSlashPattern = /(.*?)[\/]*$/; + const zabbixAPIUrlPattern = /.*api_jsonrpc.php$/; + const trimSlashPattern = /(.*?)[\/]*$/; if (url.match(zabbixAPIUrlPattern)) { return url; } else { @@ -247,7 +301,7 @@ export function callOnce(func, promiseKeeper) { */ export function sequence(funcsArray) { return function(result) { - for (var i = 0; i < funcsArray.length; i++) { + for (let i = 0; i < funcsArray.length; i++) { result = funcsArray[i].call(this, result); } return result; @@ -292,5 +346,5 @@ export function getArrayDepth(a, level = 0) { // Fix for backward compatibility with lodash 2.4 if (!_.includes) { - _.includes = _.contains; + _.includes = (_ as any).contains; } diff --git a/src/test-setup/jest-setup.js b/src/test-setup/jest-setup.js index 6d9ae49..9e4b81c 100644 --- a/src/test-setup/jest-setup.js +++ b/src/test-setup/jest-setup.js @@ -75,9 +75,9 @@ jest.mock('grafana/app/core/config', () => { jest.mock('jquery', () => 'module not found', {virtual: true}); -jest.mock('@grafana/ui', () => { - return {}; -}, {virtual: true}); +// jest.mock('@grafana/ui', () => { +// return {}; +// }, {virtual: true}); // Required for loading angularjs let dom = new JSDOM(''); diff --git a/webpack/webpack.base.conf.js b/webpack/webpack.base.conf.js index dc61c8d..ded1c67 100644 --- a/webpack/webpack.base.conf.js +++ b/webpack/webpack.base.conf.js @@ -17,7 +17,7 @@ module.exports = { entry: { './module': './module.js', 'components/config': './components/config.js', - 'datasource-zabbix/module': './datasource-zabbix/module.js', + 'datasource-zabbix/module': './datasource-zabbix/module.ts', 'panel-triggers/module': './panel-triggers/module.js', }, output: { @@ -27,7 +27,7 @@ module.exports = { }, externals: [ // remove the line below if you don't want to use builtin versions - 'jquery', 'lodash', 'moment', 'angular', + 'jquery', 'lodash', 'moment', 'angular', 'emotion', 'react', 'react-dom', '@grafana/ui', '@grafana/data', function (context, request, callback) { var prefix = 'grafana/'; diff --git a/yarn.lock b/yarn.lock index 00ba26b..e626092 100644 --- a/yarn.lock +++ b/yarn.lock @@ -696,6 +696,13 @@ dependencies: regenerator-runtime "^0.13.2" +"@babel/runtime@^7.5.5": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.7.tgz#194769ca8d6d7790ec23605af9ee3e42a0aa79cf" + integrity sha512-uCnC2JEVAu8AKB5do1WRIsvrdJ0flYx/A/9f/6chdacnEZ7LmavjdsDXr5ksYBegxtuTPR5Va9/+13QF/kFkCA== + dependencies: + regenerator-runtime "^0.13.2" + "@babel/template@^7.4.0", "@babel/template@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b" @@ -758,16 +765,68 @@ find-root "^1.1.0" source-map "^0.7.2" +"@emotion/cache@^10.0.27": + version "10.0.27" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.27.tgz#7895db204e2c1a991ae33d51262a3a44f6737303" + integrity sha512-Zp8BEpbMunFsTcqAK4D7YTm3MvCp1SekflSLJH8lze2fCcSZ/yMkXHo8kb3t1/1Tdd3hAqf3Fb7z9VZ+FMiC9w== + dependencies: + "@emotion/sheet" "0.9.4" + "@emotion/stylis" "0.8.5" + "@emotion/utils" "0.11.3" + "@emotion/weak-memoize" "0.2.5" + +"@emotion/core@^10.0.27": + version "10.0.27" + resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.27.tgz#7c3f78be681ab2273f3bf11ca3e2edc4a9dd1fdc" + integrity sha512-XbD5R36pVbohQMnKfajHv43g8EbN4NHdF6Zh9zg/C0nr0jqwOw3gYnC07Xj3yG43OYSRyrGsoQ5qPwc8ycvLZw== + dependencies: + "@babel/runtime" "^7.5.5" + "@emotion/cache" "^10.0.27" + "@emotion/css" "^10.0.27" + "@emotion/serialize" "^0.11.15" + "@emotion/sheet" "0.9.4" + "@emotion/utils" "0.11.3" + +"@emotion/css@^10.0.27": + version "10.0.27" + resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c" + integrity sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw== + dependencies: + "@emotion/serialize" "^0.11.15" + "@emotion/utils" "0.11.3" + babel-plugin-emotion "^10.0.27" + +"@emotion/hash@0.7.4": + version "0.7.4" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.7.4.tgz#f14932887422c9056b15a8d222a9074a7dfa2831" + integrity sha512-fxfMSBMX3tlIbKUdtGKxqB1fyrH6gVrX39Gsv3y8lRYKUqlgDt3UMqQyGnR1bQMa2B8aGnhLZokZgg8vT0Le+A== + "@emotion/hash@^0.6.2", "@emotion/hash@^0.6.6": version "0.6.6" resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.6.6.tgz#62266c5f0eac6941fece302abad69f2ee7e25e44" integrity sha512-ojhgxzUHZ7am3D2jHkMzPpsBAiB005GF5YU4ea+8DNPybMk01JJUM9V9YRlF/GE95tcOm8DxQvWA2jq19bGalQ== +"@emotion/memoize@0.7.4": + version "0.7.4" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" + integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== + "@emotion/memoize@^0.6.1", "@emotion/memoize@^0.6.6": version "0.6.6" resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.6.6.tgz#004b98298d04c7ca3b4f50ca2035d4f60d2eed1b" integrity sha512-h4t4jFjtm1YV7UirAFuSuFGyLa+NNxjdkq6DpFLANNQY5rHueFZHVY+8Cu1HYVP6DrheB0kv4m5xPjo7eKT7yQ== +"@emotion/serialize@^0.11.15": + version "0.11.15" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.15.tgz#9a0f5873fb458d87d4f23e034413c12ed60a705a" + integrity sha512-YE+qnrmGwyR+XB5j7Bi+0GT1JWsdcjM/d4POu+TXkcnrRs4RFCCsi3d/Ebf+wSStHqAlTT2+dfd+b9N9EO2KBg== + dependencies: + "@emotion/hash" "0.7.4" + "@emotion/memoize" "0.7.4" + "@emotion/unitless" "0.7.5" + "@emotion/utils" "0.11.3" + csstype "^2.5.7" + "@emotion/serialize@^0.9.1": version "0.9.1" resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.9.1.tgz#a494982a6920730dba6303eb018220a2b629c145" @@ -778,21 +837,46 @@ "@emotion/unitless" "^0.6.7" "@emotion/utils" "^0.8.2" +"@emotion/sheet@0.9.4": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5" + integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA== + +"@emotion/stylis@0.8.5": + version "0.8.5" + resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" + integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== + "@emotion/stylis@^0.7.0": version "0.7.1" resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.7.1.tgz#50f63225e712d99e2b2b39c19c70fff023793ca5" integrity sha512-/SLmSIkN13M//53TtNxgxo57mcJk/UJIDFRKwOiLIBEyBHEcipgR6hNMQ/59Sl4VjCJ0Z/3zeAZyvnSLPG/1HQ== +"@emotion/unitless@0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + "@emotion/unitless@^0.6.2", "@emotion/unitless@^0.6.7": version "0.6.7" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.6.7.tgz#53e9f1892f725b194d5e6a1684a7b394df592397" integrity sha512-Arj1hncvEVqQ2p7Ega08uHLr1JuRYBuO5cIvcA+WWEQ5+VmkOE3ZXzl04NbQxeQpWX78G7u6MqxKuNX3wvYZxg== +"@emotion/utils@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924" + integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw== + "@emotion/utils@^0.8.2": version "0.8.2" resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.8.2.tgz#576ff7fb1230185b619a75d258cbc98f0867a8dc" integrity sha512-rLu3wcBWH4P5q1CGoSSH/i9hrXs7SlbRLkoq9IGuoPYNGQvDJ3pt/wmOM+XgYjIDRMVIdkUWt0RsfzF50JfnCw== +"@emotion/weak-memoize@0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" + integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== + "@grafana/data@6.4.2", "@grafana/data@^6.4.2": version "6.4.2" resolved "https://registry.yarnpkg.com/@grafana/data/-/data-6.4.2.tgz#1ce4687757c609a6b12b39b04cd37e20e08fee8f" @@ -1745,6 +1829,22 @@ babel-plugin-dynamic-import-node@^2.3.0: dependencies: object.assign "^4.1.0" +babel-plugin-emotion@^10.0.27: + version "10.0.27" + resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.27.tgz#59001cf5de847c1d61f2079cd906a90a00d3184f" + integrity sha512-SUNYcT4FqhOqvwv0z1oeYhqgheU8qrceLojuHyX17ngo7WtWqN5I9l3IGHzf21Xraj465CVzF4IvOlAF+3ed0A== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@emotion/hash" "0.7.4" + "@emotion/memoize" "0.7.4" + "@emotion/serialize" "^0.11.15" + babel-plugin-macros "^2.0.0" + babel-plugin-syntax-jsx "^6.18.0" + convert-source-map "^1.5.0" + escape-string-regexp "^1.0.5" + find-root "^1.1.0" + source-map "^0.5.7" + babel-plugin-emotion@^9.2.11: version "9.2.11" resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-9.2.11.tgz#319c005a9ee1d15bb447f59fe504c35fd5807728" @@ -2810,6 +2910,11 @@ csstype@^2.5.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.7.tgz#20b0024c20b6718f4eda3853a1f5a1cce7f5e4a5" integrity sha512-9Mcn9sFbGBAdmimWb2gLVDtFJzeKtDGIr76TUqmjZrw9LFXBMSU70lcs+C0/7fyCd6iBDqmksUcCOUIkisPHsQ== +csstype@^2.5.7: + version "2.6.8" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.8.tgz#0fb6fc2417ffd2816a418c9336da74d7f07db431" + integrity sha512-msVS9qTuMT5zwAGCVm4mxfrZ18BNc6Csd0oJAtiFMZ1FAx1CCvy2+5MDmYoix63LM/6NDbNtodCiGYGmFgO0dA== + cst@^0.4.3: version "0.4.10" resolved "https://registry.yarnpkg.com/cst/-/cst-0.4.10.tgz#9c05c825290a762f0a85c0aabb8c0fe035ae8516" @@ -7333,11 +7438,16 @@ react-input-autosize@^2.2.1: dependencies: prop-types "^15.5.8" -react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4: +react-is@^16.7.0, react-is@^16.8.4: version "16.12.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q== +react-is@^16.8.1: + version "16.8.6" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" + integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== + react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" @@ -7765,13 +7875,20 @@ resolve@1.x: dependencies: path-parse "^1.0.6" -resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.3.2: +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2: version "1.14.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.1.tgz#9e018c540fcf0c427d678b9931cbf45e984bcaff" integrity sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg== dependencies: path-parse "^1.0.6" +resolve@^1.10.0: + version "1.11.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" + integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== + dependencies: + path-parse "^1.0.6" + restructured@0.0.11: version "0.0.11" resolved "https://registry.yarnpkg.com/restructured/-/restructured-0.0.11.tgz#f914f6b6f358b8e45d6d8ee268926cf1a783f710" From 376183e8e4a2a9896c19b5bf31eba27575ddf857 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Wed, 15 Jan 2020 11:02:17 +0300 Subject: [PATCH 26/27] Transform percentile function, closes #868 --- src/datasource-zabbix/dataProcessor.js | 22 ++++++++++++---------- src/datasource-zabbix/metricFunctions.js | 12 +++++++++++- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/datasource-zabbix/dataProcessor.js b/src/datasource-zabbix/dataProcessor.js index eb5d1a1..a8ecdb6 100644 --- a/src/datasource-zabbix/dataProcessor.js +++ b/src/datasource-zabbix/dataProcessor.js @@ -2,6 +2,14 @@ import _ from 'lodash'; import * as utils from './utils'; import ts, { groupBy_perf as groupBy } from './timeseries'; +let SUM = ts.SUM; +let COUNT = ts.COUNT; +let AVERAGE = ts.AVERAGE; +let MIN = ts.MIN; +let MAX = ts.MAX; +let MEDIAN = ts.MEDIAN; +let PERCENTILE = ts.PERCENTILE; + let downsampleSeries = ts.downsample; let groupBy_exported = (interval, groupFunc, datapoints) => groupBy(datapoints, interval, groupFunc); let sumSeries = ts.sumSeries; @@ -11,14 +19,7 @@ let scale = (factor, datapoints) => ts.scale_perf(datapoints, factor); let offset = (delta, datapoints) => ts.offset(datapoints, delta); let simpleMovingAverage = (n, datapoints) => ts.simpleMovingAverage(datapoints, n); let expMovingAverage = (a, datapoints) => ts.expMovingAverage(datapoints, a); - -let SUM = ts.SUM; -let COUNT = ts.COUNT; -let AVERAGE = ts.AVERAGE; -let MIN = ts.MIN; -let MAX = ts.MAX; -let MEDIAN = ts.MEDIAN; -let PERCENTILE = ts.PERCENTILE; +let percentile = (interval, n, datapoints) => groupBy(datapoints, interval, _.partial(PERCENTILE, n)); function limit(order, n, orderByFunc, timeseries) { let orderByCallback = aggregationFunctions[orderByFunc]; @@ -120,7 +121,7 @@ function aggregateWrapper(groupByCallback, interval, datapoints) { return groupBy(sortedPoints, interval, groupByCallback); } -function percentile(interval, n, datapoints) { +function percentileAgg(interval, n, datapoints) { const flattenedPoints = ts.flattenDatapoints(datapoints); // groupBy_perf works with sorted series only const sortedPoints = ts.sortByTime(flattenedPoints); @@ -153,10 +154,11 @@ let metricFunctions = { rate: rate, movingAverage: simpleMovingAverage, exponentialMovingAverage: expMovingAverage, + percentile: percentile, transformNull: transformNull, aggregateBy: aggregateByWrapper, // Predefined aggs - percentile: percentile, + percentileAgg: percentileAgg, average: _.partial(aggregateWrapper, AVERAGE), min: _.partial(aggregateWrapper, MIN), max: _.partial(aggregateWrapper, MAX), diff --git a/src/datasource-zabbix/metricFunctions.js b/src/datasource-zabbix/metricFunctions.js index 891e271..150e03a 100644 --- a/src/datasource-zabbix/metricFunctions.js +++ b/src/datasource-zabbix/metricFunctions.js @@ -85,6 +85,16 @@ addFuncDef({ defaultParams: [0.2], }); +addFuncDef({ + name: 'percentile', + category: 'Transform', + params: [ + { name: 'interval', type: 'string' }, + { name: 'percent', type: 'float', options: [25, 50, 75, 90, 95, 99, 99.9] } + ], + defaultParams: ['1m', 95], +}); + addFuncDef({ name: 'removeAboveValue', category: 'Transform', @@ -140,7 +150,7 @@ addFuncDef({ }); addFuncDef({ - name: 'percentile', + name: 'percentileAgg', category: 'Aggregate', params: [ { name: 'interval', type: 'string' }, From 5b211d80a90a8ef170c6f3967afc7444ef0c6f7b Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Wed, 15 Jan 2020 11:06:01 +0300 Subject: [PATCH 27/27] docs for percentile and percentileAgg, #868 --- docs/sources/reference/functions.md | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/docs/sources/reference/functions.md b/docs/sources/reference/functions.md index fe7e580..22622bc 100644 --- a/docs/sources/reference/functions.md +++ b/docs/sources/reference/functions.md @@ -105,6 +105,19 @@ calculates moving average over 60 points (if metric has 1 second resolution it m ``` --- +### _percentile_ +``` +percentile(interval, N) +``` +Takes a series of values and a window size and consolidate all its points fallen in the given _interval_ into one point by Nth percentile. + +Examples: +``` +percentile(1h, 99) +percentile($__range_series, 95) - 95th percentile over all series values +``` +--- + ### _removeAboveValue_ ``` removeAboveValue(N) @@ -159,16 +172,16 @@ This will add metrics together and return the sum at each datapoint. This method --- -### _percentile_ +### _percentileAgg_ ``` -percentile(interval, N) +percentileAgg(interval, N) ``` Takes all timeseries and consolidate all its points fallen in the given _interval_ into one point by Nth percentile. Examples: ``` -percentile(1h, 99) -percentile($__range_series, 95) - 95th percentile over all values +percentileAgg(1h, 99) +percentileAgg($__range_series, 95) - 95th percentile over all values ``` ---