Projet

Général

Profil

Révision 12ded312

ID12ded312fce160f8b50fa28eae3bb99d0bc9c087
Parent bc2dc914
Enfant a4f8f332

Ajouté par JTSage il y a plus de 5 ans

- 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"

Voir les différences:

templates/muncollapse/.gitignore
1
static/img/
2
static/css/bootstrap.min.css
3
static/js/bootstrap.min.js
4
static/js/jquery.min.js
5
static/js/lazysizes.min.js
6
static/js/typeahead.bundle.min.js
templates/muncollapse/Makefile
1
# MunCollapsible
2
#
3
# Makefile for the MunCollapsible template.
4

  
5
# HTTP Fetch program to use.  Called as $(HTTP_FETCH) <output_file> <input_url>
6
#
7
# Swap the comments to use curl instead.
8
HTTP_FETCH = wget -nv -O
9
#HTTP_FETCH = curl -s -w "%{http_code} - %{filename_effective} - %{size_download} bytes\n" -o
10

  
11

  
12
# The versions of the external libraries to use.
13
BOOTSTRAP_VERSION = 4.4.1
14
JQUERY_VERSION    = 3.4.1.slim
15
TYPEAHEAD_VERSION = latest
16

  
17
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
18
FAVICON_BASEURL = https://raw.githubusercontent.com/munin-monitoring/munin/master/web/static/img/favicons/
19

  
20
LOGO_URL = https://raw.githubusercontent.com/munin-monitoring/munin/master/web/static/img/logo-h.png
21

  
22
BOOTSTRAP_CSS_URL = https://stackpath.bootstrapcdn.com/bootstrap/$(BOOTSTRAP_VERSION)/css/bootstrap.min.css
23
BOOTSTRAP_JS_URL  = https://stackpath.bootstrapcdn.com/bootstrap/$(BOOTSTRAP_VERSION)/js/bootstrap.bundle.min.js
24
JQUERY_JS_URL     = https://code.jquery.com/jquery-$(JQUERY_VERSION).min.js
25
TYPEAHEAD_JS_URL  = https://twitter.github.io/typeahead.js/releases/$(TYPEAHEAD_VERSION)/typeahead.bundle.js
26
LAZYSIZES_URL     = http://afarkas.github.io/lazysizes/lazysizes.min.js
27

  
28
CWD := $(abspath $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))))
29

  
30

  
31
main:
32
	@echo $(CWD)
33
	@echo Downloading External Libraries...
34

  
35
	$(HTTP_FETCH) $(CWD)/static/css/bootstrap.min.css $(BOOTSTRAP_CSS_URL)
36
	$(HTTP_FETCH) $(CWD)/static/js/bootstrap.min.js $(BOOTSTRAP_JS_URL)
37
	$(HTTP_FETCH) $(CWD)/static/js/jquery.min.js $(JQUERY_JS_URL)
38
	$(HTTP_FETCH) $(CWD)/static/js/typeahead.bundle.min.js $(TYPEAHEAD_JS_URL)
39
	$(HTTP_FETCH) $(CWD)/static/js/lazysizes.min.js $(LAZYSIZES_URL)
40

  
41
	@echo Downloading Logo...
42
	@mkdir -p $(CWD)/static/img
43
	$(HTTP_FETCH) $(CWD)/static/img/logo-munin.png $(LOGO_URL)
44

  
45
	@echo Downloading Favicon Files...
46

  
47
	@mkdir -p $(CWD)/static/img/favicon
48
	@for file in ${FAVICON_FILES}; do \
49
		eval $(HTTP_FETCH) $(CWD)/static/img/favicon/$${file} $(FAVICON_BASEURL)$${file}; \
50
	done
51

  
52

  
53

  
54
	
templates/muncollapse/README.md
1
# MunCollapse
2

  
3
Alternative Munin 2.x templates based on Twitter Bootstrap using collapsibles.
4

  
5
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.
6

  
7
#### Overview Sample Image
8
<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>
9

  
10
[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.
11

  
12
---
13

  
14
## Installation
15

  
16
### 1. Clone the munin-monitoring/contrib repo to a temporary location:
17

  
18
```
19
$ cd /opt
20
$ git clone https://github.com/munin-monitoring/contrib.git
21
```
22

  
23
### 2. Fetch the template libraries
24

  
25
```
26
$ cd /opt/contrib/templates/muncollapse/
27
$ make
28
```
29

  
30
### 3. Place the template in an appropriate safe place
31

  
32
Ubuntu shown - other distros may prefer ```/usr/local/share/munin/...```
33

  
34
```
35
$ mkdir /usr/share/munin/template
36
$ mkdir /usr/share/munin/template/muncollapse
37
```
38
__NOTE__: If this step fails, your munin installation may use ```/usr/local/share/munin/...``` instead!
39

  
40
```
41
$ cp -r /opt/contrib/templates/muncollapse/templates /usr/share/munin/template/muncollapse/
42
$ cp -r /opt/contrib/templates/muncollapse/static /usr/share/munin/template/muncollapse/
43
```
44

  
45
### 4. Edit your ```munin.conf``` file.
46

  
47
Typically located at ```/etc/munin.conf```
48

  
49
__FIND AND CHANGE:__ (near the top of the file)
50

  
51
```
52
# Where to look for the HTML templates
53
#
54
#tmpldir        /etc/munin/templates
55

  
56
# Where to look for the static www files
57
#
58
#staticdir /etc/munin/static
59
```
60

  
61
__TO:__
62
```
63
# Where to look for the HTML templates
64
#
65
tmpldir /usr/share/munin/template/muncollapse/templates
66

  
67
# Where to look for the static www files
68
#
69
staticdir /usr/share/munin/template/muncollapse/static
70
```
71

  
72
### 5. [Optional / Recommended] Clean out the old generated files.
73

  
74
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.
75

  
76
__NOTE:__ Ubuntu shown, other distributions may be in ```/var/www/munin/```
77

  
78
```
79
$ rm -rf /var/cache/munin/www/*
80
```
81

  
82
### 6. Wait Patiently
83

  
84
```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.
85

  
86
---
87

  
88
## Revert to Official Munin Template
89

  
90
### 1. Edit your ```munin.conf``` file.
91

  
92
Typically located at ```/etc/munin.conf```
93

  
94
__FIND AND CHANGE:__ (near the top of the file - comment these lines out!)
95

  
96
# Where to look for the HTML templates
97
#
98
#tmpldir /usr/share/munin/template/muncollapse/templates
99

  
100
# Where to look for the static www files
101
#
102
#staticdir /usr/share/munin/template/muncollapse/static
103

  
104
### 2. [Optional / Recommended] Clean up
105

  
106
Remove the files from step #1 & #3 above, and repeat step #5 & #6.
107

  
108
---
109

  
110
## Samples
111

  
112
#### View of a group:
113
<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>
114

  
115
#### View of a specific node:
116
<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>
117

  
118

  
119
#### Zoom feature:
120
<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>
121

  
122

  
123
---
124

  
125
## Munin Compatibility
126

  
127
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.
128

  
129
---
130

  
131
### Browser Compatibility
132

  
133
For this template set, Internet Explorer support has been dropped for the dynamic zoom functions. Everything else should work across all browsers.
templates/muncollapse/static/css/style-munstrap.css
18 18
}
19 19

  
20 20
img#zoom_image {
21
    margin-bottom: 15px;
21
    border: none;
22 22
}
23 23

  
24 24
ul.groupview, ul.groupview ul {
......
27 27

  
28 28
.munin-icon {
29 29
    background: url(../img/logo-munin.png) left top;
30
    margin-top: -6px;
31
    width: 35px;
32
    height: 35px;
30
    width: 115px;
31
    height: 30px;
33 32
    display: block;
34
    float: left;
35 33
}
36 34

  
37 35

  
templates/muncollapse/static/js/dynazoom.js
1
/* MunCollapse Template DynaZoom JavaScript File
2
*
3
* Notes:
4
* 
5
*  - No Internet Explorer support (uses "URLSearchParams")
6
*  - This is not even really a fork of the upstream version any more
7
*  - Drops upstream requirement of "QueryString" include (URL.URLSearchParams)
8
*  - Drops upstream requirement of "FormatDate" include (Date.toISOString())
9
*/
10

  
11
URLSearchParams.prototype.getDefault = function ( name, value ) {
12
    // Overload URLSearchParams to allow "default" values.
13
    return ( this.get( name ) === null ) ? value : this.get( name );
14
};
15

  
16
function refreshZoom( query, form, image ) {
17
    //INIT
18
    var qs = new URLSearchParams( query.split( "\?" )[ 1 ] );
19
    
20
    init();
21

  
22
    refreshImg();
23
    
24
    var start_epoch = parseInt( qs.getDefault( "rst_start_epoch", form.start_epoch.value ), 10 );
25
    var stop_epoch  = parseInt( qs.getDefault( "rst_stop_epoch", form.stop_epoch.value ), 10 );
26

  
27
    var highLighter      = document.getElementById( "image-overlay" );
28
    var gutterOffsetLeft = 66;
29
    var highlightStartX  = 0;
30
    var clickCounter     = 0;
31
    var relativeStartX   = 0;
32
    var graph_shown_width;
33
    var epoch_shown_start;
34
    var epoch_shown_stop;
35
    var eachPixelEpoch;
36

  
37
    form.plugin_name.onblur   = refreshImg;
38
    form.start_iso8601.onblur = majDates;
39
    form.stop_iso8601.onblur  = majDates;
40
    form.start_epoch.onblur   = function() { refreshImg(); updateStartStop(); };
41
    form.stop_epoch.onblur    = function() { refreshImg(); updateStartStop(); };
42
    form.lower_limit.onblur   = refreshImg;
43
    form.upper_limit.onblur   = refreshImg;
44
    form.size_x.onblur        = refreshImg;
45
    form.size_y.onblur        = refreshImg;
46
    form.btnReset.onclick     = reset;
47
    form.btnShowDay.onclick   = function() { showPeriod( 1 ); };
48
    form.btnShowWeek.onclick  = function() { showPeriod( 2 ); };
49
    form.btnShowMonth.onclick = function() { showPeriod( 3 ); };
50
    form.btnShowYear.onclick  = function() { showPeriod( 4 ); };
51
    form.onsubmit             = function() { document.activeElement.blur(); refreshImg(); return false; };
52

  
53
    // Sets the onClick handler
54
    image.onclick = click;
55

  
56
    //FUNCTIONS
57
    function init() {
58
        form.plugin_name.value = qs.getDefault( "plugin_name", "localdomain/localhost.localdomain/if_eth0" );
59
        form.start_epoch.value = qs.getDefault( "start_epoch", "1236561663" );
60
        form.stop_epoch.value  = qs.getDefault( "stop_epoch",  "1237561663" );
61
        form.lower_limit.value = qs.getDefault( "lower_limit", "" );
62
        form.upper_limit.value = qs.getDefault( "upper_limit", "" );
63
        form.size_x.value      = qs.getDefault( "size_x",      "" );
64
        form.size_y.value      = qs.getDefault( "size_y",      "" );
65

  
66
        updateStartStop();
67
    }
68

  
69
    function reset( event ) {
70
        init();
71

  
72
        //Can be not the initial ones in case of manual refresh
73
        form.start_epoch.value = start_epoch;
74
        form.stop_epoch.value  = stop_epoch;
75
        updateStartStop();
76

  
77
        //Redraw
78
        scale = refreshImg();
79

  
80
        //Reset gui
81
        clickCounter                = 0;
82
        image.onmousemove           = undefined;
83
        form.start_iso8601.disabled = false;
84
        form.stop_iso8601.disabled  = false;
85
        form.start_epoch.disabled   = false;
86
        form.stop_epoch.disabled    = false;
87
        highLighter.style.left      = "0px";
88
        highLighter.style.width     = "2px";
89
        highLighter.style.display   = "none";
90

  
91
        document.activeElement.blur();
92
        return false;
93
    }
94

  
95
    function refreshImg(event) {
96
        image.src = qs.getDefault( "cgiurl_graph", "/munin-cgi/munin-cgi-graph" ) + "/" +
97
            form.plugin_name.value +
98
            "-pinpoint=" + parseInt( form.start_epoch.value, 10 ) + "," + parseInt( form.stop_epoch.value, 10 ) +
99
            ".png" + "?" +
100
            "&lower_limit=" + form.lower_limit.value +
101
            "&upper_limit=" + form.upper_limit.value +
102
            "&size_x=" + form.size_x.value +
103
            "&size_y=" + form.size_y.value;
104
    }
105

  
106
    function updateStartStop() {
107
        form.start_iso8601.value = new Date( form.start_epoch.value * 1000 ).toISOString();
108
        form.stop_iso8601.value  = new Date( form.stop_epoch.value * 1000 ).toISOString();
109
    }
110

  
111
    function majDates( event ) {
112
        var lowLimit    = new Date(),
113
            topLimit    = new Date(),
114
            date_parsed = null;
115

  
116
        lowLimit.setFullYear( lowLimit.getFullYear() - 1 );
117

  
118
        date_parsed = new Date( Date.parse( form.start_iso8601.value ) || lowLimit.getTime() );
119
        form.start_epoch.value   = Math.floor( date_parsed.getTime() / 1000 );
120

  
121
        date_parsed = new Date( Date.parse( form.stop_iso8601.value) || topLimit.getTime() );
122
        form.stop_epoch.value   = Math.floor( date_parsed.getTime() / 1000 );
123

  
124
        updateStartStop();
125

  
126
        refreshImg();
127
    }
128

  
129
    function click( event ) {
130
        var relativeClickX = getClickLocation( event ),
131
            thisEpoch      = null;
132

  
133
        switch ( ( clickCounter++ ) % 3 ) {
134
            case 0: // First click of the displayed graph
135
                graph_shown_width = parseInt( form.size_x.value, 10) ;
136
                epoch_shown_start = parseInt( form.start_epoch.value,10 );
137
                epoch_shown_stop  = parseInt( form.stop_epoch.value, 10 );
138
                eachPixelEpoch    = ( ( epoch_shown_stop - epoch_shown_start ) / graph_shown_width );
139
                relativeStartX    = ( relativeClickX < 0 ? 0 : relativeClickX );
140

  
141
                form.start_iso8601.disabled = true;
142
                form.stop_iso8601.disabled  = true;
143
                form.start_epoch.disabled   = true;
144
                form.stop_epoch.disabled    = true;
145
                
146
                highlightStartX           = event.pageX;
147
                highLighter.style.left    = ( relativeStartX + gutterOffsetLeft + image.offsetLeft ) + "px";
148
                highLighter.style.display = "block";
149

  
150
                form.start_epoch.value = offsetEpoch( relativeClickX );
151
                updateStartStop();
152

  
153
                image.onmousemove = divMouseMove;
154

  
155
                break;
156
            case 1: // Second (end) click of the displayed graph
157
                thisEpoch = offsetEpoch( relativeClickX );
158

  
159
                image.onmousemove           = undefined;
160
                form.start_iso8601.disabled = false;
161
                form.stop_iso8601.disabled  = false;
162
                form.start_epoch.disabled   = false;
163
                form.stop_epoch.disabled    = false;
164

  
165
                // For negative values, assume we want a new start point and the old end point.
166
                // If it's not, set it.
167
                if ( thisEpoch > form.start_epoch.value ) {
168
                    form.stop_epoch.value = thisEpoch;
169
                } else {
170
                    form.stop_epoch.value   = Math.floor( epoch_shown_stop );
171
                    highLighter.style.width = ( graph_shown_width - relativeStartX ) + "px";
172
                }
173
                updateStartStop();
174

  
175
                break;
176
            case 2: // Nevermind or Do It.
177
                thisEpoch = offsetEpoch( relativeClickX );
178

  
179
                if ( thisEpoch >= form.start_epoch.value && thisEpoch <= form.stop_epoch.value ) {
180
                    refreshImg();
181
                } else {
182
                    form.start_epoch.value = epoch_shown_start;
183
                    form.stop_epoch.value  = epoch_shown_stop;
184
                    updateStartStop();
185
                }
186

  
187
                highLighter.style.left    = "0px";
188
                highLighter.style.width   = "2px";
189
                highLighter.style.display = "none";
190
        }
191
    }
192

  
193
    function divMouseMove( event ) {
194
        var diff           = event.pageX - highlightStartX,
195
            maxDiff        = graph_shown_width - relativeStartX,
196
            relativeClickX = getClickLocation( event );
197

  
198
        form.stop_epoch.value = offsetEpoch( relativeClickX );
199
        updateStartStop();
200

  
201
        highLighter.style.width = ( ( diff < 2 ) ? 2 : ( diff > maxDiff ? maxDiff : diff ) ) + "px";
202
    }
203

  
204
    function offsetEpoch( clickX ) {
205
        if ( clickX < 0 ) { return Math.floor( epoch_shown_start ); }
206

  
207
        if ( clickX > graph_shown_width ) { return Math.floor( epoch_shown_stop ); }
208

  
209
        return Math.floor( epoch_shown_start + ( clickX * eachPixelEpoch ) );
210
    }
211

  
212
    function getClickLocation( event ) {
213
        return ( event.pageX - image.getBoundingClientRect().x - gutterOffsetLeft );
214
    }
215

  
216
    function showPeriod( period ) {
217
        var now  = new Date(),
218
            past = new Date();
219

  
220
        switch (period) {
221
            case 1:
222
                past.setDate( past.getDate() - 1 ); break;
223
            case 2:
224
                past.setDate( past.getDate() - 7 ); break;
225
            case 3:
226
                past.setMonth( past.getMonth() - 1 ); break;
227
            case 4:
228
                past.setFullYear( past.getFullYear() - 1 ); break;
229
        }
230

  
231
        form.start_epoch.value = Math.floor( past.getTime() / 1000 );
232
        form.stop_epoch.value  = Math.floor( now.getTime() / 1000 );
233

  
234
        updateStartStop();
235
        refreshImg();
236
        document.activeElement.blur();
237
        return false;
238
    }
239
}
templates/muncollapse/templates/munin-comparison-day.tmpl
1 1
<TMPL_INCLUDE NAME="partial/head.tmpl" />
2 2

  
3
<h2 class="mb-3">Comparison: by day</h2>
4

  
5
<TMPL_INCLUDE NAME="partial/compare_navigation.tmpl" />
6

  
7 3
<!--
8 4
	File: munin-comparison-day.tmpl
9 5

  
templates/muncollapse/templates/munin-comparison-month.tmpl
1 1
<TMPL_INCLUDE NAME="partial/head.tmpl" />
2 2

  
3
<h2 class="mb-3">Comparison: by month</h2>
4

  
5
<TMPL_INCLUDE NAME="partial/compare_navigation.tmpl" />
6

  
7 3
<!--
8 4
	File: munin-comparison-monthy.tmpl
9 5

  
templates/muncollapse/templates/munin-comparison-week.tmpl
1 1
<TMPL_INCLUDE NAME="partial/head.tmpl" />
2 2

  
3
<h2 class="mb-3">Comparison: by week</h2>
4

  
5
<TMPL_INCLUDE NAME="partial/compare_navigation.tmpl" />
6

  
7 3
<!--
8 4
	File: munin-comparison-week.tmpl
9 5

  
templates/muncollapse/templates/munin-comparison-year.tmpl
1 1
<TMPL_INCLUDE NAME="partial/head.tmpl" />
2 2

  
3
<h2 class="mb-3">Comparison: by year</h2>
4

  
5
<TMPL_INCLUDE NAME="partial/compare_navigation.tmpl" />
6

  
7 3
<!--
8 4
	File: munin-comparison-year.tmpl
9 5

  
templates/muncollapse/templates/munin-domainview.tmpl
7 7
-->
8 8

  
9 9
<script>
10
	$(document).ready(function() {
11
		$('.custom-collapse').on('click', function() {
12
			$(this).parent().find('.collapse').collapse('toggle');
10
	$( document ).ready( function() {
11
		$( ".custom-collapse" ).on( "click", function() {
12
			$( this ).parent().find( ".collapse" ).collapse( "toggle" );
13 13
			return false;
14
		});
15
		$('.custom-collapse-all').on('click', function() {
16
			if ( $(this).hasClass('all-hide') ) {
17
				$(this).parent().parent().find('.collapse').collapse('hide');
14
		} );
15
		$( ".custom-collapse-all" ).on( "click", function() {
16
			if ( $( this ).hasClass( "all-hide" ) ) {
17
				$( this ).parent().parent().find( ".collapse" ).collapse( "hide" );
18 18
			} else {
19
				$(this).parent().parent().find('.collapse').collapse('show');
19
				$( this ).parent().parent().find( ".collapse" ).collapse( "show" );
20 20
			}
21 21
			return false;
22
		});
23
	});
22
		} );
23
	} );
24 24
</script>
25 25

  
26 26
<div class="btn-group w-100 mb-3">
templates/muncollapse/templates/munin-nodeview.tmpl
13 13
</div>
14 14

  
15 15
<script>
16
	$(document).ready(function (){
16
	$( document ).ready( function () {
17 17
		// Should we auto-scroll when a service category is opened?
18 18
		window.doScroll = false;
19 19
		// Store display status of graph periods
20
		window.gsets = {
20
		window.gsets    = {
21 21
			"day"   : true,
22 22
			"week"  : true,
23 23
			"month" : false,
24 24
			"year"  : false
25 25
		};
26 26

  
27
		$('.graph-click').on('click', function(){
27
		$( ".graph-click" ).on( "click", function() {
28 28
			// This shows / hides graph periods.
29
			var gset = $(this).data("gset");
30
			var newState = ! gsets[gset];
31
			gsets[gset] = newState;
29
			var gset      = $( this ).data( "gset" ),
30
				newState  = ! gsets[ gset ];
31

  
32
			gsets[ gset ] = newState;
33

  
32 34
			$(this)
33
				.toggleClass("btn-outline-success btn-outline-secondary")
34
				.find(".gset-state")
35
				.text((newState ? "Shown" : "Hidden"));
36
			$('.graph-' + gset).toggleClass("d-none");
35
				.toggleClass( "btn-outline-success btn-outline-secondary" )
36
				.find( ".gset-state" )
37
				.text( ( newState ? "Shown" : "Hidden" ) );
38

  
39
			$( ".graph-" + gset ).toggleClass( "d-none" );
40

  
37 41
			return false;
38
		});
39
		$('.tab-click').on('click', function() {
42
		} );
43

  
44
		$( ".tab-click" ).on( "click", function() {
45
			var theCollapse = $( "#" + $( this ).data( "target" ) + "_coll" );
46

  
40 47
			window.doScroll = true; // Do scroll when we click a tab header
41
			var theCollapse = '#' + $(this).data("target") + "_coll";
42 48

  
43
			if ( $(theCollapse).hasClass('show') ) {
49
			if ( theCollapse.hasClass( "show" ) ) {
44 50
				// Already open, lets just trigger the event.
45
				$(theCollapse).trigger('shown.bs.collapse');
51
				theCollapse.trigger( "shown.bs.collapse" );
46 52
			} else {
47
				// Close all
48
				$(".card-collapse.collapse").collapse("hide");
49
				// Open the one we want
50
				$(theCollapse).collapse('show');
53
				// Close all and open the one we want
54
				$( ".card-collapse.collapse" ).collapse( "hide" );
55
				theCollapse.collapse( "show" );
51 56
			}
52 57
			// Do nothing with the click otherwise.
53 58
			return false;
54
		});
59
		} );
55 60

  
56 61
		// Actual scroll function
57
		$('.collapse').on('shown.bs.collapse', function(e) {
62
		$( ".collapse" ).on( "shown.bs.collapse", function( e ) {
58 63
			if ( window.doScroll ) {
59
				var $card = $(this).closest('.card');
60
				$('html,body').animate({
61
					scrollTop: $card.offset().top
62
				}, 500);
64
				$( document ).scrollTop( $( this ).closest( ".card" ).offset().top );
63 65
				window.doScroll = false;
64 66
			}
65
		});
67
		} );
66 68
		
67

  
68 69
		// If we came here with a hash, open that category and scroll to it.
69 70
		if ( location.hash != "" ) {
70 71
			window.doScroll = true;
71
			$(location.hash + "_coll" + '.collapse').collapse('show');
72
			$( location.hash + "_coll" + ".collapse" ).collapse( "show" );
72 73
		}
73 74

  
74 75
		// Alternatively, if something changed the hash (looking at you search feature), we should
75 76
		// pretend that the user clicked on the link for that category.
76
		$( window ).on( 'hashchange', function( e ) {
77
		$( window ).on( "hashchange", function( e ) {
77 78
			var newPlace = window.location.hash.substr(1);;
78
			$(".tab-click[data-target='" + newPlace + "']").trigger("click");
79
			$( ".tab-click[data-target='" + newPlace + "']" ).trigger( "click" );
79 80
		} );
80 81

  
81 82
		// If there is only one service group, show it by default.
82
		if ( $(".card-collapse.collapse").length < 2 ) {
83
			$(".card-collapse.collapse").collapse('show');
84
		}
83
		if ( $( ".card-collapse.collapse" ).length < 2 ) { $( ".card-collapse.collapse" ).collapse( "show" ); }
85 84

  
86
		$(".close-all-tabs").on("click", function(){
87
			$('.card-collapse.collapse').collapse('hide');
88
			return false;
89
		});
90
		$(".open-all-tabs").on("click", function() {
91
			$('.card-collapse.collapse').collapse('show');
92
			return false;
93
		});
85
		$( ".close-all-tabs" ).on( "click", function() { $( ".card-collapse.collapse" ).collapse( "hide" ); return false; } );
86
		$( ".open-all-tabs"  ).on( "click", function() { $( ".card-collapse.collapse" ).collapse( "show" ); return false; } );
94 87
	});
95 88
</script>
96 89

  
templates/muncollapse/templates/munin-serviceview.tmpl
20 20
	
21 21
	<div class="row">
22 22
		<div class="col-md-6">
23
			<!-- <TMPL_VAR NAME="ZOOMDAY"> -->
23 24
			<img data-href="<TMPL_VAR NAME='ZOOMDAY' />" src="<TMPL_VAR NAME='IMGDAY' />" 
24 25
				alt="daily graph"
25 26
				class="img-fluid img-zoom i<TMPL_IF NAME='STATE_WARNING'> warn</TMPL_IF><TMPL_IF NAME='STATE_CRITICAL'> crit</TMPL_IF>"
......
109 110
</TMPL_LOOP>
110 111

  
111 112
<div id="zoom" class="modal fade">
112
	<div class="modal-dialog modal-lg">
113
	<div class="modal-dialog modal-xl">
113 114
		<div class="modal-content">
114 115
			<div class="modal-body">
115 116
			
116 117
				<div class="row">
117 118
					<div class="col-md-12">
118
						<img alt="Zoom Image - Requires munin-cgi-graph" id="zoom_image" class="img-fluid"/>
119
						<img alt="Zoom Image - Requires munin-cgi-graph" id="zoom_image" class="no-refresh d-block mx-auto"/>
120
						<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>
119 121
					</div>
120 122
				</div>
121 123
				
122
				<div class="row">
124
				<div class="row mt-3">
123 125
					<div class="col-md-12">
124 126
						<form class="form-horizontal" role="form" name="zoom_form" id="zoom_form">
125 127
							<div class="form-group row">
126 128
								<label for="plugin_name" class="col-sm-2 control-label">Plugin Name</label>
127 129
								<div class="col-sm-10">
128
									<input type="text" class="form-control" name="plugin_name" id="plugin_name">
130
									<input type="text" class="form-control form-control-sm" name="plugin_name" id="plugin_name">
129 131
								</div>
130 132
							</div>
131 133
							<div class="form-group row">
132 134
								<label for="start_iso8601" class="col-sm-2 control-label">Time Start/Stop</label>
133 135
								<div class="col-sm-5">
134
									<input type="text" class="form-control" name="start_iso8601" id="start_iso8601">
136
									<input type="text" class="form-control form-control-sm" name="start_iso8601" id="start_iso8601">
135 137
								</div>
136 138
								<div class="col-sm-5">
137
									<input type="text" class="form-control" name="stop_iso8601" id="stop_iso8601">
139
									<input type="text" class="form-control form-control-sm" name="stop_iso8601" id="stop_iso8601">
138 140
								</div>
139 141
							</div>
140 142
							<div class="form-group row">
141 143
								<label for="start_epoch" class="col-sm-2 control-label">Epoch Start/Stop</label>
142 144
								<div class="col-sm-5">
143
									<input type="text" class="form-control" name="start_epoch" id="start_epoch">
145
									<input type="text" class="form-control form-control-sm" name="start_epoch" id="start_epoch">
144 146
								</div>
145 147
								<div class="col-sm-5">
146
									<input type="text" class="form-control" name="stop_epoch" id="stop_epoch">
148
									<input type="text" class="form-control form-control-sm" name="stop_epoch" id="stop_epoch">
147 149
								</div>
148 150
							</div>
149 151
							<div class="form-group row">
150 152
								<label for="lower_limit" class="col-sm-2 control-label">Limit Low/High</label>
151 153
								<div class="col-sm-5">
152
									<input type="text" class="form-control" name="lower_limit" id="lower_limit">
154
									<input type="text" class="form-control form-control-sm" name="lower_limit" id="lower_limit">
153 155
								</div>
154 156
								<div class="col-sm-5">
155
									<input type="text" class="form-control" name="upper_limit" id="upper_limit">
157
									<input type="text" class="form-control form-control-sm" name="upper_limit" id="upper_limit">
156 158
								</div>
157 159
							</div>
158 160
							<div class="form-group row">
159 161
								<label for="size_x" class="col-sm-2 control-label">Width/Height</label>
160 162
								<div class="col-sm-5">
161
									<div class="input-group">
163
									<div class="input-group input-group-sm">
162 164
										<input type="text" class="form-control" name="size_x" id="size_x">
163 165
										<span class="input-group-append"><span class="input-group-text">px</span></span>
164 166
									</div>
165 167
								</div>
166 168
								<div class="col-sm-5">
167
									<div class="input-group">
169
									<div class="input-group input-group-sm">
168 170
										<input type="text" class="form-control" name="size_y" id="size_y">
169 171
										<span class="input-group-append"><span class="input-group-text">px</span></span>
170 172
									</div>
......
173 175
							<div class="form-group row">
174 176
									<input type=hidden name="cgiurl_graph"/>
175 177
									<div class="btn-group w-100 mx-3">
176
										<button type="submit" class="btn btn-outline-success">Refresh</button>
177
										<button type="button" class="btn btn-outline-primary" name="btnReset">Reset</button>
178
										<button type="button" class="btn btn-outline-primary" data-dismiss="modal">Close</button>
178
										<button type="button" class="btn btn-outline-primary" name="btnReset">&#8634; Reset to Initial</button>
179
										<button type="button" class="btn btn-outline-info" name="btnShowDay">&#9201; Show Today</button>
180
										<button type="button" class="btn btn-outline-info" name="btnShowWeek">&#9201; Show Week</button>
181
										<button type="button" class="btn btn-outline-info" name="btnShowMonth">&#9201; Show Month</button>
182
										<button type="button" class="btn btn-outline-info" name="btnShowYear">&#9201; Show Year</button>
183
									</div>
184
									<div class="btn-group w-100 mx-3 mt-2">
185
										<button type="button" class="btn btn-outline-danger w-100" data-dismiss="modal">&times; Close</button>
179 186
									</div>
187
									<button type="submit" class="d-none">Hidden Submit Button - "onsubmit" needs this to exist.</button>
188
									
180 189
							</div>
181 190
						</form>
182 191
					</div>
......
185 194
				<div class="row">
186 195
					<div class="col-md-12">
187 196
						<div class="alert alert-info">
188
								<p>Zooming is very easy, it's done in 3 clicks (regular clicks, no drag&amp;drop):</p>
197
								<p>Zooming is very easy, it's done in 3 clicks ( regular clicks, no drag &amp; drop ):</p>
189 198
								<ol>
190 199
									<li>Click to define the start of zoom.</li>
191 200
									<li>Click to define the ending of zoom.</li>
192
									<li>Refresh.</li>
201
									<li>Click inside shaded area to zoom, outside to cancel.</li>
193 202
								</ol>
194
								<p>You can use the interactive form too.</p>
203
								<p><em>Shortcut:</em> To just set a new start of zoom, click before your start point for your second click.</p>
204
								<p class="mb-1">You can use the interactive form too.</p>
195 205
						</div>
196 206
					</div>
197 207
				</div>
......
202 212

  
203 213
<TMPL_INCLUDE NAME="partial/footer_pre.tmpl" />
204 214

  
205
<script src="<TMPL_VAR NAME='R_PATH'>/static/js/formatdate.min.js"></script>
206
<script src="<TMPL_VAR NAME='R_PATH'>/static/js/querystring.min.js"></script>
207
<script src="<TMPL_VAR NAME='R_PATH'>/static/js/dynazoom.min.js"></script>
215

  
216
<script src="<TMPL_VAR NAME='R_PATH'>/static/js/dynazoom.js"></script>
208 217
<script type="text/javascript">
209 218
	//Zoom modal opening
210
	$('.img-zoom').click(function(){
211
		var query = $(this).attr('data-href');
212
		var form = document.getElementById("zoom_form");
213
		var image = document.getElementById("zoom_image");
214
		
215
		form.onsubmit = function(){//Submit catching
216
			var qs = new Querystring(query);
217
			var src = "cgiurl_graph=" + qs.get("cgiurl_graph", "/munin-cgi/munin-cgi-graph")
218
				+ "&plugin_name=" + form.plugin_name.value
219
				+ "&start_epoch=" + form.start_epoch.value
220
				+ "&stop_epoch=" + form.stop_epoch.value
221
				+ "&rst_start_epoch=" + qs.get("start_epoch", "")
222
				+ "&rst_stop_epoch=" + qs.get("stop_epoch", "")
223
				+ "&lower_limit=" + form.lower_limit.value
224
				+ "&upper_limit=" + form.upper_limit.value
225
				+ "&size_x=" + form.size_x.value
226
				+ "&size_y=" + form.size_y.value
227
			;
228
			refreshZoom(src, form, image);
229
			return false;
230
		};
219
	$( ".img-zoom" ).click(function(){
220
		var query = $(this).attr( "data-href" );
221
		var form  = document.getElementById( "zoom_form" );
222
		var image = document.getElementById( "zoom_image" );
231 223
		
232 224
		refreshZoom(query, form, image);
233
		$('#zoom').modal('show');
225
		$( "#zoom" ).modal( "show" );
234 226
	});
235 227
</script>
236 228

  
237
<TMPL_INCLUDE NAME="partial/footer.tmpl" />
229
<TMPL_INCLUDE NAME="partial/footer.tmpl" />
templates/muncollapse/templates/partial/compare_navigation.tmpl
5 5
-->
6 6

  
7 7
<script>
8
	$(document).ready(function (){
8
	$( document ).ready( function (){
9 9
		// Should we auto-scroll when a service category is opened?
10 10
		window.doScroll = false;
11 11
		
12
		$('.tab-click').on('click', function() {
12
		$( ".tab-click" ).on( "click", function() {
13 13
			window.doScroll = true; // Do scroll when we click a tab header
14
			var theCollapse = '#' + $(this).data("target") + "_coll";
14
			var theCollapse = $( "#" + $( this ).data( "target" ) + "_coll" );
15 15

  
16
			if ( $(theCollapse).hasClass('show') ) {
16
			if ( theCollapse.hasClass( "show" ) ) {
17 17
				// Already open, lets just trigger the event.
18
				$(theCollapse).trigger('shown.bs.collapse');
18
				theCollapse.trigger( "shown.bs.collapse" );
19 19
			} else {
20
				// Close all
21
				$(".card-collapse.collapse").collapse("hide");
22
				// Open the one we want
23
				$(theCollapse).collapse('show');
20
				// Close all, and open the one we want
21
				$( ".card-collapse.collapse" ).collapse("hide" );
22
				theCollapse.collapse( "show" );
24 23
			}
25 24
			// Do nothing with the click otherwise.
26 25
			return false;
27 26
		});
28 27

  
29 28
		// Actual scroll function
30
		$('.collapse').on('shown.bs.collapse', function(e) {
29
		$( ".collapse" ).on( "shown.bs.collapse", function( e ) {
31 30
			if ( window.doScroll ) {
32
				var $card = $(this).closest('.card');
33
				$('html,body').animate({
34
					scrollTop: $card.offset().top
35
				}, 500);
31
				$( document ).scrollTop( $( this ).closest( ".card" ).offset().top );
36 32
				window.doScroll = false;
37 33
			}
38 34
		});
39 35
		
40 36

  
41 37
		// If there is only one service group, show it by default.
42
		if ( $(".card-collapse.collapse").length < 2 ) {
43
			$(".card-collapse.collapse").collapse('show');
44
		}
38
		if ( $( ".card-collapse.collapse" ).length < 2 ) { $( ".card-collapse.collapse" ).collapse( "show" ); }
45 39

  
46
		$(".close-all-tabs").on("click", function(){
47
			$('.card-collapse.collapse').collapse('hide');
48
			return false;
49
		});
50
		$(".open-all-tabs").on("click", function() {
51
			$('.card-collapse.collapse').collapse('show');
52
			return false;
53
		});
40
		$( ".close-all-tabs" ).on( "click", function() { $( ".card-collapse.collapse" ).collapse( "hide" ); return false; } );
41
		$( ".open-all-tabs"  ).on( "click", function() { $( ".card-collapse.collapse" ).collapse( "show" ); return false; } );
54 42
	});
55 43
</script>
56 44

  
templates/muncollapse/templates/partial/footer.tmpl
1
<!--
2
	File: partial/footer.tmpl
3

  
4
	Used: All views, called after partial/footer.tmpl
5
-->
6
<script>
7
	// Lightweight Cookie Library.
8
	!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(){})});
9
</script>
10
</body>
11
</html>
templates/muncollapse/templates/partial/footer_pre.tmpl
10 10
		<span class="text-muted"><small>
11 11
			This page was generated by <a href="http://www.munin-monitoring.org/">Munin</a>
12 12
			version <TMPL_VAR NAME="MUNIN_VERSION"> at <TMPL_VAR NAME="TIMESTAMP">
13
			with <a href="https://github.com/munin-monitoring/contrib/tree/master/templates/munstrap4/">MunStrap4</a> template.
13
			with <a href="https://github.com/munin-monitoring/contrib/tree/master/templates/muncollapse/">MunCollapse</a> template.
14 14
		</small></span>
15 15
	</div>
16 16
</footer>
17 17

  
18 18

  
19
<script src="<TMPL_VAR NAME='R_PATH' />/static/js/lazysizes.min.js" async></script>
templates/muncollapse/templates/partial/head.tmpl
1
<!DOCTYPE html>
2
<html lang="en">
3

  
4
<!--
5
	File: partial/head.tmpl
6

  
7
	Used: All views, called before anything else
8
-->
9

  
10
	<head>
11
		<title>
12
			<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>
13
		</title>
14
		<meta charset="utf-8">
15
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
16
		<meta name="description" content="">
17
		<meta name="author" content="Auto-generated by Munin">
18

  
19
		<link rel="apple-touch-icon" sizes="57x57" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-57x57.png">
20
		<link rel="apple-touch-icon" sizes="60x60" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-60x60.png">
21
		<link rel="apple-touch-icon" sizes="72x72" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-72x72.png">
22
		<link rel="apple-touch-icon" sizes="76x76" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-76x76.png">
23
		<link rel="apple-touch-icon" sizes="114x114" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-114x114.png">
24
		<link rel="apple-touch-icon" sizes="120x120" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-120x120.png">
25
		<link rel="apple-touch-icon" sizes="144x144" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-144x144.png">
26
		<link rel="apple-touch-icon" sizes="152x152" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-152x152.png">
27
		<link rel="apple-touch-icon" sizes="180x180" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/apple-touch-icon-180x180.png">
28
		<link rel="icon" type="image/png" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/favicon-32x32.png" sizes="32x32">
29
		<link rel="icon" type="image/png" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/favicon-194x194.png" sizes="194x194">
30
		<link rel="icon" type="image/png" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/favicon-96x96.png" sizes="96x96">
31
		<link rel="icon" type="image/png" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/android-chrome-192x192.png" sizes="192x192">
32
		<link rel="icon" type="image/png" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/favicon-16x16.png" sizes="16x16">
33
		<link rel="manifest" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/manifest.json" crossorigin="use-credentials">
34
		<link rel="shortcut icon" href="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/favicon.ico">
35
		<meta name="msapplication-TileColor" content="#00a300">
36
		<meta name="msapplication-TileImage" content="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/mstile-144x144.png">
37
		<meta name="msapplication-config" content="<TMPL_VAR NAME='R_PATH' />/static/img/favicon/browserconfig.xml">
38
		<meta name="theme-color" content="#076202">
39

  
40
		<link href="<TMPL_VAR NAME='R_PATH' />/static/css/bootstrap.min.css" rel="stylesheet" />
41
		<link href="<TMPL_VAR NAME='R_PATH' />/static/css/style-munstrap.css" rel="stylesheet" />
42

  
43
		<script src="<TMPL_VAR NAME='R_PATH' />/static/js/jquery.min.js"></script>
44
		<script src="<TMPL_VAR NAME='R_PATH' />/static/js/bootstrap.min.js"></script>
45
		<script src="<TMPL_VAR NAME='R_PATH' />/static/js/typeahead.bundle.min.js"></script>
46

  
47
		<TMPL_INCLUDE NAME="search_and_reload.tmpl">
48
	</head>
49

  
50
	<body>
51

  
52
		<nav class="navbar navbar-expand-lg navbar-light bg-light mb-3">
53
			<a class="navbar-brand" href="<TMPL_VAR NAME='R_PATH' />"><span class="munin-icon"></span></a>
54
			<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
55
				<span class="navbar-toggler-icon"></span>
56
			</button>
57
		
58
			<div class="collapse navbar-collapse" id="navbarSupportedContent">
59
				<ul class="navbar-nav mr-auto">
60
					<li class="nav-item">
61
						<a class="nav-link" href="<TMPL_VAR NAME='R_PATH' />">Home</a>
62
					</li>
63
					<li class="nav-item dropdown">
64
						<a class="nav-link dropdown-toggle" href="#" id="navbarProblems" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
65
							Problems
66
						</a>
67
						<div class="dropdown-menu" aria-labelledby="navbarProblems">
68
							<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>
69
							<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>
70
							<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>
71
						</div>
72
					</li>
73
					<li class="nav-item dropdown">
74
						<a class="nav-link dropdown-toggle" href="#" id="navbarGroups" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
75
							Groups
76
						</a>
77
						<div class="dropdown-menu" aria-labelledby="navbarGroups">
78
							<TMPL_LOOP NAME="ROOTGROUPS">
79
								<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL'>"><TMPL_VAR NAME="NAME"></a>
80
							</TMPL_LOOP>
81
						</div>
82
					</li>
83
					<li class="nav-item dropdown">
84
						<a class="nav-link dropdown-toggle" href="#" id="navbarHosts" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
85
							Hosts
86
						</a>
87
						<div class="dropdown-menu" aria-labelledby="navbarHosts">
88
							<TMPL_LOOP NAME="ROOTGROUPS">
89
								<TMPL_LOOP NAME="GROUPS">
90
									<TMPL_IF NAME="NCATEGORIES">
91
										<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL'>"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a>
92
									</TMPL_IF>
93
								</TMPL_LOOP>
94
							</TMPL_LOOP>
95
						</div>
96
					</li>
97
					<li class="nav-item dropdown">
98
						<a class="nav-link dropdown-toggle" href="#" id="navbarCats" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
99
							Categories
100
						</a>
101
						<div class="dropdown-menu" aria-labelledby="navbarCats">
102
								<TMPL_LOOP NAME="GLOBALCATS">
103
									<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLDAY'>"><TMPL_VAR NAME="NAME"> - Day</a>
104
									<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLWEEK'>"><TMPL_VAR NAME="NAME"> - Week</a>
105
									<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLMONTH'>"><TMPL_VAR NAME="NAME"> - Month</a>
106
									<a class="dropdown-item" href="<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLYEAR'>"><TMPL_VAR NAME="NAME"> - Year</a>
107
									<TMPL_IF NAME="__first__"><div class="dropdown-divider"></div></TMPL_IF>
108
									<TMPL_IF NAME="__inner__"><div class="dropdown-divider"></div></TMPL_IF>
109
								</TMPL_LOOP>
110
						</div>
111
					</li>
112

  
113
				</ul>
114
				<form id="formy1" class="form-inline my-2 my-lg-0 w-25">
115
					<input class="form-control mr-sm-2 w-100" type="text" id="findthehost" placeholder="Host or Service" aria-label="Search">
116
				</form>
117
			</div>
118
		</nav>
119
		
120
	<div class="container">
121
		<TMPL_INCLUDE NAME="logo_navigation.tmpl">
122

  
templates/muncollapse/templates/partial/logo_navigation.tmpl
4 4
	Used: All views, called after from head.
5 5
-->
6 6

  
7
<!-- TEST DATA :: BEGIN -->
8
<!-- a/n: IF THE NAVIGATION LOOKS WIERD, PLEASE INCLUDE THIS INFO WHEN ASKING FOR HELP FIXING. -->
9
<TMPL_IF NAME="PATH"><TMPL_LOOP NAME="PATH">
10
	<!-- PATH <TMPL_VAR NAME="PATHNAME"> -->
11
</TMPL_LOOP>
12
<TMPL_ELSE>
13
	<!-- SHIT -->
14
</TMPL_IF>
15

  
16
<TMPL_IF NAME="CATEGORY" >
17
	<!-- CAT: <TMPL_VAR ESCAPE="HTML" NAME="CATEGORY" /> -->
18
</TMPL_IF>
19
<TMPL_IF NAME="NAME">
20
	<!-- NAME <TMPL_VAR ESCAPE="HTML" NAME="NAME"> -->
21
<TMPL_ELSE>
22
	<!-- NO NAME -->
23
</TMPL_IF>
24
<!-- TEST DATA :: END -->
25

  
26 7
<TMPL_IF NAME="PATH">
27 8
	<nav aria-label="breadcrumb pt1">
28 9
		<ol class="breadcrumb">
......
43 24
					</TMPL_IF>
44 25
				</li>
45 26
			</TMPL_LOOP>
27
			<div class="custom-control custom-switch ml-auto mr-0">
28
				<input type="checkbox" class="custom-control-input" id="autorefimg">
29
				<label class="custom-control-label" for="autorefimg">Auto-refresh Images</label>
30
			</div>
46 31
		</ol>
47 32
	</nav>
48 33
<TMPL_ELSE>
......
50 35
		<ol class="breadcrumb">
51 36
			<TMPL_IF NAME="NAME">
52 37
				<!-- 2.0.37 - Shouldn't get hit with new HTML generator -->
53
				<li class="breadcrumb-item"><a href="<TMPL_VAR NAME='R_PATH'>">Home</a></li>
38
				<li class="breadcrumb-item"><a href="<TMPL_VAR NAME='R_PATH' />">Home</a></li>
54 39
				<li class="breadcrumb-item"><TMPL_VAR NAME="NAME" /></li>
55 40
			<TMPL_ELSE>
56 41
				<li class="breadcrumb-item">Home</li>
......
60 45
</TMPL_IF>
61 46

  
62 47
<TMPL_IF NAME="PEERS">
63
	<TMPL_INCLUDE NAME="bottom_navigation.tmpl">
48
	<TMPL_INCLUDE NAME="bottom_navigation.tmpl" />
49
</TMPL_IF>
50

  
51
<TMPL_IF NAME="COMPARISON-DAY">
52
	<h2 class="mb-3">Comparison: by day</h2>
53
	<TMPL_INCLUDE NAME="compare_navigation.tmpl" />
54
</TMPL_IF>
55

  
56
<TMPL_IF NAME="COMPARISON-WEEK">
57
	<h2 class="mb-3">Comparison: by week</h2>
58
	<TMPL_INCLUDE NAME="compare_navigation.tmpl" />
59
</TMPL_IF>
60

  
61
<TMPL_IF NAME="COMPARISON-MONTH">
62
	<h2 class="mb-3">Comparison: by month</h2>
63
	<TMPL_INCLUDE NAME="compare_navigation.tmpl" />
64
</TMPL_IF>
65

  
66
<TMPL_IF NAME="COMPARISON-YEAR">
67
	<h2 class="mb-3">Comparison: by year</h2>
68
	<TMPL_INCLUDE NAME="compare_navigation.tmpl" />
64 69
</TMPL_IF>
templates/muncollapse/templates/partial/search_and_reload.tmpl
1

  
2
		<!--
3
			File: partial/search_and_reload.tmpl
4

  
5
			Used: All views, generates the search functionality, and the auto-reload stuff.
6
		-->
7

  
8
		<script>
9
			// $('img').each(function(){ if (this.src.length > 0) {
10
			//         console.log(this.src);
11
			// 	} });
12

  
13

  
14

  
15
			// This is used to build the navigation quick search - there is no backend, so we have to do 
16
			// it all client side.
17
			//
18
			// As a curious side note, commenting out the template loops and whatnot allows vscode to parse
19
			// the javascript - so please note that the commented out TMPL directives STILL FUNCTION.
20
			var gen_basegroups = {
21
				// <TMPL_LOOP NAME="ROOTGROUPS">
22
					"<TMPL_VAR NAME='NAME' />" : {
23
						"baseurl" :  "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL'>",
24
						"compare" : {
25
							// <TMPL_IF NAME="COMPARE">
26
								"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",
27
								"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",
28
								"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",
29
								"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"
30
							// </TMPL_IF>
31
						}
32
					},
33
				// </TMPL_LOOP>
34
			};
35
			var gen_hosts = {
36
				// <TMPL_LOOP NAME="ROOTGROUPS">
37
					// <TMPL_LOOP NAME="GROUPS">
38
						// <TMPL_IF NAME="NCATEGORIES">
39
							"<TMPL_VAR ESCAPE='HTML' NAME='NAME' />" : {
40
								"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL'>",
41
								"services" : {
42
								// <TMPL_LOOP NAME="CATEGORIES">
43
									"<TMPL_VAR ESCAPE='HTML' NAME='NAME' />" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URL' />",
44
								// </TMPL_LOOP>
45
								}
46
							},
47
						// </TMPL_IF>
48
					// </TMPL_LOOP>
49
				// </TMPL_LOOP>
50
			};
51
			var gen_cats = {
52
				// <TMPL_LOOP NAME="GLOBALCATS">
53
					"Category :: <TMPL_VAR NAME='NAME'> :: Day" : {
54
						"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLDAY'>"
55
					},
56
					"Category :: <TMPL_VAR NAME='NAME'> :: Week" : {
57
						"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLWEEK'>"
58
					},
59
					"Category :: <TMPL_VAR NAME='NAME'> :: Month" : {
60
						"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLMONTH'>"
61
					},
62
					"Category :: <TMPL_VAR NAME='NAME'> :: Year" : {
63
						"baseurl" : "<TMPL_VAR NAME='R_PATH' />/<TMPL_VAR NAME='URLYEAR'>"
64
					},
65
				// </TMPL_LOOP>
66
			};
67

  
68
			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("/")}
69

  
70
			var navMap = [];
71

  
72
			$.each( gen_cats, function( name, obby ) {
73
				navMap.push( { "name" : name, "link" : absolute( location.href, obby.baseurl ) } );
74
			});
75

  
76
			$.each( gen_hosts, function( name, obby ) {
77
				var host_name = name;
78
				navMap.push( { "name" : "Host :: " + name, "link" : absolute( location.href, obby.baseurl ) } );
79
				$.each( obby.services, function( svcname, url ) {
80
					navMap.push( { "name" : "Service :: " + host_name + " :: " + svcname, "link" : absolute( location.href, url ) } );
81
				});
82
			});
83

  
84
			$.each( gen_basegroups, function( name, obby ) {
85
				var host_name = name;
86
				navMap.push( { "name" : "Host :: " + name, "link" : absolute( location.href, obby.baseurl ) } );
87
				$.each( obby.compare, function( svcname, url ) {
88
					navMap.push( { "name" : "Compare :: " + host_name + " :: " + svcname, "link" : absolute(location.href, url) } );
89
				});
90
			});
91

  
92
			var navMapB = new Bloodhound({
93
				datumTokenizer: function ( d ) { return Bloodhound.tokenizers.whitespace( d.name ); },
94
				queryTokenizer: Bloodhound.tokenizers.whitespace,
95
				identify: function ( obj ) { return obj.link; },
96
				local: navMap
97
			});
98

  
99
			$(document).ready(function(){
100
				$( "#findthehost" ).typeahead({
101
					hint      : true,
102
					highlight : true,
103
					minLength : 2,
104
				},
105
				{
106
					name      : "navMap",
107
					limit     : 10,
108
					display   : "link",
109
					source    : navMapB,
110
					templates : {
111
						suggestion : function ( data ) {
112
							return "<div>" + data.name + "</div>";
113
						}
114
					}
115
				}
116
				);
117

  
118
				$( "#findthehost" ).on( "typeahead:select", function() { $( "#formy1" ).submit(); } );
119

  
120
				$( "#formy1" ).on( "submit", function() {
121
					inputVal = $( "#findthehost" ).val();
122

  
123
					if ( inputVal.substring( 0, 4 ) == "http" ) {
124
						window.location.href = inputVal;
125
					} else {
126
						$( "#findthehost" ).typeahead( "val", "" );
127
					}
128
					return false;
129
				});
130
			});
131

  
132
			function autoRefImages() {
133
				$( "img" ).each(function () {
134
					if ( this.src.length > 0 && (! $( this ).hasClass( "no-refresh" )) ) {
135
						var thisURL = new URL( this.src );
136
						thisURL.searchParams.set( "tt", new Date().getTime() );
137
						this.src = thisURL.href;
138
					}
139
				});
140
			}
141

  
142
			$( document ).ready( function() {
143
				if ( Cookies.get( "autorefreshimg" ) == 0 ) {
144
					$( "#autorefimg" ).prop( "checked", false );
145
				} else {
146
					$( "#autorefimg" ).prop( "checked", true);
147
					Cookies.set("autorefreshimg", "1", { expires: 60 });
148
					window.autoreftimeout = setInterval( autoRefImages, 300000 );
149
				}
150

  
151
				$( "#autorefimg" ).on( "change", function() {
152
					Cookies.set( "autorefreshimg", "0", { expires: 60 } )
153
					clearInterval( window.autoreftimeout );
154
					if ( $( "#autorefimg" ).is( ":checked" ) ) {
155
						Cookies.set( "autorefreshimg", "1", { expires: 60 } );
156
						window.autoreftimeout = setInterval( autoRefImages, 300000 );
157
					}
158
				});
159
			})
160
		</script>
templates/munstrap4/README.md
1
# Munstrap4
2

  
3
Alternative Munin 2.x templates based on Twitter Bootstrap 4.
4

  
5
Based on "Munstrap" by [Jonny McCullagh](https://github.com/jonnymccullagh), [munin-monitoring/contrib](https://github.com/munin-monitoring/contrib/tree/master/templates/munstrap) repo.
6

  
7
#### Overview Sample Image
8
<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>
9

  
10

  
11
#### [Semi-Live Demo](https://jtsage.dev/munin-demo/)
12
Zoom functionality for this demo has been disabled, and the data will never update, but it's a decent visual reference.
13

  
14
---
15

  
16
## Installation
17

  
18
### 1. Clone the munin-monitoring/contrib repo to a temporary location:
19

  
20
```
21
$ cd /opt
22
$ git clone https://github.com/munin-monitoring/contrib.git
23
```
24

  
25
### 2. Place the template in an appropriate safe place
26

  
27
Ubuntu shown - other distros may prefer ```/usr/local/share/munin/...```
28

  
29
```
30
$ mkdir /usr/share/munin/template
31
$ mkdir /usr/share/munin/template/munstrap4
32
```
33
__NOTE__: If this step fails, your munin installation may use ```/usr/local/share/munin/...``` instead!
34

  
35
```
36
$ cp -r /opt/contrib/templates/munstrap4/templates /usr/share/munin/template/munstrap4/
37
$ cp -r /opt/contrib/templates/munstrap4/static /usr/share/munin/template/munstrap4/
38
```
39

  
40
### 3. Edit your ```munin.conf``` file.
41

  
42
Typically located at ```/etc/munin.conf```
43

  
44
__FIND AND CHANGE:__ (near the top of the file)
45

  
46
```
47
# Where to look for the HTML templates
48
#
49
#tmpldir        /etc/munin/templates
50

  
51
# Where to look for the static www files
52
#
53
#staticdir /etc/munin/static
54
```
55

  
56
__TO:__
57
```
58
# Where to look for the HTML templates
59
#
60
tmpldir /usr/share/munin/template/munstrap4/templates
... Ce différentiel a été tronqué car il excède la taille maximale pouvant être affichée.

Formats disponibles : Unified diff