Commit 27cacbd2 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch 'psi-burnup-feature-flag' into 'master'

Add burnup_chart feature flag

See merge request gitlab-org/gitlab!29391
parents 7beb37cf b1721584
......@@ -5,6 +5,9 @@ class Groups::MilestonesController < Groups::ApplicationController
before_action :milestone, only: [:edit, :show, :update, :merge_requests, :participants, :labels, :destroy]
before_action :authorize_admin_milestones!, only: [:edit, :new, :create, :update, :destroy]
before_action do
push_frontend_feature_flag(:burnup_charts)
end
def index
respond_to do |format|
......
......@@ -6,6 +6,9 @@ class Projects::MilestonesController < Projects::ApplicationController
before_action :check_issuables_available!
before_action :milestone, only: [:edit, :update, :destroy, :show, :merge_requests, :participants, :labels, :promote]
before_action do
push_frontend_feature_flag(:burnup_charts)
end
# Allow read any milestone
before_action :authorize_read_milestone!
......
<script>
import { GlButton, GlButtonGroup } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { __ } from '~/locale';
import BurndownChart from './burndown_chart.vue';
export default {
components: {
GlButton,
GlButtonGroup,
BurndownChart,
},
mixins: [glFeatureFlagsMixin()],
props: {
startDate: {
type: String,
required: true,
},
dueDate: {
type: String,
required: true,
},
openIssuesCount: {
type: Array,
required: false,
default: () => [],
},
openIssuesWeight: {
type: Array,
required: false,
default: () => [],
},
},
data() {
return {
issuesSelected: true,
};
},
computed: {
title() {
return this.glFeatures.burnupCharts ? __('Charts') : __('Burndown chart');
},
issueButtonCategory() {
return this.issuesSelected ? 'primary' : 'secondary';
},
weightButtonCategory() {
return this.issuesSelected ? 'secondary' : 'primary';
},
},
methods: {
setIssueSelected(selected) {
this.issuesSelected = selected;
},
},
};
</script>
<template>
<div data-qa-selector="burndown_chart">
<div class="burndown-header d-flex align-items-center">
<h3 ref="chartsTitle">{{ title }}</h3>
<gl-button-group class="ml-3 js-burndown-data-selector">
<gl-button
ref="totalIssuesButton"
:category="issueButtonCategory"
variant="info"
size="small"
@click="setIssueSelected(true)"
>
{{ __('Issues') }}
</gl-button>
<gl-button
ref="totalWeightButton"
:category="weightButtonCategory"
variant="info"
size="small"
data-qa-selector="weight_button"
@click="setIssueSelected(false)"
>
{{ __('Issue weight') }}
</gl-button>
</gl-button-group>
</div>
<div v-if="glFeatures.burnupCharts" class="row">
<burndown-chart
:start-date="startDate"
:due-date="dueDate"
:open-issues-count="openIssuesCount"
:open-issues-weight="openIssuesWeight"
:issues-selected="issuesSelected"
class="col-md-6"
/>
</div>
<burndown-chart
v-else
:show-title="false"
:start-date="startDate"
:due-date="dueDate"
:open-issues-count="openIssuesCount"
:open-issues-weight="openIssuesWeight"
:issues-selected="issuesSelected"
/>
</div>
</template>
<script>
import { GlDeprecatedButton, GlButtonGroup } from '@gitlab/ui';
import { GlLineChart } from '@gitlab/ui/dist/charts';
import dateFormat from 'dateformat';
import ResizableChartContainer from '~/vue_shared/components/resizable_chart/resizable_chart_container.vue';
......@@ -7,8 +6,6 @@ import { s__, __, sprintf } from '~/locale';
export default {
components: {
GlDeprecatedButton,
GlButtonGroup,
GlLineChart,
ResizableChartContainer,
},
......@@ -31,10 +28,19 @@ export default {
required: false,
default: () => [],
},
issuesSelected: {
type: Boolean,
required: false,
default: true,
},
showTitle: {
type: Boolean,
required: false,
default: true,
},
},
data() {
return {
issuesSelected: true,
tooltip: {
title: '',
content: '',
......@@ -132,27 +138,8 @@ export default {
<template>
<div data-qa-selector="burndown_chart">
<div class="burndown-header d-flex align-items-center">
<div v-if="showTitle" class="burndown-header d-flex align-items-center">
<h3>{{ __('Burndown chart') }}</h3>
<gl-button-group class="ml-3 js-burndown-data-selector">
<gl-deprecated-button
ref="totalIssuesButton"
:variant="issuesSelected ? 'primary' : 'inverted-primary'"
size="sm"
@click="showIssueCount"
>
{{ __('Issues') }}
</gl-deprecated-button>
<gl-deprecated-button
ref="totalWeightButton"
:variant="issuesSelected ? 'inverted-primary' : 'primary'"
size="sm"
data-qa-selector="weight_button"
@click="showIssueWeight"
>
{{ __('Issue weight') }}
</gl-deprecated-button>
</gl-button-group>
</div>
<resizable-chart-container class="burndown-chart">
<gl-line-chart
......
import Vue from 'vue';
import $ from 'jquery';
import Cookies from 'js-cookie';
import BurndownChart from './components/burndown_chart.vue';
import BurnCharts from './components/burn_charts.vue';
import BurndownChartData from './burndown_chart_data';
import Flash from '~/flash';
import axios from '~/lib/utils/axios_utils';
......@@ -36,10 +36,10 @@ export default () => {
return new Vue({
el: container,
components: {
BurndownChart,
BurnCharts,
},
render(createElement) {
return createElement('burndown-chart', {
return createElement('burn-charts', {
props: {
startDate,
dueDate,
......
import { shallowMount } from '@vue/test-utils';
import { GlButton } from '@gitlab/ui';
import BurnCharts from 'ee/burndown_chart/components/burn_charts.vue';
import BurndownChart from 'ee/burndown_chart/components/burndown_chart.vue';
describe('burndown_chart', () => {
let wrapper;
const findChartsTitle = () => wrapper.find({ ref: 'chartsTitle' });
const findIssuesButton = () => wrapper.find({ ref: 'totalIssuesButton' });
const findWeightButton = () => wrapper.find({ ref: 'totalWeightButton' });
const findActiveButtons = () =>
wrapper.findAll(GlButton).filter(button => button.attributes().category === 'primary');
const findBurndownChart = () => wrapper.find(BurndownChart);
const defaultProps = {
startDate: '2019-08-07T00:00:00.000Z',
dueDate: '2019-09-09T00:00:00.000Z',
openIssuesCount: [],
openIssuesWeight: [],
};
const createComponent = ({ props = {}, featureEnabled = false } = {}) => {
wrapper = shallowMount(BurnCharts, {
propsData: {
...defaultProps,
...props,
},
provide: {
glFeatures: { burnupCharts: featureEnabled },
},
});
};
it('includes Issues and Issue weight buttons', () => {
createComponent();
expect(findIssuesButton().text()).toBe('Issues');
expect(findWeightButton().text()).toBe('Issue weight');
});
it('defaults to total issues', () => {
createComponent();
expect(findActiveButtons().length).toBe(1);
expect(
findActiveButtons()
.at(0)
.text(),
).toBe('Issues');
expect(findBurndownChart().props().issuesSelected).toBe(true);
});
it('toggles Issue weight', () => {
createComponent();
findWeightButton().vm.$emit('click');
return wrapper.vm.$nextTick().then(() => {
expect(findActiveButtons().length).toBe(1);
expect(
findActiveButtons()
.at(0)
.text(),
).toBe('Issue weight');
});
});
describe('feature disabled', () => {
beforeEach(() => {
createComponent({ featureEnabled: false });
});
it('does not reduce width of burndown chart', () => {
expect(findBurndownChart().classes()).toEqual([]);
});
it('sets section title and chart title correctly', () => {
expect(findChartsTitle().text()).toBe('Burndown chart');
expect(findBurndownChart().props().showTitle).toBe(false);
});
});
describe('feature enabled', () => {
beforeEach(() => {
createComponent({ featureEnabled: true });
});
it('reduces width of burndown chart', () => {
expect(findBurndownChart().classes()).toContain('col-md-6');
});
it('sets section title and chart title correctly', () => {
expect(findChartsTitle().text()).toBe('Charts');
expect(findBurndownChart().props().showTitle).toBe(true);
});
});
});
......@@ -4,9 +4,6 @@ import BurndownChart from 'ee/burndown_chart/components/burndown_chart.vue';
describe('burndown_chart', () => {
let wrapper;
const issuesButton = () => wrapper.find({ ref: 'totalIssuesButton' });
const weightButton = () => wrapper.find({ ref: 'totalWeightButton' });
const defaultProps = {
startDate: '2019-08-07T00:00:00.000Z',
dueDate: '2019-09-09T00:00:00.000Z',
......@@ -23,31 +20,6 @@ describe('burndown_chart', () => {
});
};
it('inclues Issues and Issue weight buttons', () => {
createComponent();
expect(issuesButton().text()).toBe('Issues');
expect(weightButton().text()).toBe('Issue weight');
});
it('defaults to total issues', () => {
createComponent();
expect(issuesButton().attributes('variant')).toBe('primary');
expect(weightButton().attributes('variant')).toBe('inverted-primary');
});
it('toggles Issue weight', () => {
createComponent();
weightButton().vm.$emit('click');
return wrapper.vm.$nextTick().then(() => {
expect(issuesButton().attributes('variant')).toBe('inverted-primary');
expect(weightButton().attributes('variant')).toBe('primary');
});
});
describe('with single point', () => {
it('does not show guideline', () => {
createComponent({
......
......@@ -3576,6 +3576,9 @@ msgstr ""
msgid "Changing group path can have unintended side effects."
msgstr ""
msgid "Charts"
msgstr ""
msgid "Charts can't be displayed as the request for data has timed out. %{documentationLink}"
msgstr ""
......
......@@ -14,9 +14,12 @@ module QA
element :total_issue_weight_value
end
view 'ee/app/assets/javascripts/burndown_chart/components/burn_charts.vue' do
element :weight_button
end
view 'ee/app/assets/javascripts/burndown_chart/components/burndown_chart.vue' do
element :burndown_chart
element :weight_button
end
def click_weight_button
......
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