diff options
-rw-r--r-- | app/assets/javascripts/monitoring/components/charts/area.vue | 14 | ||||
-rw-r--r-- | app/assets/javascripts/monitoring/components/dashboard.vue | 20 | ||||
-rw-r--r-- | app/assets/javascripts/monitoring/stores/monitoring_store.js | 39 | ||||
-rw-r--r-- | changelogs/unreleased/minimized-multiple-queries-ce.yml | 5 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | spec/javascripts/monitoring/charts/area_spec.js | 7 | ||||
-rw-r--r-- | yarn.lock | 8 |
7 files changed, 74 insertions, 21 deletions
diff --git a/app/assets/javascripts/monitoring/components/charts/area.vue b/app/assets/javascripts/monitoring/components/charts/area.vue index b0bbe272d1f..eb2ab3e135e 100644 --- a/app/assets/javascripts/monitoring/components/charts/area.vue +++ b/app/assets/javascripts/monitoring/components/charts/area.vue @@ -42,10 +42,10 @@ export default { required: false, default: () => [], }, - alertData: { - type: Object, + thresholds: { + type: Array, required: false, - default: () => ({}), + default: () => [], }, }, data() { @@ -64,6 +64,9 @@ export default { }, computed: { chartData() { + // Transforms & supplements query data to render appropriate labels & styles + // Input: [{ queryAttributes1 }, { queryAttributes2 }] + // Output: [{ seriesAttributes1 }, { seriesAttributes2 }] return this.graphData.queries.reduce((acc, query) => { const { appearance } = query; const lineType = @@ -121,6 +124,9 @@ export default { }, earliestDatapoint() { return this.chartData.reduce((acc, series) => { + if (!series.data.length) { + return acc; + } const [[timestamp]] = series.data.sort(([a], [b]) => { if (a < b) { return -1; @@ -235,7 +241,7 @@ export default { :data="chartData" :option="chartOptions" :format-tooltip-text="formatTooltipText" - :thresholds="alertData" + :thresholds="thresholds" :width="width" :height="height" @updated="onChartUpdated" diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index ba6a17827f7..f5019bc627e 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -1,5 +1,6 @@ <script> import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import _ from 'underscore'; import { s__ } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue'; import '~/vue_shared/mixins/is_ee'; @@ -142,8 +143,13 @@ export default { } }, methods: { - getGraphAlerts(graphId) { - return this.alertData ? this.alertData[graphId] || {} : {}; + getGraphAlerts(queries) { + if (!this.allAlerts) return {}; + const metricIdsForChart = queries.map(q => q.metricId); + return _.pick(this.allAlerts, alert => metricIdsForChart.includes(alert.metricId)); + }, + getGraphAlertValues(queries) { + return Object.values(this.getGraphAlerts(queries)); }, getGraphsData() { this.state = 'loading'; @@ -199,17 +205,15 @@ export default { :key="graphIndex" :graph-data="graphData" :deployment-data="store.deploymentData" - :alert-data="getGraphAlerts(graphData.id)" + :thresholds="getGraphAlertValues(graphData.queries)" :container-width="elWidth" group-id="monitor-area-chart" > <alert-widget - v-if="isEE && prometheusAlertsAvailable && alertsEndpoint && graphData.id" + v-if="isEE && prometheusAlertsAvailable && alertsEndpoint && graphData" :alerts-endpoint="alertsEndpoint" - :label="getGraphLabel(graphData)" - :current-alerts="getQueryAlerts(graphData)" - :custom-metric-id="graphData.id" - :alert-data="alertData[graphData.id]" + :relevant-queries="graphData.queries" + :alerts-to-manage="getGraphAlerts(graphData.queries)" @setAlerts="setAlerts" /> </monitor-area-chart> diff --git a/app/assets/javascripts/monitoring/stores/monitoring_store.js b/app/assets/javascripts/monitoring/stores/monitoring_store.js index 70635059bd9..9761fe168be 100644 --- a/app/assets/javascripts/monitoring/stores/monitoring_store.js +++ b/app/assets/javascripts/monitoring/stores/monitoring_store.js @@ -27,10 +27,47 @@ function removeTimeSeriesNoData(queries) { return queries.reduce((series, query) => series.concat(checkQueryEmptyData(query)), []); } +// Metrics and queries are currently stored 1:1, so `queries` is an array of length one. +// We want to group queries onto a single chart by title & y-axis label. +// This function will no longer be required when metrics:queries are 1:many, +// though there is no consequence if the function stays in use. +// @param metrics [Array<Object>] +// Ex) [ +// { id: 1, title: 'title', y_label: 'MB', queries: [{ ...query1Attrs }] }, +// { id: 2, title: 'title', y_label: 'MB', queries: [{ ...query2Attrs }] }, +// { id: 3, title: 'new title', y_label: 'MB', queries: [{ ...query3Attrs }] } +// ] +// @return [Array<Object>] +// Ex) [ +// { title: 'title', y_label: 'MB', queries: [{ metricId: 1, ...query1Attrs }, +// { metricId: 2, ...query2Attrs }] }, +// { title: 'new title', y_label: 'MB', queries: [{ metricId: 3, ...query3Attrs }]} +// ] +function groupQueriesByChartInfo(metrics) { + const metricsByChart = metrics.reduce((accumulator, metric) => { + const { id, queries, ...chart } = metric; + + const chartKey = `${chart.title}|${chart.y_label}`; + accumulator[chartKey] = accumulator[chartKey] || { ...chart, queries: [] }; + + queries.forEach(queryAttrs => + accumulator[chartKey].queries.push({ metricId: id.toString(), ...queryAttrs }), + ); + + return accumulator; + }, {}); + + return Object.values(metricsByChart); +} + function normalizeMetrics(metrics) { - return metrics.map(metric => { + const groupedMetrics = groupQueriesByChartInfo(metrics); + + return groupedMetrics.map(metric => { const queries = metric.queries.map(query => ({ ...query, + // custom metrics do not require a label, so we should ensure this attribute is defined + label: query.label || metric.y_label, result: query.result.map(result => ({ ...result, values: result.values.map(([timestamp, value]) => [ diff --git a/changelogs/unreleased/minimized-multiple-queries-ce.yml b/changelogs/unreleased/minimized-multiple-queries-ce.yml new file mode 100644 index 00000000000..d8c20d492d6 --- /dev/null +++ b/changelogs/unreleased/minimized-multiple-queries-ce.yml @@ -0,0 +1,5 @@ +--- +title: Support multiple queries per chart on metrics dash +merge_request: 25758 +author: +type: added diff --git a/package.json b/package.json index 74de09010d4..ac8f6bd0db5 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@babel/preset-env": "^7.3.1", "@gitlab/csslab": "^1.9.0", "@gitlab/svgs": "^1.58.0", - "@gitlab/ui": "^3.0.0", + "@gitlab/ui": "^3.0.1", "apollo-cache-inmemory": "^1.5.1", "apollo-client": "^2.5.1", "apollo-upload-client": "^10.0.0", diff --git a/spec/javascripts/monitoring/charts/area_spec.js b/spec/javascripts/monitoring/charts/area_spec.js index 549a7935c0f..4ff519ae0e7 100644 --- a/spec/javascripts/monitoring/charts/area_spec.js +++ b/spec/javascripts/monitoring/charts/area_spec.js @@ -65,7 +65,7 @@ describe('Area component', () => { expect(props.data).toBe(areaChart.vm.chartData); expect(props.option).toBe(areaChart.vm.chartOptions); expect(props.formatTooltipText).toBe(areaChart.vm.formatTooltipText); - expect(props.thresholds).toBe(areaChart.props('alertData')); + expect(props.thresholds).toBe(areaChart.vm.thresholds); }); it('recieves a tooltip title', () => { @@ -105,12 +105,13 @@ describe('Area component', () => { seriesName: areaChart.vm.chartData[0].name, componentSubType: type, value: [mockDate, 5.55555], + seriesIndex: 0, }, ], value: mockDate, }); - describe('series is of line type', () => { + describe('when series is of line type', () => { beforeEach(() => { areaChart.vm.formatTooltipText(generateSeriesData('line')); }); @@ -131,7 +132,7 @@ describe('Area component', () => { }); }); - describe('series is of scatter type', () => { + describe('when series is of scatter type', () => { beforeEach(() => { areaChart.vm.formatTooltipText(generateSeriesData('scatter')); }); diff --git a/yarn.lock b/yarn.lock index cd420b81ad6..80f25897670 100644 --- a/yarn.lock +++ b/yarn.lock @@ -663,10 +663,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.58.0.tgz#bb05263ff2eb7ca09a25cd14d0b1a932d2ea9c2f" integrity sha512-RlWSjjBT4lMIFuNC1ziCO1nws9zqZtxCjhrqK2DxDDTgp2W0At9M/BFkHp8RHyMCrO3g1fHTrLPUgzr5oR3Epg== -"@gitlab/ui@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-3.0.0.tgz#33ca2808dbd4395e69a366a219d1edc1f3dbccd5" - integrity sha512-pDEa2k6ln5GE/N2z0V7dNEeFtSTW0p9ipO2/N9q6QMxO7fhhOhpMC0QVbdIljKTbglspDWI5v6BcqUjzYri5Pg== +"@gitlab/ui@^3.0.1": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-3.0.2.tgz#29a17699751261657487b939c651c0f93264df2a" + integrity sha512-JZhcS5cDxtpxopTc55UWvUbZAwKvxygYHT9I01QmUtKgaKIJlnjBj8zkcg1xHazX7raSjjtjqfDEla39a+luuQ== dependencies: "@babel/standalone" "^7.0.0" bootstrap-vue "^2.0.0-rc.11" |