summaryrefslogtreecommitdiffstats
path: root/modules-available/syslog
diff options
context:
space:
mode:
authorSimon Rettberg2017-07-06 14:39:06 +0200
committerSimon Rettberg2017-07-06 14:39:06 +0200
commit75c4c1c22c9f44b93602270e5b0cb521ec2aad3b (patch)
treedb7e0fecf3199bd496232e430edf8910eba8d980 /modules-available/syslog
parent[roomplanner] Support : in mac search, use small display of client (diff)
downloadslx-admin-75c4c1c22c9f44b93602270e5b0cb521ec2aad3b.tar.gz
slx-admin-75c4c1c22c9f44b93602270e5b0cb521ec2aad3b.tar.xz
slx-admin-75c4c1c22c9f44b93602270e5b0cb521ec2aad3b.zip
[syslog] Improved filtering with suggestions from existing log
Diffstat (limited to 'modules-available/syslog')
-rw-r--r--modules-available/syslog/clientscript.js8
-rw-r--r--modules-available/syslog/config.json3
-rw-r--r--modules-available/syslog/page.inc.php12
-rw-r--r--modules-available/syslog/style.css45
-rw-r--r--modules-available/syslog/templates/page-syslog.html101
5 files changed, 86 insertions, 83 deletions
diff --git a/modules-available/syslog/clientscript.js b/modules-available/syslog/clientscript.js
deleted file mode 100644
index 3d652628..00000000
--- a/modules-available/syslog/clientscript.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * bootstrap-tagsinput v0.3.9 by Tim Schlechter
- *
- */
-!function(a){"use strict";function b(b,c){this.itemsArray=[],this.$element=a(b),this.$element.hide(),this.isSelect="SELECT"===b.tagName,this.multiple=this.isSelect&&b.hasAttribute("multiple"),this.objectItems=c&&c.itemValue,this.placeholderText=b.hasAttribute("placeholder")?this.$element.attr("placeholder"):"",this.inputSize=Math.max(1,this.placeholderText.length),this.$container=a('<div class="bootstrap-tagsinput"></div>'),this.$input=a('<input size="'+this.inputSize+'" type="text" placeholder="'+this.placeholderText+'"/>').appendTo(this.$container),this.$element.after(this.$container),this.build(c)}function c(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(a){return a[c]}}}function d(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(){return c}}}function e(a){return a?h.text(a).html():""}function f(a){var b=0;if(document.selection){a.focus();var c=document.selection.createRange();c.moveStart("character",-a.value.length),b=c.text.length}else(a.selectionStart||"0"==a.selectionStart)&&(b=a.selectionStart);return b}var g={tagClass:function(){return"label label-info"},itemValue:function(a){return a?a.toString():a},itemText:function(a){return this.itemValue(a)},freeInput:!0,maxTags:void 0,confirmKeys:[13],onTagExists:function(a,b){b.hide().fadeIn()}};b.prototype={constructor:b,add:function(b,c){var d=this;if(!(d.options.maxTags&&d.itemsArray.length>=d.options.maxTags||b!==!1&&!b)){if("object"==typeof b&&!d.objectItems)throw"Can't add objects when itemValue option is not set";if(!b.toString().match(/^\s*$/)){if(d.isSelect&&!d.multiple&&d.itemsArray.length>0&&d.remove(d.itemsArray[0]),"string"==typeof b&&"INPUT"===this.$element[0].tagName){var f=b.split(",");if(f.length>1){for(var g=0;g<f.length;g++)this.add(f[g],!0);return c||d.pushVal(),void 0}}var h=d.options.itemValue(b),i=d.options.itemText(b),j=d.options.tagClass(b),k=a.grep(d.itemsArray,function(a){return d.options.itemValue(a)===h})[0];if(k){if(d.options.onTagExists){var l=a(".tag",d.$container).filter(function(){return a(this).data("item")===k});d.options.onTagExists(b,l)}}else{d.itemsArray.push(b);var m=a('<span class="tag '+e(j)+'">'+e(i)+'<span data-role="remove"></span></span>');if(m.data("item",b),d.findInputWrapper().before(m),m.after(" "),d.isSelect&&!a('option[value="'+escape(h)+'"]',d.$element)[0]){var n=a("<option selected>"+e(i)+"</option>");n.data("item",b),n.attr("value",h),d.$element.append(n)}c||d.pushVal(),d.options.maxTags===d.itemsArray.length&&d.$container.addClass("bootstrap-tagsinput-max"),d.$element.trigger(a.Event("itemAdded",{item:b}))}}}},remove:function(b,c){var d=this;d.objectItems&&(b="object"==typeof b?a.grep(d.itemsArray,function(a){return d.options.itemValue(a)==d.options.itemValue(b)})[0]:a.grep(d.itemsArray,function(a){return d.options.itemValue(a)==b})[0]),b&&(a(".tag",d.$container).filter(function(){return a(this).data("item")===b}).remove(),a("option",d.$element).filter(function(){return a(this).data("item")===b}).remove(),d.itemsArray.splice(a.inArray(b,d.itemsArray),1)),c||d.pushVal(),d.options.maxTags>d.itemsArray.length&&d.$container.removeClass("bootstrap-tagsinput-max"),d.$element.trigger(a.Event("itemRemoved",{item:b}))},removeAll:function(){var b=this;for(a(".tag",b.$container).remove(),a("option",b.$element).remove();b.itemsArray.length>0;)b.itemsArray.pop();b.pushVal(),b.options.maxTags&&!this.isEnabled()&&this.enable()},refresh:function(){var b=this;a(".tag",b.$container).each(function(){var c=a(this),d=c.data("item"),f=b.options.itemValue(d),g=b.options.itemText(d),h=b.options.tagClass(d);if(c.attr("class",null),c.addClass("tag "+e(h)),c.contents().filter(function(){return 3==this.nodeType})[0].nodeValue=e(g),b.isSelect){var i=a("option",b.$element).filter(function(){return a(this).data("item")===d});i.attr("value",f)}})},items:function(){return this.itemsArray},pushVal:function(){var b=this,c=a.map(b.items(),function(a){return b.options.itemValue(a).toString()});b.$element.val(c,!0).trigger("change")},build:function(b){var e=this;e.options=a.extend({},g,b);var h=e.options.typeahead||{};e.objectItems&&(e.options.freeInput=!1),c(e.options,"itemValue"),c(e.options,"itemText"),c(e.options,"tagClass"),e.options.source&&(h.source=e.options.source),h.source&&a.fn.typeahead&&(d(h,"source"),e.$input.typeahead({source:function(b,c){function d(a){for(var b=[],d=0;d<a.length;d++){var g=e.options.itemText(a[d]);f[g]=a[d],b.push(g)}c(b)}this.map={};var f=this.map,g=h.source(b);a.isFunction(g.success)?g.success(d):a.when(g).then(d)},updater:function(a){e.add(this.map[a])},matcher:function(a){return-1!==a.toLowerCase().indexOf(this.query.trim().toLowerCase())},sorter:function(a){return a.sort()},highlighter:function(a){var b=new RegExp("("+this.query+")","gi");return a.replace(b,"<strong>$1</strong>")}})),e.$container.on("click",a.proxy(function(){e.$input.focus()},e)),e.$container.on("keydown","input",a.proxy(function(b){var c=a(b.target),d=e.findInputWrapper();switch(b.which){case 8:if(0===f(c[0])){var g=d.prev();g&&e.remove(g.data("item"))}break;case 46:if(0===f(c[0])){var h=d.next();h&&e.remove(h.data("item"))}break;case 37:var i=d.prev();0===c.val().length&&i[0]&&(i.before(d),c.focus());break;case 39:var j=d.next();0===c.val().length&&j[0]&&(j.after(d),c.focus());break;default:e.options.freeInput&&a.inArray(b.which,e.options.confirmKeys)>=0&&(e.add(c.val()),c.val(""),b.preventDefault())}c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("click","[data-role=remove]",a.proxy(function(b){e.remove(a(b.target).closest(".tag").data("item"))},e)),e.options.itemValue===g.itemValue&&("INPUT"===e.$element[0].tagName?e.add(e.$element.val()):a("option",e.$element).each(function(){e.add(a(this).attr("value"),!0)}))},destroy:function(){var a=this;a.$container.off("keypress","input"),a.$container.off("click","[role=remove]"),a.$container.remove(),a.$element.removeData("tagsinput"),a.$element.show()},focus:function(){this.$input.focus()},input:function(){return this.$input},findInputWrapper:function(){for(var b=this.$input[0],c=this.$container[0];b&&b.parentNode!==c;)b=b.parentNode;return a(b)}},a.fn.tagsinput=function(c,d){var e=[];return this.each(function(){var f=a(this).data("tagsinput");if(f){var g=f[c](d);void 0!==g&&e.push(g)}else f=new b(this,c),a(this).data("tagsinput",f),e.push(f),"SELECT"===this.tagName&&a("option",a(this)).attr("selected","selected"),a(this).val(a(this).val())}),"string"==typeof c?e.length>1?e:e[0]:e},a.fn.tagsinput.Constructor=b;var h=a("<div />");a(function(){a("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput()})}(window.jQuery);
-/*
-//@ sourceMappingURL=bootstrap-tagsinput.min.js.map
-*/ \ No newline at end of file
diff --git a/modules-available/syslog/config.json b/modules-available/syslog/config.json
index 6778348d..2b718a8e 100644
--- a/modules-available/syslog/config.json
+++ b/modules-available/syslog/config.json
@@ -1,3 +1,4 @@
{
- "category":"main.status"
+ "category":"main.status",
+ "dependencies":["js_selectize"]
}
diff --git a/modules-available/syslog/page.inc.php b/modules-available/syslog/page.inc.php
index 486e0248..f2bc4854 100644
--- a/modules-available/syslog/page.inc.php
+++ b/modules-available/syslog/page.inc.php
@@ -15,6 +15,12 @@ class Page_SysLog extends Page
protected function doRender()
{
+ $cutoff = strtotime('-1 month');
+ $res = Database::simpleQuery("SELECT logtypeid, Count(*) AS counter FROM clientlog WHERE dateline > $cutoff GROUP BY logtypeid ORDER BY counter ASC");
+ $types = array();
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $types[$row['logtypeid']] = $row;
+ }
if (isset($_GET['filter'])) {
$filter = $_GET['filter'];
$not = isset($_GET['not']) ? 'NOT' : '';
@@ -35,6 +41,9 @@ class Page_SysLog extends Page
$filterItem = preg_replace('/[^a-z0-9_\-]/', '', trim($filterItem));
if (empty($filterItem) || in_array($filterItem, $whereClause)) continue;
$whereClause[] = "'$filterItem'";
+ if (!isset($types[$filterItem])) {
+ $types[$filterItem] = ['logtypeid' => $filterItem, 'counter' => ''];
+ }
}
if (!empty($whereClause)) $whereClause = ' WHERE logtypeid ' . $not . ' IN (' . implode(', ', $whereClause) . ')';
}
@@ -67,7 +76,8 @@ class Page_SysLog extends Page
$paginate->render('page-syslog', array(
'filter' => $filter,
'not' => $not,
- 'list' => $lines
+ 'list' => $lines,
+ 'types' => json_encode(array_values($types)),
));
}
diff --git a/modules-available/syslog/style.css b/modules-available/syslog/style.css
deleted file mode 100644
index 98cfa7f3..00000000
--- a/modules-available/syslog/style.css
+++ /dev/null
@@ -1,45 +0,0 @@
-.bootstrap-tagsinput {
- background-color: #fff;
- border: 1px solid #ccc;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- display: inline-block;
- padding: 4px 6px;
- margin-bottom: 10px;
- color: #555;
- vertical-align: middle;
- border-radius: 4px;
- max-width: 100%;
- line-height: 22px;
-}
-.bootstrap-tagsinput input {
- border: none;
- box-shadow: none;
- outline: none;
- background-color: transparent;
- padding: 0;
- margin: 0;
- width: auto !important;
- max-width: inherit;
-}
-.bootstrap-tagsinput input:focus {
- border: none;
- box-shadow: none;
-}
-.bootstrap-tagsinput .tag {
- margin-right: 2px;
- color: white;
-}
-.bootstrap-tagsinput .tag [data-role="remove"] {
- margin-left: 8px;
- cursor: pointer;
-}
-.bootstrap-tagsinput .tag [data-role="remove"]:after {
- content: "x";
- padding: 0px 2px;
-}
-.bootstrap-tagsinput .tag [data-role="remove"]:hover {
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-.bootstrap-tagsinput .tag [data-role="remove"]:hover:active {
- box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
-}
diff --git a/modules-available/syslog/templates/page-syslog.html b/modules-available/syslog/templates/page-syslog.html
index 98e94291..cb20a93a 100644
--- a/modules-available/syslog/templates/page-syslog.html
+++ b/modules-available/syslog/templates/page-syslog.html
@@ -1,35 +1,47 @@
<h1>{{lang_clientLog}}</h1>
+<style type="text/css">
+ .selectize-dropdown {
+ max-width: 500px;
+ }
+</style>
<form method="post" action="?do=SysLog">
<input type="hidden" name="token" value="{{token}}">
+ <div class="pull-left">
+ <label for="filterstring">{{lang_filter}}</label>
+ </div>
+ <div class="clearfix"></div>
<div class="input-group">
- <span class="input-group-addon">{{lang_filter}}</span>
- <input id="filterstring" type="text" placeholder="id" value="{{filter}}" name="filter" data-role="tagsinput" />
- <span class="input-group-addon">
- <input type="checkbox" name="not" {{#not}}checked="checked"{{/not}}> {{lang_not}}
- </span>
+ <input id="filterstring" placeholder="id" value="{{filter}}" name="filter">
<span class="input-group-btn">
- <button class="btn btn-default" type="submit">{{lang_go}}</button>
- </span>
+ <button class="btn btn-default" type="submit">{{lang_go}}</button>
+ </span>
+ </div>
+ <div class="pull-left">
+ <div class="checkbox">
+ <input id="notbox" type="checkbox" name="not" {{#not}}checked="checked"{{/not}}>
+ <label for="notbox">{{lang_not}}</label>
+ </div>
</div>
</form>
{{{pagenav}}}
<table class="table table-striped table-condensed">
<thead>
- <th width="1"></th>
- <th>{{lang_when}}</th>
- <th>{{lang_client}}</th>
- <th>{{lang_event}}</th>
- <th width="1">{{lang_details}}</th>
+ <th width="1"></th>
+ <th>{{lang_when}}</th>
+ <th>{{lang_client}}</th>
+ <th>{{lang_event}}</th>
+ <th width="1">{{lang_details}}</th>
</thead>
<tbody>
{{#list}}
<tr>
- <td><span class="glyphicon {{icon}}" title="{{logtypeid}}" onclick="$('#filterstring').tagsinput('add', '{{logtypeid}}')"></span></td>
+ <td><span class="type-button glyphicon {{icon}}" title="{{logtypeid}}"></span></td>
<td class="text-right" nowrap="nowrap">{{date}}</td>
<td>{{clientip}}</td>
<td>{{description}}</td>
<td>{{#extra}}
- <a class="btn btn-default btn-xs pull-left" onclick="$('#details-body').html($('#extra-{{logid}}').html())" data-toggle="modal" data-target="#myModal">&raquo;</a>
+ <a class="btn btn-default btn-xs pull-left" onclick="$('#details-body').html($('#extra-{{logid}}').html())"
+ data-toggle="modal" data-target="#myModal">&raquo;</a>
<div class="hidden" id="extra-{{logid}}">{{extra}}</div>
{{/extra}}</td>
</tr>
@@ -39,20 +51,53 @@
{{{pagenav}}}
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
- <div class="modal-dialog modal-lg">
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
- <h4 class="modal-title" id="myModalLabel">{{lang_details}}</h4>
- </div>
- <div class="modal-body">
- <pre id="details-body"></pre>
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
- </div>
- </div>
- </div>
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span
+ class="sr-only">Close</span></button>
+ <h4 class="modal-title" id="myModalLabel">{{lang_details}}</h4>
+ </div>
+ <div class="modal-body">
+ <pre id="details-body"></pre>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+ </div>
+ </div>
+ </div>
</div>
+<script type="application/javascript"><!--
+document.addEventListener('DOMContentLoaded', function () {
+
+ function renderOption(item, escape) {
+ return '<div><div class="pull-right badge">' + escape(item.counter) + '</div>' + escape(item.logtypeid) + '</div>';
+ }
+
+ function renderSelected(item, escape) {
+ return '<div>' + escape(item.logtypeid) + '</div>';
+ }
+
+ var opts = {{{types}}} || [];
+ var $box = $('#filterstring').selectize({
+ options: opts,
+ plugins: ["remove_button"],
+ valueField: 'logtypeid',
+ searchField: "logtypeid",
+ openOnFocus: true,
+ create: true,
+ render: {option: renderOption, item: renderSelected},
+ maxItems: null,
+ highlight: false
+ });
+ var inst = $box[0].selectize;
+
+ $('.type-button').click(function() {
+ inst.addOption({logtypeid: this.title, counter: ''});
+ inst.addItem(this.title, true);
+ });
+});
+//--></script>
+