Skip to content
Snippets Groups Projects
Verified Commit c538bfd1 authored by Miranda Fluharty's avatar Miranda Fluharty
Browse files

Changes from feedback, disable when max selected

Disable the select all checkbox when the limit is reached
if no artifacts are selected on the current page
Rename isInArray to isSelected
Add tests for how checkbox interacts with limit
parent e2497045
No related branches found
No related tags found
1 merge request!118083Header checkbox should select visible artifacts
......@@ -9,6 +9,7 @@ import {
GlIcon,
GlPagination,
GlFormCheckbox,
GlTooltipDirective,
} from '@gitlab/ui';
import { createAlert } from '~/alert';
import { getIdFromGraphQLId, convertToGraphQLId } from '~/graphql_shared/utils';
......@@ -43,6 +44,7 @@ import {
I18N_BULK_DELETE_PARTIAL_ERROR,
I18N_BULK_DELETE_CONFIRMATION_TOAST,
SELECTED_ARTIFACTS_MAX_COUNT,
I18N_BULK_DELETE_MAX_SELECTED,
} from '../constants';
import JobCheckbox from './job_checkbox.vue';
import ArtifactsBulkDelete from './artifacts_bulk_delete.vue';
......@@ -78,6 +80,9 @@ export default {
ArtifactsTableRowDetails,
FeedbackBanner,
},
directives: {
GlTooltip: GlTooltipDirective,
},
mixins: [glFeatureFlagsMixin()],
inject: ['projectId', 'projectPath', 'canDestroyArtifacts'],
apollo: {
......@@ -178,6 +183,11 @@ export default {
),
);
},
selectAllTooltipText() {
return this.isSelectedArtifactsLimitReached && !this.isAnyVisibleArtifactSelected
? I18N_BULK_DELETE_MAX_SELECTED
: '';
},
},
methods: {
refetchArtifacts() {
......@@ -219,11 +229,11 @@ export default {
}
},
selectArtifact(artifactNode, checked) {
const isInArray = this.selectedArtifacts.includes(artifactNode.id);
const isSelected = this.selectedArtifacts.includes(artifactNode.id);
if (checked && !isInArray && !this.isSelectedArtifactsLimitReached) {
if (checked && !isSelected && !this.isSelectedArtifactsLimitReached) {
this.selectedArtifacts.push(artifactNode.id);
} else if (isInArray) {
} else if (isSelected) {
this.selectedArtifacts.splice(this.selectedArtifacts.indexOf(artifactNode.id), 1);
}
},
......@@ -388,8 +398,11 @@ export default {
</template>
<template v-if="canBulkDestroyArtifacts" #head(checkbox)>
<gl-form-checkbox
v-gl-tooltip.right
:title="selectAllTooltipText"
:checked="isAnyVisibleArtifactSelected"
:indeterminate="isAnyVisibleArtifactSelected && !areAllVisibleArtifactsSelected"
:disabled="isSelectedArtifactsLimitReached && !isAnyVisibleArtifactSelected"
@change="handleSelectAllChecked"
/>
</template>
......
......@@ -84,6 +84,8 @@ describe('JobArtifactsTable component', () => {
const findSelectAllCheckboxChecked = () => findSelectAllCheckbox().find('input').element.checked;
const findSelectAllCheckboxIndeterminate = () =>
findSelectAllCheckbox().find('input').element.indeterminate;
const findSelectAllCheckboxDisabled = () =>
findSelectAllCheckbox().find('input').element.disabled;
const toggleSelectAllCheckbox = () =>
findSelectAllCheckbox().vm.$emit('change', !findSelectAllCheckboxChecked());
......@@ -133,12 +135,16 @@ describe('JobArtifactsTable component', () => {
},
});
const maxSelectedArtifacts = new Array(SELECTED_ARTIFACTS_MAX_COUNT).fill({});
const allArtifacts = getJobArtifactsResponse.data.project.jobs.nodes
.map((jobNode) => jobNode.artifacts.nodes.map((artifactNode) => artifactNode.id))
.reduce((artifacts, jobArtifacts) => artifacts.concat(jobArtifacts));
const maxSelectedArtifacts = new Array(SELECTED_ARTIFACTS_MAX_COUNT).fill('artifact-id');
const maxSelectedArtifactsIncludingCurrentPage = [
...allArtifacts,
...new Array(SELECTED_ARTIFACTS_MAX_COUNT - allArtifacts.length).fill('artifact-id'),
];
const createComponent = ({
handlers = {
getJobArtifactsQuery: jest.fn().mockResolvedValue(getJobArtifactsResponse),
......@@ -666,32 +672,107 @@ describe('JobArtifactsTable component', () => {
});
});
describe('when the selected artifacts limit is reached', () => {
beforeEach(async () => {
createComponent({
canDestroyArtifacts: true,
glFeatures: { [BULK_DELETE_FEATURE_FLAG]: true },
data: { selectedArtifacts: maxSelectedArtifacts },
describe('select all checkbox respects selected artifacts limit', () => {
describe('when selecting all visible artifacts would exceed the limit', () => {
const selectedArtifactsLength = SELECTED_ARTIFACTS_MAX_COUNT - 1;
beforeEach(async () => {
createComponent({
canDestroyArtifacts: true,
glFeatures: { [BULK_DELETE_FEATURE_FLAG]: true },
data: {
selectedArtifacts: new Array(selectedArtifactsLength).fill('artifact-id'),
},
});
await nextTick();
});
await nextTick();
});
it('selects only up to the limit', async () => {
expect(findSelectAllCheckboxChecked()).toBe(false);
expect(findBulkDelete().props('selectedArtifacts')).toHaveLength(selectedArtifactsLength);
toggleSelectAllCheckbox();
await nextTick();
it('passes isSelectedArtifactsLimitReached to bulk delete', () => {
expect(findBulkDelete().props('isSelectedArtifactsLimitReached')).toBe(true);
expect(findSelectAllCheckboxChecked()).toBe(true);
expect(findBulkDelete().props('selectedArtifacts')).toHaveLength(
SELECTED_ARTIFACTS_MAX_COUNT,
);
expect(findBulkDelete().props('selectedArtifacts')).not.toContain(
allArtifacts[allArtifacts.length - 1],
);
});
});
it('passes isSelectedArtifactsLimitReached to job checkbox', () => {
expect(wrapper.findComponent(JobCheckbox).props('isSelectedArtifactsLimitReached')).toBe(
true,
);
describe('when limit has been reached without artifacts on the current page', () => {
beforeEach(async () => {
createComponent({
canDestroyArtifacts: true,
glFeatures: { [BULK_DELETE_FEATURE_FLAG]: true },
data: { selectedArtifacts: maxSelectedArtifacts },
});
await nextTick();
});
it('passes isSelectedArtifactsLimitReached to bulk delete', () => {
expect(findBulkDelete().props('isSelectedArtifactsLimitReached')).toBe(true);
});
it('passes isSelectedArtifactsLimitReached to job checkbox', () => {
expect(wrapper.findComponent(JobCheckbox).props('isSelectedArtifactsLimitReached')).toBe(
true,
);
});
it('passes isSelectedArtifactsLimitReached to table row details', async () => {
findCount().trigger('click');
await nextTick();
expect(findDetailsInRow(1).props('isSelectedArtifactsLimitReached')).toBe(true);
});
it('disables the select all checkbox', () => {
expect(findSelectAllCheckboxDisabled()).toBe(true);
});
});
it('passes isSelectedArtifactsLimitReached to table row details', async () => {
findCount().trigger('click');
await nextTick();
describe('when limit has been reached including artifacts on the current page', () => {
beforeEach(async () => {
createComponent({
canDestroyArtifacts: true,
glFeatures: { [BULK_DELETE_FEATURE_FLAG]: true },
data: {
selectedArtifacts: maxSelectedArtifactsIncludingCurrentPage,
},
});
await nextTick();
});
describe('the select all checkbox', () => {
it('is checked', () => {
expect(findSelectAllCheckboxChecked()).toBe(true);
expect(findSelectAllCheckboxIndeterminate()).toBe(false);
});
it('deselects all artifacts when toggled', async () => {
expect(findBulkDelete().props('selectedArtifacts')).toHaveLength(
SELECTED_ARTIFACTS_MAX_COUNT,
);
toggleSelectAllCheckbox();
expect(findDetailsInRow(1).props('isSelectedArtifactsLimitReached')).toBe(true);
await nextTick();
expect(findSelectAllCheckboxChecked()).toBe(false);
expect(findBulkDelete().props('selectedArtifacts')).toHaveLength(
SELECTED_ARTIFACTS_MAX_COUNT - allArtifacts.length,
);
});
});
});
});
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment