7 Commits

Author SHA1 Message Date
AUDUL
0e52443830 Added possibility to create one shot job from scheduled job (#4) 2025-02-18 14:59:49 +01:00
jeremycr
a46d008cc6 Merge pull request #2 from code-rhapsodie/update-doc-screenshots
Update doc screenshots
2025-02-14 11:19:54 +01:00
Olivier Portier
3267c3bff8 Update doc screenshots 2025-02-14 11:11:25 +01:00
jeremycr
2f68d49f4b Merge pull request #1 from code-rhapsodie/date-picker
Replaced date field with date picker
2025-01-31 17:17:59 +01:00
Jérémy J
6be0993c98 Replaced date field with date picker 2025-01-31 17:17:11 +01:00
Jérémy J
28f76b279b Fixed scheduled job run history pagination 2024-12-18 11:12:45 +01:00
Jérémy J
d9b1a66f92 Added error count columns to job tables 2024-12-17 15:33:02 +01:00
27 changed files with 222 additions and 192 deletions

View File

@@ -1,3 +1,15 @@
# Version 4.4.0
* Added possibility to create one shot job from scheduled job
# Version 4.3.0
* Replaced date field with date picker
# Version 4.2.0
* Added error count columns to job tables
* Fixed scheduled job run history pagination
# Version 4.1.2
* Fix main menu label
@@ -14,56 +26,3 @@
# Version 4.0.0
* Add compatibility with Ibexa 4.0+ and drop compatibility for eZPlatform 2 and Ibexa 3
# Version 3.2.0
* Fixed History page pagination is hidden by footer on Ibexa 3.3 #38
* Added filter on history page to filter out jobs with 0 items
* Date and times will now be displayed using the user defined timezone, and stored using php timezone
# Version 3.1.0
* Allow `LocationCreateStruct` objects inside the `$locations` argument of `ContentCreateStructure` to have more control over the created locations.
# Version 3.0.1
* Bump minimum PHP version to PHP 7.3 like code-rhapsodie/dataflow-bundle dependency.
* Allow PHP 8.x.
* Add GitHub Action to run tests.
# Version 3.0.0
* Add compatibility with Ibexa Content 3.3
* Add compatibility with Symfony 5.x
# Version 2.3.0
* Added a button to display exceptions / log in a modal
* Add log in `CodeRhapsodie\EzDataflowBundle\Filter\NotModifiedContentFilter` and `CodeRhapsodie\EzDataflowBundle\Writer\ContentWriter`
# Version 2.2.0
* Added `NotModifiedContentFilter` and a bunch of `FieldComparator` classes
# version 2.1.0
* ContentWriter return created content
# version 2.0.1
* Enclosure js code into anonymous function
# version 2.0.0
* Update to use Dataflow v2.0+
* Add compiler pass to change the Dataflow DBAL connection factory
* Use the DBAL connection from siteaccess
* Add `mode` argument on `ContentStructureFactory::transform()` function
* Add `CodeRhapsodie\EzDataflowBundle\Factory\ContentStructureFactoryInterface`
# version 1.0.0
* Initial version to use Dataflow v1.0+ into eZ Platform
* Add Admin UI
* Add content writer
* Add content structure

View File

@@ -11,12 +11,9 @@ Ibexa Dataflow bundle is intended to manage content imports from external data s
> Command line notice: When you use Dataflow commands, **use `--siteaccess` instead of `--connection`** expect
> for `code-rhapsodie:dataflow:dump-schema` command.
| Ibexa Dataflow Version | Ibexa Content Version | Status |
|---------------------|-----------------------|------------------------------|
| 4.x | 4.x | :white_check_mark: Maintened |
| 3.x | 3.x | :white_check_mark: Maintened |
| 2.x | eZ Platform 2.5 | :x: Not maintened |
| 1.x | eZ Platform 2.5 | :x: Not maintained |
| Ibexa Dataflow Version | Ibexa Content Version | Status |
|------------------------|-----------------------|-------------------------------|
| 4.x | 4.x | :white_check_mark: Maintained |
## User Interface (UI)

View File

@@ -45,6 +45,7 @@
},
"require": {
"php": "^7.4||^8.0",
"ext-json": "*",
"code-rhapsodie/dataflow-bundle": "^3.0||^4.0",
"http-interop/http-factory-guzzle": "^1.2",
"ibexa/admin-ui": "^4.0",

View File

@@ -8,6 +8,8 @@ use CodeRhapsodie\DataflowBundle\Entity\Job;
use CodeRhapsodie\DataflowBundle\Entity\ScheduledDataflow;
use CodeRhapsodie\EzDataflowBundle\Form\CreateOneshotType;
use CodeRhapsodie\EzDataflowBundle\Form\CreateScheduledType;
use CodeRhapsodie\EzDataflowBundle\Form\UpdateScheduledType;
use CodeRhapsodie\EzDataflowBundle\Gateway\ExceptionJSONDecoderAdapter;
use CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway;
use CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway;
use Doctrine\DBAL\Query\QueryBuilder;
@@ -54,10 +56,12 @@ class DashboardController extends Controller
$form = $this->createForm(CreateScheduledType::class, $newWorkflow, [
'action' => $this->generateUrl('coderhapsodie.ezdataflow.workflow.create'),
]);
$updateForm = $this->createForm(UpdateScheduledType::class);
return $this->render('@ibexadesign/ezdataflow/Dashboard/repeating.html.twig', [
'pager' => $this->getPager($this->scheduledDataflowGateway->getListQueryForAdmin(), $request),
'form' => $form->createView(),
'update_form' => $updateForm->createView(),
]);
}
@@ -141,11 +145,15 @@ class DashboardController extends Controller
private function getPager(QueryBuilder $query, Request $request): Pagerfanta
{
$pager = new Pagerfanta(new QueryAdapter($query, function ($queryBuilder) {
return $queryBuilder->select('COUNT(DISTINCT id) AS total_results')
->resetQueryPart('orderBy')
->setMaxResults(1);
}));
$pager = new Pagerfanta(
new ExceptionJSONDecoderAdapter(
new QueryAdapter($query, function ($queryBuilder) {
return $queryBuilder->select('COUNT(DISTINCT id) AS total_results')
->resetQueryPart('orderBy')
->setMaxResults(1);
})
)
);
$pager->setMaxPerPage(20);
$pager->setCurrentPage($request->query->get('page', 1));

View File

@@ -7,12 +7,14 @@ namespace CodeRhapsodie\EzDataflowBundle\Controller;
use CodeRhapsodie\DataflowBundle\Entity\Job;
use CodeRhapsodie\EzDataflowBundle\Form\CreateOneshotType;
use CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway;
use CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway;
use Ibexa\Contracts\AdminUi\Controller\Controller;
use Ibexa\Contracts\AdminUi\Notification\NotificationHandlerInterface;
use Ibexa\Core\MVC\Symfony\Security\Authorization\Attribute;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
@@ -28,15 +30,19 @@ class JobController extends Controller
private $notificationHandler;
/** @var \Symfony\Contracts\Translation\TranslatorInterface */
private $translator;
/** @var \CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway */
private $scheduledDataflowGateway;
public function __construct(
JobGateway $jobGateway,
NotificationHandlerInterface $notificationHandler,
TranslatorInterface $translator
TranslatorInterface $translator,
ScheduledDataflowGateway $scheduledDataflowGateway
) {
$this->jobGateway = $jobGateway;
$this->notificationHandler = $notificationHandler;
$this->translator = $translator;
$this->scheduledDataflowGateway = $scheduledDataflowGateway;
}
/**
@@ -104,4 +110,37 @@ class JobController extends Controller
]),
]);
}
/**
* @Route("/run-oneshot/{id}", name="coderhapsodie.ezdataflow.job.run-oneshot", methods={"GET"})
*/
public function runOneShot(int $id): Response
{
$this->denyAccessUnlessGranted(new Attribute('ezdataflow', 'view'));
$scheduledDataflow = $this->scheduledDataflowGateway->find($id);
if ($scheduledDataflow === null) {
throw new NotFoundHttpException();
}
$newOneshotJob = new Job();
$newOneshotJob->setOptions($scheduledDataflow->getOptions());
$newOneshotJob->setLabel("Manual " . $scheduledDataflow->getLabel());
$newOneshotJob->setScheduledDataflowId($scheduledDataflow->getId());
$newOneshotJob->setRequestedDate((new \DateTime())->add(new \DateInterval('PT1H')));
$newOneshotJob->setDataflowType($scheduledDataflow->getDataflowType());
$form = $this->createForm(CreateOneshotType::class, $newOneshotJob, [
'action' => $this->generateUrl('coderhapsodie.ezdataflow.job.create'),
]);
return new JsonResponse([
'form' => $this->renderView('@ibexadesign/ezdataflow/parts/form_modal.html.twig', [
'form' => $form->createView(),
'id' => 'modal-new-oneshot',
'mode' => 'oneshot',
]),
]);
}
}

View File

@@ -31,7 +31,6 @@ class CreateOneshotType extends AbstractType
])
->add('requestedDate', UserTimezoneAwareDateTimeType::class, [
'label' => 'coderhapsodie.dataflow.requestedDate',
'years' => range(date('Y'), date('Y') + 5),
])
;
}

View File

@@ -38,7 +38,6 @@ class CreateScheduledType extends AbstractType
'label' => 'coderhapsodie.dataflow.frequency',
])
->add('next', UserTimezoneAwareDateTimeType::class, [
'years' => range(date('Y'), date('Y') + 5),
'label' => 'coderhapsodie.dataflow.create.next',
])
->add('enabled', CheckboxType::class, [

View File

@@ -32,7 +32,6 @@ class UpdateScheduledType extends AbstractType
'label' => 'coderhapsodie.dataflow.frequency',
])
->add('next', UserTimezoneAwareDateTimeType::class, [
'years' => range(date('Y'), date('Y') + 5),
'label' => 'coderhapsodie.dataflow.update.next',
])
;

View File

@@ -4,9 +4,9 @@ declare(strict_types=1);
namespace CodeRhapsodie\EzDataflowBundle\Form;
use Ibexa\AdminUi\Form\Type\DateTimePickerType;
use Ibexa\Contracts\Core\Repository\UserPreferenceService;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\FormBuilderInterface;
class UserTimezoneAwareDateTimeType extends AbstractType
@@ -21,7 +21,7 @@ class UserTimezoneAwareDateTimeType extends AbstractType
public function getParent()
{
return DateTimeType::class;
return DateTimePickerType::class;
}
public function buildForm(FormBuilderInterface $builder, array $options)

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace CodeRhapsodie\EzDataflowBundle\Gateway;
use Pagerfanta\Adapter\AdapterInterface;
class ExceptionJSONDecoderAdapter implements AdapterInterface
{
/** @var AdapterInterface */
private $adapter;
public function __construct(AdapterInterface $adapter)
{
$this->adapter = $adapter;
}
public function getNbResults()
{
return $this->adapter->getNbResults();
}
public function getSlice($offset, $length)
{
$slice = $this->adapter->getSlice($offset, $length);
array_walk($slice, static function (&$value) {
if (isset($value['exceptions'])) {
$value['exceptions'] = json_decode($value['exceptions'], true, 512, JSON_THROW_ON_ERROR);
}
});
return $slice;
}
}

View File

@@ -38,6 +38,7 @@ services:
$jobGateway: '@CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway'
$notificationHandler: '@Ibexa\Contracts\AdminUi\Notification\NotificationHandlerInterface'
$translator: '@translator'
$scheduledDataflowGateway: '@CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway'
calls:
- [ 'setContainer', [ '@service_container' ] ]
- [ 'performAccessCheck', [ ] ]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View File

@@ -16,12 +16,13 @@ coderhapsodie.ezdataflow.workflow.list.history: History
coderhapsodie.ezdataflow.workflow.list.edit: Edit
coderhapsodie.ezdataflow.workflow.list.disable: Disable
coderhapsodie.ezdataflow.workflow.list.enable: Enable
coderhapsodie.ezdataflow.workflow.list.runonce: Run now
coderhapsodie.ezdataflow.history.title: History
coderhapsodie.ezdataflow.history.list.title: 'Executions list'
coderhapsodie.ezdataflow.history.list.name: Name
coderhapsodie.ezdataflow.history.list.request: 'Requested on'
coderhapsodie.ezdataflow.history.list.count: 'Items count'
coderhapsodie.ezdataflow.history.list.error_count: 'Errors count'
coderhapsodie.ezdataflow.history.list.count: 'Number of successes'
coderhapsodie.ezdataflow.history.list.errors: 'Number of errors'
coderhapsodie.ezdataflow.history.list.start: 'Started on'
coderhapsodie.ezdataflow.history.list.end: 'Finished on'
coderhapsodie.ezdataflow.history.list.view: 'View details'

View File

@@ -16,12 +16,13 @@ coderhapsodie.ezdataflow.workflow.list.history: Historique
coderhapsodie.ezdataflow.workflow.list.edit: Éditer
coderhapsodie.ezdataflow.workflow.list.disable: Désactiver
coderhapsodie.ezdataflow.workflow.list.enable: Activer
coderhapsodie.ezdataflow.workflow.list.runonce: Lancer maintenant
coderhapsodie.ezdataflow.history.title: Historique
coderhapsodie.ezdataflow.history.list.title: 'Liste des exécutions'
coderhapsodie.ezdataflow.history.list.name: Nom
coderhapsodie.ezdataflow.history.list.request: 'Demandé le'
coderhapsodie.ezdataflow.history.list.count: 'Nombre d''objets'
coderhapsodie.ezdataflow.history.list.error_count: 'Nombre d''erreurs'
coderhapsodie.ezdataflow.history.list.count: 'Nombre de succès'
coderhapsodie.ezdataflow.history.list.errors: 'Nombre d''erreurs'
coderhapsodie.ezdataflow.history.list.start: 'Commencé le'
coderhapsodie.ezdataflow.history.list.end: 'Terminé le'
coderhapsodie.ezdataflow.history.list.view: 'Voir le détail'

View File

@@ -43,14 +43,17 @@
e.preventDefault();
const loading = document.getElementById('loading_ezdataflow_history_results');
const results = document.getElementById('ezdataflow_history_results').querySelector('.ibexa-table');
const pagination = document.getElementById('ezdataflow_history_results').querySelector('.pag');
loading.hidden = false;
results.innerHTML = '';
pagination.innerHTML = '';
fetch('{{ path('coderhapsodie.ezdataflow.history') }}?filter=' + this.value)
.then((r) => r.text())
.then((content) => {
const node = document.createElement('div');
node.innerHTML = content;
results.innerHTML = node.querySelector('#ezdataflow_history_results .ibexa-table').innerHTML;
pagination.innerHTML = node.querySelector('#ezdataflow_history_results .pag').innerHTML;
loading.hidden = true;
})
;

View File

@@ -71,6 +71,33 @@
.closest('ul').querySelectorAll('li.ibexa-tabs__tab');
const tabs = document.getElementById('ibexa-tab-coderhapsodie-ezdataflow-code-rhapsodie-ezdataflow-repeating')
.closest('.tab-content').querySelectorAll('.tab-pane');
// Manage ajax pagination
document.addEventListener('click', (e) => {
const link = e.target.closest('.ibexa-pagination a');
if (!link) {
return;
}
const block = link.closest('.ibexa-pagination').parentNode.parentNode;
const display = block.querySelector('.ibexa-table');
const pagination = block.querySelector('.pag');
const loader = document.querySelector('#' + block.dataset.loader);
e.preventDefault();
loader.hidden = false;
display.innerHTML = '';
pagination.innerHTML = '';
fetch(link.href)
.then((r) => r.text())
.then((content) => {
const node = document.createElement('div');
node.innerHTML = content;
display.innerHTML = node.querySelector('#' + block.id).querySelector('.ibexa-table').innerHTML;
pagination.innerHTML = node.querySelector('#' + block.id).querySelector('.pag').innerHTML;
loader.hidden = true;
})
;
});
});
</script>
{% endblock %}

View File

@@ -1,10 +1,11 @@
{%- block content -%}
{% set actions %}
<button
type="button"
class="btn ibexa-btn ibexa-btn--tertiary ibexa-btn--small"
data-bs-toggle="modal"
data-bs-target="#modal-new-oneshot"
id="create-oneshot-button"
type="button"
class="btn ibexa-btn ibexa-btn--tertiary ibexa-btn--small"
data-bs-toggle="modal"
data-bs-target="#modal-new-oneshot"
>
<svg class="ibexa-icon ibexa-icon--small ibexa-icon--create">
<use xlink:href="{{ ibexa_icon_path('create') }}"></use>
@@ -53,6 +54,16 @@
})
;
});
const createButton = document.getElementById('create-oneshot-button')
if (createButton) {
createButton.addEventListener('click', () => {
const oneShotModal = document.getElementById('modal-new-oneshot');
oneShotModal.querySelector('#create_oneshot_label').value = '';
oneShotModal.querySelector('#create_oneshot_options').value = '';
oneShotModal.querySelector('.flatpickr.flatpickr-input').parentNode.parentNode.ibexaInstance.flatpickrInstance.setDate(new Date(), true);
});
}
});
</script>
{%- endblock -%}

View File

@@ -1,4 +1,5 @@
{%- block content -%}
{% form_theme update_form '@ibexadesign/ezdataflow/form_theme.html.twig' %}
{{ include('@ibexadesign/ezdataflow/parts/tab/schedule_list.html.twig', {
identifier: 'ezdataflow_schedule_results',
@@ -15,10 +16,12 @@
title: 'coderhapsodie.ezdataflow.workflow.repeating.edit.title'|trans,
} %}
{% block body_content %}
<form action="" method="post">
<div class="form-fields"></div>
{{ form_start(update_form) }}
<div class="form-fields">
{{ form_widget(update_form) }}
</div>
<button id="modal-edit-submit" type="submit" hidden />
</form>
{{ form_end(update_form) }}
{% endblock %}
{% block footer_content %}
<button type="button" class="btn ibexa-btn ibexa-btn--primary ibexa-btn--trigger" data-click="#modal-edit-submit">
@@ -52,50 +55,6 @@
<script>
document.addEventListener('DOMContentLoaded', () => {
// $('#ez-modal--edit-scheduled').modal({keyboard: true, show: false});
// $('.modal-edit').each(function (index, elem) {
// $(elem).click(function (e) {
// e.preventDefault();
// $('#schedule_edit').html('');
// $('#ez-modal--edit-scheduled').modal('show');
// $.ajax(elem.href, {
// success: function (result) {
// if (result.redirect) {
// if (window.location.href === result.redirect) {
// window.location.reload();
// }
// window.location = result.redirect;
// window.location.reload();
// return;
// }
//
// $('#schedule_edit').html(result.form);
// }
// });
// });
// });
//
// $('#ez-modal--edit-scheduled').on('submit', 'form', function (e) {
// e.preventDefault();
// url = $(this).attr('action');
// data = new FormData(this);
// $.ajax({
// 'type': 'POST',
// 'url': url,
// 'data': data,
// processData: false,
// contentType: false,
// success: function (result) {
// if (result.redirect) {
// window.location = result.redirect;
// return;
// }
//
// $('#schedule_edit').html(result.form);
// }
// });
// });
const bindFormSubmit = (modalId) => {
document.querySelector('#'+modalId+' form').addEventListener('submit', function (e) {
e.preventDefault();
@@ -134,7 +93,13 @@
const node = document.createElement('div');
node.innerHTML = result.form;
editModal.querySelector('form').action = link.href;
editModal.querySelector('.form-fields').innerHTML = node.querySelector('.form-fields').innerHTML;
editModal.querySelector('#update_scheduled_label').value = node.querySelector('#update_scheduled_label').value;
editModal.querySelector('#update_scheduled_options').value = node.querySelector('#update_scheduled_options').value;
editModal.querySelector('#update_scheduled_frequency').value = node.querySelector('#update_scheduled_frequency').value;
editModal.querySelector('#update_scheduled_next').parentNode.parentNode.ibexaInstance.flatpickrInstance.setDate(
new Date(node.querySelector('#update_scheduled_next').value * 1000),
true
);
})
;

View File

@@ -9,7 +9,7 @@
</svg>
</div>
<div id="{{ id }}" class="history-details-aware">
<div id="{{ id }}" data-loader="loading_{{ id }}" class="history-details-aware">
{% set body_rows = [] %}
@@ -19,6 +19,7 @@
{content: job.label},
{content: date(job.requested_date)|ibexa_short_datetime},
{content: job.count|default('—')},
{content: job.exceptions|length},
{content: job.start_time ? date(job.start_time)|ibexa_short_datetime : '—'},
{content: job.end_time ? date(job.end_time)|ibexa_short_datetime : '—'},
{content: macros.translateStatus(job.status)},
@@ -61,6 +62,7 @@
{ content: 'coderhapsodie.ezdataflow.history.list.name'|trans },
{ content: 'coderhapsodie.ezdataflow.history.list.request'|trans },
{ content: 'coderhapsodie.ezdataflow.history.list.count'|trans },
{ content: 'coderhapsodie.ezdataflow.history.list.errors'|trans },
{ content: 'coderhapsodie.ezdataflow.history.list.start'|trans },
{ content: 'coderhapsodie.ezdataflow.history.list.end'|trans },
{ content: 'coderhapsodie.ezdataflow.history.list.status'|trans },
@@ -78,40 +80,15 @@
{% endblock %}
{% endembed %}
{% if pager.haveToPaginate %}
{% include '@ibexadesign/ui/pagination.html.twig' with {
'pager': pager,
'paginaton_params': {
'routeName': paginate_route,
'routeParams': paginate_params|default({})
}
} %}
{% endif %}
<div class="pag">
{% if pager.haveToPaginate %}
{% include '@ibexadesign/ui/pagination.html.twig' with {
'pager': pager,
'paginaton_params': {
'routeName': paginate_route,
'routeParams': paginate_params|default({})
}
} %}
{% endif %}
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Manage ajax pagination
const display = document.getElementById('{{ id }}');
display.addEventListener('click', (e) => {
const link = e.target.closest('.ibexa-pagination a');
if (!link) {
return;
}
const loader = document.getElementById('loading_{{ id }}');
e.preventDefault();
loader.hidden = false;
display.innerHTML = '';
fetch(link.href)
.then((r) => r.text())
.then((content) => {
const node = document.createElement('div');
node.innerHTML = content;
display.innerHTML = node.querySelector('#{{ id }}').innerHTML;
loader.hidden = true;
})
;
});
});
</script>

View File

@@ -7,7 +7,7 @@
</svg>
</div>
<div id="{{ id }}" class="history-details-aware">
<div id="{{ id }}" data-loader="loading_{{ id }}" class="history-details-aware">
{% set body_rows = [] %}
{% for item in pager.currentPageResults %}
@@ -40,6 +40,15 @@
<use xlink:href="{{ ibexa_icon_path('edit') }}"></use>
</svg>
</a>
<button
class="btn ibexa-btn ibexa-btn--ghost run-oneshot ibexa-btn--no-text"
data-url="{{ path('coderhapsodie.ezdataflow.job.run-oneshot', {id: item.id}) }}"
title="{{ 'coderhapsodie.ezdataflow.workflow.list.runonce'|trans }}"
>
<svg class="ibexa-icon ibexa-icon--small ibexa-icon--create">
<use xlink:href="{{ ibexa_icon_path('create') }}"></use>
</svg>
</button>
{% if item.enabled %}
<a href="{{ path('coderhapsodie.ezdataflow.workflow.disable', {id: item.id}) }}"
class="btn ibexa-btn ibexa-btn--ghost ibexa-btn--no-text"
@@ -113,40 +122,39 @@
{% endblock %}
{% endembed %}
{% if pager.haveToPaginate %}
{% include '@ibexadesign/ui/pagination.html.twig' with {
'pager': pager,
'paginaton_params': {
'routeName': paginate_route,
'routeParams': paginate_params|default({})
}
} %}
{% endif %}
<div class="pag">
{% if pager.haveToPaginate %}
{% include '@ibexadesign/ui/pagination.html.twig' with {
'pager': pager,
'paginaton_params': {
'routeName': paginate_route,
'routeParams': paginate_params|default({})
}
} %}
{% endif %}
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Manage ajax pagination
const display = document.getElementById('{{ id }}');
display.addEventListener('click', (e) => {
const link = e.target.closest('.ibexa-pagination a');
if (!link) {
return;
}
document.querySelectorAll(".run-oneshot").forEach((el) => {
el.addEventListener('click', () => {
const oneShotModal = document.getElementById('modal-new-oneshot');
const loader = document.getElementById('loading_{{ id }}');
e.preventDefault();
loader.hidden = false;
display.innerHTML = '';
fetch(link.href)
.then((r) => r.text())
.then((content) => {
fetch(el.getAttribute('data-url'))
.then(response => response.json())
.then(result => {
const node = document.createElement('div');
node.innerHTML = content;
display.innerHTML = node.querySelector('#{{ id }}').innerHTML;
loader.hidden = true;
node.innerHTML = result.form;
oneShotModal.querySelector('#create_oneshot_label').value = node.querySelector('#create_oneshot_label').value;
oneShotModal.querySelector('#create_oneshot_options').value = node.querySelector('#create_oneshot_options').value;
oneShotModal.querySelector('.ibexa-dropdown').ibexaInstance.selectOption(node.querySelector('#create_oneshot_dataflowType').value)
oneShotModal.querySelector('.flatpickr.flatpickr-input').parentNode.parentNode.ibexaInstance.flatpickrInstance.setDate(new Date(), true);
})
;
.then(() => {
bootstrap.Tab.getOrCreateInstance(document.querySelector('#ibexa-tab-label-coderhapsodie-ezdataflow-code-rhapsodie-ezdataflow-oneshot')).show()
bootstrap.Modal.getOrCreateInstance(oneShotModal).show()
})
});
});
</script>