Skip to content

Commit e8a4c26

Browse files
#13 ability to add modal confirmation or nothing instead of launch from of process run ui.
1 parent 16d92bb commit e8a4c26

File tree

8 files changed

+190
-13
lines changed

8 files changed

+190
-13
lines changed

config/services/twig.yaml

+20
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ services:
1717
tags:
1818
- { name: 'twig.extension' }
1919

20+
cleverage_ui_process.twig.process_extension:
21+
class: CleverAge\UiProcessBundle\Twig\Extension\ProcessExtension
22+
public: false
23+
tags:
24+
- { name: 'twig.extension' }
25+
2026
cleverage_ui_process.twig.log_level_extension_runtime:
2127
class: CleverAge\UiProcessBundle\Twig\Runtime\LogLevelExtensionRuntime
2228
public: false
@@ -37,3 +43,17 @@ services:
3743
arguments:
3844
- '@cleverage_ui_process.repository.process_execution'
3945
- '@cleverage_ui_process.manager.process_configuration'
46+
47+
cleverage_ui_process.twig.process_extension_runtime:
48+
class: CleverAge\UiProcessBundle\Twig\Runtime\ProcessExtensionRuntime
49+
public: false
50+
tags:
51+
- { name: 'twig.runtime' }
52+
arguments:
53+
- '@cleverage_ui_process.manager.process_configuration'
54+
55+
cleverage_ui_process.twig.component.bootstrap_modal:
56+
class: CleverAge\UiProcessBundle\Twig\Components\BootstrapModal
57+
shared: false
58+
tags:
59+
- { name: 'twig.component', key: 'ui:BootstrapModal', template: '@CleverAgeUiProcess/components/BootstrapModal.html.twig' }

src/Controller/Admin/Process/LaunchAction.php

+35-10
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace CleverAge\UiProcessBundle\Controller\Admin\Process;
1515

16+
use CleverAge\ProcessBundle\Exception\MissingProcessException;
1617
use CleverAge\UiProcessBundle\Entity\User;
1718
use CleverAge\UiProcessBundle\Form\Type\LaunchType;
1819
use CleverAge\UiProcessBundle\Manager\ProcessConfigurationsManager;
@@ -39,20 +40,36 @@
3940
#[IsGranted('ROLE_USER')]
4041
class LaunchAction extends AbstractController
4142
{
43+
public function __construct(private readonly MessageBusInterface $messageBus)
44+
{
45+
}
46+
4247
public function __invoke(
4348
RequestStack $requestStack,
44-
MessageBusInterface $messageBus,
4549
string $uploadDirectory,
4650
ProcessConfigurationsManager $processConfigurationsManager,
4751
AdminContext $context,
4852
): Response {
49-
$uiOptions = $processConfigurationsManager->getUiOptions($requestStack->getMainRequest()?->get('process') ?? '');
53+
$processCode = $requestStack->getMainRequest()?->get('process');
54+
if (null === $processCode) {
55+
throw new MissingProcessException();
56+
}
57+
$uiOptions = $processConfigurationsManager->getUiOptions($processCode);
58+
if (false === $uiOptions['input_context_launcher_form']) {
59+
$this->dispatch($processCode);
60+
$this->addFlash(
61+
'success',
62+
'Process has been added to queue. It will start as soon as possible'
63+
);
64+
65+
return $this->redirectToRoute('process', ['routeName' => 'process_list']);
66+
}
5067
$form = $this->createForm(
5168
LaunchType::class,
5269
null,
5370
[
5471
'constraints' => $uiOptions['constraints'] ?? [],
55-
'process_code' => $requestStack->getMainRequest()?->get('process'),
72+
'process_code' => $processCode,
5673
]
5774
);
5875
if (false === $form->isSubmitted()) {
@@ -72,16 +89,11 @@ public function __invoke(
7289
(new Filesystem())->dumpFile($filename, $input->getContent());
7390
$input = $filename;
7491
}
75-
76-
$message = new ProcessExecuteMessage(
92+
$this->dispatch(
7793
$form->getConfig()->getOption('process_code'),
7894
$input,
79-
array_merge(
80-
['execution_user' => $this->getUser()?->getEmail()],
81-
$form->get('context')->getData()
82-
)
95+
$form->get('context')->getData()
8396
);
84-
$messageBus->dispatch($message);
8597
$this->addFlash(
8698
'success',
8799
'Process has been added to queue. It will start as soon as possible'
@@ -99,6 +111,19 @@ public function __invoke(
99111
);
100112
}
101113

114+
protected function dispatch(string $processCode, mixed $input = null, array $context = []): void
115+
{
116+
$message = new ProcessExecuteMessage(
117+
$processCode,
118+
$input,
119+
array_merge(
120+
['execution_user' => $this->getUser()?->getEmail()],
121+
$context
122+
)
123+
);
124+
$this->messageBus->dispatch($message);
125+
}
126+
102127
protected function getUser(): ?User
103128
{
104129
/** @var User $user */

src/Manager/ProcessConfigurationsManager.php

+4
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ private function resolveUiOptions(array $options): array
5757
'source' => null,
5858
'target' => null,
5959
'entrypoint_type' => 'text',
60+
'input_context_launcher_form' => false,
61+
'run_confirmation_modal' => false,
6062
'constraints' => [],
6163
'run' => null,
6264
'default' => function (OptionsResolver $defaultResolver) {
@@ -76,6 +78,8 @@ private function resolveUiOptions(array $options): array
7678
);
7779
$uiResolver->setAllowedValues('entrypoint_type', ['text', 'file']);
7880
$uiResolver->setNormalizer('constraints', fn (Options $options, array $values): array => (new ConstraintLoader())->buildConstraints($values));
81+
$uiResolver->setAllowedTypes('input_context_launcher_form', ['bool']);
82+
$uiResolver->setAllowedTypes('run_confirmation_modal', ['bool']);
7983
});
8084

8185
return $resolver->resolve($options);
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the CleverAge/UiProcessBundle package.
5+
*
6+
* Copyright (c) Clever-Age
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace CleverAge\UiProcessBundle\Twig\Components;
13+
14+
class BootstrapModal
15+
{
16+
public ?string $id = null;
17+
public ?string $title = null;
18+
public ?string $message = null;
19+
public ?string $confirmUrl = null;
20+
}
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the CleverAge/UiProcessBundle package.
7+
*
8+
* Copyright (c) Clever-Age
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace CleverAge\UiProcessBundle\Twig\Extension;
15+
16+
use CleverAge\UiProcessBundle\Twig\Runtime\ProcessExtensionRuntime;
17+
use Twig\Extension\AbstractExtension;
18+
use Twig\TwigFunction;
19+
20+
class ProcessExtension extends AbstractExtension
21+
{
22+
public function getFunctions(): array
23+
{
24+
return [
25+
new TwigFunction(
26+
'resolve_ui_options',
27+
[ProcessExtensionRuntime::class, 'getUiOptions']
28+
),
29+
];
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the CleverAge/UiProcessBundle package.
5+
*
6+
* Copyright (c) Clever-Age
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace CleverAge\UiProcessBundle\Twig\Runtime;
13+
14+
use CleverAge\UiProcessBundle\Manager\ProcessConfigurationsManager;
15+
use Twig\Extension\RuntimeExtensionInterface;
16+
17+
class ProcessExtensionRuntime implements RuntimeExtensionInterface
18+
{
19+
public function __construct(protected ProcessConfigurationsManager $processConfigurationsManager)
20+
{
21+
}
22+
23+
public function getUiOptions(string $code): array
24+
{
25+
return $this->processConfigurationsManager->getUiOptions($code) ?? [];
26+
}
27+
}

templates/admin/process/list.html.twig

+16-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
{# @var process \CleverAge\ProcessBundle\Configuration\ProcessConfiguration #}
2222
{% for process in processes %}
2323
{% set lastExecution = get_last_execution_date(process.code) %}
24+
{% set uiOptions = resolve_ui_options(process.code) %}
2425
{% set statusClass = '' %}
2526
{% if lastExecution is not null %}
2627
{% set statusClass = lastExecution.status.value == 'failed' ? 'danger' : 'success' %}
@@ -32,9 +33,15 @@
3233
<td>{% if process.options.ui.source is defined %}{{ process.options.ui.source }}{% endif %}</td>
3334
<td>{% if process.options.ui.target is defined %}{{ process.options.ui.target }}{% endif %}</td>
3435
<td class="text-center">
35-
<a class="px-1" data-toggle="tooltip" data-placement="top" title="{{ 'Launch'|trans }}" href="{{ url('process', {routeName: 'process_launch', process: process.code}) }}">
36-
<i class="fas fa-rocket"></i>
37-
</a>
36+
{% if (false == uiOptions.input_context_launcher_form and true == uiOptions.run_confirmation_modal) %}
37+
<a class="px-1" data-toggle="tooltip" data-placement="top" title="{{ 'Launch'|trans }}" data-bs-toggle="modal" data-bs-target="#{{ process.code }}">
38+
<i class="fas fa-rocket"></i>
39+
</a>
40+
{% else %}
41+
<a class="px-1" data-toggle="tooltip" data-placement="top" title="{{ 'Launch'|trans }}" href="{{ url('process', {routeName: 'process_launch', process: process.code}) }}">
42+
<i class="fas fa-rocket"></i>
43+
</a>
44+
{% endif %}
3845
<a
3946
class="px-1"
4047
data-toggle="tooltip"
@@ -58,6 +65,12 @@
5865
</a>
5966
</td>
6067
</tr>
68+
<twig:ui:BootstrapModal
69+
id="{{ process.code }}"
70+
title="{{ 'Run process'|trans }} {{ process.code }}"
71+
message="{{ 'Do you really want to run process %process% in background'|trans({'%process%': process.code}) }} ?"
72+
confirmUrl="{{ url('process', {routeName: 'process_launch', process: process.code}) }}"
73+
/>
6174
{% endfor %}
6275
{% endblock %}
6376
</tbody>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<div {{ attributes.defaults({
2+
class: 'modal fade',
3+
tabindex: '-1',
4+
'aria-hidden': 'true',
5+
id: id ? id : false,
6+
}) }}
7+
data-controller="bootstrap-modal"
8+
>
9+
<div class="modal-dialog">
10+
<div class="modal-content">
11+
{% block modal_full_content %}
12+
{% if block('modal_header') %}
13+
<div class="modal-header text-center">
14+
{% block modal_header %}
15+
<h5>{{ title }}</h5>
16+
{% endblock %}
17+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
18+
</div>
19+
{% endif %}
20+
21+
<div class="modal-body">
22+
{% block modal_body %}{{ message }}{% endblock %}
23+
</div>
24+
25+
{% if block('modal_footer') %}
26+
<div class="modal-footer">
27+
{% block modal_footer %}
28+
{% if null != confirmUrl %}
29+
<a href="{{ confirmUrl }}"><button type="button" class="btn btn-primary">{{ 'Confirm'|trans }}</button></a>
30+
{% endif %}
31+
{% endblock %}
32+
</div>
33+
{% endif %}
34+
{% endblock %}
35+
</div>
36+
</div>
37+
</div>

0 commit comments

Comments
 (0)