From 3cd7dd7436b6fa3bbe3445a95b7fe9ee9ef6b72f Mon Sep 17 00:00:00 2001 From: Fedik Date: Fri, 2 Feb 2024 14:58:44 +0200 Subject: [PATCH] Dialog for scheduler run task --- .../com_scheduler/tmpl/tasks/default.php | 25 +-- .../com_scheduler/joomla.asset.json | 3 +- .../js/admin-view-run-test-task.es6.js | 190 +++++++++++------- 3 files changed, 121 insertions(+), 97 deletions(-) diff --git a/administrator/components/com_scheduler/tmpl/tasks/default.php b/administrator/components/com_scheduler/tmpl/tasks/default.php index 9a04f76691ff3..e2ecc581c7736 100644 --- a/administrator/components/com_scheduler/tmpl/tasks/default.php +++ b/administrator/components/com_scheduler/tmpl/tasks/default.php @@ -24,7 +24,7 @@ /** @var HtmlView $this*/ /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ -$wa = $this->document->getWebAssetManager(); +$wa = $this->getDocument()->getWebAssetManager(); $wa->useScript('table.columns') ->useScript('multiselect') ->useScript('com_scheduler.test-task') @@ -42,6 +42,7 @@ Text::script('JLIB_JS_AJAX_ERROR_TIMEOUT'); Text::script('JLIB_JS_AJAX_ERROR_NO_CONTENT'); Text::script('JLIB_JS_AJAX_ERROR_PARSE'); +Text::script('JCLOSE'); try { /** @var CMSWebApplicationInterface $app */ @@ -62,8 +63,6 @@ $saveOrderingUrl = 'index.php?option=com_scheduler&task=tasks.saveOrderAjax&tmpl=component&' . Session::getFormToken() . '=1'; HTMLHelper::_('draggablelist.draggable'); } - -$this->document->addScriptOptions('com_scheduler.test-task.token', Session::getFormToken()); ?>
- @@ -268,20 +270,7 @@ class="js-draggable" data-url="" data-direction=" - pagination->getListFooter(); - - // Modal for test runs - $modalparams = [ - 'title' => '', - ]; - - $modalbody = '
'; - - echo HTMLHelper::_('bootstrap.renderModal', 'scheduler-test-modal', $modalparams, $modalbody); - - ?> + pagination->getListFooter(); ?> diff --git a/build/media_source/com_scheduler/joomla.asset.json b/build/media_source/com_scheduler/joomla.asset.json index 0a02038b91012..96b02e1639119 100644 --- a/build/media_source/com_scheduler/joomla.asset.json +++ b/build/media_source/com_scheduler/joomla.asset.json @@ -10,7 +10,8 @@ "type": "script", "uri": "com_scheduler/admin-view-run-test-task.js", "dependencies": [ - "core" + "core", + "joomla.dialog" ], "attributes": { "type" : "module" diff --git a/build/media_source/com_scheduler/js/admin-view-run-test-task.es6.js b/build/media_source/com_scheduler/js/admin-view-run-test-task.es6.js index 6981c9786f975..539e6a3689977 100644 --- a/build/media_source/com_scheduler/js/admin-view-run-test-task.es6.js +++ b/build/media_source/com_scheduler/js/admin-view-run-test-task.es6.js @@ -2,7 +2,6 @@ * @copyright (C) 2021 Open Source Matters, Inc. * @license GNU General Public License version 2 or later; see LICENSE.txt */ - /** * Provides the manual-run functionality for tasks over the com_scheduler administrator backend. * @@ -11,85 +10,120 @@ * * @since 4.1.0 */ -if (!window.Joomla) { - throw new Error('Joomla API was not properly initialised'); -} - -const initRunner = () => { - const paths = Joomla.getOptions('system.paths'); - const token = Joomla.getOptions('com_scheduler.test-task.token'); - const uri = `${paths ? `${paths.base}/index.php` : window.location.pathname}?option=com_ajax&format=json&plugin=RunSchedulerTest&group=system&id=%d${token ? `&${token}=1` : ''}`; - const modal = document.getElementById('scheduler-test-modal'); - - // Task output template - const template = ` -

${Joomla.Text._('COM_SCHEDULER_TEST_RUN_TASK')}

-
${Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_STARTED')}
-
- `; - - const sanitiseTaskOutput = (text) => text - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, ''') - .replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1
$2'); - - // Trigger the task through a GET request, populate the modal with output on completion. - const triggerTaskAndShowOutput = (e) => { - const button = e.relatedTarget; - const id = parseInt(button.dataset.id, 10); - const { title } = button.dataset; - - modal.querySelector('.modal-title').innerHTML = Joomla.Text._('COM_SCHEDULER_TEST_RUN_TITLE').replace('%d', id.toString()); - modal.querySelector('.modal-body > div').innerHTML = template.replace('%s', title); - - Joomla.request({ - url: uri.replace('%d', id.toString()), - onSuccess: (data, xhr) => { - [].slice.call(modal.querySelectorAll('.modal-body > div > div')).forEach((el) => { - el.parentNode.removeChild(el); - }); +// eslint-disable-next-line import/no-unresolved +import JoomlaDialog from 'joomla.dialog'; - const output = JSON.parse(data); - - if (output && output.success && output.data) { - modal.querySelector('.modal-body > div').innerHTML += `
${Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_COMPLETED')}
`; - - if (output.data.duration > 0) { - modal.querySelector('.modal-body > div').innerHTML += `
${Joomla.Text._('COM_SCHEDULER_TEST_RUN_DURATION').replace('%s', output.data.duration.toFixed(2))}
`; - } - - if (output.data.output) { - const result = Joomla.sanitizeHtml((output.data.output), null, sanitiseTaskOutput); - - // Can use an indication for non-0 exit codes - modal.querySelector('.modal-body > div').innerHTML += `
${Joomla.Text._('COM_SCHEDULER_TEST_RUN_OUTPUT').replace('%s', result)}
`; - } - } else { - modal.querySelector('.modal-body > div').innerHTML += `
${Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_TERMINATED')}
`; - modal.querySelector('.modal-body > div').innerHTML += `
${Joomla.Text._('COM_SCHEDULER_TEST_RUN_OUTPUT').replace('%s', Joomla.Text._('JLIB_JS_AJAX_ERROR_OTHER').replace('%s', xhr.status))}
`; - } - }, - onError: (xhr) => { - modal.querySelector('.modal-body > div').innerHTML += `
${Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_TERMINATED')}
`; - - const msg = Joomla.ajaxErrorsMessages(xhr); - modal.querySelector('.modal-body > div').innerHTML += `
${Joomla.Text._('COM_SCHEDULER_TEST_RUN_OUTPUT').replace('%s', msg.error)}
`; - }, - }); - }; +/** + * Helper to create an element + * + * @param {String} nodeName + * @param {String} text + * @param {Array} classList + * @returns {HTMLElement} + */ +const createEl = (nodeName, text = '', classList = []) => { + const el = document.createElement(nodeName); + el.textContent = text; + if (classList && classList.length) { + el.classList.add(...classList); + } + return el; +}; - const reloadOnClose = () => { - window.location.href = `${paths ? `${paths.base}/index.php` : window.location.pathname}?option=com_scheduler&view=tasks`; +/** + * Trigger the task through a GET request + * + * @param {String} url + * @param {HTMLElement} resultContainer + */ +const runTheTask = (url, resultContainer) => { + const statusHolder = resultContainer.querySelector('.scheduler-status'); + const progressBar = resultContainer.querySelector('.progress-bar'); + const complete = (success) => { + progressBar.style.width = '100%'; + progressBar.classList.add(success ? 'bg-success' : 'bg-danger'); + setTimeout(() => progressBar.classList.remove('progress-bar-animated'), 500); }; - - if (modal) { - modal.addEventListener('show.bs.modal', triggerTaskAndShowOutput); - modal.addEventListener('hidden.bs.modal', reloadOnClose); - } - document.removeEventListener('DOMContentLoaded', initRunner); + progressBar.style.width = '15%'; + + fetch(url, { headers: { 'X-CSRF-Token': Joomla.getOptions('csrf.token', '') } }) + .then((response) => { + if (!response.ok) { + throw new Error(Joomla.Text._('JLIB_JS_AJAX_ERROR_OTHER').replace('%s', response.status).replace('%d', response.status)); + } + return response.json(); + }) + .then((output) => { + if (!output.data) { + // The request was successful but the response is empty in some reason + throw new Error(Joomla.Text._('JLIB_JS_AJAX_ERROR_NO_CONTENT')); + } + + statusHolder.textContent = Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_COMPLETED'); + + if (output.data.duration > 0) { + resultContainer.appendChild(createEl('div', Joomla.Text._('COM_SCHEDULER_TEST_RUN_DURATION').replace('%s', output.data.duration.toFixed(2)))); + } + + if (output.data.output) { + resultContainer.appendChild(createEl('div', Joomla.Text._('COM_SCHEDULER_TEST_RUN_OUTPUT').replace('%s', '').replace('
', ''))); + resultContainer.appendChild(createEl('pre', output.data.output, ['bg-light', 'p-2'])); + } + + complete(true); + }) + .catch((error) => { + complete(false); + statusHolder.textContent = Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_TERMINATED'); + resultContainer.appendChild(createEl('div', error.message, ['text-danger'])); + }); }; -document.addEventListener('DOMContentLoaded', initRunner); +// Listen on click over a task button to run a task +document.addEventListener('click', (event) => { + const button = event.target.closest('button[data-scheduler-run]'); + if (!button) return; + event.preventDefault(); + + // Get the task info from the button + const { id, title, url } = button.dataset; + + // Prepare the initial popup content, by following template: + //
+ //

Task: Task title

+ //
Status: Task Status
+ //
+ //
+ const content = (() => { + const body = createEl('div', '', ['p-3']); + const progress = createEl('div', '', ['progress', 'mb-2']); + const progressBar = createEl('div', '', ['progress-bar', 'progress-bar-striped', 'progress-bar-animated']); + body.appendChild(createEl('h4', Joomla.Text._('COM_SCHEDULER_TEST_RUN_TASK').replace('%s', title))); + body.appendChild(createEl('div', Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_STARTED'), ['mb-2', 'scheduler-status'])); + progress.appendChild(progressBar); + body.appendChild(progress); + progressBar.style.width = '0%'; + return body; + })(); + + // Create dialog instance + const dialog = new JoomlaDialog({ + popupType: 'inline', + textHeader: Joomla.Text._('COM_SCHEDULER_TEST_RUN_TITLE').replace('%d', id), + textClose: Joomla.Text._('JCLOSE'), + popupContent: content, + width: '800px', + height: 'fit-content', + }); + + // Run the task when dialog is ready + dialog.addEventListener('joomla-dialog:open', () => { + runTheTask(url, content); + }); + // Reload the page when dialog is closed + dialog.addEventListener('joomla-dialog:close', () => { + window.location.reload(); + }); + + dialog.show(); +});