From 0e35252a54c58beb8c4a9b5de2bb168afda973be Mon Sep 17 00:00:00 2001 From: Simon Knox <simon@gitlab.com> Date: Tue, 11 Mar 2025 04:34:43 +1100 Subject: [PATCH] Fix archived view of custom field settings --- .../settings/work_items/custom_field_form.vue | 15 ++++++++++ .../work_items/custom_fields_list.vue | 22 +++++++++++---- .../work_items/custom_field_form_spec.js | 28 +++++++++++++++++++ .../work_items/custom_fields_list_spec.js | 14 ++++++++++ 4 files changed, 73 insertions(+), 6 deletions(-) diff --git a/ee/app/assets/javascripts/groups/settings/work_items/custom_field_form.vue b/ee/app/assets/javascripts/groups/settings/work_items/custom_field_form.vue index 029ae1b44de87..c8bf70b427b1e 100644 --- a/ee/app/assets/javascripts/groups/settings/work_items/custom_field_form.vue +++ b/ee/app/assets/javascripts/groups/settings/work_items/custom_field_form.vue @@ -170,6 +170,19 @@ export default { option.value.trim(), ); }, + resetForm() { + this.formData = { + fieldType: FIELD_TYPE_OPTIONS[0].value, + fieldName: '', + workItemTypes: [], + selectOptions: [{ value: '' }], + }; + this.formState = { + fieldName: null, + selectOptions: null, + }; + this.mutationError = ''; + }, async saveCustomField() { if (!this.validateForm()) { return; @@ -211,6 +224,7 @@ export default { this.$emit(this.isEditing ? 'updated' : 'created'); this.visible = false; + this.resetForm(); } catch (error) { Sentry.captureException(error); this.mutationError = @@ -311,6 +325,7 @@ export default { v-model="formData.fieldName" width="md" :state="formState.fieldName" + autocomplete="off" @input="validateFieldName" /> </gl-form-group> diff --git a/ee/app/assets/javascripts/groups/settings/work_items/custom_fields_list.vue b/ee/app/assets/javascripts/groups/settings/work_items/custom_fields_list.vue index 45a6244dbb3ef..f73e8b0ed47d8 100644 --- a/ee/app/assets/javascripts/groups/settings/work_items/custom_fields_list.vue +++ b/ee/app/assets/javascripts/groups/settings/work_items/custom_fields_list.vue @@ -54,6 +54,9 @@ export default { ? s__('WorkItem|Active custom fields') : s__('WorkItem|Archived custom fields'); }, + archiveButtonIcon() { + return this.showActive ? 'archive' : 'redo'; + }, }, apollo: { customFields: { @@ -104,7 +107,7 @@ export default { return null; }, archiveButtonText(item) { - return item.active + return this.showActive ? sprintf(s__('WorkItem|Archive %{itemName}'), { itemName: item.name }) : sprintf(s__('WorkItem|Unarchive %{itemName}'), { itemName: item.name }); }, @@ -272,10 +275,15 @@ export default { data-testid="table-title" > {{ titleText }} - <gl-badge v-if="!isLoading" class="gl-mx-4"> - <!-- eslint-disable-next-line @gitlab/vue-require-i18n-strings --> - {{ customFields.count }}/50 - </gl-badge> + <template v-if="!isLoading"> + <gl-badge v-if="showActive" class="gl-mx-4"> + <!-- eslint-disable-next-line @gitlab/vue-require-i18n-strings --> + {{ customFields.count }}/50 + </gl-badge> + <gl-badge v-else class="gl-mx-4"> + {{ customFields.count }} + </gl-badge> + </template> <custom-field-form class="gl-ml-auto" @created="$apollo.queries.customFields.refetch()" /> </div> @@ -324,14 +332,16 @@ export default { <template #cell(actions)="{ item }"> <div class="gl-align-items-center gl-end gl-flex gl-justify-end gl-gap-1"> <custom-field-form + v-if="showActive" :custom-field-id="item.id" :custom-field-name="item.name" + data-testid="editButton" @updated="$apollo.queries.customFields.refetch()" /> <gl-button v-gl-tooltip="archiveButtonText(item)" :aria-label="archiveButtonText(item)" - icon="archive" + :icon="archiveButtonIcon" category="tertiary" data-testid="archiveButton" @click="archiveCustomField(item.id)" diff --git a/ee/spec/frontend/groups/settings/work_items/custom_field_form_spec.js b/ee/spec/frontend/groups/settings/work_items/custom_field_form_spec.js index 782c431c1d652..ecd707afcfdd4 100644 --- a/ee/spec/frontend/groups/settings/work_items/custom_field_form_spec.js +++ b/ee/spec/frontend/groups/settings/work_items/custom_field_form_spec.js @@ -158,6 +158,10 @@ describe('CustomFieldForm', () => { findToggleModalButton().vm.$emit('click'); }); + it('has autocomplete disabled on the name field', () => { + expect(findFieldNameInput().attributes('autocomplete')).toBe('off'); + }); + it.each(['SINGLE_SELECT', 'MULTI_SELECT'])( `shows select options section when field type is %s`, async (type) => { @@ -334,6 +338,30 @@ describe('CustomFieldForm', () => { expect(Sentry.captureException).toHaveBeenCalled(); }); + + it('resets form after successful creation', async () => { + const createFieldHandler = jest.fn().mockResolvedValue(mockCreateFieldResponse); + createComponent({ createFieldHandler }); + + await findToggleModalButton().vm.$emit('click'); + + findFieldTypeSelect().vm.$emit('input', 'TEXT'); + findFieldNameInput().vm.$emit('input', 'Test Field'); + findWorkItemTypeListbox().vm.$emit('select', [mockWorkItemTypes[2].id]); + + await nextTick(); + + findSaveCustomFieldButton().vm.$emit('click'); + await waitForPromises(); + + await findToggleModalButton().vm.$emit('click'); + await waitForPromises(); + + expect(findFieldTypeSelect().attributes('value')).toBe('SINGLE_SELECT'); + expect(findFieldNameInput().props('value')).toBe(''); + expect(findWorkItemTypeListbox().props('selected')).toEqual([]); + expect(findWorkItemTypeListbox().props('toggleText')).toBe('Select types'); + }); }); describe('edit mode', () => { diff --git a/ee/spec/frontend/groups/settings/work_items/custom_fields_list_spec.js b/ee/spec/frontend/groups/settings/work_items/custom_fields_list_spec.js index 578616f5b5b05..bb6c5ce9b47f7 100644 --- a/ee/spec/frontend/groups/settings/work_items/custom_fields_list_spec.js +++ b/ee/spec/frontend/groups/settings/work_items/custom_fields_list_spec.js @@ -63,6 +63,7 @@ describe('CustomFieldsTable', () => { }); const findTableItems = () => wrapper.findAll('tbody tr'); + const findEditButton = () => wrapper.find('[data-testid="editButton"]'); const findArchiveButton = () => wrapper.find('[data-testid="archiveButton"]'); const findDetailsButton = () => wrapper.find('[data-testid="toggleDetailsButton"'); const findAlert = () => wrapper.find('[data-testid="alert"]'); @@ -178,6 +179,19 @@ describe('CustomFieldsTable', () => { expect(timeagoComponents.exists()).toBe(true); expect(timeagoComponents.at(0).props('time')).toBe(selectField.updatedAt); }); + + it('shows archive icon and edit button for active fields', () => { + expect(findArchiveButton().props('icon')).toBe('archive'); + expect(findEditButton().exists()).toBe(true); + }); + + it('shows redo icon and no edit button for archived fields', async () => { + await findArchivedFilterButton().vm.$emit('click'); + await waitForPromises(); + + expect(findArchiveButton().props('icon')).toBe('redo'); + expect(findEditButton().exists()).toBe(false); + }); }); it('refetches list after create-custom-field emits created', async () => { -- GitLab