diff --git a/app/dashboard/__init__.py b/app/dashboard/__init__.py index 5d99276c7..33abcbc0a 100644 --- a/app/dashboard/__init__.py +++ b/app/dashboard/__init__.py @@ -196,6 +196,9 @@ def static_html_proxy(path): @app.route( "/_ajax/test/regression", defaults={"api": "TEST_REGRESSION_API_ENDPOINT"}, methods=["GET"]) +@app.route( + "/_ajax/nodes", + defaults={"api": "NEW_API_ENDPOINT"}, methods=["GET"]) def ajax_get(api): if validate_csrf(request.headers.get(CSRF_TOKEN_H, None)): return backend.ajax_get(request, app_conf_get(api), timeout=60 * 20) diff --git a/app/dashboard/default_settings.py b/app/dashboard/default_settings.py index 336ceca6b..aa36a7c06 100644 --- a/app/dashboard/default_settings.py +++ b/app/dashboard/default_settings.py @@ -64,6 +64,7 @@ TEST_GROUP_API_ENDPOINT = "/test/group" TEST_CASE_API_ENDPOINT = "/test/case" TEST_REGRESSION_API_ENDPOINT = "/test/regression" +NEW_API_ENDPOINT = "/nodes" # Default date range to show the results. The higher the value, the more # data will need to be loaded from the server and parsed. It can take time diff --git a/app/dashboard/static/js/app/tables/common.js b/app/dashboard/static/js/app/tables/common.js index 4c219aecd..146448273 100644 --- a/app/dashboard/static/js/app/tables/common.js +++ b/app/dashboard/static/js/app/tables/common.js @@ -125,6 +125,10 @@ define([ tooltipNode.setAttribute('title', defaults.warning); tooltipNode.appendChild(html.warning()); break; + case 'DONE': + tooltipNode.setAttribute('title', defaults.done); + tooltipNode.appendChild(html.success()); + break; default: tooltipNode.setAttribute('title', defaults.default); tooltipNode.appendChild(html.unknown()); @@ -255,7 +259,11 @@ define([ node = _dateNode(date).firstElementChild; rendered = node.outerHTML; } else { - created = new Date(date.$date); + if (date.$date) { + created = new Date(date.$date); + } else { + created = new Date(date); + } rendered = created.toCustomISODate(); } } else { diff --git a/app/dashboard/static/js/app/tables/job.js b/app/dashboard/static/js/app/tables/job.js index fd201d18e..9081ad229 100644 --- a/app/dashboard/static/js/app/tables/job.js +++ b/app/dashboard/static/js/app/tables/job.js @@ -31,6 +31,7 @@ define([ pass: 'Build completed', build: 'Building', fail: 'Build failed', + done: 'Job done', default: 'Unknown status' }; diff --git a/app/dashboard/static/js/app/utils/html.js b/app/dashboard/static/js/app/utils/html.js index 3520f45c0..4bc46422a 100644 --- a/app/dashboard/static/js/app/utils/html.js +++ b/app/dashboard/static/js/app/utils/html.js @@ -1,6 +1,8 @@ /*! * kernelci dashboard. * + * Copyright (C) 2022 Collabora Ltd. + * * Copyright (C) 2014, 2015, 2016, 2017 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify it under @@ -513,7 +515,11 @@ define([ frag = document.createDocumentFragment(); - created = new Date(date.$date); + if (date.$date) { + created = new Date(date.$date); + } else { + created = new Date(date); + } timeNode = frag.appendChild(document.createElement('time')); timeNode.setAttribute('datetime', created.toISOString()); timeNode.appendChild( diff --git a/app/dashboard/static/js/app/view-new-api-job-branch-kernel-plan.2022.11.js b/app/dashboard/static/js/app/view-new-api-job-branch-kernel-plan.2022.11.js new file mode 100644 index 000000000..69d1384d7 --- /dev/null +++ b/app/dashboard/static/js/app/view-new-api-job-branch-kernel-plan.2022.11.js @@ -0,0 +1,375 @@ +/*! + * kernelci dashboard. + * + * Copyright (C) 2020 Collabora Limited + * Author: Guillaume Tucker + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +require([ + 'jquery', + 'charts/passpie', + 'tables/test', + 'utils/error', + 'utils/init', + 'utils/html', + 'utils/request', + 'utils/table', + 'utils/urls', + 'URI', +], function($, pieChart, ttable, error, init, html, request, table, + urls, URI) { + 'use strict'; + + var gPlan; + var gKernel; + var gBranch; + var gJob; + var gFileServer; + var gTestsTable; + + setTimeout(function() { + document.getElementById('li-test').setAttribute('class', 'active'); + }, 15); + + function detailsFailed() { + html.replaceByClassTxt('loading-content', '?'); + } + + function updateDetails(results) { + var job; + var branch; + var kernel; + var commit; + var treeNode; + var describeNode; + var branchNode; + var planNode; + var gitNode; + var createdOn; + var dateNode; + var url; + var plan; + + job = results.revision.tree; + branch = results.revision.branch; + kernel = results.revision.describe; + commit = results.revision.commit; + url = results.revision.url.replace('.git', '/commit/'+commit); + plan = results.group; + + treeNode = html.tooltip(); + treeNode.title = "All results for tree «" + job + "»"; + treeNode.appendChild(document.createTextNode(job)); + + planNode = html.tooltip(); + planNode.title = "All results for test plan «" + plan + "»"; + planNode.appendChild(document.createTextNode(plan)); + + branchNode = html.tooltip(); + branchNode.title = "All results for branch «" + branch + "»"; + branchNode.appendChild(document.createTextNode(branch)); + + describeNode = html.tooltip(); + describeNode.title = "Build results for «" + kernel + "» - "; + describeNode.appendChild(document.createTextNode(kernel)); + + gitNode = document.createElement('a'); + gitNode.appendChild(document.createTextNode(url)); + gitNode.href = url; + gitNode.title = "Git URL"; + + createdOn = new Date(results.created); + dateNode = document.createElement('time'); + dateNode.setAttribute('datetime', createdOn.toISOString()); + dateNode.appendChild( + document.createTextNode(createdOn.toCustomISODate())); + + html.replaceContent( + document.getElementById('tree'), treeNode); + html.replaceContent( + document.getElementById('plan'), planNode); + html.replaceContent( + document.getElementById('git-branch'), branchNode); + html.replaceContent( + document.getElementById('git-describe'), describeNode); + html.replaceContent( + document.getElementById('git-url'), gitNode); + html.replaceContent( + document.getElementById('job-date'), dateNode); + html.replaceContent( + document.getElementById('plan-title'), + document.createTextNode(results.group)); + html.replaceContent( + document.getElementById('kernel-title'), + document.createTextNode(results.revision.describe)); + html.replaceContent( + document.getElementById('tree-title'), + document.createTextNode(job)); + html.replaceContent( + document.getElementById('branch-title'), + document.createTextNode(branch)); + } + + function updateChart(testCount) { + function countTests(tc) { + return [ + tc['total'], + [tc['pass'], tc['failures'], tc['regressions'], tc['unknown']] + ]; + } + + pieChart.testpie({ + element: 'test-chart', + countFunc: countTests, + response: testCount, + legend: true, + legendIds: { + 'pass': '#show-pass', + 'warning': '#show-warning', + 'fail': '#show-fail', + 'unknown': '#show-unknown', + }, + legendTitles: { + 'pass': 'Successful', + 'warning': 'Failures', + 'fail': 'Regressions', + 'unknown': 'Unknown', + }, + size: { + height: 200, + width: 200, + }, + radius: {inner: -30, outer: -42}, + }); + } + + function listenForTableEvents(testCount) { + var btnList = ['total', 'pass', 'regressions', 'failures', 'unknown']; + + function _tableFilter(event) { + var activeId = event.target.id; + var status = activeId.substring('btn-'.length); + + if (status == 'total') { + status = ''; + } else if (status == 'regressions') { + status = 'fail'; + } else if (status == 'failures') { + status = 'warning'; + } + + gTestsTable.table.column(2).search(status).draw(); + + btnList.forEach(function(id) { + var btnId = 'btn-' + id; + var ele = document.getElementById(btnId); + + if (btnId == activeId) { + html.addClass(ele, 'active'); + } else { + html.removeClass(ele, 'active'); + } + }); + } + + btnList.forEach(function(id) { + var ele = document.getElementById('btn-' + id); + ele.addEventListener('click', _tableFilter, true); + if (testCount[id]) + ele.removeAttribute('disabled'); + if (id == 'total') + html.addClass(ele, 'active'); + }); + } + + function updateTestsTable(results) { + var columns; + var data; + function _renderStatus(data, type) { + if (type == "display") { + var node = document.createElement('div'); + node.appendChild(ttable.statusNode(data)); + return node.outerHTML; + } else { + return data; + } + } + + data = []; + results.forEach(function(item) { + var status; + + if (item.result == 'pass') + status = 'PASS'; + else if (item.result == 'fail') + status = 'WARNING'; + else if (item.result === null) + return + else + status = 'UNKNOWN'; + + data.push({ + '_id': item._id, + 'test_case_path': item.path.join('.'), + 'measurements': '-', + 'status': status, + }); + }); + + columns = [ + { + title: 'Test case path', + data: 'test_case_path', + type: 'string', + className: 'test-group-column', + }, + { + title: 'Measurements', + data: 'measurements', + type: 'string', + className: 'test-group-column', + searchable: false, + orderable: false, + }, + { + title: 'Status', + data: 'status', + type: 'string', + className: 'pull-center', + searchable: true, + orderable: false, + render: _renderStatus, + }, + ]; + + gTestsTable + .data(data) + .columns(columns) + .order([0, 'asc']) + .paging(true) + .info(false) + .draw(); + } + + function getTestsFailed() { + html.removeElement(document.getElementById('table-loading')); + html.replaceContent( + document.getElementById('table-div'), + html.errorDiv('No test data available.') + ); + } + + function getTestsDone(response) { + if (response.length === 0) { + getTestsFailed(); + return; + } + + updateTestsTable(response.items); + } + + function testCountDone(response) { + var testCount; + var total = 0; + var pass = 0; + var fail = 0; + var regressions = 0; + var unknown = 0; + + response.forEach(function(item){ + if (item.path.length > 2 & item.result !== null) { + switch(item.result) { + case 'fail': + fail += 1; + break; + case 'pass': + pass += 1; + break; + case 'unknown': + unknown += 1; + break; + } + } + }); + + total = fail+pass+regressions+unknown; + + testCount = { + 'total': total, + 'pass': pass, + 'regressions': regressions, + 'failures': fail, + 'unknown': unknown, + }; + updateChart(testCount); + listenForTableEvents(testCount); + } + + function getPlanFailed() { + detailsFailed(); + } + + function getPlanDone(response) { + updateDetails(response.items[0]); + getTestsDone(response); + testCountDone(response.items); + } + + function getPlan() { + var data; + if (!gPlan) { + getPlanFailed(); + return; + } + + data = { + 'revision.tree': gJob, + 'revision.branch': gBranch, + 'revision.describe': gKernel, + group: gPlan, + limit: 100000, + offset: 0, + }; + + $.when(request.get('/_ajax/nodes', data)) + .fail(error.error, getPlanFailed) + .done(getPlanDone); + } + if (document.getElementById('job-name') !== null) { + gJob = document.getElementById('job-name').value; + } + if (document.getElementById('branch-name') !== null) { + gBranch = URI.decode(document.getElementById('branch-name').value); + } + if (document.getElementById('kernel-name') !== null) { + gKernel = document.getElementById('kernel-name').value; + } + if (document.getElementById('plan-name') !== null) { + gPlan = document.getElementById('plan-name').value; + } + + gTestsTable = table({ + tableId: 'tests-table', + tableLoadingDivId: 'table-loading', + tableDivId: 'table-div', + }); + + setTimeout(getPlan, 10); + + setTimeout(init.hotkeys, 50); + setTimeout(init.tooltip, 50); +}); diff --git a/app/dashboard/static/js/app/view-new-api-job-branch-kernel.2022.11.js b/app/dashboard/static/js/app/view-new-api-job-branch-kernel.2022.11.js new file mode 100644 index 000000000..cff41108c --- /dev/null +++ b/app/dashboard/static/js/app/view-new-api-job-branch-kernel.2022.11.js @@ -0,0 +1,325 @@ +/*! + * kernelci dashboard. + * + * Copyright (C) 2022 Collabora Ltd + * Author: Alexandra Pereira + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +require([ + 'jquery', + 'utils/init', + 'utils/html', + 'utils/error', + 'utils/request', + 'utils/table', + 'tables/test', + 'charts/passpie', + 'URI', +], function($, init, html, error, request, table, ttest, chart, URI) { + 'use strict'; + var gJob; + var gBranch; + var gKernel; + var gPlansTable; + + setTimeout(function() { + document.getElementById('li-test').setAttribute('class', 'active'); + }, 15); + + function detailsFailed() { + html.replaceByClassTxt('loading-content', '?'); + } + + function updateChart(response) { + function countTests(response) { + var count = {'pass': 0, 'fail': 0, 'warning': 0}; + response.forEach(function(item){ + count.pass += item.result.pass; + count.fail += item.result.fail; + count.warning += item.result.warning; + }) + var total = count.pass + count.fail + count.warning; + return [total, [count.pass, count.fail, count.warning]]; + } + + chart.testpie({ + element: 'test-chart', + countFunc: countTests, + response: response, + size: { + height: 140, + width: 140 + }, + radius: {inner: -12.5, outer: 0}, + }); + } + + function updateDetails(results) { + var job; + var branch; + var kernel; + var commit; + var treeNode; + var describeNode; + var branchNode; + var gitNode; + var createdOn; + var dateNode; + var url; + + job = results.tree; + branch = results.branch; + kernel = results.describe; + commit = results.commit; + url = results.url.replace('.git', '/commit/' + commit); + + treeNode = html.tooltip(); + treeNode.title = "All results for tree «" + job + "»"; + treeNode.appendChild(document.createTextNode(job)); + + branchNode = html.tooltip(); + branchNode.title = "All results for branch «" + branch + "»"; + branchNode.appendChild(document.createTextNode(branch)); + + describeNode = html.tooltip(); + describeNode.title = "Build results for «" + kernel + "» - "; + describeNode.appendChild(document.createTextNode(kernel)); + + gitNode = document.createElement('a'); + gitNode.appendChild(document.createTextNode(url)); + gitNode.href = url; + gitNode.title = "Git URL"; + + createdOn = new Date(results.created); + dateNode = document.createElement('time'); + dateNode.setAttribute('datetime', createdOn.toISOString()); + dateNode.appendChild( + document.createTextNode(createdOn.toCustomISODate())); + + html.replaceContent( + document.getElementById('tree'), treeNode); + html.replaceContent( + document.getElementById('git-branch'), branchNode); + html.replaceContent( + document.getElementById('git-describe'), describeNode); + html.replaceContent( + document.getElementById('git-url'), gitNode); + html.replaceContent( + document.getElementById('job-date'), dateNode); + } + + function getBuilds() { + var data; + var deferred; + + data = { + 'revision.tree': gJob, + 'revision.branch': gBranch, + 'revision.describe': gKernel, + limit: 100000, + offset: 0, + }; + + deferred = request.get('/_ajax/nodes', data); + $.when(deferred) + .fail( + error.error, + getBuildsFailed) + .done(getBuildsDone); + } + + function getBuildsFailed() { + html.removeElement(document.getElementById('table-loading')); + html.replaceContent( + document.getElementById('table-div'), + html.errorDiv('Error loading build data.')); + } + + function plansFailed() { + html.removeElement(document.getElementById('table-loading')); + html.replaceContent( + document.getElementById('table-div'), + html.errorDiv('No test data available.') + ); + } + + function getPlansFailed() { + detailsFailed(); + plansFailed(); + } + + function getBuildsDone(response) { + if (response.items.length === 0) { + getPlansFailed(); + return; + } + var columns; + var results; + var count = {}; + + response.items.forEach(function(item){ + var date = new Date(item.created).toCustomISODate(); + if (!(date in count) && item.group !== null) { + count[date] = {}; + count[date][item.group] = {'pass':0, 'fail': 0, 'warning':0, 'id': item._id}; + } else if (item.group !== null && !(item.group in count[date])) { + count[date][item.group] = {'pass':0, 'fail': 0, 'warning':0, 'id': item._id}; + } else if (date in count && item.group in count[date]) { + if (item.result) { + if (item.result in count[date][item.group]) { + count[date][item.group][item.result]++; + } else { + count[date][item.group]['pass'] = 0; + count[date][item.group]['fail'] = 0; + count[date][item.group]['warning'] = 0; + count[date][item.group]['group'] = item.group; + } + } + } + }); + results = Object.values(response.items).filter(item => item.path.length === 2 && item.group !== null).map((item) => { + var revision = item.revision; + var newDate = new Date(item.created); + revision.status = String(item.state).toUpperCase(); + revision.created = new Date(newDate); + revision.group = item.group; + if (newDate.toCustomISODate() in count){ + if (Object.keys(count[newDate.toCustomISODate()][item.group]).length === 0){ + revision.result = {'pass':0, 'fail': 0, 'warning':0}; + } else { + revision.result = count[newDate.toCustomISODate()][item.group]; + } + } + return revision + }); + + /** + * Create the table column title for the tests count. + **/ + function _testColumnTitle() { + var tooltipNode; + + tooltipNode = html.tooltip(); + tooltipNode.setAttribute( + 'title', 'Successful/Regressions/Failures'); + tooltipNode.appendChild( + document.createTextNode('Test Results')); + + return tooltipNode.outerHTML; + } + + /** + * Wrapper to provide the href. + **/ + function _renderTestCount(data, type) { + return ttest.renderTestCount({data: data.id, type: type}); + } + + /** + * Wrapper to provide the href. + **/ + function _renderDetails(data, type, object) { + var href = + '/new-api-job/' + gJob + + '/branch/' + URI.encode(gBranch) + + '/kernel/' + gKernel + + '/plan/' + object.group + '/'; + return ttest.renderDetails(href, type); + } + + if (results.length === 0) { + html.replaceContent( + document.getElementById('table-div'), + html.errorDiv('No builds data available.')); + } else { + updateDetails(results[0]); + updateChart(results); + columns = [ + { + data: 'group', + title: 'Test Plan', + type: 'string', + className: 'test-group-column', + }, + { + data: 'created', + title: 'Date', + type: 'date', + className: 'pull-center', + render: ttest.renderDate + }, + { + data: 'result', + title: _testColumnTitle(), + type: 'string', + orderable: false, + searchable: false, + className: 'test-count pull-center', + render: _renderTestCount + }, + { + data: 'tree', + title: '', + type: 'string', + searchable: false, + orderable: false, + className: 'select-column pull-center', + render: _renderDetails + } + ]; + gPlansTable + .data(results) + .columns(columns) + .order([1, 'desc']) + .paging(true) + .info(false) + .draw(); + } + results.forEach(function(data) { + var objectId; + for (var key in data.result) { + if (key === 'id') + continue; + objectId = 'test-' + key + '-count-' + data.result.id; + html.replaceContent( + document.getElementById(objectId), + document.createTextNode(data.result[key])) + } + }); + } + + if (document.getElementById('job-name') !== null) { + gJob = document.getElementById('job-name').value; + } + if (document.getElementById('branch-name') !== null) { + gBranch = URI.decode(document.getElementById('branch-name').value); + } + if (document.getElementById('kernel-name') !== null) { + gKernel = document.getElementById('kernel-name').value; + } + + gPlansTable = table({ + tableId: 'plans-table', + tableLoadingDivId: 'table-loading', + tableDivId: 'table-div', + }); + + setTimeout(getBuilds, 10); + + setTimeout(init.hotkeys, 50); + setTimeout(init.tooltip, 50); +}); diff --git a/app/dashboard/static/js/app/view-new-api-jobs-all.2022.11.js b/app/dashboard/static/js/app/view-new-api-jobs-all.2022.11.js new file mode 100644 index 000000000..ea013a713 --- /dev/null +++ b/app/dashboard/static/js/app/view-new-api-jobs-all.2022.11.js @@ -0,0 +1,176 @@ +/*! + * kernelci dashboard. + * + * Copyright (C) 2022 Collabora Limited + * Author: Alexandra Pereira + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +require([ + 'jquery', + 'utils/init', + 'utils/error', + 'utils/request', + 'utils/table', + 'utils/html', + 'utils/const', + 'tables/job', + 'URI', +], function($, init, e, r, table, html, appconst, jobt, URI) { + 'use strict'; + var gDateRange; + var gJobsTable; + var gPageLen; + var gSearchFilter; + + setTimeout(function() { + document.getElementById('li-job').setAttribute('class', 'active'); + }, 15); + + gDateRange = appconst.MAX_DATE_RANGE; + gPageLen = null; + gSearchFilter = null; + + function getJobsFail() { + html.replaceContent( + document.getElementById('table-loading'), + html.errorDiv('Error loading data.')); + } + + function getJobsDone(response){ + var columns; + var results; + + function _renderDetails(data, type, object) { + var href = + '/new-api-job/' + data + + '/branch/' + URI.encode(object.branch) + + '/kernel/' + URI.encode(object.describe); + return jobt.renderDetails(href, type); + } + + function filterByDate(created){ + var dateNow = new Date(); + var dateReference = new Date(created); + dateNow.setDate(dateNow.getDate()-gDateRange); + return dateReference >= dateNow; + } + + results = Object.values(response.items).filter(item => item.parent === null && filterByDate(item.created)).map((item) => { + var revision = item.revision; + revision.status = String(item.state).toUpperCase(); + revision.created = item.created; + return revision + }); + + if (results.length === 0) { + html.removeElement(document.getElementById('table-loading')); + html.replaceContent( + document.getElementById('table-div'), + html.errorDiv('No jobs data available.')); + } else { + columns = [ + { + data: 'tree', + title: 'Tree', + type: 'string', + className: 'tree-column' + }, + { + data: 'branch', + title: 'Branch', + type: 'string', + className: 'branch-column' + }, + { + data: 'describe', + title: 'Kernel', + type: 'string', + className: 'kernel-column' + }, + { + data: 'created', + title: 'Date', + type: 'date', + className: 'pull-center', + render: jobt.renderDate + }, + { + data: 'status', + title: 'Status', + type: 'string', + className: 'pull-center', + render: jobt.renderStatus + }, + { + data: 'tree', + title: '', + type: 'string', + searchable: false, + orderable: false, + className: 'select-column pull-center', + render: _renderDetails + } + ]; + + gJobsTable + .data(results) + .columns(columns) + .order([3, 'desc']) + .languageLengthMenu('jobs per page') + .draw(); + } + } + + function getJobs() { + var dateNow = new Date(); + dateNow.setDate(dateNow.getDate()-gDateRange); + var data; + var deferred; + + data = { + limit: 100000, + offset: 0, + created__gte: dateNow.toISOString().replace('Z', '000'), + }; + + deferred = r.get('/_ajax/nodes', data); + $.when(deferred) + .fail(e.error, getJobsFail) + .done(getJobsDone); + } + + if (document.getElementById('search-filter') !== null) { + gSearchFilter = document.getElementById('search-filter').value; + } + if (document.getElementById('page-len') !== null) { + gPageLen = document.getElementById('page-len').value; + } + if (document.getElementById('date-range') !== null) { + gDateRange = document.getElementById('date-range').value; + } + + gJobsTable = table({ + tableId: 'jobstable', + tableDivId: 'table-div', + tableLoadingDivId: 'table-loading' + }); + + setTimeout(getJobs, 10); + + setTimeout(init.hotkeys, 50); + setTimeout(init.tooltip, 50); +}); diff --git a/app/dashboard/static/js/build.js b/app/dashboard/static/js/build.js index 67ff33f32..5d596a6c3 100644 --- a/app/dashboard/static/js/build.js +++ b/app/dashboard/static/js/build.js @@ -1,5 +1,5 @@ /*! - * Copyright (C) Collabora Limited 2020 + * Copyright (C) Collabora Limited 2020, 2022 * Author: Alexandra Pereira * * Copyright (C) Linaro Limited 2015,2016,2017,2019 @@ -71,6 +71,9 @@ 'app/view-jobs-all': 'app/view-jobs-all.2020.10', 'app/view-jobs-job': 'app/view-jobs-job.2020.10', 'app/view-jobs-job-branch': 'app/view-jobs-job-branch.2020.10', + 'app/view-new-api-jobs-all': 'app/view-new-api-jobs-all.2022.11', + 'app/view-new-api-job-branch-kernel': 'app/view-new-api-job-branch-kernel.2022.11', + 'app/view-new-api-job-branch-kernel-plan': 'app/view-new-api-job-branch-kernel-plan.2022.11', 'app/view-socs-all': 'app/view-socs-all.2020.10', 'app/view-socs-soc': 'app/view-socs-soc.2020.10', 'app/view-socs-soc-job': 'app/view-socs-soc-job.2020.10', @@ -117,6 +120,7 @@ {name: 'app/view-tests-case-id.2021.06'}, {name: 'app/view-tests-job-branch-kernel.2020.10'}, {name: 'app/view-tests-job-branch-kernel-plan.2020.10'}, + {name: 'app/view-new-api-jobs-all.2022.11'}, {name: 'kci-builds-all'}, {name: 'kci-builds-id'}, {name: 'kci-builds-job-kernel'}, @@ -136,5 +140,8 @@ {name: 'kci-tests-job-branch-kernel'}, {name: 'kci-tests-plan-id'}, {name: 'kci-tests-case-id'}, + {name: 'kci-new-api-jobs-all'}, + {name: 'kci-new-api-job-branch-kernel'}, + {name: 'kci-new-api-job-branch-kernel-plan'} ] }) diff --git a/app/dashboard/static/js/common.js b/app/dashboard/static/js/common.js index 02e8eab29..980e013c7 100644 --- a/app/dashboard/static/js/common.js +++ b/app/dashboard/static/js/common.js @@ -68,6 +68,9 @@ require.config({ 'app/view-jobs-all': 'app/view-jobs-all.2020.10', 'app/view-jobs-job': 'app/view-jobs-job.2020.10', 'app/view-jobs-job-branch': 'app/view-jobs-job-branch.2020.10', + 'app/view-new-api-jobs-all': 'app/view-new-api-jobs-all.2022.11', + 'app/view-new-api-job-branch-kernel': 'app/view-new-api-job-branch-kernel.2022.11', + 'app/view-new-api-job-branch-kernel-plan': 'app/view-new-api-job-branch-kernel-plan.2022.11', 'app/view-socs-all': 'app/view-socs-all.2020.10', 'app/view-socs-soc': 'app/view-socs-soc.2020.10', 'app/view-socs-soc-job': 'app/view-socs-soc-job.2020.10', diff --git a/app/dashboard/static/js/kci-new-api-job-branch-kernel-plan.js b/app/dashboard/static/js/kci-new-api-job-branch-kernel-plan.js new file mode 100644 index 000000000..7493d67d3 --- /dev/null +++ b/app/dashboard/static/js/kci-new-api-job-branch-kernel-plan.js @@ -0,0 +1,23 @@ +/*! + * kernelci dashboard. + * + * Copyright (C) 2022 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +require(['common'], function() { + 'use strict'; + require(['app/view-new-api-job-branch-kernel-plan']); +}); diff --git a/app/dashboard/static/js/kci-new-api-job-branch-kernel.js b/app/dashboard/static/js/kci-new-api-job-branch-kernel.js new file mode 100644 index 000000000..1e073020b --- /dev/null +++ b/app/dashboard/static/js/kci-new-api-job-branch-kernel.js @@ -0,0 +1,23 @@ +/*! + * kernelci dashboard. + * + * Copyright (C) 2022 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +require(['common'], function() { + 'use strict'; + require(['app/view-new-api-job-branch-kernel']); +}); diff --git a/app/dashboard/static/js/kci-new-api-jobs-all.js b/app/dashboard/static/js/kci-new-api-jobs-all.js new file mode 100644 index 000000000..696058857 --- /dev/null +++ b/app/dashboard/static/js/kci-new-api-jobs-all.js @@ -0,0 +1,23 @@ +/*! + * kernelci dashboard. + * + * Copyright (C) 2022 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +require(['common'], function() { + 'use strict'; + require(['app/view-new-api-jobs-all']); +}); diff --git a/app/dashboard/templates/new-api-job-branch-kernel-plan.html b/app/dashboard/templates/new-api-job-branch-kernel-plan.html new file mode 100644 index 000000000..da6b9a700 --- /dev/null +++ b/app/dashboard/templates/new-api-job-branch-kernel-plan.html @@ -0,0 +1,122 @@ +{%- extends "base.html" %} +{%- block meta -%} + +{%- endblock %} +{%- block title %}{{ page_title|safe }}{%- endblock %} +{%- block head %} +{{ super() }} + +{%- endblock %} +{%- block content %} +
+ +
+
+
Tree
+
+ +  loading… + +
+
Test Plan
+
+ +  loading… + +
+
Git branch
+
+ +  loading… + +
+
Git describe
+
+ +  loading… + +
+
Git URL
+
+ +  loading… + +
+
Date
+
+ +  loading… + +
+
+
+
+
+
+ + + + + + + + + + + + +
0 / 0 / 0 / 0
+
+
+
+
+
+
+
+ +
+
+
+ + + + + +
+
+
+
+ + +  retrieving test data… + +
+ {%- if is_mobile %} +
+ {%- else %} +
+ {%- endif %} + +
+
+
+
+ + + + +{%- endblock %} +{%- block scripts %} + +{%- endblock %} diff --git a/app/dashboard/templates/new-api-job-branch-kernel.html b/app/dashboard/templates/new-api-job-branch-kernel.html new file mode 100644 index 000000000..b52c179dd --- /dev/null +++ b/app/dashboard/templates/new-api-job-branch-kernel.html @@ -0,0 +1,89 @@ +{% extends "base.html" %} +{%- block meta -%} + +{%- endblock %} +{%- block title %}{{ page_title|safe }}{%- endblock %} +{%- block head %} +{{ super() }} + + +{%- endblock %} +{%- block content %} +
+ +
+
+
Tree
+
+ +  loading… + +
+
Git branch
+
+ +  loading… + +
+
Git describe
+
+ +  loading… + +
+
Git URL
+
+ +  loading… + +
+
Date
+
+ +  loading… + +
+
+
+
+
+
+
+
+
+ +
+ + +  retrieving test data… + +
+ {%- if is_mobile %} +
+ {%- else %} +
+ {%- endif %} + +
+
+
+
+ + + +{%- endblock %} +{%- block scripts %} + +{%- endblock %} diff --git a/app/dashboard/utils/route.py b/app/dashboard/utils/route.py index 8c6024f33..ff4f4bb67 100644 --- a/app/dashboard/utils/route.py +++ b/app/dashboard/utils/route.py @@ -33,6 +33,7 @@ import dashboard.views.job as vjob import dashboard.views.soc as vsoc import dashboard.views.test as vtest +import dashboard.views.newapi as vnewapi import dashboard.utils.feed.job as jobfeed import dashboard.utils.feed.soc as socfeed @@ -231,3 +232,22 @@ def init(): as_view("test-job-branch-kernel-plan"), methods=["GET"] ) + + #New API views + add_rule( + "/new-api-job/", + view_func=vnewapi.APIJobsAllView.as_view("new-api-jobs"), + methods=["GET"] + ) + + add_rule( + "/new-api-job//branch//kernel//", + view_func=vnewapi.APIJobBranchKernelView.as_view("new-api-job-branch-kernel"), + methods=["GET"] + ) + + add_rule( + "/new-api-job//branch//kernel//plan//", + view_func=vnewapi.APIJobBranchKernelPlanView.as_view("new-api-job-branch-kernel-plan"), + methods=["GET"] + ) diff --git a/app/dashboard/views/newapi.py b/app/dashboard/views/newapi.py new file mode 100644 index 000000000..cc7ee770d --- /dev/null +++ b/app/dashboard/views/newapi.py @@ -0,0 +1,92 @@ +# Copyright (C) 2022 Collabora LTD +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from flask import ( + current_app as app, + render_template, + request +) +from flask.views import View + +from dashboard.utils.backend import get_search_parameters + + +class GeneralNewAPIView(View): + + PAGE_TITLE = app.config.get("DEFAULT_PAGE_TITLE") + JOB_PAGES_TITLE = "%s — %s" % (PAGE_TITLE, "Job Reports") + RSS_LINK = ( + "" + + "" + + "" + ) + + +class APIJobsAllView(GeneralNewAPIView): + def dispatch_request(self): + body_title = "Available Jobs - New Kernel CI API" + search_filter, page_len = get_search_parameters(request) + return render_template( + "base-all.html", + table_id="jobstable", + data_main="kci-new-api-jobs-all", + body_title=body_title, + page_len=page_len, + page_title=self.JOB_PAGES_TITLE, + search_filter=search_filter + ) + + +class APIJobBranchKernelView(GeneralNewAPIView): + + def dispatch_request(self, **kwargs): + job, branch, kernel = (kwargs[k] for k in ['job', 'branch', 'kernel']) + page_title = "{} — {}/{} {}".format( + self.JOB_PAGES_TITLE, job, branch, kernel) + body_title = ( + "Test Results: «{}» ({} / {})".format( + kernel, job, branch) + ) + + return render_template( + "new-api-job-branch-kernel.html", + page_title=page_title, + body_title=body_title, + job=job, + branch=branch, + kernel=kernel + ) + + +class APIJobBranchKernelPlanView(GeneralNewAPIView): + + def dispatch_request(self, **kwargs): + job, branch, kernel, plan = (kwargs[k] for k in ['job', 'branch', 'kernel', 'plan']) + page_title = "{} — {}/{} {}".format( + self.JOB_PAGES_TITLE, job, branch, kernel) + body_title = ( + "Test Results: «{}» ({} / {})".format( + kernel, job, branch) + ) + + return render_template( + "new-api-job-branch-kernel-plan.html", + page_title=page_title, + body_title=body_title, + job=job, + branch=branch, + kernel=kernel, + plan=plan + )