Commit f6084e65 authored by Daniel Tian's avatar Daniel Tian Committed by Savas Vedova

Fix bulk select dropdown layering

parent aa0eb491
...@@ -61,11 +61,13 @@ export default { ...@@ -61,11 +61,13 @@ export default {
<template> <template>
<div> <div>
<vulnerability-filters <div class="security-dashboard-filters gl-mt-7">
:filters="$options.filtersToShow" <vulnerability-filters
class="security-dashboard-filters gl-mt-7" :filters="$options.filtersToShow"
@filters-changed="updateGraphqlFilters" @filters-changed="updateGraphqlFilters"
/> />
<portal-target name="vulnerability-report-sticky" />
</div>
<vulnerability-list-graphql <vulnerability-list-graphql
:query="$options.projectVulnerabilitiesQuery" :query="$options.projectVulnerabilitiesQuery"
......
...@@ -241,14 +241,18 @@ export default { ...@@ -241,14 +241,18 @@ export default {
</script> </script>
<template> <template>
<div class="vulnerability-list"> <div>
<selection-summary <portal to="vulnerability-report-sticky">
:selected-vulnerabilities="Object.values(selectedVulnerabilities)" <selection-summary
:visible="shouldShowSelectionSummary" :selected-vulnerabilities="Object.values(selectedVulnerabilities)"
@cancel-selection="deselectAllVulnerabilities" :visible="shouldShowSelectionSummary"
@vulnerability-updated="deselectVulnerability" @cancel-selection="deselectAllVulnerabilities"
/> @vulnerability-updated="deselectVulnerability"
/>
</portal>
<gl-table <gl-table
class="vulnerability-list"
:busy="isLoading" :busy="isLoading"
:fields="displayFields" :fields="displayFields"
:items="vulnerabilities" :items="vulnerabilities"
...@@ -269,7 +273,7 @@ export default { ...@@ -269,7 +273,7 @@ export default {
> >
<template #head(checkbox)> <template #head(checkbox)>
<gl-form-checkbox <gl-form-checkbox
class="gl-m-0" class="gl-display-table-cell"
data-testid="vulnerability-checkbox-all" data-testid="vulnerability-checkbox-all"
:checked="hasSelectedAllVulnerabilities" :checked="hasSelectedAllVulnerabilities"
@change="toggleAllVulnerabilities" @change="toggleAllVulnerabilities"
...@@ -278,7 +282,7 @@ export default { ...@@ -278,7 +282,7 @@ export default {
<template #cell(checkbox)="{ item }"> <template #cell(checkbox)="{ item }">
<gl-form-checkbox <gl-form-checkbox
class="gl-display-inline-block! gl-m-0 gl-pointer-events-none" class="gl-pointer-events-none gl-display-table-cell"
data-testid="vulnerability-checkbox" data-testid="vulnerability-checkbox"
:checked="isSelected(item)" :checked="isSelected(item)"
@change="toggleVulnerability(item)" @change="toggleVulnerability(item)"
......
<script> <script>
import { PortalTarget } from 'portal-vue';
import { DASHBOARD_TYPES } from 'ee/security_dashboard/store/constants'; import { DASHBOARD_TYPES } from 'ee/security_dashboard/store/constants';
import VulnerabilityCounts from './vulnerability_counts.vue'; import VulnerabilityCounts from './vulnerability_counts.vue';
import VulnerabilityListGraphql from './vulnerability_list_graphql.vue'; import VulnerabilityListGraphql from './vulnerability_list_graphql.vue';
...@@ -16,6 +17,7 @@ export default { ...@@ -16,6 +17,7 @@ export default {
VulnerabilityCounts, VulnerabilityCounts,
VulnerabilityListGraphql, VulnerabilityListGraphql,
VulnerabilityFilters, VulnerabilityFilters,
PortalTarget,
}, },
inject: ['dashboardType'], inject: ['dashboardType'],
props: { props: {
...@@ -80,11 +82,10 @@ export default { ...@@ -80,11 +82,10 @@ export default {
@counts-changed="emitCountsChanged" @counts-changed="emitCountsChanged"
/> />
<vulnerability-filters <div class="security-dashboard-filters gl-mt-7">
:filters="filtersToShow" <vulnerability-filters :filters="filtersToShow" @filters-changed="updateGraphqlFilters" />
class="security-dashboard-filters gl-mt-7" <portal-target name="vulnerability-report-sticky" />
@filters-changed="updateGraphqlFilters" </div>
/>
<vulnerability-list-graphql <vulnerability-list-graphql
class="gl-mt-6" class="gl-mt-6"
......
$security-filter-height: 90px; $security-filter-height: 85px;
$selection-summary-height: 66px; $selection-summary-height: 66px;
$selection-summary-with-error-height: 118px; $selection-summary-with-error-height: 118px;
...@@ -25,7 +25,9 @@ $selection-summary-with-error-height: 118px; ...@@ -25,7 +25,9 @@ $selection-summary-with-error-height: 118px;
.checkbox { .checkbox {
@include gl-pl-4; @include gl-pl-4;
@include gl-pr-0; @include gl-pr-0;
width: 1px; // Width needs to be something other than auto for the column to shrink down to the content
// width. The actual value doesn't matter as long as it's less than the content.
width: 0;
+ td, + td,
+ th { + th {
...@@ -64,16 +66,18 @@ $selection-summary-with-error-height: 118px; ...@@ -64,16 +66,18 @@ $selection-summary-with-error-height: 118px;
// Due to position: sticky not being supported on Chrome (https://caniuse.com/#feat=css-sticky), // Due to position: sticky not being supported on Chrome (https://caniuse.com/#feat=css-sticky),
// the property is assigned to the th element as a workaround // the property is assigned to the th element as a workaround
.selection-summary,
thead th { thead th {
@include gl-sticky; @include gl-sticky;
// Some input elements have a z-index of "1" so we need to place this higher // The checkboxes use z-index: 1, so we need to place the headers higher so that the checkboxes
// don't show on top of the headers when scrolling down.
@include gl-z-index-2; @include gl-z-index-2;
@include sticky-top-positioning($security-filter-height); @include sticky-top-positioning($security-filter-height);
} }
thead th { thead th {
box-shadow: 0 1px $gray-100; // Need to use an inset box-shadow here for the bottom border because position: sticky will hide
// any borders once the table headers become sticky.
box-shadow: inset 0 -1px $gray-100;
} }
thead.below-selection-summary th { thead.below-selection-summary th {
......
@import 'page_bundles/mixins_and_variables_and_functions'; @import 'page_bundles/mixins_and_variables_and_functions';
@import '../components/vulnerability_list';
@import '../components/generic_vulnerability_report'; @import '../components/generic_vulnerability_report';
.vulnerabilities-row { .vulnerabilities-row {
......
...@@ -2,10 +2,19 @@ ...@@ -2,10 +2,19 @@
exports[`Agent vulnerability report component renders 1`] = ` exports[`Agent vulnerability report component renders 1`] = `
<div> <div>
<vulnerability-filters-stub <div
class="security-dashboard-filters gl-mt-7" class="security-dashboard-filters gl-mt-7"
filters="[object Object],[object Object],[object Object]" >
/> <vulnerability-filters-stub
filters="[object Object],[object Object],[object Object]"
/>
<portal-target-stub
name="vulnerability-report-sticky"
slotprops="[object Object]"
tag="div"
/>
</div>
<vulnerability-list-graphql-stub <vulnerability-list-graphql-stub
fields="[object Object],[object Object],[object Object],[object Object],,[object Object]" fields="[object Object],[object Object],[object Object],[object Object],,[object Object]"
......
import { GlSkeletonLoading, GlTable, GlTruncate } from '@gitlab/ui'; import { GlSkeletonLoading, GlTable, GlTruncate } from '@gitlab/ui';
import { capitalize } from 'lodash'; import { capitalize } from 'lodash';
import { Portal } from 'portal-vue';
import DashboardHasNoVulnerabilities from 'ee/security_dashboard/components/shared/empty_states/dashboard_has_no_vulnerabilities.vue'; import DashboardHasNoVulnerabilities from 'ee/security_dashboard/components/shared/empty_states/dashboard_has_no_vulnerabilities.vue';
import FiltersProducedNoResults from 'ee/security_dashboard/components/shared/empty_states/filters_produced_no_results.vue'; import FiltersProducedNoResults from 'ee/security_dashboard/components/shared/empty_states/filters_produced_no_results.vue';
import IssuesBadge from 'ee/security_dashboard/components/shared/issues_badge.vue'; import IssuesBadge from 'ee/security_dashboard/components/shared/issues_badge.vue';
...@@ -28,6 +29,9 @@ describe('Vulnerability list component', () => { ...@@ -28,6 +29,9 @@ describe('Vulnerability list component', () => {
}, },
stubs: { stubs: {
GlPopover: true, GlPopover: true,
Portal: {
template: '<div><slot></slot></div>',
},
...stubs, ...stubs,
}, },
listeners, listeners,
...@@ -143,6 +147,10 @@ describe('Vulnerability list component', () => { ...@@ -143,6 +147,10 @@ describe('Vulnerability list component', () => {
expect(cells.at(3).text()).toBe(''); expect(cells.at(3).text()).toBe('');
}); });
it('should portal the selection summary to the expected portal', () => {
expect(wrapper.find(Portal).attributes('to')).toBe('vulnerability-report-sticky');
});
it('should not show the selection summary if no vulnerabilities are selected', () => { it('should not show the selection summary if no vulnerabilities are selected', () => {
expect(findSelectionSummary().props('visible')).toBe(false); expect(findSelectionSummary().props('visible')).toBe(false);
}); });
......
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { PortalTarget } from 'portal-vue';
import VulnerabilityListGraphql from 'ee/security_dashboard/components/shared/vulnerability_report/vulnerability_list_graphql.vue'; import VulnerabilityListGraphql from 'ee/security_dashboard/components/shared/vulnerability_report/vulnerability_list_graphql.vue';
import VulnerabilityReport from 'ee/security_dashboard/components/shared/vulnerability_report/vulnerability_report.vue'; import VulnerabilityReport from 'ee/security_dashboard/components/shared/vulnerability_report/vulnerability_report.vue';
import VulnerabilityCounts from 'ee/security_dashboard/components/shared/vulnerability_report/vulnerability_counts.vue'; import VulnerabilityCounts from 'ee/security_dashboard/components/shared/vulnerability_report/vulnerability_counts.vue';
...@@ -38,6 +39,7 @@ describe('Vulnerability report component', () => { ...@@ -38,6 +39,7 @@ describe('Vulnerability report component', () => {
const findVulnerabilityCounts = () => wrapper.findComponent(VulnerabilityCounts); const findVulnerabilityCounts = () => wrapper.findComponent(VulnerabilityCounts);
const findVulnerabilityFilters = () => wrapper.findComponent(VulnerabilityFilters); const findVulnerabilityFilters = () => wrapper.findComponent(VulnerabilityFilters);
const findVulnerabilityListGraphql = () => wrapper.findComponent(VulnerabilityListGraphql); const findVulnerabilityListGraphql = () => wrapper.findComponent(VulnerabilityListGraphql);
const findPortalTarget = () => wrapper.findComponent(PortalTarget);
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
...@@ -117,4 +119,11 @@ describe('Vulnerability report component', () => { ...@@ -117,4 +119,11 @@ describe('Vulnerability report component', () => {
}, },
); );
}); });
describe('sticky portal', () => {
it('has the portal target with the expected name', () => {
createWrapper();
expect(findPortalTarget().props('name')).toBe('vulnerability-report-sticky');
});
});
}); });
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