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 {
<template>
<div>
<div class="security-dashboard-filters gl-mt-7">
<vulnerability-filters
:filters="$options.filtersToShow"
class="security-dashboard-filters gl-mt-7"
@filters-changed="updateGraphqlFilters"
/>
<portal-target name="vulnerability-report-sticky" />
</div>
<vulnerability-list-graphql
:query="$options.projectVulnerabilitiesQuery"
......
......@@ -241,14 +241,18 @@ export default {
</script>
<template>
<div class="vulnerability-list">
<div>
<portal to="vulnerability-report-sticky">
<selection-summary
:selected-vulnerabilities="Object.values(selectedVulnerabilities)"
:visible="shouldShowSelectionSummary"
@cancel-selection="deselectAllVulnerabilities"
@vulnerability-updated="deselectVulnerability"
/>
</portal>
<gl-table
class="vulnerability-list"
:busy="isLoading"
:fields="displayFields"
:items="vulnerabilities"
......@@ -269,7 +273,7 @@ export default {
>
<template #head(checkbox)>
<gl-form-checkbox
class="gl-m-0"
class="gl-display-table-cell"
data-testid="vulnerability-checkbox-all"
:checked="hasSelectedAllVulnerabilities"
@change="toggleAllVulnerabilities"
......@@ -278,7 +282,7 @@ export default {
<template #cell(checkbox)="{ item }">
<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"
:checked="isSelected(item)"
@change="toggleVulnerability(item)"
......
<script>
import { PortalTarget } from 'portal-vue';
import { DASHBOARD_TYPES } from 'ee/security_dashboard/store/constants';
import VulnerabilityCounts from './vulnerability_counts.vue';
import VulnerabilityListGraphql from './vulnerability_list_graphql.vue';
......@@ -16,6 +17,7 @@ export default {
VulnerabilityCounts,
VulnerabilityListGraphql,
VulnerabilityFilters,
PortalTarget,
},
inject: ['dashboardType'],
props: {
......@@ -80,11 +82,10 @@ export default {
@counts-changed="emitCountsChanged"
/>
<vulnerability-filters
:filters="filtersToShow"
class="security-dashboard-filters gl-mt-7"
@filters-changed="updateGraphqlFilters"
/>
<div class="security-dashboard-filters gl-mt-7">
<vulnerability-filters :filters="filtersToShow" @filters-changed="updateGraphqlFilters" />
<portal-target name="vulnerability-report-sticky" />
</div>
<vulnerability-list-graphql
class="gl-mt-6"
......
$security-filter-height: 90px;
$security-filter-height: 85px;
$selection-summary-height: 66px;
$selection-summary-with-error-height: 118px;
......@@ -25,7 +25,9 @@ $selection-summary-with-error-height: 118px;
.checkbox {
@include gl-pl-4;
@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,
+ th {
......@@ -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),
// the property is assigned to the th element as a workaround
.selection-summary,
thead th {
@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 sticky-top-positioning($security-filter-height);
}
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 {
......
@import 'page_bundles/mixins_and_variables_and_functions';
@import '../components/vulnerability_list';
@import '../components/generic_vulnerability_report';
.vulnerabilities-row {
......
......@@ -2,11 +2,20 @@
exports[`Agent vulnerability report component renders 1`] = `
<div>
<vulnerability-filters-stub
<div
class="security-dashboard-filters gl-mt-7"
>
<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
fields="[object Object],[object Object],[object Object],[object Object],,[object Object]"
filters="[object Object]"
......
import { GlSkeletonLoading, GlTable, GlTruncate } from '@gitlab/ui';
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 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';
......@@ -28,6 +29,9 @@ describe('Vulnerability list component', () => {
},
stubs: {
GlPopover: true,
Portal: {
template: '<div><slot></slot></div>',
},
...stubs,
},
listeners,
......@@ -143,6 +147,10 @@ describe('Vulnerability list component', () => {
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', () => {
expect(findSelectionSummary().props('visible')).toBe(false);
});
......
import { nextTick } from 'vue';
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 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';
......@@ -38,6 +39,7 @@ describe('Vulnerability report component', () => {
const findVulnerabilityCounts = () => wrapper.findComponent(VulnerabilityCounts);
const findVulnerabilityFilters = () => wrapper.findComponent(VulnerabilityFilters);
const findVulnerabilityListGraphql = () => wrapper.findComponent(VulnerabilityListGraphql);
const findPortalTarget = () => wrapper.findComponent(PortalTarget);
afterEach(() => {
wrapper.destroy();
......@@ -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