Commit 6aa8044f authored by Brandon Labuschagne's avatar Brandon Labuschagne

Move Devops Score empty into vue

The empty state is currently being handled outside
of the vue app. This commit moves it into the
devops score vue app.

Changelog: changed
parent 52bf0fff
<script>
import { GlBadge, GlTable } from '@gitlab/ui';
import { GlBadge, GlTable, GlLink, GlEmptyState } from '@gitlab/ui';
import { GlSingleStat } from '@gitlab/ui/dist/charts';
import { sprintf, s__ } from '~/locale';
......@@ -13,11 +13,19 @@ export default {
GlBadge,
GlTable,
GlSingleStat,
GlLink,
GlEmptyState,
},
inject: {
devopsScoreMetrics: {
default: null,
},
devopsReportDocsPath: {
default: '',
},
noDataImagePath: {
default: '',
},
},
computed: {
titleHelperText() {
......@@ -28,6 +36,9 @@ export default {
{ timestamp: this.devopsScoreMetrics.createdAt },
);
},
isEmpty() {
return this.devopsScoreMetrics.averageScore === undefined;
},
},
tableHeaderFields: [
{
......@@ -54,7 +65,19 @@ export default {
};
</script>
<template>
<div data-testid="devops-score-app">
<gl-empty-state
v-if="isEmpty"
:title="__('Data is still calculating...')"
:svg-path="noDataImagePath"
>
<template #description>
<div>{{ __('It may be several days before you see feature usage data.') }}</div>
<gl-link :href="devopsReportDocsPath">{{
__('Our documentation includes an example DevOps Score report.')
}}</gl-link>
</template>
</gl-empty-state>
<div v-else data-testid="devops-score-app">
<div class="gl-text-gray-400 gl-my-4" data-testid="devops-score-note-text">
{{ titleHelperText }}
</div>
......
......@@ -6,12 +6,14 @@ export default () => {
if (!el) return false;
const { devopsScoreMetrics } = el.dataset;
const { devopsScoreMetrics, devopsReportDocsPath, noDataImagePath } = el.dataset;
return new Vue({
el,
provide: {
devopsScoreMetrics: JSON.parse(devopsScoreMetrics),
devopsReportDocsPath,
noDataImagePath,
},
render(h) {
return h(DevopsScore);
......
......@@ -6,7 +6,7 @@ export default () => {
// eslint-disable-next-line no-new
new UserCallout();
const emptyStateContainer = document.getElementById('js-devops-empty-state');
const emptyStateContainer = document.getElementById('js-devops-usage-ping-disabled');
if (!emptyStateContainer) return false;
......
import initDevOpsScore from '~/analytics/devops_report/devops_score';
import initDevOpsScoreEmptyState from '~/analytics/devops_report/devops_score_empty_state';
import initDevOpsScoreDisabledUsagePing from '~/analytics/devops_report/devops_score_disabled_usage_ping';
initDevOpsScoreEmptyState();
initDevOpsScoreDisabledUsagePing();
initDevOpsScore();
@import 'mixins_and_variables_and_functions';
.devops-empty svg {
margin: 64px auto 32px;
max-width: 420px;
}
......@@ -2,12 +2,16 @@
module DevOpsReportHelper
def devops_score_metrics(metric)
if metric.blank?
{}
else
{
averageScore: average_score_data(metric),
cards: devops_score_card_data(metric),
createdAt: metric.created_at.strftime('%Y-%m-%d %H:%M')
}
end
end
private
......
......@@ -4,9 +4,7 @@
= render 'callout'
- if !usage_ping_enabled
#js-devops-empty-state{ data: { is_admin: current_user&.admin.to_s, empty_state_svg_path: image_path('illustrations/convdev/convdev_no_index.svg'), enable_usage_ping_link: metrics_and_profiling_admin_application_settings_path(anchor: 'js-usage-settings'), docs_link: help_page_path('development/usage_ping/index.md') } }
- elsif @metric.blank?
= render 'no_data'
#js-devops-usage-ping-disabled{ data: { is_admin: current_user&.admin.to_s, empty_state_svg_path: image_path('illustrations/convdev/convdev_no_index.svg'), enable_usage_ping_link: metrics_and_profiling_admin_application_settings_path(anchor: 'js-usage-settings'), docs_link: help_page_path('development/usage_ping/index.md') } }
- else
#js-devops-score{ data: { devops_score_metrics: devops_score_metrics(@metric).to_json } }
#js-devops-score{ data: { devops_score_metrics: devops_score_metrics(@metric).to_json, devops_report_docs_path: help_page_path('user/admin_area/analytics/dev_ops_report'), no_data_image_path: image_path('dev_ops_report_no_data.svg') } }
---
title: Migrate DevOps Score empty state to Vue
merge_request: 60715
author:
type: changed
@import '../../../../../app/assets/stylesheets/page_bundles/dev_ops_report';
@import 'page_bundles/mixins_and_variables_and_functions';
.circle {
width: $gl-spacing-scale-3;
......
import { GlTable, GlBadge } from '@gitlab/ui';
import { GlTable, GlBadge, GlEmptyState, GlLink } from '@gitlab/ui';
import { GlSingleStat } from '@gitlab/ui/dist/charts';
import { mount } from '@vue/test-utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import DevopsScore from '~/analytics/devops_report/components/devops_score.vue';
import { createdAt, cards, averageScore, devopsScoreTableHeaders } from '../mock_data';
import {
devopsScoreMetricsData,
devopsReportDocsPath,
noDataImagePath,
devopsScoreTableHeaders,
} from '../mock_data';
describe('DevopsScore', () => {
let wrapper;
const createComponent = () => {
const createComponent = ({ devopsScoreMetrics = devopsScoreMetricsData } = {}) => {
wrapper = extendedWrapper(
mount(DevopsScore, {
provide: {
devopsScoreMetrics: {
createdAt,
cards,
averageScore,
},
devopsScoreMetrics,
devopsReportDocsPath,
noDataImagePath,
},
}),
);
};
const findTable = () => wrapper.find(GlTable);
const findEmptyState = () => wrapper.find(GlEmptyState);
const findCol = (testId) => findTable().find(`[data-testid="${testId}"]`);
const findUsageCol = () => findCol('usageCol');
const findDevopsScoreApp = () => wrapper.findByTestId('devops-score-app');
describe('with no data', () => {
beforeEach(() => {
createComponent({ devopsScoreMetrics: {} });
});
describe('empty state', () => {
it('displays the empty state', () => {
expect(findEmptyState().exists()).toBe(true);
});
it('displays the correct message', () => {
expect(findEmptyState().text()).toBe(
'Data is still calculating... It may be several days before you see feature usage data. Our documentation includes an example DevOps Score report.',
);
});
it('contains a link to the feature documentation', () => {
expect(wrapper.find(GlLink).exists()).toBe(true);
});
});
it('does not display the devops score app', () => {
expect(findDevopsScoreApp().exists()).toBe(false);
});
});
describe('with data', () => {
beforeEach(() => {
createComponent();
});
it('does not display the empty state', () => {
expect(findEmptyState().exists()).toBe(false);
});
it('displays the devops score app', () => {
expect(findDevopsScoreApp().exists()).toBe(true);
});
describe('devops score app', () => {
it('displays the title note', () => {
expect(wrapper.findByTestId('devops-score-note-text').text()).toBe(
'DevOps score metrics are based on usage over the last 30 days. Last updated: 2020-06-29 08:16.',
......@@ -40,7 +81,7 @@ describe('DevopsScore', () => {
const component = wrapper.find(GlSingleStat);
expect(component.exists()).toBe(true);
expect(component.props('value')).toBe(averageScore.value);
expect(component.props('value')).toBe(devopsScoreMetricsData.averageScore.value);
});
describe('devops score table', () => {
......@@ -88,4 +129,6 @@ describe('DevopsScore', () => {
});
});
});
});
});
});
export const averageScore = {
value: '10',
scoreLevel: {
label: 'High',
icon: 'check-circle',
variant: 'success',
},
};
export const cards = [
{
title: 'Issues created per active user',
usage: '3.2',
leadInstance: '10.2',
score: '0',
scoreLevel: {
label: 'Low',
variant: 'muted',
},
},
];
export const createdAt = '2020-06-29 08:16';
export const devopsScoreTableHeaders = [
{
index: 0,
......@@ -40,3 +16,31 @@ export const devopsScoreTableHeaders = [
label: 'Score',
},
];
export const devopsScoreMetricsData = {
createdAt: '2020-06-29 08:16',
cards: [
{
title: 'Issues created per active user',
usage: '3.2',
leadInstance: '10.2',
score: '0',
scoreLevel: {
label: 'Low',
variant: 'muted',
},
},
],
averageScore: {
value: '10',
scoreLevel: {
label: 'High',
icon: 'check-circle',
variant: 'success',
},
},
};
export const devopsReportDocsPath = 'docs-path';
export const noDataImagePath = 'image-path';
......@@ -9,6 +9,9 @@ RSpec.describe DevOpsReportHelper do
describe '#devops_score_metrics' do
let(:devops_score_metrics) { helper.devops_score_metrics(subject) }
let(:devops_score_metrics_blank) { helper.devops_score_metrics({}) }
it { expect(devops_score_metrics_blank).to eq({}) }
it { expect(devops_score_metrics[:averageScore]).to eq({ scoreLevel: { icon: "status-alert", label: "Moderate", variant: "warning" }, value: "55.9" } ) }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment