Merge branch 'feature/ws' into develop
This commit is contained in:
commit
07ab45ce29
|
@ -6,19 +6,25 @@ module.exports = function() {
|
|||
e.stopPropagation();
|
||||
|
||||
let container = $('#modal-container');
|
||||
const body = $('body')
|
||||
|
||||
if (!container.length) {
|
||||
container = $('<div id="modal-container" class="modal">');
|
||||
|
||||
$('body').append(container);
|
||||
body.append(container);
|
||||
}
|
||||
|
||||
container.html('');
|
||||
const loader = $('<div style="position: absolute; top: 25vh; left: 50vw; z-index: 2000">')
|
||||
loader.html('<div class="spinner-border text-primary" role="status"><span class="sr-only">Loading...</span></div>')
|
||||
body.append(loader)
|
||||
|
||||
container.html();
|
||||
|
||||
const url = $(e.target).attr('data-modal');
|
||||
$(container).modal('show');
|
||||
|
||||
container.load(url, function() {
|
||||
$(container).modal('show');
|
||||
loader.remove()
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ use Symfony\Component\HttpKernel\KernelInterface;
|
|||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\HttpClient\Exception\ClientException;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* class SymfonyCacheManager.
|
||||
|
@ -51,11 +52,14 @@ class SymfonyCacheManager
|
|||
}
|
||||
}
|
||||
|
||||
public function cleanAll()
|
||||
public function cleanAll(OutputInterface $output = null)
|
||||
{
|
||||
$application = new Application($this->kernel);
|
||||
$application->setAutoExit(false);
|
||||
$output = new BufferedOutput();
|
||||
|
||||
if (null === $output) {
|
||||
$output = new BufferedOutput();
|
||||
}
|
||||
|
||||
$input = new ArrayInput([
|
||||
'command' => 'cache:clear',
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Controller\Task;
|
||||
|
||||
use App\Core\Controller\Admin\AdminController;
|
||||
use App\Core\Event\Task\TaskInitEvent;
|
||||
use App\Core\Event\Task\TaskRunRequestedEvent;
|
||||
use Symfony\Component\Console\Output\BufferedOutput;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
/**
|
||||
* @Route("/admin/task")
|
||||
*/
|
||||
class TaskAdminController extends AdminController
|
||||
{
|
||||
/**
|
||||
* @Route("/", name="admin_task_index")
|
||||
*/
|
||||
public function index(EventDispatcherInterface $eventDispatcher): Response
|
||||
{
|
||||
$event = new TaskInitEvent();
|
||||
$eventDispatcher->dispatch($event, TaskInitEvent::INIT_EVENT);
|
||||
|
||||
return $this->render('@Core/task/task_admin/index.html.twig', [
|
||||
'pager' => $event->getTasks(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/run/{task}", name="admin_task_run", methods={"GET"})
|
||||
*/
|
||||
public function run(
|
||||
string $task,
|
||||
Request $request,
|
||||
EventDispatcherInterface $eventDispatcher
|
||||
): Response {
|
||||
if (!$this->isCsrfTokenValid('task_run', $request->query->get('_token'))) {
|
||||
throw $this->createAccessDeniedException();
|
||||
}
|
||||
|
||||
$output = new BufferedOutput();
|
||||
$event = new TaskRunRequestedEvent($task, $request->query, $output);
|
||||
$eventDispatcher->dispatch($event, TaskRunRequestedEvent::RUN_REQUEST_EVENT);
|
||||
|
||||
$content = $output->fetch();
|
||||
|
||||
return $this->render('@Core/task/task_admin/run.html.twig', [
|
||||
'output' => $content,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getSection(): string
|
||||
{
|
||||
return 'task';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Event\Task;
|
||||
|
||||
use Symfony\Contracts\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* class TaskInitEvent.
|
||||
*
|
||||
* @author Simon Vieille <simon@deblan.fr>
|
||||
*/
|
||||
class TaskInitEvent extends Event
|
||||
{
|
||||
const INIT_EVENT = 'task_event.init';
|
||||
|
||||
protected array $tasks = [];
|
||||
|
||||
public function getTasks(): array
|
||||
{
|
||||
usort($this->tasks, function ($t1, $t2) {
|
||||
return $t1['section'] != $t2['section'];
|
||||
});
|
||||
|
||||
return $this->tasks;
|
||||
}
|
||||
|
||||
public function addTask(string $task, string $label, string $section): self
|
||||
{
|
||||
$this->tasks[$task] = [
|
||||
'label' => $label,
|
||||
'section' => $section,
|
||||
'task' => $task,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Event\Task;
|
||||
|
||||
use Symfony\Component\Console\Output\BufferedOutput;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\HttpFoundation\InputBag;
|
||||
use Symfony\Contracts\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* class TaskRunRequestedEvent.
|
||||
*
|
||||
* @author Simon Vieille <simon@deblan.fr>
|
||||
*/
|
||||
class TaskRunRequestedEvent extends Event
|
||||
{
|
||||
const RUN_REQUEST_EVENT = 'task_event.run_request';
|
||||
|
||||
protected string $task;
|
||||
protected InputBag $parameters;
|
||||
protected BufferedOutput $output;
|
||||
|
||||
public function __construct(string $task, InputBag $parameters, BufferedOutput $output)
|
||||
{
|
||||
$this->task = $task;
|
||||
$this->parameters = $parameters;
|
||||
$this->output = $output;
|
||||
}
|
||||
|
||||
public function getTask(): string
|
||||
{
|
||||
return $this->task;
|
||||
}
|
||||
|
||||
public function getParameters(): ParameterBagInterface
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
public function getOutput(): BufferedOutput
|
||||
{
|
||||
return $this->output;
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
|||
*
|
||||
* @author Simon Vieille <simon@deblan.fr>
|
||||
*/
|
||||
class SettingEventSubscriber implements EventSubscriberInterface
|
||||
abstract class SettingEventSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
protected static int $priority = 0;
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\EventSuscriber\Task;
|
||||
|
||||
use App\Core\Cache\SymfonyCacheManager;
|
||||
use App\Core\Event\Task\TaskInitEvent;
|
||||
use App\Core\Event\Task\TaskRunRequestedEvent;
|
||||
|
||||
/**
|
||||
* class CacheCleanTaskEventSubscriber.
|
||||
*
|
||||
* @author Simon Vieille <simon@deblan.fr>
|
||||
*/
|
||||
class CacheCleanTaskEventSubscriber extends TaskEventSubscriber
|
||||
{
|
||||
protected SymfonyCacheManager $cacheManager;
|
||||
|
||||
public function __construct(SymfonyCacheManager $cacheManager)
|
||||
{
|
||||
$this->cacheManager = $cacheManager;
|
||||
}
|
||||
|
||||
public function onInit(TaskInitEvent $event)
|
||||
{
|
||||
$event->addTask('cache:clear', 'Clean all cache', '♻️ Cache');
|
||||
}
|
||||
|
||||
public function onRunRequest(TaskRunRequestedEvent $event)
|
||||
{
|
||||
if ('cache:clear' !== $event->getTask()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cacheManager->cleanAll($event->getOutput());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\EventSuscriber\Task;
|
||||
|
||||
use App\Core\Event\Task\TaskInitEvent;
|
||||
use App\Core\Event\Task\TaskRunRequestedEvent;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
/**
|
||||
* class TaskEventSubscriber.
|
||||
*
|
||||
* @author Simon Vieille <simon@deblan.fr>
|
||||
*/
|
||||
abstract class TaskEventSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
protected static int $priority = 0;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
TaskInitEvent::INIT_EVENT => ['onInit', self::$priority],
|
||||
TaskRunRequestedEvent::RUN_REQUEST_EVENT => ['onRunRequest', self::$priority],
|
||||
];
|
||||
}
|
||||
|
||||
public function onInit(TaskInitEvent $event)
|
||||
{
|
||||
}
|
||||
|
||||
public function onRunRequest(TaskRunRequestedEvent $event)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -153,3 +153,7 @@
|
|||
"Regular expression: do not add the delimiter": "Expréssion régulière : ne pas ajouter de délimiteur"
|
||||
"Content type": "Type de contenu"
|
||||
'Leave blank equals "text/html"': 'Laissez vide équivaut à "text/html"'
|
||||
"Close": "Fermer"
|
||||
"Tasks": "Tâches"
|
||||
"Results": "Résultats"
|
||||
"Clean all cache": "Nettoyer tout le cache"
|
||||
|
|
|
@ -68,6 +68,16 @@
|
|||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ macros_menu.active_class('task', section) }}" href="{{ path('admin_task_index') }}">
|
||||
<span class="fa fa-play"></span>
|
||||
|
||||
<span class="nav-item-label">
|
||||
{{ 'Tasks'|trans }}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ macros_menu.active_class('setting', section) }}" href="{{ path('admin_setting_index') }}">
|
||||
<span class="fa fa-sliders-h"></span>
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ form_widget(form) }}
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,56 @@
|
|||
{% extends '@Core/admin/layout.html.twig' %}
|
||||
|
||||
{% block title %}{{ 'Tasks'|trans }} - {{ parent() }}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="bg-light pl-5 pr-4 pt-5 pb-5">
|
||||
<div class="crud-header">
|
||||
<h1 class="crud-header-title">{{ 'Tasks'|trans }}</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th class="col-5">{{ 'Label'|trans }}</th>
|
||||
<th class="col-5">{{ 'Section'|trans }}</th>
|
||||
<th class="col-2 miw-100 text-right">{{ 'Actions'|trans }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in pager %}
|
||||
{% set run = path('admin_task_run', {
|
||||
task: item.task,
|
||||
_token: csrf_token('task_run')
|
||||
}) %}
|
||||
|
||||
<tr>
|
||||
<td class="col-5">
|
||||
{{ item.label|trans }}
|
||||
</td>
|
||||
<td class="col-5">
|
||||
<span class="btn btn-light">{{ item.section|trans }}</span>
|
||||
</td>
|
||||
<td class="col-2 miw-100 text-right">
|
||||
<span data-modal="{{ run }}" class="btn btn-sm btn-primary mr-1">
|
||||
<span data-modal="{{ run }}" class="fa fa-play"></span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td class="col-12 text-center p-4 text-black-50" colspan="3">
|
||||
<div class="display-1">
|
||||
<span class="fa fa-search"></span>
|
||||
</div>
|
||||
<div class="display-5 mt-3">
|
||||
{{ 'No result'|trans }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -2,20 +2,18 @@
|
|||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">
|
||||
{{ 'Filter'|trans }}
|
||||
{{ 'Results'|trans }}
|
||||
</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form action="{{ path('admin_site_page_index') }}" id="form-filters" method="GET">
|
||||
{{ form_widget(form) }}
|
||||
</form>
|
||||
<pre>{{ output|trim }}</pre>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="{{ path('admin_site_page_index', {page_filter: 0}) }}" class="btn btn-secondary">{{ 'Vider'|trans }}</a>
|
||||
<button type="submit" form="form-filters" class="btn btn-primary">{{ 'Filter'|trans }}</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ 'Close'|trans }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue