From 51997792304658768a64459001508582518908df Mon Sep 17 00:00:00 2001 From: Ludovic <54670129+lbr38@users.noreply.github.com> Date: Sat, 28 Dec 2024 10:39:20 +0100 Subject: [PATCH] patch --- www/controllers/Task/Step.php | 237 +++++---------- www/controllers/ajax/task.php | 30 +- www/public/assets/icons/pause.svg | 38 +++ .../resources/js/events/task/actions.js | 287 +++++++++--------- www/public/resources/js/functions/task.js | 59 ++-- www/public/resources/styles/run.css | 25 +- .../includes/containers/tasks/log.inc.php | 26 +- .../containers/tasks/log/step-content.inc.php | 47 ++- 8 files changed, 369 insertions(+), 380 deletions(-) create mode 100644 www/public/assets/icons/pause.svg diff --git a/www/controllers/Task/Step.php b/www/controllers/Task/Step.php index 810c3658..19cc6eca 100644 --- a/www/controllers/Task/Step.php +++ b/www/controllers/Task/Step.php @@ -6,50 +6,61 @@ class Step { - /** - * Get and return the steps name, status and HTML content - */ - public function getSteps(int $taskId) + private $taskId; + private $jsonContent; + + public function __construct(int $taskId) { - 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.'); - } + $this->taskId = $taskId; - /** - * Load task log content - */ - $content = file_get_contents(MAIN_LOGS_DIR . '/' . $taskId . '.json'); + /** + * If task log does not exist, throw an exception + */ + if (!file_exists(MAIN_LOGS_DIR . '/' . $this->taskId . '.json')) { + throw new Exception('No log file found for this task.'); + } - if ($content === false) { - throw new Exception('could not read log file.'); - } + /** + * Load task log content + */ + $content = file_get_contents(MAIN_LOGS_DIR . '/' . $this->taskId . '.json'); - /** - * Decode JSON content - */ - $jsonContent = json_decode($content, true); + if ($content === false) { + throw new Exception('Could not read task log file.'); + } - if ($jsonContent === null) { - throw new Exception('could not decode log file.'); - } + /** + * Decode JSON content + */ + $this->jsonContent = json_decode($content, true); - if (!empty($jsonContent['steps'])) { - foreach ($jsonContent['steps'] as $stepName => $step) { + if ($this->jsonContent === null) { + throw new Exception('Could not decode task log file.'); + } + } + + /** + * Get and return the steps name, status and HTML content + */ + public function getSteps() + { + try { + // For the needs of the include file + $taskId = $this->taskId; + + if (!empty($this->jsonContent['steps'])) { + foreach ($this->jsonContent['steps'] as $stepName => $step) { // Get HTML content of the step ob_start(); include(ROOT . '/views/includes/containers/tasks/log/step.inc.php'); $content = ob_get_clean(); // Add step name, status and HTML content to the steps array - $jsonContent['steps'][$stepName]['html'] = $content; + $this->jsonContent['steps'][$stepName]['html'] = $content; } } - return json_encode($jsonContent); + return json_encode($this->jsonContent); } catch (Exception $e) { throw new Exception('Cannot retrieve steps status: ' . $e->getMessage()); } @@ -58,44 +69,21 @@ public function getSteps(int $taskId) /** * Get and return the content of a specific step */ - public function getStepContent(int $taskId, string $stepName, bool $autoscroll) + public function getStepContent(string $stepName, bool $autoscroll) { try { $data = ''; - /** - * 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($stepName, $content['steps'])) { + if (!array_key_exists($stepName, $this->jsonContent['steps'])) { throw new Exception('step does not exist in the log.'); } - $step = $content['steps'][$stepName]; + // For the needs of the include file + $taskId = $this->taskId; + $step = $this->jsonContent['steps'][$stepName]; ob_start(); include(ROOT . '/views/includes/containers/tasks/log/step-content.inc.php'); @@ -108,146 +96,73 @@ public function getStepContent(int $taskId, string $stepName, bool $autoscroll) } /** - * Get task previous log lines + * Get task log lines */ - public function getPreviousLogLines(int $taskId, string $step, string $substepFirstKey) + public function getLogLines(string $step, string $direction, string|null $key = null) { try { /** - * If task log does not exist, throw an exception + * If step does not exist in the log, throw an exception */ - if (!file_exists(MAIN_LOGS_DIR . '/' . $taskId . '.json')) { - throw new Exception('no log file found for this task.'); + if (!array_key_exists($step, $this->jsonContent['steps'])) { + throw new Exception('no step ' . $step . ' found in the log.'); } /** - * Load task log content + * If a substep key is provided */ - $content = file_get_contents(MAIN_LOGS_DIR . '/' . $taskId . '.json'); + if (!empty($key)) { + // If the substep does not exist in the log, throw an exception + if (!array_key_exists($key, $this->jsonContent['steps'][$step]['substeps'])) { + throw new Exception('no substep ' . $key . ' found in the log.'); + } - if ($content === false) { - throw new Exception('could not read log file.'); + // If the substep key is the first one, return an empty content (because we cannot go up anymore) + if ($key == array_key_first($this->jsonContent['steps'][$step]['substeps'])) { + return ''; + } } /** - * Decode JSON content + * If direction is 'top', get the very first 30 substeps */ - $content = json_decode($content, true); - - if ($content === null) { - throw new Exception('could not decode log file.'); + if ($direction == 'top') { + $substeps = array_slice($this->jsonContent['steps'][$step]['substeps'], 0, 30, true); } /** - * If step does not exist in the log, throw an exception + * If direction is 'up', get the 10 substeps before the provided substep key */ - if (!array_key_exists($step, $content['steps'])) { - throw new Exception('step does not exist in the log.'); + if ($direction == 'up') { + $substeps = array_slice($this->jsonContent['steps'][$step]['substeps'], 0, array_search($key, array_keys($this->jsonContent['steps'][$step]['substeps'])), true); + // Only keep the 10 previous substeps + $substeps = array_slice($substeps, -10, 10, true); } /** - * If substep does not exist in the log, throw an exception + * If direction is 'down', get the 10 substeps after the provided substep key */ - if (!isset($substepFirstKey, $content['steps'][$step]['substeps'][$substepFirstKey])) { - throw new Exception('substep does not exist in the log.'); + if ($direction == 'down') { + $substeps = array_slice($this->jsonContent['steps'][$step]['substeps'], array_search($key, array_keys($this->jsonContent['steps'][$step]['substeps'])) + 1, 10, true); } /** - * If the substep key is the first one, return an empty array + * If direction is 'bottom', get the very last 30 substeps */ - if ($substepFirstKey == array_key_first($content['steps'][$step]['substeps'])) { - return ''; + if ($direction == 'bottom') { + $substeps = array_slice($this->jsonContent['steps'][$step]['substeps'], -30, 30, true); } /** - * Get all substeps before the provided substep key - */ - $substeps = array_slice($content['steps'][$step]['substeps'], 0, array_search($substepFirstKey, array_keys($content['steps'][$step]['substeps'])), true); - - /** - * If there is no more substep to display, return an empty string + * If there is no substep to display, return an empty string */ if (empty($substeps)) { return ''; } - // Only keep the 10 previous substeps - $substeps = array_slice($substeps, -10, 10, true); - - 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 { - /** - * 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 + * Load each substep 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 next substeps after the provided substep key - */ - $substeps = array_slice($content['steps'][$step]['substeps'], array_search($substepLastKey, array_keys($content['steps'][$step]['substeps'])) + 1, 10, true); - - if (empty($substeps)) { - return ''; - } - ob_start(); foreach ($substeps as $substepKey => $substep) { diff --git a/www/controllers/ajax/task.php b/www/controllers/ajax/task.php index 71b982c5..81ece5e6 100644 --- a/www/controllers/ajax/task.php +++ b/www/controllers/ajax/task.php @@ -92,8 +92,8 @@ */ if ($_POST['action'] == 'get-steps' and !empty($_POST['taskId'])) { try { - $taskStepController = new \Controllers\Task\Step(); - $content = $taskStepController->getSteps($_POST['taskId']); + $taskStepController = new \Controllers\Task\Step($_POST['taskId']); + $content = $taskStepController->getSteps(); } catch (\Exception $e) { response(HTTP_BAD_REQUEST, $e->getMessage()); } @@ -106,8 +106,8 @@ */ if ($_POST['action'] == 'get-step-content' and !empty($_POST['taskId']) and !empty($_POST['stepName']) and !empty($_POST['autoscroll'])) { try { - $taskStepController = new \Controllers\Task\Step(); - $content = $taskStepController->getStepContent($_POST['taskId'], $_POST['stepName'], $_POST['autoscroll']); + $taskStepController = new \Controllers\Task\Step($_POST['taskId']); + $content = $taskStepController->getStepContent($_POST['stepName'], $_POST['autoscroll']); } catch (\Exception $e) { response(HTTP_BAD_REQUEST, $e->getMessage()); } @@ -116,26 +116,12 @@ } /** - * Get task previous log lines on scroll + * Get and return previous or next log lines of a specific task step */ -if ($_POST['action'] == 'get-previous-log-lines' and !empty($_POST['taskId']) and !empty($_POST['step']) and !empty($_POST['substepFirstKey'])) { +if ($_POST['action'] == 'get-log-lines' and !empty($_POST['taskId']) and !empty($_POST['step']) and !empty($_POST['direction']) and isset($_POST['key'])) { try { - $taskStepController = new \Controllers\Task\Step(); - $content = $taskStepController->getPreviousLogLines($_POST['taskId'], $_POST['step'], $_POST['substepFirstKey']); - } catch (\Exception $e) { - response(HTTP_BAD_REQUEST, $e->getMessage()); - } - - 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 { - $taskStepController = new \Controllers\Task\Step(); - $content = $taskStepController->getNextLogLines($_POST['taskId'], $_POST['step'], $_POST['substepLastKey']); + $taskStepController = new \Controllers\Task\Step($_POST['taskId']); + $content = $taskStepController->getLogLines($_POST['step'], $_POST['direction'], $_POST['key']); } catch (\Exception $e) { response(HTTP_BAD_REQUEST, $e->getMessage()); } diff --git a/www/public/assets/icons/pause.svg b/www/public/assets/icons/pause.svg new file mode 100644 index 00000000..0e5dadfe --- /dev/null +++ b/www/public/assets/icons/pause.svg @@ -0,0 +1,38 @@ + + diff --git a/www/public/resources/js/events/task/actions.js b/www/public/resources/js/events/task/actions.js index 633e8ee7..33b853fe 100644 --- a/www/public/resources/js/events/task/actions.js +++ b/www/public/resources/js/events/task/actions.js @@ -8,6 +8,10 @@ $(document).ready(function () { // Start log autorefresh, with or without autoscroll autorefresh(); + + // TODO debug + autoscrollCookie = getCookie('autoscroll'); + console.log('autoscroll: ' + autoscrollCookie); }); /** @@ -17,7 +21,11 @@ $(document).on('click','.show-step-content-btn',function () { var taskId = $(this).attr('task-id'); var step = $(this).attr('step'); - $('.task-step-content[task-id="' + taskId + '"][step="' + step + '"]').toggle(); + if ($('.task-step-content[task-id="' + taskId + '"][step="' + step + '"]').is(':visible')) { + $('.task-step-content[task-id="' + taskId + '"][step="' + step + '"]').hide(); + } else { + $('.task-step-content[task-id="' + taskId + '"][step="' + step + '"]').css('display', 'grid'); + } }); /** @@ -34,15 +42,21 @@ $(document).on('click','.show-task-btn',function () { * Event: enable / disable automatic scroll on log */ $(document).on('click','#autoscroll-btn',function () { - var autoscroll = localStorage.getItem('autoscroll'); + var autoscroll = getCookie('autoscroll'); + + console.log('autoscroll: ' + autoscroll); - if (autoscroll == null || autoscroll == 'false') { - localStorage.setItem('autoscroll', 'true'); + // Enable autoscroll + if (autoscroll == "" || autoscroll == 'false') { + setCookie('autoscroll', 'true'); + $(this).find('img').attr('src', '/assets/icons/pause.svg'); $(this).attr('title', 'Disable auto scroll'); } + // Disable autoscroll if (autoscroll == 'true') { - localStorage.setItem('autoscroll', 'false'); + setCookie('autoscroll', 'false'); + $(this).find('img').attr('src', '/assets/icons/play.svg'); $(this).attr('title', 'Enable auto scroll'); // Restart scroll event listener because autoscroll may have broken it @@ -51,7 +65,7 @@ $(document).on('click','#autoscroll-btn',function () { }); /** - * Event: print all log + * Event: print all log (legacy logs) */ $(document).on('click','#display-log-btn',function () { var display = $(this).attr('display'); @@ -78,141 +92,134 @@ $(document).on('click','#display-log-btn',function () { }); /** - * Event: load more logs on scroll + * Event: go to the top in step log + */ +$(document).on('click','.step-top-btn',function () { + // Retrieve task Id + var taskId = $(this).attr('task-id'); + + // Retrieve current step + var step = $(this).attr('step'); + + // Lock any other scroll from appending data + localStorage.setItem('scrollLock', 'true'); + + // Get logs from server + // Server will return a html with the new logs + ajaxRequest( + // Controller: + 'task', + // Action: + 'get-log-lines', + // Data: + { + taskId: taskId, + step: step, + direction: 'top', + key: '' + }, + // Print success alert: + false, + // Print error alert: + true, + // Reload containers: + [], + // Execute functions on success: + [ + // If server returns logs, clear all and append them to the container, and set scroll bar position to 0 + "if (jsonValue.message != '') { \ + $('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"] .task-sub-step-container').html(jsonValue.message); \ + $('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"]').scrollTop(0); \ + }", + + // Remove scroll lock + "localStorage.removeItem('scrollLock');" + ] + ); +}); + +/** + * Event: go to the bottom in step log + */ +$(document).on('click','.step-bottom-btn',function () { + // Retrieve task Id + var taskId = $(this).attr('task-id'); + + // Retrieve current step + var step = $(this).attr('step'); + + // Lock any other scroll from appending data + localStorage.setItem('scrollLock', 'true'); + + // Get logs from server + // Server will return a html with the new logs + ajaxRequest( + // Controller: + 'task', + // Action: + 'get-log-lines', + // Data: + { + taskId: taskId, + step: step, + direction: 'bottom', + key: '' + }, + // Print success alert: + false, + // Print error alert: + true, + // Reload containers: + [], + // Execute functions on success: + [ + // If server returns logs, clear all and append them to the container, and set scroll bar position to 0 from the bottom + "if (jsonValue.message != '') { \ + $('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"] .task-sub-step-container').html(jsonValue.message); \ + $('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"]').scrollTop($('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"]')[0].scrollHeight); \ + }", + + // Remove scroll lock + "localStorage.removeItem('scrollLock');" + ] + ); +}); + + + + + + + + + +/** + * Event: go up in step log + */ +$(document).on('click','.step-up-btn',function () { + // Retrieve task Id + var taskId = $(this).attr('task-id'); + + // Retrieve current step + var step = $(this).attr('step'); + + // Move scroll bar up + $('.task-step-content[task-id="' + taskId + '"][step="' + step + '"]').scrollTop($('.task-step-content[task-id="' + taskId + '"][step="' + step + '"]').scrollTop() - 100); +}); + +/** + * Event: go down in step log */ -// $('.task-step-content').scroll(function () { -// var taskId = $(this).attr('task-id'); -// var step = $(this).attr('step'); - -// /** -// * If scroll is locked, do nothing -// */ -// if (localStorage.getItem('scrollLock') == 'true') { -// return; -// } - -// /** -// * Get latest scroll position from local storage -// */ -// var lastScrollPosition = localStorage.getItem('lastScrollPosition'); - -// /** -// * Get current scroll position -// */ -// var currentScrollPosition = $(this).scrollTop(); - -// /** -// * If latest scroll position is null (meaning the page has been refreshed), set it to 0 -// */ -// if (lastScrollPosition == null) { -// lastScrollPosition = 0; -// } - -// /** -// * Detect if the current scroll is a scroll up or down -// */ -// if (currentScrollPosition > lastScrollPosition) { -// var scroll = 'down'; -// } -// if (currentScrollPosition < lastScrollPosition) { -// var scroll = 'up'; -// } - -// /** -// * Save current scroll position in local storage -// */ -// localStorage.setItem('lastScrollPosition', currentScrollPosition); - -// /** -// * Load more logs on scroll up -// */ -// if (scroll == 'up' && $(this).scrollTop() < 20) { -// // Lock any other scroll from appending data -// localStorage.setItem('scrollLock', 'true'); - -// // Get first substep key -// var substepFirstKey = $(this).find('.task-sub-step-content:first').attr('key'); - -// // 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: -// [ -// // If server returns logs, prepend them to the container, then remove the last 30 logs -// // Set scroll bar position to 1.5 from the top -// "if (jsonValue.message != '') { \ -// $('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"] .task-sub-step-container').prepend(jsonValue.message); \ -// $('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"] .task-sub-step-content:first').nextAll().slice(30).remove(); \ -// $('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"]').scrollTop(1.5); \ -// }", - -// // Remove scroll lock -// "localStorage.removeItem('scrollLock');" -// ] -// ); -// } - -// /** -// * Load more logs on scroll down -// */ -// if (scroll == 'down' && $(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight - 20) { -// // Lock any other scroll from appending data -// localStorage.setItem('scrollLock', 'true'); - -// // Get last substep key -// var substepLastKey = $(this).find('.task-sub-step-content:last').attr('key'); - -// // Get more logs from server -// // Server will return a html with the new logs -// ajaxRequest( -// // Controller: -// 'task', -// // Action: -// 'get-next-log-lines', -// // Data: -// { -// taskId: taskId, -// step: step, -// substepLastKey: substepLastKey -// }, -// // Print success alert: -// false, -// // Print error alert: -// true, -// // Reload containers: -// [], -// // Execute functions on success: -// [ -// // If server returns logs, append them to the container, then remove the first 30 logs -// // Set scroll bar position to 1.5 from the bottom -// "if (jsonValue.message != '') { \ -// $('.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-content').slice(0, -30).remove(); \ -// $('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"]').scrollTop($('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"]')[0].scrollHeight - $('.task-step-content').innerHeight() - 1.5); \ -// }", - -// // Remove scroll lock -// "localStorage.removeItem('scrollLock');" -// ] -// ); -// } -// }); +$(document).on('click','.step-down-btn',function () { + // Retrieve task Id + var taskId = $(this).attr('task-id'); + + // Retrieve current step + var step = $(this).attr('step'); + + // Move scroll bar down + $('.task-step-content[task-id="' + taskId + '"][step="' + step + '"]').scrollTop($('.task-step-content[task-id="' + taskId + '"][step="' + step + '"]').scrollTop() + 100); +}); /** * Event: show or hide scheduled task informations diff --git a/www/public/resources/js/functions/task.js b/www/public/resources/js/functions/task.js index 3b134244..a8115d67 100644 --- a/www/public/resources/js/functions/task.js +++ b/www/public/resources/js/functions/task.js @@ -1,7 +1,8 @@ /** * Start task log autorefresh */ -function autorefresh() { +function autorefresh() +{ // Ignore refresh if 'legacy' attribute is set if ($('#log-refresh-container').attr('legacy') == 'true') { return; @@ -45,9 +46,10 @@ function autorefresh() { /** * Refresh each step, based on the status received from the server (in JSON format) * @param {*} steps - * @returns + * @returns */ -function refreshStepsInDOM(steps) { +function refreshStepsInDOM(steps) +{ var autoscroll = false; // Retrieve task Id @@ -73,11 +75,13 @@ function refreshStepsInDOM(steps) { $('.steps-container[task-id="' + taskId + '"]').append(step.html); } - // Ignore autoscroll if disabled - if (localStorage.getItem('autoscroll') == 'true') { + // If autoscroll if enabled, scroll to the bottom of the step content + if (getCookie('autoscroll') == 'true') { autoscroll = true; } + // console.log('autoscroll: ' + autoscroll); + // Get step content (all its substeps) ajaxRequest( // Controller: @@ -106,10 +110,10 @@ function refreshStepsInDOM(steps) { visibility = $('.task-step-content[task-id=" + taskId + "][step=" + stepName + "]').is(':visible'); \ $('.task-step-content[task-id=" + taskId + "][step=" + stepName + "]').replaceWith(jsonValue.message); \ if (visibility) { \ - $('.task-step-content[task-id=" + taskId + "][step=" + stepName + "]').show(); \ + $('.task-step-content[task-id=" + taskId + "][step=" + stepName + "]').css('display', 'grid'); \ } \ $('.task-step-content[task-id=" + taskId + "][step=" + stepName + "]').scrollTop($('.task-step-content[task-id=" + taskId + "][step=" + stepName + "]')[0].scrollHeight); \ - }" + }" ] ); }); @@ -119,35 +123,36 @@ function refreshStepsInDOM(steps) { * Start log scroll event listener * This is used to listen for user scroll up or down in the logs */ -function scrollEvent() { +function scrollEvent() +{ $('.task-step-content').scroll(function () { var taskId = $(this).attr('task-id'); var step = $(this).attr('step'); - + /** * If scroll is locked, do nothing */ if (localStorage.getItem('scrollLock') == 'true') { return; } - + /** * Get latest scroll position from local storage */ var lastScrollPosition = localStorage.getItem('lastScrollPosition'); - + /** * Get current scroll position */ var currentScrollPosition = $(this).scrollTop(); - + /** * If latest scroll position is null (meaning the page has been refreshed), set it to 0 */ if (lastScrollPosition == null) { lastScrollPosition = 0; } - + /** * Detect if the current scroll is a scroll up or down */ @@ -157,34 +162,35 @@ function scrollEvent() { if (currentScrollPosition < lastScrollPosition) { var scroll = 'up'; } - + /** * Save current scroll position in local storage */ localStorage.setItem('lastScrollPosition', currentScrollPosition); - + /** * Load more logs on scroll up */ if (scroll == 'up' && $(this).scrollTop() < 20) { // Lock any other scroll from appending data localStorage.setItem('scrollLock', 'true'); - + // Get first substep key var substepFirstKey = $(this).find('.task-sub-step-content:first').attr('key'); - + // Get more logs from server // Server will return a html with the new logs ajaxRequest( // Controller: 'task', // Action: - 'get-previous-log-lines', + 'get-log-lines', // Data: { taskId: taskId, step: step, - substepFirstKey: substepFirstKey + direction: 'up', + key: substepFirstKey }, // Print success alert: false, @@ -201,35 +207,36 @@ function scrollEvent() { $('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"] .task-sub-step-content:first').nextAll().slice(30).remove(); \ $('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"]').scrollTop(1.5); \ }", - + // Remove scroll lock "localStorage.removeItem('scrollLock');" ] ); } - + /** * Load more logs on scroll down */ if (scroll == 'down' && $(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight - 20) { // Lock any other scroll from appending data localStorage.setItem('scrollLock', 'true'); - + // Get last substep key var substepLastKey = $(this).find('.task-sub-step-content:last').attr('key'); - + // Get more logs from server // Server will return a html with the new logs ajaxRequest( // Controller: 'task', // Action: - 'get-next-log-lines', + 'get-log-lines', // Data: { taskId: taskId, step: step, - substepLastKey: substepLastKey + direction: 'down', + key: substepLastKey }, // Print success alert: false, @@ -246,7 +253,7 @@ function scrollEvent() { $('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"] .task-sub-step-content').slice(0, -30).remove(); \ $('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"]').scrollTop($('.task-step-content[task-id=\"" + taskId + "\"][step=\"" + step + "\"]')[0].scrollHeight - $('.task-step-content').innerHeight() - 1.5); \ }", - + // Remove scroll lock "localStorage.removeItem('scrollLock');" ] diff --git a/www/public/resources/styles/run.css b/www/public/resources/styles/run.css index 0244e552..fff29442 100644 --- a/www/public/resources/styles/run.css +++ b/www/public/resources/styles/run.css @@ -23,7 +23,7 @@ font-size: 14px; line-height: 1.5; padding: 20px; - margin: 0; + margin: 10px 0 0 0; } .getPackagesDiv, .signRepoDiv, .createRepoDiv { @@ -124,12 +124,15 @@ justify-content: space-between; align-items: center; column-gap: 10px; - padding: 10px 20px; + padding: 20px; border-radius: 8px; } .task-step-content { - min-height: 100px; + /* display: grid; */ + grid-template-columns: 96% 4%; + justify-content: space-between; + min-height: 250px; max-height: 700px; overflow-y: auto; border-radius: 8px; @@ -142,10 +145,24 @@ box-shadow: rgb(0 0 0) 0px 10px 13px -12px, rgb(0 0 0 / 15%) 0px 0px 10px 2px; } +.task-sub-step-container { + border-right: 1px solid #24405c; +} + .task-sub-step-content, .step-loading { display: grid; grid-template-columns: minmax(20px, 20px) auto; column-gap: 10px; border-top: 1px solid #24405c; padding: 15px; -} \ No newline at end of file +} + +.step-content-btns { + display: flex; + flex-direction: column; + align-items: center; + row-gap: 5px; + position: sticky; + top: 50%; + transform: translateY(-50%); +} diff --git a/www/views/includes/containers/tasks/log.inc.php b/www/views/includes/containers/tasks/log.inc.php index 71950e2e..d7b50aaf 100644 --- a/www/views/includes/containers/tasks/log.inc.php +++ b/www/views/includes/containers/tasks/log.inc.php @@ -15,23 +15,19 @@ + endif; -
+ diff --git a/www/views/includes/containers/tasks/log/step-content.inc.php b/www/views/includes/containers/tasks/log/step-content.inc.php index 5f80c3c6..17820e0c 100644 --- a/www/views/includes/containers/tasks/log/step-content.inc.php +++ b/www/views/includes/containers/tasks/log/step-content.inc.php @@ -1,15 +1,17 @@ -