Skip to content

Commit

Permalink
Reuse restartJob in order of restart jobs in Overview page
Browse files Browse the repository at this point in the history
Refactor restartJob in order to make sure that is able to handle request for
multiple restarts. This follows up with some changes to the form and the
javascript part of the overview.html.ep, which triggers the restart with the
use of restartJob, as opposed of reimplement the logic.
The advantage is that we have one common behavior and error handling on the
restart operation.

- An optional comment can be passed not to restartJob, which is included to
the request.
- restartJob handles both single and multible job restarts.
- The form is designed to handle each occasion in separate functions making
the code becomes more modular and easier to maintain.
- The overvies's restartJobs function will restart only jobs with valid id.

https://progress.opensuse.org/issues/166559

Signed-off-by: Ioannis Bonatakis <[email protected]>
  • Loading branch information
b10n1k committed Nov 6, 2024
1 parent 3d3dbc9 commit 29fdf01
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 77 deletions.
32 changes: 26 additions & 6 deletions assets/javascripts/openqa.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,12 @@ function forceJobRestartViaRestartLink(restartLink) {
restartLink.click();
}

function restartJob(ajaxUrl, jobId) {
function restartJob(ajaxUrl, jobIds, comment) {
let singleJobId;
if (!Array.isArray(jobIds)) {
singleJobId = jobIds;
jobIds = [jobIds];
}
var showError = function (reason) {
var errorMessage = '<strong>Unable to restart job';
if (reason) {
Expand All @@ -248,30 +253,45 @@ function restartJob(ajaxUrl, jobId) {
}
addFlash('danger', errorMessage);
};

return fetchWithCSRF(ajaxUrl, {method: 'POST'})
const body = new FormData();
body.append('comment', comment);
return fetchWithCSRF(ajaxUrl, {method: 'POST', body: body})
.then(response => {
if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`;
return response.json();
})
.then(responseJSON => {
var newJobUrl;
try {
newJobUrl = responseJSON.test_url[0][jobId];
if (singleJobId) {
newJobUrl = responseJSON.test_url[0][singleJobId];
} else {
const testUrlData = responseJSON?.test_url;
if (Array.isArray(testUrlData)) {
newJobUrl = testUrlData.map(item => Object.values(item)[0]);
}
}
} catch {
// Intentionally ignore all errors
}
if (
showJobRestartResults(
responseJSON,
newJobUrl,
restartJob.bind(undefined, addParam(ajaxUrl, 'force', '1'), jobId)
restartJob.bind(undefined, addParam(ajaxUrl, 'force', '1'), jobIds, comment)
)
) {
return;
}
if (newJobUrl) {
window.location.replace(newJobUrl);
if (Array.isArray(newJobUrl)) {
addFlash(
'info',
'The jobs have been restarted. <a href="javascript: location.reload()">Reload</a> the page to show changes.'
);
} else {
window.location.replace(newJobUrl);
}
} else {
throw 'URL for new job not available';
}
Expand Down
59 changes: 33 additions & 26 deletions assets/javascripts/overview.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,49 +287,56 @@ function showAddCommentsDialog() {
modal.show();
}

function restartOrCommentJobs(form) {
function restartJobsWithComment(btn) {
const form = btn.form;
const text = form.elements.text.value;
const jobs = btn.dataset.jobs
.split(',')
.map(Number)
.filter(n => !isNaN(n));
const apiUrl = btn.dataset.url;
if (!text.length) {
return window.alert("The comment text mustn't be empty.");
}
const actionBtn = form.clickedButton ? form.clickedButton.value : null;
console.log(actionBtn);
let reqUrl = form.clickedButton.getAttribute('formaction');
console.log(form.clickedButton.getAttribute('formaction'));
const progressIndication = document.getElementById('add-comments-progress-indication');

const progressIndication = document.getElementById('add-comments-progress-indication');
const controls = document.getElementById('add-comments-controls');
progressIndication.style.display = 'flex';
controls.style.display = 'none';
const done = () => {
restartJob(apiUrl, jobs, text).finally(() => {
progressIndication.style.display = 'none';
controls.style.display = 'inline';
window.addCommentsModal.hide();
};
});
}

let infoText =
'The comments have been created. <a href="javascript: location.reload()">Reload</a> the page to show changes.';
let errText = 'The comments could not be added:';
if (actionBtn === 'restartAndCommentJobs') {
infoText = '<a href="javascript: location.reload()">Reload</a> the page to show restarted jobs.';
errText = 'Failed to restart jobs: ';
function addComments(btn) {
const form = btn.form;
const text = form.elements.text.value;
const apiUrl = btn.dataset.url;
if (!text.length) {
return window.alert("The comment text mustn't be empty.");
}
fetchWithCSRF(reqUrl, {method: 'POST', body: new FormData(form)})
const progressIndication = document.getElementById('add-comments-progress-indication');
const controls = document.getElementById('add-comments-controls');
progressIndication.style.display = 'flex';
controls.style.display = 'none';
const done = () => {
progressIndication.style.display = 'none';
controls.style.display = 'inline';
window.addCommentsModal.hide();
};
fetchWithCSRF(apiUrl, {method: 'POST', body: new FormData(form)})
.then(response => {
if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`;
addFlash('info', infoText);
addFlash(
'info',
'The comments have been created. <a href="javascript: location.reload()">Reload</a> the page to show changes.'
);
done();
return response.json();
})
.then(resData => {
console.log(resData);
if (resData.errors && resData.errors.length > 0) {
for (let i in resData.errors) {
addFlash('warning', 'Warning: Errors found in Response:\n' + resData.errors[i].trim());
}
}
})
.catch(error => {
addFlash('danger', `${errText} ${error}`);
addFlash('danger', `The comments could not be added: ${error}`);
done();
});
}
10 changes: 9 additions & 1 deletion assets/stylesheets/overview.scss
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,12 @@
#add-comments-progress-indication {
display: none;
width: 100%;
}
}

.group-comment-icon-stack {
font-size: 0.9em;
}

.group-comment-icon-stack .fa-undo {
color: #0c4374;
}
12 changes: 5 additions & 7 deletions t/ui/10-tests_overview.t
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ like($driver->find_elements('.failedmodule', 'css')->[1]->get_attribute('href'),

my @descriptions = $driver->find_elements('td.name a', 'css');
is(scalar @descriptions, 2, 'only test suites with description content are shown as links');
disable_bootstrap_animations;
$descriptions[0]->click();
is($driver->find_element('.popover-header')->get_text, 'kde', 'description popover shows content');

Expand Down Expand Up @@ -546,15 +545,14 @@ subtest 'filter by result and state' => sub {
subtest "job template names displayed on 'Test result overview' page" => sub {
$driver->get('/group_overview/1002');
is($driver->find_element('.progress-bar-unfinished')->get_text(),
'1 unfinished', 'The number of unfinished jobs is right');
'1 unfinished', 'expected number of unfinished jobs');

$driver->get('/tests/overview?distri=opensuse&version=13.1&build=0091&groupid=1002');
my @tds = $driver->find_elements('#results_DVD tbody tr .name');
is($tds[0]->get_text(), 'kde_variant', 'job template name kde_variant displayed correctly');

my @descriptions = $driver->find_elements('td.name a', 'css');
is(scalar @descriptions, 2, 'only test suites with description content are shown as links');
disable_bootstrap_animations;
$descriptions[0]->click();
is(wait_for_element(selector => '.popover-header')->get_text, 'kde_variant', 'description popover shows content');
};
Expand All @@ -565,7 +563,6 @@ subtest 'add comments' => sub {

$driver->find_element_by_link_text('Login')->click;
$driver->get('/tests/overview?state=done&result=failed');
disable_bootstrap_animations;
$driver->find_element('button[title="Restart or comment jobs"]')->click;
my $comment_text = 'comment via add-comments';
my $submit_button = $driver->find_element('#add-comments-controls button[id="commentJobsBtn"]');
Expand All @@ -584,17 +581,18 @@ subtest 'add comments' => sub {

subtest 'restart jobs with comment' => sub {
$driver->get('/tests/overview?state=done&result=failed');
disable_bootstrap_animations;
$driver->find_element('button[title="Restart or comment jobs"]')->click;
my $comment_text = 'comment current jobs and restart';
my $submit_button = $driver->find_element('#add-comments-controls button[id="restartAndCommentJobsBtn"]');
my $submit_button = $driver->find_element('#restartAndCommentJobsBtn');
$driver->find_element_by_id('text')->send_keys($comment_text);
is $submit_button->get_text, 'Restart and comment on 2 jobs', 'submit button displayed with number of jobs';
$submit_button->click;
wait_for_ajax msg => 'comments created';
like $driver->find_element_by_id('flash-messages')->get_text, qr/Reload the page to show restarted jobs/,
like $driver->find_element_by_id('flash-messages')->get_text, qr/Reload the page to show changes/,
'info about successful restart shown';
my @failed_job_ids = map { $_->id } $jobs->search({result => FAILED})->all;
is $comments->search({job_id => {-in => \@failed_job_ids}, text => $comment_text})->count, 2,
'comments created on all relevant jobs';
is $comments->search({job_id => {-not_in => \@failed_job_ids}, text => $comment_text})->count, 0,
'comments not created on other jobs';
my $running_job_ids = map { $_->id } $jobs->search({state => RUNNING})->all;
Expand Down
72 changes: 35 additions & 37 deletions templates/webapi/test/overview.html.ep
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,10 @@
<div class="card-body">
% my $allow_commenting = @$job_ids && current_user;
% if ($allow_commenting) {
<button type="button" class="btn btn-secondary btn-circle btn-sm
trigger-edit-button" onclick="showAddCommentsDialog()" title="Restart or comment jobs">
<span class="fa-stack" style="font-size: 0.9em" >
<button type="button" class="btn btn-secondary btn-circle btn-sm trigger-edit-button" onclick="showAddCommentsDialog()" title="Restart or comment jobs">
<span class="fa-stack group-comment-icon-stack">
<i class="fa fa-comment fa-stack-2x text-danger-info" aria-hidden="true"></i>
<i class="fa fa-undo fa-stack-1x" style="color: #0c4374;" aria-hidden="true"></i>
<i class="fa fa-undo fa-stack-1x" aria-hidden="true"></i>
</span>
</button>
% }
Expand Down Expand Up @@ -219,40 +218,39 @@

% if ($allow_commenting) {
<div class="modal fade" id="add-comments-modal">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form method="post" onsubmit="restartOrCommentJobs(this); return false;">
<div class="modal-header">
<h4 class="modal-title">Add comment on all currently shown jobs</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
%= include 'comments/add_comment_form_groups', group_comment => 0, nosubmit => 1
</div>
<div class="modal-footer">
<div id="add-comments-progress-indication">
<div class="flex-fill"><i class="fa fa-cog fa-spin fa-fw"></i> Saving…</div>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
<div id="add-comments-controls">
<button type="submit" name="bulkAction" class="btn btn-warning"
value="commentJobs" id="commentJobsBtn"
formaction="<%= url_for('apiv1_post_comments')->query(job_id=>$job_ids) %>"
onclick="form.clickedButton = this;">
<i class="fa fa-comment"></i> Comment on all <%= scalar @$job_ids %> jobs
</button>
<button type="submit" name="bulkAction" class="btn btn-danger"
value="restartAndCommentJobs"
id="restartAndCommentJobsBtn"
formaction="<%= url_for('apiv1_restart_jobs')->query(jobs => $job_ids) %>"
onclick="form.clickedButton = this;">
<i class="fa fa-play-circle-o"></i> Restart and comment on <%= scalar @$job_ids %> jobs
</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Discard</button>
</div>
</div>
</form>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form method="post">
<div class="modal-header">
<h4 class="modal-title">Add comment on all currently shown jobs</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
%= include 'comments/add_comment_form_groups', group_comment => 0, nosubmit => 1
</div>
<div class="modal-footer">
<div id="add-comments-progress-indication">
<div class="flex-fill"><i class="fa fa-cog fa-spin fa-fw"></i> Saving…</div>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
<div id="add-comments-controls">
<button type="button" class="btn btn-warning" id="commentJobsBtn"
data-url="<%= url_for('apiv1_post_comments')->query(job_id=>$job_ids) %>"
onclick="addComments(this);">
<i class="fa fa-comment"></i> Comment on all <%= scalar @$job_ids %> jobs
</button>
<button type="button" class="btn btn-danger" id="restartAndCommentJobsBtn"
data-jobs="<%= join(',', @$job_ids) %>"
data-url="<%= url_for('apiv1_restart_jobs')->query(jobs=>$job_ids) %>"
onclick="restartJobsWithComment(this);">
<i class="fa fa-play-circle-o"></i> Restart and comment on <%= scalar @$job_ids %> jobs
</button>
<button type="button" class="btn btn-secondary"
data-bs-dismiss="modal">Discard</button>
</div>
</div>
</form>
</div>
</div>
</div>
% }

0 comments on commit 29fdf01

Please sign in to comment.