Merge pull request #341 from mterzo/data_table_format

Update HTML and Javascript
This commit is contained in:
Mike Terzo
2017-02-02 07:31:16 -05:00
committed by GitHub
16 changed files with 163 additions and 82 deletions

View File

@@ -219,6 +219,9 @@ Other settings that might be interesting in no particular order:
* ``ENABLE_QUERY``: Defaults to ``True`` causing a Query tab to show up in the * ``ENABLE_QUERY``: Defaults to ``True`` causing a Query tab to show up in the
web interface allowing users to write and execute arbitrary queries against web interface allowing users to write and execute arbitrary queries against
a set of endpoints in PuppetDB. Change this to ``False`` to disable this. a set of endpoints in PuppetDB. Change this to ``False`` to disable this.
* ``GRAPH_TYPE```: Specify the type of graph to display. Default is
pie, other good option is donut. Other choices can be found here:
`_C3JS_documentation`
* ``GRAPH_FACTS``: A list of fact names to tell PuppetBoard to generate a * ``GRAPH_FACTS``: A list of fact names to tell PuppetBoard to generate a
pie-chart on the fact page. With some fact values being unique per node, pie-chart on the fact page. With some fact values being unique per node,
like ipaddress, uuid, and serial number, as well as structured facts it was like ipaddress, uuid, and serial number, as well as structured facts it was
@@ -241,6 +244,7 @@ Other settings that might be interesting in no particular order:
.. _pypuppetdb documentation: http://pypuppetdb.readthedocs.org/en/v0.1.0/quickstart.html#ssl .. _pypuppetdb documentation: http://pypuppetdb.readthedocs.org/en/v0.1.0/quickstart.html#ssl
.. _Flask documentation: http://flask.pocoo.org/docs/0.10/quickstart/#sessions .. _Flask documentation: http://flask.pocoo.org/docs/0.10/quickstart/#sessions
.. _C3JS_documentation: http://c3js.org/examples.html#chart
Puppet Enterprise Puppet Enterprise
----------------- -----------------

View File

@@ -21,6 +21,7 @@ TABLE_COUNT_SELECTOR = [10, 20, 50, 100, 500]
OFFLINE_MODE = False OFFLINE_MODE = False
ENABLE_CATALOG = False ENABLE_CATALOG = False
OVERVIEW_FILTER = None OVERVIEW_FILTER = None
GRAPH_TYPE = 'pie'
GRAPH_FACTS = ['architecture', GRAPH_FACTS = ['architecture',
'clientversion', 'clientversion',
'domain', 'domain',

View File

@@ -47,6 +47,8 @@ GRAPH_FACTS = [x.strip() for x in os.getenv('GRAPH_FACTS',
GRAPH_FACTS_DEFAULT).split(',')] GRAPH_FACTS_DEFAULT).split(',')]
GRAPH_TYPE = os.getenv('GRAPH_TYPE', 'pie')
# Tuples are hard to express as an environment variable, so here # Tuples are hard to express as an environment variable, so here
# the tupple can be listed as a list of items # the tupple can be listed as a list of items
# export INVENTORY_FACTS="Hostname, fqdn, IP Address, ipaddress,.. etc" # export INVENTORY_FACTS="Hostname, fqdn, IP Address, ipaddress,.. etc"

View File

@@ -1,21 +1,28 @@
$ = jQuery $ = jQuery
$ -> filter_list = (val) ->
$('input.filter-list').parent('div').removeClass('hide') rex = new RegExp(val, "i")
$("input.filter-list").on "keyup", (e) ->
rex = new RegExp($(this).val(), "i")
$(".searchable li").hide() $(".searchable li").hide()
$(".searchable li").parent().parent().hide() $(".searchable li").parent().parent('.list_hide_segment').hide()
$(".searchable li").filter( -> $(".searchable li").filter( ->
rex.test $(this).text() rex.test $(this).text()
).show() ).show()
$(".searchable li").filter( -> $(".searchable li").filter( ->
rex.test $(this).text() rex.test $(this).text()
).parent().parent().show() ).parent().parent().show()
$("input.filter-list").on "keyup", (e) ->
# If key is escape, reset value
if e.keyCode is 27 if e.keyCode is 27
$(e.currentTarget).val "" $(e.currentTarget).val ""
ev = $.Event("keyup") ev = $.Event("keyup")
ev.keyCode = 13 ev.keyCode = 13
$(e.currentTarget).trigger(ev) $(e.currentTarget).trigger(ev)
e.currentTarget.blur() e.currentTarget.blur()
else
filter_list($(this).val())
$("input.filter-list").ready ->
elem = $("input.filter-list")
elem.focus()
val = elem.val()
filter_list(val)
# Force cursor at the end
elem.val('').val(val)

View File

@@ -14,7 +14,7 @@ h1.ui.header.no-margin-bottom {
} }
.ui.grid.padding-bottom { .ui.grid.padding-bottom {
padding-bottom: 40px !important; padding-bottom: 4em !important;
} }
.status { .status {

View File

@@ -0,0 +1,6 @@
/*
A simple, lightweight jQuery plugin for creating sortable tables.
https://github.com/kylefox/jquery-tablesort
Version 0.0.7
*/
!function(t){t.tablesort=function(e,s){var i=this;this.$table=e,this.$thead=this.$table.find("thead"),this.settings=t.extend({},t.tablesort.defaults,s),this.$sortCells=this.$thead.length>0?this.$thead.find("th:not(.no-sort)"):this.$table.find("th:not(.no-sort)"),this.$sortCells.bind("click.tablesort",function(){i.sort(t(this))}),this.index=null,this.$th=null,this.direction=null},t.tablesort.prototype={sort:function(e,s){var i=new Date,n=this,o=this.$table,l=this.$thead.length>0?o.find("tbody tr"):o.find("tr").has("td"),a=o.find("tr td:nth-of-type("+(e.index()+1)+")"),r=e.data().sortBy,d=[],h=a.map(function(s,i){return r?"function"==typeof r?r(t(e),t(i),n):r:null!=t(this).data().sortValue?t(this).data().sortValue:t(this).text()});0!==h.length&&("asc"!==s&&"desc"!==s?this.direction="asc"===this.direction?"desc":"asc":this.direction=s,s="asc"==this.direction?1:-1,n.$table.trigger("tablesort:start",[n]),n.log("Sorting by "+this.index+" "+this.direction),n.$table.css("display"),setTimeout(function(){n.$sortCells.removeClass(n.settings.asc+" "+n.settings.desc);for(var r=0,c=h.length;c>r;r++)d.push({index:r,cell:a[r],row:l[r],value:h[r]});d.sort(function(t,e){return t.value>e.value?1*s:t.value<e.value?-1*s:0}),t.each(d,function(t,e){o.append(e.row)}),e.addClass(n.settings[n.direction]),n.log("Sort finished in "+((new Date).getTime()-i.getTime())+"ms"),n.$table.trigger("tablesort:complete",[n]),n.$table.css("display")},h.length>2e3?200:10))},log:function(e){(t.tablesort.DEBUG||this.settings.debug)&&console&&console.log&&console.log("[tablesort] "+e)},destroy:function(){return this.$sortCells.unbind("click.tablesort"),this.$table.data("tablesort",null),null}},t.tablesort.DEBUG=!1,t.tablesort.defaults={debug:t.tablesort.DEBUG,asc:"sorted ascending",desc:"sorted descending"},t.fn.tablesort=function(e){var s,i;return this.each(function(){s=t(this),i=s.data("tablesort"),i&&i.destroy(),s.data("tablesort",new t.tablesort(s,e))})}}(window.Zepto||window.jQuery);

View File

@@ -1,31 +1,42 @@
// Generated by CoffeeScript 1.9.3 // Generated by CoffeeScript 1.9.3
(function() { (function() {
var $; var $, filter_list;
$ = jQuery; $ = jQuery;
$(function() {}); filter_list = function(val) {
var rex;
$('input.filter-list').parent('div').removeClass('hide'); rex = new RegExp(val, "i");
$("input.filter-list").on("keyup", function(e) {
var ev, rex;
rex = new RegExp($(this).val(), "i");
$(".searchable li").hide(); $(".searchable li").hide();
$(".searchable li").parent().parent().hide(); $(".searchable li").parent().parent('.list_hide_segment').hide();
$(".searchable li").filter(function() { $(".searchable li").filter(function() {
return rex.test($(this).text()); return rex.test($(this).text());
}).show(); }).show();
$(".searchable li").filter(function() { return $(".searchable li").filter(function() {
return rex.test($(this).text()); return rex.test($(this).text());
}).parent().parent().show(); }).parent().parent().show();
};
$("input.filter-list").on("keyup", function(e) {
var ev;
if (e.keyCode === 27) { if (e.keyCode === 27) {
$(e.currentTarget).val(""); $(e.currentTarget).val("");
ev = $.Event("keyup"); ev = $.Event("keyup");
ev.keyCode = 13; ev.keyCode = 13;
$(e.currentTarget).trigger(ev); $(e.currentTarget).trigger(ev);
return e.currentTarget.blur(); return e.currentTarget.blur();
} else {
return filter_list($(this).val());
} }
}); });
$("input.filter-list").ready(function() {
var elem, val;
elem = $("input.filter-list");
elem.focus();
val = elem.val();
filter_list(val);
return elem.val('').val(val);
});
}).call(this); }).call(this);

View File

@@ -0,0 +1,35 @@
// Generated by CoffeeScript 1.4.0
(function() {
var $;
$ = jQuery;
$(function() {});
if ($('th.default-sort').data()) {
$('table.sortable').tablesort().data('tablesort').sort($("th.default-sort"), "desc");
}
$('thead th.date').data('sortBy', function(th, td, tablesort) {
return moment.utc(td.text()).unix();
});
$('input.filter-table').parent('div').removeClass('hide');
$("input.filter-table").on("keyup", function(e) {
var ev, rex;
rex = new RegExp($(this).val(), "i");
$(".searchable tr").hide();
$(".searchable tr").filter(function() {
return rex.test($(this).text());
}).show();
if (e.keyCode === 27) {
$(e.currentTarget).val("");
ev = $.Event("keyup");
ev.keyCode = 13;
$(e.currentTarget).trigger(ev);
return e.currentTarget.blur();
}
});
}).call(this);

View File

@@ -46,39 +46,6 @@
</table> </table>
{%- endmacro %} {%- endmacro %}
{% macro facts_graph(facts, autofocus=False, condensed=False, show_node=False, margin_top=20, margin_bottom=20) -%}
<script src="{{url_for('static', filename='js/d3.min.js')}}"></script>
<script src="{{url_for('static', filename='js/c3.min.js')}}"></script>
<div id="factChart" width="300" height="300"></div>
<script type="text/javascript">
var data = [
{% for fact in facts|groupby('value') %}
{
label: '{{ fact.grouper.replace("\n", " ") }}',
value: {{ fact.list|length }}
},
{% endfor %}
{
value: 0,
}
]
var fact_values = data.map(function(item) { return [item.label, item.value]; }).filter(function(item){return item[0];}).sort(function(a,b){return b[1] - a[1];});
var realdata = fact_values.slice(0, 15);
var otherdata = fact_values.slice(15);
if (otherdata.length > 0) {
realdata.push(["other", otherdata.reduce(function(a,b){return a + b[1];},0)]);
}
var chart = c3.generate({
bindto: '#factChart',
data: {
columns: realdata,
type : 'pie',
}
});
</script>
{%- endmacro %}
{% macro status_counts(caller, status, node_name, events, current_env, unreported_time=False, report_hash=False) -%} {% macro status_counts(caller, status, node_name, events, current_env, unreported_time=False, report_hash=False) -%}
<a class="ui {{status}} label status" href="{{url_for('report', env=current_env, node_name=node_name, report_id=report_hash)}}">{{ status|upper }}</a> <a class="ui {{status}} label status" href="{{url_for('report', env=current_env, node_name=node_name, report_id=report_hash)}}">{{ status|upper }}</a>
{% if status == 'unreported' %} {% if status == 'unreported' %}
@@ -90,7 +57,7 @@
{% endif %} {% endif %}
{%- endmacro %} {%- endmacro %}
{% macro datatable_init(table_html_id, ajax_url, default_length, length_selector, extra_options=None, columns) -%} {% macro datatable_init(table_html_id, ajax_url, default_length, length_selector, extra_options=None) -%}
// Init datatable // Init datatable
$.fn.dataTable.ext.errMode = 'throw'; $.fn.dataTable.ext.errMode = 'throw';
var table = $('#{{ table_html_id }}').DataTable({ var table = $('#{{ table_html_id }}').DataTable({

View File

@@ -1,10 +1,47 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% import '_macros.html' as macros %} {% import '_macros.html' as macros %}
{% block content %}
<h1>{{name}}{% if value %}/{{value}}{% endif %} ({{facts|length}})</h1> {% block javascript %}
{% if render_graph %} {% if render_graph %}
{{macros.facts_graph(facts, autofocus=True, show_node=True, margin_bottom=10)}} var chart = null;
var data = [
{% for fact in facts|groupby('value') %}
{
label: '{{ fact.grouper.replace("\n", " ") }}',
value: {{ fact.list|length }}
},
{% endfor %}
{
value: 0,
}
]
var fact_values = data.map(function(item) { return [item.label, item.value]; }).filter(function(item){return item[0];}).sort(function(a,b){return b[1] - a[1];});
var realdata = fact_values.slice(0, 15);
var otherdata = fact_values.slice(15);
if (otherdata.length > 0) {
realdata.push(["other", otherdata.reduce(function(a,b){return a + b[1];},0)]);
}
{% endif %} {% endif %}
{% endblock javascript %}
{% block onload_script %}
$('table').tablesort();
{% if render_graph %}
chart = c3.generate({
bindto: '#factChart',
data: {
columns: realdata,
type : '{{config.GRAPH_TYPE|default('pie')}}',
}
});
{% endif %}
{% endblock onload_script %}
{% block content %}
<div id="factChart" width="300" height="300"></div>
<h1>{{name}}{% if value %}/{{value}}{% endif %} ({{facts|length}})</h1>
{% if value %} {% if value %}
{{macros.facts_table(facts, current_env=current_env, autofocus=True, show_node=True, show_value=False, margin_bottom=10)}} {{macros.facts_table(facts, current_env=current_env, autofocus=True, show_node=True, show_value=False, margin_bottom=10)}}
{% else %} {% else %}

View File

@@ -1,29 +1,29 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% block content %} {% block content %}
<div class="ui fluid icon input hide" style="margin-bottom:20px"> <div class="ui fluid icon input" style="margin-bottom:20px">
<input autofocus="autofocus" class="filter-list" placeholder="Type here to filter..."> <input autofocus="autofocus" class="filter-list" placeholder="Type here to filter...">
</div> </div>
<div class="ui searchable stackable doubling four column grid factlist"> <div class="ui searchable stackable doubling four column grid factlist">
<div class="column"> <div class="column">
{%- set facts_count = 0 -%} {%- set facts_count = 0 -%}
{%- set break = facts_len//4 + 1 -%} {%- set break = facts_len//4 + 1 -%}
{%- for key,facts_list in facts_dict %} {%- for key,facts_list in facts_dict %}
<div class="ui segment"> <div class="ui list_hide_segment segment">
<a class="ui darkblue ribbon label">{{key}}</a> <a class="ui darkblue ribbon label">{{key}}</a>
<ul> <ul>
{%- for fact in facts_list %} {%- for fact in facts_list %}
<li><a href="{{url_for('fact', env=current_env, fact=fact)}}">{{fact}}</a></li> <li><a href="{{url_for('fact', env=current_env, fact=fact)}}">{{fact}}</a></li>
{%- endfor %} {%- endfor %}
</ul> </ul>
</div> </div>
{%- set facts_count = facts_count + facts_list|length -%} {%- set facts_count = facts_count + facts_list|length -%}
{%- if facts_count >= break -%} {%- if facts_count >= break -%}
</div> </div>
<div class="column"> <div class="column">
{%- set break = facts_len//4 + 1 + break -%} {%- set break = facts_len//4 + 1 + break -%}
{%- endif -%} {%- endif -%}
{%- set facts_count = facts_count + 5 -%} {%- set facts_count = facts_count + 5 -%}
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@@ -12,6 +12,7 @@
{% endblock script %} {% endblock script %}
{% endif %} {% endif %}
{% endblock head %} {% endblock head %}
{% block content %} {% block content %}
{% if config.REFRESH_RATE > 0 %} {% if config.REFRESH_RATE > 0 %}
<meta http-equiv="refresh" content="{{config.REFRESH_RATE}}"> <meta http-equiv="refresh" content="{{config.REFRESH_RATE}}">

View File

@@ -41,14 +41,20 @@
<script src="{{ url_for('static', filename='Semantic-UI-2.1.8/semantic.min.js') }}"></script> <script src="{{ url_for('static', filename='Semantic-UI-2.1.8/semantic.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/lists.js') }}"></script> <script src="{{ url_for('static', filename='js/lists.js') }}"></script>
<script src="{{ url_for('static', filename='js/scroll.top.js') }}"></script> <script src="{{ url_for('static', filename='js/scroll.top.js') }}"></script>
<script src="{{url_for('static', filename='js/d3.min.js')}}"></script>
<script src="{{url_for('static', filename='js/c3.min.js')}}"></script>
<script src="{{url_for('static',
filename='jquery-tablesort-v.0.0.7/jquery.tablesort.min.js')}}"></script>
{% block script %} {% endblock script %}
<script type="text/javascript"> <script type="text/javascript">
{% block javascript %} {% endblock javascript %}
$(document).ready(function(){ $(document).ready(function(){
$(".ui.dropdown").dropdown(); $(".ui.dropdown").dropdown();
$.getScript('{{url_for('static', filename='js/lists.js')}}')
$.getScript('{{url_for('static', filename='js/tables.js')}}')
{% block onload_script %} {% endblock onload_script %} {% block onload_script %} {% endblock onload_script %}
}) })
</script> </script>
{% block script %} {% endblock script %}
{% block head %} {% endblock head %} {% block head %} {% endblock head %}
</head> </head>

View File

@@ -1,7 +1,7 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% block content %} {% block content %}
<h1>Metrics</h1> <h1>Metrics</h1>
<div class="ui fluid icon input hide" style="margin-bottom:20px"> <div class="ui fluid icon input" style="margin-bottom:20px">
<input autofocus="autofocus" class="filter-list" placeholder="Type here to filter..."> <input autofocus="autofocus" class="filter-list" placeholder="Type here to filter...">
</div> </div>
<ul class="ui list searchable"> <ul class="ui list searchable">

View File

@@ -13,7 +13,11 @@
{% endblock script %} {% endblock script %}
{% endblock head %} {% endblock head %}
{% block onload_script %} {% block onload_script %}
{{ macros.datatable_init(table_html_id="reports_table", ajax_url=url_for('reports_ajax', env=current_env, node_name=node.name), default_length=config.LITTLE_TABLE_COUNT, length_selector=config.TABLE_COUNT_SELECTOR, columns=columns) }} {% macro extra_options(caller) %}
'pagingType': 'simple',
"bFilter": false,
{% endmacro %}
{{ macros.datatable_init(table_html_id="reports_table", ajax_url=url_for('reports_ajax', env=current_env, node_name=node.name), default_length=config.LITTLE_TABLE_COUNT, length_selector=config.TABLE_COUNT_SELECTOR, extra_options=extra_options) }}
{% endblock onload_script %} {% endblock onload_script %}
{% block content %} {% block content %}

View File

@@ -33,7 +33,7 @@
// No initial loading // No initial loading
"deferLoading": true, "deferLoading": true,
{% endmacro %} {% endmacro %}
{{ macros.datatable_init(table_html_id="reports_table", ajax_url=url_for('reports_ajax', env=current_env, node_name=node_name), default_length=config.NORMAL_TABLE_COUNT, length_selector=config.TABLE_COUNT_SELECTOR, extra_options=extra_options, columns=columns) }} {{ macros.datatable_init(table_html_id="reports_table", ajax_url=url_for('reports_ajax', env=current_env, node_name=node_name), default_length=config.NORMAL_TABLE_COUNT, length_selector=config.TABLE_COUNT_SELECTOR, extra_options=extra_options) }}
// Event listener for status filters // Event listener for status filters
function status_filter_change(){ function status_filter_change(){