- Add "muncollapse" template (the template formerly known as munstrap4).

Lots of changes:

 * Fix the README
 * Add a makefile to fetch bootstrap, lazyload, jquery, the munin logo, and the munin favicon
 * Mostly re-write dynazoom.  It works very much like the stock one now, with a few extra quick buttons, and of course the bootstrap styling
 * Remove all minified versions of scripts / css - The includes are minimal, it was not much of cost savings
 * Add sample images
 * Rename template to "muncollapse"
This commit is contained in:
JTSage 2020-04-15 22:29:49 -04:00
parent bc2dc914b3
commit 12ded312fc
45 changed files with 852 additions and 1147 deletions

6
templates/muncollapse/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
static/img/
static/css/bootstrap.min.css
static/js/bootstrap.min.js
static/js/jquery.min.js
static/js/lazysizes.min.js
static/js/typeahead.bundle.min.js

View File

@ -0,0 +1,54 @@
# MunCollapsible
#
# Makefile for the MunCollapsible template.
# HTTP Fetch program to use. Called as $(HTTP_FETCH) <output_file> <input_url>
#
# Swap the comments to use curl instead.
HTTP_FETCH = wget -nv -O
#HTTP_FETCH = curl -s -w "%{http_code} - %{filename_effective} - %{size_download} bytes\n" -o
# The versions of the external libraries to use.
BOOTSTRAP_VERSION = 4.4.1
JQUERY_VERSION = 3.4.1.slim
TYPEAHEAD_VERSION = latest
FAVICON_FILES := android-chrome-144x144.png android-chrome-192x192.png android-chrome-36x36.png android-chrome-48x48.png android-chrome-72x72.png android-chrome-96x96.png apple-touch-icon-114x114.png apple-touch-icon-120x120.png apple-touch-icon-144x144.png apple-touch-icon-152x152.png apple-touch-icon-180x180.png apple-touch-icon-57x57.png apple-touch-icon-60x60.png apple-touch-icon-72x72.png apple-touch-icon-76x76.png apple-touch-icon-precomposed.png apple-touch-icon.png browserconfig.xml favicon-16x16.png favicon-194x194.png favicon-32x32.png favicon-96x96.png favicon.ico manifest.json mstile-144x144.png mstile-150x150.png mstile-310x150.png mstile-310x310.png mstile-70x70.png
FAVICON_BASEURL = https://raw.githubusercontent.com/munin-monitoring/munin/master/web/static/img/favicons/
LOGO_URL = https://raw.githubusercontent.com/munin-monitoring/munin/master/web/static/img/logo-h.png
BOOTSTRAP_CSS_URL = https://stackpath.bootstrapcdn.com/bootstrap/$(BOOTSTRAP_VERSION)/css/bootstrap.min.css
BOOTSTRAP_JS_URL = https://stackpath.bootstrapcdn.com/bootstrap/$(BOOTSTRAP_VERSION)/js/bootstrap.bundle.min.js
JQUERY_JS_URL = https://code.jquery.com/jquery-$(JQUERY_VERSION).min.js
TYPEAHEAD_JS_URL = https://twitter.github.io/typeahead.js/releases/$(TYPEAHEAD_VERSION)/typeahead.bundle.js
LAZYSIZES_URL = http://afarkas.github.io/lazysizes/lazysizes.min.js
CWD := $(abspath $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))))
main:
@echo $(CWD)
@echo Downloading External Libraries...
$(HTTP_FETCH) $(CWD)/static/css/bootstrap.min.css $(BOOTSTRAP_CSS_URL)
$(HTTP_FETCH) $(CWD)/static/js/bootstrap.min.js $(BOOTSTRAP_JS_URL)
$(HTTP_FETCH) $(CWD)/static/js/jquery.min.js $(JQUERY_JS_URL)
$(HTTP_FETCH) $(CWD)/static/js/typeahead.bundle.min.js $(TYPEAHEAD_JS_URL)
$(HTTP_FETCH) $(CWD)/static/js/lazysizes.min.js $(LAZYSIZES_URL)
@echo Downloading Logo...
@mkdir -p $(CWD)/static/img
$(HTTP_FETCH) $(CWD)/static/img/logo-munin.png $(LOGO_URL)
@echo Downloading Favicon Files...
@mkdir -p $(CWD)/static/img/favicon
@for file in ${FAVICON_FILES}; do \
eval $(HTTP_FETCH) $(CWD)/static/img/favicon/$${file} $(FAVICON_BASEURL)$${file}; \
done

View File

@ -0,0 +1,133 @@
# MunCollapse
Alternative Munin 2.x templates based on Twitter Bootstrap using collapsibles.
Based on some of the work of "Munstrap" by [Jonny McCullagh](https://github.com/jonnymccullagh), [munin-monitoring/contrib](https://github.com/munin-monitoring/contrib/tree/master/templates/munstrap) repo.
#### Overview Sample Image
<a href="sample-image/sample-home.png"><img src="sample-image/sample-home.png" style="max-width: 1229px; display:block; margin-left: auto; margin-right: auto; width: 75%" /></a>
[Semi-Live Demo](https://jtsage.dev/munin-demo/) - For the purposes of this demo only, the data is static and the zoom functionality is disabled.
---
## Installation
### 1. Clone the munin-monitoring/contrib repo to a temporary location:
```
$ cd /opt
$ git clone https://github.com/munin-monitoring/contrib.git
```
### 2. Fetch the template libraries
```
$ cd /opt/contrib/templates/muncollapse/
$ make
```
### 3. Place the template in an appropriate safe place
Ubuntu shown - other distros may prefer ```/usr/local/share/munin/...```
```
$ mkdir /usr/share/munin/template
$ mkdir /usr/share/munin/template/muncollapse
```
__NOTE__: If this step fails, your munin installation may use ```/usr/local/share/munin/...``` instead!
```
$ cp -r /opt/contrib/templates/muncollapse/templates /usr/share/munin/template/muncollapse/
$ cp -r /opt/contrib/templates/muncollapse/static /usr/share/munin/template/muncollapse/
```
### 4. Edit your ```munin.conf``` file.
Typically located at ```/etc/munin.conf```
__FIND AND CHANGE:__ (near the top of the file)
```
# Where to look for the HTML templates
#
#tmpldir /etc/munin/templates
# Where to look for the static www files
#
#staticdir /etc/munin/static
```
__TO:__
```
# Where to look for the HTML templates
#
tmpldir /usr/share/munin/template/muncollapse/templates
# Where to look for the static www files
#
staticdir /usr/share/munin/template/muncollapse/static
```
### 5. [Optional / Recommended] Clean out the old generated files.
This isn't really required, but there will likely be orphaned files. The location of these files can be found in your ```munin.conf``` file, with the ```htmldir``` directive.
__NOTE:__ Ubuntu shown, other distributions may be in ```/var/www/munin/```
```
$ rm -rf /var/cache/munin/www/*
```
### 6. Wait Patiently
```munin-update``` will regenerate the files the next time it runs. By default, this is on the :05 minute tick for most installations. If you do not have new files within 10 minutes, be sure to check ```munin-update.log``` and find out what went wrong.
---
## Revert to Official Munin Template
### 1. Edit your ```munin.conf``` file.
Typically located at ```/etc/munin.conf```
__FIND AND CHANGE:__ (near the top of the file - comment these lines out!)
# Where to look for the HTML templates
#
#tmpldir /usr/share/munin/template/muncollapse/templates
# Where to look for the static www files
#
#staticdir /usr/share/munin/template/muncollapse/static
### 2. [Optional / Recommended] Clean up
Remove the files from step #1 & #3 above, and repeat step #5 & #6.
---
## Samples
#### View of a group:
<a href="sample-image/sample-group.png"><img src="sample-image/sample-group.png" style="max-width: 1229px; display:block; margin-left: auto; margin-right: auto; width: 75%" /></a>
#### View of a specific node:
<a href="sample-image/sample-node.png"><img src="sample-image/sample-node.png" style="max-width: 1229px; display:block; margin-left: auto; margin-right: auto; width: 75%" /></a>
#### Zoom feature:
<a href="sample-image/sample-zoom.png"><img src="sample-image/sample-zoom.png" style="max-width: 1229px; display:block; margin-left: auto; margin-right: auto; width: 75%" /></a>
---
## Munin Compatibility
a/n: I am unsure of the compatibility with Munin 3. Most things will work from what I've read, but the navigation may be slightly funky.
---
### Browser Compatibility
For this template set, Internet Explorer support has been dropped for the dynamic zoom functions. Everything else should work across all browsers.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

View File

@ -18,7 +18,7 @@ div.service-alert {
}
img#zoom_image {
margin-bottom: 15px;
border: none;
}
ul.groupview, ul.groupview ul {
@ -27,11 +27,9 @@ ul.groupview, ul.groupview ul {
.munin-icon {
background: url(../img/logo-munin.png) left top;
margin-top: -6px;
width: 35px;
height: 35px;
width: 115px;
height: 30px;
display: block;
float: left;
}

View File

@ -0,0 +1,239 @@
/* MunCollapse Template DynaZoom JavaScript File
*
* Notes:
*
* - No Internet Explorer support (uses "URLSearchParams")
* - This is not even really a fork of the upstream version any more
* - Drops upstream requirement of "QueryString" include (URL.URLSearchParams)
* - Drops upstream requirement of "FormatDate" include (Date.toISOString())
*/
URLSearchParams.prototype.getDefault = function ( name, value ) {
// Overload URLSearchParams to allow "default" values.
return ( this.get( name ) === null ) ? value : this.get( name );
};
function refreshZoom( query, form, image ) {
//INIT
var qs = new URLSearchParams( query.split( "\?" )[ 1 ] );
init();
refreshImg();
var start_epoch = parseInt( qs.getDefault( "rst_start_epoch", form.start_epoch.value ), 10 );
var stop_epoch = parseInt( qs.getDefault( "rst_stop_epoch", form.stop_epoch.value ), 10 );
var highLighter = document.getElementById( "image-overlay" );
var gutterOffsetLeft = 66;
var highlightStartX = 0;
var clickCounter = 0;
var relativeStartX = 0;
var graph_shown_width;
var epoch_shown_start;
var epoch_shown_stop;
var eachPixelEpoch;
form.plugin_name.onblur = refreshImg;
form.start_iso8601.onblur = majDates;
form.stop_iso8601.onblur = majDates;
form.start_epoch.onblur = function() { refreshImg(); updateStartStop(); };
form.stop_epoch.onblur = function() { refreshImg(); updateStartStop(); };
form.lower_limit.onblur = refreshImg;
form.upper_limit.onblur = refreshImg;
form.size_x.onblur = refreshImg;
form.size_y.onblur = refreshImg;
form.btnReset.onclick = reset;
form.btnShowDay.onclick = function() { showPeriod( 1 ); };
form.btnShowWeek.onclick = function() { showPeriod( 2 ); };
form.btnShowMonth.onclick = function() { showPeriod( 3 ); };
form.btnShowYear.onclick = function() { showPeriod( 4 ); };
form.onsubmit = function() { document.activeElement.blur(); refreshImg(); return false; };
// Sets the onClick handler
image.onclick = click;
//FUNCTIONS
function init() {
form.plugin_name.value = qs.getDefault( "plugin_name", "localdomain/localhost.localdomain/if_eth0" );
form.start_epoch.value = qs.getDefault( "start_epoch", "1236561663" );
form.stop_epoch.value = qs.getDefault( "stop_epoch", "1237561663" );
form.lower_limit.value = qs.getDefault( "lower_limit", "" );
form.upper_limit.value = qs.getDefault( "upper_limit", "" );
form.size_x.value = qs.getDefault( "size_x", "" );
form.size_y.value = qs.getDefault( "size_y", "" );
updateStartStop();
}
function reset( event ) {
init();
//Can be not the initial ones in case of manual refresh
form.start_epoch.value = start_epoch;
form.stop_epoch.value = stop_epoch;
updateStartStop();
//Redraw
scale = refreshImg();
//Reset gui
clickCounter = 0;
image.onmousemove = undefined;
form.start_iso8601.disabled = false;
form.stop_iso8601.disabled = false;
form.start_epoch.disabled = false;
form.stop_epoch.disabled = false;
highLighter.style.left = "0px";
highLighter.style.width = "2px";
highLighter.style.display = "none";
document.activeElement.blur();
return false;
}
function refreshImg(event) {
image.src = qs.getDefault( "cgiurl_graph", "/munin-cgi/munin-cgi-graph" ) + "/" +
form.plugin_name.value +
"-pinpoint=" + parseInt( form.start_epoch.value, 10 ) + "," + parseInt( form.stop_epoch.value, 10 ) +
".png" + "?" +
"&lower_limit=" + form.lower_limit.value +
"&upper_limit=" + form.upper_limit.value +
"&size_x=" + form.size_x.value +
"&size_y=" + form.size_y.value;
}
function updateStartStop() {
form.start_iso8601.value = new Date( form.start_epoch.value * 1000 ).toISOString();
form.stop_iso8601.value = new Date( form.stop_epoch.value * 1000 ).toISOString();
}
function majDates( event ) {
var lowLimit = new Date(),
topLimit = new Date(),
date_parsed = null;
lowLimit.setFullYear( lowLimit.getFullYear() - 1 );
date_parsed = new Date( Date.parse( form.start_iso8601.value ) || lowLimit.getTime() );
form.start_epoch.value = Math.floor( date_parsed.getTime() / 1000 );
date_parsed = new Date( Date.parse( form.stop_iso8601.value) || topLimit.getTime() );
form.stop_epoch.value = Math.floor( date_parsed.getTime() / 1000 );
updateStartStop();
refreshImg();
}
function click( event ) {
var relativeClickX = getClickLocation( event ),
thisEpoch = null;
switch ( ( clickCounter++ ) % 3 ) {
case 0: // First click of the displayed graph
graph_shown_width = parseInt( form.size_x.value, 10) ;
epoch_shown_start = parseInt( form.start_epoch.value,10 );
epoch_shown_stop = parseInt( form.stop_epoch.value, 10 );
eachPixelEpoch = ( ( epoch_shown_stop - epoch_shown_start ) / graph_shown_width );
relativeStartX = ( relativeClickX < 0 ? 0 : relativeClickX );
form.start_iso8601.disabled = true;
form.stop_iso8601.disabled = true;
form.start_epoch.disabled = true;
form.stop_epoch.disabled = true;
highlightStartX = event.pageX;
highLighter.style.left = ( relativeStartX + gutterOffsetLeft + image.offsetLeft ) + "px";
highLighter.style.display = "block";
form.start_epoch.value = offsetEpoch( relativeClickX );
updateStartStop();
image.onmousemove = divMouseMove;
break;
case 1: // Second (end) click of the displayed graph
thisEpoch = offsetEpoch( relativeClickX );
image.onmousemove = undefined;
form.start_iso8601.disabled = false;
form.stop_iso8601.disabled = false;
form.start_epoch.disabled = false;
form.stop_epoch.disabled = false;
// For negative values, assume we want a new start point and the old end point.
// If it's not, set it.
if ( thisEpoch > form.start_epoch.value ) {
form.stop_epoch.value = thisEpoch;
} else {
form.stop_epoch.value = Math.floor( epoch_shown_stop );
highLighter.style.width = ( graph_shown_width - relativeStartX ) + "px";
}
updateStartStop();
break;
case 2: // Nevermind or Do It.
thisEpoch = offsetEpoch( relativeClickX );
if ( thisEpoch >= form.start_epoch.value && thisEpoch <= form.stop_epoch.value ) {
refreshImg();
} else {
form.start_epoch.value = epoch_shown_start;
form.stop_epoch.value = epoch_shown_stop;
updateStartStop();
}
highLighter.style.left = "0px";
highLighter.style.width = "2px";
highLighter.style.display = "none";
}
}
function divMouseMove( event ) {
var diff = event.pageX - highlightStartX,
maxDiff = graph_shown_width - relativeStartX,
relativeClickX = getClickLocation( event );
form.stop_epoch.value = offsetEpoch( relativeClickX );
updateStartStop();
highLighter.style.width = ( ( diff < 2 ) ? 2 : ( diff > maxDiff ? maxDiff : diff ) ) + "px";
}
function offsetEpoch( clickX ) {
if ( clickX < 0 ) { return Math.floor( epoch_shown_start ); }
if ( clickX > graph_shown_width ) { return Math.floor( epoch_shown_stop ); }
return Math.floor( epoch_shown_start + ( clickX * eachPixelEpoch ) );
}
function getClickLocation( event ) {
return ( event.pageX - image.getBoundingClientRect().x - gutterOffsetLeft );
}
function showPeriod( period ) {
var now = new Date(),
past = new Date();
switch (period) {
case 1:
past.setDate( past.getDate() - 1 ); break;
case 2:
past.setDate( past.getDate() - 7 ); break;
case 3:
past.setMonth( past.getMonth() - 1 ); break;
case 4:
past.setFullYear( past.getFullYear() - 1 ); break;
}
form.start_epoch.value = Math.floor( past.getTime() / 1000 );
form.stop_epoch.value = Math.floor( now.getTime() / 1000 );
updateStartStop();
refreshImg();
document.activeElement.blur();
return false;
}
}

View File

@ -1,9 +1,5 @@
<TMPL_INCLUDE NAME="partial/head.tmpl" />
<h2 class="mb-3">Comparison: by day</h2>
<TMPL_INCLUDE NAME="partial/compare_navigation.tmpl" />
<!--
File: munin-comparison-day.tmpl

View File

@ -1,9 +1,5 @@
<TMPL_INCLUDE NAME="partial/head.tmpl" />
<h2 class="mb-3">Comparison: by month</h2>
<TMPL_INCLUDE NAME="partial/compare_navigation.tmpl" />
<!--
File: munin-comparison-monthy.tmpl

View File

@ -1,9 +1,5 @@
<TMPL_INCLUDE NAME="partial/head.tmpl" />
<h2 class="mb-3">Comparison: by week</h2>
<TMPL_INCLUDE NAME="partial/compare_navigation.tmpl" />
<!--
File: munin-comparison-week.tmpl

View File

@ -1,9 +1,5 @@
<TMPL_INCLUDE NAME="partial/head.tmpl" />
<h2 class="mb-3">Comparison: by year</h2>
<TMPL_INCLUDE NAME="partial/compare_navigation.tmpl" />
<!--
File: munin-comparison-year.tmpl

View File

@ -7,20 +7,20 @@
-->
<script>
$(document).ready(function() {
$('.custom-collapse').on('click', function() {
$(this).parent().find('.collapse').collapse('toggle');
$( document ).ready( function() {
$( ".custom-collapse" ).on( "click", function() {
$( this ).parent().find( ".collapse" ).collapse( "toggle" );
return false;
});
$('.custom-collapse-all').on('click', function() {
if ( $(this).hasClass('all-hide') ) {
$(this).parent().parent().find('.collapse').collapse('hide');
} );
$( ".custom-collapse-all" ).on( "click", function() {
if ( $( this ).hasClass( "all-hide" ) ) {
$( this ).parent().parent().find( ".collapse" ).collapse( "hide" );
} else {
$(this).parent().parent().find('.collapse').collapse('show');
$( this ).parent().parent().find( ".collapse" ).collapse( "show" );
}
return false;
});
});
} );
} );
</script>
<div class="btn-group w-100 mb-3">

View File

@ -13,84 +13,77 @@
</div>
<script>
$(document).ready(function (){
$( document ).ready( function () {
// Should we auto-scroll when a service category is opened?
window.doScroll = false;
// Store display status of graph periods
window.gsets = {
window.gsets = {
"day" : true,
"week" : true,
"month" : false,
"year" : false
};
$('.graph-click').on('click', function(){
$( ".graph-click" ).on( "click", function() {
// This shows / hides graph periods.
var gset = $(this).data("gset");
var newState = ! gsets[gset];
gsets[gset] = newState;
$(this)
.toggleClass("btn-outline-success btn-outline-secondary")
.find(".gset-state")
.text((newState ? "Shown" : "Hidden"));
$('.graph-' + gset).toggleClass("d-none");
return false;
});
$('.tab-click').on('click', function() {
window.doScroll = true; // Do scroll when we click a tab header
var theCollapse = '#' + $(this).data("target") + "_coll";
var gset = $( this ).data( "gset" ),
newState = ! gsets[ gset ];
if ( $(theCollapse).hasClass('show') ) {
gsets[ gset ] = newState;
$(this)
.toggleClass( "btn-outline-success btn-outline-secondary" )
.find( ".gset-state" )
.text( ( newState ? "Shown" : "Hidden" ) );
$( ".graph-" + gset ).toggleClass( "d-none" );
return false;
} );
$( ".tab-click" ).on( "click", function() {
var theCollapse = $( "#" + $( this ).data( "target" ) + "_coll" );
window.doScroll = true; // Do scroll when we click a tab header
if ( theCollapse.hasClass( "show" ) ) {
// Already open, lets just trigger the event.
$(theCollapse).trigger('shown.bs.collapse');
theCollapse.trigger( "shown.bs.collapse" );
} else {
// Close all
$(".card-collapse.collapse").collapse("hide");
// Open the one we want
$(theCollapse).collapse('show');
// Close all and open the one we want
$( ".card-collapse.collapse" ).collapse( "hide" );
theCollapse.collapse( "show" );
}
// Do nothing with the click otherwise.
return false;
});
} );
// Actual scroll function
$('.collapse').on('shown.bs.collapse', function(e) {
$( ".collapse" ).on( "shown.bs.collapse", function( e ) {
if ( window.doScroll ) {
var $card = $(this).closest('.card');
$('html,body').animate({
scrollTop: $card.offset().top
}, 500);
$( document ).scrollTop( $( this ).closest( ".card" ).offset().top );
window.doScroll = false;
}
});
} );
// If we came here with a hash, open that category and scroll to it.
if ( location.hash != "" ) {
window.doScroll = true;
$(location.hash + "_coll" + '.collapse').collapse('show');
$( location.hash + "_coll" + ".collapse" ).collapse( "show" );
}
// Alternatively, if something changed the hash (looking at you search feature), we should
// pretend that the user clicked on the link for that category.
$( window ).on( 'hashchange', function( e ) {
$( window ).on( "hashchange", function( e ) {
var newPlace = window.location.hash.substr(1);;
$(".tab-click[data-target='" + newPlace + "']").trigger("click");
$( ".tab-click[data-target='" + newPlace + "']" ).trigger( "click" );
} );
// If there is only one service group, show it by default.
if ( $(".card-collapse.collapse").length < 2 ) {
$(".card-collapse.collapse").collapse('show');
}
if ( $( ".card-collapse.collapse" ).length < 2 ) { $( ".card-collapse.collapse" ).collapse( "show" ); }
$(".close-all-tabs").on("click", function(){
$('.card-collapse.collapse').collapse('hide');
return false;
});
$(".open-all-tabs").on("click", function() {
$('.card-collapse.collapse').collapse('show');
return false;
});
$( ".close-all-tabs" ).on( "click", function() { $( ".card-collapse.collapse" ).collapse( "hide" ); return false; } );
$( ".open-all-tabs" ).on( "click", function() { $( ".card-collapse.collapse" ).collapse( "show" ); return false; } );
});
</script>

View File

@ -20,6 +20,7 @@
<div class="row">
<div class="col-md-6">
<!-- <TMPL_VAR NAME="ZOOMDAY"> -->
<img data-href="<TMPL_VAR NAME='ZOOMDAY' />" src="<TMPL_VAR NAME='IMGDAY' />"
alt="daily graph"
class="img-fluid img-zoom i<TMPL_IF NAME='STATE_WARNING'> warn</TMPL_IF><TMPL_IF NAME='STATE_CRITICAL'> crit</TMPL_IF>"
@ -109,62 +110,63 @@
</TMPL_LOOP>
<div id="zoom" class="modal fade">
<div class="modal-dialog modal-lg">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-body">
<div class="row">
<div class="col-md-12">
<img alt="Zoom Image - Requires munin-cgi-graph" id="zoom_image" class="img-fluid"/>
<img alt="Zoom Image - Requires munin-cgi-graph" id="zoom_image" class="no-refresh d-block mx-auto"/>
<div id="image-overlay" style="position: absolute; top: 33px; left: 0; background-color: rgba(3, 50, 109, 0.3); width: 2px; height: 400px; display:none; pointer-events: none;"></div>
</div>
</div>
<div class="row">
<div class="row mt-3">
<div class="col-md-12">
<form class="form-horizontal" role="form" name="zoom_form" id="zoom_form">
<div class="form-group row">
<label for="plugin_name" class="col-sm-2 control-label">Plugin Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="plugin_name" id="plugin_name">
<input type="text" class="form-control form-control-sm" name="plugin_name" id="plugin_name">
</div>
</div>
<div class="form-group row">
<label for="start_iso8601" class="col-sm-2 control-label">Time Start/Stop</label>
<div class="col-sm-5">
<input type="text" class="form-control" name="start_iso8601" id="start_iso8601">
<input type="text" class="form-control form-control-sm" name="start_iso8601" id="start_iso8601">
</div>
<div class="col-sm-5">
<input type="text" class="form-control" name="stop_iso8601" id="stop_iso8601">
<input type="text" class="form-control form-control-sm" name="stop_iso8601" id="stop_iso8601">
</div>
</div>
<div class="form-group row">
<label for="start_epoch" class="col-sm-2 control-label">Epoch Start/Stop</label>
<div class="col-sm-5">
<input type="text" class="form-control" name="start_epoch" id="start_epoch">
<input type="text" class="form-control form-control-sm" name="start_epoch" id="start_epoch">
</div>
<div class="col-sm-5">
<input type="text" class="form-control" name="stop_epoch" id="stop_epoch">
<input type="text" class="form-control form-control-sm" name="stop_epoch" id="stop_epoch">
</div>
</div>
<div class="form-group row">
<label for="lower_limit" class="col-sm-2 control-label">Limit Low/High</label>
<div class="col-sm-5">
<input type="text" class="form-control" name="lower_limit" id="lower_limit">
<input type="text" class="form-control form-control-sm" name="lower_limit" id="lower_limit">
</div>
<div class="col-sm-5">
<input type="text" class="form-control" name="upper_limit" id="upper_limit">
<input type="text" class="form-control form-control-sm" name="upper_limit" id="upper_limit">
</div>
</div>
<div class="form-group row">
<label for="size_x" class="col-sm-2 control-label">Width/Height</label>
<div class="col-sm-5">
<div class="input-group">
<div class="input-group input-group-sm">
<input type="text" class="form-control" name="size_x" id="size_x">
<span class="input-group-append"><span class="input-group-text">px</span></span>
</div>
</div>
<div class="col-sm-5">
<div class="input-group">
<div class="input-group input-group-sm">
<input type="text" class="form-control" name="size_y" id="size_y">
<span class="input-group-append"><span class="input-group-text">px</span></span>
</div>
@ -173,10 +175,17 @@
<div class="form-group row">
<input type=hidden name="cgiurl_graph"/>
<div class="btn-group w-100 mx-3">
<button type="submit" class="btn btn-outline-success">Refresh</button>
<button type="button" class="btn btn-outline-primary" name="btnReset">Reset</button>
<button type="button" class="btn btn-outline-primary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-outline-primary" name="btnReset">&#8634; Reset to Initial</button>
<button type="button" class="btn btn-outline-info" name="btnShowDay">&#9201; Show Today</button>
<button type="button" class="btn btn-outline-info" name="btnShowWeek">&#9201; Show Week</button>
<button type="button" class="btn btn-outline-info" name="btnShowMonth">&#9201; Show Month</button>
<button type="button" class="btn btn-outline-info" name="btnShowYear">&#9201; Show Year</button>
</div>
<div class="btn-group w-100 mx-3 mt-2">
<button type="button" class="btn btn-outline-danger w-100" data-dismiss="modal">&times; Close</button>
</div>
<button type="submit" class="d-none">Hidden Submit Button - "onsubmit" needs this to exist.</button>
</div>
</form>
</div>
@ -185,13 +194,14 @@
<div class="row">
<div class="col-md-12">
<div class="alert alert-info">
<p>Zooming is very easy, it's done in 3 clicks (regular clicks, no drag&amp;drop):</p>
<p>Zooming is very easy, it's done in 3 clicks ( regular clicks, no drag &amp; drop ):</p>
<ol>
<li>Click to define the start of zoom.</li>
<li>Click to define the ending of zoom.</li>
<li>Refresh.</li>
<li>Click inside shaded area to zoom, outside to cancel.</li>
</ol>
<p>You can use the interactive form too.</p>
<p><em>Shortcut:</em> To just set a new start of zoom, click before your start point for your second click.</p>
<p class="mb-1">You can use the interactive form too.</p>
</div>
</div>
</div>
@ -202,36 +212,18 @@
<TMPL_INCLUDE NAME="partial/footer_pre.tmpl" />
<script src="<TMPL_VAR NAME='R_PATH'>/static/js/formatdate.min.js"></script>
<script src="<TMPL_VAR NAME='R_PATH'>/static/js/querystring.min.js"></script>
<script src="<TMPL_VAR NAME='R_PATH'>/static/js/dynazoom.min.js"></script>
<script src="<TMPL_VAR NAME='R_PATH'>/static/js/dynazoom.js"></script>
<script type="text/javascript">
//Zoom modal opening
$('.img-zoom').click(function(){
var query = $(this).attr('data-href');
var form = document.getElementById("zoom_form");
var image = document.getElementById("zoom_image");
form.onsubmit = function(){//Submit catching
var qs = new Querystring(query);
var src = "cgiurl_graph=" + qs.get("cgiurl_graph", "/munin-cgi/munin-cgi-graph")
+ "&plugin_name=" + form.plugin_name.value
+ "&start_epoch=" + form.start_epoch.value
+ "&stop_epoch=" + form.stop_epoch.value
+ "&rst_start_epoch=" + qs.get("start_epoch", "")
+ "&rst_stop_epoch=" + qs.get("stop_epoch", "")
+ "&lower_limit=" + form.lower_limit.value
+ "&upper_limit=" + form.upper_limit.value
+ "&size_x=" + form.size_x.value
+ "&size_y=" + form.size_y.value
;
refreshZoom(src, form, image);
return false;
};
$( ".img-zoom" ).click(function(){
var query = $(this).attr( "data-href" );
var form = document.getElementById( "zoom_form" );
var image = document.getElementById( "zoom_image" );
refreshZoom(query, form, image);
$('#zoom').modal('show');
$( "#zoom" ).modal( "show" );
});
</script>
<TMPL_INCLUDE NAME="partial/footer.tmpl" />
<TMPL_INCLUDE NAME="partial/footer.tmpl" />

View File

@ -5,52 +5,40 @@
-->
<script>
$(document).ready(function (){
$( document ).ready( function (){
// Should we auto-scroll when a service category is opened?
window.doScroll = false;
$('.tab-click').on('click', function() {
$( ".tab-click" ).on( "click", function() {
window.doScroll = true; // Do scroll when we click a tab header
var theCollapse = '#' + $(this).data("target") + "_coll";
var theCollapse = $( "#" + $( this ).data( "target" ) + "_coll" );
if ( $(theCollapse).hasClass('show') ) {
if ( theCollapse.hasClass( "show" ) ) {
// Already open, lets just trigger the event.
$(theCollapse).trigger('shown.bs.collapse');
theCollapse.trigger( "shown.bs.collapse" );
} else {
// Close all
$(".card-collapse.collapse").collapse("hide");
// Open the one we want
$(theCollapse).collapse('show');
// Close all, and open the one we want
$( ".card-collapse.collapse" ).collapse("hide" );
theCollapse.collapse( "show" );
}
// Do nothing with the click otherwise.
return false;
});
// Actual scroll function
$('.collapse').on('shown.bs.collapse', function(e) {
$( ".collapse" ).on( "shown.bs.collapse", function( e ) {
if ( window.doScroll ) {
var $card = $(this).closest('.card');
$('html,body').animate({
scrollTop: $card.offset().top
}, 500);
$( document ).scrollTop( $( this ).closest( ".card" ).offset().top );
window.doScroll = false;
}
});
// If there is only one service group, show it by default.
if ( $(".card-collapse.collapse").length < 2 ) {
$(".card-collapse.collapse").collapse('show');
}
if ( $( ".card-collapse.collapse" ).length < 2 ) { $( ".card-collapse.collapse" ).collapse( "show" ); }
$(".close-all-tabs").on("click", function(){
$('.card-collapse.collapse').collapse('hide');
return false;
});
$(".open-all-tabs").on("click", function() {
$('.card-collapse.collapse').collapse('show');
return false;
});
$( ".close-all-tabs" ).on( "click", function() { $( ".card-collapse.collapse" ).collapse( "hide" ); return false; } );
$( ".open-all-tabs" ).on( "click", function() { $( ".card-collapse.collapse" ).collapse( "show" ); return false; } );
});
</script>

View File

@ -0,0 +1,11 @@
<!--
File: partial/footer.tmpl
Used: All views, called after partial/footer.tmpl
-->
<script>
// Lightweight Cookie Library.
!function(e){var n;if("function"==typeof define&&define.amd&&(define(e),n=!0),"object"==typeof exports&&(module.exports=e(),n=!0),!n){var t=window.Cookies,o=window.Cookies=e();o.noConflict=function(){return window.Cookies=t,o}}}(function(){function e(){for(var e=0,n={};e<arguments.length;e++){var t=arguments[e];for(var o in t)n[o]=t[o]}return n}function n(e){return e.replace(/(%[0-9A-Z]{2})+/g,decodeURIComponent)}return function t(o){function r(){}function i(n,t,i){if("undefined"!=typeof document){"number"==typeof(i=e({path:"/"},r.defaults,i)).expires&&(i.expires=new Date(1*new Date+864e5*i.expires)),i.expires=i.expires?i.expires.toUTCString():"";try{var c=JSON.stringify(t);/^[\{\[]/.test(c)&&(t=c)}catch(e){}t=o.write?o.write(t,n):encodeURIComponent(String(t)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),n=encodeURIComponent(String(n)).replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent).replace(/[\(\)]/g,escape);var f="";for(var u in i)i[u]&&(f+="; "+u,!0!==i[u]&&(f+="="+i[u].split(";")[0]));return document.cookie=n+"="+t+f}}function c(e,t){if("undefined"!=typeof document){for(var r={},i=document.cookie?document.cookie.split("; "):[],c=0;c<i.length;c++){var f=i[c].split("="),u=f.slice(1).join("=");t||'"'!==u.charAt(0)||(u=u.slice(1,-1));try{var a=n(f[0]);if(u=(o.read||o)(u,a)||n(u),t)try{u=JSON.parse(u)}catch(e){}if(r[a]=u,e===a)break}catch(e){}}return e?r[e]:r}}return r.set=i,r.get=function(e){return c(e,!1)},r.getJSON=function(e){return c(e,!0)},r.remove=function(n,t){i(n,"",e(t,{expires:-1}))},r.defaults={},r.withConverter=t,r}(function(){})});
</script>
</body>
</html>

View File

@ -10,9 +10,10 @@
<span class="text-muted"><small>
This page was generated by <a href="http://www.munin-monitoring.org/">Munin</a>
version <TMPL_VAR NAME="MUNIN_VERSION"> at <TMPL_VAR NAME="TIMESTAMP">
with <a href="https://github.com/munin-monitoring/contrib/tree/master/templates/munstrap4/">MunStrap4</a> template.
with <a href="https://github.com/munin-monitoring/contrib/tree/master/templates/muncollapse/">MunCollapse</a> template.
</small></span>
</div>
</footer>
<script src="<TMPL_VAR NAME='R_PATH' />/static/js/lazysizes.min.js" async></script>

View File

@ -0,0 +1,122 @@
<!DOCTYPE html>
<html lang="en">
<!--
File: partial/head.tmpl
Used: All views, called before anything else
-->
<head>
<title>
<TMPL_IF NAME="NAME"><TMPL_VAR ESCAPE="HTML" NAME="NAME"> (</TMPL_IF>Munin<TMPL_LOOP NAME="PATH"><TMPL_IF NAME="pathname"> :: <TMPL_VAR ESCAPE="HTML" NAME="pathname"></TMPL_IF></TMPL_LOOP><TMPL_IF NAME="NAME">)</TMPL_IF>
</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="Auto-generated by Munin">
<link rel="apple-touch-icon" sizes="57x57" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/favicon-194x194.png" sizes="194x194">
<link rel="icon" type="image/png" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/android-chrome-192x192.png" sizes="192x192">
<link rel="icon" type="image/png" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/manifest.json" crossorigin="use-credentials">
<link rel="shortcut icon" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/favicon.ico">
<meta name="msapplication-TileColor" content="#00a300">
<meta name="msapplication-TileImage" content="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/mstile-144x144.png">
<meta name="msapplication-config" content="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/browserconfig.xml">
<meta name="theme-color" content="#076202">
<link href="<TMPL_VAR NAME='R_PATH' />/static/css/bootstrap.min.css" rel="stylesheet" />
<link href="<TMPL_VAR NAME='R_PATH' />/static/css/style-munstrap.css" rel="stylesheet" />
<script src="<TMPL_VAR NAME='R_PATH' />/static/js/jquery.min.js"></script>
<script src="<TMPL_VAR NAME='R_PATH' />/static/js/bootstrap.min.js"></script>
<script src="<TMPL_VAR NAME='R_PATH' />/static/js/typeahead.bundle.min.js"></script>
<TMPL_INCLUDE NAME="search_and_reload.tmpl">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-3">
<a class="navbar-brand" href="<TMPL_VAR NAME='R_PATH' />"><span class="munin-icon"></span></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="<TMPL_VAR NAME='R_PATH' />">Home</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarProblems" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Problems
</a>
<div class="dropdown-menu" aria-labelledby="navbarProblems">
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/problems.html#critical"><span class="badge alert-danger mr-2"><TMPL_VAR NAME="NCRITICAL"></span>Critical</a>
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/problems.html#warnings"><span class="badge alert-warning mr-2"><TMPL_VAR NAME="NWARNING"></span>Warning</a>
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/problems.html#unknowns"><span class="badge alert-info mr-2"><TMPL_VAR NAME="NUNKNOWN"></span>Unknown</a>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarGroups" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Groups
</a>
<div class="dropdown-menu" aria-labelledby="navbarGroups">
<TMPL_LOOP NAME="ROOTGROUPS">
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL'>"><TMPL_VAR NAME="NAME"></a>
</TMPL_LOOP>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarHosts" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Hosts
</a>
<div class="dropdown-menu" aria-labelledby="navbarHosts">
<TMPL_LOOP NAME="ROOTGROUPS">
<TMPL_LOOP NAME="GROUPS">
<TMPL_IF NAME="NCATEGORIES">
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL'>"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a>
</TMPL_IF>
</TMPL_LOOP>
</TMPL_LOOP>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarCats" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Categories
</a>
<div class="dropdown-menu" aria-labelledby="navbarCats">
<TMPL_LOOP NAME="GLOBALCATS">
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLDAY'>"><TMPL_VAR NAME="NAME"> - Day</a>
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLWEEK'>"><TMPL_VAR NAME="NAME"> - Week</a>
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLMONTH'>"><TMPL_VAR NAME="NAME"> - Month</a>
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLYEAR'>"><TMPL_VAR NAME="NAME"> - Year</a>
<TMPL_IF NAME="__first__"><div class="dropdown-divider"></div></TMPL_IF>
<TMPL_IF NAME="__inner__"><div class="dropdown-divider"></div></TMPL_IF>
</TMPL_LOOP>
</div>
</li>
</ul>
<form id="formy1" class="form-inline my-2 my-lg-0 w-25">
<input class="form-control mr-sm-2 w-100" type="text" id="findthehost" placeholder="Host or Service" aria-label="Search">
</form>
</div>
</nav>
<div class="container">
<TMPL_INCLUDE NAME="logo_navigation.tmpl">

View File

@ -4,25 +4,6 @@
Used: All views, called after from head.
-->
<!-- TEST DATA :: BEGIN -->
<!-- a/n: IF THE NAVIGATION LOOKS WIERD, PLEASE INCLUDE THIS INFO WHEN ASKING FOR HELP FIXING. -->
<TMPL_IF NAME="PATH"><TMPL_LOOP NAME="PATH">
<!-- PATH <TMPL_VAR NAME="PATHNAME"> -->
</TMPL_LOOP>
<TMPL_ELSE>
<!-- SHIT -->
</TMPL_IF>
<TMPL_IF NAME="CATEGORY" >
<!-- CAT: <TMPL_VAR ESCAPE="HTML" NAME="CATEGORY" /> -->
</TMPL_IF>
<TMPL_IF NAME="NAME">
<!-- NAME <TMPL_VAR ESCAPE="HTML" NAME="NAME"> -->
<TMPL_ELSE>
<!-- NO NAME -->
</TMPL_IF>
<!-- TEST DATA :: END -->
<TMPL_IF NAME="PATH">
<nav aria-label="breadcrumb pt1">
<ol class="breadcrumb">
@ -43,6 +24,10 @@
</TMPL_IF>
</li>
</TMPL_LOOP>
<div class="custom-control custom-switch ml-auto mr-0">
<input type="checkbox" class="custom-control-input" id="autorefimg">
<label class="custom-control-label" for="autorefimg">Auto-refresh Images</label>
</div>
</ol>
</nav>
<TMPL_ELSE>
@ -50,7 +35,7 @@
<ol class="breadcrumb">
<TMPL_IF NAME="NAME">
<!-- 2.0.37 - Shouldn't get hit with new HTML generator -->
<li class="breadcrumb-item"><a href="<TMPL_VAR NAME='R_PATH'>">Home</a></li>
<li class="breadcrumb-item"><a href="<TMPL_VAR NAME='R_PATH' />">Home</a></li>
<li class="breadcrumb-item"><TMPL_VAR NAME="NAME" /></li>
<TMPL_ELSE>
<li class="breadcrumb-item">Home</li>
@ -60,5 +45,25 @@
</TMPL_IF>
<TMPL_IF NAME="PEERS">
<TMPL_INCLUDE NAME="bottom_navigation.tmpl">
<TMPL_INCLUDE NAME="bottom_navigation.tmpl" />
</TMPL_IF>
<TMPL_IF NAME="COMPARISON-DAY">
<h2 class="mb-3">Comparison: by day</h2>
<TMPL_INCLUDE NAME="compare_navigation.tmpl" />
</TMPL_IF>
<TMPL_IF NAME="COMPARISON-WEEK">
<h2 class="mb-3">Comparison: by week</h2>
<TMPL_INCLUDE NAME="compare_navigation.tmpl" />
</TMPL_IF>
<TMPL_IF NAME="COMPARISON-MONTH">
<h2 class="mb-3">Comparison: by month</h2>
<TMPL_INCLUDE NAME="compare_navigation.tmpl" />
</TMPL_IF>
<TMPL_IF NAME="COMPARISON-YEAR">
<h2 class="mb-3">Comparison: by year</h2>
<TMPL_INCLUDE NAME="compare_navigation.tmpl" />
</TMPL_IF>

View File

@ -0,0 +1,160 @@
<!--
File: partial/search_and_reload.tmpl
Used: All views, generates the search functionality, and the auto-reload stuff.
-->
<script>
// $('img').each(function(){ if (this.src.length > 0) {
// console.log(this.src);
// } });
// This is used to build the navigation quick search - there is no backend, so we have to do
// it all client side.
//
// As a curious side note, commenting out the template loops and whatnot allows vscode to parse
// the javascript - so please note that the commented out TMPL directives STILL FUNCTION.
var gen_basegroups = {
// <TMPL_LOOP NAME="ROOTGROUPS">
"<TMPL_VAR NAME='NAME' />" : {
"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL'>",
"compare" : {
// <TMPL_IF NAME="COMPARE">
"Day" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_LOOP NAME='PATH' /><TMPL_IF NAME='pathname'><TMPL_VAR ESCAPE='URL' NAME='PATHNAME' />/</TMPL_IF></TMPL_LOOP>comparison-day.html",
"Week" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_LOOP NAME='PATH' /><TMPL_IF NAME='pathname'><TMPL_VAR ESCAPE='URL' NAME='PATHNAME' />/</TMPL_IF></TMPL_LOOP>comparison-week.html",
"Month" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_LOOP NAME='PATH' /><TMPL_IF NAME='pathname'><TMPL_VAR ESCAPE='URL' NAME='PATHNAME' />/</TMPL_IF></TMPL_LOOP>comparison-month.html",
"Year" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_LOOP NAME='PATH' /><TMPL_IF NAME='pathname'><TMPL_VAR ESCAPE='URL' NAME='PATHNAME' />/</TMPL_IF></TMPL_LOOP>comparison-year.html"
// </TMPL_IF>
}
},
// </TMPL_LOOP>
};
var gen_hosts = {
// <TMPL_LOOP NAME="ROOTGROUPS">
// <TMPL_LOOP NAME="GROUPS">
// <TMPL_IF NAME="NCATEGORIES">
"<TMPL_VAR ESCAPE='HTML' NAME='NAME' />" : {
"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL'>",
"services" : {
// <TMPL_LOOP NAME="CATEGORIES">
"<TMPL_VAR ESCAPE='HTML' NAME='NAME' />" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL' />",
// </TMPL_LOOP>
}
},
// </TMPL_IF>
// </TMPL_LOOP>
// </TMPL_LOOP>
};
var gen_cats = {
// <TMPL_LOOP NAME="GLOBALCATS">
"Category :: <TMPL_VAR NAME='NAME'> :: Day" : {
"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLDAY'>"
},
"Category :: <TMPL_VAR NAME='NAME'> :: Week" : {
"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLWEEK'>"
},
"Category :: <TMPL_VAR NAME='NAME'> :: Month" : {
"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLMONTH'>"
},
"Category :: <TMPL_VAR NAME='NAME'> :: Year" : {
"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLYEAR'>"
},
// </TMPL_LOOP>
};
function absolute(p,o){var t=p.split("/"),n=o.split("/");t.pop();for(var r=0;r<n.length;r++)"."!=n[r]&&(".."==n[r]?t.pop():t.push(n[r]));return t.join("/")}
var navMap = [];
$.each( gen_cats, function( name, obby ) {
navMap.push( { "name" : name, "link" : absolute( location.href, obby.baseurl ) } );
});
$.each( gen_hosts, function( name, obby ) {
var host_name = name;
navMap.push( { "name" : "Host :: " + name, "link" : absolute( location.href, obby.baseurl ) } );
$.each( obby.services, function( svcname, url ) {
navMap.push( { "name" : "Service :: " + host_name + " :: " + svcname, "link" : absolute( location.href, url ) } );
});
});
$.each( gen_basegroups, function( name, obby ) {
var host_name = name;
navMap.push( { "name" : "Host :: " + name, "link" : absolute( location.href, obby.baseurl ) } );
$.each( obby.compare, function( svcname, url ) {
navMap.push( { "name" : "Compare :: " + host_name + " :: " + svcname, "link" : absolute(location.href, url) } );
});
});
var navMapB = new Bloodhound({
datumTokenizer: function ( d ) { return Bloodhound.tokenizers.whitespace( d.name ); },
queryTokenizer: Bloodhound.tokenizers.whitespace,
identify: function ( obj ) { return obj.link; },
local: navMap
});
$(document).ready(function(){
$( "#findthehost" ).typeahead({
hint : true,
highlight : true,
minLength : 2,
},
{
name : "navMap",
limit : 10,
display : "link",
source : navMapB,
templates : {
suggestion : function ( data ) {
return "<div>" + data.name + "</div>";
}
}
}
);
$( "#findthehost" ).on( "typeahead:select", function() { $( "#formy1" ).submit(); } );
$( "#formy1" ).on( "submit", function() {
inputVal = $( "#findthehost" ).val();
if ( inputVal.substring( 0, 4 ) == "http" ) {
window.location.href = inputVal;
} else {
$( "#findthehost" ).typeahead( "val", "" );
}
return false;
});
});
function autoRefImages() {
$( "img" ).each(function () {
if ( this.src.length > 0 && (! $( this ).hasClass( "no-refresh" )) ) {
var thisURL = new URL( this.src );
thisURL.searchParams.set( "tt", new Date().getTime() );
this.src = thisURL.href;
}
});
}
$( document ).ready( function() {
if ( Cookies.get( "autorefreshimg" ) == 0 ) {
$( "#autorefimg" ).prop( "checked", false );
} else {
$( "#autorefimg" ).prop( "checked", true);
Cookies.set("autorefreshimg", "1", { expires: 60 });
window.autoreftimeout = setInterval( autoRefImages, 300000 );
}
$( "#autorefimg" ).on( "change", function() {
Cookies.set( "autorefreshimg", "0", { expires: 60 } )
clearInterval( window.autoreftimeout );
if ( $( "#autorefimg" ).is( ":checked" ) ) {
Cookies.set( "autorefreshimg", "1", { expires: 60 } );
window.autoreftimeout = setInterval( autoRefImages, 300000 );
}
});
})
</script>

View File

@ -1,114 +0,0 @@
# Munstrap4
Alternative Munin 2.x templates based on Twitter Bootstrap 4.
Based on "Munstrap" by [Jonny McCullagh](https://github.com/jonnymccullagh), [munin-monitoring/contrib](https://github.com/munin-monitoring/contrib/tree/master/templates/munstrap) repo.
#### Overview Sample Image
<a href="https://jtsage.dev/munstrap4/sample-home.png"><img src="https://jtsage.dev/munstrap4/sample-home.png" style="max-width: 1229px; display:block; margin-left: auto; margin-right: auto; width: 75%" /></a>
#### [Semi-Live Demo](https://jtsage.dev/munin-demo/)
Zoom functionality for this demo has been disabled, and the data will never update, but it's a decent visual reference.
---
## Installation
### 1. Clone the munin-monitoring/contrib repo to a temporary location:
```
$ cd /opt
$ git clone https://github.com/munin-monitoring/contrib.git
```
### 2. Place the template in an appropriate safe place
Ubuntu shown - other distros may prefer ```/usr/local/share/munin/...```
```
$ mkdir /usr/share/munin/template
$ mkdir /usr/share/munin/template/munstrap4
```
__NOTE__: If this step fails, your munin installation may use ```/usr/local/share/munin/...``` instead!
```
$ cp -r /opt/contrib/templates/munstrap4/templates /usr/share/munin/template/munstrap4/
$ cp -r /opt/contrib/templates/munstrap4/static /usr/share/munin/template/munstrap4/
```
### 3. Edit your ```munin.conf``` file.
Typically located at ```/etc/munin.conf```
__FIND AND CHANGE:__ (near the top of the file)
```
# Where to look for the HTML templates
#
#tmpldir /etc/munin/templates
# Where to look for the static www files
#
#staticdir /etc/munin/static
```
__TO:__
```
# Where to look for the HTML templates
#
tmpldir /usr/share/munin/template/munstrap4/templates
# Where to look for the static www files
#
staticdir /usr/share/munin/template/munstrap4/static
```
### 4. [Optional / Recommended] Clean out the old generated files.
This isn't really required, and is totally not nessesary if you are using `munin-httpd`. The location of these files can be found in your ```munin.conf``` file, with the ```htmldir``` directive.
__NOTE:__ Ubuntu shown, other distributions may be in ```/var/www/munin/```
```
$ rm -rf /var/cache/munin/www/*
```
### 5. Wait Patiently
```munin-update``` will regenerate the files the next time it runs. By default, this is on the :05 minute tick for most installations. If you do not have new files within 10 minutes, be sure to check ```munin-update.log``` and find out what went wrong.
---
## Revert to Official Munin Template
### 1. Edit your ```munin.conf``` file.
Typically located at ```/etc/munin.conf```
__FIND AND CHANGE:__ (near the top of the file - comment these lines out!)
### 2. [Optional / Recommended] Clean up
Remove the files from step #1 & #2 above, and repeat step #4 & #5.
---
## Samples
#### View of a group:
<a href="https://jtsage.dev/munstrap4/sample-group.png"><img src="https://jtsage.dev/munstrap4/sample-group.png" style="max-width: 1229px; display:block; margin-left: auto; margin-right: auto; width: 75%" /></a>
#### View of a specific node:
<a href="https://jtsage.dev/munstrap4/sample-node.png"><img src="https://jtsage.dev/munstrap4/sample-node.png" style="max-width: 1229px; display:block; margin-left: auto; margin-right: auto; width: 75%" /></a>
#### Zoom feature:
<a href="https://jtsage.dev/munstrap4/sample-zoom.png"><img src="https://jtsage.dev/munstrap4/sample-zoom.png" style="max-width: 1229px; display:block; margin-left: auto; margin-right: auto; width: 75%" /></a>
---
## Compatibility
a/n: I am unsure of the compatibility with the next major version of munin. Most things will work from what I've read, but the navigation may be slightly funky.

View File

@ -1 +0,0 @@
@media(min-width:992px){.modal-lg{width:940px!important}}img.i{display:block;margin:10px auto}img.img-zoom{cursor:pointer}div.service-alert{margin-top:10px}img#zoom_image{margin-bottom:15px}ul.groupview,ul.groupview ul{list-style-type:none}.munin-icon{background:url(../img/logo-munin.png) left top;margin-top:-6px;width:35px;height:35px;display:block;float:left}img{box-sizing:content-box;border:2px solid transparent}img.warn{border:2px solid #8a6d3b}img.crit{border:2px solid #a94442}img.unkn{border:2px solid #fa0}html{position:relative;min-height:100%}body{margin-bottom:75px}.footer{position:absolute;bottom:0;width:100%;height:60px;line-height:60px;background-color:#f5f5f5}.breadcrumb-item-svc::before{display:inline-block;color:#6c757d;content:"["}.breadcrumb-item-svc::after{display:inline-block;padding-right:.5rem;color:#6c757d;content:"]"}.custom-collapse{color:#6c757d;font-size:75%}.custom-collapse::before{display:inline-block;color:#6c757d;content:"["}.custom-collapse::after{display:inline-block;padding-right:.5rem;color:#6c757d;content:"]"}.custom-collapse-all{color:#6c757d;font-size:75%}.custom-collapse-all::before{display:inline-block;color:#6c757d;content:"["}.custom-collapse-all::after{display:inline-block;padding-right:.5rem;color:#6c757d;content:"]"}.cat-list::before{display:inline-block;color:#6c757d;content:"[ "}.cat-list::after{display:inline-block;color:#6c757d;content:" ]"}span.twitter-typeahead .tt-menu{cursor:pointer}span.twitter-typeahead .tt-menu{position:absolute;top:100%;left:0;width:100%;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:1rem;color:#373a3c;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,0.15);border-radius:.25rem;overflow:hidden}span.twitter-typeahead .tt-suggestion{display:block;width:100%;padding:3px 20px;clear:both;font-weight:normal;line-height:1.5;color:#373a3c;text-align:inherit;white-space:nowrap;background:0;border:0}span.twitter-typeahead .tt-suggestion:focus,.dropdown-item:hover,span.twitter-typeahead .tt-suggestion:hover{color:#2b2d2f;text-decoration:none;background-color:#f5f5f5}span.twitter-typeahead .active.tt-suggestion,span.twitter-typeahead .tt-suggestion.tt-cursor,span.twitter-typeahead .active.tt-suggestion:focus,span.twitter-typeahead .tt-suggestion.tt-cursor:focus,span.twitter-typeahead .active.tt-suggestion:hover,span.twitter-typeahead .tt-suggestion.tt-cursor:hover{color:#fff;text-decoration:none;background-color:#0275d8;outline:0}span.twitter-typeahead .disabled.tt-suggestion,span.twitter-typeahead .disabled.tt-suggestion:focus,span.twitter-typeahead .disabled.tt-suggestion:hover{color:#818a91}span.twitter-typeahead{width:100%}.input-group span.twitter-typeahead{display:block!important}.input-group span.twitter-typeahead .tt-menu{top:2.375rem!important}span.hangindent2{padding-left:1em}span.hangindent3{padding-left:2em}span.hangindent4{padding-left:3em}span.hangindent5{padding-left:4em}span.hangindent6{padding-left:5em}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

File diff suppressed because one or more lines are too long

View File

@ -1,199 +0,0 @@
function refreshZoom(query, form, image, divOverlay) {
//INIT
var qs = new Querystring(query);
init();
var scale = refreshImg();
var start_epoch = (+qs.get("rst_start_epoch", form.start_epoch.value));
var stop_epoch = (+qs.get("rst_stop_epoch", form.stop_epoch.value));
var initial_left;
var initial_top;
//form.btnMaj.onclick = majDates;
form.plugin_name.onblur = refreshImg;
form.start_iso8601.onblur = majDates;
form.stop_iso8601.onblur = majDates;
form.start_epoch.onblur = refreshImg;
form.stop_epoch.onblur = refreshImg;
form.lower_limit.onblur = refreshImg;
form.upper_limit.onblur = refreshImg;
form.size_x.onblur = refreshImg;
form.size_y.onblur = refreshImg;
form.btnReset.onclick = reset;
// Sets the onClick handler
image.onclick = click;
var clickCounter = 0;
//FUNCTIONS
function init() {
form.plugin_name.value = qs.get("plugin_name", "localdomain/localhost.localdomain/if_eth0");
form.start_epoch.value = qs.get("start_epoch", "1236561663");
form.stop_epoch.value = qs.get("stop_epoch", "1237561663");
form.lower_limit.value = qs.get("lower_limit", "");
form.upper_limit.value = qs.get("upper_limit", "");
form.size_x.value = qs.get("size_x", "");
form.size_y.value = qs.get("size_y", "");
updateStartStop();
}
function reset(event) {
init();
//Can be not the initial ones in case of manual refresh
form.start_epoch.value = start_epoch;
form.stop_epoch.value = stop_epoch;
updateStartStop();
//Redraw
scale = refreshImg();
//Reset gui
clickCounter = 0;
initial_left = 0;
initial_top = 0;
image.onmousemove = undefined;
form.start_iso8601.disabled = false;
form.stop_iso8601.disabled = false;
form.start_epoch.disabled = false;
form.stop_epoch.disabled = false;
}
function refreshImg(event) {
image.src = qs.get("cgiurl_graph", "/munin-cgi/munin-cgi-graph") + "/"
+ form.plugin_name.value
+ "-pinpoint=" + parseInt(form.start_epoch.value) + "," + parseInt(form.stop_epoch.value)
+ ".png"
+ "?"
+ "&lower_limit=" + form.lower_limit.value
+ "&upper_limit=" + form.upper_limit.value
+ "&size_x=" + form.size_x.value
+ "&size_y=" + form.size_y.value
;
return ((+form.stop_epoch.value) - (+form.start_epoch.value)) / (+form.size_x.value);
}
function updateStartStop() {
form.start_iso8601.value = new Date(form.start_epoch.value * 1000).formatDate(Date.DATE_ISO8601);
form.stop_iso8601.value = new Date(form.stop_epoch.value * 1000).formatDate(Date.DATE_ISO8601);
}
function divMouseMove(event) {
var delta_x;
var size_x;
// Handling the borders (X1>X2 ou X1<X2)
var posX = getCoordinatesOnImage(event)[0];
var current_width = posX - initial_left;
if (current_width < 0) {
delta_x = posX - 63; // the Y Axis is 63px from the left border
size_x = -current_width;
} else {
delta_x = initial_left - 63; // the Y Axis is 63px from the left border
size_x = current_width;
}
// Compute the epochs UNIX (only for horizontal)
form.start_epoch.value = start_epoch + scale * delta_x;
form.stop_epoch.value = start_epoch + scale * ( delta_x + size_x );
// update !
updateStartStop();
}
function startZoom(event) {
var pos = getCoordinatesOnImage(event);
initial_left = pos[0];
initial_top = pos[1];
// Fix the handles
form.start_iso8601.disabled = true;
form.stop_iso8601.disabled = true;
form.start_epoch.disabled = true;
form.stop_epoch.disabled = true;
image.onmousemove = divMouseMove;
}
function endZoom(event) {
image.onmousemove = undefined;
form.start_iso8601.disabled = false;
form.stop_iso8601.disabled = false;
form.start_epoch.disabled = false;
form.stop_epoch.disabled = false;
}
function fillDate(date, default_date) {
return date + default_date.substring(date.length, default_date.length);
}
function majDates(event) {
var default_date = "2009-01-01T00:00:00+0100";
var start_manual = fillDate(form.start_iso8601.value, default_date);
var stop_manual = fillDate(form.stop_iso8601.value, default_date);
var dateRegex = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).(\d{4})/;
if (dateRegex.test(start_manual)) {
var date_parsed = new Date(start_manual.replace(dateRegex, "$2 $3, $1 $4:$5:$6"));
form.start_epoch.value = date_parsed.getTime() / 1000;
}
if (dateRegex.test(stop_manual)) {
var date_parsed = new Date(stop_manual.replace(dateRegex, "$2 $3, $1 $4:$5:$6"));
form.stop_epoch.value = date_parsed.getTime() / 1000;
}
//form.submit();
refreshImg();
}
function click(event) {
switch ((clickCounter++) % 2) {
case 0:
startZoom(event);
break;
case 1:
endZoom(event);
break;
}
}
//Coordinates on image
function findPosition(oElement) {
if (typeof( oElement.offsetParent ) != "undefined") {
for (var posX = 0, posY = 0; oElement; oElement = oElement.offsetParent) {
posX += oElement.offsetLeft;
posY += oElement.offsetTop;
}
return [posX, posY];
}
else {
return [oElement.x, oElement.y];
}
}
function getCoordinatesOnImage(event) {
var posX = 0;
var posY = 0;
var imgPos;
imgPos = findPosition(image);
if (!event) var event = window.event;
if (event.pageX || event.pageY) {
posX = event.pageX;
posY = event.pageY;
}
else if (event.clientX || event.clientY) {
posX = event.clientX + document.body.scrollLeft
+ document.documentElement.scrollLeft;
posY = event.clientY + document.body.scrollTop
+ document.documentElement.scrollTop;
}
posX = posX - imgPos[0];
posY = posY - imgPos[1];
return [posX, posY];
}
};

View File

@ -1 +0,0 @@
function refreshZoom(query,form,image,divOverlay){var qs=new Querystring(query);init();var scale=refreshImg();var start_epoch=+qs.get("rst_start_epoch",form.start_epoch.value);var stop_epoch=+qs.get("rst_stop_epoch",form.stop_epoch.value);var initial_left;var initial_top;form.plugin_name.onblur=refreshImg;form.start_iso8601.onblur=majDates;form.stop_iso8601.onblur=majDates;form.start_epoch.onblur=refreshImg;form.stop_epoch.onblur=refreshImg;form.lower_limit.onblur=refreshImg;form.upper_limit.onblur=refreshImg;form.size_x.onblur=refreshImg;form.size_y.onblur=refreshImg;form.btnReset.onclick=reset;image.onclick=click;var clickCounter=0;function init(){form.plugin_name.value=qs.get("plugin_name","localdomain/localhost.localdomain/if_eth0");form.start_epoch.value=qs.get("start_epoch","1236561663");form.stop_epoch.value=qs.get("stop_epoch","1237561663");form.lower_limit.value=qs.get("lower_limit","");form.upper_limit.value=qs.get("upper_limit","");form.size_x.value=qs.get("size_x","");form.size_y.value=qs.get("size_y","");updateStartStop()}function reset(event){init();form.start_epoch.value=start_epoch;form.stop_epoch.value=stop_epoch;updateStartStop();scale=refreshImg();clickCounter=0;initial_left=0;initial_top=0;image.onmousemove=undefined;form.start_iso8601.disabled=false;form.stop_iso8601.disabled=false;form.start_epoch.disabled=false;form.stop_epoch.disabled=false}function refreshImg(event){image.src=qs.get("cgiurl_graph","/munin-cgi/munin-cgi-graph")+"/"+form.plugin_name.value+"-pinpoint="+parseInt(form.start_epoch.value)+","+parseInt(form.stop_epoch.value)+".png"+"?"+"&lower_limit="+form.lower_limit.value+"&upper_limit="+form.upper_limit.value+"&size_x="+form.size_x.value+"&size_y="+form.size_y.value;return(+form.stop_epoch.value-+form.start_epoch.value)/+form.size_x.value}function updateStartStop(){form.start_iso8601.value=new Date(form.start_epoch.value*1e3).formatDate(Date.DATE_ISO8601);form.stop_iso8601.value=new Date(form.stop_epoch.value*1e3).formatDate(Date.DATE_ISO8601)}function divMouseMove(event){var delta_x;var size_x;var posX=getCoordinatesOnImage(event)[0];var current_width=posX-initial_left;if(current_width<0){delta_x=posX-63;size_x=-current_width}else{delta_x=initial_left-63;size_x=current_width}form.start_epoch.value=start_epoch+scale*delta_x;form.stop_epoch.value=start_epoch+scale*(delta_x+size_x);updateStartStop()}function startZoom(event){var pos=getCoordinatesOnImage(event);initial_left=pos[0];initial_top=pos[1];form.start_iso8601.disabled=true;form.stop_iso8601.disabled=true;form.start_epoch.disabled=true;form.stop_epoch.disabled=true;image.onmousemove=divMouseMove}function endZoom(event){image.onmousemove=undefined;form.start_iso8601.disabled=false;form.stop_iso8601.disabled=false;form.start_epoch.disabled=false;form.stop_epoch.disabled=false}function fillDate(date,default_date){return date+default_date.substring(date.length,default_date.length)}function majDates(event){var default_date="2009-01-01T00:00:00+0100";var start_manual=fillDate(form.start_iso8601.value,default_date);var stop_manual=fillDate(form.stop_iso8601.value,default_date);var dateRegex=/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).(\d{4})/;if(dateRegex.test(start_manual)){var date_parsed=new Date(start_manual.replace(dateRegex,"$2 $3, $1 $4:$5:$6"));form.start_epoch.value=date_parsed.getTime()/1e3}if(dateRegex.test(stop_manual)){var date_parsed=new Date(stop_manual.replace(dateRegex,"$2 $3, $1 $4:$5:$6"));form.stop_epoch.value=date_parsed.getTime()/1e3}refreshImg()}function click(event){switch(clickCounter++%2){case 0:startZoom(event);break;case 1:endZoom(event);break}}function findPosition(oElement){if(typeof oElement.offsetParent!="undefined"){for(var posX=0,posY=0;oElement;oElement=oElement.offsetParent){posX+=oElement.offsetLeft;posY+=oElement.offsetTop}return[posX,posY]}else{return[oElement.x,oElement.y]}}function getCoordinatesOnImage(event){var posX=0;var posY=0;var imgPos;imgPos=findPosition(image);if(!event)var event=window.event;if(event.pageX||event.pageY){posX=event.pageX;posY=event.pageY}else if(event.clientX||event.clientY){posX=event.clientX+document.body.scrollLeft+document.documentElement.scrollLeft;posY=event.clientY+document.body.scrollTop+document.documentElement.scrollTop}posX=posX-imgPos[0];posY=posY-imgPos[1];return[posX,posY]}}

View File

@ -1,363 +0,0 @@
// formatDate :
// a PHP date like function, for formatting date strings
// authored by Svend Tofte <www.svendtofte.com>
// the code is in the public domain
//
// see http://www.svendtofte.com/javascript/javascript-date-string-formatting/
// and http://www.php.net/date
//
// thanks to
// - Daniel Berlin <mail@daniel-berlin.de>,
// major overhaul and improvements
// - Matt Bannon,
// correcting some stupid bugs in my days-in-the-months list!
// - levon ghazaryan. pointing out an error in z switch.
// - Andy Pemberton. pointing out error in c switch
//
// input : format string
// time : epoch time (seconds, and optional)
//
// if time is not passed, formatting is based on
// the current "this" date object's set time.
//
// supported switches are
// a, A, B, c, d, D, F, g, G, h, H, i, I (uppercase i), j, l (lowecase L),
// L, m, M, n, N, O, P, r, s, S, t, U, w, W, y, Y, z, Z
//
// unsupported (as compared to date in PHP 5.1.3)
// T, e, o
Date.prototype.formatDate = function (input,time) {
var daysLong = ["Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
var daysShort = ["Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat"];
var monthsShort = ["Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"];
var monthsLong = ["January", "February", "March", "April",
"May", "June", "July", "August", "September",
"October", "November", "December"];
var switches = { // switches object
a : function () {
// Lowercase Ante meridiem and Post meridiem
return date.getHours() > 11? "pm" : "am";
},
A : function () {
// Uppercase Ante meridiem and Post meridiem
return (this.a().toUpperCase ());
},
B : function (){
// Swatch internet time. code simply grabbed from ppk,
// since I was feeling lazy:
// http://www.xs4all.nl/~ppk/js/beat.html
var off = (date.getTimezoneOffset() + 60)*60;
var theSeconds = (date.getHours() * 3600) +
(date.getMinutes() * 60) +
date.getSeconds() + off;
var beat = Math.floor(theSeconds/86.4);
if (beat > 1000) beat -= 1000;
if (beat < 0) beat += 1000;
if ((String(beat)).length == 1) beat = "00"+beat;
if ((String(beat)).length == 2) beat = "0"+beat;
return beat;
},
c : function () {
// ISO 8601 date (e.g.: "2004-02-12T15:19:21+00:00"), as per
// http://www.cl.cam.ac.uk/~mgk25/iso-time.html
return (this.Y() + "-" + this.m() + "-" + this.d() + "T" +
this.H() + ":" + this.i() + ":" + this.s() + this.P());
},
d : function () {
// Day of the month, 2 digits with leading zeros
var j = String(this.j());
return (j.length == 1 ? "0"+j : j);
},
D : function () {
// A textual representation of a day, three letters
return daysShort[date.getDay()];
},
F : function () {
// A full textual representation of a month
return monthsLong[date.getMonth()];
},
g : function () {
// 12-hour format of an hour without leading zeros, 1 through 12!
if (date.getHours() == 0) {
return 12;
} else {
return date.getHours()>12 ? date.getHours()-12 : date.getHours();
}
},
G : function () {
// 24-hour format of an hour without leading zeros
return date.getHours();
},
h : function () {
// 12-hour format of an hour with leading zeros
var g = String(this.g());
return (g.length == 1 ? "0"+g : g);
},
H : function () {
// 24-hour format of an hour with leading zeros
var G = String(this.G());
return (G.length == 1 ? "0"+G : G);
},
i : function () {
// Minutes with leading zeros
var min = String (date.getMinutes ());
return (min.length == 1 ? "0" + min : min);
},
I : function () {
// Whether or not the date is in daylight saving time (DST)
// note that this has no bearing in actual DST mechanics,
// and is just a pure guess. buyer beware.
var noDST = new Date ("January 1 " + this.Y() + " 00:00:00");
return (noDST.getTimezoneOffset () ==
date.getTimezoneOffset () ? 0 : 1);
},
j : function () {
// Day of the month without leading zeros
return date.getDate();
},
l : function () {
// A full textual representation of the day of the week
return daysLong[date.getDay()];
},
L : function () {
// leap year or not. 1 if leap year, 0 if not.
// the logic should match iso's 8601 standard.
// http://www.uic.edu/depts/accc/software/isodates/leapyear.html
var Y = this.Y();
if (
(Y % 4 == 0 && Y % 100 != 0) ||
(Y % 4 == 0 && Y % 100 == 0 && Y % 400 == 0)
) {
return 1;
} else {
return 0;
}
},
m : function () {
// Numeric representation of a month, with leading zeros
var n = String(this.n());
return (n.length == 1 ? "0"+n : n);
},
M : function () {
// A short textual representation of a month, three letters
return monthsShort[date.getMonth()];
},
n : function () {
// Numeric representation of a month, without leading zeros
return date.getMonth()+1;
},
N : function () {
// ISO-8601 numeric representation of the day of the week
var w = this.w();
return (w == 0 ? 7 : w);
},
O : function () {
// Difference to Greenwich time (GMT) in hours
var os = Math.abs(date.getTimezoneOffset());
var h = String(Math.floor(os/60));
var m = String(os%60);
h.length == 1? h = "0"+h:1;
m.length == 1? m = "0"+m:1;
return date.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m;
},
P : function () {
// Difference to GMT, with colon between hours and minutes
var O = this.O();
return (O.substr(0, 3) + ":" + O.substr(3, 2));
},
r : function () {
// RFC 822 formatted date
var r; // result
// Thu , 21 Dec 2000
r = this.D() + ", " + this.d() + " " + this.M() + " " + this.Y() +
// 16 : 01 : 07 0200
" " + this.H() + ":" + this.i() + ":" + this.s() + " " + this.O();
return r;
},
s : function () {
// Seconds, with leading zeros
var sec = String (date.getSeconds ());
return (sec.length == 1 ? "0" + sec : sec);
},
S : function () {
// English ordinal suffix for the day of the month, 2 characters
switch (date.getDate ()) {
case 1: return ("st");
case 2: return ("nd");
case 3: return ("rd");
case 21: return ("st");
case 22: return ("nd");
case 23: return ("rd");
case 31: return ("st");
default: return ("th");
}
},
t : function () {
// thanks to Matt Bannon for some much needed code-fixes here!
var daysinmonths = [null,31,28,31,30,31,30,31,31,30,31,30,31];
if (this.L()==1 && this.n()==2) return 29; // ~leap day
return daysinmonths[this.n()];
},
U : function () {
// Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
return Math.round(date.getTime()/1000);
},
w : function () {
// Numeric representation of the day of the week
return date.getDay();
},
W : function () {
// Weeknumber, as per ISO specification:
// http://www.cl.cam.ac.uk/~mgk25/iso-time.html
var DoW = this.N ();
var DoY = this.z ();
// If the day is 3 days before New Year's Eve and is Thursday or earlier,
// it's week 1 of next year.
var daysToNY = 364 + this.L () - DoY;
if (daysToNY <= 2 && DoW <= (3 - daysToNY)) {
return 1;
}
// If the day is within 3 days after New Year's Eve and is Friday or later,
// it belongs to the old year.
if (DoY <= 2 && DoW >= 5) {
return new Date (this.Y () - 1, 11, 31).formatDate ("W");
}
var nyDoW = new Date (this.Y (), 0, 1).getDay ();
nyDoW = nyDoW != 0 ? nyDoW - 1 : 6;
if (nyDoW <= 3) { // First day of the year is a Thursday or earlier
return (1 + Math.floor ((DoY + nyDoW) / 7));
} else { // First day of the year is a Friday or later
return (1 + Math.floor ((DoY - (7 - nyDoW)) / 7));
}
},
y : function () {
// A two-digit representation of a year
var y = String(this.Y());
return y.substring(y.length-2,y.length);
},
Y : function () {
// A full numeric representation of a year, 4 digits
// we first check, if getFullYear is supported. if it
// is, we just use that. ppks code is nice, but won't
// work with dates outside 1900-2038, or something like that
if (date.getFullYear) {
var newDate = new Date("January 1 2001 00:00:00 +0000");
var x = newDate .getFullYear();
if (x == 2001) {
// i trust the method now
return date.getFullYear();
}
}
// else, do this:
// codes thanks to ppk:
// http://www.xs4all.nl/~ppk/js/introdate.html
var x = date.getYear();
var y = x % 100;
y += (y < 38) ? 2000 : 1900;
return y;
},
z : function () {
// The day of the year, zero indexed! 0 through 366
var s = "January 1 " + this.Y() + " 00:00:00 GMT" + this.O();
var t = new Date(s);
var diff = date.getTime() - t.getTime();
return Math.floor(diff/1000/60/60/24);
},
Z : function () {
// Timezone offset in seconds
return (date.getTimezoneOffset () * -60);
}
}
function getSwitch(str) {
if (switches[str] != undefined) {
return switches[str]();
} else {
return str;
}
}
var date;
if (time) {
var date = new Date (time);
} else {
var date = this;
}
var formatString = input.split("");
var i = 0;
while (i < formatString.length) {
if (formatString[i] == "%") {
// this is our way of allowing users to escape stuff
formatString.splice(i,1);
} else {
formatString[i] = getSwitch(formatString[i]);
}
i++;
}
return formatString.join("");
}
// Some (not all) predefined format strings from PHP 5.1.1, which
// offer standard date representations.
// See: http://www.php.net/manual/en/ref.datetime.php#datetime.constants
//
// Atom "2005-08-15T15:52:01+00:00"
Date.DATE_ATOM = "Y-m-d%TH:i:sP";
// ISO-8601 "2005-08-15T15:52:01+0000"
Date.DATE_ISO8601 = "Y-m-d%TH:i:sO";
// RFC 2822 "Mon, 15 Aug 2005 15:52:01 +0000"
Date.DATE_RFC2822 = "D, d M Y H:i:s O";
// W3C "2005-08-15 15:52:01+00:00"
Date.DATE_W3C = "Y-m-d%TH:i:sP";

View File

@ -1 +0,0 @@
Date.prototype.formatDate=function(input,time){var daysLong=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var daysShort=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];var monthsShort=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];var monthsLong=["January","February","March","April","May","June","July","August","September","October","November","December"];var switches={a:function(){return date.getHours()>11?"pm":"am"},A:function(){return this.a().toUpperCase()},B:function(){var off=(date.getTimezoneOffset()+60)*60;var theSeconds=date.getHours()*3600+date.getMinutes()*60+date.getSeconds()+off;var beat=Math.floor(theSeconds/86.4);if(beat>1e3)beat-=1e3;if(beat<0)beat+=1e3;if(String(beat).length==1)beat="00"+beat;if(String(beat).length==2)beat="0"+beat;return beat},c:function(){return this.Y()+"-"+this.m()+"-"+this.d()+"T"+this.H()+":"+this.i()+":"+this.s()+this.P()},d:function(){var j=String(this.j());return j.length==1?"0"+j:j},D:function(){return daysShort[date.getDay()]},F:function(){return monthsLong[date.getMonth()]},g:function(){if(date.getHours()==0){return 12}else{return date.getHours()>12?date.getHours()-12:date.getHours()}},G:function(){return date.getHours()},h:function(){var g=String(this.g());return g.length==1?"0"+g:g},H:function(){var G=String(this.G());return G.length==1?"0"+G:G},i:function(){var min=String(date.getMinutes());return min.length==1?"0"+min:min},I:function(){var noDST=new Date("January 1 "+this.Y()+" 00:00:00");return noDST.getTimezoneOffset()==date.getTimezoneOffset()?0:1},j:function(){return date.getDate()},l:function(){return daysLong[date.getDay()]},L:function(){var Y=this.Y();if(Y%4==0&&Y%100!=0||Y%4==0&&Y%100==0&&Y%400==0){return 1}else{return 0}},m:function(){var n=String(this.n());return n.length==1?"0"+n:n},M:function(){return monthsShort[date.getMonth()]},n:function(){return date.getMonth()+1},N:function(){var w=this.w();return w==0?7:w},O:function(){var os=Math.abs(date.getTimezoneOffset());var h=String(Math.floor(os/60));var m=String(os%60);h.length==1?h="0"+h:1;m.length==1?m="0"+m:1;return date.getTimezoneOffset()<0?"+"+h+m:"-"+h+m},P:function(){var O=this.O();return O.substr(0,3)+":"+O.substr(3,2)},r:function(){var r;r=this.D()+", "+this.d()+" "+this.M()+" "+this.Y()+" "+this.H()+":"+this.i()+":"+this.s()+" "+this.O();return r},s:function(){var sec=String(date.getSeconds());return sec.length==1?"0"+sec:sec},S:function(){switch(date.getDate()){case 1:return"st";case 2:return"nd";case 3:return"rd";case 21:return"st";case 22:return"nd";case 23:return"rd";case 31:return"st";default:return"th"}},t:function(){var daysinmonths=[null,31,28,31,30,31,30,31,31,30,31,30,31];if(this.L()==1&&this.n()==2)return 29;return daysinmonths[this.n()]},U:function(){return Math.round(date.getTime()/1e3)},w:function(){return date.getDay()},W:function(){var DoW=this.N();var DoY=this.z();var daysToNY=364+this.L()-DoY;if(daysToNY<=2&&DoW<=3-daysToNY){return 1}if(DoY<=2&&DoW>=5){return new Date(this.Y()-1,11,31).formatDate("W")}var nyDoW=new Date(this.Y(),0,1).getDay();nyDoW=nyDoW!=0?nyDoW-1:6;if(nyDoW<=3){return 1+Math.floor((DoY+nyDoW)/7)}else{return 1+Math.floor((DoY-(7-nyDoW))/7)}},y:function(){var y=String(this.Y());return y.substring(y.length-2,y.length)},Y:function(){if(date.getFullYear){var newDate=new Date("January 1 2001 00:00:00 +0000");var x=newDate.getFullYear();if(x==2001){return date.getFullYear()}}var x=date.getYear();var y=x%100;y+=y<38?2e3:1900;return y},z:function(){var s="January 1 "+this.Y()+" 00:00:00 GMT"+this.O();var t=new Date(s);var diff=date.getTime()-t.getTime();return Math.floor(diff/1e3/60/60/24)},Z:function(){return date.getTimezoneOffset()*-60}};function getSwitch(str){if(switches[str]!=undefined){return switches[str]()}else{return str}}var date;if(time){var date=new Date(time)}else{var date=this}var formatString=input.split("");var i=0;while(i<formatString.length){if(formatString[i]=="%"){formatString.splice(i,1)}else{formatString[i]=getSwitch(formatString[i])}i++}return formatString.join("")};Date.DATE_ATOM="Y-m-d%TH:i:sP";Date.DATE_ISO8601="Y-m-d%TH:i:sO";Date.DATE_RFC2822="D, d M Y H:i:s O";Date.DATE_W3C="Y-m-d%TH:i:sP";

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,42 +0,0 @@
/* Client-side access to querystring name=value pairs
Version 1.3
28 May 2008
License (Simplified BSD):
http://adamv.com/dev/javascript/qslicense.txt
*/
function Querystring(qs) { // optionally pass a querystring to parse
this.params = {};
var query_string = window.location.search;
if (qs == null) qs = query_string.substring(1, query_string.length);
if (qs.length == 0) return;
// Turn <plus> back to <space>
// See: http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4.1
qs = qs.replace(/\+/g, ' ');
var args = qs.split('&'); // parse out name/value pairs separated via &
// split out each name=value pair
for (var i = 0; i < args.length; i++) {
var pair = args[i].split('=');
var name = decodeURIComponent(pair[0]);
var value = (pair.length==2)
? decodeURIComponent(pair[1])
: name;
this.params[name] = value;
}
}
Querystring.prototype.get = function(key, default_) {
var value = this.params[key];
return (value != null) ? value : default_;
}
Querystring.prototype.contains = function(key) {
var value = this.params[key];
return (value != null);
}

View File

@ -1 +0,0 @@
function Querystring(qs){this.params={};var query_string=window.location.search;if(qs==null)qs=query_string.substring(1,query_string.length);if(qs.length==0)return;qs=qs.replace(/\+/g," ");var args=qs.split("&");for(var i=0;i<args.length;i++){var pair=args[i].split("=");var name=decodeURIComponent(pair[0]);var value=pair.length==2?decodeURIComponent(pair[1]):name;this.params[name]=value}}Querystring.prototype.get=function(key,default_){var value=this.params[key];return value!=null?value:default_};Querystring.prototype.contains=function(key){var value=this.params[key];return value!=null};

File diff suppressed because one or more lines are too long

View File

@ -1,8 +0,0 @@
<!--
File: partial/footer.tmpl
Used: All views, called after partial/footer.tmpl
-->
</body>
</html>

View File

@ -1,240 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<!--
File: partial/head.tmpl
Used: All views, called before anything else
-->
<head>
<title>
<TMPL_IF NAME="NAME"><TMPL_VAR ESCAPE="HTML" NAME="NAME"> (</TMPL_IF>Munin<TMPL_LOOP NAME="PATH"><TMPL_IF NAME="pathname"> :: <TMPL_VAR ESCAPE="HTML" NAME="pathname"></TMPL_IF></TMPL_LOOP><TMPL_IF NAME="NAME">)</TMPL_IF>
</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="Auto-generated by Munin">
<TMPL_UNLESS NAME="SHOW_ZOOM_JS">
<meta http-equiv="refresh" content="300" />
</TMPL_UNLESS>
<link rel="shortcut icon" type="image/x-icon" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon.ico" />
<link rel="icon" type="image/png" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon.png" />
<link href="<TMPL_VAR NAME='R_PATH' />/static/css/bootstrap4.min.css" rel="stylesheet" />
<link href="<TMPL_VAR NAME='R_PATH' />/static/css/style-munstrap.min.css" rel="stylesheet" />
<script src="<TMPL_VAR NAME='R_PATH' />/static/js/jquery.min.js"></script>
<script src="<TMPL_VAR NAME='R_PATH' />/static/js/lazysizes.min.js" async></script>
<script src="<TMPL_VAR NAME='R_PATH' />/static/js/bootstrap4.min.js"></script>
<script src="<TMPL_VAR NAME='R_PATH' />/static/js/typeahead.bundle.min.js"></script>
<script>
// This is used to build the navigation quick search - there is no backend, so we have to do
// it all client side.
//
// As a curious side note, commenting out the template loops and whatnot allows vscode to parse
// the javascript - so please note that the commented out TMPL directives STILL FUNCTION.
var gen_basegroups = {
// <TMPL_LOOP NAME="ROOTGROUPS">
"<TMPL_VAR NAME='NAME' />" : {
"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL'>",
"compare" : {
// <TMPL_IF NAME="COMPARE">
"Day" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_LOOP NAME='PATH' /><TMPL_IF NAME='pathname'><TMPL_VAR ESCAPE='URL' NAME='PATHNAME' />/</TMPL_IF></TMPL_LOOP>comparison-day.html",
"Week" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_LOOP NAME='PATH' /><TMPL_IF NAME='pathname'><TMPL_VAR ESCAPE='URL' NAME='PATHNAME' />/</TMPL_IF></TMPL_LOOP>comparison-week.html",
"Month" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_LOOP NAME='PATH' /><TMPL_IF NAME='pathname'><TMPL_VAR ESCAPE='URL' NAME='PATHNAME' />/</TMPL_IF></TMPL_LOOP>comparison-month.html",
"Year" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_LOOP NAME='PATH' /><TMPL_IF NAME='pathname'><TMPL_VAR ESCAPE='URL' NAME='PATHNAME' />/</TMPL_IF></TMPL_LOOP>comparison-year.html"
// </TMPL_IF>
}
},
// </TMPL_LOOP>
};
var gen_hosts = {
// <TMPL_LOOP NAME="ROOTGROUPS">
// <TMPL_LOOP NAME="GROUPS">
// <TMPL_IF NAME="NCATEGORIES">
"<TMPL_VAR ESCAPE='HTML' NAME='NAME' />" : {
"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL'>",
"services" : {
// <TMPL_LOOP NAME="CATEGORIES">
"<TMPL_VAR ESCAPE='HTML' NAME='NAME' />" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL' />",
// </TMPL_LOOP>
}
},
// </TMPL_IF>
// </TMPL_LOOP>
// </TMPL_LOOP>
};
var gen_cats = {
// <TMPL_LOOP NAME="GLOBALCATS">
"Category :: <TMPL_VAR NAME='NAME'> :: Day" : {
"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLDAY'>"
},
"Category :: <TMPL_VAR NAME='NAME'> :: Week" : {
"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLWEEK'>"
},
"Category :: <TMPL_VAR NAME='NAME'> :: Month" : {
"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLMONTH'>"
},
"Category :: <TMPL_VAR NAME='NAME'> :: Year" : {
"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLYEAR'>"
},
// </TMPL_LOOP>
};
function absolute(base, relative) {
var stack = base.split("/"),
parts = relative.split("/");
stack.pop(); // remove current file name (or empty string)
// (omit if "base" is the current folder without trailing slash)
for (var i=0; i<parts.length; i++) {
if (parts[i] == ".") { continue; }
if (parts[i] == "..") {
stack.pop();
} else {
stack.push(parts[i]);
}
}
return stack.join("/");
}
var navMap = [];
$.each(gen_cats, function(name, obby) {
navMap.push( { "name" : name, "link" : absolute(location.href, obby.baseurl) } );
});
$.each(gen_hosts, function(name, obby) {
var host_name = name;
navMap.push( { "name" : "Host :: " + name, "link" : absolute(location.href, obby.baseurl) });
$.each(obby.services, function(svcname, url){
navMap.push( { "name" : "Service :: " + host_name + " :: " + svcname, "link" : absolute(location.href, url) });
});
});
$.each(gen_basegroups, function(name, obby) {
var host_name = name;
navMap.push( { "name" : "Host :: " + name, "link" : absolute(location.href, obby.baseurl) });
$.each(obby.compare, function(svcname, url){
navMap.push( { "name" : "Compare :: " + host_name + " :: " + svcname, "link" : absolute(location.href, url) });
});
});
var navMapB = new Bloodhound({
datumTokenizer: function (d) { return Bloodhound.tokenizers.whitespace(d.name); },
queryTokenizer: Bloodhound.tokenizers.whitespace,
identify: function (obj) { return obj.link; },
local: navMap
});
$(document).ready(function(){
$('#findthehost').typeahead({
hint: true,
highlight: true,
minLength: 2,
},
{
name: 'navMap',
limit: 10,
display: 'link',
source: navMapB,
templates: {
suggestion: function (data) {
return '<div>' + data.name + '</div>';
}
}
}
);
//$('#findthehost').on('typeahead:change',function(){ $('#formy1').submit(); });
$('#findthehost').on('typeahead:select',function(){ $('#formy1').submit(); });
$('#formy1').on('submit', function(){
inputVal = $('#findthehost').val();
if ( inputVal.substring(0, 4) == "http" ) {
window.location.href = inputVal;
} else {
$('#findthehost').typeahead('val', '');
}
return false;
});
});
</script>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-3">
<a class="navbar-brand" href="<TMPL_VAR NAME='R_PATH' />"><span class="munin-icon"></span> MUNIN</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="<TMPL_VAR NAME='R_PATH' />">Home</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarProblems" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Problems
</a>
<div class="dropdown-menu" aria-labelledby="navbarProblems">
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/problems.html#critical"><span class="badge alert-danger mr-2"><TMPL_VAR NAME="NCRITICAL"></span>Critical</a>
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/problems.html#warnings"><span class="badge alert-warning mr-2"><TMPL_VAR NAME="NWARNING"></span>Warning</a>
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/problems.html#unknowns"><span class="badge alert-info mr-2"><TMPL_VAR NAME="NUNKNOWN"></span>Unknown</a>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarGroups" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Groups
</a>
<div class="dropdown-menu" aria-labelledby="navbarGroups">
<TMPL_LOOP NAME="ROOTGROUPS">
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL'>"><TMPL_VAR NAME="NAME"></a>
</TMPL_LOOP>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarHosts" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Hosts
</a>
<div class="dropdown-menu" aria-labelledby="navbarHosts">
<TMPL_LOOP NAME="ROOTGROUPS">
<TMPL_LOOP NAME="GROUPS">
<TMPL_IF NAME="NCATEGORIES">
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL'>"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a>
</TMPL_IF>
</TMPL_LOOP>
</TMPL_LOOP>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarCats" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Categories
</a>
<div class="dropdown-menu" aria-labelledby="navbarCats">
<TMPL_LOOP NAME="GLOBALCATS">
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLDAY'>"><TMPL_VAR NAME="NAME"> - Day</a>
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLWEEK'>"><TMPL_VAR NAME="NAME"> - Week</a>
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLMONTH'>"><TMPL_VAR NAME="NAME"> - Month</a>
<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLYEAR'>"><TMPL_VAR NAME="NAME"> - Year</a>
<TMPL_IF NAME="__first__"><div class="dropdown-divider"></div></TMPL_IF>
<TMPL_IF NAME="__inner__"><div class="dropdown-divider"></div></TMPL_IF>
</TMPL_LOOP>
</div>
</li>
</ul>
<form id="formy1" class="form-inline my-2 my-lg-0 w-25">
<input class="form-control mr-sm-2 w-100" type="text" id="findthehost" placeholder="Host or Service" aria-label="Search">
</form>
</div>
</nav>
<div class="container">
<TMPL_INCLUDE NAME="logo_navigation.tmpl">