diff --git a/src/Glpi/Form/QuestionType/QuestionTypeItem.php b/src/Glpi/Form/QuestionType/QuestionTypeItem.php index 71ae08d7436..bc92e9c5577 100644 --- a/src/Glpi/Form/QuestionType/QuestionTypeItem.php +++ b/src/Glpi/Form/QuestionType/QuestionTypeItem.php @@ -308,6 +308,7 @@ public function getSubTypeDefaultValue(?Question $question): ?string #[Override] public function renderAdministrationTemplate(?Question $question): string { + $default_itemtype = $this->getDefaultValueItemtype($question); $twig = TemplateRenderer::getInstance(); return $twig->render( 'pages/admin/form/question_type/item/administration_template.html.twig', @@ -315,11 +316,12 @@ public function renderAdministrationTemplate(?Question $question): string 'init' => $question != null, 'question' => $question, 'question_type' => $this::class, - 'default_itemtype' => $this->getDefaultValueItemtype($question), + 'default_itemtype' => $default_itemtype, 'default_items_id' => $this->getDefaultValueItemId($question), 'itemtypes' => $this->getAllowedItemtypes(), 'aria_label' => $this->items_id_aria_label, 'advanced_config' => $this->renderAdvancedConfigurationTemplate($question), + 'displaywith' => $this->getDisplayWith($default_itemtype), ] ); } @@ -355,16 +357,24 @@ public function renderAdvancedConfigurationTemplate(?Question $question): string ); } - #[Override] - public function renderEndUserTemplate(Question $question): string + /** + * Compute the list of additional fields to display alongside item names in dropdowns. + * + * @param string|null $itemtype The itemtype to compute displaywith for. + * @return array + */ + public function getDisplayWith(?string $itemtype): array { global $CFG_GLPI; - $itemtype = $this->getDefaultValueItemtype($question) ?? '0'; + if ($itemtype === null || $itemtype === '0') { + return []; + } + + $displaywith = []; $is_itil_type = in_array($itemtype, $CFG_GLPI['itil_types']); $id_already_visible = isset($_SESSION['glpiis_ids_visible']) && $_SESSION['glpiis_ids_visible']; - $displaywith = []; if ($is_itil_type && !$id_already_visible) { $displaywith[] = 'id'; } @@ -372,18 +382,27 @@ public function renderEndUserTemplate(Question $question): string if (in_array($itemtype, $CFG_GLPI['asset_types'])) { $item = getItemForItemtype($itemtype); if ($item) { - if ($item->isField('serial')) { - $displaywith[] = 'serial'; - } if ($item->isField('otherserial')) { $displaywith[] = 'otherserial'; } + if ($item->isField('serial')) { + $displaywith[] = 'serial'; + } if ($item->isField('users_id')) { $displaywith[] = 'users_id'; } } } + return $displaywith; + } + + #[Override] + public function renderEndUserTemplate(Question $question): string + { + $itemtype = $this->getDefaultValueItemtype($question) ?? '0'; + $displaywith = $this->getDisplayWith($itemtype); + $twig = TemplateRenderer::getInstance(); return $twig->render( 'pages/admin/form/question_type/item/end_user_template.html.twig', diff --git a/templates/pages/admin/form/question_type/item/administration_template.html.twig b/templates/pages/admin/form/question_type/item/administration_template.html.twig index e2733a212bf..21942a02b77 100644 --- a/templates/pages/admin/form/question_type/item/administration_template.html.twig +++ b/templates/pages/admin/form/question_type/item/administration_template.html.twig @@ -36,26 +36,33 @@
{# Define empty choice manually to handle root entity #} + {% set dropdown_options = { + 'init' : init, + 'no_label' : true, + 'right' : 'all', + 'width' : '100%', + 'mb' : '', + 'comments' : false, + 'addicon' : false, + 'aria_label' : aria_label, + 'nochecklimit' : true, + 'display_emptychoice': false, + 'toadd' : { + '-1': constant('Dropdown::EMPTY_VALUE'), + }, + } %} + + {# Display additional fields in dropdown: IDs for ITIL objects, serial/user for assets #} + {% if displaywith is not empty %} + {% set dropdown_options = dropdown_options|merge({'displaywith': displaywith}) %} + {% endif %} + {{ fields.dropdownField( default_itemtype|default(itemtypes|first|first), 'default_value', default_items_id, '', - { - 'init' : init, - 'no_label' : true, - 'right' : 'all', - 'width' : '100%', - 'mb' : '', - 'comments' : false, - 'addicon' : false, - 'aria_label' : aria_label, - 'nochecklimit' : true, - 'display_emptychoice': false, - 'toadd' : { - '-1': constant('Dropdown::EMPTY_VALUE'), - }, - } + dropdown_options ) }} {{ advanced_config|raw }}
diff --git a/tests/e2e/pages/FormPage.ts b/tests/e2e/pages/FormPage.ts index b1c557088b7..7eaa78f0e72 100644 --- a/tests/e2e/pages/FormPage.ts +++ b/tests/e2e/pages/FormPage.ts @@ -111,6 +111,26 @@ export class FormPage extends GlpiPage ); } + public async setSubQuestionType(question: Locator, type: string): Promise + { + await this.doSetDropdownValue( + this.getDropdownByLabel('Question sub type', question) + .filter({visible : true}), + type, + false + ); + } + + public async setItemTypeForItemQuestion(question: Locator, item_type: string): Promise + { + await this.doSetDropdownValue( + this.getDropdownByLabel('Select an itemtype', question) + .filter({visible : true}), + item_type, + false + ); + } + public async addComment(name: string): Promise { await this.getButton("Add a comment").click(); diff --git a/tests/e2e/specs/Form/QuestionTypes/item.spec.ts b/tests/e2e/specs/Form/QuestionTypes/item.spec.ts new file mode 100644 index 00000000000..ff62d5dea46 --- /dev/null +++ b/tests/e2e/specs/Form/QuestionTypes/item.spec.ts @@ -0,0 +1,98 @@ +/** + * --------------------------------------------------------------------- + * + * GLPI - Gestionnaire Libre de Parc Informatique + * + * http://glpi-project.org + * + * @copyright 2015-2026 Teclib' and contributors. + * @licence https://www.gnu.org/licenses/gpl-3.0.html + * + * --------------------------------------------------------------------- + * + * LICENSE + * + * This file is part of GLPI. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * --------------------------------------------------------------------- + */ + +import { test, expect } from '../../../fixtures/glpi_fixture'; +import { FormPage } from '../../../pages/FormPage'; +import { Profiles } from '../../../utils/Profiles'; +import { getWorkerEntityId } from '../../../utils/WorkerEntities'; + +test.describe('Item form question type', () => { + let form: FormPage; + let form_id: number; + let entity_id: number; + + test.beforeEach(async ({ page, profile, entity, api, formImporter }) => { + await profile.set(Profiles.SuperAdmin); + form = new FormPage(page); + + // Create new entity + entity_id = await api.createItem('Entity', { + name: `Entity ${Date.now()}`, + entities_id: getWorkerEntityId(), + }); + + // Switch to the new entity and refresh session to ensure the new entity is taken into account in the session + entity.switchToWithoutRecursion(entity_id); + api.refreshSession(); + + const info = await formImporter.importForm('question_types/item-editor-test.json'); + form_id = info.getId(); + await form.goto(form_id); + + }); + + test.afterEach(async ({ entity, api }) => { + // Reset entity to default one to avoid issues with other tests in the same worker + entity.resetToDefaultWorkerEntity(); + api.refreshSession(); + }); + + test('Adding new item option and compare select option labels', async ({ api }) => { + // Add two computers + await api.createItem('Computer', { + name: 'Computer 1', + entities_id: entity_id + }); + await api.createItem('Computer', { + name: 'Computer 2', + entities_id: entity_id, + serial: '123456', + otherserial: '654321' + }); + + const persisted_question = form.getLastQuestion(); + await persisted_question.click({ position: { x: 0, y: 0 } }); + + form.getDropdownByLabel('Select an item', persisted_question).click(); + await expect(form.page.getByRole('option', { name: 'Computer 1' })).toBeVisible(); + await expect(form.page.getByRole('option', { name: 'Computer 2 - 654321 - 123456' })).toBeVisible(); + + const new_question = await form.addQuestion('Item question'); + await form.setQuestionType(new_question, 'Item'); + await form.setSubQuestionType(new_question, 'GLPI Objects'); + await form.setItemTypeForItemQuestion(new_question, 'Computers'); + + form.getDropdownByLabel('Select an item', new_question).click(); + await expect(form.page.getByRole('option', { name: 'Computer 1' })).toBeVisible(); + await expect(form.page.getByRole('option', { name: 'Computer 2 - 654321 - 123456' })).toBeVisible(); + }); +}); diff --git a/tests/fixtures/forms/question_types/item-editor-test.json b/tests/fixtures/forms/question_types/item-editor-test.json new file mode 100644 index 00000000000..f079d8b1fd3 --- /dev/null +++ b/tests/fixtures/forms/question_types/item-editor-test.json @@ -0,0 +1,77 @@ +{ + "version": 1, + "forms": [ + { + "id": 1, + "uuid": "dd000001-0001-0001-0001-000000000001", + "name": "Tests form for the item form question type suite", + "header": null, + "description": null, + "entity_name": "Root entity", + "is_recursive": true, + "is_active": false, + "submit_button_visibility_strategy": "always_visible", + "illustration": "", + "submit_button_conditions": [], + "sections": [ + { + "id": 1, + "uuid": "dd000001-0001-0001-0001-000000000010", + "name": "First section", + "description": null, + "rank": 0, + "visibility_strategy": "always_visible", + "conditions": [] + } + ], + "comments": [], + "questions": [ + { + "id": 1, + "uuid": "dd000001-0001-0001-0001-000000000100", + "name": "Test item question", + "type": "Glpi\\Form\\QuestionType\\QuestionTypeItem", + "is_mandatory": false, + "vertical_rank": 0, + "horizontal_rank": null, + "description": "", + "default_value": "", + "extra_data": { + "root_items_id": "0", + "subtree_depth": "0", + "selectable_tree_root": "0", + "itemtype": "Computer" + }, + "section_id": 1, + "visibility_strategy": "always_visible", + "validation_strategy": "no_validation", + "conditions": [], + "validation_conditions": [] + } + ], + "policies": [ + { + "strategy": "Glpi\\Form\\AccessControl\\ControlType\\AllowList", + "config": { + "user_ids": [ + "all" + ], + "group_ids": [], + "profile_ids": [] + }, + "is_active": true + } + ], + "destinations": [], + "translations": [], + "data_requirements": [ + { + "itemtype": "Entity", + "name": "Root entity" + } + ], + "custom_types_requirements": [], + "plugin_requirements": [] + } + ] +} \ No newline at end of file