This instance will be upgraded to Heptapod 0.27.1 on 2021-12-02 at 15:00 UTC+1 (a few minutes of down time)

Commit 58c69cb3 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent dcd9852800af
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
- .default-before_script - .default-before_script
- .assets-compile-cache - .assets-compile-cache
- .only:changes-code-backstage-qa - .only:changes-code-backstage-qa
image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.3-git-2.22-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.33-docker-18.06.1 image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.3-git-2.22-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.33-docker-19.03.1
stage: test stage: test
dependencies: ["setup-test-env"] dependencies: ["setup-test-env"]
needs: ["setup-test-env"] needs: ["setup-test-env"]
......
...@@ -312,8 +312,7 @@ gem 'gettext', '~> 3.2.2', require: false, group: :development ...@@ -312,8 +312,7 @@ gem 'gettext', '~> 3.2.2', require: false, group: :development
gem 'batch-loader', '~> 1.4.0' gem 'batch-loader', '~> 1.4.0'
# Perf bar # Perf bar
# https://gitlab.com/gitlab-org/gitlab/issues/13996 gem 'peek', '~> 1.1'
gem 'gitlab-peek', '~> 0.0.1', require: 'peek'
# Snowplow events tracking # Snowplow events tracking
gem 'snowplow-tracker', '~> 0.6.1' gem 'snowplow-tracker', '~> 0.6.1'
...@@ -381,7 +380,7 @@ group :development, :test do ...@@ -381,7 +380,7 @@ group :development, :test do
gem 'knapsack', '~> 1.17' gem 'knapsack', '~> 1.17'
gem 'stackprof', '~> 0.2.10', require: false gem 'stackprof', '~> 0.2.13', require: false
gem 'simple_po_parser', '~> 1.1.2', require: false gem 'simple_po_parser', '~> 1.1.2', require: false
......
...@@ -373,8 +373,6 @@ GEM ...@@ -373,8 +373,6 @@ GEM
gitlab-license (1.0.0) gitlab-license (1.0.0)
gitlab-markup (1.7.0) gitlab-markup (1.7.0)
gitlab-net-dns (0.9.1) gitlab-net-dns (0.9.1)
gitlab-peek (0.0.1)
railties (>= 4.0.0)
gitlab-sidekiq-fetcher (0.5.2) gitlab-sidekiq-fetcher (0.5.2)
sidekiq (~> 5) sidekiq (~> 5)
gitlab-styles (2.8.0) gitlab-styles (2.8.0)
...@@ -724,6 +722,8 @@ GEM ...@@ -724,6 +722,8 @@ GEM
parser (2.6.3.0) parser (2.6.3.0)
ast (~> 2.4.0) ast (~> 2.4.0)
parslet (1.8.2) parslet (1.8.2)
peek (1.1.0)
railties (>= 4.0.0)
pg (1.1.4) pg (1.1.4)
po_to_json (1.0.1) po_to_json (1.0.1)
json (>= 1.6.0) json (>= 1.6.0)
...@@ -1003,7 +1003,7 @@ GEM ...@@ -1003,7 +1003,7 @@ GEM
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
sqlite3 (1.3.13) sqlite3 (1.3.13)
sshkey (2.0.0) sshkey (2.0.0)
stackprof (0.2.10) stackprof (0.2.13)
state_machines (0.5.0) state_machines (0.5.0)
state_machines-activemodel (0.7.1) state_machines-activemodel (0.7.1)
activemodel (>= 4.1) activemodel (>= 4.1)
...@@ -1201,7 +1201,6 @@ DEPENDENCIES ...@@ -1201,7 +1201,6 @@ DEPENDENCIES
gitlab-license (~> 1.0) gitlab-license (~> 1.0)
gitlab-markup (~> 1.7.0) gitlab-markup (~> 1.7.0)
gitlab-net-dns (~> 0.9.1) gitlab-net-dns (~> 0.9.1)
gitlab-peek (~> 0.0.1)
gitlab-sidekiq-fetcher (= 0.5.2) gitlab-sidekiq-fetcher (= 0.5.2)
gitlab-styles (~> 2.7) gitlab-styles (~> 2.7)
gitlab_chronic_duration (~> 0.10.6.2) gitlab_chronic_duration (~> 0.10.6.2)
...@@ -1276,6 +1275,7 @@ DEPENDENCIES ...@@ -1276,6 +1275,7 @@ DEPENDENCIES
omniauth_crowd (~> 2.2.0) omniauth_crowd (~> 2.2.0)
omniauth_openid_connect (~> 0.3.3) omniauth_openid_connect (~> 0.3.3)
org-ruby (~> 0.9.12) org-ruby (~> 0.9.12)
peek (~> 1.1)
pg (~> 1.1) pg (~> 1.1)
premailer-rails (~> 1.10.3) premailer-rails (~> 1.10.3)
prometheus-client-mmap (~> 0.9.10) prometheus-client-mmap (~> 0.9.10)
...@@ -1340,7 +1340,7 @@ DEPENDENCIES ...@@ -1340,7 +1340,7 @@ DEPENDENCIES
spring-commands-rspec (~> 1.0.4) spring-commands-rspec (~> 1.0.4)
sprockets (~> 3.7.0) sprockets (~> 3.7.0)
sshkey (~> 2.0) sshkey (~> 2.0)
stackprof (~> 0.2.10) stackprof (~> 0.2.13)
state_machines-activerecord (~> 0.6.0) state_machines-activerecord (~> 0.6.0)
sys-filesystem (~> 1.1.6) sys-filesystem (~> 1.1.6)
test-prof (~> 0.10.0) test-prof (~> 0.10.0)
......
...@@ -29,7 +29,7 @@ const AREA_COLOR_RGBA = `rgba(${hexToRgb(AREA_COLOR).join(',')},${AREA_OPACITY}) ...@@ -29,7 +29,7 @@ const AREA_COLOR_RGBA = `rgba(${hexToRgb(AREA_COLOR).join(',')},${AREA_OPACITY})
* time series chart, the boundary band shows the normal * time series chart, the boundary band shows the normal
* range of values the metric should take. * range of values the metric should take.
* *
* This component accepts 3 queries, which contain the * This component accepts 3 metrics, which contain the
* "metric", "upper" limit and "lower" limit. * "metric", "upper" limit and "lower" limit.
* *
* The upper and lower series are "stacked areas" visually * The upper and lower series are "stacked areas" visually
...@@ -62,10 +62,10 @@ export default { ...@@ -62,10 +62,10 @@ export default {
}, },
computed: { computed: {
series() { series() {
return this.graphData.queries.map(query => { return this.graphData.metrics.map(metric => {
const values = query.result[0] ? query.result[0].values : []; const values = metric.result && metric.result[0] ? metric.result[0].values : [];
return { return {
label: query.label, label: metric.label,
// NaN values may disrupt avg., max. & min. calculations in the legend, filter them out // NaN values may disrupt avg., max. & min. calculations in the legend, filter them out
data: values.filter(([, value]) => !Number.isNaN(value)), data: values.filter(([, value]) => !Number.isNaN(value)),
}; };
...@@ -83,7 +83,7 @@ export default { ...@@ -83,7 +83,7 @@ export default {
return min < 0 ? -min : 0; return min < 0 ? -min : 0;
}, },
metricData() { metricData() {
const originalMetricQuery = this.graphData.queries[0]; const originalMetricQuery = this.graphData.metrics[0];
const metricQuery = { ...originalMetricQuery }; const metricQuery = { ...originalMetricQuery };
metricQuery.result[0].values = metricQuery.result[0].values.map(([x, y]) => [ metricQuery.result[0].values = metricQuery.result[0].values.map(([x, y]) => [
...@@ -93,7 +93,7 @@ export default { ...@@ -93,7 +93,7 @@ export default {
return { return {
...this.graphData, ...this.graphData,
type: 'line-chart', type: 'line-chart',
queries: [metricQuery], metrics: [metricQuery],
}; };
}, },
metricSeriesConfig() { metricSeriesConfig() {
......
...@@ -32,8 +32,8 @@ export default { ...@@ -32,8 +32,8 @@ export default {
}, },
computed: { computed: {
chartData() { chartData() {
const queryData = this.graphData.queries.reduce((acc, query) => { const queryData = this.graphData.metrics.reduce((acc, query) => {
const series = makeDataSeries(query.result, { const series = makeDataSeries(query.result || [], {
name: this.formatLegendLabel(query), name: this.formatLegendLabel(query),
}); });
...@@ -45,13 +45,13 @@ export default { ...@@ -45,13 +45,13 @@ export default {
}; };
}, },
xAxisTitle() { xAxisTitle() {
return this.graphData.queries[0].result[0].x_label !== undefined return this.graphData.metrics[0].result[0].x_label !== undefined
? this.graphData.queries[0].result[0].x_label ? this.graphData.metrics[0].result[0].x_label
: ''; : '';
}, },
yAxisTitle() { yAxisTitle() {
return this.graphData.queries[0].result[0].y_label !== undefined return this.graphData.metrics[0].result[0].y_label !== undefined
? this.graphData.queries[0].result[0].y_label ? this.graphData.metrics[0].result[0].y_label
: ''; : '';
}, },
xAxisType() { xAxisType() {
......
...@@ -24,7 +24,7 @@ export default { ...@@ -24,7 +24,7 @@ export default {
}, },
computed: { computed: {
chartData() { chartData() {
return this.queries.result.reduce( return this.metrics.result.reduce(
(acc, result, i) => [...acc, ...result.values.map((value, j) => [i, j, value[1]])], (acc, result, i) => [...acc, ...result.values.map((value, j) => [i, j, value[1]])],
[], [],
); );
...@@ -36,7 +36,7 @@ export default { ...@@ -36,7 +36,7 @@ export default {
return this.graphData.y_label || ''; return this.graphData.y_label || '';
}, },
xAxisLabels() { xAxisLabels() {
return this.queries.result.map(res => Object.values(res.metric)[0]); return this.metrics.result.map(res => Object.values(res.metric)[0]);
}, },
yAxisLabels() { yAxisLabels() {
return this.result.values.map(val => { return this.result.values.map(val => {
...@@ -46,10 +46,10 @@ export default { ...@@ -46,10 +46,10 @@ export default {
}); });
}, },
result() { result() {
return this.queries.result[0]; return this.metrics.result[0];
}, },
queries() { metrics() {
return this.graphData.queries[0]; return this.graphData.metrics[0];
}, },
}, },
}; };
......
...@@ -17,7 +17,7 @@ export default { ...@@ -17,7 +17,7 @@ export default {
}, },
computed: { computed: {
queryInfo() { queryInfo() {
return this.graphData.queries[0]; return this.graphData.metrics[0];
}, },
engineeringNotation() { engineeringNotation() {
return `${roundOffFloat(this.queryInfo.result[0].value[1], 1)}${this.queryInfo.unit}`; return `${roundOffFloat(this.queryInfo.result[0].value[1], 1)}${this.queryInfo.unit}`;
......
...@@ -105,7 +105,7 @@ export default { ...@@ -105,7 +105,7 @@ export default {
// Transforms & supplements query data to render appropriate labels & styles // Transforms & supplements query data to render appropriate labels & styles
// Input: [{ queryAttributes1 }, { queryAttributes2 }] // Input: [{ queryAttributes1 }, { queryAttributes2 }]
// Output: [{ seriesAttributes1 }, { seriesAttributes2 }] // Output: [{ seriesAttributes1 }, { seriesAttributes2 }]
return this.graphData.queries.reduce((acc, query) => { return this.graphData.metrics.reduce((acc, query) => {
const { appearance } = query; const { appearance } = query;
const lineType = const lineType =
appearance && appearance.line && appearance.line.type appearance && appearance.line && appearance.line.type
...@@ -121,7 +121,7 @@ export default { ...@@ -121,7 +121,7 @@ export default {
? appearance.area.opacity ? appearance.area.opacity
: undefined, : undefined,
}; };
const series = makeDataSeries(query.result, { const series = makeDataSeries(query.result || [], {
name: this.formatLegendLabel(query), name: this.formatLegendLabel(query),
lineStyle: { lineStyle: {
type: lineType, type: lineType,
......
...@@ -250,14 +250,9 @@ export default { ...@@ -250,14 +250,9 @@ export default {
'setEndpoints', 'setEndpoints',
'setPanelGroupMetrics', 'setPanelGroupMetrics',
]), ]),
chartsWithData(charts) { updateMetrics(key, panels) {
return charts.filter(chart =>
chart.metrics.some(metric => this.metricsWithData.includes(metric.metric_id)),
);
},
updateMetrics(key, metrics) {
this.setPanelGroupMetrics({ this.setPanelGroupMetrics({
metrics, panels,
key, key,
}); });
}, },
...@@ -292,8 +287,13 @@ export default { ...@@ -292,8 +287,13 @@ export default {
submitCustomMetricsForm() { submitCustomMetricsForm() {
this.$refs.customMetricsForm.submit(); this.$refs.customMetricsForm.submit();
}, },
chartsWithData(panels) {
return panels.filter(panel =>
panel.metrics.some(metric => this.metricsWithData.includes(metric.metric_id)),
);
},
groupHasData(group) { groupHasData(group) {
return this.chartsWithData(group.metrics).length > 0; return this.chartsWithData(group.panels).length > 0;
}, },
onDateTimePickerApply(timeWindowUrlParams) { onDateTimePickerApply(timeWindowUrlParams) {
return redirectTo(mergeUrlParams(timeWindowUrlParams, window.location.href)); return redirectTo(mergeUrlParams(timeWindowUrlParams, window.location.href));
...@@ -453,14 +453,14 @@ export default { ...@@ -453,14 +453,14 @@ export default {
:collapse-group="groupHasData(groupData)" :collapse-group="groupHasData(groupData)"
> >
<vue-draggable <vue-draggable
:value="groupData.metrics" :value="groupData.panels"
group="metrics-dashboard" group="metrics-dashboard"
:component-data="{ attrs: { class: 'row mx-0 w-100' } }" :component-data="{ attrs: { class: 'row mx-0 w-100' } }"
:disabled="!isRearrangingPanels" :disabled="!isRearrangingPanels"
@input="updateMetrics(groupData.key, $event)" @input="updateMetrics(groupData.key, $event)"
> >
<div <div
v-for="(graphData, graphIndex) in groupData.metrics" v-for="(graphData, graphIndex) in groupData.panels"
:key="`panel-type-${graphIndex}`" :key="`panel-type-${graphIndex}`"
class="col-12 col-lg-6 px-2 mb-2 draggable" class="col-12 col-lg-6 px-2 mb-2 draggable"
:class="{ 'draggable-enabled': isRearrangingPanels }" :class="{ 'draggable-enabled': isRearrangingPanels }"
...@@ -469,7 +469,7 @@ export default { ...@@ -469,7 +469,7 @@ export default {
<div <div
v-if="isRearrangingPanels" v-if="isRearrangingPanels"
class="draggable-remove js-draggable-remove p-2 w-100 position-absolute d-flex justify-content-end" class="draggable-remove js-draggable-remove p-2 w-100 position-absolute d-flex justify-content-end"
@click="removeGraph(groupData.metrics, graphIndex)" @click="removeGraph(groupData.panels, graphIndex)"
> >
<a class="mx-2 p-2 draggable-remove-link" :aria-label="__('Remove')" <a class="mx-2 p-2 draggable-remove-link" :aria-label="__('Remove')"
><icon name="close" ><icon name="close"
......
...@@ -37,11 +37,14 @@ export default { ...@@ -37,11 +37,14 @@ export default {
computed: { computed: {
...mapState('monitoringDashboard', ['dashboard', 'metricsWithData']), ...mapState('monitoringDashboard', ['dashboard', 'metricsWithData']),
charts() { charts() {
if (!this.dashboard || !this.dashboard.panel_groups) {
return [];
}
const groupWithMetrics = this.dashboard.panel_groups.find(group => const groupWithMetrics = this.dashboard.panel_groups.find(group =>
group.metrics.find(chart => this.chartHasData(chart)), group.panels.find(chart => this.chartHasData(chart)),
) || { metrics: [] }; ) || { panels: [] };
return groupWithMetrics.metrics.filter(chart => this.chartHasData(chart)); return groupWithMetrics.panels.filter(chart => this.chartHasData(chart));
}, },
isSingleChart() { isSingleChart() {
return this.charts.length === 1; return this.charts.length === 1;
......
...@@ -54,10 +54,14 @@ export default { ...@@ -54,10 +54,14 @@ export default {
return IS_EE && this.prometheusAlertsAvailable && this.alertsEndpoint && this.graphData; return IS_EE && this.prometheusAlertsAvailable && this.alertsEndpoint && this.graphData;
}, },
graphDataHasMetrics() { graphDataHasMetrics() {
return this.graphData.queries[0].result.length > 0; return (
this.graphData.metrics &&
this.graphData.metrics[0].result &&
this.graphData.metrics[0].result.length > 0
);
}, },
csvText() { csvText() {
const chartData = this.graphData.queries[0].result[0].values; const chartData = this.graphData.metrics[0].result[0].values;
const yLabel = this.graphData.y_label; const yLabel = this.graphData.y_label;
const header = `timestamp,${yLabel}\r\n`; // eslint-disable-line @gitlab/i18n/no-non-i18n-strings const header = `timestamp,${yLabel}\r\n`; // eslint-disable-line @gitlab/i18n/no-non-i18n-strings
return chartData.reduce((csv, data) => { return chartData.reduce((csv, data) => {
...@@ -112,7 +116,7 @@ export default { ...@@ -112,7 +116,7 @@ export default {
:graph-data="graphData" :graph-data="graphData"
:deployment-data="deploymentData" :deployment-data="deploymentData"
:project-path="projectPath" :project-path="projectPath"
:thresholds="getGraphAlertValues(graphData.queries)" :thresholds="getGraphAlertValues(graphData.metrics)"
group-id="panel-type-chart" group-id="panel-type-chart"
> >
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
...@@ -120,8 +124,8 @@ export default { ...@@ -120,8 +124,8 @@ export default {
v-if="alertWidgetAvailable && graphData" v-if="alertWidgetAvailable && graphData"
:modal-id="`alert-modal-${index}`" :modal-id="`alert-modal-${index}`"
:alerts-endpoint="alertsEndpoint" :alerts-endpoint="alertsEndpoint"
:relevant-queries="graphData.queries" :relevant-queries="graphData.metrics"
:alerts-to-manage="getGraphAlerts(graphData.queries)" :alerts-to-manage="getGraphAlerts(graphData.metrics)"
@setAlerts="setAlerts" @setAlerts="setAlerts"
/> />
<gl-dropdown <gl-dropdown
......
import Vue from 'vue'; import Vue from 'vue';
import { slugify } from '~/lib/utils/text_utility'; import { slugify } from '~/lib/utils/text_utility';
import * as types from './mutation_types'; import * as types from './mutation_types';
import { normalizeMetrics, normalizeMetric, normalizeQueryResult } from './utils'; import { normalizeMetric, normalizeQueryResult } from './utils';
const normalizePanel = panel => panel.metrics.map(normalizeMetric); const normalizePanelMetrics = (metrics, defaultLabel) =>
metrics.map(metric => ({
...normalizeMetric(metric),
label: metric.label || defaultLabel,
}));
export default { export default {
[types.REQUEST_METRICS_DATA](state) { [types.REQUEST_METRICS_DATA](state) {
...@@ -13,28 +17,18 @@ export default { ...@@ -13,28 +17,18 @@ export default {
[types.RECEIVE_METRICS_DATA_SUCCESS](state, groupData) { [types.RECEIVE_METRICS_DATA_SUCCESS](state, groupData) {
state.dashboard.panel_groups = groupData.map((group, i) => { state.dashboard.panel_groups = groupData.map((group, i) => {
const key = `${slugify(group.group || 'default')}-${i}`; const key = `${slugify(group.group || 'default')}-${i}`;
let { metrics = [], panels = [] } = group; let { panels = [] } = group;
// each panel has metric information that needs to be normalized // each panel has metric information that needs to be normalized
panels = panels.map(panel => ({ panels = panels.map(panel => ({
...panel, ...panel,
metrics: normalizePanel(panel), metrics: normalizePanelMetrics(panel.metrics, panel.y_label),
}));
// for backwards compatibility, and to limit Vue template changes:
// for each group alias panels to metrics
// for each panel alias metrics to queries
metrics = panels.map(panel => ({
...panel,
queries: panel.metrics,
})); }));
return { return {
...group, ...group,
panels, panels,
key, key,
metrics: normalizeMetrics(metrics),
}; };
}); });
...@@ -58,6 +52,7 @@ export default { ...@@ -58,6 +52,7 @@ export default {
[types.RECEIVE_ENVIRONMENTS_DATA_FAILURE](state) { [types.RECEIVE_ENVIRONMENTS_DATA_FAILURE](state) {
state.environments = []; state.environments = [];
}, },
[types.SET_QUERY_RESULT](state, { metricId, result }) { [types.SET_QUERY_RESULT](state, { metricId, result }) {
if (!metricId || !result || result.length === 0) { if (!metricId || !result || result.length === 0) {
return; return;
...@@ -65,14 +60,17 @@ export default { ...@@ -65,14 +60,17 @@ export default {
state.showEmptyState = false; state.showEmptyState = false;
/**
* Search the dashboard state for a matching id
*/
state.dashboard.panel_groups.forEach(group => { state.dashboard.panel_groups.forEach(group => {
group.metrics.forEach(metric => { group.panels.forEach(panel => {
metric.queries.forEach(query => { panel.metrics.forEach(metric => {
if (query.metric_id === metricId) { if (metric.metric_id === metricId) {
state.metricsWithData.push(metricId); state.metricsWithData.push(metricId);
// ensure dates/numbers are correctly formatted for charts // ensure dates/numbers are correctly formatted for charts
const normalizedResults = result.map(normalizeQueryResult); const normalizedResults = result.map(normalizeQueryResult);
Vue.set(query, 'result', Object.freeze(normalizedResults)); Vue.set(metric, 'result', Object.freeze(normalizedResults));
} }
}); });
}); });
...@@ -101,6 +99,6 @@ export default { ...@@ -101,6 +99,6 @@ export default {
}, },
[types.SET_PANEL_GROUP_METRICS](state, payload) { [types.SET_PANEL_GROUP_METRICS](state, payload) {
const panelGroup = state.dashboard.panel_groups.find(pg => payload.key === pg.key); const panelGroup = state.dashboard.panel_groups.find(pg => payload.key === pg.key);
panelGroup.metrics = payload.metrics; panelGroup.panels = payload.panels;
}, },
}; };
import _ from 'underscore'; import _ from 'underscore';