summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJose Vargas <jvargas@gitlab.com>2019-06-06 13:35:29 -0500
committerJose Vargas <jvargas@gitlab.com>2019-06-21 16:39:44 -0500
commit5665e91ade9e16ec39e3d7e82e31849ef3554ce4 (patch)
tree29326971c3478af8c088713b318e188076abeccd
parent6d4f33ceafbf55ae1283352d092c873221fdcbf1 (diff)
downloadgitlab-ce-5665e91ade9e16ec39e3d7e82e31849ef3554ce4.tar.gz
Add column chart component to the monitoring bundlejivanvl-add-column-chart-monitoring-dashboard
This merge request just adds the column chart component without integrating it to the dashboard
-rw-r--r--app/assets/javascripts/monitoring/components/charts/column.vue131
-rw-r--r--spec/javascripts/monitoring/charts/column_spec.js58
2 files changed, 189 insertions, 0 deletions
diff --git a/app/assets/javascripts/monitoring/components/charts/column.vue b/app/assets/javascripts/monitoring/components/charts/column.vue
new file mode 100644
index 00000000000..05a2036f4c3
--- /dev/null
+++ b/app/assets/javascripts/monitoring/components/charts/column.vue
@@ -0,0 +1,131 @@
+<script>
+import { GlColumnChart } from '@gitlab/ui/dist/charts';
+import { debounceByAnimationFrame } from '~/lib/utils/common_utils';
+import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
+import { chartHeight } from '../../constants';
+import { makeDataSeries } from '~/helpers/monitor_helper';
+
+export default {
+ components: {
+ GlColumnChart,
+ },
+ inheritAttrs: false,
+ props: {
+ graphData: {
+ type: Object,
+ required: true,
+ validator(data) {
+ return (
+ Array.isArray(data.queries) &&
+ data.queries.filter(query => {
+ if (Array.isArray(query.result)) {
+ return (
+ query.result.filter(res => Array.isArray(res.values)).length === query.result.length
+ );
+ }
+ return false;
+ }).length === data.queries.length
+ );
+ },
+ containerWidth: {
+ type: Number,
+ required: true,
+ },
+ },
+ },
+ data() {
+ return {
+ width: 0,
+ height: chartHeight,
+ svgs: {},
+ debouncedResizeCallback: {},
+ };
+ },
+ computed: {
+ chartData() {
+ const queryData = this.graphData.queries.reduce((acc, query) => {
+ const series = makeDataSeries(query.result, {
+ name: this.formatLegendLabel(query),
+ });
+
+ return acc.concat(series);
+ }, []);
+
+ return {
+ values: queryData[0].data,
+ };
+ },
+ xAxisTitle() {
+ return this.graphData.queries[0].result[0].x_label !== undefined
+ ? this.graphData.queries[0].result[0].x_label
+ : '';
+ },
+ yAxisTitle() {
+ return this.graphData.queries[0].result[0].y_label !== undefined
+ ? this.graphData.queries[0].result[0].y_label
+ : '';
+ },
+ xAxisType() {
+ return this.graphData.x_type !== undefined ? this.graphData.x_type : 'category';
+ },
+ dataZoomConfig() {
+ const handleIcon = this.svgs['scroll-handle'];
+
+ return handleIcon ? { handleIcon } : {};
+ },
+ chartOptions() {
+ return {
+ dataZoom: this.dataZoomConfig,
+ };
+ },
+ },
+ watch: {
+ containerWidth: 'onResize',
+ },
+ beforeDestroy() {
+ window.removeEventListener('resize', this.debouncedResizeCallback);
+ },
+ created() {
+ this.debouncedResizeCallback = debounceByAnimationFrame(this.onResize);
+ window.addEventListener('resize', this.debouncedResizeCallback);
+ this.setSvg('scroll-handle');
+ },
+ methods: {
+ formatLegendLabel(query) {
+ return `${query.label}`;
+ },
+ onResize() {
+ const { width } = this.$refs.columnChart.$el.getBoundingClientRect();
+ this.width = width;
+ },
+ setSvg(name) {
+ getSvgIconPathContent(name)
+ .then(path => {
+ if (path) {
+ this.$set(this.svgs, name, `path://${path}`);
+ }
+ })
+ .catch(() => {});
+ },
+ },
+};
+</script>
+<template>
+ <div class="prometheus-graph col-12 col-lg-6">
+ <div class="prometheus-graph-header">
+ <h5 ref="graphTitle" class="prometheus-graph-title">{{ graphData.title }}</h5>
+ <div ref="graphWidgets" class="prometheus-graph-widgets"><slot></slot></div>
+ </div>
+ <gl-column-chart
+ ref="columnChart"
+ v-bind="$attrs"
+ :data="chartData"
+ :option="chartOptions"
+ :width="width"
+ :height="height"
+ :x-axis-title="xAxisTitle"
+ :y-axis-title="yAxisTitle"
+ :x-axis-type="xAxisType"
+ />
+ </div>
+</template>
diff --git a/spec/javascripts/monitoring/charts/column_spec.js b/spec/javascripts/monitoring/charts/column_spec.js
new file mode 100644
index 00000000000..d8ac68b9484
--- /dev/null
+++ b/spec/javascripts/monitoring/charts/column_spec.js
@@ -0,0 +1,58 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlColumnChart } from '@gitlab/ui/dist/charts';
+import ColumnChart from '~/monitoring/components/charts/column.vue';
+
+describe('Column component', () => {
+ let columnChart;
+
+ beforeEach(() => {
+ columnChart = shallowMount(ColumnChart, {
+ propsData: {
+ graphData: {
+ queries: [
+ {
+ x_label: 'Time',
+ y_label: 'Usage',
+ result: [
+ {
+ metric: {},
+ values: [
+ [1495700554.925, '8.0390625'],
+ [1495700614.925, '8.0390625'],
+ [1495700674.925, '8.0390625'],
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ containerWidth: 100,
+ },
+ });
+ });
+
+ afterEach(() => {
+ columnChart.destroy();
+ });
+
+ describe('wrapped components', () => {
+ describe('GitLab UI column chart', () => {
+ let glColumnChart;
+
+ beforeEach(() => {
+ glColumnChart = columnChart.find(GlColumnChart);
+ });
+
+ it('is a Vue instance', () => {
+ expect(glColumnChart.isVueInstance()).toBe(true);
+ });
+
+ it('receives data properties needed for proper chart render', () => {
+ const props = glColumnChart.props();
+
+ expect(props.data).toBe(columnChart.vm.chartData);
+ expect(props.option).toBe(columnChart.vm.chartOptions);
+ });
+ });
+ });
+});