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