edit application

This commit is contained in:
Charles 2025-10-08 11:37:18 +02:00
parent 20509385f6
commit 6dc6d3bfa9
11 changed files with 226 additions and 5 deletions

View File

@ -21,5 +21,7 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="quill.snow" level="application" />
<orderEntry type="library" name="quill" level="application" />
</component>
</module>

View File

@ -18,3 +18,4 @@ import './js/hoverable-collapse.js';
import './js/cookies.js';
import 'choices.js';
import 'choices.js/public/assets/styles/choices.min.css';
import 'quill'

View File

@ -0,0 +1,40 @@
import { Controller } from '@hotwired/stimulus'
import Quill from 'quill'
// controllers/application_controller.js
export default class extends Controller {
static targets = ['hidden']
connect() {
// Map each editor to its toolbar and hidden field
this.editors = [
{
editorSelector: '#editor-description',
toolbarSelector: '#toolbar-description',
hiddenTarget: this.hiddenTargets[0],
},
{
editorSelector: '#editor-descriptionSmall',
toolbarSelector: '#toolbar-descriptionSmall',
hiddenTarget: this.hiddenTargets[1],
},
]
this.editors.forEach(({ editorSelector, toolbarSelector, hiddenTarget }) => {
const quill = new Quill(editorSelector, {
modules: {
toolbar: toolbarSelector, // HTML toolbar container
},
theme: 'snow', // include quill.snow.css
placeholder: 'Écrivez votre texte...',
})
// Keep hidden field in sync with editor HTML
quill.on('text-change', () => {
hiddenTarget.value = quill.root.innerHTML
})
// Ensure initial value sync in case user submits without changes
hiddenTarget.value = quill.root.innerHTML
})
}
}

View File

@ -42,4 +42,28 @@ return [
'version' => '11.1.0',
'type' => 'css',
],
'quill' => [
'version' => '2.0.3',
],
'lodash-es' => [
'version' => '4.17.21',
],
'parchment' => [
'version' => '3.0.0',
],
'quill-delta' => [
'version' => '5.1.0',
],
'eventemitter3' => [
'version' => '5.0.1',
],
'fast-diff' => [
'version' => '1.3.0',
],
'lodash.clonedeep' => [
'version' => '4.5.0',
],
'lodash.isequal' => [
'version' => '4.5.0',
],
];

View File

@ -0,0 +1,36 @@
<?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 Version20251008081943 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 apps ALTER description TYPE TEXT');
$this->addSql('ALTER TABLE apps ALTER description DROP NOT NULL');
$this->addSql('ALTER TABLE apps ALTER description_small TYPE TEXT');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('ALTER TABLE apps ALTER description TYPE VARCHAR(255)');
$this->addSql('ALTER TABLE apps ALTER description SET NOT NULL');
$this->addSql('ALTER TABLE apps ALTER description_small TYPE VARCHAR(255)');
}
}

View File

@ -3,8 +3,11 @@
namespace App\Controller;
use App\Entity\Apps;
use App\Service\ActionService;
use App\Service\UserService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
@ -12,7 +15,7 @@ use Symfony\Component\Routing\Attribute\Route;
class ApplicationController extends AbstractController
{
public function __construct(private readonly EntityManagerInterface $entityManager)
public function __construct(private readonly EntityManagerInterface $entityManager, private readonly UserService $userService, private readonly ActionService $actionService)
{
}
@ -27,4 +30,38 @@ class ApplicationController extends AbstractController
]);
}
#[Route(path: '/edit/{id}', name: 'edit', methods: ['GET', 'POST'])]
public function edit(int $id, Request $request): Response{
$this->denyAccessUnlessGranted('ROLE_SUPER_ADMIN');
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
$application = $this->entityManager->getRepository(Apps::class)->find($id);
if (!$application) {
$this->addFlash('error', "L'application n'existe pas ou n'est pas reconnu.");
return $this->redirectToRoute('application_index');
}
$applicationData = [
'id' => $application->getId(),
'name' => $application->getName(),
'description' => $application->getDescription(),
'descriptionSmall' => $application->getDescriptionSmall(),
'isActive' => $application->isActive(),
];
if ($request->isMethod('POST')) {
$data = $request->request->all();
$application->setName($data['name']);
$application->setDescription($data['description']);
$application->setDescriptionSmall($data['descriptionSmall']);
$this->entityManager->persist($application);
$this->actionService->createAction("Modification de l'application ", $actingUser, null, $application->getId());
return $this->redirectToRoute('application_index');
}
return $this->render('application/edit.html.twig', [
'apps' => $applicationData,
]);
}
}

View File

@ -5,6 +5,7 @@ namespace App\Entity;
use App\Repository\AppsRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: AppsRepository::class)]
@ -24,7 +25,7 @@ class Apps
#[ORM\Column(length: 255)]
private ?string $logo_url = null;
#[ORM\Column(length: 255)]
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $description = null;
#[ORM\Column(length: 255)]
@ -33,7 +34,7 @@ class Apps
#[ORM\Column(options: ['default' => true])]
private ?bool $isActive = null;
#[ORM\Column(length: 255, nullable: true)]
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $descriptionSmall = null;
/**

View File

@ -8,9 +8,12 @@
</div>
</div>
<div class="card-body d-flex flex-column align-items-center">
<p class="card-text">{{ application.description }}</p>
<p class="card-text">{{ application.description|raw }}</p>
<div>
<a href="http://{{ application.subDomain }}.solutions-easy.moi" class="btn btn-primary me-2">Accéder à l'application</a>
{% if is_granted("ROLE_SUPER_ADMIN") %}
<a href="{{ path('application_edit', {'id': application.id}) }}" class="btn btn-secondary">Modifier l'application</a>
{% endif %}
</div>
</div>
</div>

View File

@ -8,7 +8,7 @@
</div>
</div>
<div class="card-body d-flex flex-column align-items-center">
<p class="card-text">{{ application.entity.descriptionSmall }}</p>
<p class="card-text">{{ application.entity.descriptionSmall|raw }}</p>
{% if application.hasAccess %}
<div >
<a href="http://{{ application.entity.subDomain }}.solutions-easy.moi" class="btn btn-primary me-2">Y

View File

@ -0,0 +1,75 @@
{% extends 'base.html.twig' %}
{% block body %}
<div class=" col-md-10 m-auto p-5">
<div class="card">
<div class="card-title shadow-sm p-3 d-flex justify-content-between align-items-center">
<h2>Modifier l'application</h2>
</div>
<div class="card-body">
{# templates/application/edit.html.twig #}
<form method="post" action="{{ path('application_edit', {'id': apps.id}) }}" data-controller="application">
<input name="name" type="text" value="{{ apps.name }}" class="form-control mb-3" required>
{# Description (full) #}
<div id="toolbar-description" class="mb-2">
<button class="ql-bold"></button>
<button class="ql-italic"></button>
<button class="ql-underline"></button>
<button class="ql-strike"></button>
<button class="ql-blockquote"></button>
<button class="ql-code-block"></button>
<select class="ql-header">
<option value="1"></option>
<option value="2"></option>
<option selected></option>
</select>
<select class="ql-size">
<option value="small"></option>
<option selected></option>
<option value="large"></option>
<option value="huge"></option>
</select>
<select class="ql-color"></select>
<select class="ql-background"></select>
<select class="ql-align"></select>
<button class="ql-link"></button>
<button class="ql-image"></button>
<button class="ql-clean"></button>
</div>
<div id="editor-description" class="form-control" style="min-height: 200px;">
{{ apps.description|raw }}
</div>
<textarea name="description" data-application-target="hidden" class="d-none">{{ apps.description|raw }}</textarea>
{# Description Small #}
<div id="toolbar-descriptionSmall" class="mb-2 mt-3">
<button class="ql-bold"></button>
<button class="ql-italic"></button>
<button class="ql-underline"></button>
<select class="ql-header">
<option value="2"></option>
<option selected></option>
</select>
<button class="ql-clean"></button>
</div>
<div id="editor-descriptionSmall" class="form-control" style="min-height: 120px;">
{{ apps.descriptionSmall|raw }}
</div>
<textarea name="descriptionSmall" data-application-target="hidden" class="d-none">{{ apps.descriptionSmall|raw }}</textarea>
<input type="file" name="logo" class="form-control mb-3 mt-3">
<button type="submit" class="btn btn-primary mt-3">Enregistrer</button>
</form>
</div>
</div>
</div>
{% endblock %}
{% block title %}
{% endblock %}

View File

@ -13,10 +13,12 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap" rel="stylesheet">
<link href="https://cdn.quilljs.com/1.3.7/quill.snow.css" rel="stylesheet">
{% endblock %}
{% block javascripts %}
{% block importmap %}{{ importmap('app') }}{% endblock %}
<script src="https://cdn.quilljs.com/1.3.7/quill.min.js"></script>
{% endblock %}
</head>
<body data-application="{{application}}">