Use JavaScript modules
This commit is contained in:
parent
1bb8a55169
commit
2abc407c77
|
@ -13,26 +13,17 @@
|
||||||
<link rel="stylesheet" type="text/css" href="css/layout.css" />
|
<link rel="stylesheet" type="text/css" href="css/layout.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="css/genericrendering.css" />
|
<link rel="stylesheet" type="text/css" href="css/genericrendering.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="css/specifics.css" />
|
<link rel="stylesheet" type="text/css" href="css/specifics.css" />
|
||||||
<script src="js/ajaxhelper.js"></script>
|
<script type="module" src="js/main.js"></script>
|
||||||
<script src="js/terminal.js"></script>
|
|
||||||
<script src="js/genericrendering.js"></script>
|
|
||||||
<script src="js/customrendering.js"></script>
|
|
||||||
<script src="js/globalstatuspage.js"></script>
|
|
||||||
<script src="js/packagesearchpage.js"></script>
|
|
||||||
<script src="js/packagedetailspage.js"></script>
|
|
||||||
<script src="js/buildactionspage.js"></script>
|
|
||||||
<script src="js/singlepage.js"></script>
|
|
||||||
<script src="js/utils.js"></script>
|
|
||||||
<!-- include xterm.js -->
|
<!-- include xterm.js -->
|
||||||
<link rel="stylesheet" type="text/css" href="node_modules/xterm/css/xterm.css" />
|
<link rel="stylesheet" type="text/css" href="node_modules/xterm/css/xterm.css" />
|
||||||
<script src="node_modules/xterm/lib/xterm.js"></script>
|
<script src="node_modules/xterm/lib/xterm.js"></script>
|
||||||
<script src="node_modules/xterm-addon-search/out/SearchAddon.js"></script>
|
<script src="node_modules/xterm-addon-search/out/SearchAddon.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body onload="initPage();" onhashchange="handleHashChange();">
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<nav>
|
<nav>
|
||||||
<div>
|
<div>
|
||||||
<a href="#" onclick="document.getElementById('about-dialog').style.display = 'block'; return false;">
|
<a href="#" id="logo-link">
|
||||||
<img src="img/logo.svg" alt="Logo" />
|
<img src="img/logo.svg" alt="Logo" />
|
||||||
</a>
|
</a>
|
||||||
Repository Manager for Arch Linux<br />
|
Repository Manager for Arch Linux<br />
|
||||||
|
@ -65,7 +56,7 @@
|
||||||
</section>
|
</section>
|
||||||
<section id="package-search-section">
|
<section id="package-search-section">
|
||||||
<h2>Package search</h2>
|
<h2>Package search</h2>
|
||||||
<form id="package-search-form" onsubmit="searchForPackages(); return false;" action="/packages" method="GET">
|
<form id="package-search-form" action="/packages" method="GET">
|
||||||
<table class="form-row">
|
<table class="form-row">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Package name:</th>
|
<th>Package name:</th>
|
||||||
|
@ -109,13 +100,13 @@
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Actions</legend>
|
<legend>Actions</legend>
|
||||||
<div>
|
<div>
|
||||||
<button type="button" style="background-image: url(img/icon/select-all.svg)" onclick="alterFormSelection(this.form, 'check-all');" class="icon-button">
|
<button type="button" name="selectall" style="background-image: url(img/icon/select-all.svg)" class="icon-button">
|
||||||
Select all packages
|
Select all packages
|
||||||
</button>
|
</button>
|
||||||
<button type="button" style="background-image: url(img/icon/select-off.svg)" onclick="alterFormSelection(this.form, 'uncheck-all');" class="icon-button">
|
<button type="button" name="unselectall" style="background-image: url(img/icon/select-off.svg)" class="icon-button">
|
||||||
Unselect all package
|
Unselect all package
|
||||||
</button>
|
</button>
|
||||||
<button type="button" style="background-image: url(img/icon/plus.svg)" onclick="fillBuildActionFromPackageSearch();" class="icon-button">
|
<button type="button" name="startselected" style="background-image: url(img/icon/plus.svg)" class="icon-button">
|
||||||
Start build action from selection
|
Start build action from selection
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -131,15 +122,13 @@
|
||||||
<section id="build-action-section">
|
<section id="build-action-section">
|
||||||
<h2>
|
<h2>
|
||||||
Build actions
|
Build actions
|
||||||
<span class="heading-actions">
|
<span class="heading-actions" id="build-action-toolbar">
|
||||||
<a href="#" title="Save state manually"
|
<a href="#" title="Save state manually"
|
||||||
class="icon-link"
|
class="icon-link"
|
||||||
onclick="return triggerToolbarAction(this);"
|
|
||||||
data-action="/dump/cache-file"
|
data-action="/dump/cache-file"
|
||||||
data-method="POST"><img src="img/icon/content-save.svg" alt="Save state manually" class="icon" /></a>
|
data-method="POST"><img src="img/icon/content-save.svg" alt="Save state manually" class="icon" /></a>
|
||||||
<a href="#" title="Stop service"
|
<a href="#" title="Stop service"
|
||||||
class="icon-link"
|
class="icon-link"
|
||||||
onclick="return triggerToolbarAction(this);"
|
|
||||||
data-action="/quit"
|
data-action="/quit"
|
||||||
data-method="POST"
|
data-method="POST"
|
||||||
data-confirmation="Do you really want to stop the service?"><img src="img/icon/power.svg" alt="Save state manually" class="icon" /></a>
|
data-confirmation="Do you really want to stop the service?"><img src="img/icon/power.svg" alt="Save state manually" class="icon" /></a>
|
||||||
|
@ -152,22 +141,22 @@
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Modify selected actions</legend>
|
<legend>Modify selected actions</legend>
|
||||||
<div>
|
<div>
|
||||||
<button type="button" style="background-image: url(img/icon/select-all.svg)" onclick="alterFormSelection(this.form, 'check-all');" class="icon-button">
|
<button type="button" name="selectall" style="background-image: url(img/icon/select-all.svg)" class="icon-button">
|
||||||
Select all actions
|
Select all actions
|
||||||
</button>
|
</button>
|
||||||
<button type="button" style="background-image: url(img/icon/select-off.svg)" onclick="alterFormSelection(this.form, 'uncheck-all');" class="icon-button">
|
<button type="button" name="unselectall" style="background-image: url(img/icon/select-off.svg)" class="icon-button">
|
||||||
Unselect all actions
|
Unselect all actions
|
||||||
</button>
|
</button>
|
||||||
<button type="button" style="background-image: url(img/icon/magnify.svg)" onclick="showSelectedActions();" class="icon-button">
|
<button type="button" name="showselected" style="background-image: url(img/icon/magnify.svg)" class="icon-button">
|
||||||
Show selected actions
|
Show selected actions
|
||||||
</button>
|
</button>
|
||||||
<button type="button" style="background-image: url(img/icon/delete.svg)" onclick="deleteSelectedActions();" class="icon-button">
|
<button type="button" name="deleteselected" style="background-image: url(img/icon/delete.svg)" class="icon-button">
|
||||||
Delete selected actions
|
Delete selected actions
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
<form id ="build-action-form" onsubmit="submitBuildAction(); return false;" action="/build-action" method="POST">
|
<form id ="build-action-form" action="/build-action" method="POST">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Start new build action</legend>
|
<legend>Start new build action</legend>
|
||||||
<div>
|
<div>
|
||||||
|
@ -175,7 +164,7 @@
|
||||||
<div class="form-split-50">
|
<div class="form-split-50">
|
||||||
<label for="build-action-task">Predefined task:</label>
|
<label for="build-action-task">Predefined task:</label>
|
||||||
<br />
|
<br />
|
||||||
<select name="task" id="build-action-task" onchange="handleBuildActionPresetChange();">
|
<select name="task" id="build-action-task">
|
||||||
<option id="build-action-task-none" data-ignore="1" style="font-style: italic;">None</option>
|
<option id="build-action-task-none" data-ignore="1" style="font-style: italic;">None</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -186,7 +175,7 @@
|
||||||
<div class="form-split-50">
|
<div class="form-split-50">
|
||||||
<label for="build-action-type">Action:</label>
|
<label for="build-action-type">Action:</label>
|
||||||
<br />
|
<br />
|
||||||
<select name="type" id="build-action-type" onchange="handleBuildActionTypeChange();"></select>
|
<select name="type" id="build-action-type"></select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-split-50">
|
<div class="form-split-50">
|
||||||
<label for="build-action-directory">Directory:</label>
|
<label for="build-action-directory">Directory:</label>
|
||||||
|
@ -262,7 +251,7 @@
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<div id="about-dialog" style="display: none;">
|
<div id="about-dialog" style="display: none;">
|
||||||
<a href="#" onclick="document.getElementById('about-dialog').style.display = 'none'; return false;" class="close-button">×</a>
|
<a href="#" onclick="this.parentNode.style.display = 'none'; return false;" class="close-button">×</a>
|
||||||
<div id="about-text">
|
<div id="about-text">
|
||||||
<h1>Repository Manager for Arch Linux</h1>
|
<h1>Repository Manager for Arch Linux</h1>
|
||||||
<p><img src="img/logo.svg" alt="Logo" /></p>
|
<p><img src="img/logo.svg" alt="Logo" /></p>
|
||||||
|
@ -271,4 +260,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
const apiPrefix = 'api/v0';
|
export const apiPrefix = 'api/v0';
|
||||||
let authError = false;
|
let authError = false;
|
||||||
|
|
||||||
/// \brief Makes an AJAX query with basic error handling.
|
/// \brief Makes an AJAX query with basic error handling.
|
||||||
function queryRoute(method, path, callback)
|
export function queryRoute(method, path, callback)
|
||||||
{
|
{
|
||||||
const ajaxRequest = new XMLHttpRequest();
|
const ajaxRequest = new XMLHttpRequest();
|
||||||
ajaxRequest.onreadystatechange = function() {
|
ajaxRequest.onreadystatechange = function() {
|
||||||
|
@ -34,13 +34,13 @@ function queryRoute(method, path, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Makes an AJAX query for the specified form.
|
/// \brief Makes an AJAX query for the specified form.
|
||||||
function startFormQuery(formId, handler)
|
export function startFormQuery(formId, handler)
|
||||||
{
|
{
|
||||||
return startFormQueryEx(formId, handler).ajaxRequest;
|
return startFormQueryEx(formId, handler).ajaxRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Makes an AJAX query for the specified form.
|
/// \brief Makes an AJAX query for the specified form.
|
||||||
function startFormQueryEx(formId, handler)
|
export function startFormQueryEx(formId, handler)
|
||||||
{
|
{
|
||||||
const form = document.getElementById(formId);
|
const form = document.getElementById(formId);
|
||||||
const params = makeFormQueryParameter(form);
|
const params = makeFormQueryParameter(form);
|
||||||
|
@ -105,7 +105,7 @@ function makeFormQueryParameter(form)
|
||||||
return "?" + params.join("&");
|
return "?" + params.join("&");
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeIdParams(ids)
|
export function makeIdParams(ids)
|
||||||
{
|
{
|
||||||
if (!Array.isArray(ids)) {
|
if (!Array.isArray(ids)) {
|
||||||
ids = [ids];
|
ids = [ids];
|
||||||
|
@ -114,7 +114,7 @@ function makeIdParams(ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Shows an alert for the specified AJAX request.
|
/// \brief Shows an alert for the specified AJAX request.
|
||||||
function showAjaxError(xhr, action)
|
export function showAjaxError(xhr, action)
|
||||||
{
|
{
|
||||||
let errorMessage;
|
let errorMessage;
|
||||||
try {
|
try {
|
||||||
|
@ -129,7 +129,7 @@ function showAjaxError(xhr, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Returns whether the specified AJAX request failed and shows an alert it it did.
|
/// \brief Returns whether the specified AJAX request failed and shows an alert it it did.
|
||||||
function checkForAjaxError(xhr, action)
|
export function checkForAjaxError(xhr, action)
|
||||||
{
|
{
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,9 +1,31 @@
|
||||||
function initBuildActionsForm()
|
import * as AjaxHelper from './ajaxhelper.js';
|
||||||
|
import * as CustomRendering from './customrendering.js';
|
||||||
|
import * as GenericRendering from './genericrendering.js';
|
||||||
|
import * as SinglePageHelper from './singlepage.js';
|
||||||
|
import * as Terminal from './terminal.js';
|
||||||
|
import * as Utils from './utils.js';
|
||||||
|
|
||||||
|
export function initBuildActionsForm()
|
||||||
{
|
{
|
||||||
const buildActionsForm = document.getElementById('build-action-form');
|
const buildActionsForm = document.getElementById('build-action-form');
|
||||||
if (buildActionsForm.dataset.initialized) {
|
if (buildActionsForm.dataset.initialized) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
buildActionsForm.onsubmit = submitBuildAction;
|
||||||
|
buildActionsForm.task.onchange = handleBuildActionPresetChange;
|
||||||
|
buildActionsForm.type.onchange = handleBuildActionTypeChange;
|
||||||
|
Array.from(document.getElementById('build-action-toolbar').getElementsByTagName('a')).forEach(a => {
|
||||||
|
a.onclick = triggerToolbarAction;
|
||||||
|
});
|
||||||
|
const listFormElements = document.getElementById('build-actions-list-form').elements;
|
||||||
|
listFormElements.selectall.onclick = function () {
|
||||||
|
Utils.alterFormSelection(this.form, 'check-all');
|
||||||
|
};
|
||||||
|
listFormElements.unselectall.onclick = function () {
|
||||||
|
Utils.alterFormSelection(this.form, 'uncheck-all');
|
||||||
|
};
|
||||||
|
listFormElements.showselected.onclick = showSelectedActions;
|
||||||
|
listFormElements.deleteselected.onclick = deleteSelectedActions;
|
||||||
queryBuildActions();
|
queryBuildActions();
|
||||||
handleBuildActionTypeChange();
|
handleBuildActionTypeChange();
|
||||||
buildActionsForm.dataset.initialized = true;
|
buildActionsForm.dataset.initialized = true;
|
||||||
|
@ -12,21 +34,21 @@ function initBuildActionsForm()
|
||||||
|
|
||||||
function queryBuildActions()
|
function queryBuildActions()
|
||||||
{
|
{
|
||||||
queryRoute('GET', '/build-action', showBuildActions);
|
AjaxHelper.queryRoute('GET', '/build-action', showBuildActions);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function queryBuildActionDetails(ids)
|
function queryBuildActionDetails(ids)
|
||||||
{
|
{
|
||||||
queryRoute('GET', '/build-action/details?' + makeIdParams(ids), showBuildActionDetails);
|
AjaxHelper.queryRoute('GET', '/build-action/details?' + AjaxHelper.makeIdParams(ids), showBuildActionDetails);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cloneBuildAction(ids)
|
function cloneBuildAction(ids)
|
||||||
{
|
{
|
||||||
queryRoute('POST', '/build-action/clone?' + makeIdParams(ids), function (xhr, success) {
|
AjaxHelper.queryRoute('POST', '/build-action/clone?' + AjaxHelper.makeIdParams(ids), function (xhr, success) {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return showAjaxError(xhr, 'clone build action');
|
return AjaxHelper.showAjaxError(xhr, 'clone build action');
|
||||||
}
|
}
|
||||||
const cloneIDs = JSON.parse(xhr.responseText);
|
const cloneIDs = JSON.parse(xhr.responseText);
|
||||||
if (cloneIDs.length === 1 && typeof cloneIDs[0] === 'number') {
|
if (cloneIDs.length === 1 && typeof cloneIDs[0] === 'number') {
|
||||||
|
@ -42,24 +64,24 @@ function cloneBuildAction(ids)
|
||||||
|
|
||||||
function deleteBuildAction(ids)
|
function deleteBuildAction(ids)
|
||||||
{
|
{
|
||||||
queryRoute('DELETE', '/build-action?' + makeIdParams(ids), function (xhr, success) {
|
AjaxHelper.queryRoute('DELETE', '/build-action?' + AjaxHelper.makeIdParams(ids), function (xhr, success) {
|
||||||
success ? window.alert('Build action has been deleted.') : showAjaxError(xhr, 'delete build action');
|
success ? window.alert('Build action has been deleted.') : AjaxHelper.showAjaxError(xhr, 'delete build action');
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopBuildAction(ids)
|
function stopBuildAction(ids)
|
||||||
{
|
{
|
||||||
queryRoute('POST', '/build-action/stop?' + makeIdParams(ids), function (xhr, success) {
|
AjaxHelper.queryRoute('POST', '/build-action/stop?' + AjaxHelper.makeIdParams(ids), function (xhr, success) {
|
||||||
success ? window.alert('Build action has been stopped.') : showAjaxError(xhr, 'stop build action');
|
success ? window.alert('Build action has been stopped.') : AjaxHelper.showAjaxError(xhr, 'stop build action');
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function startBuildAction(ids)
|
function startBuildAction(ids)
|
||||||
{
|
{
|
||||||
queryRoute('POST', '/build-action/start?' + makeIdParams(ids), function (xhr, success) {
|
AjaxHelper.queryRoute('POST', '/build-action/start?' + AjaxHelper.makeIdParams(ids), function (xhr, success) {
|
||||||
success ? window.alert('Build action has been started.') : showAjaxError(xhr, 'start build action');
|
success ? window.alert('Build action has been started.') : AjaxHelper.showAjaxError(xhr, 'start build action');
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -98,7 +120,7 @@ function prepareBuildActionBasedOnExistingOne(existingBuildAction)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBuildActionTypeChange()
|
export function handleBuildActionTypeChange()
|
||||||
{
|
{
|
||||||
if (!globalInfo) {
|
if (!globalInfo) {
|
||||||
return;
|
return;
|
||||||
|
@ -129,14 +151,14 @@ function handleBuildActionTypeChange()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBuildActionPresetChange()
|
export function handleBuildActionPresetChange()
|
||||||
{
|
{
|
||||||
if (!globalInfo) {
|
if (!globalInfo) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const task = document.getElementById('build-action-task').value;
|
const task = document.getElementById('build-action-task').value;
|
||||||
const taskInfo = globalInfo.presets.tasks[task];
|
const taskInfo = globalInfo.presets.tasks[task];
|
||||||
const taskInfoElement = getAndEmptyElement('build-action-task-info');
|
const taskInfoElement = Utils.getAndEmptyElement('build-action-task-info');
|
||||||
const actionSelect = document.getElementById('build-action-type');
|
const actionSelect = document.getElementById('build-action-type');
|
||||||
if (!taskInfo) {
|
if (!taskInfo) {
|
||||||
actionSelect.disabled = false;
|
actionSelect.disabled = false;
|
||||||
|
@ -170,33 +192,33 @@ function renderBuildActionActions(actionValue, buildAction, refresh)
|
||||||
container.className = 'table-row-actions';
|
container.className = 'table-row-actions';
|
||||||
}
|
}
|
||||||
const id = buildAction.id;
|
const id = buildAction.id;
|
||||||
container.appendChild(renderIconLink(refresh ? 'table-refresh' : 'magnify', buildAction, function() {
|
container.appendChild(CustomRendering.renderIconLink(refresh ? 'table-refresh' : 'magnify', buildAction, function() {
|
||||||
queryBuildActionDetails(id);
|
queryBuildActionDetails(id);
|
||||||
return false;
|
return false;
|
||||||
}, refresh ? 'Refresh details table' : 'Show details', undefined, '#build-action-details-section?' + id));
|
}, refresh ? 'Refresh details table' : 'Show details', undefined, '#build-action-details-section?' + id));
|
||||||
container.appendChild(renderIconLink('restart', buildAction, function() {
|
container.appendChild(CustomRendering.renderIconLink('restart', buildAction, function() {
|
||||||
if (window.confirm('Do you really want to clone/restart action ' + id + '?')) {
|
if (window.confirm('Do you really want to clone/restart action ' + id + '?')) {
|
||||||
cloneBuildAction(id);
|
cloneBuildAction(id);
|
||||||
}
|
}
|
||||||
}, 'Clone ' + id));
|
}, 'Clone ' + id));
|
||||||
container.appendChild(renderIconLink('plus', buildAction, function() {
|
container.appendChild(CustomRendering.renderIconLink('plus', buildAction, function() {
|
||||||
prepareBuildActionBasedOnExistingOne(buildAction);
|
prepareBuildActionBasedOnExistingOne(buildAction);
|
||||||
switchToBuildActions();
|
switchToBuildActions();
|
||||||
}, 'Create new build action based on ' + id));
|
}, 'Create new build action based on ' + id));
|
||||||
container.appendChild(renderIconLink('delete', buildAction, function() {
|
container.appendChild(CustomRendering.renderIconLink('delete', buildAction, function() {
|
||||||
if (window.confirm('Do you really want to delete action ' + id + '?')) {
|
if (window.confirm('Do you really want to delete action ' + id + '?')) {
|
||||||
deleteBuildAction(id);
|
deleteBuildAction(id);
|
||||||
}
|
}
|
||||||
}, 'Delete ' + id));
|
}, 'Delete ' + id));
|
||||||
if (buildAction.status !== 0 && buildAction.status !== 4) {
|
if (buildAction.status !== 0 && buildAction.status !== 4) {
|
||||||
container.appendChild(renderIconLink('stop', buildAction, function() {
|
container.appendChild(CustomRendering.renderIconLink('stop', buildAction, function() {
|
||||||
if (window.confirm('Do you really want to stop/decline action ' + id + '?')) {
|
if (window.confirm('Do you really want to stop/decline action ' + id + '?')) {
|
||||||
stopBuildAction(id);
|
stopBuildAction(id);
|
||||||
}
|
}
|
||||||
}, 'Stop/decline ' + id));
|
}, 'Stop/decline ' + id));
|
||||||
}
|
}
|
||||||
if (buildAction.status === 0) {
|
if (buildAction.status === 0) {
|
||||||
container.appendChild(renderIconLink('play', buildAction, function() {
|
container.appendChild(CustomRendering.renderIconLink('play', buildAction, function() {
|
||||||
if (window.confirm('Do you really want to start action ' + id + '?')) {
|
if (window.confirm('Do you really want to start action ' + id + '?')) {
|
||||||
startBuildAction(id);
|
startBuildAction(id);
|
||||||
}
|
}
|
||||||
|
@ -211,16 +233,16 @@ function showBuildActions(ajaxRequest)
|
||||||
window.functionsPostponedUntilGlobalInfo.push(showBuildActions.bind(this, ...arguments));
|
window.functionsPostponedUntilGlobalInfo.push(showBuildActions.bind(this, ...arguments));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const buildActionsList = getAndEmptyElement('build-actions-list');
|
const buildActionsList = Utils.getAndEmptyElement('build-actions-list');
|
||||||
if (ajaxRequest.status !== 200) {
|
if (ajaxRequest.status !== 200) {
|
||||||
buildActionsList.appendChild(document.createTextNode('Unable to load build actions: ' + ajaxRequest.responseText));
|
buildActionsList.appendChild(document.createTextNode('Unable to load build actions: ' + ajaxRequest.responseText));
|
||||||
buildActionsList.appendChild(renderReloadButton(queryBuildActions));
|
buildActionsList.appendChild(CustomRendering.renderReloadButton(queryBuildActions));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const responseJson = JSON.parse(ajaxRequest.responseText);
|
const responseJson = JSON.parse(ajaxRequest.responseText);
|
||||||
if (!Array.isArray(responseJson)) {
|
if (!Array.isArray(responseJson)) {
|
||||||
buildActionsList.appendChild(document.createTextNode('Unable to load build actions: response is no array'));
|
buildActionsList.appendChild(document.createTextNode('Unable to load build actions: response is no array'));
|
||||||
buildActionsList.appendChild(renderReloadButton(queryBuildActions));
|
buildActionsList.appendChild(CustomRendering.renderReloadButton(queryBuildActions));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +307,7 @@ function showBuildActions(ajaxRequest)
|
||||||
};
|
};
|
||||||
|
|
||||||
// render the table
|
// render the table
|
||||||
const container = renderTableFromJsonArray({
|
const container = GenericRendering.renderTableFromJsonArray({
|
||||||
rows: responseJson,
|
rows: responseJson,
|
||||||
rowsPerPage: 10,
|
rowsPerPage: 10,
|
||||||
columnHeaders: ['', 'ID', 'Task', 'Type', 'Status', 'Result', 'Created', 'Started', 'Runtime', 'Directory', 'Source repo', 'Destination repo', 'Packages', 'Actions'],
|
columnHeaders: ['', 'ID', 'Task', 'Type', 'Status', 'Result', 'Created', 'Started', 'Runtime', 'Directory', 'Source repo', 'Destination repo', 'Packages', 'Actions'],
|
||||||
|
@ -293,46 +315,46 @@ function showBuildActions(ajaxRequest)
|
||||||
columnSortAccessors: [null, null, null, null, null, null, '_cc'],
|
columnSortAccessors: [null, null, null, null, null, null, '_cc'],
|
||||||
customRenderer: {
|
customRenderer: {
|
||||||
checkbox: function(value, row) {
|
checkbox: function(value, row) {
|
||||||
return renderCheckBoxForTableRow(value, row, function(row) {
|
return GenericRendering.renderCheckBoxForTableRow(value, row, function(row) {
|
||||||
return row.name;
|
return row.name;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
actions: renderBuildActionActions,
|
actions: renderBuildActionActions,
|
||||||
id: function(value, row) {
|
id: function(value, row) {
|
||||||
return renderLink(value, row, function() {
|
return GenericRendering.renderLink(value, row, function() {
|
||||||
queryBuildActionDetails(row.id);
|
queryBuildActionDetails(row.id);
|
||||||
return false;
|
return false;
|
||||||
}, 'Show details', undefined, '#build-action-details-section?' + row.id);
|
}, 'Show details', undefined, '#build-action-details-section?' + row.id);
|
||||||
},
|
},
|
||||||
taskName: function (value) {
|
taskName: function (value) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return renderNoneInGrey();
|
return GenericRendering.renderNoneInGrey();
|
||||||
}
|
}
|
||||||
return document.createTextNode(getProperty(globalInfo.presets.tasks[value], 'name', value));
|
return document.createTextNode(Utils.getProperty(globalInfo.presets.tasks[value], 'name', value));
|
||||||
},
|
},
|
||||||
status: function(value) {
|
status: function(value) {
|
||||||
return document.createTextNode(getProperty(globalInfo.buildActionStates[value], 'name', 'Invalid/unknown'));
|
return document.createTextNode(Utils.getProperty(globalInfo.buildActionStates[value], 'name', 'Invalid/unknown'));
|
||||||
},
|
},
|
||||||
result: function(value) {
|
result: function(value) {
|
||||||
return renderNoneInGrey(getProperty(globalInfo.buildActionResults[value], 'name', 'Invalid/unknown'));
|
return GenericRendering.renderNoneInGrey(Utils.getProperty(globalInfo.buildActionResults[value], 'name', 'Invalid/unknown'));
|
||||||
},
|
},
|
||||||
type: function(value) {
|
type: function(value) {
|
||||||
return document.createTextNode(getProperty(globalInfo.buildActionTypes[value], 'name', 'Invalid/debugging'));
|
return document.createTextNode(Utils.getProperty(globalInfo.buildActionTypes[value], 'name', 'Invalid/debugging'));
|
||||||
},
|
},
|
||||||
created: renderShortTimeStamp,
|
created: GenericRendering.renderShortTimeStamp,
|
||||||
started: renderShortTimeStamp,
|
started: GenericRendering.renderShortTimeStamp,
|
||||||
finished: function (value, row) {
|
finished: function (value, row) {
|
||||||
return renderTimeSpan(row.started, value);
|
return GenericRendering.renderTimeSpan(row.started, value);
|
||||||
},
|
},
|
||||||
sourceDbs: renderArrayElidedAsCommaSeparatedString,
|
sourceDbs: GenericRendering.renderArrayElidedAsCommaSeparatedString,
|
||||||
destinationDbs: renderArrayElidedAsCommaSeparatedString,
|
destinationDbs: GenericRendering.renderArrayElidedAsCommaSeparatedString,
|
||||||
packageNames: function(value) {
|
packageNames: function(value) {
|
||||||
return renderNoneInGrey(!Array.isArray(value) || value.length <= 0 ? 'none' : value.length);
|
return GenericRendering.renderNoneInGrey(!Array.isArray(value) || value.length <= 0 ? 'none' : value.length);
|
||||||
},
|
},
|
||||||
note: function(rows) {
|
note: function(rows) {
|
||||||
const note = document.createElement('p');
|
const note = document.createElement('p');
|
||||||
note.appendChild(document.createTextNode(rows.length + ' build actions present '));
|
note.appendChild(document.createTextNode(rows.length + ' build actions present '));
|
||||||
note.appendChild(renderReloadButton(queryBuildActions));
|
note.appendChild(CustomRendering.renderReloadButton(queryBuildActions));
|
||||||
return note;
|
return note;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -396,15 +418,15 @@ function showBuildActions(ajaxRequest)
|
||||||
|
|
||||||
function switchToBuildActionDetails(buildActionIds)
|
function switchToBuildActionDetails(buildActionIds)
|
||||||
{
|
{
|
||||||
sections['build-action-details'].state.ids = buildActionIds;
|
SinglePageHelper.sections['build-action-details'].state.ids = buildActionIds;
|
||||||
updateHashPreventingSectionInitializer(!Array.isArray(buildActionIds) || buildActionIds.length === 0
|
SinglePageHelper.updateHashPreventingSectionInitializer(!Array.isArray(buildActionIds) || buildActionIds.length === 0
|
||||||
? '#build-action-details-section'
|
? '#build-action-details-section'
|
||||||
: '#build-action-details-section?' + encodeURIComponent(buildActionIds.join(',')));
|
: '#build-action-details-section?' + encodeURIComponent(buildActionIds.join(',')));
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchToBuildActions()
|
function switchToBuildActions()
|
||||||
{
|
{
|
||||||
updateHashPreventingSectionInitializer('#build-action-section');
|
SinglePageHelper.updateHashPreventingSectionInitializer('#build-action-section');
|
||||||
}
|
}
|
||||||
|
|
||||||
function showBuildActionDetails(ajaxRequest)
|
function showBuildActionDetails(ajaxRequest)
|
||||||
|
@ -413,7 +435,7 @@ function showBuildActionDetails(ajaxRequest)
|
||||||
window.functionsPostponedUntilGlobalInfo.push(showBuildActionDetails.bind(this, ...arguments));
|
window.functionsPostponedUntilGlobalInfo.push(showBuildActionDetails.bind(this, ...arguments));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (checkForAjaxError(ajaxRequest, 'show build action')) {
|
if (AjaxHelper.checkForAjaxError(ajaxRequest, 'show build action')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const responseJSON = JSON.parse(ajaxRequest.responseText);
|
const responseJSON = JSON.parse(ajaxRequest.responseText);
|
||||||
|
@ -422,8 +444,8 @@ function showBuildActionDetails(ajaxRequest)
|
||||||
|
|
||||||
function showBuildActionDetails2(buildActions)
|
function showBuildActionDetails2(buildActions)
|
||||||
{
|
{
|
||||||
const buildActionResults = getAndEmptyElement('build-action-results');
|
const buildActionResults = Utils.getAndEmptyElement('build-action-results');
|
||||||
let buildActionActions = getAndEmptyElement('build-action-details-actions');
|
let buildActionActions = Utils.getAndEmptyElement('build-action-details-actions');
|
||||||
buildActions.forEach(function (buildActionDetails) {
|
buildActions.forEach(function (buildActionDetails) {
|
||||||
if (!buildActionActions) {
|
if (!buildActionActions) {
|
||||||
buildActionActions = document.createElement('span');
|
buildActionActions = document.createElement('span');
|
||||||
|
@ -439,33 +461,33 @@ function showBuildActionDetails2(buildActions)
|
||||||
|
|
||||||
function renderBuildActionDetailsTable(buildActionDetails)
|
function renderBuildActionDetailsTable(buildActionDetails)
|
||||||
{
|
{
|
||||||
return renderTableFromJsonObject({
|
return GenericRendering.renderTableFromJsonObject({
|
||||||
data: buildActionDetails,
|
data: buildActionDetails,
|
||||||
displayLabels: ['ID', 'Task', 'Type', 'Status', 'Result', 'Result data', 'Created', 'Started', 'Finished', 'Start after', 'Directory', 'Source repo', 'Destination repo', 'Packages', 'Flags', 'Settings', 'Log files', 'Artefacts', 'Output'],
|
displayLabels: ['ID', 'Task', 'Type', 'Status', 'Result', 'Result data', 'Created', 'Started', 'Finished', 'Start after', 'Directory', 'Source repo', 'Destination repo', 'Packages', 'Flags', 'Settings', 'Log files', 'Artefacts', 'Output'],
|
||||||
fieldAccessors: ['id', 'taskName', 'type', 'status', 'result', 'resultData', 'created', 'started', 'finished', 'startAfter', 'directory', 'sourceDbs', 'destinationDbs', 'packageNames', 'flags', 'settings', 'logfiles', 'artefacts', 'output'],
|
fieldAccessors: ['id', 'taskName', 'type', 'status', 'result', 'resultData', 'created', 'started', 'finished', 'startAfter', 'directory', 'sourceDbs', 'destinationDbs', 'packageNames', 'flags', 'settings', 'logfiles', 'artefacts', 'output'],
|
||||||
customRenderer: {
|
customRenderer: {
|
||||||
taskName: function (value) {
|
taskName: function (value) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return renderNoneInGrey();
|
return GenericRendering.renderNoneInGrey();
|
||||||
}
|
}
|
||||||
return document.createTextNode(getProperty(globalInfo.presets.tasks[value], 'name', value));
|
return document.createTextNode(Utils.getProperty(globalInfo.presets.tasks[value], 'name', value));
|
||||||
},
|
},
|
||||||
status: function(value) {
|
status: function(value) {
|
||||||
return document.createTextNode(getProperty(globalInfo.buildActionStates[value], 'name', 'Invalid/unknown'));
|
return document.createTextNode(Utils.getProperty(globalInfo.buildActionStates[value], 'name', 'Invalid/unknown'));
|
||||||
},
|
},
|
||||||
result: function(value) {
|
result: function(value) {
|
||||||
return renderNoneInGrey(getProperty(globalInfo.buildActionResults[value], 'name', 'Invalid/unknown'));
|
return GenericRendering.renderNoneInGrey(Utils.getProperty(globalInfo.buildActionResults[value], 'name', 'Invalid/unknown'));
|
||||||
},
|
},
|
||||||
type: function(value) {
|
type: function(value) {
|
||||||
return document.createTextNode(getProperty(globalInfo.buildActionTypes[value], 'name', 'Invalid/debugging'));
|
return document.createTextNode(Utils.getProperty(globalInfo.buildActionTypes[value], 'name', 'Invalid/debugging'));
|
||||||
},
|
},
|
||||||
created: renderTimeStamp,
|
created: GenericRendering.renderTimeStamp,
|
||||||
started: renderTimeStamp,
|
started: GenericRendering.renderTimeStamp,
|
||||||
finished: renderTimeStamp,
|
finished: GenericRendering.renderTimeStamp,
|
||||||
startAfter: renderArrayAsCommaSeparatedString,
|
startAfter: GenericRendering.renderArrayAsCommaSeparatedString,
|
||||||
sourceDbs: renderArrayAsCommaSeparatedString,
|
sourceDbs: GenericRendering.renderArrayAsCommaSeparatedString,
|
||||||
destinationDbs: renderArrayAsCommaSeparatedString,
|
destinationDbs: GenericRendering.renderArrayAsCommaSeparatedString,
|
||||||
packageNames: renderArrayAsCommaSeparatedString,
|
packageNames: GenericRendering.renderArrayAsCommaSeparatedString,
|
||||||
flags: function(value, row) {
|
flags: function(value, row) {
|
||||||
const flagNames = [];
|
const flagNames = [];
|
||||||
const typeInfo = globalInfo.buildActionTypes[row.type];
|
const typeInfo = globalInfo.buildActionTypes[row.type];
|
||||||
|
@ -474,19 +496,19 @@ function renderBuildActionDetailsTable(buildActionDetails)
|
||||||
flagNames.push(flag.name);
|
flagNames.push(flag.name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return renderArrayAsCommaSeparatedString(flagNames);
|
return GenericRendering.renderArrayAsCommaSeparatedString(flagNames);
|
||||||
},
|
},
|
||||||
settings: function(value, row) {
|
settings: function(value, row) {
|
||||||
const typeInfo = globalInfo.buildActionTypes[row.type];
|
const typeInfo = globalInfo.buildActionTypes[row.type];
|
||||||
if (typeInfo.settingNames.length === 0) {
|
if (typeInfo.settingNames.length === 0) {
|
||||||
return renderNoneInGrey();
|
return GenericRendering.renderNoneInGrey();
|
||||||
}
|
}
|
||||||
return renderTableFromJsonObject({
|
return GenericRendering.renderTableFromJsonObject({
|
||||||
data: value,
|
data: value,
|
||||||
displayLabels: typeInfo.settingNames,
|
displayLabels: typeInfo.settingNames,
|
||||||
fieldAccessors: typeInfo.settingParams,
|
fieldAccessors: typeInfo.settingParams,
|
||||||
defaultRenderer: function (arg1, arg2, arg3) {
|
defaultRenderer: function (arg1, arg2, arg3) {
|
||||||
return renderNoneInGrey(arg1, arg2, arg3, 'default/none');
|
return GenericRendering.renderNoneInGrey(arg1, arg2, arg3, 'default/none');
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -495,7 +517,7 @@ function renderBuildActionDetailsTable(buildActionDetails)
|
||||||
case 3: { // update info
|
case 3: { // update info
|
||||||
const formElement = document.createElement('form');
|
const formElement = document.createElement('form');
|
||||||
formElement.className = 'update-info-form';
|
formElement.className = 'update-info-form';
|
||||||
formElement.appendChild(renderTableFromJsonObject({
|
formElement.appendChild(GenericRendering.renderTableFromJsonObject({
|
||||||
data: value.data,
|
data: value.data,
|
||||||
relatedRow: row,
|
relatedRow: row,
|
||||||
displayLabels: ['Version updates', 'Package updates', 'Downgrades', 'Orphans'],
|
displayLabels: ['Version updates', 'Package updates', 'Downgrades', 'Orphans'],
|
||||||
|
@ -530,15 +552,15 @@ function renderBuildActionDetailsTable(buildActionDetails)
|
||||||
return formElement;
|
return formElement;
|
||||||
}
|
}
|
||||||
case 4: // build preparation info
|
case 4: // build preparation info
|
||||||
return renderTableFromJsonObject({
|
return GenericRendering.renderTableFromJsonObject({
|
||||||
data: value.data,
|
data: value.data,
|
||||||
displayLabels: ['Error', 'Warnings', 'Database config', 'Batches', 'Cyclic leftovers', 'Build data'],
|
displayLabels: ['Error', 'Warnings', 'Database config', 'Batches', 'Cyclic leftovers', 'Build data'],
|
||||||
fieldAccessors: ['error', 'warnings', 'dbConfig', 'batches', 'cyclicLeftovers', 'buildData'],
|
fieldAccessors: ['error', 'warnings', 'dbConfig', 'batches', 'cyclicLeftovers', 'buildData'],
|
||||||
customRenderer: {
|
customRenderer: {
|
||||||
buildData: renderBuildPreparationResultData,
|
buildData: renderBuildPreparationResultData,
|
||||||
cyclicLeftovers: renderArrayAsCommaSeparatedString,
|
cyclicLeftovers: GenericRendering.renderArrayAsCommaSeparatedString,
|
||||||
batches: function(batch) {
|
batches: function(batch) {
|
||||||
return renderCustomList(batch, renderArrayAsCommaSeparatedString);
|
return GenericRendering.renderCustomList(batch, GenericRendering.renderArrayAsCommaSeparatedString);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -546,7 +568,7 @@ function renderBuildActionDetailsTable(buildActionDetails)
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
container.className = 'repo-problems';
|
container.className = 'repo-problems';
|
||||||
for (const [database, problems] of Object.entries(value.data)) {
|
for (const [database, problems] of Object.entries(value.data)) {
|
||||||
const table = renderTableFromJsonArray({
|
const table = GenericRendering.renderTableFromJsonArray({
|
||||||
rows: problems,
|
rows: problems,
|
||||||
columnHeaders: ['Related package', 'Problem description'],
|
columnHeaders: ['Related package', 'Problem description'],
|
||||||
columnAccessors: ['pkg', 'desc'],
|
columnAccessors: ['pkg', 'desc'],
|
||||||
|
@ -555,16 +577,16 @@ function renderBuildActionDetailsTable(buildActionDetails)
|
||||||
desc: function(value) {
|
desc: function(value) {
|
||||||
switch(value.index) {
|
switch(value.index) {
|
||||||
case 1:
|
case 1:
|
||||||
return renderTableFromJsonObject({
|
return GenericRendering.renderTableFromJsonObject({
|
||||||
data: value.data,
|
data: value.data,
|
||||||
displayLabels: ['Missing dependencies', 'Missing libraries'],
|
displayLabels: ['Missing dependencies', 'Missing libraries'],
|
||||||
fieldAccessors: ['deps', 'libs'],
|
fieldAccessors: ['deps', 'libs'],
|
||||||
customRenderer: {
|
customRenderer: {
|
||||||
deps: renderDependency,
|
deps: CustomRendering.renderDependency,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
default:
|
default:
|
||||||
return renderStandardTableCell(value.data);
|
return GenericRendering.renderStandardTableCell(value.data);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -575,7 +597,7 @@ function renderBuildActionDetailsTable(buildActionDetails)
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return renderStandardTableCell(value.data);
|
return GenericRendering.renderStandardTableCell(value.data);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
logfiles: renderBuildActionLogFiles,
|
logfiles: renderBuildActionLogFiles,
|
||||||
|
@ -583,12 +605,12 @@ function renderBuildActionDetailsTable(buildActionDetails)
|
||||||
output: function(value, row) {
|
output: function(value, row) {
|
||||||
const isFinished = row.status === 4;
|
const isFinished = row.status === 4;
|
||||||
if (!value && isFinished) {
|
if (!value && isFinished) {
|
||||||
return renderNoneInGrey();
|
return GenericRendering.renderNoneInGrey();
|
||||||
}
|
}
|
||||||
const targetElement = document.createElement('div');
|
const targetElement = document.createElement('div');
|
||||||
if (isFinished) {
|
if (isFinished) {
|
||||||
const terminal = makeTerminal();
|
const terminal = Terminal.makeTerminal();
|
||||||
setupTerminalLater(terminal, targetElement, value);
|
Terminal.setupTerminalLater(terminal, targetElement, value);
|
||||||
return targetElement;
|
return targetElement;
|
||||||
}
|
}
|
||||||
const streamingSetup = setupTerminalForStreaming({
|
const streamingSetup = setupTerminalForStreaming({
|
||||||
|
@ -610,15 +632,15 @@ function setupTerminalForStreaming(args)
|
||||||
{
|
{
|
||||||
const id = args.id; // a page-unique ID to make up DOM element IDs as needed
|
const id = args.id; // a page-unique ID to make up DOM element IDs as needed
|
||||||
const targetElement = args.targetElement; // the DOM element to stream contents into
|
const targetElement = args.targetElement; // the DOM element to stream contents into
|
||||||
const path = args.path; // the path to GET contents from via streamRouteIntoTerminal()
|
const path = args.path; // the path to GET contents from via Terminal.streamRouteIntoTerminal()
|
||||||
let terminal;
|
let terminal;
|
||||||
let ajaxRequest;
|
let ajaxRequest;
|
||||||
return {
|
return {
|
||||||
elements: [targetElement],
|
elements: [targetElement],
|
||||||
startStreaming: function () {
|
startStreaming: function () {
|
||||||
terminal = makeTerminal();
|
terminal = Terminal.makeTerminal();
|
||||||
ajaxRequest = streamRouteIntoTerminal('GET', path, terminal);
|
ajaxRequest = Terminal.streamRouteIntoTerminal('GET', path, terminal);
|
||||||
setupTerminalLater(terminal, targetElement);
|
Terminal.setupTerminalLater(terminal, targetElement);
|
||||||
},
|
},
|
||||||
stopStreaming: function () {
|
stopStreaming: function () {
|
||||||
ajaxRequest.abort();
|
ajaxRequest.abort();
|
||||||
|
@ -635,25 +657,15 @@ function setupTerminalForStreaming(args)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function fillBuildActionFromPackageSearch()
|
|
||||||
{
|
|
||||||
const packageNamesTextArea = document.getElementById('build-action-form')['package-names'];
|
|
||||||
const data = getFormTableData('package-results-form');
|
|
||||||
if (data === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
packageNamesTextArea.value = getSelectedRowProperties(data, 'name').join(' ');
|
|
||||||
location.hash = '#build-action-section';
|
|
||||||
}
|
|
||||||
|
|
||||||
function submitBuildAction()
|
function submitBuildAction()
|
||||||
{
|
{
|
||||||
startFormQuery('build-action-form', handleBuildActionResponse);
|
AjaxHelper.startFormQuery('build-action-form', handleBuildActionResponse);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBuildActionResponse(ajaxRequest)
|
function handleBuildActionResponse(ajaxRequest)
|
||||||
{
|
{
|
||||||
const results = getAndEmptyElement('build-action-results');
|
const results = Utils.getAndEmptyElement('build-action-results');
|
||||||
if (ajaxRequest.status !== 200) {
|
if (ajaxRequest.status !== 200) {
|
||||||
results.appendChild(document.createTextNode('unable to create build action: ' + ajaxRequest.responseText));
|
results.appendChild(document.createTextNode('unable to create build action: ' + ajaxRequest.responseText));
|
||||||
switchToBuildActionDetails();
|
switchToBuildActionDetails();
|
||||||
|
@ -664,7 +676,7 @@ function handleBuildActionResponse(ajaxRequest)
|
||||||
|
|
||||||
function renderBuildActionLogFiles(array, obj)
|
function renderBuildActionLogFiles(array, obj)
|
||||||
{
|
{
|
||||||
return renderCustomList(array, function(arrayElement) {
|
return GenericRendering.renderCustomList(array, function(arrayElement) {
|
||||||
const params = 'id=' + encodeURIComponent(obj.id) + '&name=' + encodeURIComponent(arrayElement);
|
const params = 'id=' + encodeURIComponent(obj.id) + '&name=' + encodeURIComponent(arrayElement);
|
||||||
const logFilePath = '/build-action/logfile?' + params;
|
const logFilePath = '/build-action/logfile?' + params;
|
||||||
const newWindowPath = 'log.html#' + params;
|
const newWindowPath = 'log.html#' + params;
|
||||||
|
@ -675,25 +687,25 @@ function renderBuildActionLogFiles(array, obj)
|
||||||
path: logFilePath,
|
path: logFilePath,
|
||||||
});
|
});
|
||||||
const basicElements = streamingSetup.elements;
|
const basicElements = streamingSetup.elements;
|
||||||
const openInNewWindowLinkElement = renderIconLink('dock-window', obj, function() { window.open(newWindowPath); }, 'Open in new window');
|
const openInNewWindowLinkElement = CustomRendering.renderIconLink('dock-window', obj, function() { window.open(newWindowPath); }, 'Open in new window');
|
||||||
const downloadLinkElement = renderIconLink('download', obj, function() { window.open(apiPrefix + logFilePath); }, 'Download log');
|
const downloadLinkElement = CustomRendering.renderIconLink('download', obj, function() { window.open(AjaxHelper.apiPrefix + logFilePath); }, 'Download log');
|
||||||
const stopStreamingLinkElement = renderIconLink('stop', obj, function() {
|
const stopStreamingLinkElement = CustomRendering.renderIconLink('stop', obj, function() {
|
||||||
if (!streamingSetup.isStreaming()) {
|
if (!streamingSetup.isStreaming()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
streamingSetup.stopStreaming();
|
streamingSetup.stopStreaming();
|
||||||
targetElement.style.display = stopStreamingLinkElement.style.display = 'none';
|
targetElement.style.display = stopStreamingLinkElement.style.display = 'none';
|
||||||
emptyDomElement(targetElement);
|
Utils.emptyDomElement(targetElement);
|
||||||
}, 'Close log');
|
}, 'Close log');
|
||||||
const startStreamingLinkElement = renderLink(arrayElement, obj, function() {
|
const startStreamingLinkElement = GenericRendering.renderLink(arrayElement, obj, function() {
|
||||||
if (streamingSetup.isStreaming()) {
|
if (streamingSetup.isStreaming()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emptyDomElement(targetElement);
|
Utils.emptyDomElement(targetElement);
|
||||||
streamingSetup.startStreaming();
|
streamingSetup.startStreaming();
|
||||||
targetElement.style.display = 'block';
|
targetElement.style.display = 'block';
|
||||||
stopStreamingLinkElement.style.display = 'inline-block';
|
stopStreamingLinkElement.style.display = 'inline-block';
|
||||||
}, 'Show log file', apiPrefix + logFilePath);
|
}, 'Show log file', AjaxHelper.apiPrefix + logFilePath);
|
||||||
targetElement.style.display = stopStreamingLinkElement.style.display = 'none';
|
targetElement.style.display = stopStreamingLinkElement.style.display = 'none';
|
||||||
[downloadLinkElement, stopStreamingLinkElement].forEach(function(element) {
|
[downloadLinkElement, stopStreamingLinkElement].forEach(function(element) {
|
||||||
element.classList.add('streaming-link');
|
element.classList.add('streaming-link');
|
||||||
|
@ -704,9 +716,9 @@ function renderBuildActionLogFiles(array, obj)
|
||||||
|
|
||||||
function renderBuildActionArtefacts(array, obj)
|
function renderBuildActionArtefacts(array, obj)
|
||||||
{
|
{
|
||||||
return renderCustomList(array, function(arrayElement) {
|
return GenericRendering.renderCustomList(array, function(arrayElement) {
|
||||||
const path = apiPrefix + '/build-action/artefact?id=' + encodeURIComponent(obj.id) + '&name=' + encodeURIComponent(arrayElement);
|
const path = AjaxHelper.apiPrefix + '/build-action/artefact?id=' + encodeURIComponent(obj.id) + '&name=' + encodeURIComponent(arrayElement);
|
||||||
return renderLink(arrayElement, obj, function() {
|
return GenericRendering.renderLink(arrayElement, obj, function() {
|
||||||
window.open(path);
|
window.open(path);
|
||||||
}, 'Download artefact', path);
|
}, 'Download artefact', path);
|
||||||
});
|
});
|
||||||
|
@ -751,12 +763,12 @@ function renderUpdateInfoWithCheckbox(id, packageName, newPackageName, versionIn
|
||||||
|
|
||||||
function renderPackageList(packageList)
|
function renderPackageList(packageList)
|
||||||
{
|
{
|
||||||
return renderCustomList(packageList, renderPackage);
|
return GenericRendering.renderCustomList(packageList, CustomRendering.renderPackage);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderBuildPreparationBuildData(buildDataForPackage)
|
function renderBuildPreparationBuildData(buildDataForPackage)
|
||||||
{
|
{
|
||||||
return renderTableFromJsonObject({
|
return GenericRendering.renderTableFromJsonObject({
|
||||||
data: buildDataForPackage,
|
data: buildDataForPackage,
|
||||||
displayLabels: ['Error', 'Warnings', 'Has source', 'Source directory', 'Original/local source directory', 'New packages', 'Existing packages', 'Specified index'],
|
displayLabels: ['Error', 'Warnings', 'Has source', 'Source directory', 'Original/local source directory', 'New packages', 'Existing packages', 'Specified index'],
|
||||||
fieldAccessors: ['error', 'warnings', 'hasSource', 'sourceDirectory', 'originalSourceDirectory', 'packages', 'existingPackages', 'specifiedIndex'],
|
fieldAccessors: ['error', 'warnings', 'hasSource', 'sourceDirectory', 'originalSourceDirectory', 'packages', 'existingPackages', 'specifiedIndex'],
|
||||||
|
@ -769,7 +781,7 @@ function renderBuildPreparationBuildData(buildDataForPackage)
|
||||||
|
|
||||||
function makeVersionsString(packages)
|
function makeVersionsString(packages)
|
||||||
{
|
{
|
||||||
const versions = packages.map(package => package.version);
|
const versions = packages.map(packageObj => packageObj.version);
|
||||||
if (versions.length === 0) {
|
if (versions.length === 0) {
|
||||||
return '?';
|
return '?';
|
||||||
} else if (versions.length === 1) {
|
} else if (versions.length === 1) {
|
||||||
|
@ -786,7 +798,7 @@ function renderBuildPreparationResultData(buildPreparationData)
|
||||||
const heading = document.createElement('h4');
|
const heading = document.createElement('h4');
|
||||||
let table;
|
let table;
|
||||||
heading.className = 'compact-heading';
|
heading.className = 'compact-heading';
|
||||||
heading.appendChild(renderLink(packageName, undefined, function() {
|
heading.appendChild(GenericRendering.renderLink(packageName, undefined, function() {
|
||||||
if (table === undefined) {
|
if (table === undefined) {
|
||||||
table = renderBuildPreparationBuildData(buildDataForPackage);
|
table = renderBuildPreparationBuildData(buildDataForPackage);
|
||||||
heading.insertAdjacentElement('afterEnd', table);
|
heading.insertAdjacentElement('afterEnd', table);
|
||||||
|
@ -808,13 +820,13 @@ function renderBuildPreparationResultData(buildPreparationData)
|
||||||
|
|
||||||
function renderOrphanPackage(value, obj, level, row)
|
function renderOrphanPackage(value, obj, level, row)
|
||||||
{
|
{
|
||||||
return renderCustomList(value, function(package) {
|
return GenericRendering.renderCustomList(value, function(packageObj) {
|
||||||
const packageName = package.name;
|
const packageName = packageObj.name;
|
||||||
return renderUpdateInfoWithCheckbox(
|
return renderUpdateInfoWithCheckbox(
|
||||||
'update-info-checkbox-' + packageName + '-' + package.version,
|
'update-info-checkbox-' + packageName + '-' + packageObj.version,
|
||||||
packageName,
|
packageName,
|
||||||
undefined,
|
undefined,
|
||||||
package.version,
|
packageObj.version,
|
||||||
row.sourceDbs,
|
row.sourceDbs,
|
||||||
);
|
);
|
||||||
}, function(package1, package2) {
|
}, function(package1, package2) {
|
||||||
|
@ -824,7 +836,7 @@ function renderOrphanPackage(value, obj, level, row)
|
||||||
|
|
||||||
function renderUpdateOrDowngrade(value, obj, level, row)
|
function renderUpdateOrDowngrade(value, obj, level, row)
|
||||||
{
|
{
|
||||||
return renderCustomList(value, function(updateInfo) {
|
return GenericRendering.renderCustomList(value, function(updateInfo) {
|
||||||
const oldVersion = updateInfo.oldVersion;
|
const oldVersion = updateInfo.oldVersion;
|
||||||
const newVersion = updateInfo.newVersion;
|
const newVersion = updateInfo.newVersion;
|
||||||
const packageName = oldVersion.name;
|
const packageName = oldVersion.name;
|
||||||
|
@ -843,12 +855,15 @@ function renderUpdateOrDowngrade(value, obj, level, row)
|
||||||
|
|
||||||
function triggerToolbarAction(toolbarElement)
|
function triggerToolbarAction(toolbarElement)
|
||||||
{
|
{
|
||||||
|
if (!toolbarElement || toolbarElement instanceof PointerEvent) {
|
||||||
|
toolbarElement = this;
|
||||||
|
}
|
||||||
const confirmQuestion = toolbarElement.dataset.confirmation;
|
const confirmQuestion = toolbarElement.dataset.confirmation;
|
||||||
if (confirmQuestion !== undefined && !window.confirm(confirmQuestion)) {
|
if (confirmQuestion !== undefined && !window.confirm(confirmQuestion)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
toolbarElement.disabled = true;
|
toolbarElement.disabled = true;
|
||||||
queryRoute(toolbarElement.dataset.method, toolbarElement.dataset.action, function(ajaxRequest) {
|
AjaxHelper.queryRoute(toolbarElement.dataset.method, toolbarElement.dataset.action, function(ajaxRequest) {
|
||||||
window.alert(ajaxRequest.responseText);
|
window.alert(ajaxRequest.responseText);
|
||||||
toolbarElement.disabled = false;
|
toolbarElement.disabled = false;
|
||||||
});
|
});
|
||||||
|
@ -857,11 +872,11 @@ function triggerToolbarAction(toolbarElement)
|
||||||
|
|
||||||
function deleteSelectedActions()
|
function deleteSelectedActions()
|
||||||
{
|
{
|
||||||
const data = getFormTableData('build-actions-list');
|
const data = Utils.getFormTableData('build-actions-list');
|
||||||
if (data === undefined) {
|
if (data === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const ids = getSelectedRowProperties(data, 'id');
|
const ids = Utils.getSelectedRowProperties(data, 'id');
|
||||||
if (ids.length && window.confirm('Do you really want to delete the build action(s) ' + ids.join(', ') + '?')) {
|
if (ids.length && window.confirm('Do you really want to delete the build action(s) ' + ids.join(', ') + '?')) {
|
||||||
deleteBuildAction(ids);
|
deleteBuildAction(ids);
|
||||||
}
|
}
|
||||||
|
@ -869,23 +884,23 @@ function deleteSelectedActions()
|
||||||
|
|
||||||
function showSelectedActions()
|
function showSelectedActions()
|
||||||
{
|
{
|
||||||
const data = getFormTableData('build-actions-list');
|
const data = Utils.getFormTableData('build-actions-list');
|
||||||
if (data === undefined) {
|
if (data === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const ids = getSelectedRowProperties(data, 'id');
|
const ids = Utils.getSelectedRowProperties(data, 'id');
|
||||||
if (ids.length) {
|
if (ids.length) {
|
||||||
queryBuildActionDetails(ids);
|
queryBuildActionDetails(ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initBuildActionDetails(sectionElement, sectionData, newHashParts)
|
export function initBuildActionDetails(sectionElement, sectionData, newHashParts)
|
||||||
{
|
{
|
||||||
const currentBuildActionIds = sectionData.state.ids;
|
const currentBuildActionIds = sectionData.state.ids;
|
||||||
const hasCurrentlyBuildActions = Array.isArray(currentBuildActionIds) && currentBuildActionIds.length !== 0;
|
const hasCurrentlyBuildActions = Array.isArray(currentBuildActionIds) && currentBuildActionIds.length !== 0;
|
||||||
if (!newHashParts.length) {
|
if (!newHashParts.length) {
|
||||||
if (hasCurrentlyBuildActions) {
|
if (hasCurrentlyBuildActions) {
|
||||||
updateHashPreventingChangeHandler('#build-action-details-section?' + encodeURIComponent(currentBuildActionIds.join(',')));
|
SinglePageHelper.updateHashPreventingChangeHandler('#build-action-details-section?' + encodeURIComponent(currentBuildActionIds.join(',')));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
import * as GenericRendering from './genericrendering.js';
|
||||||
|
import * as Utils from './utils.js';
|
||||||
|
|
||||||
/// \brief Renders a dependency object.
|
/// \brief Renders a dependency object.
|
||||||
function renderDependency(value)
|
export function renderDependency(value)
|
||||||
{
|
{
|
||||||
if (value.length < 1) {
|
if (value.length < 1) {
|
||||||
return renderArrayAsCommaSeparatedString(value);
|
return GenericRendering.renderArrayAsCommaSeparatedString(value);
|
||||||
}
|
}
|
||||||
const list = document.createElement('ul');
|
const list = document.createElement('ul');
|
||||||
list.className = 'dependency-list';
|
list.className = 'dependency-list';
|
||||||
|
@ -29,7 +32,7 @@ function renderDependency(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders a "Reload" button invoking the specified \a handler when clicked.
|
/// \brief Renders a "Reload" button invoking the specified \a handler when clicked.
|
||||||
function renderReloadButton(handler)
|
export function renderReloadButton(handler)
|
||||||
{
|
{
|
||||||
const reloadButton = document.createElement('button');
|
const reloadButton = document.createElement('button');
|
||||||
reloadButton.className = 'icon-button icon-reload';
|
reloadButton.className = 'icon-button icon-reload';
|
||||||
|
@ -40,7 +43,7 @@ function renderReloadButton(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders an icon.
|
/// \brief Renders an icon.
|
||||||
function renderIcon(iconName)
|
export function renderIcon(iconName)
|
||||||
{
|
{
|
||||||
const icon = document.createElement('span');
|
const icon = document.createElement('span');
|
||||||
icon.className = 'icon icon-' + iconName;
|
icon.className = 'icon icon-' + iconName;
|
||||||
|
@ -48,9 +51,57 @@ function renderIcon(iconName)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders an icon link which will invoke the specified \a handler when clicked.
|
/// \brief Renders an icon link which will invoke the specified \a handler when clicked.
|
||||||
function renderIconLink(value, row, handler, tooltip, href, middleClickHref)
|
export function renderIconLink(value, row, handler, tooltip, href, middleClickHref)
|
||||||
{
|
{
|
||||||
const link = renderLink(renderIcon(value), row, handler, tooltip, href, middleClickHref);
|
const link = GenericRendering.renderLink(renderIcon(value), row, handler, tooltip, href, middleClickHref);
|
||||||
link.className = 'icon-link';
|
link.className = 'icon-link';
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const labelsWithoutBasics = ['Architecture', 'Repository', 'Description', 'Upstream URL', 'License(s)', 'Groups', 'Package size', 'Installed size', 'Packager', 'Build date', 'Dependencies', 'Optional dependencies', 'Make dependencies', 'Check dependencies', 'Provides', 'Replaces', 'Conflicts', 'Contained libraries', 'Needed libraries', 'Files'];
|
||||||
|
const fieldsWithoutBasics = ['packageInfo.arch', 'db', 'description', 'upstreamUrl', 'licenses', 'groups', 'packageInfo.size', 'installInfo.installedSize', 'packageInfo.packager', 'packageInfo.buildDate', 'dependencies', 'optionalDependencies', 'sourceInfo.makeDependencies', 'sourceInfo.checkDependencies', 'provides', 'replaces', 'conflicts', 'libprovides', 'libdepends', 'packageInfo.files'];
|
||||||
|
const labelsWithBasics = ['Name', 'Version', ...labelsWithoutBasics];
|
||||||
|
const fieldsWithBasics = ['name', 'version', ...fieldsWithoutBasics];
|
||||||
|
|
||||||
|
export function renderPackage(packageObj, withoutBasics)
|
||||||
|
{
|
||||||
|
const table = GenericRendering.renderTableFromJsonObject({
|
||||||
|
data: packageObj,
|
||||||
|
displayLabels: withoutBasics ? labelsWithoutBasics : labelsWithBasics,
|
||||||
|
fieldAccessors: withoutBasics ? fieldsWithoutBasics : fieldsWithBasics,
|
||||||
|
customRenderer: {
|
||||||
|
db: function(value, row) {
|
||||||
|
return document.createTextNode(Utils.makeRepoName(value, row.dbArch));
|
||||||
|
},
|
||||||
|
upstreamUrl: function(value, row) {
|
||||||
|
return GenericRendering.renderLink(value, row, function(value) {
|
||||||
|
window.open(value);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
licenses: GenericRendering.renderArrayAsCommaSeparatedString,
|
||||||
|
groups: GenericRendering.renderArrayAsCommaSeparatedString,
|
||||||
|
dependencies: renderDependency,
|
||||||
|
optionalDependencies: renderDependency,
|
||||||
|
provides: renderDependency,
|
||||||
|
replaces: renderDependency,
|
||||||
|
conflicts: renderDependency,
|
||||||
|
libprovides: GenericRendering.renderArrayAsCommaSeparatedString,
|
||||||
|
libdepends: GenericRendering.renderArrayAsCommaSeparatedString,
|
||||||
|
'sourceInfo.makeDependencies': renderDependency,
|
||||||
|
'sourceInfo.checkDependencies': renderDependency,
|
||||||
|
'packageInfo.arch': function(value, row) {
|
||||||
|
const sourceInfo = row.sourceInfo;
|
||||||
|
const sourceArchs = sourceInfo !== undefined ? sourceInfo.archs : undefined;
|
||||||
|
if (Array.isArray(sourceArchs) && sourceArchs.length) {
|
||||||
|
return GenericRendering.renderArrayAsCommaSeparatedString(sourceArchs);
|
||||||
|
} else {
|
||||||
|
return GenericRendering.renderNoneInGrey(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'packageInfo.size': GenericRendering.renderDataSize,
|
||||||
|
'installInfo.installedSize': GenericRendering.renderDataSize,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
table.className = 'package-details-table';
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/// \brief Renders the specified \a value as text or a grey 'none' if the value is 'none' or empty.
|
/// \brief Renders the specified \a value as text or a grey 'none' if the value is 'none' or empty.
|
||||||
function renderNoneInGrey(value, row, elementName, noneText)
|
export function renderNoneInGrey(value, row, elementName, noneText)
|
||||||
{
|
{
|
||||||
const noValue = value === undefined || value === null || value === 'none' || value === 'None' ||
|
const noValue = value === undefined || value === null || value === 'none' || value === 'None' ||
|
||||||
value === '' || value === 18446744073709552000;
|
value === '' || value === 18446744073709552000;
|
||||||
|
@ -18,7 +18,7 @@ function renderNoneInGrey(value, row, elementName, noneText)
|
||||||
|
|
||||||
/// \brief Renders a standard table cell.
|
/// \brief Renders a standard table cell.
|
||||||
/// \remarks This is the default renderer used by renderTableFromJsonArray() and renderTableFromJsonObject().
|
/// \remarks This is the default renderer used by renderTableFromJsonArray() and renderTableFromJsonObject().
|
||||||
function renderStandardTableCell(data, allData, level)
|
export function renderStandardTableCell(data, allData, level)
|
||||||
{
|
{
|
||||||
const dataType = typeof data;
|
const dataType = typeof data;
|
||||||
if (dataType !== 'object') {
|
if (dataType !== 'object') {
|
||||||
|
@ -43,7 +43,7 @@ function renderStandardTableCell(data, allData, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders a custom list.
|
/// \brief Renders a custom list.
|
||||||
function renderCustomList(array, customRenderer, compareFunction)
|
export function renderCustomList(array, customRenderer, compareFunction)
|
||||||
{
|
{
|
||||||
if (!Array.isArray(array) || array.length < 1) {
|
if (!Array.isArray(array) || array.length < 1) {
|
||||||
return renderNoneInGrey();
|
return renderNoneInGrey();
|
||||||
|
@ -68,7 +68,7 @@ function renderCustomList(array, customRenderer, compareFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders a list of links.
|
/// \brief Renders a list of links.
|
||||||
function renderLinkList(array, obj, handler)
|
export function renderLinkList(array, obj, handler)
|
||||||
{
|
{
|
||||||
return renderCustomList(array, function(arrayElement) {
|
return renderCustomList(array, function(arrayElement) {
|
||||||
return renderLink(array, obj, function() {
|
return renderLink(array, obj, function() {
|
||||||
|
@ -78,7 +78,7 @@ function renderLinkList(array, obj, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Returns a 'time ago' string used by the time stamp rendering functions.
|
/// \brief Returns a 'time ago' string used by the time stamp rendering functions.
|
||||||
function formatTimeAgoString(date)
|
export function formatTimeAgoString(date)
|
||||||
{
|
{
|
||||||
const seconds = Math.floor((new Date() - date) / 1000);
|
const seconds = Math.floor((new Date() - date) / 1000);
|
||||||
let interval = Math.floor(seconds / 31536000);
|
let interval = Math.floor(seconds / 31536000);
|
||||||
|
@ -105,13 +105,13 @@ function formatTimeAgoString(date)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Returns a Date object from the specified time stamp.
|
/// \brief Returns a Date object from the specified time stamp.
|
||||||
function dateFromTimeStamp(timeStamp)
|
export function dateFromTimeStamp(timeStamp)
|
||||||
{
|
{
|
||||||
return new Date(timeStamp + 'Z');
|
return new Date(timeStamp + 'Z');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders a short time stamp, e.g. "12 hours ago" with the exact date as tooltip.
|
/// \brief Renders a short time stamp, e.g. "12 hours ago" with the exact date as tooltip.
|
||||||
function renderShortTimeStamp(timeStamp)
|
export function renderShortTimeStamp(timeStamp)
|
||||||
{
|
{
|
||||||
const date = dateFromTimeStamp(timeStamp);
|
const date = dateFromTimeStamp(timeStamp);
|
||||||
if (date.getFullYear() === 1) {
|
if (date.getFullYear() === 1) {
|
||||||
|
@ -124,7 +124,7 @@ function renderShortTimeStamp(timeStamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders a time stamp, e.g. "12 hours ago" with the exact date in brackets.
|
/// \brief Renders a time stamp, e.g. "12 hours ago" with the exact date in brackets.
|
||||||
function renderTimeStamp(timeStamp)
|
export function renderTimeStamp(timeStamp)
|
||||||
{
|
{
|
||||||
const date = dateFromTimeStamp(timeStamp);
|
const date = dateFromTimeStamp(timeStamp);
|
||||||
if (date.getFullYear() === 1) {
|
if (date.getFullYear() === 1) {
|
||||||
|
@ -134,7 +134,7 @@ function renderTimeStamp(timeStamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders a time delta from 2 time stamps.
|
/// \brief Renders a time delta from 2 time stamps.
|
||||||
function renderTimeSpan(startTimeStamp, endTimeStamp)
|
export function renderTimeSpan(startTimeStamp, endTimeStamp)
|
||||||
{
|
{
|
||||||
const startDate = dateFromTimeStamp(startTimeStamp);
|
const startDate = dateFromTimeStamp(startTimeStamp);
|
||||||
if (startDate.getFullYear() === 1) {
|
if (startDate.getFullYear() === 1) {
|
||||||
|
@ -159,7 +159,7 @@ function renderTimeSpan(startTimeStamp, endTimeStamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders a link which will invoke the specified \a handler when clicked.
|
/// \brief Renders a link which will invoke the specified \a handler when clicked.
|
||||||
function renderLink(value, row, handler, tooltip, href, middleClickHref)
|
export function renderLink(value, row, handler, tooltip, href, middleClickHref)
|
||||||
{
|
{
|
||||||
const linkElement = document.createElement('a');
|
const linkElement = document.createElement('a');
|
||||||
const linkText = typeof value === 'object' ? value : document.createTextNode(value);
|
const linkText = typeof value === 'object' ? value : document.createTextNode(value);
|
||||||
|
@ -188,13 +188,13 @@ function renderLink(value, row, handler, tooltip, href, middleClickHref)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders the specified array as comma-separated string or 'none' if the array is empty.
|
/// \brief Renders the specified array as comma-separated string or 'none' if the array is empty.
|
||||||
function renderArrayAsCommaSeparatedString(value)
|
export function renderArrayAsCommaSeparatedString(value)
|
||||||
{
|
{
|
||||||
return renderNoneInGrey(!Array.isArray(value) || value.length <= 0 ? 'none' : value.join(', '));
|
return renderNoneInGrey(!Array.isArray(value) || value.length <= 0 ? 'none' : value.join(', '));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders the specified array as a possibly elided comma-separated string or 'none' if the array is empty.
|
/// \brief Renders the specified array as a possibly elided comma-separated string or 'none' if the array is empty.
|
||||||
function renderArrayElidedAsCommaSeparatedString(value)
|
export function renderArrayElidedAsCommaSeparatedString(value)
|
||||||
{
|
{
|
||||||
if (!Array.isArray(value) || value.length <= 0) {
|
if (!Array.isArray(value) || value.length <= 0) {
|
||||||
return renderNoneInGrey('none');
|
return renderNoneInGrey('none');
|
||||||
|
@ -203,7 +203,7 @@ function renderArrayElidedAsCommaSeparatedString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders the specified value, possibly eliding the end.
|
/// \brief Renders the specified value, possibly eliding the end.
|
||||||
function renderTextPossiblyElidingTheEnd(value)
|
export function renderTextPossiblyElidingTheEnd(value)
|
||||||
{
|
{
|
||||||
const limit = 50;
|
const limit = 50;
|
||||||
if (value.length < limit) {
|
if (value.length < limit) {
|
||||||
|
@ -223,7 +223,7 @@ function renderTextPossiblyElidingTheEnd(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders the specified \a sizeInByte using an appropriate unit.
|
/// \brief Renders the specified \a sizeInByte using an appropriate unit.
|
||||||
function renderDataSize(sizeInByte, row, includeBytes)
|
export function renderDataSize(sizeInByte, row, includeBytes)
|
||||||
{
|
{
|
||||||
if (typeof(sizeInByte) !== 'number') {
|
if (typeof(sizeInByte) !== 'number') {
|
||||||
return renderNoneInGrey('none');
|
return renderNoneInGrey('none');
|
||||||
|
@ -264,7 +264,7 @@ function accessProperty(object, accessor)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Renders a checkbox for selecting a table row.
|
/// \brief Renders a checkbox for selecting a table row.
|
||||||
function renderCheckBoxForTableRow(value, row, computeCheckBoxValue)
|
export function renderCheckBoxForTableRow(value, row, computeCheckBoxValue)
|
||||||
{
|
{
|
||||||
const checkbox = document.createElement('input');
|
const checkbox = document.createElement('input');
|
||||||
checkbox.type = 'checkbox';
|
checkbox.type = 'checkbox';
|
||||||
|
@ -275,7 +275,7 @@ function renderCheckBoxForTableRow(value, row, computeCheckBoxValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Returns a table for the specified JSON array.
|
/// \brief Returns a table for the specified JSON array.
|
||||||
function renderTableFromJsonArray(args)
|
export function renderTableFromJsonArray(args)
|
||||||
{
|
{
|
||||||
// handle arguments
|
// handle arguments
|
||||||
const rows = args.rows;
|
const rows = args.rows;
|
||||||
|
@ -568,7 +568,7 @@ function renderTableFromJsonArray(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Returns a table for the specified JSON object.
|
/// \brief Returns a table for the specified JSON object.
|
||||||
function renderTableFromJsonObject(args)
|
export function renderTableFromJsonObject(args)
|
||||||
{
|
{
|
||||||
// handle arguments
|
// handle arguments
|
||||||
const data = args.data;
|
const data = args.data;
|
||||||
|
@ -619,7 +619,7 @@ function renderTableFromJsonObject(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Returns a heading for each key and values via renderStandardTableCell().
|
/// \brief Returns a heading for each key and values via renderStandardTableCell().
|
||||||
function renderObjectWithHeadings(object, row, level)
|
export function renderObjectWithHeadings(object, row, level)
|
||||||
{
|
{
|
||||||
const elements = [];
|
const elements = [];
|
||||||
for (const [key, value] of Object.entries(object)) {
|
for (const [key, value] of Object.entries(object)) {
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
function queryGlobalStatus()
|
import * as AjaxHelper from './ajaxhelper.js';
|
||||||
|
import * as BuildActionsPage from './buildactionspage.js';
|
||||||
|
import * as CustomRendering from './customrendering.js';
|
||||||
|
import * as GenericRendering from './genericrendering.js';
|
||||||
|
import * as Utils from './utils.js';
|
||||||
|
|
||||||
|
const status = {repoNames: undefined};
|
||||||
|
|
||||||
|
export function queryGlobalStatus()
|
||||||
{
|
{
|
||||||
queryRoute('GET', '/status', handleGlobalStatusUpdate);
|
AjaxHelper.queryRoute('GET', '/status', handleGlobalStatusUpdate);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleGlobalStatusUpdate(ajaxRequest)
|
function handleGlobalStatusUpdate(ajaxRequest)
|
||||||
{
|
{
|
||||||
const globalStatus = getAndEmptyElement('global-status');
|
const globalStatus = Utils.getAndEmptyElement('global-status');
|
||||||
let responseText = ajaxRequest.responseText;
|
let responseText = ajaxRequest.responseText;
|
||||||
if (ajaxRequest.status === 500) {
|
if (ajaxRequest.status === 500) {
|
||||||
responseText = 'internal server error';
|
responseText = 'internal server error';
|
||||||
|
@ -18,24 +26,24 @@ function handleGlobalStatusUpdate(ajaxRequest)
|
||||||
const responseJson = JSON.parse(responseText);
|
const responseJson = JSON.parse(responseText);
|
||||||
const applicationVersion = responseJson.version;
|
const applicationVersion = responseJson.version;
|
||||||
if (applicationVersion) {
|
if (applicationVersion) {
|
||||||
getAndEmptyElement('application-version').appendChild(document.createTextNode(applicationVersion));
|
Utils.getAndEmptyElement('application-version').appendChild(document.createTextNode(applicationVersion));
|
||||||
}
|
}
|
||||||
const dbStats = responseJson.config.dbStats;
|
const dbStats = responseJson.config.dbStats;
|
||||||
const table = renderTableFromJsonArray({
|
const table = GenericRendering.renderTableFromJsonArray({
|
||||||
rows: dbStats,
|
rows: dbStats,
|
||||||
columnHeaders: ['Arch', 'Database', 'Package count', 'Last update', 'Synced from mirror'],
|
columnHeaders: ['Arch', 'Database', 'Package count', 'Last update', 'Synced from mirror'],
|
||||||
columnAccessors: ['arch', 'name', 'packageCount', 'lastUpdate', 'syncFromMirror'],
|
columnAccessors: ['arch', 'name', 'packageCount', 'lastUpdate', 'syncFromMirror'],
|
||||||
customRenderer: {
|
customRenderer: {
|
||||||
name: function (value, row) {
|
name: function (value, row) {
|
||||||
return renderLink(value, row, showRepository);
|
return GenericRendering.renderLink(value, row, showRepository);
|
||||||
},
|
},
|
||||||
lastUpdate: renderShortTimeStamp,
|
lastUpdate: GenericRendering.renderShortTimeStamp,
|
||||||
note: function(rows) {
|
note: function(rows) {
|
||||||
const note = document.createElement('div');
|
const note = document.createElement('div');
|
||||||
const totalPackageCount = rows.reduce((acc, cur) => acc + cur.packageCount, 0);
|
const totalPackageCount = rows.reduce((acc, cur) => acc + cur.packageCount, 0);
|
||||||
note.className = 'form-row';
|
note.className = 'form-row';
|
||||||
note.appendChild(document.createTextNode(rows.length + ' databases and ' + totalPackageCount + ' packages '));
|
note.appendChild(document.createTextNode(rows.length + ' databases and ' + totalPackageCount + ' packages '));
|
||||||
note.appendChild(renderReloadButton(queryGlobalStatus));
|
note.appendChild(CustomRendering.renderReloadButton(queryGlobalStatus));
|
||||||
return note;
|
return note;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -44,13 +52,13 @@ function handleGlobalStatusUpdate(ajaxRequest)
|
||||||
|
|
||||||
// update database selections
|
// update database selections
|
||||||
const repoSelections = [
|
const repoSelections = [
|
||||||
getAndEmptyElement('build-action-source-repo', {'build-action-source-repo-none': 'keep'}),
|
Utils.getAndEmptyElement('build-action-source-repo', {'build-action-source-repo-none': 'keep'}),
|
||||||
getAndEmptyElement('build-action-destination-repo', {'build-action-destination-repo-none': 'keep'}),
|
Utils.getAndEmptyElement('build-action-destination-repo', {'build-action-destination-repo-none': 'keep'}),
|
||||||
getAndEmptyElement('package-search-db', {'package-search-db-any': 'keep'}),
|
Utils.getAndEmptyElement('package-search-db', {'package-search-db-any': 'keep'}),
|
||||||
];
|
];
|
||||||
status.repoNames = [];
|
status.repoNames = [];
|
||||||
dbStats.forEach(function (dbInfo) {
|
dbStats.forEach(function (dbInfo) {
|
||||||
const repoName = makeRepoName(dbInfo.name, dbInfo.arch);
|
const repoName = Utils.makeRepoName(dbInfo.name, dbInfo.arch);
|
||||||
status.repoNames.push(repoName);
|
status.repoNames.push(repoName);
|
||||||
repoSelections.forEach(function (selection) {
|
repoSelections.forEach(function (selection) {
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
|
@ -74,9 +82,9 @@ function handleGlobalStatusUpdate(ajaxRequest)
|
||||||
});
|
});
|
||||||
|
|
||||||
// update build action form and make settingNames/settingParams arrays for build action details
|
// update build action form and make settingNames/settingParams arrays for build action details
|
||||||
const buildActionTypeSelect = getAndEmptyElement('build-action-type');
|
const buildActionTypeSelect = Utils.getAndEmptyElement('build-action-type');
|
||||||
const buildActionFlagsContainer = getAndEmptyElement('build-action-flags');
|
const buildActionFlagsContainer = Utils.getAndEmptyElement('build-action-flags');
|
||||||
const buildActionSettingsTable = getAndEmptyElement('build-action-settings');
|
const buildActionSettingsTable = Utils.getAndEmptyElement('build-action-settings');
|
||||||
let optgroupElements = {};
|
let optgroupElements = {};
|
||||||
const makeOrReuseOptgroup = function (label) {
|
const makeOrReuseOptgroup = function (label) {
|
||||||
const existingOptgroupElement = optgroupElements[label];
|
const existingOptgroupElement = optgroupElements[label];
|
||||||
|
@ -148,7 +156,7 @@ function handleGlobalStatusUpdate(ajaxRequest)
|
||||||
});
|
});
|
||||||
|
|
||||||
// update presets/tasks form
|
// update presets/tasks form
|
||||||
const buildActionPresetSelect = getAndEmptyElement('build-action-task', {'build-action-task-none': 'keep'});
|
const buildActionPresetSelect = Utils.getAndEmptyElement('build-action-task', {'build-action-task-none': 'keep'});
|
||||||
const presets = responseJson.presets;
|
const presets = responseJson.presets;
|
||||||
globalInfo.presets = presets;
|
globalInfo.presets = presets;
|
||||||
optgroupElements = {};
|
optgroupElements = {};
|
||||||
|
@ -167,8 +175,8 @@ function handleGlobalStatusUpdate(ajaxRequest)
|
||||||
window.functionsPostponedUntilGlobalInfo.forEach(function(f) { f(); });
|
window.functionsPostponedUntilGlobalInfo.forEach(function(f) { f(); });
|
||||||
window.functionsPostponedUntilGlobalInfo = [];
|
window.functionsPostponedUntilGlobalInfo = [];
|
||||||
|
|
||||||
handleBuildActionTypeChange();
|
BuildActionsPage.handleBuildActionTypeChange();
|
||||||
handleBuildActionPresetChange();
|
BuildActionsPage.handleBuildActionPresetChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showRepository(dbName, dbInfo)
|
function showRepository(dbName, dbInfo)
|
||||||
|
|
|
@ -1,21 +1,27 @@
|
||||||
|
import * as Terminal from './terminal.js';
|
||||||
|
import * as Utils from './utils.js';
|
||||||
|
|
||||||
function initLog()
|
function initLog()
|
||||||
{
|
{
|
||||||
const hashParts = hashAsObject();
|
const hashParts = Utils.hashAsObject();
|
||||||
const id = hashParts.id;
|
const id = hashParts.id;
|
||||||
const name = hashParts.name;
|
const name = hashParts.name;
|
||||||
const mainElement = getAndEmptyElement('log-container');
|
const mainElement = Utils.getAndEmptyElement('log-container');
|
||||||
if (id === undefined || id === '' || name === undefined || name === '') {
|
if (id === undefined || id === '' || name === undefined || name === '') {
|
||||||
document.title += ' - logfile';
|
document.title += ' - logfile';
|
||||||
mainElement.appendChild(document.createTextNode('id or name invalid'));
|
mainElement.appendChild(document.createTextNode('id or name invalid'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const path = '/build-action/logfile?id=' + encodeURIComponent(id) + '&name=' + encodeURIComponent(name);
|
const path = '/build-action/logfile?id=' + encodeURIComponent(id) + '&name=' + encodeURIComponent(name);
|
||||||
const terminal = makeTerminal();
|
const terminal = Terminal.makeTerminal();
|
||||||
const ajaxRequest = streamRouteIntoTerminal('GET', path, terminal);
|
const ajaxRequest = Terminal.streamRouteIntoTerminal('GET', path, terminal);
|
||||||
document.title += ' - ' + name;
|
document.title += ' - ' + name;
|
||||||
terminal.resize(180, 500);
|
terminal.resize(180, 500);
|
||||||
window.setTimeout(function() {
|
window.setTimeout(function() {
|
||||||
addSearchToTerminal(terminal, mainElement);
|
Terminal.addSearchToTerminal(terminal, mainElement);
|
||||||
terminal.open(mainElement);
|
terminal.open(mainElement);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.body.onhashchange = initLog;
|
||||||
|
initLog();
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import * as BuildActionsPage from './buildactionspage.js';
|
||||||
|
import * as PackageDetailsPage from './packagedetailspage.js';
|
||||||
|
import * as PackageSearchPage from './packagesearchpage.js';
|
||||||
|
import * as SinglePage from './singlepage.js';
|
||||||
|
|
||||||
|
SinglePage.initPage({
|
||||||
|
'global': {
|
||||||
|
},
|
||||||
|
'package-search': {
|
||||||
|
initializer: PackageSearchPage.initPackageSearch,
|
||||||
|
state: {params: undefined},
|
||||||
|
},
|
||||||
|
'package-details': {
|
||||||
|
initializer: PackageDetailsPage.initPackageDetails,
|
||||||
|
state: {package: undefined},
|
||||||
|
},
|
||||||
|
'build-action': {
|
||||||
|
initializer: BuildActionsPage.initBuildActionsForm,
|
||||||
|
},
|
||||||
|
'build-action-details': {
|
||||||
|
initializer: BuildActionsPage.initBuildActionDetails,
|
||||||
|
state: {id: undefined},
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,10 +1,16 @@
|
||||||
function initPackageDetails(sectionElement, sectionData, newPackages)
|
import * as AjaxHelper from './ajaxhelper.js';
|
||||||
|
import * as CustomRendering from './customrendering.js';
|
||||||
|
import * as GenericRendering from './genericrendering.js';
|
||||||
|
import * as SinglePageHelper from './singlepage.js';
|
||||||
|
import * as Utils from './utils.js';
|
||||||
|
|
||||||
|
export function initPackageDetails(sectionElement, sectionData, newPackages)
|
||||||
{
|
{
|
||||||
const currentPackage = sectionData.state.package;
|
const currentPackage = sectionData.state.package;
|
||||||
const hasNewPackages = newPackages.length >= 1;
|
const hasNewPackages = newPackages.length >= 1;
|
||||||
if (!hasNewPackages) {
|
if (!hasNewPackages) {
|
||||||
if (currentPackage !== undefined) {
|
if (currentPackage !== undefined) {
|
||||||
updateHashPreventingChangeHandler('#package-details-section?' + encodeURIComponent(currentPackage));
|
SinglePageHelper.updateHashPreventingChangeHandler('#package-details-section?' + encodeURIComponent(currentPackage));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -13,12 +19,12 @@ function initPackageDetails(sectionElement, sectionData, newPackages)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const packageParts = packageStr.split('/');
|
const packageParts = packageStr.split('/');
|
||||||
const package = {
|
const packageObj = {
|
||||||
db: packageParts[0],
|
db: packageParts[0],
|
||||||
name: packageParts[1]
|
name: packageParts[1]
|
||||||
};
|
};
|
||||||
queryRoute('GET', '/packages?details=1&name=' + encodeURIComponent(packageStr), function(ajaxRequest) {
|
AjaxHelper.queryRoute('GET', '/packages?details=1&name=' + encodeURIComponent(packageStr), function(ajaxRequest) {
|
||||||
showPackageDetails(ajaxRequest, package);
|
showPackageDetails(ajaxRequest, packageObj);
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -30,21 +36,21 @@ function makePackageID(row)
|
||||||
|
|
||||||
function queryPackageDetails(value, row)
|
function queryPackageDetails(value, row)
|
||||||
{
|
{
|
||||||
queryRoute('GET', '/packages?details=1&name=' + encodeURIComponent(makePackageID(row)), function(ajaxRequest) {
|
AjaxHelper.queryRoute('GET', '/packages?details=1&name=' + encodeURIComponent(makePackageID(row)), function(ajaxRequest) {
|
||||||
showPackageDetails(ajaxRequest, row);
|
showPackageDetails(ajaxRequest, row);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchToPackageDetails(packageID)
|
function switchToPackageDetails(packageID)
|
||||||
{
|
{
|
||||||
sections['package-details'].state.package = packageID;
|
SinglePageHelper.sections['package-details'].state.package = packageID;
|
||||||
updateHashPreventingSectionInitializer('#package-details-section?' + encodeURIComponent(packageID));
|
SinglePageHelper.updateHashPreventingSectionInitializer('#package-details-section?' + encodeURIComponent(packageID));
|
||||||
}
|
}
|
||||||
|
|
||||||
function showPackageDetails(ajaxRequest, row)
|
function showPackageDetails(ajaxRequest, row)
|
||||||
{
|
{
|
||||||
const packageID = makePackageID(row);
|
const packageID = makePackageID(row);
|
||||||
const packageDetailsContainer = getAndEmptyElement('package-details-container');
|
const packageDetailsContainer = Utils.getAndEmptyElement('package-details-container');
|
||||||
if (ajaxRequest.status !== 200) {
|
if (ajaxRequest.status !== 200) {
|
||||||
packageDetailsContainer.appendChild(document.createTextNode('unable query package details: ' + ajaxRequest.responseText));
|
packageDetailsContainer.appendChild(document.createTextNode('unable query package details: ' + ajaxRequest.responseText));
|
||||||
return;
|
return;
|
||||||
|
@ -55,62 +61,14 @@ function showPackageDetails(ajaxRequest, row)
|
||||||
packageDetailsContainer.appendChild(document.createTextNode('unable query package details: package not present'));
|
packageDetailsContainer.appendChild(document.createTextNode('unable query package details: package not present'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const package = responseJson[0];
|
const packageObj = responseJson[0];
|
||||||
const heading = document.createElement('h3');
|
const heading = document.createElement('h3');
|
||||||
heading.appendChild(document.createTextNode(package.name));
|
heading.appendChild(document.createTextNode(packageObj.name));
|
||||||
heading.appendChild(document.createTextNode(' ' + package.version));
|
heading.appendChild(document.createTextNode(' ' + packageObj.version));
|
||||||
packageDetailsContainer.appendChild(heading);
|
packageDetailsContainer.appendChild(heading);
|
||||||
package.db = row.db;
|
packageObj.db = row.db;
|
||||||
package.dbArch = row.dbArch;
|
packageObj.dbArch = row.dbArch;
|
||||||
packageDetailsContainer.appendChild(renderPackage(package, true));
|
packageDetailsContainer.appendChild(CustomRendering.renderPackage(packageObj, true));
|
||||||
|
|
||||||
switchToPackageDetails(packageID);
|
switchToPackageDetails(packageID);
|
||||||
}
|
}
|
||||||
|
|
||||||
const labelsWithoutBasics = ['Architecture', 'Repository', 'Description', 'Upstream URL', 'License(s)', 'Groups', 'Package size', 'Installed size', 'Packager', 'Build date', 'Dependencies', 'Optional dependencies', 'Make dependencies', 'Check dependencies', 'Provides', 'Replaces', 'Conflicts', 'Contained libraries', 'Needed libraries', 'Files'];
|
|
||||||
const fieldsWithoutBasics = ['packageInfo.arch', 'db', 'description', 'upstreamUrl', 'licenses', 'groups', 'packageInfo.size', 'installInfo.installedSize', 'packageInfo.packager', 'packageInfo.buildDate', 'dependencies', 'optionalDependencies', 'sourceInfo.makeDependencies', 'sourceInfo.checkDependencies', 'provides', 'replaces', 'conflicts', 'libprovides', 'libdepends', 'packageInfo.files'];
|
|
||||||
const labelsWithBasics = ['Name', 'Version', ...labelsWithoutBasics];
|
|
||||||
const fieldsWithBasics = ['name', 'version', ...fieldsWithoutBasics];
|
|
||||||
|
|
||||||
function renderPackage(package, withoutBasics)
|
|
||||||
{
|
|
||||||
const table = renderTableFromJsonObject({
|
|
||||||
data: package,
|
|
||||||
displayLabels: withoutBasics ? labelsWithoutBasics : labelsWithBasics,
|
|
||||||
fieldAccessors: withoutBasics ? fieldsWithoutBasics : fieldsWithBasics,
|
|
||||||
customRenderer: {
|
|
||||||
db: function(value, row) {
|
|
||||||
return document.createTextNode(makeRepoName(value, row.dbArch));
|
|
||||||
},
|
|
||||||
upstreamUrl: function(value, row) {
|
|
||||||
return renderLink(value, row, function(value) {
|
|
||||||
window.open(value);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
licenses: renderArrayAsCommaSeparatedString,
|
|
||||||
groups: renderArrayAsCommaSeparatedString,
|
|
||||||
dependencies: renderDependency,
|
|
||||||
optionalDependencies: renderDependency,
|
|
||||||
provides: renderDependency,
|
|
||||||
replaces: renderDependency,
|
|
||||||
conflicts: renderDependency,
|
|
||||||
libprovides: renderArrayAsCommaSeparatedString,
|
|
||||||
libdepends: renderArrayAsCommaSeparatedString,
|
|
||||||
'sourceInfo.makeDependencies': renderDependency,
|
|
||||||
'sourceInfo.checkDependencies': renderDependency,
|
|
||||||
'packageInfo.arch': function(value, row) {
|
|
||||||
const sourceInfo = row.sourceInfo;
|
|
||||||
const sourceArchs = sourceInfo !== undefined ? sourceInfo.archs : undefined;
|
|
||||||
if (Array.isArray(sourceArchs) && sourceArchs.length) {
|
|
||||||
return renderArrayAsCommaSeparatedString(sourceArchs);
|
|
||||||
} else {
|
|
||||||
return renderNoneInGrey(value);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'packageInfo.size': renderDataSize,
|
|
||||||
'installInfo.installedSize': renderDataSize,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
table.className = 'package-details-table';
|
|
||||||
return table;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +1,38 @@
|
||||||
function initPackageSearch(sectionElement, sectionData, newParams)
|
import * as AjaxHelper from './ajaxhelper.js';
|
||||||
|
import * as GenericRendering from './genericrendering.js';
|
||||||
|
import * as SinglePageHelper from './singlepage.js';
|
||||||
|
import * as PackageDetailsPage from './packagedetailspage.js';
|
||||||
|
import * as Utils from './utils.js';
|
||||||
|
|
||||||
|
export function initPackageSearch(sectionElement, sectionData, newParams)
|
||||||
{
|
{
|
||||||
|
const searchForm = document.getElementById('package-search-form');
|
||||||
|
if (!searchForm.dataset.initialized) {
|
||||||
|
searchForm.onsubmit = function() {
|
||||||
|
searchForPackages();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
const packageResultsFormElements = document.getElementById('package-results-form').elements;
|
||||||
|
packageResultsFormElements.selectall.onclick = function () {
|
||||||
|
Utils.alterFormSelection(this.form, 'check-all');
|
||||||
|
};
|
||||||
|
packageResultsFormElements.unselectall.onclick = function () {
|
||||||
|
Utils.alterFormSelection(this.form, 'uncheck-all');
|
||||||
|
};
|
||||||
|
packageResultsFormElements.startselected.onclick = function () {
|
||||||
|
fillBuildActionFromPackageSearch();
|
||||||
|
};
|
||||||
|
searchForm.dataset.initialized = true;
|
||||||
|
}
|
||||||
const currentParams = sectionData.state.params;
|
const currentParams = sectionData.state.params;
|
||||||
const hasNewParams = newParams.length >= 1;
|
const hasNewParams = newParams.length >= 1;
|
||||||
if (!hasNewParams) {
|
if (!hasNewParams) {
|
||||||
if (currentParams !== undefined) {
|
if (currentParams !== undefined) {
|
||||||
updateHashPreventingChangeHandler('#package-search-section?' + encodeURIComponent(currentParams));
|
SinglePageHelper.updateHashPreventingChangeHandler('#package-search-section?' + encodeURIComponent(currentParams));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const searchParams = sections['package-search'].state.params = newParams[0];
|
const searchParams = SinglePageHelper.sections['package-search'].state.params = newParams[0];
|
||||||
if (currentParams === searchParams) {
|
if (currentParams === searchParams) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +44,17 @@ function initPackageSearch(sectionElement, sectionData, newParams)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fillBuildActionFromPackageSearch()
|
||||||
|
{
|
||||||
|
const packageNamesTextArea = document.getElementById('build-action-form')['package-names'];
|
||||||
|
const data = Utils.getFormTableData('package-results-form');
|
||||||
|
if (data === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
packageNamesTextArea.value = Utils.getSelectedRowProperties(data, 'name').join(' ');
|
||||||
|
location.hash = '#build-action-section';
|
||||||
|
}
|
||||||
|
|
||||||
function searchForPackagesFromParams(searchParams)
|
function searchForPackagesFromParams(searchParams)
|
||||||
{
|
{
|
||||||
const params = new URLSearchParams(searchParams);
|
const params = new URLSearchParams(searchParams);
|
||||||
|
@ -41,39 +76,39 @@ function searchForPackagesFromParams(searchParams)
|
||||||
formElement.value = value;
|
formElement.value = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const res = startFormQueryEx('package-search-form', showPackageSearchResults);
|
const res = AjaxHelper.startFormQueryEx('package-search-form', showPackageSearchResults);
|
||||||
sections['package-search'].state.params = res.params;
|
SinglePageHelper.sections['package-search'].state.params = res.params;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchForPackages()
|
function searchForPackages()
|
||||||
{
|
{
|
||||||
const res = startFormQueryEx('package-search-form', showPackageSearchResults);
|
const res = AjaxHelper.startFormQueryEx('package-search-form', showPackageSearchResults);
|
||||||
const params = sections['package-search'].state.params = res.params.substr(1);
|
const params = SinglePageHelper.sections['package-search'].state.params = res.params.substr(1);
|
||||||
updateHashPreventingSectionInitializer('#package-search-section?' + encodeURIComponent(params));
|
SinglePageHelper.updateHashPreventingSectionInitializer('#package-search-section?' + encodeURIComponent(params));
|
||||||
return res.ajaxRequest;
|
return res.ajaxRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showPackageSearchResults(ajaxRequest)
|
function showPackageSearchResults(ajaxRequest)
|
||||||
{
|
{
|
||||||
const packageSearchResults = getAndEmptyElement('package-search-results');
|
const packageSearchResults = Utils.getAndEmptyElement('package-search-results');
|
||||||
if (ajaxRequest.status !== 200) {
|
if (ajaxRequest.status !== 200) {
|
||||||
packageSearchResults.appendChild(document.createTextNode('unable search for packages: ' + ajaxRequest.responseText));
|
packageSearchResults.appendChild(document.createTextNode('unable search for packages: ' + ajaxRequest.responseText));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const responseJson = JSON.parse(ajaxRequest.responseText);
|
const responseJson = JSON.parse(ajaxRequest.responseText);
|
||||||
const table = renderTableFromJsonArray({
|
const table = GenericRendering.renderTableFromJsonArray({
|
||||||
rows: responseJson,
|
rows: responseJson,
|
||||||
columnHeaders: ['', 'Arch', 'Repo', 'Name', 'Version', 'Description', 'Build date'],
|
columnHeaders: ['', 'Arch', 'Repo', 'Name', 'Version', 'Description', 'Build date'],
|
||||||
columnAccessors: ['checkbox', 'arch', 'db', 'name', 'version', 'description', 'buildDate'],
|
columnAccessors: ['checkbox', 'arch', 'db', 'name', 'version', 'description', 'buildDate'],
|
||||||
rowsPerPage: 40,
|
rowsPerPage: 40,
|
||||||
customRenderer: {
|
customRenderer: {
|
||||||
name: function (value, row) {
|
name: function (value, row) {
|
||||||
return renderLink(value, row, queryPackageDetails, 'Show package details', undefined,
|
return GenericRendering.renderLink(value, row, PackageDetailsPage.queryPackageDetails, 'Show package details', undefined,
|
||||||
'#package-details-section?' + encodeURIComponent(row.db + (row.dbArch ? '@' + row.dbArch : '') + '/' + value));
|
'#package-details-section?' + encodeURIComponent(row.db + (row.dbArch ? '@' + row.dbArch : '') + '/' + value));
|
||||||
},
|
},
|
||||||
checkbox: function(value, row) {
|
checkbox: function(value, row) {
|
||||||
return renderCheckBoxForTableRow(value, row, function(row) {
|
return GenericRendering.renderCheckBoxForTableRow(value, row, function(row) {
|
||||||
return [row.db, row.name].join('/');
|
return [row.db, row.name].join('/');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,18 +1,34 @@
|
||||||
|
import * as GlobalStatusPage from './globalstatuspage.js';
|
||||||
|
import * as Utils from './utils.js';
|
||||||
|
|
||||||
|
export let sections = {};
|
||||||
|
export let sectionNames = [];
|
||||||
|
|
||||||
/// \brief 'main()' function which initializes the single page app.
|
/// \brief 'main()' function which initializes the single page app.
|
||||||
function initPage()
|
export function initPage(pageSections)
|
||||||
{
|
{
|
||||||
|
sections = pageSections;
|
||||||
|
sectionNames = Object.keys(sections);
|
||||||
handleHashChange();
|
handleHashChange();
|
||||||
queryGlobalStatus();
|
document.body.onhashchange = handleHashChange;
|
||||||
|
document.getElementById('logo-link').onclick = function () {
|
||||||
|
document.getElementById('about-dialog').style.display = 'block';
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
GlobalStatusPage.queryGlobalStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let preventHandlingHashChange = false;
|
||||||
|
let preventSectionInitializer = false;
|
||||||
|
|
||||||
/// \brief Shows the current section and hides other sections.
|
/// \brief Shows the current section and hides other sections.
|
||||||
function handleHashChange()
|
function handleHashChange()
|
||||||
{
|
{
|
||||||
if (window.preventHandlingHashChange) {
|
if (preventHandlingHashChange) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hashParts = splitHashParts();
|
const hashParts = Utils.splitHashParts();
|
||||||
const currentSectionName = hashParts.shift() || 'global-section';
|
const currentSectionName = hashParts.shift() || 'global-section';
|
||||||
if (!currentSectionName.endsWith('-section')) {
|
if (!currentSectionName.endsWith('-section')) {
|
||||||
return;
|
return;
|
||||||
|
@ -23,7 +39,7 @@ function handleHashChange()
|
||||||
const sectionElement = document.getElementById(sectionName + '-section');
|
const sectionElement = document.getElementById(sectionName + '-section');
|
||||||
if (sectionElement.id === currentSectionName) {
|
if (sectionElement.id === currentSectionName) {
|
||||||
const sectionInitializer = sectionData.initializer;
|
const sectionInitializer = sectionData.initializer;
|
||||||
if (sectionInitializer === undefined || window.preventSectionInitializer || sectionInitializer(sectionElement, sectionData, hashParts)) {
|
if (sectionInitializer === undefined || preventSectionInitializer || sectionInitializer(sectionElement, sectionData, hashParts)) {
|
||||||
sectionElement.style.display = 'block';
|
sectionElement.style.display = 'block';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -42,39 +58,17 @@ function handleHashChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Updates the #hash without triggering the handler.
|
/// \brief Updates the #hash without triggering the handler.
|
||||||
function updateHashPreventingChangeHandler(newHash)
|
export function updateHashPreventingChangeHandler(newHash)
|
||||||
{
|
{
|
||||||
window.preventHandlingHashChange = true;
|
preventHandlingHashChange = true;
|
||||||
window.location.hash = newHash;
|
window.location.hash = newHash;
|
||||||
window.preventHandlingHashChange = false;
|
preventHandlingHashChange = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Updates the #hash without triggering the section initializer.
|
/// \brief Updates the #hash without triggering the section initializer.
|
||||||
function updateHashPreventingSectionInitializer(newHash)
|
export function updateHashPreventingSectionInitializer(newHash)
|
||||||
{
|
{
|
||||||
window.preventSectionInitializer = true;
|
preventSectionInitializer = true;
|
||||||
window.location.hash = newHash;
|
window.location.hash = newHash;
|
||||||
window.preventSectionInitializer = false;
|
preventSectionInitializer = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sections = {
|
|
||||||
'global': {
|
|
||||||
},
|
|
||||||
'package-search': {
|
|
||||||
initializer: initPackageSearch,
|
|
||||||
state: {params: undefined},
|
|
||||||
},
|
|
||||||
'package-details': {
|
|
||||||
initializer: initPackageDetails,
|
|
||||||
state: {package: undefined},
|
|
||||||
},
|
|
||||||
'build-action': {
|
|
||||||
initializer: initBuildActionsForm,
|
|
||||||
},
|
|
||||||
'build-action-details': {
|
|
||||||
initializer: initBuildActionDetails,
|
|
||||||
state: {id: undefined},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const sectionNames = Object.keys(sections);
|
|
||||||
const status = {repoNames: undefined};
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
import * as AjaxHelper from './ajaxhelper.js';
|
||||||
|
|
||||||
/// \brief Returns a new terminal created via xterm.js.
|
/// \brief Returns a new terminal created via xterm.js.
|
||||||
function makeTerminal()
|
export function makeTerminal()
|
||||||
{
|
{
|
||||||
const terminal = new Terminal({
|
const terminal = new Terminal({
|
||||||
disableStdin: true,
|
disableStdin: true,
|
||||||
|
@ -11,7 +13,7 @@ function makeTerminal()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Adds a search for the specified \a terminal to the specified \a targetElement.
|
/// \brief Adds a search for the specified \a terminal to the specified \a targetElement.
|
||||||
function addSearchToTerminal(terminal, targetElement)
|
export function addSearchToTerminal(terminal, targetElement)
|
||||||
{
|
{
|
||||||
const searchAddon = new SearchAddon();
|
const searchAddon = new SearchAddon();
|
||||||
// FIXME: import the search addon correctly
|
// FIXME: import the search addon correctly
|
||||||
|
@ -41,7 +43,7 @@ function addSearchToTerminal(terminal, targetElement)
|
||||||
/// to the terminal.
|
/// to the terminal.
|
||||||
/// \remarks This initialization only works if \a targetElement is already part of the rendered HTML page. Hence this function
|
/// \remarks This initialization only works if \a targetElement is already part of the rendered HTML page. Hence this function
|
||||||
/// uses window.setTimeout to ensure \a targetElement is rendered.
|
/// uses window.setTimeout to ensure \a targetElement is rendered.
|
||||||
function setupTerminalLater(terminal, targetElement, value)
|
export function setupTerminalLater(terminal, targetElement, value)
|
||||||
{
|
{
|
||||||
window.setTimeout(function() {
|
window.setTimeout(function() {
|
||||||
terminal.open(targetElement);
|
terminal.open(targetElement);
|
||||||
|
@ -56,7 +58,7 @@ function setupTerminalLater(terminal, targetElement, value)
|
||||||
|
|
||||||
/// \brief Makes an AJAX query and writes the received data to the specified \a terminal.
|
/// \brief Makes an AJAX query and writes the received data to the specified \a terminal.
|
||||||
/// \remarks If the server responds in chunks, each chunk is written as soon as it arrives.
|
/// \remarks If the server responds in chunks, each chunk is written as soon as it arrives.
|
||||||
function streamRouteIntoTerminal(method, path, terminal)
|
export function streamRouteIntoTerminal(method, path, terminal)
|
||||||
{
|
{
|
||||||
const ajaxRequest = new XMLHttpRequest();
|
const ajaxRequest = new XMLHttpRequest();
|
||||||
let responseWritten = 0;
|
let responseWritten = 0;
|
||||||
|
@ -72,7 +74,7 @@ function streamRouteIntoTerminal(method, path, terminal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ajaxRequest.open(method, apiPrefix + path, true);
|
ajaxRequest.open(method, AjaxHelper.apiPrefix + path, true);
|
||||||
ajaxRequest.send();
|
ajaxRequest.send();
|
||||||
return ajaxRequest;
|
return ajaxRequest;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
function splitHashParts()
|
|
||||||
|
export function splitHashParts()
|
||||||
{
|
{
|
||||||
const currentHash = location.hash.substr(1);
|
const currentHash = location.hash.substr(1);
|
||||||
const hashParts = currentHash.split('?');
|
const hashParts = currentHash.split('?');
|
||||||
|
@ -8,10 +9,10 @@ function splitHashParts()
|
||||||
return hashParts;
|
return hashParts;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hashAsObject()
|
export function hashAsObject()
|
||||||
{
|
{
|
||||||
const hashObject = {};
|
const hashObject = {};
|
||||||
location.hash.substr(1).split('?').forEach(function(hashPart) {
|
location.hash.substr(1).split('&').forEach(function(hashPart) {
|
||||||
const parts = hashPart.split('=', 2);
|
const parts = hashPart.split('=', 2);
|
||||||
if (parts.length < 1) {
|
if (parts.length < 1) {
|
||||||
return;
|
return;
|
||||||
|
@ -21,12 +22,12 @@ function hashAsObject()
|
||||||
return hashObject;
|
return hashObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAndEmptyElement(elementId, specialActionsById)
|
export function getAndEmptyElement(elementId, specialActionsById)
|
||||||
{
|
{
|
||||||
return emptyDomElement(document.getElementById(elementId), specialActionsById);
|
return emptyDomElement(document.getElementById(elementId), specialActionsById);
|
||||||
}
|
}
|
||||||
|
|
||||||
function emptyDomElement(domElement, specialActionsById)
|
export function emptyDomElement(domElement, specialActionsById)
|
||||||
{
|
{
|
||||||
let child = domElement.firstChild;
|
let child = domElement.firstChild;
|
||||||
while (child) {
|
while (child) {
|
||||||
|
@ -40,7 +41,7 @@ function emptyDomElement(domElement, specialActionsById)
|
||||||
return domElement;
|
return domElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
function alterFormSelection(form, command)
|
export function alterFormSelection(form, command)
|
||||||
{
|
{
|
||||||
// modify form elements
|
// modify form elements
|
||||||
const elements = form.elements;
|
const elements = form.elements;
|
||||||
|
@ -78,7 +79,7 @@ function alterFormSelection(form, command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProperty(object, property, fallback)
|
export function getProperty(object, property, fallback)
|
||||||
{
|
{
|
||||||
if (typeof object !== 'object') {
|
if (typeof object !== 'object') {
|
||||||
return fallback;
|
return fallback;
|
||||||
|
@ -87,13 +88,13 @@ function getProperty(object, property, fallback)
|
||||||
return value !== undefined ? value : fallback;
|
return value !== undefined ? value : fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeRepoName(dbName, dbArch)
|
export function makeRepoName(dbName, dbArch)
|
||||||
{
|
{
|
||||||
return dbArch && dbArch !== 'x86_64' ? dbName + '@' + dbArch : dbName;
|
return dbArch && dbArch !== 'x86_64' ? dbName + '@' + dbArch : dbName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Returns the table row data for the table within the element with the specified ID.
|
/// \brief Returns the table row data for the table within the element with the specified ID.
|
||||||
function getFormTableData(formId)
|
export function getFormTableData(formId)
|
||||||
{
|
{
|
||||||
const formElement = document.getElementById(formId);
|
const formElement = document.getElementById(formId);
|
||||||
const tableElement = formElement.getElementsByTagName('table')[0];
|
const tableElement = formElement.getElementsByTagName('table')[0];
|
||||||
|
@ -106,7 +107,7 @@ function getFormTableData(formId)
|
||||||
|
|
||||||
/// \brief Returns the cell values of selected rows.
|
/// \brief Returns the cell values of selected rows.
|
||||||
/// \remarks The row data needs to be passed. The cell is determined by the specified \a propertyName.
|
/// \remarks The row data needs to be passed. The cell is determined by the specified \a propertyName.
|
||||||
function getSelectedRowProperties(data, propertyName)
|
export function getSelectedRowProperties(data, propertyName)
|
||||||
{
|
{
|
||||||
const propertyValues = [];
|
const propertyValues = [];
|
||||||
data.forEach(function (row) {
|
data.forEach(function (row) {
|
||||||
|
|
|
@ -8,17 +8,13 @@
|
||||||
<meta name="author" content="Martchus" />
|
<meta name="author" content="Martchus" />
|
||||||
<meta name="keywords" content="pacman, Arch Linux, build, service" />
|
<meta name="keywords" content="pacman, Arch Linux, build, service" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||||||
<link rel="stylesheet" type="text/css" href="css/style.css" />
|
<link rel="stylesheet" type="text/css" href="css/basics.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="css/log.css" />
|
<link rel="stylesheet" type="text/css" href="css/log.css" />
|
||||||
<script type="application/javascript" src="js/ajaxhelper.js"></script>
|
<script type="module" src="js/log.js"></script>
|
||||||
<script type="application/javascript" src="js/utils.js"></script>
|
|
||||||
<script type="application/javascript" src="js/log.js"></script>
|
|
||||||
<!-- 3rd party libraries -->
|
<!-- 3rd party libraries -->
|
||||||
<link rel="stylesheet" type="text/css" href="node_modules/xterm/css/xterm.css" />
|
<link rel="stylesheet" type="text/css" href="node_modules/xterm/css/xterm.css" />
|
||||||
<script type="application/javascript" src="node_modules/xterm/lib/xterm.js"></script>
|
<script type="application/javascript" src="node_modules/xterm/lib/xterm.js"></script>
|
||||||
<script type="application/javascript" src="node_modules/xterm-addon-search/out/SearchAddon.js"></script>
|
<script type="application/javascript" src="node_modules/xterm-addon-search/out/SearchAddon.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body onload="initLog();" onhashchange="initLog();">
|
<body><main id="log-container"></main></body>
|
||||||
<main id="log-container"></main>
|
</html>
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
Loading…
Reference in New Issue