<!DOCTYPE html>
<html>
<head>
  <title>Dashboard</title>
  <meta name="description" content="Dashboard">

  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
  <script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
        
  <!-- See http://bernii.github.io/gauge.js/ -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/gauge.js/1.3.2/gauge.min.js" integrity="sha256-KEsUMeRzEtuzIgL/g8GXg5zolwofZs+J4Lrg2wLn1AE=" crossorigin="anonymous"></script>
  
  <!-- See http://omnipotent.net/jquery.sparkline -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-sparklines/2.1.2/jquery.sparkline.js" integrity="sha256-LyvLC4QvPtUU7GAeXnI4atDtDDSKOtUFoIRsysvDSDQ=" crossorigin="anonymous"></script>
  
  <!-- https://github.com/datavisyn/chartjs-chart-box-and-violin-plot -->
  <script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0/dist/Chart.min.js" integrity="sha256-Uv9BNBucvCPipKQ2NS9wYpJmi8DTOEfTA/nH2aoJALw=" crossorigin="anonymous"></script>
  <script src="https://unpkg.com/chartjs-chart-box-and-violin-plot@2/build/Chart.BoxPlot.js"></script>

  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.css">
</head>

<body>
  <style>

#title {
  text-align: center;
}

/* For status */
.status_ok {
  color: green;
  font-size: 300%;
}

.status_ko {
  color: red;
  font-size: 300%;
}

.centered {
  text-align: center;
  vertical-align: middle;
  line-height: 143px;
}

.row-label {
  font-size: 200%;
}

td h4 {
  text-align: center;
}

/* For simple values */
.value-value {
  font-family: sans-serif;
  font-size: 130%;
  font-weight: bold;
}

.gauge-canvas {
  top: 0px;
  position: relative;
}

.histo-canvas {
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
}

.histo-text {
  vertical-align: text-top;
  margin: 10px;
}

.gauge-text {
  position: relative;
  top: -10px; left: 0; right: 0;
  text-align: center; font-size: 1em; font-weight: bold;
  color: black; font-family: 'Amaranth', sans-serif;
}  

.gauge-sparkline {
  position: relative;
  top: 0px; left: 0; right: 0;
}  

.thumbnail {
    padding: 1px;
    margin-bottom: 0px;
}
    
.h1, .h2, .h3, .h4, h1, h2, h3, h4 {
    margin-top: 1px;
    margin-bottom: 0px;
}

td {
  vertical-align: top;
  padding: 5px;
  }

.number {
  text-align: right;
}

.tile {
    margin-right: 10px;
    margin-left: 10px;
    background-color: #fff;
    border-color: #ddd;
    border-width: 1px;
}
  
.panel-body {
    padding: 2px;
}

.panel-heading {
    padding: 2px 3px;
}
  
.panel-primary > .health_ok {
  background-color: #1a961a;
}

.panel-primary > .health_ko {
  background-color: #9c2a2a;
}
  </style>
  <script type="text/javascript">
  
  $( function(){

    setInterval(refresh_values,5000);

    {% for R in config.rows %}
      {% for C in R.cells %}
        init_{{C.id}}();
      {% endfor %}
    {% endfor %}

    refresh_values();
  });
  
  var $mpoints_max = 50;
  function refresh_values() {
    {% for R in config.rows %}
      {% for C in R.cells %}
        $.get("all", {server: "{{C.server}}"}, function(stats,status) {
          update_{{C.id}}(stats,status);
        }).fail(function() {
          update_{{C.id}}(null,false);
        });
      {% endfor %}
    {% endfor %}
  }

  function conv(val,factor) {
    if (factor.slice(0,1)=='*') {
      return val * factor.slice(1);
    }
    if (factor.slice(0,1)=='/') {
      return val / factor.slice(1);
    }
  }

  /* Init and update function */
  {% for R in config.rows %}
    {% for C in R.cells %}

      /* Global vars */
      {% if C.type == 'status' %}
      {% elif C.type == 'value' %}
      {% elif C.type == 'gauge' %}

        var ${{C.id}}_gauge = null;
        var $mpoints_{{C.id}}_gauge = [];

      {% elif C.type == 'histogram' %}
      {% endif %}

      /* Init function */
      function init_{{C.id}}() {
        {% if C.type == 'status' %}
        {% elif C.type == 'value' %}
        {% elif C.type == 'gauge' %}

          var opts = {
            angle: 0.0,
            lineWidth: 0.25,
            radiusScale: 0.7,
            pointer: {
              length: 0.51, // // Relative to gauge radius
              strokeWidth: 0.05, // The thickness
              color: '#000000' // Fill color
            },
            limitMax: false,
            limitMin: false,
            strokeColor: '#E0E0E0',
            colorStop: '{{C.gauge_color|default("blue")}}'
          };

          ${{C.id}}_gauge = new Gauge(document.getElementById("canvas-{{C.id}}-gauge"));
          ${{C.id}}_gauge.setOptions(opts);
          ${{C.id}}_gauge.setTextField(document.getElementById("text-{{C.id}}-gauge"));
          ${{C.id}}_gauge.setMinValue(0);
          ${{C.id}}_gauge.maxValue = {{C.max|default(25000)}};
          ${{C.id}}_gauge.animationSpeed = 20;

        {% elif C.type == 'histogram' %}
        {% endif %}
      }

      /* Update function */
      function update_{{C.id}}(stats,status) {
        {% if C.type == 'status' %}
          var obj = document.getElementById("status-{{C.id}}");
          if (status==true || status=='success') {
            obj.className = "far fa-thumbs-up status_ok";
          } else {
            obj.className = "far fa-thumbs-down status_ko";
          }
        {% elif C.type == 'value' %}

          // Provide default values if metric does not exist yet
          if (stats==null) {
            stats = 0;
          }

          const obj_{{C.id}} = document.getElementById("value-{{C.id}}");
          obj_{{C.id}}.innerHTML = conv(stats,"{{C.factor|default("*1")}}");

        {% elif C.type == 'gauge' %}

          var value = conv(stats,"{{C.factor|default("*1")}}");

          ${{C.id}}_gauge.set(Math.min(value,{{C.max|default(25000)}}));

          $mpoints_{{C.id}}_gauge.push(value);
          if ($mpoints_{{C.id}}_gauge.length > $mpoints_max) {
            $mpoints_{{C.id}}_gauge.splice(0,1);
          }
          $('#line-{{C.id}}-gauge').sparkline($mpoints_{{C.id}}_gauge, { 
              type:"line", 
              chartRangeMin: 0, 
              height: 40, 
              width: $mpoints_{{C.id}}_gauge.length*2,
              fillColor: "{{C.color|default('#C0D0F0')}}",
            } );

        {% elif C.type == 'histogram' %}

          // Provide default values if histograms does not exist yet
          if (stats==null) {
            stats = {"quantiles": {"0.05": 0.0, "0.25": 0.0, "0.75": 0.0, "0.95": 0.0, "0.5": 0.0}};
          }

          const boxplotData = {
            // define label tree
            labels: ["{{C.unit}}"],
            datasets: [{
              backgroundColor:  '{{C.color|default("rgba(0,0,255,0.5)")}}',
              borderColor: '{{C.color|default("rgba(0,0,255,0.5)")}}',
              borderWidth: 1,
              outlierColor: '#999999',
              medianColor:'{{C.median_color|default("rgba(255,0,0,0.5)")}}',
              padding: 10,
              itemRadius: 0,
              //width: 5,
              data: [
                            { 'min':    conv(stats.quantiles[0.05],"{{C.factor|default("*1")}}"),
                              'q1':     conv(stats.quantiles[0.25],"{{C.factor|default("*1")}}"),
                              'q3':     conv(stats.quantiles[0.75],"{{C.factor|default("*1")}}"),
                              'max':    conv(stats.quantiles[0.95],"{{C.factor|default("*1")}}"),
                              'median': conv(stats.quantiles[0.5],"{{C.factor|default("*1")}}")
                              }
              ]
            }]
          };

          const ctx = document.getElementById("chart-{{C.id}}-histo").getContext("2d");
          window.myBar = new Chart(ctx, {
            type: 'boxplot',
            data: boxplotData,
            options: {
              responsive: true,
              legend: {
                display: false,
                position: 'top',
              },
              title: {
                display: false,
                text: ''
              }
            }
          });

        {% endif %}
      }
    {% endfor %}
  {% endfor %}

  </script>

<h2 id="title">{{config.title}}</h2>

<table>

  {% for R in config.rows %}

  <tr>

    {% for C in R.cells %}
      <td>
          {% if C.type == 'empty' %}

            <span style="display: inline-block;">
              <div class="centered">
                  <div style="height: 143px; width: 100px;">
                      <span class="row-label">&nbsp;</span>
                  </div>
              </div>
              <div>
                  <h4>&nbsp;</h4>
              </div>
            </span>
  
          {% elif C.type == 'label' %}

          <span style="display: inline-block;">
            <div class="centered">
                <div style="height: 143px; width: 100px;">
                    <span class="row-label">{{C.label}}</span>
                </div>
            </div>
            <div>
                <h4>&nbsp;</h4>
            </div>
          </span>

        {% elif C.type == 'status' %}

          <span style="display: inline-block;">
            <div class="thumbnail centered">
                <div style="height: 143px; width: 100px;">
                    <i id="status-{{C.id}}" class="far fa-thumbs-down status_ko"></i>
                </div>
            </div>
            <div>
                <h4 title="{{C.label}}">{{C.label|truncate(10)}}</h4>
            </div>
          </span>

        {% elif C.type == 'value' %}

          <span style="display: inline-block;">
            <div class="thumbnail centered">
              <div class="value-value" style="height: 143px; width: 100px;">
                <span id="value-{{C.id}}" style="color: {{C.color}}"></span><span style="color: {{C.color}}">&nbsp;{{C.unit}}</span>
              </div>
            </div>
            <div>
                <h4 title="{{C.label}}">{{C.label|truncate(10)}}</h4>
            </div>
          </span>
        
        {% elif C.type == 'gauge' %}

          <span style="display: inline-block;">
            <div class="thumbnail">
              <canvas width=100 height=80 id="canvas-{{C.id}}-gauge" class="center-block gauge-canvas"></canvas>
              <div id="text-{{C.id}}-gauge" class="gauge-text"></div>
            </div>
            <div class="thumbnail gauge-sparkline">
              <span id="line-{{C.id}}-gauge">Loading..</span>
            </div>
            <div>
              {% set label = C.label ~ " (" ~ C.unit ~ ")" %}
              <h4 title="{{C.label}} ({{C.unit}})">{{label|truncate(10)}}</h4>
            </div>
          </span>
      
        {% elif C.type == 'histogram' %}

          <span style="display: inline-block;">
            <div class="thumbnail">
              <canvas class="histo-canvas" id="chart-{{C.id}}-histo" style="height: 143px; width: 100px;"></canvas>
            </div>
            <div>
                <h4 title="{{C.label}}">{{C.label|truncate(10)}}</h4>
            </div>
          </span>

        {% endif %}

      </td>

      {% endfor %}
    
    </tr>
    {% endfor %}

</table>

</body>
</html>
  