Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package openQA for openSUSE:Factory checked in at 2026-08-17 16:59:01 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openQA (Old) and /work/SRC/openSUSE:Factory/.openQA.new.1258 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openQA" Mon Aug 17 16:59:01 2026 rev:874 rq:1371468 version:5.1786788019.aa348157 Changes: -------- --- /work/SRC/openSUSE:Factory/openQA/openQA.changes 2026-08-14 22:08:18.938910858 +0200 +++ /work/SRC/openSUSE:Factory/.openQA.new.1258/openQA.changes 2026-08-17 17:02:18.271052682 +0200 @@ -1,0 +2,12 @@ +Mon Aug 17 01:54:40 UTC 2026 - [email protected] + +- Update to version 5.1786788019.aa348157: + * refactor(ui): remove jQuery from core utility scripts + * fix(layout): Avoid horizontal scrollbar on the whole page + * chore(deps): Dependency cron 2026-08-14 + * refactor: remove deprecated job templates table view + * fix(storage): correct MD RAID0 setup and Agama schema validation + * feat: Add experimental log view mode to test details + * refactor(css): Use classes for preview containers + +------------------------------------------------------------------- Old: ---- openQA-5.1786629850.d1bdb83d.obscpio New: ---- openQA-5.1786788019.aa348157.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openQA-client-test.spec ++++++ --- /var/tmp/diff_new_pack.7eZTd5/_old 2026-08-17 17:02:19.921110982 +0200 +++ /var/tmp/diff_new_pack.7eZTd5/_new 2026-08-17 17:02:19.923111053 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-client Name: %{short_name}-test -Version: 5.1786629850.d1bdb83d +Version: 5.1786788019.aa348157 Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-devel-test.spec ++++++ --- /var/tmp/diff_new_pack.7eZTd5/_old 2026-08-17 17:02:19.949111972 +0200 +++ /var/tmp/diff_new_pack.7eZTd5/_new 2026-08-17 17:02:19.952112078 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-devel Name: %{short_name}-test -Version: 5.1786629850.d1bdb83d +Version: 5.1786788019.aa348157 Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-test.spec ++++++ --- /var/tmp/diff_new_pack.7eZTd5/_old 2026-08-17 17:02:19.983113173 +0200 +++ /var/tmp/diff_new_pack.7eZTd5/_new 2026-08-17 17:02:19.986113279 +0200 @@ -18,7 +18,7 @@ %define short_name openQA Name: %{short_name}-test -Version: 5.1786629850.d1bdb83d +Version: 5.1786788019.aa348157 Release: 0 Summary: Test package for openQA License: GPL-2.0-or-later ++++++ openQA-worker-test.spec ++++++ --- /var/tmp/diff_new_pack.7eZTd5/_old 2026-08-17 17:02:20.018114410 +0200 +++ /var/tmp/diff_new_pack.7eZTd5/_new 2026-08-17 17:02:20.019114445 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-worker Name: %{short_name}-test -Version: 5.1786629850.d1bdb83d +Version: 5.1786788019.aa348157 Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA.spec ++++++ --- /var/tmp/diff_new_pack.7eZTd5/_old 2026-08-17 17:02:20.055115717 +0200 +++ /var/tmp/diff_new_pack.7eZTd5/_new 2026-08-17 17:02:20.058115823 +0200 @@ -104,7 +104,7 @@ %define devel_requires %devel_no_selenium_requires chromedriver Name: openQA -Version: 5.1786629850.d1bdb83d +Version: 5.1786788019.aa348157 Release: 0 Summary: Framework for automated system-level testing (web-frontend, scheduler and tools) Group: Development/Tools/Other ++++++ openQA-5.1786629850.d1bdb83d.obscpio -> openQA-5.1786788019.aa348157.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1786629850.d1bdb83d/assets/javascripts/back_to_top.js new/openQA-5.1786788019.aa348157/assets/javascripts/back_to_top.js --- old/openQA-5.1786629850.d1bdb83d/assets/javascripts/back_to_top.js 2026-08-13 16:04:10.000000000 +0200 +++ new/openQA-5.1786788019.aa348157/assets/javascripts/back_to_top.js 2026-08-15 12:00:19.000000000 +0200 @@ -1,17 +1,15 @@ function backToTop() { - $(document).ready(function () { - $(window).scroll(function () { - // Increase the value to not show the button on shorter pages - if ($(this).scrollTop() > 50) { - $('#back-to-top').fadeIn(); - } else { - $('#back-to-top').fadeOut(); - } - }); - $('#back-to-top').click(function () { - $('#back-to-top').tooltip('hide'); - $('body, html').animate({scrollTop: 0}, 800); - return false; - }); + const button = document.getElementById('back-to-top'); + if (!button) return; + + window.addEventListener('scroll', () => { + // Increase the value to not show the button on shorter pages + button.style.display = window.scrollY > 50 ? 'block' : 'none'; + }); + button.addEventListener('click', () => { + const tooltip = bootstrap.Tooltip.getInstance(button); + if (tooltip) tooltip.hide(); + window.scrollTo({top: 0, behavior: 'smooth'}); + return false; }); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1786629850.d1bdb83d/assets/javascripts/job_templates.js new/openQA-5.1786788019.aa348157/assets/javascripts/job_templates.js --- old/openQA-5.1786629850.d1bdb83d/assets/javascripts/job_templates.js 2026-08-13 16:04:10.000000000 +0200 +++ new/openQA-5.1786788019.aa348157/assets/javascripts/job_templates.js 2026-08-15 12:00:19.000000000 +0200 @@ -1,342 +1,6 @@ -let job_templates_url; -let job_group_id; let user_is_admin; let editor; -function setupJobTemplates(url, id) { - job_templates_url = url; - job_group_id = id; - $.ajax(url + '?group_id=' + id).done(loadJobTemplates); -} - -function loadJobTemplates(data) { - const mediagroups = {}; - const groups = []; - $.each(data.JobTemplates, function (i, jt) { - let media = mediagroups[jt.product.group]; - if (!media) { - groups.push(jt.product.group); - media = []; - } - media.push(jt); - mediagroups[jt.product.group] = media; - }); - groups.sort(); - $.each(groups, function (i, group) { - buildMediumGroup(group, mediagroups[group]); - }); - const width = alignCols() - 16; - $('#loading').remove(); - $('.chosen-select').chosen({width: width + 'px'}); - $(document).on('change', '.chosen-select', chosenChanged); -} - -function highlightChosen(chosen) { - const container = chosen.parent('td').find('.chosen-container'); - container.fadeTo('fast', 0.3).fadeTo('fast', 1); -} - -function templateRemoved(chosen, deselected) { - const jid = chosen.find('option[value="' + deselected + '"]').data('jid'); - $.ajax({ - url: job_templates_url + '/' + jid, - type: 'DELETE', - dataType: 'json' - }) - .done(function () { - highlightChosen(chosen); - }) - .fail(addFailed); -} - -function addFailed(data) { - // display something without alert - if (Object.prototype.hasOwnProperty.call(data, 'responseJSON')) { - alert(data.responseJSON.error); - } else { - alert('unknown error'); - } -} - -function addSucceeded(chosen, selected, data) { - chosen.find('option[value="' + selected + '"]').data('jid', data['id']); - highlightChosen(chosen); -} - -// after a machine was added the select is final -function finalizeTest(tr) { - const test_select = tr.find('td.name select'); - if (!test_select.length) return; - - // disable select and assign the selected ID to the row - test_select.prop('disabled', true); - tr.data('test-id', test_select.find('option:selected').data('test-id')); - - // make test unavailable in other selections - const tbody = tr.parents('tbody'); - presentTests = findPresentTests(tbody); - tbody.find('td.name select').each(function (index, select) { - select = $(select); - if (!select.prop('disabled')) { - filterTestSelection(select, presentTests); - } - }); -} - -function formatPriority(prio) { - return !prio || prio.length === 0 ? 'inherit' : prio; -} - -function templateAdded(chosen, selected) { - const tr = chosen.parents('tr'); - finalizeTest(tr); - const postData = { - prio: formatPriority(tr.find('.prio input').val()), - group_id: job_group_id, - product_id: chosen.data('product-id'), - machine_id: chosen.find('option[value="' + selected + '"]').data('machine-id'), - test_suite_id: tr.data('test-id') - }; - - $.ajax({ - url: job_templates_url, - type: 'POST', - dataType: 'json', - data: postData - }) - .fail(addFailed) - .done(function (data) { - addSucceeded(chosen, selected, data); - }); -} - -function priorityChanged(priorityInput) { - const tr = priorityInput.parents('tr'); - - // just skip if there are no machines added anyways - const hasMachines = tr.find('td.arch select option:selected').length > 0; - if (!hasMachines) { - return; - } - - $.ajax({ - url: job_templates_url, - type: 'POST', - dataType: 'json', - data: { - prio: formatPriority(priorityInput.val()), - prio_only: true, - group_id: job_group_id, - test_suite_id: tr.data('test-id') - } - }).fail(addFailed); -} - -function chosenChanged(evt, param) { - if (param.deselected) { - templateRemoved($(this), param.deselected); - } else { - templateAdded($(this), param.selected); - } -} - -function testChanged() { - const select = $(this); - const selectedValue = select.find('option:selected').val(); - const noSelection = !selectedValue || selectedValue.length === 0; - const tr = select.parents('tr'); - const chosens = tr.find('.chosen-select'); - const inputs = tr.find('input'); - chosens.prop('disabled', noSelection).trigger('chosen:updated'); - inputs.prop('disabled', noSelection); -} - -function findPresentTests(table) { - const presentTests = []; - table.find('td.name').each(function (index, td) { - let test; - const select = $(td).find('select'); - if (select.length && select.prop('disabled')) { - test = select.val(); - } else { - test = td.innerText.trim(); - } - if (test) { - presentTests.push(test); - } - }); - return presentTests; -} - -function filterTestSelection(select, presentTests) { - select.find('option').each(function (index, option) { - if (presentTests.indexOf(option.innerText.trim()) >= 0) { - $(option).remove(); - } - }); -} - -function makePrioCell(prio, disabled) { - // use default priority if no prio passed; also disable the input in this case - const useDefaultPrio = !prio; - let defaultPrio = $('#editor-default-priority').data('initial-value'); - if (!defaultPrio) { - defaultPrio = 50; - } - if (!prio) { - prio = defaultPrio; - } - - const td = $('<td class="prio"></td>'); - const prioInput = $('<input type="number"></input>'); - if (!useDefaultPrio) { - prioInput.val(prio); - } - prioInput.change(function () { - priorityChanged($(this)); - }); - prioInput.prop('disabled', disabled); - prioInput.attr('placeholder', defaultPrio); - prioInput.appendTo(td); - return td; -} - -function buildMediumGroup(group, media) { - const div = $('<div class="jobtemplate-medium"/>').appendTo('#media'); - div.append('<div class="jobtemplate-header">' + group + '</div>'); - const table = $('<table class="table table-striped mediagroup" id="' + group + '"/>').appendTo(div); - const thead = $('<thead/>').appendTo(table); - const tr = $('<tr/>').appendTo(thead); - const tname = tr.append($('<th class="name">Test</th>')); - const prioHeading = $('<th class="prio">Prio</th>'); - prioHeading.css('white-space', 'nowrap'); - const prioHelpPopover = $( - '<a href="#" class="help_popover fa-solid fa-circle-question"" data-content="' + - 'The priority can be set for each row specifically. However, the priority might be left empty as well. ' + - 'In this case default priority for the whole job group is used (displayed in italic font)." data-bs-toggle="popover" ' + - 'data-trigger="focus" role="button"></a>' - ); - prioHelpPopover.popover({html: true}); - prioHeading.append(prioHelpPopover); - tr.append(prioHeading); - const archs = {}; - const tests = {}; - const prio = 444; - $.each(media, function (index, temp) { - let a = archs[temp.product.arch]; - if (!a) a = {}; - if (!Object.prototype.hasOwnProperty.call(a, temp.test_suite.name)) { - a[temp.test_suite.name] = []; - table.data('product-' + temp.product.arch, temp.product.id); - a['_id'] = temp.product.id; - } - a[temp.test_suite.name].push(temp); - archs[temp.product.arch] = a; - tests[temp.test_suite.name] = { - prio: temp.prio, - id: temp.test_suite.id - }; - }); - const archnames = Object.keys(archs).sort(); - table.data('archs', archnames); - const testnames = Object.keys(tests).sort(); - $.each(archnames, function (index, arch) { - const a = $('<th class="arch arch_' + arch + '">' + arch + '</th>').appendTo(tr); - }); - const tbody = $('<tbody/>').appendTo(table); - $.each(testnames, function (ti, test) { - const tr = $('<tr class="test_' + test + '"/>').appendTo(tbody); - tr.data('test-id', tests[test]['id']); - let shortname = test; - if (test.length >= 70) { - shortname = '<span title=' + test + '>' + test.substr(0, 67) + '…</span>'; - } - $('<td class="name">' + shortname + '</td>').appendTo(tr); - makePrioCell(tests[test].prio, false).appendTo(tr); - - $.each(archnames, function (archIndex, arch) { - const td = $('<td class="arch"/>').appendTo(tr); - const select = $('#machines-template').clone().appendTo(td); - select.attr('id', group + '-' + arch + '-' + test); - select.attr('data-product-id', archs[arch]['_id']); - select.addClass('chosen-select'); - if ( - Object.prototype.hasOwnProperty.call(archs, arch) && - Object.prototype.hasOwnProperty.call(archs[arch], test) - ) { - $.each(archs[arch][test], function (mi, temp) { - const option = select.find("option[value='" + temp.machine.name + "']").prop('selected', true); - // remember the id for DELETE - option.data('jid', temp.id); - }); - } - }); - }); -} - -function addArchSpacer(table, position, method) { - $(table).find('thead th.arch').eq(position)[method]('<th class="arch"> </th>'); - $(table) - .find('tbody tr') - .each(function () { - $(this).find('td.arch').eq(position)[method]('<td class="arch"> </td>'); - }); -} - -function findHeaderWithAllArchitectures() { - let headerWithAllArchs = []; - $('table.mediagroup thead').each(function () { - const archs = $(this).find('th.arch'); - if (archs.length > headerWithAllArchs.length) headerWithAllArchs = archs; - }); - return headerWithAllArchs; -} - -function fillEmptySpace(table, tableHead, headerWithAllArchs) { - if (tableHead.length < headerWithAllArchs.length) { - headerWithAllArchs.each(function (i) { - // Used all ths, fill the rest - if (tableHead.length == i) { - for (let j = i; j < headerWithAllArchs.length; j++) { - addArchSpacer(table, j - 1, 'after'); - } - return false; - } else if (this.innerHTML != tableHead.get(i).innerHTML) { - addArchSpacer(table, i, 'before'); - tableHead = $(table).find('thead th.arch'); - } - }); - } -} - -function alignCols() { - // Set minimal width - $('th.name,th.prio').width('0'); - - // Find biggest minimal width - let namewidth = 450; - $('td.name').each(function (index, test) { - if ($(this).outerWidth() > namewidth) namewidth = $(this).outerWidth(); - }); - namewidth = Math.ceil(namewidth); - - const headerWithAllArchs = findHeaderWithAllArchitectures(); - - // Fill empty space - $('table.mediagroup').each(function (index, table) { - fillEmptySpace(table, $(this).find('thead th.arch'), headerWithAllArchs); - }); - - // Compute arch width - let archwidth = $('.jobtemplate-header').outerWidth() - namewidth - $('th.prio').outerWidth(); - archwidth = Math.floor(archwidth / headerWithAllArchs.length) - 1; - - $('th.name').outerWidth(namewidth); - $('th.arch').outerWidth(archwidth); - - return archwidth; -} - function toggleEdit() { $('#properties').toggle(250); validateJobGroupForm(document.getElementById('group_properties_form')); @@ -349,13 +13,11 @@ } } -function toggleTemplateEditor() { - $('#media').toggle(250); +function setupTemplateEditor() { const form = $('#editor-form'); - form.toggle(250); + form.show(); form.find('.buttons').hide(); form.find('.progress-indication').show(); - $('#toggle-yaml-editor').toggleClass('btn-secondary'); if (editor === undefined) { editor = ace.edit('editor-template', { mode: 'ace/mode/yaml', @@ -463,9 +125,6 @@ value = data.changes; break; case 'save': - // Once a valid YAML template was saved we no longer offer the legacy editor - $('#toggle-yaml-editor').hide(); - $('#media-add').hide(); // Update the reference to the saved document form.data('reference', editor.getValue()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1786629850.d1bdb83d/assets/javascripts/openqa.js new/openQA-5.1786788019.aa348157/assets/javascripts/openqa.js --- old/openQA-5.1786629850.d1bdb83d/assets/javascripts/openqa.js 2026-08-13 16:04:10.000000000 +0200 +++ new/openQA-5.1786788019.aa348157/assets/javascripts/openqa.js 2026-08-15 12:00:19.000000000 +0200 @@ -19,8 +19,9 @@ updateTimeago(); document.querySelectorAll('[data-bs-toggle="popover"]').forEach(e => new bootstrap.Popover(e, {html: true})); document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(e => new bootstrap.Tooltip(e, {html: true})); - $.ajaxSetup({ - headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')} + + window.jQuery?.ajaxSetup({ + headers: {'X-CSRF-TOKEN': getCSRFToken()} }); } @@ -36,20 +37,36 @@ } function makeFlashElement(text) { - return typeof text === 'string' ? '<span>' + text + '</span>' : text; + if (typeof text === 'string') { + const span = document.createElement('span'); + span.innerHTML = text; + return span; + } + return text; } function addFlash(status, text, container, method = 'append') { // add flash messages by default on top of the page if (!container) { - container = $('#flash-messages'); + container = document.getElementById('flash-messages'); } - const div = $('<div class="alert alert-primary alert-dismissible fade show" role="alert"></div>'); - div.append(makeFlashElement(text)); - div.append('<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>'); - div.addClass('alert-' + status); - container[method](div); + const div = document.createElement('div'); + div.className = `alert alert-primary alert-dismissible fade show alert-${status}`; + div.setAttribute('role', 'alert'); + div.appendChild(makeFlashElement(text)); + const closeButton = document.createElement('button'); + closeButton.type = 'button'; + closeButton.className = 'btn-close'; + closeButton.setAttribute('data-bs-dismiss', 'alert'); + closeButton.setAttribute('aria-label', 'Close'); + div.appendChild(closeButton); + + if (method === 'prepend') { + container.prepend(div); + } else { + container.append(div); + } return div; } @@ -61,21 +78,21 @@ // update existing flash message const existingFlashMessage = window.uniqueFlashMessages[id]; if (existingFlashMessage) { - existingFlashMessage.find('span').first().replaceWith(makeFlashElement(text)); + existingFlashMessage.querySelector('span').replaceWith(makeFlashElement(text)); return; } const msgElement = addFlash(status, text, container, method); window.uniqueFlashMessages[id] = msgElement; - msgElement.on('closed.bs.alert', function () { + msgElement.addEventListener('closed.bs.alert', function () { delete window.uniqueFlashMessages[id]; }); } function toggleChildGroups(link) { - const buildRow = $(link).parents('.build-row'); - buildRow.toggleClass('children-collapsed'); - buildRow.toggleClass('children-expanded'); + const buildRow = link.closest('.build-row'); + buildRow.classList.toggle('children-collapsed'); + buildRow.classList.toggle('children-expanded'); return false; } @@ -97,8 +114,8 @@ } const search = []; const hash = document.location.hash; - $.each(params, function (key, values) { - $.each(values, function (index, value) { + Object.entries(params).forEach(([key, values]) => { + values.forEach(value => { if (value === undefined) { search.push(encodeURIComponent(key)); } else { @@ -112,13 +129,13 @@ function renderDataSize(sizeInByte) { let unitFactor = 1073741824; // one GiB let sizeWithUnit = 0; - $.each([' GiB', ' MiB', ' KiB', ' byte'], function (index, unit) { + for (const unit of [' GiB', ' MiB', ' KiB', ' byte']) { if (!unitFactor || sizeInByte >= unitFactor) { sizeWithUnit = Math.round((sizeInByte / unitFactor) * 100) / 100 + unit; - return false; + break; } unitFactor >>= 10; - }); + } return sizeWithUnit; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1786629850.d1bdb83d/assets/javascripts/render.js new/openQA-5.1786788019.aa348157/assets/javascripts/render.js --- old/openQA-5.1786629850.d1bdb83d/assets/javascripts/render.js 2026-08-13 16:04:10.000000000 +0200 +++ new/openQA-5.1786788019.aa348157/assets/javascripts/render.js 2026-08-15 12:00:19.000000000 +0200 @@ -121,12 +121,16 @@ const srcElement = srcUrl ? E('a', [module.name], {href: srcUrl}) : E('span', [module.name]); const component = E('td', [E('div', [srcElement]), E('div', flags, {class: 'flags'})], {class: 'component'}); - const result = E('td', [module.result], {class: 'result ' + moduleResultCSS(module.result)}); + const result = E('td', [module.result], { + class: 'result ' + moduleResultCSS(module.result), + style: 'position: relative' + }); const showPreviewForLink = function () { setCurrentPreview($(this).parent()); // show the preview when clicking on step links return false; }; + let hasTextResults = false; for (const idx in module.details) { const step = module.details[idx]; const title = step.display_title; @@ -202,6 +206,7 @@ box.push(E('span', [content], {class: 'resborder ' + resborder})); } if (step.text && title !== 'Soft Failed') { + hasTextResults = true; const stepActions = E('span', [], {class: 'step_actions', style: 'float: right'}); stepActions.innerHTML = renderTemplate(snippets.bug_actions, {MODULE: module.name, STEP: step.num}); @@ -214,6 +219,7 @@ const link = E('a', box, { class: 'no_hover' + (title === 'wait_serial' ? ' serial-result-preview' : ''), 'data-text': txt, + 'data-textorig': textData, title: title, href: href }); @@ -237,6 +243,17 @@ } } + if (hasTextResults) { + const expandIcon = E('i', [''], {class: 'fa fa-expand'}); + const expandButton = E('button', [expandIcon], { + class: 'logview_expand_btn', + 'aria-label': 'Expand row', + title: 'Expand row' + }); + expandButton.onclick = () => showTextBoxes(expandButton); + result.firstChild.before(expandButton); + } + const links = E('td', stepnodes, {class: 'links'}); return E('tr', [component, result, links], {id: rowid}); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1786629850.d1bdb83d/assets/javascripts/test_result.js new/openQA-5.1786788019.aa348157/assets/javascripts/test_result.js --- old/openQA-5.1786629850.d1bdb83d/assets/javascripts/test_result.js 2026-08-13 16:04:10.000000000 +0200 +++ new/openQA-5.1786788019.aa348157/assets/javascripts/test_result.js 2026-08-15 12:00:19.000000000 +0200 @@ -1,6 +1,8 @@ // jshint multistr: true // jshint esversion: 6 +let details_mode = 'default'; + const testGitInfoRe = /TEST_GIT_HASH=([a-fA-F0-9]+) TEST_GIT_URL=([^\p{Cc}]+)/u; const testStatus = { @@ -117,6 +119,13 @@ // insert and initialize preview data pin.html(data); pout.insertAfter(stepPreviewContainer); + if (details_mode === 'log') { + const caretSpace = 15; // .fa-caret-up is positioned bottom: -25px + pout.css('top', stepPreviewContainer.position().top + stepPreviewContainer.outerHeight() + caretSpace); + } else { + pout.css('top', ''); + } + if (!(pin.find('pre').length || pin.find('audio').length)) { const imageSource = pin.find('#step_view').data('image'); if (!imageSource) { @@ -229,6 +238,13 @@ stepPreviewContainer.addClass('current_preview'); setPageHashAccordingToCurrentTab(link.attr('href')); const text = unescape(link.data('text')); + if (details_mode === 'log') { + hidePreviewContainer(); + const log_container = stepPreviewContainer.get(0).nextElementSibling; + log_container.querySelector('div').innerHTML = text; + return; + } + previewSuccess(stepPreviewContainer, text, force); return; } @@ -248,6 +264,46 @@ }); } +function showTextBoxes(el) { + setCurrentPreview(null); + const E = createElement; + const currentTd = el.closest('td'); + const nextTd = currentTd.nextElementSibling; + const divs = nextTd.querySelectorAll('div.links_a'); + divs.forEach(div => { + const cl = div.getAttribute('class'); + + if (details_mode === 'log') { + div.classList.remove('logview'); + } else { + const link = div.querySelector('a'); + const textData = link.dataset.textorig; + if (textData) { + const textresult = E('pre', [textData]); + const logbox_inner = E('div', [textresult], {class: 'log_container_in preview_container_inner'}); + const logbox = E('div', [logbox_inner], {class: 'log_container_out preview_container_outer'}); + div.after(logbox); + } + div.classList.add('logview'); + } + }); + el.firstChild.classList.toggle('fa-expand'); + el.firstChild.classList.toggle('fa-compress'); + if (details_mode === 'log') { + details_mode = 'default'; + el.setAttribute('title', 'Expand row'); + el.setAttribute('aria-lebel', 'Expand row'); + const logdivs = nextTd.querySelectorAll('div.log_container_out'); + logdivs.forEach(div => { + div.remove(); + }); + } else { + details_mode = 'log'; + el.setAttribute('title', 'Collapse row'); + el.setAttribute('aria-lebel', 'Collapse row'); + } +} + function selectPreview(which) { const currentPreview = $('.current_preview'); let linkContainer = currentPreview[which](); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1786629850.d1bdb83d/assets/stylesheets/dashboard.scss new/openQA-5.1786788019.aa348157/assets/stylesheets/dashboard.scss --- old/openQA-5.1786629850.d1bdb83d/assets/stylesheets/dashboard.scss 2026-08-13 16:04:10.000000000 +0200 +++ new/openQA-5.1786788019.aa348157/assets/stylesheets/dashboard.scss 2026-08-15 12:00:19.000000000 +0200 @@ -173,6 +173,9 @@ #results_filter label { vertical-align: top; } +#results td.links { + max-width: 0; /* Forces cell to obey overflow rules of inner content */ +} .corner-buttons { display: inline-block; float: right; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1786629850.d1bdb83d/assets/stylesheets/result_preview.scss new/openQA-5.1786788019.aa348157/assets/stylesheets/result_preview.scss --- old/openQA-5.1786629850.d1bdb83d/assets/stylesheets/result_preview.scss 2026-08-13 16:04:10.000000000 +0200 +++ new/openQA-5.1786788019.aa348157/assets/stylesheets/result_preview.scss 2026-08-15 12:00:19.000000000 +0200 @@ -1,13 +1,27 @@ -#preview_container_out { +.logview_expand_btn { position: absolute; - z-index: 4; - display: none; - margin-top: 10px; + top: -2px; + right: 0; + background: transparent; + border: none; + cursor: pointer; + padding: 0; + color: grey; +} +div.log_container_out { + float: left; + width: 90%; + margin-top: 0 !important; + margin-bottom: 0 !important; +} +div.log_container_in { + position: relative; +} +div.preview_container_outer { margin-bottom: 7px; } -#preview_container_in { +div.preview_container_inner { padding: 5px; - position: absolute; right: 0; text-align: center; background-color: #f5f5f5; @@ -36,6 +50,15 @@ background-color: inherit; } } +#preview_container_out { + z-index: 4; + position: absolute; + display: none; + margin-top: 10px; +} +#preview_container_in { + position: absolute; +} [data-bs-theme='dark'] #preview_container_in { background-color: #0a0a0a; } @@ -46,7 +69,11 @@ color: $default-font-color-dark; background-color: $default-bg-color-dark; } -.links > div { +.links > div.logview { + clear: left; + float: left; +} +.links > div.links_a { display: inline-block; margin-top: 3px; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1786629850.d1bdb83d/contrib/agama-openqa-worker.jsonnet new/openQA-5.1786788019.aa348157/contrib/agama-openqa-worker.jsonnet --- old/openQA-5.1786629850.d1bdb83d/contrib/agama-openqa-worker.jsonnet 2026-08-13 16:04:10.000000000 +0200 +++ new/openQA-5.1786788019.aa348157/contrib/agama-openqa-worker.jsonnet 2026-08-15 12:00:19.000000000 +0200 @@ -13,28 +13,38 @@ std.filter(function(d) d.logicalname != os_disk, disks_with_size) ); -// Helper function to create a unique, safe alias from the device name (e.g., "/dev/sdb" -> "raid-sdb") +// Helper function to create a unique, safe alias from the device name local raid_alias = function(dev_name) "raid-" + std.strReplace(dev_name, "/dev/", ""); +// Check if we actually have enough extra disks to form a RAID 0 +local has_enough_disks_for_raid = std.length(extra_disks) >= 2; + // 1. Build the OS drive config local os_drive_config = if os_disk != null then [{ search: os_disk, - partitions: [{ search: '*', delete: true }, { generate: 'default' }], + partitions: [{ search: {}, delete: true }, { generate: 'default' }], }] else []; // 2. Build the extra drives config dynamically -// Omitting 'size' tells Agama to use the maximum available space on the disk for the partition. local extra_drives_config = std.map( function(disk) { search: disk, - partitions: [{ search: '*', delete: true }, { alias: raid_alias(disk) }] + ptableType: 'gpt', + partitions: [ + { search: {}, delete: true }, + // If we have 2+ disks, prep them for RAID. Otherwise, prep as a standard Linux partition. + if has_enough_disks_for_raid then + { alias: raid_alias(disk), id: 'raid' } + else + { id: 'linux' } + ] }, extra_disks ); -// 3. Build the mdRaids config using the generated aliases +// 3. Build the mdRaids config ONLY if we have at least 2 disks local mdraids = - if std.length(extra_disks) > 0 then + if has_enough_disks_for_raid then [{ devices: std.map(raid_alias, extra_disks), level: "raid0", @@ -47,8 +57,8 @@ id: 'openSUSE_Leap' }, storage: { - // Concatenate the OS drive and the dynamically generated extra drives drives: os_drive_config + extra_drives_config, + // If mdraids is empty, Agama will just ignore it safely mdRaids: mdraids }, localization: { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1786629850.d1bdb83d/lib/OpenQA/WebAPI/Controller/Admin/JobTemplate.pm new/openQA-5.1786788019.aa348157/lib/OpenQA/WebAPI/Controller/Admin/JobTemplate.pm --- old/openQA-5.1786629850.d1bdb83d/lib/OpenQA/WebAPI/Controller/Admin/JobTemplate.pm 2026-08-13 16:04:10.000000000 +0200 +++ new/openQA-5.1786788019.aa348157/lib/OpenQA/WebAPI/Controller/Admin/JobTemplate.pm 2026-08-15 12:00:19.000000000 +0200 @@ -9,20 +9,11 @@ my $group = $schema->resultset('JobGroups')->find($self->param('groupid')); return $self->reply->not_found unless $group; - my $yaml = $group->template; - my $force_yaml_editor - = defined $yaml || $schema->resultset('JobTemplates')->search({group_id => $group->id}, {rows => 1})->count == 0; $self->stash( group => $group, - yaml_template => $yaml, - force_yaml_editor => $force_yaml_editor, + yaml_template => $group->template, ); - my @machines = $schema->resultset('Machines')->search(undef, {order_by => 'name'}); - $self->stash(machines => \@machines); - my @tests = $schema->resultset('TestSuites')->search(undef, {order_by => 'name'}); - $self->stash(tests => \@tests); - $self->render('admin/job_template/index'); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1786629850.d1bdb83d/t/ui/13-admin.t new/openQA-5.1786788019.aa348157/t/ui/13-admin.t --- old/openQA-5.1786629850.d1bdb83d/t/ui/13-admin.t 2026-08-13 16:04:10.000000000 +0200 +++ new/openQA-5.1786788019.aa348157/t/ui/13-admin.t 2026-08-15 12:00:19.000000000 +0200 @@ -494,10 +494,8 @@ my ($yaml, $form); subtest 'open YAML editor for legacy group' => sub { $driver->get('/admin/job_templates/1001'); - $form = $driver->find_element_by_id('editor-form'); - ok $form->is_hidden(), 'editor form is not shown by default'; - $driver->find_element_by_id('toggle-yaml-editor')->click(); wait_for_ajax; + $form = $driver->find_element_by_id('editor-form'); ok $form->is_displayed(), 'editor form is shown'; ok $form->child('.progress-indication')->is_hidden(), 'spinner is hidden'; $yaml = $driver->execute_script('return editor.getValue();'); @@ -560,8 +558,8 @@ or always_explain $result->get_text(); # Legacy UI is hidden and no longer available - ok $driver->find_element_by_id('toggle-yaml-editor')->is_hidden(), 'editor toggle hidden'; - ok $driver->find_element_by_id('media')->is_hidden(), 'media editor hidden'; + is scalar @{$driver->find_elements('toggle-yaml-editor', 'id')}, 0, 'editor toggle not present'; + is scalar @{$driver->find_elements('media', 'id')}, 0, 'media editor not present'; # More changes on top of the previous ones $yaml .= " - advanced_kde_high_prio:\n"; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1786629850.d1bdb83d/templates/webapi/admin/job_template/index.html.ep new/openQA-5.1786788019.aa348157/templates/webapi/admin/job_template/index.html.ep --- old/openQA-5.1786629850.d1bdb83d/templates/webapi/admin/job_template/index.html.ep 2026-08-13 16:04:10.000000000 +0200 +++ new/openQA-5.1786788019.aa348157/templates/webapi/admin/job_template/index.html.ep 2026-08-15 12:00:19.000000000 +0200 @@ -6,41 +6,15 @@ % title 'Job templates for ' . $group->name; -% unless ($force_yaml_editor) { - <div class="alert alert-danger"> - The old job group view is deprecated and will be removed from - future versions of openQA. Please save the job templates in YAML - format as soon as possible. - </div> -% } - % content_for 'ready_function' => begin user_is_admin = <%= is_admin_js %>; - % if ($force_yaml_editor) { - toggleTemplateEditor(); - % } - % else { - setupJobTemplates("<%= url_for('apiv1_job_templates') %>", <%= $group->id %>); - % } + setupTemplateEditor(); $('#expand-template').click(function() { submitTemplateEditor('expand'); }); $('#preview-template').click(function() { submitTemplateEditor('preview'); }); $('#save-template').click(function() { submitTemplateEditor('save'); }); % end <form action="<%= url_for('admin_groups') %>" class="corner-buttons"> - % if (!$force_yaml_editor) { - <button type="button" id="toggle-yaml-editor" class="btn btn-light" onclick="toggleTemplateEditor();"> - <span> - <i class="fa-solid fa-pen-to-square"></i> - % if (is_admin) { - Edit YAML - % } - % else { - Show YAML - % } - </span> - </button> - % } <button type="button" id="toggle-group-properties" class="btn btn-light" onclick="toggleEdit();"> <span> <i class="fa-solid fa-pen-to-square"></i> @@ -74,30 +48,6 @@ <a href="https://open.qa/docs/#using-job-templates-to-automate-jobs-creation" target="blank">the documentation</a> for more details. </p> - % if (!$force_yaml_editor) { - <div id="media"> - <p id="loading"><i class="fa-solid fa-spinner fa-spin"></i> Loading…</p> - - <select id="machines-template" multiple="true" disabled data-placeholder="None" style="display: none"> - % for my $machine (@$machines) { - <option value="<%= $machine->name %>" - data-machine-id="<%= $machine->id %>" > - %= $machine->name - </option> - % } - </select> - - <select id="tests-template" disabled style="display: none"> - <option value="">Select…</option> - % for my $test (@$tests) { - <option value="<%= $test->name %>" data-test-id="<%= $test->id %>"> - %= $test->name - </option> - % } - </select> - - </div> - % } <form action="#" id="editor-form" class="form-horizontal" style="display: none;" data-put-url="<%= url_for('apiv1_job_templates_schedules' => (id => $group->id)) %>" data-reference="<%= $yaml_template %>"> <div class="row"> @@ -204,9 +154,3 @@ </div> </div> </form> - - % if (!$force_yaml_editor && is_admin) { - <p> - <i class="fa-solid fa-plus-square"></i> Please save as YAML to add new medium as part of this group - </p> - % } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1786629850.d1bdb83d/templates/webapi/test/result.html.ep new/openQA-5.1786788019.aa348157/templates/webapi/test/result.html.ep --- old/openQA-5.1786629850.d1bdb83d/templates/webapi/test/result.html.ep 2026-08-13 16:04:10.000000000 +0200 +++ new/openQA-5.1786788019.aa348157/templates/webapi/test/result.html.ep 2026-08-15 12:00:19.000000000 +0200 @@ -100,7 +100,7 @@ </div> </div> -<div id="preview_container_out"> - <div id="preview_container_in" class="well well-lg"> +<div id="preview_container_out" class="preview_container_outer"> + <div id="preview_container_in" class="well well-lg preview_container_inner"> </div> </div> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1786629850.d1bdb83d/tools/ci/autoinst.sha new/openQA-5.1786788019.aa348157/tools/ci/autoinst.sha --- old/openQA-5.1786629850.d1bdb83d/tools/ci/autoinst.sha 2026-08-13 16:04:10.000000000 +0200 +++ new/openQA-5.1786788019.aa348157/tools/ci/autoinst.sha 2026-08-15 12:00:19.000000000 +0200 @@ -1 +1 @@ -5.044000-93ba8ca76e07943f6f7c9873a02a87ecd7a483fc \ No newline at end of file +5.044000-b29247340708d3e6224cc2dad478bc7290c7ecf0 \ No newline at end of file ++++++ openQA.obsinfo ++++++ --- /var/tmp/diff_new_pack.7eZTd5/_old 2026-08-17 17:02:30.758493892 +0200 +++ /var/tmp/diff_new_pack.7eZTd5/_new 2026-08-17 17:02:30.766494174 +0200 @@ -1,5 +1,5 @@ name: openQA -version: 5.1786629850.d1bdb83d -mtime: 1786629850 -commit: d1bdb83db24dcca85d541d11a9035a98f665d53a +version: 5.1786788019.aa348157 +mtime: 1786788019 +commit: aa348157e5888e5e9ef30dc62039623d7ed9a7cb
