diff --git a/www/controllers/Task/Task.php b/www/controllers/Task/Task.php index 405c4c85..4cef0c6b 100644 --- a/www/controllers/Task/Task.php +++ b/www/controllers/Task/Task.php @@ -820,9 +820,83 @@ public function getChildrenPid(int $pid) } /** - * Get logs from a task + * Get task previous log lines */ - public function getMoreLogs(int $taskId, string $step, string $substepLastKey) + public function getPreviousLogLines(int $taskId, string $step, string $substepLastKey) + { + try { + /** + * If task log does not exist, throw an exception + */ + if (!file_exists(MAIN_LOGS_DIR . '/' . $taskId . '.json')) { + throw new Exception('no log file found for this task.'); + } + + /** + * Load task log content + */ + $content = file_get_contents(MAIN_LOGS_DIR . '/' . $taskId . '.json'); + + if ($content === false) { + throw new Exception('could not read log file.'); + } + + /** + * Decode JSON content + */ + $content = json_decode($content, true); + + if ($content === null) { + throw new Exception('could not decode log file.'); + } + + /** + * If step does not exist in the log, throw an exception + */ + if (!array_key_exists($step, $content['steps'])) { + throw new Exception('step does not exist in the log.'); + } + + /** + * If substep does not exist in the log, throw an exception + */ + if (!isset($substepLastKey, $content['steps'][$step]['substeps'][$substepLastKey])) { + throw new Exception('substep does not exist in the log.'); + } + + /** + * Return the 20 previous substeps before the provided substep key + */ + $substeps = array_slice($content['steps'][$step]['substeps'], array_search($substepLastKey, array_keys($content['steps'][$step]['substeps'])) - 20, 20, true); + + if (empty($substeps)) { + return ''; + } + + ob_start(); + + foreach ($substeps as $substepKey => $substep) { + $substepTitle = $substep['title']; + $substepNote = $substep['note']; + $substepStatus = $substep['status']; + $substepOutput = $substep['output']; + $substepStart = $substep['start']; + $substepDuration = $substep['duration']; + + // Include substep template + include(ROOT . '/views/includes/containers/tasks/log/substep.inc.php'); + } + + return ob_get_clean(); + } catch (Exception $e) { + throw new Exception('Cannot load more logs: ' . $e->getMessage()); + } + } + + /** + * Get task next log lines + */ + public function getNextLogLines(int $taskId, string $step, string $substepLastKey) { try { /** diff --git a/www/controllers/ajax/task.php b/www/controllers/ajax/task.php index 9bb7751b..f3ccddbc 100644 --- a/www/controllers/ajax/task.php +++ b/www/controllers/ajax/task.php @@ -88,11 +88,11 @@ } /** - * Get task log content on scroll + * Get task previous log lines on scroll */ -if ($_POST['action'] == 'getMoreLogs' and !empty($_POST['taskId']) and !empty($_POST['step']) and !empty($_POST['substepLastKey'])) { +if ($_POST['action'] == 'get-previous-log-lines' and !empty($_POST['taskId']) and !empty($_POST['step']) and !empty($_POST['substepFirstKey'])) { try { - $content = $myTask->getMoreLogs($_POST['taskId'], $_POST['step'], $_POST['substepLastKey']); + $content = $myTask->getPreviousLogLines($_POST['taskId'], $_POST['step'], $_POST['substepFirstKey']); } catch (\Exception $e) { response(HTTP_BAD_REQUEST, $e->getMessage()); } @@ -100,5 +100,17 @@ response(HTTP_OK, $content); } +/** + * Get task next log lines on scroll + */ +if ($_POST['action'] == 'get-next-log-lines' and !empty($_POST['taskId']) and !empty($_POST['step']) and !empty($_POST['substepLastKey'])) { + try { + $content = $myTask->getNextLogLines($_POST['taskId'], $_POST['step'], $_POST['substepLastKey']); + } catch (\Exception $e) { + response(HTTP_BAD_REQUEST, $e->getMessage()); + } + + response(HTTP_OK, $content); +} response(HTTP_BAD_REQUEST, 'Invalid action'); diff --git a/www/public/resources/js/events/task/actions.js b/www/public/resources/js/events/task/actions.js index 9ce6a541..cbd884ce 100644 --- a/www/public/resources/js/events/task/actions.js +++ b/www/public/resources/js/events/task/actions.js @@ -1,10 +1,109 @@ /** - * Event: load more logs on scroll down + * Event: show logfile + */ +$(document).on('click','.show-task-btn',function () { + var taskId = $(this).attr('task-id'); + + // Go to task page + window.location.href = '/run/' + taskId; +}); + +/** + * Event: print all log + */ +$(document).on('click','#display-log-btn',function () { + var display = $(this).attr('display'); + + if (display == 'true') { + $('.getPackagesDiv').css('display', 'block'); + $('.signRepoDiv').css('display', 'block'); + $('.createRepoDiv').css('display', 'block'); + $('#display-log-btn').attr('display', 'false'); + $('#display-log-btn').attr('title', 'Hide details'); + $('#display-log-btn').find('img').attr('src', '/assets/icons/view.svg'); + $('.task-step-content').show(); + } + + if (display == 'false') { + $('.getPackagesDiv').css('display', 'none'); + $('.signRepoDiv').css('display', 'none'); + $('.createRepoDiv').css('display', 'none'); + $('#display-log-btn').attr('display', 'true'); + $('#display-log-btn').attr('title', 'Show details'); + $('#display-log-btn').find('img').attr('src', '/assets/icons/view-off.svg'); + $('.task-step-content').hide(); + } +}); + +/** + * Event: load more logs on scroll */ $('.task-step-content').scroll(function () { var taskId = $(this).attr('task-id'); var step = $(this).attr('step'); + /** + * Load more logs on scroll up + */ + if ($(this).scrollTop() == 0) { + // Get first substep key + var substepFirstKey = $(this).find('.task-sub-step-content:first').attr('key'); + + // TODO debug + console.log('task: ' + taskId); + console.log('step: ' + step); + console.log('key: ' + substepFirstKey); + + // If there is already a loading icon, then do not print another one + if ($('.task-step-content[task-id="' + taskId + '"][step="' + step + '"] .step-loading').length) { + return; + } + + // Print loading icon + $('.task-step-content[task-id="' + taskId + '"][step="' + step + '"]').find('div.task-sub-step-container').prepend('\ +
\ + Loading... \ +

Loading...

\ +
' + ); + + // Get more logs from server + // Server will return a html with the new logs + ajaxRequest( + // Controller: + 'task', + // Action: + 'get-previous-log-lines', + // Data: + { + taskId: taskId, + step: step, + substepFirstKey: substepFirstKey + }, + // Print success alert: + false, + // Print error alert: + true, + // Reload containers: + [], + // Execute functions on success: + [ + // Remove loading icon + "$('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"] .step-loading').remove();", + + // Prepend new logs + "$('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"] .task-sub-step-container').prepend(jsonValue.message);", + + // Delete previous logs and all below + // Start from substepFirstKey, keep 10 substeps below and remove the rest + "$('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"] .task-sub-step-content[key=\"" + substepFirstKey + "\"]').nextAll().slice(10).remove();" + ] + ); + } + + /** + * Load more logs on scroll down + */ if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) { // Get last substep key var substepLastKey = $(this).find('.task-sub-step-content:last').attr('key'); @@ -33,7 +132,7 @@ $('.task-step-content').scroll(function () { // Controller: 'task', // Action: - 'getMoreLogs', + 'get-next-log-lines', // Data: { taskId: taskId, @@ -52,8 +151,146 @@ $('.task-step-content').scroll(function () { "$('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"] .step-loading').remove();", // Append new logs - "$('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"] .task-sub-step-container').append(jsonValue.message);" + "$('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"] .task-sub-step-container').append(jsonValue.message);", + + // Delete previous logs and all above + // Start from substepLastKey, keep 10 substeps above and remove the rest + "$('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"] .task-sub-step-content[key=\"" + substepLastKey + "\"]').prevAll().slice(10).remove();" ] ); } +}); + +/** + * Event: show or hide scheduled task informations + */ +$(document).on('click','.show-scheduled-task-info-btn',function (e) { + // Prevent parent to be triggered + e.stopPropagation(); + + var taskId = $(this).attr('task-id'); + + /** + * Show or hide task informations + */ + $('.scheduled-task-info[task-id="' + taskId + '"]').toggle(); +}); + +/** + * Event: disable scheduled task execution + */ +$(document).on('click','.disable-scheduled-task-btn',function (e) { + // Prevent parent to be triggered + e.stopPropagation(); + + var taskId = $(this).attr('task-id'); + + ajaxRequest( + // Controller: + 'task', + // Action: + 'disableTask', + // Data: + { + taskId: taskId, + }, + // Print success alert: + true, + // Print error alert: + true, + // Reload containers: + ['tasks/list'] + ); +}); + +/** + * Event: enable scheduled task execution + */ +$(document).on('click','.enable-scheduled-task-btn',function (e) { + // Prevent parent to be triggered + e.stopPropagation(); + + var taskId = $(this).attr('task-id'); + + ajaxRequest( + // Controller: + 'task', + // Action: + 'enableTask', + // Data: + { + taskId: taskId, + }, + // Print success alert: + true, + // Print error alert: + true, + // Reload containers: + ['tasks/list'] + ); +}); + +/** + * Event: cancel scheduled task + */ +$(document).on('click','.cancel-scheduled-task-btn',function (e) { + // Prevent parent to be triggered + e.stopPropagation(); + + var taskId = $(this).attr('task-id'); + + confirmBox( + { + 'title': 'Cancel and delete scheduled task', + 'message': 'Are you sure you want to cancel and delete this task?', + 'buttons': [ + { + 'text': 'Delete', + 'color': 'red', + 'callback': function () { + ajaxRequest( + // Controller: + 'task', + // Action: + 'deleteTask', + // Data: + { + taskId: taskId, + }, + // Print success alert: + true, + // Print error alert: + true, + // Reload containers: + ['tasks/list'] + ) + } + }] + } + ); +}); + +/** + * Event: relaunch task + */ +$(document).on('click','.relaunch-task-btn',function (e) { + // Prevent parent to be triggered + e.stopPropagation(); + + var taskId = $(this).attr('task-id'); + + ajaxRequest( + // Controller: + 'task', + // Action: + 'relaunchTask', + // Data: + { + taskId: taskId, + }, + // Print success alert: + true, + // Print error alert: + true + ); }); \ No newline at end of file diff --git a/www/public/resources/js/run.js b/www/public/resources/js/run.js deleted file mode 100644 index c4a99494..00000000 --- a/www/public/resources/js/run.js +++ /dev/null @@ -1,172 +0,0 @@ -/** - * Event: print full log - */ -$(document).on('click','#display-log-btn',function () { - var display = $(this).attr('display'); - - if (display == 'true') { - $('.getPackagesDiv').css('display', 'block'); - $('.signRepoDiv').css('display', 'block'); - $('.createRepoDiv').css('display', 'block'); - $('#display-log-btn').attr('display', 'false'); - $('#display-log-btn').attr('title', 'Hide details'); - $('#display-log-btn').find('img').attr('src', '/assets/icons/view.svg'); - $('.task-step-content').show(); - } - - if (display == 'false') { - $('.getPackagesDiv').css('display', 'none'); - $('.signRepoDiv').css('display', 'none'); - $('.createRepoDiv').css('display', 'none'); - $('#display-log-btn').attr('display', 'true'); - $('#display-log-btn').attr('title', 'Show details'); - $('#display-log-btn').find('img').attr('src', '/assets/icons/view-off.svg'); - $('.task-step-content').hide(); - } -}); - -/** - * Event: show logfile content - */ -$(document).on('click','.show-task-btn',function () { - var taskId = $(this).attr('task-id'); - - // Go to task page - window.location.href = '/run/' + taskId; -}); - - - -/** - * Event: relaunch task - */ -$(document).on('click','.relaunch-task-btn',function (e) { - // Prevent parent to be triggered - e.stopPropagation(); - - var taskId = $(this).attr('task-id'); - - ajaxRequest( - // Controller: - 'task', - // Action: - 'relaunchTask', - // Data: - { - taskId: taskId, - }, - // Print success alert: - true, - // Print error alert: - true - ); -}); - -/** - * Event: show or hide scheduled task informations - */ -$(document).on('click','.show-scheduled-task-info-btn',function (e) { - // Prevent parent to be triggered - e.stopPropagation(); - - var taskId = $(this).attr('task-id'); - - /** - * Show or hide task informations - */ - $('.scheduled-task-info[task-id="' + taskId + '"]').toggle(); -}); - -/** - * Event: disable scheduled task execution - */ -$(document).on('click','.disable-scheduled-task-btn',function (e) { - // Prevent parent to be triggered - e.stopPropagation(); - - var taskId = $(this).attr('task-id'); - - ajaxRequest( - // Controller: - 'task', - // Action: - 'disableTask', - // Data: - { - taskId: taskId, - }, - // Print success alert: - true, - // Print error alert: - true, - // Reload containers: - ['tasks/list'] - ); -}); - -/** - * Event: enable scheduled task execution - */ -$(document).on('click','.enable-scheduled-task-btn',function (e) { - // Prevent parent to be triggered - e.stopPropagation(); - - var taskId = $(this).attr('task-id'); - - ajaxRequest( - // Controller: - 'task', - // Action: - 'enableTask', - // Data: - { - taskId: taskId, - }, - // Print success alert: - true, - // Print error alert: - true, - // Reload containers: - ['tasks/list'] - ); -}); - -/** - * Event: cancel scheduled task - */ -$(document).on('click','.cancel-scheduled-task-btn',function (e) { - // Prevent parent to be triggered - e.stopPropagation(); - - var taskId = $(this).attr('task-id'); - - confirmBox( - { - 'title': 'Cancel and delete scheduled task', - 'message': 'Are you sure you want to cancel and delete this task?', - 'buttons': [ - { - 'text': 'Delete', - 'color': 'red', - 'callback': function () { - ajaxRequest( - // Controller: - 'task', - // Action: - 'deleteTask', - // Data: - { - taskId: taskId, - }, - // Print success alert: - true, - // Print error alert: - true, - // Reload containers: - ['tasks/list'] - ) - } - }] - } - ); -}); diff --git a/www/public/resources/styles/main.css b/www/public/resources/styles/main.css index e5e82c9a..ffe0f394 100644 --- a/www/public/resources/styles/main.css +++ b/www/public/resources/styles/main.css @@ -362,13 +362,12 @@ article { align-items: center; align-content: flex-start; justify-content: space-evenly; - column-gap: 2px; padding: 6px 0 0 0 !important; position: inherit !important; } .item-info img, .item-env-info img { - height: 17px; + height: 19px; margin-left: 4px !important; margin-right: 4px !important; } diff --git a/www/views/includes/containers/tasks/log/step.inc.php b/www/views/includes/containers/tasks/log/step.inc.php index 94cfad3e..a9e2ad79 100644 --- a/www/views/includes/containers/tasks/log/step.inc.php +++ b/www/views/includes/containers/tasks/log/step.inc.php @@ -17,7 +17,7 @@
Running

'; + echo '

Running

'; } if ($step['status'] == 'completed') { echo '

Completed

'; diff --git a/www/views/includes/footer.inc.php b/www/views/includes/footer.inc.php index bd9a0b58..31b3bad5 100644 --- a/www/views/includes/footer.inc.php +++ b/www/views/includes/footer.inc.php @@ -71,7 +71,7 @@ $jsFiles = ['functions/environment', 'events/environment/actions', 'settings']; } if (__ACTUAL_URI__[1] == 'run') { - $jsFiles = ['run', 'events/task/actions']; + $jsFiles = ['events/task/actions']; } if (__ACTUAL_URI__[1] == 'history') { $jsFiles = ['events/history/actions']; diff --git a/www/views/includes/repos-list.inc.php b/www/views/includes/repos-list.inc.php index 953a73f6..561831e7 100644 --- a/www/views/includes/repos-list.inc.php +++ b/www/views/includes/repos-list.inc.php @@ -296,7 +296,6 @@
- Calc. '; } ?> + + Calc.