mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-21 09:35:49 +02:00
Added possibility to export Parts from part tables
This commit is contained in:
parent
3b36b2a4dc
commit
49944cda87
9 changed files with 161 additions and 8 deletions
|
@ -107,6 +107,13 @@ export default class extends DatatablesController {
|
||||||
//Hide the select element (the tomselect button is the sibling of the select element)
|
//Hide the select element (the tomselect button is the sibling of the select element)
|
||||||
select_target.nextElementSibling.classList.add('d-none');
|
select_target.nextElementSibling.classList.add('d-none');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//If the selected option has a data-turbo attribute, set it to the form
|
||||||
|
if (selected_option.dataset.turbo) {
|
||||||
|
this.element.dataset.turbo = selected_option.dataset.turbo;
|
||||||
|
} else {
|
||||||
|
this.element.dataset.turbo = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
confirmDeletionAtSubmit(event) {
|
confirmDeletionAtSubmit(event) {
|
||||||
|
|
63
src/Controller/PartImportExportController.php
Normal file
63
src/Controller/PartImportExportController.php
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Services\ImportExportSystem\EntityExporter;
|
||||||
|
use App\Services\Parts\PartsTableActionHandler;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
class PartImportExportController extends AbstractController
|
||||||
|
{
|
||||||
|
private EntityManagerInterface $entityManager;
|
||||||
|
private PartsTableActionHandler $partsTableActionHandler;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $entityManager, PartsTableActionHandler $partsTableActionHandler)
|
||||||
|
{
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
$this->partsTableActionHandler = $partsTableActionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/parts/export", name="parts_export", methods={"GET"})
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function exportParts(Request $request, EntityExporter $entityExporter): Response
|
||||||
|
{
|
||||||
|
$ids = $request->query->get('ids', '');
|
||||||
|
$parts = $this->partsTableActionHandler->idStringToArray($ids);
|
||||||
|
|
||||||
|
if (empty($parts)) {
|
||||||
|
throw new \RuntimeException('No parts found!');
|
||||||
|
}
|
||||||
|
|
||||||
|
//Ensure that we have access to the parts
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
$this->denyAccessUnlessGranted('read', $part);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $entityExporter->exportEntityFromRequest($parts, $request);
|
||||||
|
}
|
||||||
|
}
|
|
@ -95,6 +95,25 @@ class SelectAPIController extends AbstractController
|
||||||
return $this->getResponseForClass(Project::class, false);
|
return $this->getResponseForClass(Project::class, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/export_level", name="select_export_level")
|
||||||
|
*/
|
||||||
|
public function exportLevel(): Response
|
||||||
|
{
|
||||||
|
$entries = [
|
||||||
|
1 => $this->translator->trans('export.level.simple'),
|
||||||
|
2 => $this->translator->trans('export.level.extended'),
|
||||||
|
3 => $this->translator->trans('export.level.full'),
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->json(array_map(function ($key, $value) {
|
||||||
|
return [
|
||||||
|
'text' => $value,
|
||||||
|
'value' => $key,
|
||||||
|
];
|
||||||
|
}, array_keys($entries), $entries));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/label_profiles", name="select_label_profiles")
|
* @Route("/label_profiles", name="select_label_profiles")
|
||||||
* @return Response
|
* @return Response
|
||||||
|
|
|
@ -52,7 +52,7 @@ class EntityExporter
|
||||||
$resolver->setDefault('format', 'csv');
|
$resolver->setDefault('format', 'csv');
|
||||||
$resolver->setAllowedValues('format', ['csv', 'json', 'xml', 'yaml']);
|
$resolver->setAllowedValues('format', ['csv', 'json', 'xml', 'yaml']);
|
||||||
|
|
||||||
$resolver->setDefault('csv_delimiter', ',');
|
$resolver->setDefault('csv_delimiter', ';');
|
||||||
$resolver->setAllowedTypes('csv_delimiter', 'string');
|
$resolver->setAllowedTypes('csv_delimiter', 'string');
|
||||||
|
|
||||||
$resolver->setDefault('level', 'extended');
|
$resolver->setDefault('level', 'extended');
|
||||||
|
|
|
@ -102,6 +102,34 @@ final class PartsTableActionHandler
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//When action starts with "export_" we have to redirect to the export controller
|
||||||
|
$matches = [];
|
||||||
|
if (preg_match('/^export_(json|yaml|xml|csv)$/', $action, $matches)) {
|
||||||
|
$ids = implode(',', array_map(static fn (Part $part) => $part->getID(), $selected_parts));
|
||||||
|
switch ($target_id) {
|
||||||
|
case 1:
|
||||||
|
default:
|
||||||
|
$level = 'simple';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
$level = 'extended';
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
$level = 'full';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return new RedirectResponse(
|
||||||
|
$this->urlGenerator->generate('parts_export', [
|
||||||
|
'format' => $matches[1],
|
||||||
|
'level' => $level,
|
||||||
|
'ids' => $ids,
|
||||||
|
'_redirect' => $redirect_url
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//Iterate over the parts and apply the action to it:
|
//Iterate over the parts and apply the action to it:
|
||||||
foreach ($selected_parts as $part) {
|
foreach ($selected_parts as $part) {
|
||||||
|
|
|
@ -63,6 +63,12 @@
|
||||||
<optgroup label="{% trans %}part_list.action.action.delete{% endtrans %}">
|
<optgroup label="{% trans %}part_list.action.action.delete{% endtrans %}">
|
||||||
<option {% if not is_granted('@parts.delete') %}disabled{% endif %} value="delete">{% trans %}part_list.action.action.delete{% endtrans %}</option>
|
<option {% if not is_granted('@parts.delete') %}disabled{% endif %} value="delete">{% trans %}part_list.action.action.delete{% endtrans %}</option>
|
||||||
</optgroup>
|
</optgroup>
|
||||||
|
<optgroup label="{% trans %}part_list.action.action.export{% endtrans %}">
|
||||||
|
<option {% if not is_granted('@parts.read') %}disabled{% endif %} value="export_json" data-url="{{ path('select_export_level')}}" data-turbo="false">{% trans %}part_list.action.export_json{% endtrans %}</option>
|
||||||
|
<option {% if not is_granted('@parts.read') %}disabled{% endif %} value="export_csv" data-url="{{ path('select_export_level')}}" data-turbo="false">{% trans %}part_list.action.export_csv{% endtrans %}</option>
|
||||||
|
<option {% if not is_granted('@parts.read') %}disabled{% endif %} value="export_yaml" data-url="{{ path('select_export_level')}}" data-turbo="false">{% trans %}part_list.action.export_yaml{% endtrans %}</option>
|
||||||
|
<option {% if not is_granted('@parts.read') %}disabled{% endif %} value="export_xml" data-url="{{ path('select_export_level')}}" data-turbo="false">{% trans %}part_list.action.export_xml{% endtrans %}</option>
|
||||||
|
</optgroup>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select class="form-select d-none" data-controller="elements--structural-entity-select" name="target" {{ stimulus_target('elements/datatables/parts', 'selectTargetPicker') }}>
|
<select class="form-select d-none" data-controller="elements--structural-entity-select" name="target" {{ stimulus_target('elements/datatables/parts', 'selectTargetPicker') }}>
|
||||||
|
|
|
@ -10970,34 +10970,64 @@ Element 3</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="Qt585vm" name="attachment.max_file_size">
|
<unit id="Qt585vm" name="attachment.max_file_size">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>attachment.max_file_size</source>
|
<source>attachment.max_file_size</source>
|
||||||
<target>Maximum file size</target>
|
<target>Maximum file size</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="tkkbiag" name="user.saml_user">
|
<unit id="tkkbiag" name="user.saml_user">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>user.saml_user</source>
|
<source>user.saml_user</source>
|
||||||
<target>SSO / SAML user</target>
|
<target>SSO / SAML user</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="fhepjKr" name="user.saml_user.pw_change_hint">
|
<unit id="fhepjKr" name="user.saml_user.pw_change_hint">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>user.saml_user.pw_change_hint</source>
|
<source>user.saml_user.pw_change_hint</source>
|
||||||
<target>Your user uses single sign-on (SSO). You can not change the password and 2FA settings here. Configure them on your central SSO provider instead!</target>
|
<target>Your user uses single sign-on (SSO). You can not change the password and 2FA settings here. Configure them on your central SSO provider instead!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="32beTBH" name="login.sso_saml_login">
|
<unit id="32beTBH" name="login.sso_saml_login">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>login.sso_saml_login</source>
|
<source>login.sso_saml_login</source>
|
||||||
<target>Single Sign-On Login (SSO)</target>
|
<target>Single Sign-On Login (SSO)</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="wnMLanX" name="login.local_login_hint">
|
<unit id="wnMLanX" name="login.local_login_hint">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>login.local_login_hint</source>
|
<source>login.local_login_hint</source>
|
||||||
<target>The form below is only for log in with a local user. If you want to log in via single sign-on, press the button above.</target>
|
<target>The form below is only for log in with a local user. If you want to log in via single sign-on, press the button above.</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="fa76Qc9" name="part_list.action.action.export">
|
||||||
|
<segment>
|
||||||
|
<source>part_list.action.action.export</source>
|
||||||
|
<target>Export parts</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="OfOI7tn" name="part_list.action.export_json">
|
||||||
|
<segment>
|
||||||
|
<source>part_list.action.export_json</source>
|
||||||
|
<target>Export to JSON</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="8Y5uz7l" name="part_list.action.export_csv">
|
||||||
|
<segment>
|
||||||
|
<source>part_list.action.export_csv</source>
|
||||||
|
<target>Export to CSV</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="gtllBTO" name="part_list.action.export_yaml">
|
||||||
|
<segment>
|
||||||
|
<source>part_list.action.export_yaml</source>
|
||||||
|
<target>Export to YAML</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="IW9wGBS" name="part_list.action.export_xml">
|
||||||
|
<segment>
|
||||||
|
<source>part_list.action.export_xml</source>
|
||||||
|
<target>Export to XML</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="Dpb9AmY" name="saml.error.cannot_login_local_user_per_saml">
|
<unit id="Dpb9AmY" name="saml.error.cannot_login_local_user_per_saml">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>saml.error.cannot_login_local_user_per_saml</source>
|
<source>saml.error.cannot_login_local_user_per_saml</source>
|
||||||
<target>You can not login as local user via SSO! Use your local user password instead.</target>
|
<target>You can not login as local user via SSO! Use your local user password instead.</target>
|
||||||
</segment>
|
</segment>
|
||||||
|
|
|
@ -300,7 +300,7 @@
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="m8kMFhf" name="validator.attachment.name_not_blank">
|
<unit id="m8kMFhf" name="validator.attachment.name_not_blank">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.attachment.name_not_blank</source>
|
<source>validator.attachment.name_not_blank</source>
|
||||||
<target>Set a value here, or upload a file to automatically use its filename as name for the attachment.</target>
|
<target>Set a value here, or upload a file to automatically use its filename as name for the attachment.</target>
|
||||||
</segment>
|
</segment>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue