mirror of
https://github.com/gSpotx2f/ruantiblock_openwrt.git
synced 2026-05-13 14:10:59 +00:00
luci-app: update log.
This commit is contained in:
@@ -11,7 +11,7 @@ LUCI_APP=1
|
||||
OWRT_VERSION="current"
|
||||
RUAB_VERSION="1.3-1"
|
||||
RUAB_MOD_LUA_VERSION="1.3-2"
|
||||
RUAB_LUCI_APP_VERSION="1.3-1"
|
||||
RUAB_LUCI_APP_VERSION="1.3-2"
|
||||
BASE_URL="https://raw.githubusercontent.com/gSpotx2f/packages-openwrt/master"
|
||||
PKG_DIR="/tmp"
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_VERSION:=1.3-1
|
||||
PKG_VERSION:=1.3-2
|
||||
LUCI_TITLE:=LuCI support for ruantiblock
|
||||
LUCI_DEPENDS:=+ruantiblock
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
+91
-145
@@ -17,6 +17,7 @@ document.head.append(E('style', {'type': 'text/css'},
|
||||
--app-log-notice: #e3ffec;
|
||||
--app-log-info: rgba(0,0,0,0);
|
||||
--app-log-debug: #ebf6ff;
|
||||
--app-log-entries-count-border: #ccc;
|
||||
}
|
||||
:root[data-darkmode="true"] {
|
||||
--app-log-dark-font-color: #fff;
|
||||
@@ -30,34 +31,7 @@ document.head.append(E('style', {'type': 'text/css'},
|
||||
--app-log-notice: #007627;
|
||||
--app-log-info: rgba(0,0,0,0);
|
||||
--app-log-debug: #5986b1;
|
||||
}
|
||||
.log-entry-empty {
|
||||
}
|
||||
.log-entry-number {
|
||||
min-width: 4em !important;
|
||||
}
|
||||
.log-entry-time {
|
||||
min-width: 15em !important;
|
||||
}
|
||||
.log-entry-host {
|
||||
min-width: 10em !important;
|
||||
}
|
||||
.log-entry-host-cell {
|
||||
word-break: break-all !important;
|
||||
word-wrap: break-word !important;
|
||||
}
|
||||
.log-entry-log-level {
|
||||
max-width: 5em !important;
|
||||
}
|
||||
.log-entry-facility{
|
||||
max-width: 7em !important;
|
||||
}
|
||||
.log-entry-message {
|
||||
min-width: 25em !important;
|
||||
}
|
||||
.log-entry-message-cell {
|
||||
overflow-x: hidden !important;
|
||||
text-overflow: ellipsis !important;
|
||||
--app-log-entries-count-border: #555;
|
||||
}
|
||||
.log-empty {
|
||||
}
|
||||
@@ -123,6 +97,7 @@ log-emerg td {
|
||||
}
|
||||
.log-info {
|
||||
background-color: var(--app-log-info) !important;
|
||||
/*color: var(--app-log-dark-font-color) !important;*/
|
||||
}
|
||||
.log-debug {
|
||||
background-color: var(--app-log-debug) !important;
|
||||
@@ -150,13 +125,25 @@ log-emerg td {
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid var(--app-log-entries-count-border);
|
||||
font-weight: normal;
|
||||
}
|
||||
.log-host-dropdown-item {
|
||||
}
|
||||
.log-facility-dropdown-item {
|
||||
}
|
||||
.log-scroll-block {
|
||||
position: fixed;
|
||||
z-index: 1 !important;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.log-scroll-btn {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin: 0 !important;
|
||||
left: 1px;
|
||||
top: 1px;
|
||||
}
|
||||
`));
|
||||
|
||||
return baseclass.extend({
|
||||
@@ -325,7 +312,7 @@ return baseclass.extend({
|
||||
*
|
||||
* @param {number} tail
|
||||
* @returns {string}
|
||||
* Returns the raw content of the log
|
||||
* Returns the raw content of the log.
|
||||
*/
|
||||
getLogData(tail) {
|
||||
throw new Error('getLogData must be overridden by a subclass');
|
||||
@@ -338,12 +325,49 @@ return baseclass.extend({
|
||||
* @param {string} logdata
|
||||
* @param {number} tail
|
||||
* @returns {Array<number, string|null, string|null, string|null, string|null, string|null>}
|
||||
* Returns an array of values: [ #, Timestamp, Host, Level, Facility, Message ]
|
||||
* Returns an array of values: [ #, Timestamp, Host, Level, Facility, Message ].
|
||||
*/
|
||||
parseLogData(logdata, tail) {
|
||||
throw new Error('parseLogData must be overridden by a subclass');
|
||||
},
|
||||
|
||||
/**
|
||||
* Highlight the result of a regular expression.
|
||||
* Abstract method, must be overridden by a subclass!
|
||||
*
|
||||
* @param {string} logdata
|
||||
* @returns {string}
|
||||
* Returns a string with the highlighted part.
|
||||
*/
|
||||
regexpFilterHighlightFunc(match) {
|
||||
throw new Error('parseLogData must be overridden by a subclass');
|
||||
},
|
||||
|
||||
setRegexpFilter(entriesArray, fieldNum, pattern) {
|
||||
let fArr = [];
|
||||
try {
|
||||
let regExp = new RegExp(pattern, 'giu');
|
||||
entriesArray.forEach((e, i) => {
|
||||
if(e[fieldNum] !== null && regExp.test(e[fieldNum])) {
|
||||
if(this.regexpFilterHighlightFunc) {
|
||||
e[fieldNum] = e[fieldNum].replace(regExp, this.regexpFilterHighlightFunc);
|
||||
};
|
||||
fArr.push(e);
|
||||
};
|
||||
regExp.lastIndex = 0;
|
||||
});
|
||||
} catch(err) {
|
||||
if(err.name === 'SyntaxError') {
|
||||
ui.addNotification(null,
|
||||
E('p', {}, _('Invalid regular expression') + ': ' + err.message));
|
||||
return entriesArray;
|
||||
} else {
|
||||
throw err;
|
||||
};
|
||||
};
|
||||
return fArr;
|
||||
},
|
||||
|
||||
setDateFilter(entriesArray) {
|
||||
let fPattern = document.getElementById('timeFilter').value;
|
||||
if(!fPattern) {
|
||||
@@ -389,35 +413,6 @@ return baseclass.extend({
|
||||
return entriesArray;
|
||||
},
|
||||
|
||||
regexpFilterHighlightFunc(match) {
|
||||
return `<span class="log-highlight-item">${match}</span>`;
|
||||
},
|
||||
|
||||
setRegexpFilter(entriesArray, fieldNum, pattern) {
|
||||
let fArr = [];
|
||||
try {
|
||||
let regExp = new RegExp(pattern, 'giu');
|
||||
entriesArray.forEach((e, i) => {
|
||||
if(e[fieldNum] !== null && regExp.test(e[fieldNum])) {
|
||||
if(this.regexpFilterHighlightFunc) {
|
||||
e[fieldNum] = e[fieldNum].replace(regExp, this.regexpFilterHighlightFunc);
|
||||
};
|
||||
fArr.push(e);
|
||||
};
|
||||
regExp.lastIndex = 0;
|
||||
});
|
||||
} catch(err) {
|
||||
if(err.name === 'SyntaxError') {
|
||||
ui.addNotification(null,
|
||||
E('p', {}, _('Invalid regular expression') + ': ' + err.message));
|
||||
return entriesArray;
|
||||
} else {
|
||||
throw err;
|
||||
};
|
||||
};
|
||||
return fArr;
|
||||
},
|
||||
|
||||
setMsgFilter(entriesArray) {
|
||||
let fPattern = document.getElementById('msgFilter').value;
|
||||
if(!fPattern) {
|
||||
@@ -426,70 +421,16 @@ return baseclass.extend({
|
||||
return this.setRegexpFilter(entriesArray, 5, fPattern);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the contents of the log area.
|
||||
* Abstract method, must be overridden by a subclass!
|
||||
*
|
||||
* @param {Array<number, string|null, string|null, string|null, string|null, string|null>} logdataArray
|
||||
* @returns {Node}
|
||||
* Returns a DOM node containing the log area.
|
||||
*/
|
||||
makeLogArea(logdataArray) {
|
||||
let lines = `<tr class="tr"><td class="td center log-entry-empty">${_('No entries available...')}</td></tr>`;
|
||||
let logTable = E('table', { 'id': 'logTable', 'class': 'table' });
|
||||
|
||||
for(let level of Object.keys(this.logLevels)) {
|
||||
this.logLevelsStat[level] = 0;
|
||||
};
|
||||
|
||||
if(logdataArray.length > 0) {
|
||||
lines = [];
|
||||
logdataArray.forEach((e, i) => {
|
||||
if(e[4] in this.logLevels) {
|
||||
this.logLevelsStat[e[4]] = this.logLevelsStat[e[4]] + 1;
|
||||
};
|
||||
|
||||
lines.push(
|
||||
`<tr class="tr log-${e[4] || 'empty'}"><td class="td left" data-title="#">${e[0]}</td>` +
|
||||
((e[1]) ? `<td class="td left" data-title="${_('Timestamp')}"><span class="log-timestamp">${e[1]}</span></td>` : '') +
|
||||
((e[2]) ? `<td class="td left log-entry-host-cell" data-title="${_('Host')}">${e[2]}</td>` : '') +
|
||||
((e[3]) ? `<td class="td left" data-title="${_('Facility')}">${e[3]}</td>` : '') +
|
||||
((e[4]) ? `<td class="td left" data-title="${_('Level')}">${e[4]}</td>` : '') +
|
||||
((e[5]) ? `<td class="td left log-entry-message-cell" data-title="${_('Message')}">${e[5]}</td>` : '') +
|
||||
`</tr>`
|
||||
);
|
||||
});
|
||||
lines = lines.join('');
|
||||
|
||||
logTable.append(
|
||||
E('tr', { 'class': 'tr table-titles' }, [
|
||||
E('th', { 'class': 'th left log-entry-number' }, '#'),
|
||||
(logdataArray[0][1]) ? E('th', { 'class': 'th left log-entry-time' }, _('Timestamp')) : '',
|
||||
(logdataArray[0][2]) ? E('th', { 'class': 'th left log-entry-host' }, _('Host')) : '',
|
||||
(logdataArray[0][4]) ? E('th', { 'class': 'th left log-entry-facility' }, _('Facility')) : '',
|
||||
(logdataArray[0][3]) ? E('th', { 'class': 'th left log-entry-log-level' }, _('Level')) : '',
|
||||
(logdataArray[0][5]) ? E('th', { 'class': 'th left log-entry-message' }, _('Message')) : '',
|
||||
])
|
||||
);
|
||||
};
|
||||
|
||||
try {
|
||||
logTable.insertAdjacentHTML('beforeend', lines);
|
||||
} catch(err) {
|
||||
if(err.name === 'SyntaxError') {
|
||||
ui.addNotification(null,
|
||||
E('p', {}, _('HTML/XML error') + ': ' + err.message), 'error');
|
||||
};
|
||||
throw err;
|
||||
};
|
||||
|
||||
let levelsStatString = '';
|
||||
if((Object.values(this.logLevelsStat).reduce((s,c) => s + c, 0)) > 0) {
|
||||
Object.entries(this.logLevelsStat).forEach(e => {
|
||||
if(e[0] in this.logLevels && e[1] > 0) {
|
||||
levelsStatString += `<span class="log-entries-count-level log-${e[0]}" title="${e[0]}">${e[1]}</span>`;
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
return E([
|
||||
E('div', { 'class': 'log-entries-count' },
|
||||
`${_('Entries')}: ${logdataArray.length} / ${this.totalLogLines}${levelsStatString}`
|
||||
),
|
||||
logTable,
|
||||
]);
|
||||
throw new Error('parseLogData must be overridden by a subclass');
|
||||
},
|
||||
|
||||
downloadLog(ev) {
|
||||
@@ -529,7 +470,7 @@ return baseclass.extend({
|
||||
render(logdata) {
|
||||
let logWrapper = E('div', {
|
||||
'id' : 'logWrapper',
|
||||
'style': 'width:100%; min-height:20em; padding: 0 0 0 45px; font-size:0.9em !important'
|
||||
'style': 'width:100%; min-height:20em'
|
||||
}, this.makeLogArea(this.parseLogData(logdata, this.tailValue)));
|
||||
|
||||
let tailInput = E('input', {
|
||||
@@ -670,6 +611,29 @@ return baseclass.extend({
|
||||
});
|
||||
};
|
||||
|
||||
document.body.append(
|
||||
E('div', {
|
||||
'class': 'log-scroll-block',
|
||||
'style': 'right:1px; top:' + (window.innerHeight / 4 * 3) + 'px',
|
||||
}, [
|
||||
E('button', {
|
||||
'class': 'btn log-scroll-btn',
|
||||
'click': ev => {
|
||||
document.getElementById('logTitle').scrollIntoView(true);
|
||||
ev.target.blur();
|
||||
},
|
||||
}, '↑'),
|
||||
E('button', {
|
||||
'class': 'btn log-scroll-btn',
|
||||
'style': 'margin-top:1px !important',
|
||||
'click': ev => {
|
||||
logWrapper.scrollIntoView(false);
|
||||
ev.target.blur();
|
||||
},
|
||||
}, '↓'),
|
||||
])
|
||||
);
|
||||
|
||||
return E([
|
||||
E('h2', { 'id': 'logTitle', 'class': 'fade-in' }, this.title),
|
||||
E('div', { 'class': 'cbi-section-descr fade-in' }),
|
||||
@@ -740,27 +704,9 @@ return baseclass.extend({
|
||||
])
|
||||
),
|
||||
E('div', { 'class': 'cbi-section fade-in' },
|
||||
E('div', { 'class': 'cbi-section-node' }, [
|
||||
E('div', { 'style': 'position:fixed; z-index:1 !important' }, [
|
||||
E('button', {
|
||||
'class': 'btn',
|
||||
'style': 'position:relative; display:block; margin:0 !important; left:1px; top:1px',
|
||||
'click': ev => {
|
||||
document.getElementById('logTitle').scrollIntoView(true);
|
||||
ev.target.blur();
|
||||
},
|
||||
}, '↑'),
|
||||
E('button', {
|
||||
'class': 'btn',
|
||||
'style': 'position:relative; display:block; margin:0 !important; margin-top:1px !important; left:1px; top:1px',
|
||||
'click': ev => {
|
||||
logWrapper.scrollIntoView(false);
|
||||
ev.target.blur();
|
||||
},
|
||||
}, '↓'),
|
||||
]),
|
||||
logWrapper,
|
||||
])
|
||||
E('div', { 'class': 'cbi-section-node' },
|
||||
logWrapper
|
||||
)
|
||||
),
|
||||
E('div', { 'class': 'cbi-section fade-in' },
|
||||
E('div', { 'class': 'cbi-section-node' },
|
||||
@@ -0,0 +1,111 @@
|
||||
'use strict';
|
||||
'require baseclass';
|
||||
'require ui';
|
||||
'require view.log.log-base as abc';
|
||||
|
||||
document.head.append(E('style', {'type': 'text/css'},
|
||||
`
|
||||
.log-entry-empty {
|
||||
}
|
||||
.log-entry-number {
|
||||
min-width: 4em !important;
|
||||
}
|
||||
.log-entry-time {
|
||||
min-width: 15em !important;
|
||||
}
|
||||
.log-entry-host {
|
||||
min-width: 10em !important;
|
||||
}
|
||||
.log-entry-host-cell {
|
||||
word-break: break-all !important;
|
||||
word-wrap: break-word !important;
|
||||
}
|
||||
.log-entry-log-level {
|
||||
max-width: 5em !important;
|
||||
}
|
||||
.log-entry-facility{
|
||||
max-width: 7em !important;
|
||||
}
|
||||
.log-entry-message {
|
||||
min-width: 25em !important;
|
||||
}
|
||||
.log-entry-message-cell {
|
||||
overflow-x: hidden !important;
|
||||
text-overflow: ellipsis !important;
|
||||
}
|
||||
`));
|
||||
|
||||
return baseclass.extend({
|
||||
view: abc.view.extend({
|
||||
|
||||
regexpFilterHighlightFunc(match) {
|
||||
return `<span class="log-highlight-item">${match}</span>`;
|
||||
},
|
||||
|
||||
makeLogArea(logdataArray) {
|
||||
let lines = `<tr class="tr"><td class="td center log-entry-empty">${_('No entries available...')}</td></tr>`;
|
||||
let logTable = E('table', { 'id': 'logTable', 'class': 'table' });
|
||||
|
||||
for(let level of Object.keys(this.logLevels)) {
|
||||
this.logLevelsStat[level] = 0;
|
||||
};
|
||||
|
||||
if(logdataArray.length > 0) {
|
||||
lines = [];
|
||||
logdataArray.forEach((e, i) => {
|
||||
if(e[4] in this.logLevels) {
|
||||
this.logLevelsStat[e[4]] = this.logLevelsStat[e[4]] + 1;
|
||||
};
|
||||
|
||||
lines.push(
|
||||
`<tr class="tr log-${e[4] || 'empty'}"><td class="td left" data-title="#">${e[0]}</td>` +
|
||||
((e[1]) ? `<td class="td left" data-title="${_('Timestamp')}">${e[1]}</td>` : '') +
|
||||
((e[2]) ? `<td class="td left log-entry-host-cell" data-title="${_('Host')}">${e[2]}</td>` : '') +
|
||||
((e[3]) ? `<td class="td left" data-title="${_('Facility')}">${e[3]}</td>` : '') +
|
||||
((e[4]) ? `<td class="td left" data-title="${_('Level')}">${e[4]}</td>` : '') +
|
||||
((e[5]) ? `<td class="td left log-entry-message-cell" data-title="${_('Message')}">${e[5]}</td>` : '') +
|
||||
'</tr>'
|
||||
);
|
||||
});
|
||||
lines = lines.join('');
|
||||
|
||||
logTable.append(
|
||||
E('tr', { 'class': 'tr table-titles' }, [
|
||||
E('th', { 'class': 'th left log-entry-number' }, '#'),
|
||||
(logdataArray[0][1]) ? E('th', { 'class': 'th left log-entry-time' }, _('Timestamp')) : '',
|
||||
(logdataArray[0][2]) ? E('th', { 'class': 'th left log-entry-host' }, _('Host')) : '',
|
||||
(logdataArray[0][3]) ? E('th', { 'class': 'th left log-entry-facility' }, _('Facility')) : '',
|
||||
(logdataArray[0][4]) ? E('th', { 'class': 'th left log-entry-log-level' }, _('Level')) : '',
|
||||
(logdataArray[0][5]) ? E('th', { 'class': 'th left log-entry-message' }, _('Message')) : '',
|
||||
])
|
||||
);
|
||||
};
|
||||
|
||||
try {
|
||||
logTable.insertAdjacentHTML('beforeend', lines);
|
||||
} catch(err) {
|
||||
if(err.name === 'SyntaxError') {
|
||||
ui.addNotification(null,
|
||||
E('p', {}, _('HTML/XML error') + ': ' + err.message), 'error');
|
||||
};
|
||||
throw err;
|
||||
};
|
||||
|
||||
let levelsStatString = '';
|
||||
if((Object.values(this.logLevelsStat).reduce((s,c) => s + c, 0)) > 0) {
|
||||
Object.entries(this.logLevelsStat).forEach(e => {
|
||||
if(e[0] in this.logLevels && e[1] > 0) {
|
||||
levelsStatString += `<span class="log-entries-count-level log-${e[0]}" title="${e[0]}">${e[1]}</span>`;
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
return E([
|
||||
E('div', { 'class': 'log-entries-count' },
|
||||
`${_('Entries')}: ${logdataArray.length} / ${this.totalLogLines}${levelsStatString}`
|
||||
),
|
||||
logTable,
|
||||
]);
|
||||
},
|
||||
}),
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
'require fs';
|
||||
'require ui';
|
||||
'require view.ruantiblock.abstract-log as abc';
|
||||
'require view.ruantiblock.log-widget as abc';
|
||||
'require view.ruantiblock.tools as tools';
|
||||
|
||||
return abc.view.extend({
|
||||
|
||||
Reference in New Issue
Block a user