Compare commits

..

3 Commits

13 changed files with 434 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
kind: Feature
body: Admin interface for Motive entity
time: 2025-10-07T15:59:45.597029709+02:00
custom:
Issue: ""
SchemaChange: No schema change

View File

@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\TicketBundle\Controller\Admin;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class MotiveController extends CRUDController
{
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
/* @var QueryBuilder $query */
$query->addOrderBy('e.id', 'ASC');
return parent::orderQuery($action, $query, $request, $paginator);
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\TicketBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
/**
* Class AdminController
* Controller for the ticket configuration section (in admin section).
*/
class AdminController extends AbstractController
{
/**
* Ticket admin.
*/
#[Route(path: '/{_locale}/admin/ticket', name: 'chill_ticket_admin_index')]
public function indexAdminAction()
{
return $this->render('@ChillTicket/Admin/index.html.twig');
}
}

View File

@@ -11,8 +11,10 @@ declare(strict_types=1);
namespace Chill\TicketBundle\DependencyInjection; namespace Chill\TicketBundle\DependencyInjection;
use Chill\TicketBundle\Controller\Admin\MotiveController;
use Chill\TicketBundle\Controller\MotiveApiController; use Chill\TicketBundle\Controller\MotiveApiController;
use Chill\TicketBundle\Entity\Motive; use Chill\TicketBundle\Entity\Motive;
use Chill\TicketBundle\Form\MotiveType;
use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
@@ -36,6 +38,7 @@ class ChillTicketExtension extends Extension implements PrependExtensionInterfac
public function prepend(ContainerBuilder $container) public function prepend(ContainerBuilder $container)
{ {
$this->prependApi($container); $this->prependApi($container);
$this->prependCruds($container);
} }
private function prependApi(ContainerBuilder $container): void private function prependApi(ContainerBuilder $container): void
@@ -66,4 +69,37 @@ class ChillTicketExtension extends Extension implements PrependExtensionInterfac
], ],
]); ]);
} }
protected function prependCruds(ContainerBuilder $container): void
{
$container->prependExtensionConfig('chill_main', [
'cruds' => [
[
'class' => Motive::class,
'name' => 'motive',
'base_path' => '/admin/ticket/motive',
'form_class' => MotiveType::class,
'controller' => MotiveController::class,
'actions' => [
'index' => [
'template' => '@ChillTicket/Admin/Motive/index.html.twig',
'role' => 'ROLE_ADMIN',
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillTicket/Admin/Motive/new.html.twig',
],
'view' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillTicket/Admin/Motive/view.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillTicket/Admin/Motive/edit.html.twig',
],
],
],
],
]);
}
} }

View File

@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\TicketBundle\Form;
use Chill\MainBundle\Form\Type\ChillCollectionType;
use Chill\MainBundle\Form\Type\CommentType;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Chill\TicketBundle\Entity\EmergencyStatusEnum;
use Chill\TicketBundle\Entity\Motive;
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\EnumType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class MotiveType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('label', TranslatableStringFormType::class, [
'label' => 'Label',
'required' => true,
])
->add('active', CheckboxType::class, [
'label' => 'Active',
'required' => false,
])
->add('makeTicketEmergency', EnumType::class, [
'class' => EmergencyStatusEnum::class,
'label' => 'emergency?',
'required' => false,
'placeholder' => 'Choose an option...',
])
->add('supplementaryComments', ChillCollectionType::class, [
'entry_type' => TextareaType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => true,
'label' => 'Supplementary comments',
'required' => false,
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Motive::class,
]);
}
public function getBlockPrefix(): string
{
return 'chill_ticketbundle_motive';
}
}

View File

@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\TicketBundle\Menu;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
class AdminMenuBuilder implements LocalMenuBuilderInterface
{
public function __construct(protected AuthorizationCheckerInterface $authorizationChecker) {}
public function buildMenu($menuId, MenuItem $menu, array $parameters): void
{
if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) {
return;
}
$menu->addChild('Tickets', [
'route' => 'chill_ticket_admin_index',
])
->setAttribute('class', 'list-group-item-header')
->setExtras([
'order' => 7500,
]);
$menu->addChild('admin.ticket.motive.menu', [
'route' => 'chill_crud_motive_index',
])->setExtras(['order' => 7510]);
}
public static function getMenuIds(): array
{
return ['admin_section', 'admin_ticket'];
}
}

View File

@@ -0,0 +1,15 @@
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_edit_title.html.twig') %}
{% endblock %}
{% block js %}
{{ parent() }}
{% endblock %}
{% block admin_content %}
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
{% block content_form_actions_save_and_view %}{% endblock %}
{% endembed %}
{% endblock %}

View File

@@ -0,0 +1,64 @@
{% extends '@ChillMain/Admin/layoutWithVerticalMenu.html.twig' %}
{% block title %}{{ 'admin.motive.list.title'|trans }}{% endblock title %}
{% block admin_content %}
<h1>{{ 'admin.motive.list.title'|trans }}</h1>
<table class="records_list table table-bordered border-dark">
<thead>
<tr>
<th>{{ 'Label'|trans }}</th>
<th>{{ 'Active'|trans }}</th>
<th>{{ 'emergency?'|trans }}</th>
<th>{{ 'Supplementary comments'|trans }}</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
{% for entity in entities %}
<tr>
<td>{{ entity.label|localize_translatable_string }}</td>
<td style="text-align:center;">
{%- if entity.isActive -%}
<i class="fa fa-check-square-o"></i>
{%- else -%}
<i class="fa fa-square-o"></i>
{%- endif -%}
</td>
<td style="text-align:center;">
{%- if entity.makeTicketEmergency -%}
{{ entity.makeTicketEmergency.value|trans }}
{%- else -%}
-
{%- endif -%}
</td>
<td style="text-align:center;">
{{ entity.supplementaryComments|length }}
</td>
<td>
<ul class="record_actions">
<li>
<a href="{{ path('chill_crud_motive_view', { 'id': entity.id }) }}" class="btn btn-show" title="{{ 'show'|trans }}"></a>
</li>
<li>
<a href="{{ path('chill_crud_motive_edit', { 'id': entity.id }) }}" class="btn btn-edit" title="{{ 'edit'|trans }}"></a>
</li>
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{{ chill_pagination(paginator) }}
<ul class="record_actions sticky-form-buttons">
<li>
<a href="{{ path('chill_crud_motive_new') }}" class="btn btn-create">
{{ 'admin.motive.new.title'|trans }}
</a>
</li>
</ul>
{% endblock %}

View File

@@ -0,0 +1,15 @@
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
{% endblock %}
{% block js %}
{{ parent() }}
{% endblock %}
{% block admin_content %}
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
{% block content_form_actions_save_and_show %}{% endblock %}
{% endembed %}
{% endblock %}

View File

@@ -0,0 +1,78 @@
{% extends '@ChillMain/Admin/layoutWithVerticalMenu.html.twig' %}
{% block title %}{{ 'admin.motive.view.title'|trans }}{% endblock title %}
{% block admin_content %}
<h1>{{ 'admin.motive.view.title'|trans }}</h1>
<table class="record_properties table table-bordered">
<tbody>
<tr>
<th>{{ 'Id'|trans }}</th>
<td>{{ entity.id }}</td>
</tr>
<tr>
<th>{{ 'Label'|trans }}</th>
<td>{{ entity.label|localize_translatable_string }}</td>
</tr>
<tr>
<th>{{ 'Active'|trans }}</th>
<td style="text-align:center;">
{%- if entity.isActive -%}
<i class="fa fa-check-square-o"></i> {{ 'Yes'|trans }}
{%- else -%}
<i class="fa fa-square-o"></i> {{ 'No'|trans }}
{%- endif -%}
</td>
</tr>
<tr>
<th>{{ 'emergency?'|trans }}</th>
<td>
{%- if entity.makeTicketEmergency -%}
{{ entity.makeTicketEmergency.value|trans }}
{%- else -%}
-
{%- endif -%}
</td>
</tr>
</tbody>
</table>
{% if entity.supplementaryComments is not empty %}
<h2>{{ 'Supplementary comments'|trans }}</h2>
<div class="supplementary-comments">
{% for comment in entity.supplementaryComments %}
<div class="card mb-3">
<div class="card-body">
<div class="comment-content">
{{ comment.comment|raw }}
</div>
{% if comment.date %}
<div class="comment-meta text-muted mt-2">
<small>
{{ 'Date'|trans }}: {{ comment.date|date('d/m/Y H:i') }}
{% if comment.userId %}
- {{ 'User'|trans }}: {{ comment.userId }}
{% endif %}
</small>
</div>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% else %}
<h2>{{ 'Supplementary comments'|trans }}</h2>
<p class="text-muted">{{ 'No supplementary comments'|trans }}</p>
{% endif %}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ path('chill_crud_motive_index') }}" class="btn btn-cancel">{{ 'Back to the list'|trans }}</a>
</li>
<li>
<a href="{{ path('chill_crud_motive_edit', { 'id': entity.id }) }}" class="btn btn-edit">{{ 'Edit'|trans }}</a>
</li>
</ul>
{% endblock %}

View File

@@ -0,0 +1,13 @@
{% extends "@ChillMain/Admin/layoutWithVerticalMenu.html.twig" %}
{% block vertical_menu_content %}
{{ chill_menu('admin_ticket', {
'layout': '@ChillMain/Admin/menu_admin_section.html.twig',
}) }}
{% endblock %}
{% block layout_wvm_content %}
{% block admin_content %}<!-- block content empty -->
<h1>{{ 'Tickets configuration' |trans }}</h1>
{% endblock %}
{% endblock %}

View File

@@ -40,3 +40,6 @@ services:
Chill\TicketBundle\DataFixtures\: Chill\TicketBundle\DataFixtures\:
resource: '../DataFixtures/' resource: '../DataFixtures/'
Chill\TicketBundle\Form\:
resource: '../Form/'

View File

@@ -148,3 +148,35 @@ chill_ticket:
open_new_tab: "Ouvrir dans un nouvel onglet" open_new_tab: "Ouvrir dans un nouvel onglet"
iframe_not_supported: "Votre navigateur ne supporte pas les iframes." iframe_not_supported: "Votre navigateur ne supporte pas les iframes."
click_to_open_pdf: "Cliquez ici pour ouvrir le PDF" click_to_open_pdf: "Cliquez ici pour ouvrir le PDF"
admin:
ticket:
motive:
menu: Motifs
motive:
list:
title: Liste des motifs
view:
title: Le motif
new:
title: Créer un motif
crud:
motive:
title_edit: Modifier le motif
new:
"Create a new motive": "Créer un nouveau motif"
"Label": "Libellé"
"Active": "Actif"
"emergency?": "Urgent ?"
"Supplementary comments": "Commentaires supplémentaires"
"edit": "modifier"
"show": "voir"
"Yes": "Oui"
"No": "Non"
"Id": "ID"
"Date": "Date"
"User": "Utilisateur"
"No supplementary comments": "Aucun commentaire supplémentaire"
"Back to the list": "Retour à la liste"
"Edit": "Modifier"