diff --git a/src/Glpi/Controller/Form/Import/Step2PreviewController.php b/src/Glpi/Controller/Form/Import/Step2PreviewController.php index c817c680ce5..ab29a4031f8 100644 --- a/src/Glpi/Controller/Form/Import/Step2PreviewController.php +++ b/src/Glpi/Controller/Form/Import/Step2PreviewController.php @@ -39,6 +39,7 @@ use Glpi\Form\Export\Serializer\FormSerializer; use Glpi\Form\Form; use Session; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; @@ -54,10 +55,37 @@ public function __invoke(Request $request): Response } $json = $this->getJsonFormFromRequest($request); - $serializer = new FormSerializer(); - $mapper = new DatabaseMapper(Session::getActiveEntities()); + $replacements = $request->request->all()["replacements"] ?? []; + return $this->previewResponse($json, $replacements); + } + + #[Route("/Form/Import/Remove", name: "glpi_form_import_remove", methods: "POST")] + public function removeForm(Request $request): Response + { + if (!Form::canCreate()) { + throw new AccessDeniedHttpException(); + } + + $json = $this->getJsonFormFromRequest($request); + $form_name = $request->request->get('remove_form_name'); $replacements = $request->request->all()["replacements"] ?? []; + + $serializer = new FormSerializer(); + $json = $serializer->removeFormFromJson($json, $form_name); + + // If all forms have been removed, redirect to the first step + if (!$serializer->isFormsInJson($json)) { + return new RedirectResponse('/Form/Import'); + } + + return $this->previewResponse($json, $replacements); + } + + private function previewResponse(string $json, array $replacements): Response + { + $serializer = new FormSerializer(); + $mapper = new DatabaseMapper(Session::getActiveEntities()); foreach ($replacements as $itemtype => $replacements_for_itemtype) { foreach ($replacements_for_itemtype as $original_name => $items_id) { $mapper->addMappedItem($itemtype, $original_name, $items_id); diff --git a/src/Glpi/Form/Export/Serializer/FormSerializer.php b/src/Glpi/Form/Export/Serializer/FormSerializer.php index 81b3ffb8d9f..697d34bf971 100644 --- a/src/Glpi/Form/Export/Serializer/FormSerializer.php +++ b/src/Glpi/Form/Export/Serializer/FormSerializer.php @@ -61,6 +61,19 @@ public function getVersion(): int return 1; } + public function isFormsInJson(string $json): bool + { + $export_specification = $this->deserialize($json); + + // Validate version + if ($export_specification->version !== $this->getVersion()) { + throw new InvalidArgumentException("Unsupported version"); + } + + // Check if the forms list is empty + return !empty($export_specification->forms); + } + /** @param array
$forms */ public function exportFormsToJson(array $forms): ExportResult { @@ -132,6 +145,19 @@ public function resolveIssues( return $results; } + public function removeFormFromJson(string $json, string $form_name): string + { + $export_specification = $this->deserialize($json); + + // Filter the forms to remove the one that matches the given name + $export_specification->forms = array_filter( + $export_specification->forms, + fn($form_spec) => $form_spec->name !== $form_name + ); + + return $this->serialize($export_specification); + } + public function importFormsFromJson( string $json, DatabaseMapper $mapper, diff --git a/templates/pages/admin/form/import/step2_preview.html.twig b/templates/pages/admin/form/import/step2_preview.html.twig index 52e232c1fe0..73c18a7bcab 100644 --- a/templates/pages/admin/form/import/step2_preview.html.twig +++ b/templates/pages/admin/form/import/step2_preview.html.twig @@ -53,43 +53,74 @@ {{ __("Form name") }} {{ __("Status") }} - {{ __("Action") }} + {{ _n('Action', 'Actions', 2) }} - {% for forms_name in preview.getValidForms() %} + {% macro render_row(forms_name, status_icon, status_text, show_resolve_issues_action, show_remove_action) %} - {{ forms_name }} - + {{ forms_name }} +
- - {{ __("Ready to be imported") }} + + {{ status_text }}
- + + {% if show_resolve_issues_action or show_remove_action %} +
+ {% if show_remove_action %} + + {% endif %} + + {% if show_resolve_issues_action and show_remove_action %} + + {% endif %} + + {% if show_resolve_issues_action %} + + {% endif %} +
+ {% endif %} + + {% endmacro %} + + {% for forms_name in preview.getValidForms() %} + {{ _self.render_row( + forms_name, + 'ti-check text-success', + __("Ready to be imported"), + false, + true + ) }} {% endfor %} {% for forms_name in preview.getInvalidForms() %} - - {{ forms_name }} - -
- - {{ __("Can't be imported") }} -
- - - - - + {{ _self.render_row( + forms_name, + 'ti-x text-danger', + __("Can't be imported"), + true, + true + ) }} {% endfor %} diff --git a/tests/cypress/e2e/form/serializer/import.cy.js b/tests/cypress/e2e/form/serializer/import.cy.js index cee259e47d2..741d083b780 100644 --- a/tests/cypress/e2e/form/serializer/import.cy.js +++ b/tests/cypress/e2e/form/serializer/import.cy.js @@ -51,11 +51,13 @@ describe ('Import forms', () => { cy.findByText("My valid form").should('exist'); cy.findByText("Ready to be imported").should('exist'); cy.findByRole("button", {'name': "Resolve issues"}).should('not.exist'); + cy.findByRole("button", {'name': "Remove form"}).should('exist'); }); cy.get("@preview").eq(2).within(() => { cy.findByText("My invalid form").should('exist'); cy.findByText("Can't be imported").should('exist'); cy.findByRole("button", {'name': "Resolve issues"}).should('exist'); + cy.findByRole("button", {'name': "Remove form"}).should('exist'); }); // Step 4: import @@ -88,10 +90,12 @@ describe ('Import forms', () => { cy.findByText("My valid form").should('exist'); cy.findByText("Ready to be imported").should('exist'); cy.findByRole("button", {'name': "Resolve issues"}).should('not.exist'); + cy.findByRole("button", {'name': "Remove form"}).should('exist'); }); cy.get("@preview").eq(2).within(() => { cy.findByText("My invalid form").should('exist'); cy.findByText("Can't be imported").should('exist'); + cy.findByRole("button", {'name': "Remove form"}).should('exist'); cy.findByRole("button", {'name': "Resolve issues"}).should('exist').click(); }); @@ -111,11 +115,13 @@ describe ('Import forms', () => { cy.findByText("My valid form").should('exist'); cy.findByText("Ready to be imported").should('exist'); cy.findByRole("button", {'name': "Resolve issues"}).should('not.exist'); + cy.findByRole("button", {'name': "Remove form"}).should('exist'); }); cy.get("@preview").eq(2).within(() => { cy.findByText("My invalid form").should('exist'); cy.findByText("Ready to be imported").should('exist'); cy.findByRole("button", {'name': "Resolve issues"}).should('not.exist'); + cy.findByRole("button", {'name': "Remove form"}).should('exist'); }); // Step 4: import @@ -134,4 +140,39 @@ describe ('Import forms', () => { cy.findByRole('link', {'name': "Import another file"}).click(); cy.findByLabelText("Select your file").should('exist'); }); + + it('can remove forms from the import list', () => { + // Step 1: file selection + cy.visit('/front/form/form.php'); + cy.findByRole('button', {'name': "Import forms"}).click(); + cy.findByLabelText("Select your file").selectFile("fixtures/export-of-2-forms.json"); + + // Step 2: preview + cy.findByRole('button', {'name': "Preview import"}).click(); + cy.findAllByRole('row').as('preview'); + cy.get("@preview").eq(1).within(() => { + cy.findByText("My valid form").should('exist'); + cy.findByText("Ready to be imported").should('exist'); + cy.findByRole("button", {'name': "Resolve issues"}).should('not.exist'); + cy.findByRole("button", {'name': "Remove form"}).should('exist'); + }); + cy.get("@preview").eq(2).within(() => { + cy.findByText("My invalid form").should('exist'); + cy.findByText("Can't be imported").should('exist'); + cy.findByRole("button", {'name': "Resolve issues"}).should('exist'); + cy.findByRole("button", {'name': "Remove form"}).should('exist'); + }); + + // Remove the second form + cy.get("@preview").eq(2).findByRole("button", {'name': "Remove form"}).click(); + cy.get("@preview").eq(1).should('exist'); + cy.get("@preview").eq(2).should('not.exist'); + + // Remove the first form + cy.get("@preview").eq(1).findByRole("button", {'name': "Remove form"}).click(); + cy.get("@preview").should('not.exist'); + + // Check if we are back to the first step + cy.findByLabelText("Select your file").should('exist'); + }); });