Commit 71d337e4 authored by Aishwarya Subramanian's avatar Aishwarya Subramanian

Add CSV export button in Compliance Dashboard

Adds a CSV export button for Merge Commits in
a group in the Compliance Dashboard.
parent ecc3943d
...@@ -5,7 +5,7 @@ import { parseBoolean } from '~/lib/utils/common_utils'; ...@@ -5,7 +5,7 @@ import { parseBoolean } from '~/lib/utils/common_utils';
export default () => { export default () => {
const el = document.getElementById('js-compliance-dashboard'); const el = document.getElementById('js-compliance-dashboard');
const { mergeRequests, emptyStateSvgPath, isLastPage } = el.dataset; const { mergeRequests, emptyStateSvgPath, isLastPage, mergeCommitsCsvExportPath } = el.dataset;
return new Vue({ return new Vue({
el, el,
...@@ -15,6 +15,7 @@ export default () => { ...@@ -15,6 +15,7 @@ export default () => {
mergeRequests: JSON.parse(mergeRequests), mergeRequests: JSON.parse(mergeRequests),
isLastPage: parseBoolean(isLastPage), isLastPage: parseBoolean(isLastPage),
emptyStateSvgPath, emptyStateSvgPath,
mergeCommitsCsvExportPath,
}, },
}), }),
}); });
......
...@@ -4,6 +4,7 @@ import { GlTabs, GlTab } from '@gitlab/ui'; ...@@ -4,6 +4,7 @@ import { GlTabs, GlTab } from '@gitlab/ui';
import { __ } from '~/locale'; import { __ } from '~/locale';
import MergeRequestsGrid from './merge_requests/grid.vue'; import MergeRequestsGrid from './merge_requests/grid.vue';
import EmptyState from './empty_state.vue'; import EmptyState from './empty_state.vue';
import MergeCommitsExportButton from './merge_requests/merge_commits_export_button.vue';
import { COMPLIANCE_TAB_COOKIE_KEY } from '../constants'; import { COMPLIANCE_TAB_COOKIE_KEY } from '../constants';
export default { export default {
...@@ -13,6 +14,7 @@ export default { ...@@ -13,6 +14,7 @@ export default {
EmptyState, EmptyState,
GlTab, GlTab,
GlTabs, GlTabs,
MergeCommitsExportButton,
}, },
props: { props: {
emptyStateSvgPath: { emptyStateSvgPath: {
...@@ -28,11 +30,19 @@ export default { ...@@ -28,11 +30,19 @@ export default {
required: false, required: false,
default: false, default: false,
}, },
mergeCommitsCsvExportPath: {
type: String,
required: false,
default: '',
},
}, },
computed: { computed: {
hasMergeRequests() { hasMergeRequests() {
return this.mergeRequests.length > 0; return this.mergeRequests.length > 0;
}, },
hasMergeCommitsCsvExportPath() {
return this.mergeCommitsCsvExportPath !== '';
},
}, },
methods: { methods: {
showTabs() { showTabs() {
...@@ -49,8 +59,14 @@ export default { ...@@ -49,8 +59,14 @@ export default {
<template> <template>
<div v-if="hasMergeRequests" class="compliance-dashboard"> <div v-if="hasMergeRequests" class="compliance-dashboard">
<header class="gl-my-5"> <header>
<h4>{{ $options.strings.heading }}</h4> <div class="gl-mt-5 d-flex">
<h4 class="gl-flex-grow-1 gl-my-0">{{ $options.strings.heading }}</h4>
<merge-commits-export-button
v-if="hasMergeCommitsCsvExportPath"
:merge-commits-csv-export-path="mergeCommitsCsvExportPath"
/>
</div>
<p>{{ $options.strings.subheading }}</p> <p>{{ $options.strings.subheading }}</p>
</header> </header>
......
<script>
import { GlButton, GlTooltip } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
components: {
GlButton,
GlTooltip,
},
props: {
mergeCommitsCsvExportPath: {
required: true,
type: String,
},
},
strings: {
listMergeCommitsButtonText: __('List of all merge commits'),
exportAsCsv: __('Export as CSV'),
csvSizeLimit: __('(max size 15 MB)'),
},
data() {
return {
button: null,
};
},
mounted() {
this.button = this.$refs.button;
},
};
</script>
<template>
<div>
<gl-button
ref="button"
:href="mergeCommitsCsvExportPath"
icon="export"
class="gl-align-self-center"
>
{{ $options.strings.listMergeCommitsButtonText }}
</gl-button>
<gl-tooltip v-if="button" :target="button" boundary="viewport" placement="top">
<p class="gl-my-0">{{ $options.strings.exportAsCsv }}</p>
<p class="gl-my-0">{{ $options.strings.csvSizeLimit }}</p>
</gl-tooltip>
</div>
</template>
...@@ -3,4 +3,5 @@ ...@@ -3,4 +3,5 @@
#js-compliance-dashboard{ data: { merge_requests: @merge_requests.to_json, #js-compliance-dashboard{ data: { merge_requests: @merge_requests.to_json,
is_last_page: @last_page.to_json, is_last_page: @last_page.to_json,
empty_state_svg_path: image_path('illustrations/merge_requests.svg') } } empty_state_svg_path: image_path('illustrations/merge_requests.svg'),
merge_commits_csv_export_path: group_security_merge_commit_reports_path(@group, format: :csv) } }
---
title: Add Merge Commit CSV export button in Compliance Dashboard
merge_request: 38513
author:
type: added
...@@ -4,12 +4,20 @@ exports[`ComplianceDashboard component when there are merge requests and the sho ...@@ -4,12 +4,20 @@ exports[`ComplianceDashboard component when there are merge requests and the sho
<div <div
class="compliance-dashboard" class="compliance-dashboard"
> >
<header <header>
class="gl-my-5" <div
> class="gl-mt-5 d-flex"
<h4> >
Compliance Dashboard <h4
</h4> class="gl-flex-grow-1 gl-my-0"
>
Compliance Dashboard
</h4>
<merge-commits-export-button-stub
mergecommitscsvexportpath="/csv"
/>
</div>
<p> <p>
Here you will find recent merge request activity Here you will find recent merge request activity
...@@ -44,12 +52,20 @@ exports[`ComplianceDashboard component when there are merge requests matches the ...@@ -44,12 +52,20 @@ exports[`ComplianceDashboard component when there are merge requests matches the
<div <div
class="compliance-dashboard" class="compliance-dashboard"
> >
<header <header>
class="gl-my-5" <div
> class="gl-mt-5 d-flex"
<h4> >
Compliance Dashboard <h4
</h4> class="gl-flex-grow-1 gl-my-0"
>
Compliance Dashboard
</h4>
<merge-commits-export-button-stub
mergecommitscsvexportpath="/csv"
/>
</div>
<p> <p>
Here you will find recent merge request activity Here you will find recent merge request activity
......
...@@ -4,6 +4,7 @@ import { GlTabs, GlTab } from '@gitlab/ui'; ...@@ -4,6 +4,7 @@ import { GlTabs, GlTab } from '@gitlab/ui';
import ComplianceDashboard from 'ee/compliance_dashboard/components/dashboard.vue'; import ComplianceDashboard from 'ee/compliance_dashboard/components/dashboard.vue';
import MergeRequestGrid from 'ee/compliance_dashboard/components/merge_requests/grid.vue'; import MergeRequestGrid from 'ee/compliance_dashboard/components/merge_requests/grid.vue';
import MergeCommitsExportButton from 'ee/compliance_dashboard/components/merge_requests/merge_commits_export_button.vue';
import { COMPLIANCE_TAB_COOKIE_KEY } from 'ee/compliance_dashboard/constants'; import { COMPLIANCE_TAB_COOKIE_KEY } from 'ee/compliance_dashboard/constants';
import { createMergeRequests } from '../mock_data'; import { createMergeRequests } from '../mock_data';
...@@ -12,8 +13,10 @@ describe('ComplianceDashboard component', () => { ...@@ -12,8 +13,10 @@ describe('ComplianceDashboard component', () => {
const isLastPage = false; const isLastPage = false;
const mergeRequests = createMergeRequests({ count: 2 }); const mergeRequests = createMergeRequests({ count: 2 });
const mergeCommitsCsvExportPath = '/csv';
const findMergeRequestsGrid = () => wrapper.find(MergeRequestGrid); const findMergeRequestsGrid = () => wrapper.find(MergeRequestGrid);
const findMergeCommitsExportButton = () => wrapper.find(MergeCommitsExportButton);
const findDashboardTabs = () => wrapper.find(GlTabs); const findDashboardTabs = () => wrapper.find(GlTabs);
const createComponent = (props = {}) => { const createComponent = (props = {}) => {
...@@ -21,6 +24,7 @@ describe('ComplianceDashboard component', () => { ...@@ -21,6 +24,7 @@ describe('ComplianceDashboard component', () => {
propsData: { propsData: {
mergeRequests, mergeRequests,
isLastPage, isLastPage,
mergeCommitsCsvExportPath,
emptyStateSvgPath: 'empty.svg', emptyStateSvgPath: 'empty.svg',
...props, ...props,
}, },
...@@ -57,6 +61,10 @@ describe('ComplianceDashboard component', () => { ...@@ -57,6 +61,10 @@ describe('ComplianceDashboard component', () => {
expect(findMergeRequestsGrid().props('isLastPage')).toBe(isLastPage); expect(findMergeRequestsGrid().props('isLastPage')).toBe(isLastPage);
}); });
it('renders the merge commit export button', () => {
expect(findMergeCommitsExportButton().exists()).toBe(true);
});
describe('and the show tabs cookie is true', () => { describe('and the show tabs cookie is true', () => {
beforeEach(() => { beforeEach(() => {
Cookies.set(COMPLIANCE_TAB_COOKIE_KEY, true); Cookies.set(COMPLIANCE_TAB_COOKIE_KEY, true);
...@@ -86,4 +94,16 @@ describe('ComplianceDashboard component', () => { ...@@ -86,4 +94,16 @@ describe('ComplianceDashboard component', () => {
expect(findMergeRequestsGrid().exists()).toBe(false); expect(findMergeRequestsGrid().exists()).toBe(false);
}); });
}); });
describe('when the merge commit export link is not present', () => {
beforeEach(() => {
wrapper = createComponent({ mergeCommitsCsvExportPath: '' });
});
it('does not render the merge commit export button', () => {
return wrapper.vm.$nextTick().then(() => {
expect(findMergeCommitsExportButton().exists()).toBe(false);
});
});
});
}); });
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`MergeCommitsExportButton component Merge commit CSV export button matches the snapshot 1`] = `
<div>
<gl-button-stub
category="tertiary"
class="gl-align-self-center"
href="/merge_commit_reports"
icon="export"
size="medium"
variant="default"
>
List of all merge commits
</gl-button-stub>
<gl-tooltip-stub
boundary="viewport"
placement="top"
target="[object Object]"
>
<p
class="gl-my-0"
>
Export as CSV
</p>
<p
class="gl-my-0"
>
(max size 15 MB)
</p>
</gl-tooltip-stub>
</div>
`;
import { shallowMount } from '@vue/test-utils';
import { GlButton } from '@gitlab/ui';
import MergeCommitsExportButton from 'ee/compliance_dashboard/components/merge_requests/merge_commits_export_button.vue';
const CSV_EXPORT_PATH = '/merge_commit_reports';
describe('MergeCommitsExportButton component', () => {
let wrapper;
const findCsvExportButton = () => wrapper.find(GlButton);
const createComponent = (props = {}) => {
return shallowMount(MergeCommitsExportButton, {
propsData: {
mergeCommitsCsvExportPath: CSV_EXPORT_PATH,
...props,
},
});
};
beforeEach(() => {
wrapper = createComponent();
});
afterEach(() => {
wrapper.destroy();
});
describe('Merge commit CSV export button', () => {
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('renders the merge commits csv export button', () => {
expect(findCsvExportButton().exists()).toBe(true);
});
it('renders the export icon', () => {
expect(findCsvExportButton().props('icon')).toBe('export');
});
it('links to the csv download path', () => {
expect(findCsvExportButton().attributes('href')).toEqual(CSV_EXPORT_PATH);
});
});
});
...@@ -868,6 +868,9 @@ msgstr "" ...@@ -868,6 +868,9 @@ msgstr ""
msgid "(line: %{startLine})" msgid "(line: %{startLine})"
msgstr "" msgstr ""
msgid "(max size 15 MB)"
msgstr ""
msgid "(removed)" msgid "(removed)"
msgstr "" msgstr ""
...@@ -14387,6 +14390,9 @@ msgstr "" ...@@ -14387,6 +14390,9 @@ msgstr ""
msgid "List available repositories" msgid "List available repositories"
msgstr "" msgstr ""
msgid "List of all merge commits"
msgstr ""
msgid "List settings" msgid "List settings"
msgstr "" msgstr ""
......
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