mirror of
https://github.com/netbirdio/plugins.git
synced 2026-05-22 18:44:07 -07:00
www/nginx: add columns select button to the log viewer (#3411)
This commit is contained in:
@@ -26,7 +26,11 @@
|
||||
|
||||
thead.sticky-top th {
|
||||
position: sticky;
|
||||
top: 80px;
|
||||
top: 50px;
|
||||
}
|
||||
|
||||
tr.filter > th {
|
||||
padding: 10px 10px 10px 10px !important;
|
||||
}
|
||||
|
||||
thead.sticky-top tr:first-child th {
|
||||
@@ -38,4 +42,17 @@ tfoot.sticky-bottom th {
|
||||
bottom: 50px;
|
||||
font-weight: normal;
|
||||
font-family: inherit;
|
||||
padding: 10px 10px 10px 10px !important;
|
||||
}
|
||||
|
||||
td.referer, td.request_line {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.ngx-dropdown-item {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 3px 20px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,30 +1,32 @@
|
||||
import accessLogLine from '../templates/AccessLogLine.html';
|
||||
import streamAccessLogLine from '../templates/StreamAccessLogLine.html';
|
||||
import errorLogLine from '../templates/ErrorLogLine.html';
|
||||
import LogLine from '../templates/LogLine.html';
|
||||
import LogColumn from '../templates/LogColumn.html';
|
||||
import logViewer from '../templates/logviewer.html';
|
||||
import LogLinesCollection from "../models/LogLinesCollection";
|
||||
import LogColumnModel from "../models/LogColumn";
|
||||
import noDataAvailable from '../templates/noDataAvailable.html';
|
||||
|
||||
|
||||
const LogViewLine = Backbone.View.extend({
|
||||
tagName: 'tr',
|
||||
initialize: function (data) {
|
||||
this.type = data.type;
|
||||
this.log_fields_visible = data.log_fields_visible;
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.html(this.get_template()({model: this.model}));
|
||||
this.$el.html(LogLine({log_fields_visible: this.log_fields_visible, model: this.model}));
|
||||
},
|
||||
});
|
||||
|
||||
const LogViewColumns = Backbone.View.extend({
|
||||
tagName: 'tr',
|
||||
className: 'filter',
|
||||
initialize: function (data) {
|
||||
this.log_fields_visible = data.log_fields_visible;
|
||||
},
|
||||
|
||||
get_template: function() {
|
||||
if (this.type === 'accesses') {
|
||||
return accessLogLine;
|
||||
} else if (this.type === 'stream_accesses') {
|
||||
return streamAccessLogLine;
|
||||
} else {
|
||||
return errorLogLine;
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
this.log_fields_visible.forEach((field) => this.$el.append(LogColumn({field: field, model: this.model})));
|
||||
}
|
||||
});
|
||||
|
||||
const LogView = Backbone.View.extend({
|
||||
@@ -39,6 +41,7 @@ const LogView = Backbone.View.extend({
|
||||
"click #paging_forward": "page_forward",
|
||||
"click #paging_last": "page_last",
|
||||
"change #entrycount": "change_entry_count",
|
||||
"click .ngx-dropdown-item": "toggle_column",
|
||||
},
|
||||
page_entry_count: 100,
|
||||
filter_delay: -1,
|
||||
@@ -52,10 +55,60 @@ const LogView = Backbone.View.extend({
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// set logline fields
|
||||
// all the fields are visible by default
|
||||
// users choice is stored in browser localStorage
|
||||
this.logFields = [];
|
||||
let uid = this.collection.uuid;
|
||||
let type = this.type;
|
||||
switch (type) {
|
||||
case 'accesses':
|
||||
this.logFields.push({id: "time", header: "Time"},
|
||||
{id: "remote_ip", header: "Remote IP"},
|
||||
{id: "username", header: "Username"},
|
||||
{id: "status", header: "Status"},
|
||||
{id: "size", header: "Size"},
|
||||
{id: "referer", header: "Referer"},
|
||||
{id: "user_agent", header: "User Agent"},
|
||||
{id: "forwarded_for", header: "Forwarded For"},
|
||||
{id: "request_line", header: "Request Line"});
|
||||
break;
|
||||
case 'errors':
|
||||
case 'stream_errors':
|
||||
this.logFields.push({id: "date", header: "Date"},
|
||||
{id: "time", header: "Time"},
|
||||
{id: "severity", header: "Severity"},
|
||||
{id: "number", header: "Number"},
|
||||
{id: "message", header: "Message"});
|
||||
break;
|
||||
default:
|
||||
// stream access
|
||||
this.logFields.push({id: "time", header: "Time"},
|
||||
{id: "remote_ip", header: "Remote IP"},
|
||||
{id: "status", header: "Status"},
|
||||
{id: "bytes_sent", header: "Bytes Sent"},
|
||||
{id: "bytes_received", header: "Bytes Rcvd"},
|
||||
{id: "session_time", header: "Session Time"});
|
||||
}
|
||||
this.logFields.forEach( (field) => {
|
||||
field.visible = localStorage.getItem('visibleColumns[' + type + '][' + uid + '][' + field.id + ']') !== 'false';
|
||||
});
|
||||
|
||||
this.logFieldsVisible = _.filter(this.logFields, ['visible', true]);
|
||||
// fields are ready
|
||||
|
||||
// create/update column headers
|
||||
let thead = this.$('thead');
|
||||
if (thead.children().length < 1) {
|
||||
const logColumns = new LogViewColumns({log_fields_visible: this.logFieldsVisible, model: this.collection.filter_model});
|
||||
logColumns.render();
|
||||
thead.html(logColumns.$el);
|
||||
}
|
||||
|
||||
let tbody = this.$('tbody');
|
||||
if (tbody.length < 1) {
|
||||
if (this.collection.length !== 0) {
|
||||
this.$el.html(logViewer({log_type: this.type, model: this.collection.filter_model}));
|
||||
this.$el.html(logViewer({log_type: this.type, log_fields: this.logFields, log_fields_visible: this.logFieldsVisible, model: this.collection.filter_model}));
|
||||
tbody = this.$('tbody');
|
||||
} else {
|
||||
this.$el.html(noDataAvailable);
|
||||
@@ -99,7 +152,7 @@ const LogView = Backbone.View.extend({
|
||||
},
|
||||
|
||||
render_one: function(parent_element, model) {
|
||||
const logline = new LogViewLine({type: this.type, model: model});
|
||||
const logline = new LogViewLine({type: this.type, log_fields_visible: this.logFieldsVisible, model: model});
|
||||
logline.render();
|
||||
parent_element.append(logline.$el);
|
||||
},
|
||||
@@ -161,6 +214,20 @@ const LogView = Backbone.View.extend({
|
||||
this.page_entry_count = event.target.value;
|
||||
this.current_page = 0;
|
||||
this.update();
|
||||
},
|
||||
|
||||
toggle_column: function (event) {
|
||||
event.stopPropagation();
|
||||
let uid = this.collection.uuid;
|
||||
let type = this.type;
|
||||
let field = $(event.currentTarget).find('input').prop('value');
|
||||
// toggle visibility
|
||||
localStorage.setItem('visibleColumns[' + type + '][' + uid + '][' + field + ']', !_.find(this.logFields, { 'id': field }).visible);
|
||||
// unset filter for this column (if any) so as not to confuse the user
|
||||
this.collection.filter_model.unset(field, {silent: true});
|
||||
// reset table header and update data
|
||||
this.$('thead').html('');
|
||||
this.update();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
const LogColumnModel = Backbone.Model.extend({
|
||||
});
|
||||
|
||||
export default LogColumnModel;
|
||||
@@ -1,9 +0,0 @@
|
||||
<td class="time"><%= model.escape('time') %></td>
|
||||
<td class="remote_ip"><%= model.escape('remote_ip') %></td>
|
||||
<td class="username"><%= model.escape('username') %></td>
|
||||
<td class="status"><%= model.escape('status') %></td>
|
||||
<td class="size"><%= model.escape('size') %></td>
|
||||
<td class="referer"><%= model.escape('http_referer') %></td>
|
||||
<td class="user_agent"><%= model.escape('user_agent') %></td>
|
||||
<td class="forwarded_for"><%= model.escape('forwarded_for') %></td>
|
||||
<td class="request_line"><%= model.escape('request_line') %></td>
|
||||
@@ -1,5 +0,0 @@
|
||||
<td class="date"><%= model.escape('date') %></td>
|
||||
<td class="time"><%= model.escape('time') %></td>
|
||||
<td class="severity"><%= model.escape('severity') %></td>
|
||||
<td class="number"><%= model.escape('number') %></td>
|
||||
<td class="message"><%= model.escape('message') %></td>
|
||||
@@ -0,0 +1,6 @@
|
||||
<th class="active">
|
||||
<div class="form-group" style="margin-bottom: unset;">
|
||||
<label for="<%= _.escape(field.id) %>"><%= _.escape(field.header) %></label>
|
||||
<input type="text" class="form-control" id="<%= _.escape(field.id) %>" value="<%= model.escape(field.id) %>" name="<%= _.escape(field.id) %>" />
|
||||
</div>
|
||||
</th>
|
||||
@@ -0,0 +1,3 @@
|
||||
<% log_fields_visible.forEach( (field) => { %>
|
||||
<td class="<%= _.escape(field.id) %>"><%= model.escape(field.id) %></td>
|
||||
<% }) %>
|
||||
@@ -1,6 +0,0 @@
|
||||
<td class="time"><%= model.escape('time') %></td>
|
||||
<td class="remote_ip"><%= model.escape('remote_ip') %></td>
|
||||
<td class="status"><%= model.escape('status') %></td>
|
||||
<td class="bytes_sent"><%= model.escape('bytes_sent') %></td>
|
||||
<td class="bytes_received"><%= model.escape('bytes_received') %></td>
|
||||
<td class="session_time"><%= model.escape('session_time') %></td>
|
||||
@@ -1,93 +1,42 @@
|
||||
<% let count = 0; %><table class="table table-striped">
|
||||
<table class="table table-striped">
|
||||
<thead class="sticky-top">
|
||||
<tr>
|
||||
<% if (log_type === 'errors' || log_type === 'stream_errors') {
|
||||
count = 5; %>
|
||||
<th>Date</th>
|
||||
<th>Time</th>
|
||||
<th>Severity</th>
|
||||
<th>Number</th>
|
||||
<th>Message</th>
|
||||
<% } else if (log_type === 'accesses') {
|
||||
count = 9; %>
|
||||
<th>Time</th>
|
||||
<th>Remote IP</th>
|
||||
<th>Username</th>
|
||||
<th>Status</th>
|
||||
<th>Size</th>
|
||||
<th>Referer</th>
|
||||
<th>User Agent</th>
|
||||
<th>Forwarded For</th>
|
||||
<th>Request Line</th>
|
||||
<% } else {
|
||||
count = 6; %>
|
||||
<th>Time</th>
|
||||
<th>Remote IP</th>
|
||||
<th>Status</th>
|
||||
<th>Bytes Sent</th>
|
||||
<th>Bytes Received</th>
|
||||
<th>Session Time</th>
|
||||
<% } %>
|
||||
</tr>
|
||||
<tr class="filter">
|
||||
<% if (log_type === 'errors' || log_type === 'stream_errors') { %>
|
||||
<th class="active"><input type="text" value="<%= model.escape('date') %>" name="date" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('time') %>" name="time" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('severity') %>" name="severity" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('number') %>" name="number" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('message') %>" name="message" /></th>
|
||||
<% } else if (log_type === 'accesses') { %>
|
||||
<th class="active"><input type="text" value="<%= model.escape('time') %>" name="time" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('remote_ip') %>" name="remote_ip" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('username') %>" name="username" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('status') %>" name="status" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('size') %>" name="size" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('http_referer') %>" name="http_referer" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('user_agent') %>" name="user_agent" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('forwarded_for') %>" name="forwarded_for" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('request_line') %>" name="request_line" /></th>
|
||||
<% } else { %>
|
||||
<th class="active"><input type="text" value="<%= model.escape('time') %>" name="time" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('remote_ip') %>" name="remote_ip" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('status') %>" name="status" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('bytes_sent') %>" name="bytes_sent" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('bytes_received') %>" name="bytes_received" /></th>
|
||||
<th class="active"><input type="text" value="<%= model.escape('session_time') %>" name="session_time" /></th>
|
||||
<% } %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot class="sticky-bottom">
|
||||
<tr>
|
||||
<th class="text-nowrap active">
|
||||
<th class="text-nowrap active" colspan="100">
|
||||
<div class="btn-group dropup"><button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><span class="dropdown-text"><span class="icon glyphicon glyphicon-th-list"></span></span> <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu">
|
||||
<% log_fields.forEach( (field) => { %>
|
||||
<li><label class="ngx-dropdown-item"><input type="checkbox" class="option" value="<%= _.escape(field.id) %>" <%= field.visible === true ? 'checked="checked"' : '' %>/> <%= _.escape(field.header) %></label></li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
</div>
|
||||
<button class="btn btn-primary" id="paging_first" title="First Page"><i class="fa fa-fast-backward" aria-hidden="true"></i></button>
|
||||
<button class="btn btn-primary" id="paging_back" title="Previous Page"><i class="fa fa-step-backward" aria-hidden="true"></i></button>
|
||||
<button class="btn btn-primary" id="refresh" title="Refresh"><i class="fa fa-refresh" aria-hidden="true"></i></button>
|
||||
<button class="btn btn-primary" id="paging_forward" title="Next Page"><i class="fa fa-step-forward" aria-hidden="true"></i></button>
|
||||
<button class="btn btn-primary" id="paging_last" title="Last Page"><i class="fa fa-fast-forward " aria-hidden="true"></i></button>
|
||||
<span style="padding-left: 10px;">Page </span><span id="currentpage">1</span>/<span id="pagecount">0</span>
|
||||
<div style="float: right; display: flex;">
|
||||
<label for="entrycount"><span id="entrycountdisplay">100</span> lines per page</label><input type="range" list="tickmarks" min="5" max="1000" step="5" id="entrycount" value="100" style="width: 200px;" />
|
||||
<datalist id="tickmarks">
|
||||
<option value="5" label="5">
|
||||
<option value="100" label="100">
|
||||
<option value="200" label="200">
|
||||
<option value="300">
|
||||
<option value="400">
|
||||
<option value="500" label="500">
|
||||
<option value="600">
|
||||
<option value="700">
|
||||
<option value="800">
|
||||
<option value="900">
|
||||
<option value="1000" label="1000">
|
||||
</datalist>
|
||||
</div>
|
||||
<span style="padding-left: 10px;">Found lines: </span><span id="resultcount">0</span>/<span id="totalcount">0</span>
|
||||
</th>
|
||||
<th class="active">
|
||||
Page <span id="currentpage">1</span>/<span id="pagecount">0</span>
|
||||
</th>
|
||||
<th class="active" colspan="2">
|
||||
<label for="entrycount"><span id="entrycountdisplay">100</span> lines per page</label>
|
||||
<input type="range" list="tickmarks" min="5" max="1000" step="5" id="entrycount" value="100" />
|
||||
<datalist id="tickmarks">
|
||||
<option value="5" label="5">
|
||||
<option value="100" label="100">
|
||||
<option value="200" label="200">
|
||||
<option value="300">
|
||||
<option value="400">
|
||||
<option value="500" label="500">
|
||||
<option value="600">
|
||||
<option value="700">
|
||||
<option value="800">
|
||||
<option value="900">
|
||||
<option value="1000" label="1000">
|
||||
</datalist>
|
||||
</th>
|
||||
<th class="active" colspan="<%= count - 4 %>">Found lines: <span id="resultcount">0</span>/<span id="totalcount">0</span></th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user