Revamp fact pages and tables to datatables
This commit is contained in:
@@ -412,11 +412,10 @@ def node(env, node_name):
|
|||||||
query.add(EqualsOperator("certname", node_name))
|
query.add(EqualsOperator("certname", node_name))
|
||||||
|
|
||||||
node = get_or_abort(puppetdb.node, node_name)
|
node = get_or_abort(puppetdb.node, node_name)
|
||||||
facts = node.facts()
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'node.html',
|
'node.html',
|
||||||
node=node,
|
node=node,
|
||||||
facts=yield_or_stop(facts),
|
|
||||||
envs=envs,
|
envs=envs,
|
||||||
current_env=env,
|
current_env=env,
|
||||||
columns=REPORTS_COLUMNS[:2])
|
columns=REPORTS_COLUMNS[:2])
|
||||||
@@ -661,73 +660,102 @@ def facts(env):
|
|||||||
current_env=env)
|
current_env=env)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/fact/<fact>', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
@app.route('/fact/<fact>',
|
||||||
@app.route('/<env>/fact/<fact>')
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT'], 'value': None})
|
||||||
def fact(env, fact):
|
@app.route('/<env>/fact/<fact>', defaults={'value': None})
|
||||||
"""Fetches the specific fact from PuppetDB and displays its value per
|
@app.route('/fact/<fact>/<value>',
|
||||||
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
|
@app.route('/<env>/fact/<fact>/<value>')
|
||||||
|
def fact(env, fact, value):
|
||||||
|
"""Fetches the specific fact(/value) from PuppetDB and displays per
|
||||||
node for which this fact is known.
|
node for which this fact is known.
|
||||||
|
|
||||||
:param env: Searches for facts in this environment
|
:param env: Searches for facts in this environment
|
||||||
:type env: :obj:`string`
|
:type env: :obj:`string`
|
||||||
:param fact: Find all facts with this name
|
:param fact: Find all facts with this name
|
||||||
:type fact: :obj:`string`
|
:type fact: :obj:`string`
|
||||||
|
:param fact: Find all facts with this value
|
||||||
|
:type fact: :obj:`string`
|
||||||
"""
|
"""
|
||||||
envs = environments()
|
envs = environments()
|
||||||
check_env(env, envs)
|
check_env(env, envs)
|
||||||
|
|
||||||
# we can only consume the generator once, lists can be doubly consumed
|
|
||||||
# om nom nom
|
|
||||||
render_graph = False
|
render_graph = False
|
||||||
if fact in graph_facts:
|
if fact in graph_facts and not value:
|
||||||
render_graph = True
|
render_graph = True
|
||||||
|
|
||||||
if env == '*':
|
return render_template(
|
||||||
query = None
|
|
||||||
else:
|
|
||||||
query = EqualsOperator("environment", env)
|
|
||||||
|
|
||||||
localfacts = [f for f in yield_or_stop(puppetdb.facts(
|
|
||||||
name=fact, query=query))]
|
|
||||||
return Response(stream_with_context(stream_template(
|
|
||||||
'fact.html',
|
'fact.html',
|
||||||
name=fact,
|
fact=fact,
|
||||||
|
value=value,
|
||||||
render_graph=render_graph,
|
render_graph=render_graph,
|
||||||
facts=localfacts,
|
|
||||||
envs=envs,
|
envs=envs,
|
||||||
current_env=env)))
|
current_env=env)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/fact/<fact>/<value>',
|
@app.route('/fact/<fact>/json',
|
||||||
defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT'],
|
||||||
@app.route('/<env>/fact/<fact>/<value>')
|
'node': None, 'value': None})
|
||||||
def fact_value(env, fact, value):
|
@app.route('/<env>/fact/<fact>/json', defaults={'node': None, 'value': None})
|
||||||
"""On asking for fact/value get all nodes with that fact.
|
@app.route('/fact/<fact>/<value>/json',
|
||||||
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT'], 'node': None})
|
||||||
|
@app.route('/<env>/fact/<fact>/<value>/json', defaults={'node': None})
|
||||||
|
@app.route('/node/<node>/facts/json',
|
||||||
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT'],
|
||||||
|
'fact': None, 'value': None})
|
||||||
|
@app.route('/<env>/node/<node>/facts/json',
|
||||||
|
defaults={'fact': None, 'value': None})
|
||||||
|
def fact_ajax(env, node, fact, value):
|
||||||
|
"""Fetches the specific facts matching (node/fact/value) from PuppetDB and
|
||||||
|
return a JSON table
|
||||||
|
|
||||||
:param env: Searches for facts in this environment
|
:param env: Searches for facts in this environment
|
||||||
:type env: :obj:`string`
|
:type env: :obj:`string`
|
||||||
|
:param fact: Find all facts for this node
|
||||||
|
:type fact: :obj:`string`
|
||||||
:param fact: Find all facts with this name
|
:param fact: Find all facts with this name
|
||||||
:type fact: :obj:`string`
|
:type fact: :obj:`string`
|
||||||
:param value: Filter facts whose value is equal to this
|
:param fact: Find all facts with this value
|
||||||
:type value: :obj:`string`
|
:type fact: :obj:`string`
|
||||||
"""
|
"""
|
||||||
|
draw = int(request.args.get('draw', 0))
|
||||||
|
|
||||||
envs = environments()
|
envs = environments()
|
||||||
check_env(env, envs)
|
check_env(env, envs)
|
||||||
|
|
||||||
if env == '*':
|
render_graph = False
|
||||||
query = None
|
if fact in graph_facts and not value and not node:
|
||||||
else:
|
render_graph = True
|
||||||
query = EqualsOperator("environment", env)
|
|
||||||
|
|
||||||
facts = get_or_abort(puppetdb.facts,
|
query = AndOperator()
|
||||||
|
if node:
|
||||||
|
query.add(EqualsOperator("certname", node))
|
||||||
|
|
||||||
|
if env != '*':
|
||||||
|
query.add(EqualsOperator("environment", env))
|
||||||
|
|
||||||
|
if len(query.operations) == 0:
|
||||||
|
query = None
|
||||||
|
|
||||||
|
# Generator needs to be converted (graph / total)
|
||||||
|
facts = [f for f in get_or_abort(
|
||||||
|
puppetdb.facts,
|
||||||
name=fact,
|
name=fact,
|
||||||
value=value,
|
value=value,
|
||||||
query=query)
|
query=query)]
|
||||||
localfacts = [f for f in yield_or_stop(facts)]
|
|
||||||
|
total = len(facts)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'fact.html',
|
'fact.json.tpl',
|
||||||
name=fact,
|
fact=fact,
|
||||||
|
node=node,
|
||||||
value=value,
|
value=value,
|
||||||
facts=localfacts,
|
draw=draw,
|
||||||
|
total=total,
|
||||||
|
total_filtered=total,
|
||||||
|
render_graph=render_graph,
|
||||||
|
facts=facts,
|
||||||
envs=envs,
|
envs=envs,
|
||||||
current_env=env)
|
current_env=env)
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,8 @@
|
|||||||
// Paging options
|
// Paging options
|
||||||
"lengthMenu": {{ length_selector }},
|
"lengthMenu": {{ length_selector }},
|
||||||
"pageLength": {{ default_length }},
|
"pageLength": {{ default_length }},
|
||||||
|
// Search as regex (does not apply if serverSide)
|
||||||
|
"search": {"regex": true},
|
||||||
// Default sort
|
// Default sort
|
||||||
"order": [[ 0, "desc" ]],
|
"order": [[ 0, "desc" ]],
|
||||||
// Custom options
|
// Custom options
|
||||||
|
|||||||
@@ -1,50 +1,45 @@
|
|||||||
{% extends 'layout.html' %}
|
{% extends 'layout.html' %}
|
||||||
{% import '_macros.html' as macros %}
|
{% import '_macros.html' as macros %}
|
||||||
|
|
||||||
{% block javascript %}
|
{% block onload_script %}
|
||||||
|
{% macro extra_options(caller) %}
|
||||||
|
// No per page AJAX
|
||||||
|
'serverSide': false,
|
||||||
|
{% endmacro %}
|
||||||
|
{{ macros.datatable_init(table_html_id="facts_table", ajax_url=url_for('fact_ajax', env=current_env, fact=fact, value=value), default_length=config.NORMAL_TABLE_COUNT, length_selector=config.TABLE_COUNT_SELECTOR, extra_options=extra_options) }}
|
||||||
|
|
||||||
{% if render_graph %}
|
{% if render_graph %}
|
||||||
var chart = null;
|
table.on('xhr', function(e, settings, json){
|
||||||
var data = [
|
var fact_values = json['chart'].map(function(item) { return [item.label, item.value]; }).filter(function(item){return item[0];}).sort(function(a,b){return b[1] - a[1];});
|
||||||
{% 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 realdata = fact_values.slice(0, 15);
|
||||||
var otherdata = fact_values.slice(15);
|
var otherdata = fact_values.slice(15);
|
||||||
if (otherdata.length > 0) {
|
if (otherdata.length > 0) {
|
||||||
realdata.push(["other", otherdata.reduce(function(a,b){return a + b[1];},0)]);
|
realdata.push(["other", otherdata.reduce(function(a,b){return a + b[1];},0)]);
|
||||||
}
|
}
|
||||||
{% endif %}
|
c3.generate({
|
||||||
{% endblock javascript %}
|
|
||||||
|
|
||||||
{% block onload_script %}
|
|
||||||
$('table').tablesort();
|
|
||||||
{% if render_graph %}
|
|
||||||
chart = c3.generate({
|
|
||||||
bindto: '#factChart',
|
bindto: '#factChart',
|
||||||
data: {
|
data: {
|
||||||
columns: realdata,
|
columns: realdata,
|
||||||
type : '{{config.GRAPH_TYPE|default('pie')}}',
|
type : '{{config.GRAPH_TYPE|default('pie')}}',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock onload_script %}
|
{% endblock onload_script %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% if render_graph %}
|
||||||
<div id="factChart" width="300" height="300"></div>
|
<div id="factChart" width="300" height="300"></div>
|
||||||
<h1>{{name}}{% if value %}/{{value}}{% endif %} ({{facts|length}})</h1>
|
|
||||||
|
|
||||||
|
|
||||||
{% if value %}
|
|
||||||
{{macros.facts_table(facts, current_env=current_env, autofocus=True, show_node=True, show_value=False, margin_bottom=10)}}
|
|
||||||
{% else %}
|
|
||||||
{{macros.facts_table(facts, current_env=current_env, autofocus=True, show_node=True, link_facts=True, margin_bottom=10)}}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<h1>{{ fact }}{% if value %}/{{ value }}{% endif %}</h1>
|
||||||
|
<table id="facts_table" class='ui fixed very basic compact table stackable'>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Node</th>
|
||||||
|
{% if not value %}<th>Value</th>{% endif %}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
38
puppetboard/templates/fact.json.tpl
Normal file
38
puppetboard/templates/fact.json.tpl
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"draw": {{draw}},
|
||||||
|
"recordsTotal": {{total}},
|
||||||
|
"recordsFiltered": {{total_filtered}},
|
||||||
|
"data": [
|
||||||
|
{% for fact_h in facts -%}
|
||||||
|
{%- if not loop.first %},{%- endif -%}
|
||||||
|
[
|
||||||
|
{%- if not fact -%}
|
||||||
|
{{ fact_h.name | jsonprint }}
|
||||||
|
{%- if node or value %},{% endif -%}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- if not node -%}
|
||||||
|
{% filter jsonprint %}<a href="{{ url_for('node', env=current_env, node_name=fact_h.node) }}">{{ fact_h.node }}</a>{% endfilter %}
|
||||||
|
{%- if not value %},{% endif -%}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- if not value -%}
|
||||||
|
{%- if fact_h.value is mapping -%}
|
||||||
|
{% filter jsonprint %}<a href="{{ url_for('fact', env=current_env, fact=fact_h.name, value=fact_h.value) }}"><pre>{{ fact_h.value | jsonprint }}</pre></a>{% endfilter %}
|
||||||
|
{%- else -%}
|
||||||
|
{% filter jsonprint %}<a href="{{ url_for('fact', env=current_env, fact=fact_h.name, value=fact_h.value) }}"><pre>{{ fact_h.value }}</pre></a>{% endfilter %}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endif -%}
|
||||||
|
]
|
||||||
|
{% endfor -%}
|
||||||
|
]
|
||||||
|
{%- if render_graph %},
|
||||||
|
"chart": [
|
||||||
|
{% for fact_h in facts | groupby('value') -%}
|
||||||
|
{%- if not loop.first %},{%- endif -%}
|
||||||
|
{
|
||||||
|
"label": {{ fact_h.grouper.replace("\n", " ") | jsonprint }},
|
||||||
|
"value": {{ fact_h.list|length }}
|
||||||
|
}
|
||||||
|
{% endfor %}
|
||||||
|
]
|
||||||
|
{% endif %}
|
||||||
|
}
|
||||||
@@ -17,7 +17,13 @@
|
|||||||
'pagingType': 'simple',
|
'pagingType': 'simple',
|
||||||
"bFilter": false,
|
"bFilter": false,
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
{% macro facts_extra_options(caller) %}
|
||||||
|
'paging': false,
|
||||||
|
// No per page AJAX
|
||||||
|
'serverSide': 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) }}
|
{{ 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) }}
|
||||||
|
{{ macros.datatable_init(table_html_id="facts_table", ajax_url=url_for('fact_ajax', env=current_env, node=node.name), default_length=config.LITTLE_TABLE_COUNT, length_selector=config.TABLE_COUNT_SELECTOR, extra_options=facts_extra_options) }}
|
||||||
{% endblock onload_script %}
|
{% endblock onload_script %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@@ -69,7 +75,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class='column'>
|
<div class='column'>
|
||||||
<h1>Facts</h1>
|
<h1>Facts</h1>
|
||||||
{{macros.facts_table(facts, link_facts=True, condensed=True, current_env=current_env)}}
|
<table id="facts_table" class='ui fixed very basic very compact table stackable'>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
Reference in New Issue
Block a user