%PDF- %PDF-
| Direktori : /proc/thread-self/root/backups/router/usr/local/opnsense/www/js/ |
| Current File : //proc/thread-self/root/backups/router/usr/local/opnsense/www/js/opnsense_status.js |
/**
* Copyright (C) 2022-2025 Deciso B.V.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
class Status {
constructor() {
this.observers = [];
this.data = null;
}
updateStatus() {
const fetch = new Promise((resolve, reject) => {
ajaxGet('/api/core/system/status', {path: window.location.pathname}, function (data, status) {
if (status !== "success") {
reject(status);
}
resolve(data);
});
});
fetch.then((data) => {
if (!data.subsystems || typeof data.subsystems !== 'object') {
data.subsystems = { };
}
this.notify(data);
}, (reject) => {
// Either inaccessible or something went wrong on the backend.
$('#system_status').css({
'cursor': 'default',
'pointer-events': 'none'
});
});
}
attach(observer) {
this.observers.push(observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class StatusIcon {
update(status) {
const icon = this._parseStatusIcon(status.metadata.system.status);
$('#system_status').removeClass().addClass(icon);
}
_parseStatusIcon(statusCode) {
switch (statusCode) {
case "ERROR":
return 'fa fa-circle text-danger';
case "WARNING":
return 'fa fa-circle text-warning';
case "NOTICE":
return 'fa fa-circle text-info';
default:
return 'fa fa-circle text-muted';
}
}
asClass(statusCode) {
return this._parseStatusIcon(statusCode);
}
}
class StatusDialog {
constructor() {
this.clickHandlerRegistered = false;
this.dialogOpen = false;
this.currentStatus = null;
this.dialog = null;
}
update(status) {
this.currentStatus = status;
if (!this.clickHandlerRegistered) {
this.clickHandlerRegistered = true;
const translations = status.metadata.translations;
$('#system_status').click(() => {
this.dialog = new BootstrapDialog({
title: translations.dialogTitle,
draggable: true,
buttons: [{
id: 'close',
label: translations.dialogCloseButton,
action: (dialogRef) => {
dialogRef.close();
this.dialogOpen = false;
}
}],
});
this._setDialogContent(this.currentStatus);
this.dialog.open();
this.dialogOpen = true;
});
} else {
this._setDialogContent(this.currentStatus);
if (!this.dialogOpen) {
this.dialog.open();
this.dialogOpen = true;
}
}
}
_setDialogContent(status) {
this.dialog.setMessage((dialog) => {
let $ret = $(`
<div>
<a data-dismiss="modal" class="btn btn-default" style="width:100%; text-align: left;" href="#">
<h4>
<span class="fa fa-circle text-muted">
</span>
System
</h4>
<p>No pending messages.</p>
</a>
</div>
`);
let $message = $(
'<div>' +
'<div id="opn-status-list"></div>' +
'</div>'
);
for (let [shortname, subject] of Object.entries(status.subsystems)) {
if (subject.status == "OK" || subject.isBanner)
continue;
$message.find('a').last().addClass('__mb');
let formattedSubject = subject.title;
if (subject.age != undefined) {
formattedSubject += ' <small>(' + subject.age + ')</small>';
}
let ref = subject.location != null ? `href="${subject.location}"` : '';
let hoverStyle = (subject.location == null && subject.persistent) ? 'cursor: default; pointer-events: none;' : '';
let $closeBtn = `
<button id="dismiss-${shortname}" class="close">
<span aria-hidden="true">×</span>
</button>
`;
let $listItem = $(`
<a class="btn btn-default" style="width:100%; text-align: left; ${hoverStyle}" ${ref}>
<h4>
<span class="${(new StatusIcon()).asClass(subject.status)}"></span>
${formattedSubject}
${subject.persistent ? '' : $closeBtn}
</h4>
<p style="white-space: pre-wrap;">${subject.message}</p>
</a>
`)
$message.find('#opn-status-list').append($listItem);
$message.find('#dismiss-' + shortname).on('click', function (e) {
e.preventDefault();
$.ajax('/api/core/system/dismissStatus', {
type: 'post',
data: {'subject': shortname},
dialogRef: dialog,
itemRef: $listItem,
success: function() {
statusObj.updateStatus();
}
});
});
$ret = $message;
}
return $ret;
});
}
}
class StatusBanner {
constructor() {
this.bannerActive = false;
}
update(status) {
for (let [name, subject] of Object.entries(status.subsystems)) {
if (subject.status == "OK")
continue;
if (subject.isBanner) {
if (!this.bannerActive) {
$('.page-content-main > .container-fluid > .row').prepend($(`
<div class="container-fluid">
<div id="notification-banner" class="alert ${this.parseStatusBanner(subject.status)}"
style="padding: 10px; text-align: center;">
${subject.message}
</div>
</div>
`));
this.bannerActive = true;
break;
} else {
$('#notification-banner').text(subject.message);
$('#notification-banner').removeClass().addClass(`alert ${this.parseStatusBanner(subject.status)}`);
}
}
}
}
parseStatusBanner(statusCode) {
switch (statusCode) {
case "ERROR":
return 'alert-danger';
case "WARNING":
return 'alert-warning';
default:
return 'alert-info';
}
}
}
const statusObj = new Status();
function updateSystemStatus() {
statusObj.attach(new StatusIcon());
statusObj.attach(new StatusDialog());
statusObj.attach(new StatusBanner());
statusObj.updateStatus();
}