Skip to content

Commit

Permalink
feat(forms): Add possibility to remove forms from import list
Browse files Browse the repository at this point in the history
  • Loading branch information
ccailly committed Oct 14, 2024
1 parent cf9270b commit 33b3e74
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 29 deletions.
32 changes: 30 additions & 2 deletions src/Glpi/Controller/Form/Import/Step2PreviewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
26 changes: 26 additions & 0 deletions src/Glpi/Form/Export/Serializer/FormSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<Form> $forms */
public function exportFormsToJson(array $forms): ExportResult
{
Expand Down Expand Up @@ -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,
Expand Down
85 changes: 58 additions & 27 deletions templates/pages/admin/form/import/step2_preview.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -53,43 +53,74 @@
<tr>
<th class="w-50 px-4">{{ __("Form name") }}</th>
<th class="w-25 px-4">{{ __("Status") }}</th>
<th class="w-25 px-4">{{ __("Action") }}</th>
<th class="w-25 px-4">{{ _n('Action', 'Actions', 2) }}</th>
</tr>
</thead>
<tbody>
{% for forms_name in preview.getValidForms() %}
{% macro render_row(forms_name, status_icon, status_text, show_resolve_issues_action, show_remove_action) %}
<tr>
<td class="w-50 px-4">{{ forms_name }}</td>
<td class="w-50 px-4">
<td class="w-50 px-4 align-middle">{{ forms_name }}</td>
<td class="w-50 px-4 align-middle">
<div class="d-flex align-items-center">
<i class="ti ti-check text-success me-2"></i>
<span>{{ __("Ready to be imported") }}</span>
<i class="ti {{ status_icon }} me-2"></i>
<span>{{ status_text }}</span>
</div>
</td>
<td></td>
<td class="w-25 px-4 align-middle">
{% if show_resolve_issues_action or show_remove_action %}
<div class="d-flex flex-row-reverse align-items-center gap-2">
{% if show_remove_action %}
<button
type="submit"
class="btn btn-link p-0 text-danger"
name="remove_form_name"
value="{{ forms_name }}"
formaction="{{ path('Form/Import/Remove') }}"
title="{{ __('Remove this form from the import list') }}"
aria-label="{{ __('Remove form') }}"
>
<i class="ti ti-trash"></i>
</button>
{% endif %}

{% if show_resolve_issues_action and show_remove_action %}
<span class="vr"></span>
{% endif %}

{% if show_resolve_issues_action %}
<button
type="submit"
class="btn btn-link p-0"
name="form_name"
value="{{ forms_name }}"
formaction="{{ path('Form/Import/ResolveIssues') }}"
>
{{ __("Resolve issues") }}
</button>
{% endif %}
</div>
{% endif %}
</td>
</tr>
{% 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() %}
<tr>
<td class="w-50 px-4">{{ forms_name }}</td>
<td class="w-25 px-4">
<div class="d-flex align-items-center">
<i class="ti ti-x text-danger me-2"></i>
<span>{{ __("Can't be imported") }}</span>
</div>
</td>
<td class="w-25 px-4">
<button
type="submit"
class="btn btn-link p-0"
name="form_name"
value="{{ forms_name }}"
formaction="{{ path('Form/Import/ResolveIssues') }}"
>
{{ __("Resolve issues") }}
</button>
</td>
</tr>
{{ _self.render_row(
forms_name,
'ti-x text-danger',
__("Can't be imported"),
true,
true
) }}
{% endfor %}
</tbody>
</table>
Expand Down
41 changes: 41 additions & 0 deletions tests/cypress/e2e/form/serializer/import.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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();
});

Expand All @@ -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
Expand All @@ -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');
});
});

0 comments on commit 33b3e74

Please sign in to comment.