Commit 1c3f6164 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch...

Merge branch '350162-add-view-details-button-to-stacked-table-to-open-the-drawer-on-small-screens' into 'master'

Add view details button to compliance report for small displays

See merge request gitlab-org/gitlab!78072
parents 4bd9a354 61abf570
<script>
import { GlAlert, GlLoadingIcon, GlTable, GlLink, GlKeysetPagination } from '@gitlab/ui';
import { GlAlert, GlButton, GlLoadingIcon, GlTable, GlLink, GlKeysetPagination } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import { s__, __ } from '~/locale';
import { thWidthClass, sortObjectToString, sortStringToObject } from '~/lib/utils/table_utility';
......@@ -21,6 +21,7 @@ export default {
name: 'ComplianceReport',
components: {
GlAlert,
GlButton,
GlLoadingIcon,
GlTable,
GlLink,
......@@ -114,14 +115,17 @@ export default {
this.updateUrlQuery({ ...this.urlQuery, sort: this.sortParam });
},
toggleDrawer(rows) {
const { id, mergeRequest, project } = rows[0] || {};
const { mergeRequest, project } = rows[0] || {};
if (!mergeRequest || (this.showDrawer && id === this.drawerMergeRequest.id)) {
if (!mergeRequest || this.isCurrentDrawer(mergeRequest)) {
this.closeDrawer();
} else {
this.openDrawer(mergeRequest, project);
}
},
isCurrentDrawer(mergeRequest) {
return this.showDrawer && mergeRequest.id === this.drawerMergeRequest.id;
},
openDrawer(mergeRequest, project) {
this.showDrawer = true;
this.drawerMergeRequest = mergeRequest;
......@@ -180,6 +184,12 @@ export default {
thClass: thWidthClass(20),
sortable: true,
},
{
key: 'viewDetails',
label: '',
thClass: 'gl-display-none',
tdClass: 'gl-md-display-none view-details',
},
],
i18n: {
heading: __('Compliance report'),
......@@ -191,6 +201,7 @@ export default {
learnMore: __('Learn more.'),
prev: __('Prev'),
next: __('Next'),
viewDetailsBtn: __('View details'),
},
documentationPath: helpPagePath('user/compliance/compliance_report/index.md', {
anchor: 'approval-status-and-separation-of-duties',
......@@ -243,6 +254,7 @@ export default {
select-mode="single"
hover
selected-variant="primary"
class="compliance-report-table"
thead-class="gl-border-b-solid gl-border-b-1 gl-border-b-gray-100"
@row-selected="toggleDrawer"
@sort-changed="handleSortChanged"
......@@ -262,6 +274,11 @@ export default {
<template #table-busy>
<gl-loading-icon size="lg" color="dark" class="gl-my-5" />
</template>
<template #cell(viewDetails)="{ item }">
<gl-button class="gl-mb-0" block @click="toggleDrawer([item])">
{{ $options.i18n.viewDetailsBtn }}
</gl-button>
</template>
</gl-table>
<div v-if="showPagination" class="gl-display-flex gl-justify-content-center">
<gl-keyset-pagination
......
......@@ -3,3 +3,18 @@
max-width: 11rem;
}
}
.compliance-report-table {
.view-details {
background-color: $gray-10;
div {
width: 100% !important;
padding: 0 !important;
}
}
tr:hover .view-details {
background-color: transparent;
}
}
import { GlAlert, GlLoadingIcon, GlTable, GlLink, GlKeysetPagination } from '@gitlab/ui';
import { GlAlert, GlButton, GlLoadingIcon, GlTable, GlLink, GlKeysetPagination } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import Vue, { nextTick } from 'vue';
......@@ -58,8 +58,17 @@ describe('ComplianceReport component', () => {
findViolationsTable().findAll('tbody > tr').at(0).findAll('td');
const findSelectedRows = () => findViolationsTable().findAll('tr.b-table-row-selected');
const findRow = (idx) => {
return findViolationsTable().findAll('tbody > tr').at(idx);
};
const selectRow = async (idx) => {
await findViolationsTable().findAll('tbody > tr').at(idx).trigger('click');
await findRow(idx).trigger('click');
await nextTick();
};
const viewDetails = async (idx) => {
await findRow(idx).find(GlButton).trigger('click');
await nextTick();
};
......@@ -206,7 +215,13 @@ describe('ComplianceReport component', () => {
it('has the correct table headers', () => {
const headerTexts = findTableHeaders().wrappers.map((h) => h.text());
expect(headerTexts).toStrictEqual(['Severity', 'Violation', 'Merge request', 'Date merged']);
expect(headerTexts).toStrictEqual([
'Severity',
'Violation',
'Merge request',
'Date merged',
'',
]);
});
it('has the correct first row data', () => {
......@@ -217,6 +232,7 @@ describe('ComplianceReport component', () => {
'Approved by committer',
'Officiis architecto voluptas ut sit qui qui quisquam sequi consectetur porro.',
'in 1 year',
'View details',
]);
});
......@@ -247,23 +263,8 @@ describe('ComplianceReport component', () => {
});
describe('with the merge request drawer', () => {
it('opens the drawer', async () => {
const drawerData = mapViolations(mockResolver().mergeRequestViolations.nodes)[0];
await selectRow(0);
expect(findMergeRequestDrawer().props('showDrawer')).toBe(true);
expect(findMergeRequestDrawer().props('mergeRequest')).toStrictEqual(
stripTypenames(drawerData.mergeRequest),
);
expect(findMergeRequestDrawer().props('project')).toStrictEqual(
stripTypenames(drawerData.project),
);
});
it('closes the drawer via the drawer close event', async () => {
await selectRow(0);
expect(findSelectedRows()).toHaveLength(1);
await findMergeRequestDrawer().vm.$emit('close');
......@@ -273,31 +274,48 @@ describe('ComplianceReport component', () => {
expect(findMergeRequestDrawer().props('project')).toStrictEqual({});
});
it('closes the drawer via the row-selected event', async () => {
await selectRow(0);
describe.each`
rowAction | eventDescription
${viewDetails} | ${'view details button is clicked'}
${selectRow} | ${'row is selected'}
`('when a $eventDescription', ({ rowAction, eventDescription }) => {
it('opens then drawer', async () => {
const drawerData = mapViolations(mockResolver().mergeRequestViolations.nodes)[0];
expect(findSelectedRows()).toHaveLength(1);
await rowAction(0);
await selectRow(0);
expect(findMergeRequestDrawer().props('showDrawer')).toBe(true);
expect(findMergeRequestDrawer().props('mergeRequest')).toStrictEqual(
stripTypenames(drawerData.mergeRequest),
);
expect(findMergeRequestDrawer().props('project')).toStrictEqual(
stripTypenames(drawerData.project),
);
});
expect(findMergeRequestDrawer().props('showDrawer')).toBe(false);
expect(findMergeRequestDrawer().props('mergeRequest')).toStrictEqual({});
expect(findMergeRequestDrawer().props('project')).toStrictEqual({});
});
it(`closes the drawer when the same ${eventDescription} again`, async () => {
await rowAction(0);
await rowAction(0);
it('swaps the drawer when a new row is selected', async () => {
const drawerData = mapViolations(mockResolver().mergeRequestViolations.nodes)[1];
expect(findMergeRequestDrawer().props('showDrawer')).toBe(false);
expect(findMergeRequestDrawer().props('mergeRequest')).toStrictEqual({});
expect(findMergeRequestDrawer().props('project')).toStrictEqual({});
});
await selectRow(0);
await selectRow(1);
it(`swaps the drawer when another ${eventDescription}`, async () => {
const drawerData = mapViolations(mockResolver().mergeRequestViolations.nodes)[1];
expect(findMergeRequestDrawer().props('showDrawer')).toBe(true);
expect(findMergeRequestDrawer().props('mergeRequest')).toStrictEqual(
stripTypenames(drawerData.mergeRequest),
);
expect(findMergeRequestDrawer().props('project')).toStrictEqual(
stripTypenames(drawerData.project),
);
await rowAction(0);
await rowAction(1);
expect(findMergeRequestDrawer().props('showDrawer')).toBe(true);
expect(findMergeRequestDrawer().props('mergeRequest')).toStrictEqual(
stripTypenames(drawerData.mergeRequest),
);
expect(findMergeRequestDrawer().props('project')).toStrictEqual(
stripTypenames(drawerData.project),
);
});
});
});
......
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