WIP: Implement document handling
This commit is contained in:
@@ -18,6 +18,12 @@ oneup_uploader:
|
||||
namer: app.upload_namer
|
||||
storage:
|
||||
directory: '%kernel.project_dir%/uploads/contract'
|
||||
document:
|
||||
frontend: dropzone
|
||||
use_orphanage: true
|
||||
namer: app.upload_namer
|
||||
storage:
|
||||
directory: '%kernel.project_dir%/uploads/document'
|
||||
chunks:
|
||||
maxage: 86400
|
||||
storage:
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20231012074633 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TABLE assignment_upload (assignment_id INT NOT NULL, upload_id INT NOT NULL, INDEX IDX_2F9CC602D19302F8 (assignment_id), INDEX IDX_2F9CC602CCCFBA31 (upload_id), PRIMARY KEY(assignment_id, upload_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||
$this->addSql('ALTER TABLE assignment_upload ADD CONSTRAINT FK_2F9CC602D19302F8 FOREIGN KEY (assignment_id) REFERENCES assignment (id) ON DELETE CASCADE');
|
||||
$this->addSql('ALTER TABLE assignment_upload ADD CONSTRAINT FK_2F9CC602CCCFBA31 FOREIGN KEY (upload_id) REFERENCES upload (id) ON DELETE CASCADE');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE assignment_upload DROP FOREIGN KEY FK_2F9CC602D19302F8');
|
||||
$this->addSql('ALTER TABLE assignment_upload DROP FOREIGN KEY FK_2F9CC602CCCFBA31');
|
||||
$this->addSql('DROP TABLE assignment_upload');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20231012082751 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE upload ADD display_name VARCHAR(255) DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE upload DROP display_name');
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -9,7 +9,7 @@ use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class BpnDateController extends AbstractController
|
||||
class DestinationController extends AbstractController
|
||||
{
|
||||
public function __construct(private readonly DestinationRepository $bpnDateRepository)
|
||||
{}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin\Autocomplete;
|
||||
|
||||
use App\Repository\UploadRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class DocumentController extends AbstractController
|
||||
{
|
||||
public function __construct(private readonly UploadRepository $uploadRepository)
|
||||
{}
|
||||
|
||||
#[Route('/admin/autocomplete/document', name: 'app_admin_autocomplete_document')]
|
||||
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$query = json_decode($request->getContent(), true, 512, JSON_THROW_ON_ERROR);
|
||||
$queryString = $query['search'];
|
||||
} catch (\JsonException $e) {
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
$dates = $this->uploadRepository->getAutocompletionData($queryString);
|
||||
|
||||
return $this->json($dates);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin\Document;
|
||||
|
||||
use App\Entity\Upload;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class DeleteController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly LoggerInterface $logger
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route('/admin/document/delete/{uuid}', name: 'app_admin_document_delete')]
|
||||
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
||||
#[IsGranted('DELETE', subject: 'document')]
|
||||
public function index(Upload $document): Response
|
||||
{
|
||||
$this->entityManager->remove($document);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->addFlash('success', 'Das Dokument wurde gelöscht');
|
||||
$this->logger->info('Delete document', [
|
||||
'document' => $document->getOriginalFilename(),
|
||||
]);
|
||||
|
||||
return $this->redirectToRoute('app_admin_document_index');
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,40 @@
|
||||
|
||||
namespace App\Controller\Admin\Document;
|
||||
|
||||
use App\Repository\UploadRepository;
|
||||
use Knp\Component\Pager\PaginatorInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class IndexController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UploadRepository $uploadRepository,
|
||||
private readonly PaginatorInterface $paginator
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route('/admin/document', name: 'app_admin_document_index')]
|
||||
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
||||
public function index(): Response
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
return $this->render('admin/document/index.html.twig');
|
||||
$query = $this->uploadRepository->getDocumentListQuery();
|
||||
|
||||
$pagination = $this->paginator->paginate(
|
||||
$query,
|
||||
$request->query->getInt('page', 1),
|
||||
10,
|
||||
[
|
||||
'defaultSortFieldName' => 'upload.originalFilename',
|
||||
'defaultSortDirection' => 'asc',
|
||||
]
|
||||
);
|
||||
|
||||
return $this->render('admin/document/index.html.twig', [
|
||||
'pagination' => $pagination,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin\Document;
|
||||
|
||||
use App\Entity\Upload;
|
||||
use App\Entity\User;
|
||||
use App\Model\AjaxModalResponseDto;
|
||||
use App\Service\Upload\UploadHandler;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class ReplaceController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UploadHandler $uploadHandler,
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly LoggerInterface $logger
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route('/admin/document/replace/{uuid}', name: 'app_admin_document_replace')]
|
||||
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
||||
public function index(Upload $upload, Request $request): JsonResponse
|
||||
{
|
||||
// Handle upload independently from form submission to avoid issues with failing validation
|
||||
$uploadSession = $this->uploadHandler->getUploadSession();
|
||||
if (true === $request->isMethod('POST') && 0 < $uploadSession->getCount()) {
|
||||
/** @var User $user */
|
||||
$user = $this->getUser();
|
||||
Upload::fromUploadDto($uploadSession->getUploads()->first(), $user, Upload::TYPE_DOCUMENT, $upload);
|
||||
$this->entityManager->flush();
|
||||
$this->uploadHandler->moveUploadSessionFilesFromOrphanage(Upload::TYPE_DOCUMENT, $uploadSession);
|
||||
$this->uploadHandler->destroyUploadSession();
|
||||
}
|
||||
|
||||
$response = new AjaxModalResponseDto();
|
||||
$formAction = $this->generateUrl('app_admin_document_replace', ['uuid' => $upload->getUuid()]);
|
||||
|
||||
$form = $this
|
||||
->createFormBuilder(null, ['action' => $formAction, 'ajax_submit' => true])
|
||||
->getForm()
|
||||
;
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$this->addFlash('success', 'Das Dokument wurden ersetzt');
|
||||
$this->logger->info('Replace document');
|
||||
|
||||
$response->setCloseAndRedirect($this->generateUrl('app_admin_document_index'));
|
||||
} else {
|
||||
$response->setContent($this->renderView('admin/document/replace.html.twig', [
|
||||
'form' => $form,
|
||||
]));
|
||||
}
|
||||
|
||||
return $this->json($response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin\Document;
|
||||
|
||||
use App\Entity\Upload;
|
||||
use App\Entity\User;
|
||||
use App\Model\AjaxModalResponseDto;
|
||||
use App\Service\Upload\UploadHandler;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class UploadController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UploadHandler $uploadHandler,
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly LoggerInterface $logger
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route('/admin/document/upload', name: 'app_admin_document_upload')]
|
||||
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
// Handle upload independently from form submission to avoid issues with failing validation
|
||||
$uploadSession = $this->uploadHandler->getUploadSession();
|
||||
if (true === $request->isMethod('POST') && 0 < $uploadSession->getCount()) {
|
||||
/** @var User $user */
|
||||
$user = $this->getUser();
|
||||
foreach ($uploadSession->getUploads() as $upload) {
|
||||
$document = Upload::fromUploadDto($upload, $user, Upload::TYPE_DOCUMENT);
|
||||
$this->entityManager->persist($document);
|
||||
}
|
||||
$this->entityManager->flush();
|
||||
$this->uploadHandler->moveUploadSessionFilesFromOrphanage(Upload::TYPE_DOCUMENT, $uploadSession);
|
||||
$this->uploadHandler->destroyUploadSession();
|
||||
}
|
||||
|
||||
$response = new AjaxModalResponseDto();
|
||||
$formAction = $this->generateUrl('app_admin_document_upload');
|
||||
|
||||
$form = $this
|
||||
->createFormBuilder(null, ['action' => $formAction, 'ajax_submit' => true])
|
||||
->getForm()
|
||||
;
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$this->addFlash('success', 'Das/die Dokument/e wurden hochgeladen');
|
||||
$this->logger->info('Upload document');
|
||||
|
||||
$response->setCloseAndRedirect($this->generateUrl('app_admin_document_index'));
|
||||
} else {
|
||||
$response->setContent($this->renderView('admin/document/upload.html.twig', [
|
||||
'form' => $form,
|
||||
]));
|
||||
}
|
||||
|
||||
return $this->json($response);
|
||||
}
|
||||
}
|
||||
@@ -76,6 +76,9 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
|
||||
#[ORM\ManyToMany(targetEntity: Teamer::class, mappedBy: 'bookmarks')]
|
||||
private Collection $teamers;
|
||||
|
||||
#[ORM\ManyToMany(targetEntity: Upload::class)]
|
||||
private Collection $documents;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->uuid = Uuid::v4();
|
||||
@@ -84,6 +87,7 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
|
||||
$this->dispositions = new ArrayCollection();
|
||||
$this->teamers = new ArrayCollection();
|
||||
$this->benefits = "Anreise im E&P Reisebus\nUnterkunft\nVerpflegung\nSkipass\n";
|
||||
$this->documents = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
@@ -344,4 +348,28 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Upload>
|
||||
*/
|
||||
public function getDocuments(): Collection
|
||||
{
|
||||
return $this->documents;
|
||||
}
|
||||
|
||||
public function addDocument(Upload $document): static
|
||||
{
|
||||
if (!$this->documents->contains($document)) {
|
||||
$this->documents->add($document);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeDocument(Upload $document): static
|
||||
{
|
||||
$this->documents->removeElement($document);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-2
@@ -19,6 +19,7 @@ class Upload implements BlameableEntityInterface, TimestampableEntityInterface
|
||||
public const TYPE_CERTIFICATE = 'certificate';
|
||||
public const TYPE_CONTRACT = 'contract';
|
||||
public const TYPE_INVOICE = 'invoice';
|
||||
public const TYPE_DOCUMENT = 'document';
|
||||
|
||||
public const STATUS_NEW = 'new';
|
||||
public const STATUS_IN_PROCESS = 'in_process';
|
||||
@@ -46,6 +47,9 @@ class Upload implements BlameableEntityInterface, TimestampableEntityInterface
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $originalFilename = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $displayName = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?int $size = null;
|
||||
|
||||
@@ -60,9 +64,9 @@ class Upload implements BlameableEntityInterface, TimestampableEntityInterface
|
||||
$this->uuid = Uuid::v4();
|
||||
}
|
||||
|
||||
public static function fromUploadDto(UploadDto $uploadDto, User $owner, string $type): static
|
||||
public static function fromUploadDto(UploadDto $uploadDto, User $owner, string $type, Upload $instance = null): static
|
||||
{
|
||||
$instance = new static();
|
||||
$instance = $instance ?? new static();
|
||||
$instance
|
||||
->setFilename($uploadDto->getFilename())
|
||||
->setOriginalFilename($uploadDto->getOriginalFilename())
|
||||
@@ -133,6 +137,18 @@ class Upload implements BlameableEntityInterface, TimestampableEntityInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDisplayName(): ?string
|
||||
{
|
||||
return $this->displayName;
|
||||
}
|
||||
|
||||
public function setDisplayName(?string $displayName): static
|
||||
{
|
||||
$this->displayName = $displayName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSize(): ?int
|
||||
{
|
||||
return $this->size;
|
||||
|
||||
@@ -6,11 +6,13 @@ use App\Entity\Assignment;
|
||||
use App\Entity\Destination;
|
||||
use App\Entity\Fee;
|
||||
use App\Entity\JobProfile;
|
||||
use App\Entity\Upload;
|
||||
use App\Entity\User;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
@@ -87,6 +89,19 @@ class AssignmentType extends AbstractType
|
||||
;
|
||||
},
|
||||
])
|
||||
->add('documents', CollectionType::class, [
|
||||
'label' => 'Dokumente',
|
||||
'entry_type' => AutocompleteEntityType::class,
|
||||
'entry_options' => [
|
||||
'class' => Upload::class,
|
||||
'endpoint_route' => 'app_admin_autocomplete_document',
|
||||
'label_property' => 'originalFilename',
|
||||
'placeholder' => 'Dokument...',
|
||||
],
|
||||
'allow_add' => true,
|
||||
'allow_delete' => true,
|
||||
'by_reference' => false,
|
||||
])
|
||||
->add('remarks', TextareaType::class, [
|
||||
'label' => 'Anmerkungen',
|
||||
'required' => false,
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Upload;
|
||||
use App\Repository\Traits\QueryHelperTrait;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
@@ -16,51 +18,54 @@ use Doctrine\Persistence\ManagerRegistry;
|
||||
*/
|
||||
class UploadRepository extends ServiceEntityRepository
|
||||
{
|
||||
use QueryHelperTrait;
|
||||
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Upload::class);
|
||||
}
|
||||
|
||||
public function save(Upload $entity, bool $flush = false): void
|
||||
public function getDocumentListQuery(): Query
|
||||
{
|
||||
$this->getEntityManager()->persist($entity);
|
||||
$qb = $this->createQueryBuilder('upload');
|
||||
|
||||
if ($flush) {
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
return $qb
|
||||
->where($qb->expr()->eq('upload.type', ':type'))
|
||||
->setParameter('type', Upload::TYPE_DOCUMENT)
|
||||
->getQuery()
|
||||
;
|
||||
}
|
||||
|
||||
public function remove(Upload $entity, bool $flush = false): void
|
||||
public function getAutocompletionData(string $search): array
|
||||
{
|
||||
$this->getEntityManager()->remove($entity);
|
||||
$qb = $this->createQueryBuilder('upload');
|
||||
|
||||
if ($flush) {
|
||||
$this->getEntityManager()->flush();
|
||||
$documents = $qb
|
||||
->where($qb->expr()->orX(
|
||||
$qb->expr()->like('upload.originalFilename', ':filename'),
|
||||
$qb->expr()->like('upload.displayName', ':filename')
|
||||
))
|
||||
->setParameter('filename', '%'.$this->escapeLikeWildcards($search).'%')
|
||||
->orderBy('upload.originalFilename', 'ASC')
|
||||
->getQuery()
|
||||
->getResult()
|
||||
;
|
||||
|
||||
$data = [
|
||||
[
|
||||
'value' => '',
|
||||
'text' => '...',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($documents as $document) {
|
||||
/** @var Upload $document */
|
||||
$data[] = [
|
||||
'value' => $document->getId(),
|
||||
'text' => $document->getOriginalFilename(),
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return Upload[] Returns an array of Upload objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('u')
|
||||
// ->andWhere('u.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('u.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?Upload
|
||||
// {
|
||||
// return $this->createQueryBuilder('u')
|
||||
// ->andWhere('u.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
{% macro collectionRow(form) %}
|
||||
<div {{ stimulus_target('form-collection', 'field') }}>
|
||||
<div class="flex items-center space-x-4">
|
||||
{{ form_widget(form) }}
|
||||
<button type="button" {{ stimulus_action('form-collection', 'removeItem') }}>
|
||||
{{ icon('delete', 'w-4 h-4 mt-2 pointer-events-none') }}
|
||||
</button>
|
||||
</div>
|
||||
{{ form_errors(form) }}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{{ form_start(form) }}
|
||||
<div class="flex flex-col space-y-4 pb-8">
|
||||
<div class="grid lg:grid-cols-5 gap-x-8 gap-y-4">
|
||||
@@ -25,6 +37,22 @@
|
||||
</div>
|
||||
<div class="grid lg:grid-cols-2 gap-x-8 gap-y-4">
|
||||
{{ form_row(form.remarks) }}
|
||||
<div {{ stimulus_controller('form-collection', { 'prototype': _self.collectionRow(form.documents.vars.prototype)|json_encode }) }}>
|
||||
<h4 class="font-bold pb-2">
|
||||
Dokumente
|
||||
</h4>
|
||||
<div {{ stimulus_target('form-collection', 'fields')}} class="flex flex-col space-y-4 mb-4">
|
||||
{% do form.documents.setRendered %}
|
||||
{%- for document in form.documents -%}{{- _self.collectionRow(document) -}}{%- endfor -%}
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<button type="button"
|
||||
{{ stimulus_action('form-collection', 'addItem') }}
|
||||
title="Dokument hinzufügen">
|
||||
{{ icon('plus', 'w-4 h-4 pointer-events-none') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
|
||||
@@ -6,16 +6,86 @@
|
||||
<h1 class="text-2xl font-bold pb-8">
|
||||
Dokumentenübersicht
|
||||
</h1>
|
||||
<div class="data-table-wrapper">
|
||||
<div class="data-table-wrapper__inner">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<div class="data-table-wrapper">
|
||||
<div class="data-table-wrapper__inner">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
{{ knp_pagination_sortable(pagination, 'Dateiname', 'upload.originalFilename') }}
|
||||
</th>
|
||||
<th>
|
||||
Dateigröße
|
||||
</th>
|
||||
<th>
|
||||
Upload am
|
||||
</th>
|
||||
<th>
|
||||
Upload von
|
||||
</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for document in pagination %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ document.originalFilename }}
|
||||
</td>
|
||||
<td>
|
||||
{{ document.size|file_size }}
|
||||
</td>
|
||||
<td>
|
||||
{{ document.createdAt|date('d.m.Y') }}
|
||||
</td>
|
||||
<td>
|
||||
{{ document.createdBy }}
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-2 justify-end">
|
||||
<button type="button"
|
||||
class="text-red-500"
|
||||
{{ stimulus_controller('modal-button', [], [], {'confirmation-modal': '#confirmation-modal'}) }}
|
||||
{{ stimulus_action('modal-button', 'confirmation', null, {
|
||||
'title': 'Bist du sicher?',
|
||||
'content': 'Möchtest du das Dokument wirklich löschen?',
|
||||
'target-url': path('app_admin_document_delete', { 'uuid': document.uuid })
|
||||
}) }}>
|
||||
{{ icon('delete') }}
|
||||
</button>
|
||||
<button type="button"
|
||||
{{ stimulus_controller('modal-button', [], [], {'ajax-modal': '#ajax-modal'}) }}
|
||||
{{ stimulus_action('modal-button', 'ajax', null, {
|
||||
'title': 'Dokument ersetzen',
|
||||
'url': path('app_admin_document_replace', { 'uuid': document.uuid })
|
||||
}) }}>
|
||||
{{ icon('refresh') }}
|
||||
</button>
|
||||
<a href="{{ path('app_common_download', { 'uuid': document.uuid }) }}"
|
||||
title="Download">
|
||||
{{ icon('download') }}
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="7">
|
||||
Keine Daten...
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button"
|
||||
class="btn"
|
||||
{{ stimulus_controller('modal-button', [], [], {'ajax-modal': '#ajax-modal'}) }}
|
||||
{{ stimulus_action('modal-button', 'ajax', null, {
|
||||
'title': 'Dokumente hinzufügen',
|
||||
'url': path('app_admin_document_upload')
|
||||
}) }}>
|
||||
Dokumente hinzufügen
|
||||
</button>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,14 @@
|
||||
{{ form_start(form) }}
|
||||
<div class="pb-4">
|
||||
{% include '_partials/_upload_collection_form.html.twig' with {
|
||||
'endpoint_upload': path('_uploader_upload_document'),
|
||||
'max_filesize': 5,
|
||||
'max_files': 1,
|
||||
'accepted_files': 'application/pdf',
|
||||
} %}
|
||||
</div>
|
||||
<button type="submit" class="btn">
|
||||
ersetzen
|
||||
</button>
|
||||
{{ form_rest(form) }}
|
||||
{{ form_end(form) }}
|
||||
@@ -0,0 +1,13 @@
|
||||
{{ form_start(form) }}
|
||||
<div class="pb-4">
|
||||
{% include '_partials/_upload_collection_form.html.twig' with {
|
||||
'endpoint_upload': path('_uploader_upload_document'),
|
||||
'max_filesize': 5,
|
||||
'accepted_files': 'application/pdf',
|
||||
} %}
|
||||
</div>
|
||||
<button type="submit" class="btn">
|
||||
Uploads speichern
|
||||
</button>
|
||||
{{ form_rest(form) }}
|
||||
{{ form_end(form) }}
|
||||
@@ -35,7 +35,6 @@
|
||||
<div class="pb-4">
|
||||
{% include '_partials/_upload_collection_form.html.twig' with {
|
||||
'endpoint_upload': path('_uploader_upload_contract'),
|
||||
'upload_session_params': null,
|
||||
'accepted_files': 'image/jpg,image/jpeg,application/pdf',
|
||||
} %}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user