Commit 93b4049a authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch '216279-add-source-and-destination-branch-data-to-compliance-dashboard' into 'master'

Add source and destination branch data to Compliance Dashboard

See merge request gitlab-org/gitlab!37628
parents 270f0a1b c5006455
<script>
import { GlLink, GlSprintf, GlTooltipDirective, GlTruncate } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
directives: {
GlTooltip: GlTooltipDirective,
},
components: {
GlLink,
GlSprintf,
GlTruncate,
},
props: {
sourceBranch: {
type: Object,
required: true,
},
targetBranch: {
type: Object,
required: true,
},
},
strings: {
branchDetails: __('%{sourceBranch} into %{targetBranch}'),
},
};
</script>
<template>
<div class="gl-display-flex gl-align-items-center gl-justify-content-end">
<gl-sprintf :message="this.$options.strings.branchDetails">
<template #sourceBranch>
<span class="gl-mr-2 gl-min-w-0">
<gl-link v-if="sourceBranch.uri" :href="targetBranch.uri" data-testid="source-branch-uri">
<gl-truncate
v-gl-tooltip
:title="sourceBranch.name"
:text="sourceBranch.name"
position="middle"
/>
</gl-link>
<gl-truncate
v-else
v-gl-tooltip
:title="sourceBranch.name"
:text="sourceBranch.name"
position="middle"
/>
</span>
</template>
<template #targetBranch>
<span class="gl-ml-2 gl-min-w-0">
<gl-link v-if="targetBranch.uri" :href="targetBranch.uri" data-testid="target-branch-uri">
<gl-truncate
v-gl-tooltip
:title="targetBranch.name"
:text="targetBranch.name"
position="middle"
/>
</gl-link>
<gl-truncate
v-else
v-gl-tooltip
:title="targetBranch.name"
:text="targetBranch.name"
position="middle"
/>
</span>
</template>
</gl-sprintf>
</div>
</template>
...@@ -7,6 +7,7 @@ import timeagoMixin from '~/vue_shared/mixins/timeago'; ...@@ -7,6 +7,7 @@ import timeagoMixin from '~/vue_shared/mixins/timeago';
import ApprovalStatus from './approval_status.vue'; import ApprovalStatus from './approval_status.vue';
import Approvers from './approvers.vue'; import Approvers from './approvers.vue';
import BranchDetails from './branch_details.vue';
import MergeRequest from './merge_request.vue'; import MergeRequest from './merge_request.vue';
import PipelineStatus from './pipeline_status.vue'; import PipelineStatus from './pipeline_status.vue';
import GridColumnHeading from '../shared/grid_column_heading.vue'; import GridColumnHeading from '../shared/grid_column_heading.vue';
...@@ -19,6 +20,7 @@ export default { ...@@ -19,6 +20,7 @@ export default {
components: { components: {
ApprovalStatus, ApprovalStatus,
Approvers, Approvers,
BranchDetails,
GridColumnHeading, GridColumnHeading,
MergeRequest, MergeRequest,
PipelineStatus, PipelineStatus,
...@@ -51,6 +53,9 @@ export default { ...@@ -51,6 +53,9 @@ export default {
hasStatus(status) { hasStatus(status) {
return !isEmpty(status); return !isEmpty(status);
}, },
hasBranchDetails(mergeRequest) {
return mergeRequest.target_branch && mergeRequest.source_branch;
},
}, },
strings: { strings: {
mergeRequestLabel: __('Merge Request'), mergeRequestLabel: __('Merge Request'),
...@@ -105,6 +110,17 @@ export default { ...@@ -105,6 +110,17 @@ export default {
class="gl-text-right gl-border-b-solid gl-border-b-1 gl-border-b-gray-100 gl-p-5 gl-relative" class="gl-text-right gl-border-b-solid gl-border-b-1 gl-border-b-gray-100 gl-p-5 gl-relative"
> >
<approvers :approvers="mergeRequest.approved_by_users" /> <approvers :approvers="mergeRequest.approved_by_users" />
<branch-details
v-if="hasBranchDetails(mergeRequest)"
:source-branch="{
name: mergeRequest.source_branch,
uri: mergeRequest.source_branch_uri,
}"
:target-branch="{
name: mergeRequest.target_branch,
uri: mergeRequest.target_branch_uri,
}"
/>
<span class="gl-text-gray-700"> <span class="gl-text-gray-700">
<time v-gl-tooltip.bottom="timeTooltip(mergeRequest.merged_at)">{{ <time v-gl-tooltip.bottom="timeTooltip(mergeRequest.merged_at)">{{
timeAgoString(mergeRequest.merged_at) timeAgoString(mergeRequest.merged_at)
......
...@@ -3,6 +3,6 @@ ...@@ -3,6 +3,6 @@
min-width: 550px; min-width: 550px;
.dashboard-grid { .dashboard-grid {
grid-template-columns: 1fr auto auto auto; grid-template-columns: 1fr auto auto 35%;
} }
} }
---
title: Add source and destination branch data to Compliance Dashboard
merge_request: 37628
author:
type: added
...@@ -49,6 +49,8 @@ exports[`MergeRequestsGrid component when intialized matches the snapshot 1`] = ...@@ -49,6 +49,8 @@ exports[`MergeRequestsGrid component when intialized matches the snapshot 1`] =
approvers="" approvers=""
/> />
<!---->
<span <span
class="gl-text-gray-700" class="gl-text-gray-700"
> >
...@@ -82,6 +84,8 @@ exports[`MergeRequestsGrid component when intialized matches the snapshot 1`] = ...@@ -82,6 +84,8 @@ exports[`MergeRequestsGrid component when intialized matches the snapshot 1`] =
approvers="" approvers=""
/> />
<!---->
<span <span
class="gl-text-gray-700" class="gl-text-gray-700"
> >
......
import { mount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui';
import BranchDetails from 'ee/compliance_dashboard/components/merge_requests/branch_details.vue';
describe('BranchDetails component', () => {
let wrapper;
// The truncate component adds left-to-right marks into the text that we have to remove
const getText = () => wrapper.text().replace(/\u200E/gi, '');
const linkExists = testId => wrapper.find(`[data-testid="${testId}"]`).exists();
const createComponent = ({ sourceUri = '', targetUri = '' } = {}) => {
return mount(BranchDetails, {
propsData: {
sourceBranch: {
name: 'feature',
uri: sourceUri,
},
targetBranch: {
name: 'master',
uri: targetUri,
},
},
});
};
afterEach(() => {
wrapper.destroy();
});
describe('with branch details', () => {
describe('and no branch URIs', () => {
beforeEach(() => {
wrapper = createComponent();
});
it('has no links', () => {
expect(wrapper.find(GlLink).exists()).toBe(false);
});
it('has the correct text', () => {
expect(getText()).toEqual('feature into master');
});
});
describe('and one branch URI', () => {
beforeEach(() => {
wrapper = createComponent({ targetUri: '/master-uri' });
});
it('has one link', () => {
expect(wrapper.findAll(GlLink)).toHaveLength(1);
});
it('has a link to the target branch', () => {
expect(linkExists('target-branch-uri')).toBe(true);
});
it('has the correct text', () => {
expect(getText()).toEqual('feature into master');
});
});
describe('and both branch URIs', () => {
beforeEach(() => {
wrapper = createComponent({ sourceUri: '/feature-uri', targetUri: '/master-uri' });
});
it('has two links', () => {
expect(wrapper.findAll(GlLink)).toHaveLength(2);
});
it('has a link to the source branch', () => {
expect(linkExists('source-branch-uri')).toBe(true);
});
it('has a link to the target branch', () => {
expect(linkExists('target-branch-uri')).toBe(true);
});
it('has the correct text', () => {
expect(getText()).toEqual('feature into master');
});
});
});
});
...@@ -2,9 +2,10 @@ import { shallowMount } from '@vue/test-utils'; ...@@ -2,9 +2,10 @@ import { shallowMount } from '@vue/test-utils';
import MergeRequestsGrid from 'ee/compliance_dashboard/components/merge_requests/grid.vue'; import MergeRequestsGrid from 'ee/compliance_dashboard/components/merge_requests/grid.vue';
import ApprovalStatus from 'ee/compliance_dashboard/components/merge_requests/approval_status.vue'; import ApprovalStatus from 'ee/compliance_dashboard/components/merge_requests/approval_status.vue';
import BranchDetails from 'ee/compliance_dashboard/components/merge_requests/branch_details.vue';
import PipelineStatus from 'ee/compliance_dashboard/components/merge_requests/pipeline_status.vue'; import PipelineStatus from 'ee/compliance_dashboard/components/merge_requests/pipeline_status.vue';
import Approvers from 'ee/compliance_dashboard/components/merge_requests/approvers.vue'; import Approvers from 'ee/compliance_dashboard/components/merge_requests/approvers.vue';
import { createMergeRequests } from '../../mock_data'; import { createMergeRequests, createPipelineStatus } from '../../mock_data';
describe('MergeRequestsGrid component', () => { describe('MergeRequestsGrid component', () => {
let wrapper; let wrapper;
...@@ -14,11 +15,12 @@ describe('MergeRequestsGrid component', () => { ...@@ -14,11 +15,12 @@ describe('MergeRequestsGrid component', () => {
const findApprovalStatus = () => wrapper.find(ApprovalStatus); const findApprovalStatus = () => wrapper.find(ApprovalStatus);
const findPipelineStatus = () => wrapper.find(PipelineStatus); const findPipelineStatus = () => wrapper.find(PipelineStatus);
const findApprovers = () => wrapper.find(Approvers); const findApprovers = () => wrapper.find(Approvers);
const findBranchDetails = () => wrapper.find(BranchDetails);
const createComponent = (options = {}) => { const createComponent = (mergeRequestProps = {}) => {
return shallowMount(MergeRequestsGrid, { return shallowMount(MergeRequestsGrid, {
propsData: { propsData: {
mergeRequests: createMergeRequests({ count: 2, options }), mergeRequests: createMergeRequests({ count: 2, props: mergeRequestProps }),
isLastPage: false, isLastPage: false,
}, },
stubs: { stubs: {
...@@ -53,7 +55,7 @@ describe('MergeRequestsGrid component', () => { ...@@ -53,7 +55,7 @@ describe('MergeRequestsGrid component', () => {
}); });
it('renders if there is an approval status', () => { it('renders if there is an approval status', () => {
wrapper = createComponent({ approvalStatus: 'success' }); wrapper = createComponent({ approval_status: 'success' });
expect(findApprovalStatus().exists()).toBe(true); expect(findApprovalStatus().exists()).toBe(true);
}); });
}); });
...@@ -64,11 +66,22 @@ describe('MergeRequestsGrid component', () => { ...@@ -64,11 +66,22 @@ describe('MergeRequestsGrid component', () => {
}); });
it('renders if there is a pipeline', () => { it('renders if there is a pipeline', () => {
wrapper = createComponent({ addPipeline: true }); wrapper = createComponent({ pipeline_status: createPipelineStatus('success') });
expect(findPipelineStatus().exists()).toBe(true); expect(findPipelineStatus().exists()).toBe(true);
}); });
}); });
describe('branch details', () => {
it('does not render if there are no branch details', () => {
expect(findBranchDetails().exists()).toBe(false);
});
it('renders if there are branch details', () => {
wrapper = createComponent({ target_branch: 'master', source_branch: 'feature' });
expect(findBranchDetails().exists()).toBe(true);
});
});
it('renders the approvers list', () => { it('renders the approvers list', () => {
expect(findApprovers().exists()).toBe(true); expect(findApprovers().exists()).toBe(true);
}); });
......
...@@ -13,7 +13,7 @@ const createUser = id => ({ ...@@ -13,7 +13,7 @@ const createUser = id => ({
web_url: `http://localhost:3000/user-${id}`, web_url: `http://localhost:3000/user-${id}`,
}); });
export const createMergeRequest = ({ id = 1, pipeline, approvers, approvalStatus } = {}) => { export const createMergeRequest = ({ id = 1, props } = {}) => {
const mergeRequest = { const mergeRequest = {
id, id,
approved_by_users: [], approved_by_users: [],
...@@ -26,19 +26,7 @@ export const createMergeRequest = ({ id = 1, pipeline, approvers, approvalStatus ...@@ -26,19 +26,7 @@ export const createMergeRequest = ({ id = 1, pipeline, approvers, approvalStatus
mergeRequest.author = createUser(id); mergeRequest.author = createUser(id);
if (pipeline) { return { ...mergeRequest, ...props };
mergeRequest.pipeline_status = pipeline;
}
if (approvers) {
mergeRequest.approved_by_users = approvers;
}
if (approvalStatus) {
mergeRequest.approval_status = approvalStatus;
}
return mergeRequest;
}; };
export const createPipelineStatus = status => ({ export const createPipelineStatus = status => ({
...@@ -59,14 +47,13 @@ export const createApprovers = count => { ...@@ -59,14 +47,13 @@ export const createApprovers = count => {
.map((_, id) => createUser(id)); .map((_, id) => createUser(id));
}; };
export const createMergeRequests = ({ count = 1, options = {} } = {}) => { export const createMergeRequests = ({ count = 1, props = {} } = {}) => {
return Array(count) return Array(count)
.fill() .fill()
.map((_, id) => .map((_, id) =>
createMergeRequest({ createMergeRequest({
id, id,
approvalStatus: options.approvalStatus, props,
pipeline: options.addPipeline ? createPipelineStatus('success') : null,
}), }),
); );
}; };
...@@ -670,6 +670,9 @@ msgstr "" ...@@ -670,6 +670,9 @@ msgstr ""
msgid "%{size} bytes" msgid "%{size} bytes"
msgstr "" msgstr ""
msgid "%{sourceBranch} into %{targetBranch}"
msgstr ""
msgid "%{spammable_titlecase} was submitted to Akismet successfully." msgid "%{spammable_titlecase} was submitted to Akismet successfully."
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