mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-23 02:09:03 +02:00
Added a page to quickly add many parts to a project from parts lists.
This commit is contained in:
parent
345fb0a3c1
commit
25494c9ddf
7 changed files with 157 additions and 3 deletions
|
@ -77,7 +77,7 @@ class PartListsController extends AbstractController
|
|||
$this->addFlash('error', 'part.table.actions.no_params_given');
|
||||
} else {
|
||||
$parts = $actionHandler->idStringToArray($ids);
|
||||
$actionHandler->handleAction($action, $parts, $target ? (int) $target : null);
|
||||
$redirectResponse = $actionHandler->handleAction($action, $parts, $target ? (int) $target : null, $redirect);
|
||||
|
||||
//Save changes
|
||||
$this->entityManager->flush();
|
||||
|
@ -85,6 +85,11 @@ class PartListsController extends AbstractController
|
|||
$this->addFlash('success', 'part.table.actions.success');
|
||||
}
|
||||
|
||||
//If the action handler returned a response, we use it, otherwise we redirect back to the previous page.
|
||||
if ($redirectResponse){
|
||||
return $redirectResponse;
|
||||
}
|
||||
|
||||
return $this->redirect($redirect);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,18 @@
|
|||
namespace App\Controller;
|
||||
|
||||
use App\DataTables\ProjectBomEntriesDataTable;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Entity\ProjectSystem\Project;
|
||||
use App\Entity\ProjectSystem\ProjectBOMEntry;
|
||||
use App\Form\ProjectSystem\ProjectBOMEntryCollectionType;
|
||||
use App\Form\Type\StructuralEntityType;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Omines\DataTablesBundle\DataTableFactory;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
/**
|
||||
|
@ -58,4 +66,69 @@ class ProjectController extends AbstractController
|
|||
'project' => $project,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{id}/add_parts", name="project_add_parts")
|
||||
* @param Request $request
|
||||
* @param Project|null $project
|
||||
*/
|
||||
public function addPart(Request $request, Project $project, EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted('edit', $project);
|
||||
|
||||
$builder = $this->createFormBuilder();
|
||||
$builder->add('project', StructuralEntityType::class, [
|
||||
'class' => Project::class,
|
||||
'required' => true,
|
||||
'disabled' => true,
|
||||
'data' => $project,
|
||||
]);
|
||||
$builder->add('bom_entries', ProjectBOMEntryCollectionType::class);
|
||||
$builder->add('submit', SubmitType::class, ['label' => 'save']);
|
||||
$form = $builder->getForm();
|
||||
|
||||
//Preset the BOM entries with the selected parts, when the form was not submitted yet
|
||||
$preset_data = new ArrayCollection();
|
||||
foreach (explode(',', $request->get('parts', '')) as $part_id) {
|
||||
$part = $entityManager->getRepository(Part::class)->find($part_id);
|
||||
if (null !== $part) {
|
||||
//If there is already a BOM entry for this part, we use this one (we edit it then)
|
||||
$bom_entry = $entityManager->getRepository(ProjectBOMEntry::class)->findOneBy([
|
||||
'project' => $project,
|
||||
'part' => $part
|
||||
]);
|
||||
if ($bom_entry) {
|
||||
$preset_data->add($bom_entry);
|
||||
} else { //Otherwise create an empty one
|
||||
$entry = new ProjectBOMEntry();
|
||||
$entry->setProject($project);
|
||||
$entry->setPart($part);
|
||||
$preset_data->add($entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
$form['bom_entries']->setData($preset_data);
|
||||
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$data = $form->getData();
|
||||
$bom_entries = $data['bom_entries'];
|
||||
foreach ($bom_entries as $bom_entry){
|
||||
$project->addBOMEntry($bom_entry);
|
||||
}
|
||||
$entityManager->flush();
|
||||
|
||||
//If a redirect query parameter is set, redirect to this page
|
||||
if ($request->query->get('_redirect')) {
|
||||
return $this->redirect($request->query->get('_redirect'));
|
||||
}
|
||||
//Otherwise just show the project info page
|
||||
return $this->redirectToRoute('project_info', ['id' => $project->getID()]);
|
||||
}
|
||||
|
||||
return $this->renderForm('Projects/add_parts.html.twig', [
|
||||
'project' => $project,
|
||||
'form' => $form,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ use App\Entity\Parts\Category;
|
|||
use App\Entity\Parts\Footprint;
|
||||
use App\Entity\Parts\Manufacturer;
|
||||
use App\Entity\Parts\MeasurementUnit;
|
||||
use App\Entity\ProjectSystem\Project;
|
||||
use App\Services\Trees\NodesListBuilder;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
@ -79,6 +80,14 @@ class SelectAPIController extends AbstractController
|
|||
return $this->getResponseForClass(MeasurementUnit::class, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/project", name="select_project")
|
||||
*/
|
||||
public function projects(): Response
|
||||
{
|
||||
return $this->getResponseForClass(Project::class, false);
|
||||
}
|
||||
|
||||
protected function getResponseForClass(string $class, bool $include_empty = false): Response
|
||||
{
|
||||
$test_obj = new $class();
|
||||
|
|
|
@ -29,6 +29,8 @@ use App\Repository\DBElementRepository;
|
|||
use App\Repository\PartRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use InvalidArgumentException;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
||||
|
@ -36,11 +38,13 @@ final class PartsTableActionHandler
|
|||
{
|
||||
private EntityManagerInterface $entityManager;
|
||||
private Security $security;
|
||||
private UrlGeneratorInterface $urlGenerator;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, Security $security)
|
||||
public function __construct(EntityManagerInterface $entityManager, Security $security, UrlGeneratorInterface $urlGenerator)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->security = $security;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,9 +66,21 @@ final class PartsTableActionHandler
|
|||
|
||||
/**
|
||||
* @param Part[] $selected_parts
|
||||
* @return RedirectResponse|null Returns a redirect response if the user should be redirected to another page, otherwise null
|
||||
*/
|
||||
public function handleAction(string $action, array $selected_parts, ?int $target_id): void
|
||||
public function handleAction(string $action, array $selected_parts, ?int $target_id, ?string $redirect_url = null): ?RedirectResponse
|
||||
{
|
||||
if ($action === 'add_to_project') {
|
||||
return new RedirectResponse(
|
||||
$this->urlGenerator->generate('project_add_parts', [
|
||||
'id' => $target_id,
|
||||
'parts' => implode(',', array_map(static fn (Part $part) => $part->getID(), $selected_parts)),
|
||||
'_redirect' => $redirect_url
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
//Iterate over the parts and apply the action to it:
|
||||
foreach ($selected_parts as $part) {
|
||||
if (!$part instanceof Part) {
|
||||
|
@ -115,6 +131,8 @@ final class PartsTableActionHandler
|
|||
default:
|
||||
throw new InvalidArgumentException('The given action is unknown! ('.$action.')');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
22
templates/Projects/add_parts.html.twig
Normal file
22
templates/Projects/add_parts.html.twig
Normal file
|
@ -0,0 +1,22 @@
|
|||
{% extends "main_card.html.twig" %}
|
||||
|
||||
{% block title %}{% trans %}project.add_parts_to_project{% endtrans %}{% endblock %}
|
||||
|
||||
{% block card_title %}
|
||||
<i class="fa-solid fa-magnifying-glass-plus fa-fw"></i>
|
||||
{% trans %}project.add_parts_to_project{% endtrans %}{% if project %}: <i>{{ project.name }}</i>{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block card_content %}
|
||||
|
||||
{{ form_start(form) }}
|
||||
|
||||
{{ form_row(form.project) }}
|
||||
{% form_theme form.bom_entries with ['Form/collection_types_layout.html.twig'] %}
|
||||
{{ form_widget(form.bom_entries) }}
|
||||
|
||||
{{ form_row(form.submit) }}
|
||||
|
||||
{{ form_end(form) }}
|
||||
|
||||
{% endblock %}
|
|
@ -48,6 +48,9 @@
|
|||
<option {% if not is_granted('@manufacturers.read') %}disabled{% endif %} value="change_manufacturer" data-url="{{ path('select_manufacturer') }}">{% trans %}part_list.action.action.change_manufacturer{% endtrans %}</option>
|
||||
<option {% if not is_granted('@measurement_units.read') %}disabled{% endif %} value="change_unit" data-url="{{ path('select_measurement_unit') }}">{% trans %}part_list.action.action.change_unit{% endtrans %}</option>
|
||||
</optgroup>
|
||||
<optgroup label="{% trans %}part_list.action.group.projects{% endtrans %}">
|
||||
<option {% if not is_granted('@devices.read') %}disabled{% endif %} value="add_to_project" data-url="{{ path('select_project')}}">{% trans %}part_list.action.projects.add_to_project{% endtrans %}</option>
|
||||
</optgroup>
|
||||
|
||||
<option {% if not is_granted('@parts.delete') %}disabled{% endif %} value="delete">{% trans %}part_list.action.action.delete{% endtrans %}</option>
|
||||
</select>
|
||||
|
|
|
@ -9983,5 +9983,29 @@ Element 3</target>
|
|||
<target>Add entry</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="gwloIYB" name="part_list.action.group.projects">
|
||||
<segment>
|
||||
<source>part_list.action.group.projects</source>
|
||||
<target>Projects</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="QDvlT74" name="part_list.action.projects.add_to_project">
|
||||
<segment>
|
||||
<source>part_list.action.projects.add_to_project</source>
|
||||
<target>Add parts to project</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ZVrMX6T" name="project.bom.delete.confirm">
|
||||
<segment>
|
||||
<source>project.bom.delete.confirm</source>
|
||||
<target>Do you really want to delete this BOM entry?</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="T_wVWg_" name="project.add_parts_to_project">
|
||||
<segment>
|
||||
<source>project.add_parts_to_project</source>
|
||||
<target>Add parts to project BOM</target>
|
||||
</segment>
|
||||
</unit>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue