Commit bd92ec6a authored by Patrick Godwin's avatar Patrick Godwin

Merge branch 'ui_overhaul' into 'master'

UI overhaul

See merge request !26
parents 71055826 b8f7200a
Pipeline #74593 passed with stages
in 1 minute and 41 seconds
......@@ -79,24 +79,28 @@ def index():
config = dict(app.config)
static_dir = '../' if config['use_cgi'] else ''
if "gps" in bottle.request.query:
config['dashboard']['gps']=bottle.request.query['gps']
if "duration" in bottle.request.query:
config['dashboard']['duration']=bottle.request.query['duration']
if 'type' in bottle.request.query:
config['dashboard']['type'] = bottle.request.query['type']
else:
config['dashboard']['type'] = 'online'
if config['dashboard']['type'] == 'online':
if 'lookback' in bottle.request.query:
config['dashboard']['lookback'] = int(bottle.request.query['lookback'])
if 'delay' in bottle.request.query:
config['dashboard']['delay'] = int(bottle.request.query['delay'])
else:
config['dashboard']['start'] = int(bottle.request.query['start'])
config['dashboard']['end'] = int(bottle.request.query['end'])
### find out whether query is for realtime or historical data
### NOTE: gps < 0 is used as a proxy for realtime data and refers
### to the delay (i.e. -5 means to query up to now - 5s
gpstime = int(config['dashboard']['gps'])
if gpstime < 0:
delay = -gpstime
stop = int(aggregator.now() - delay)
if config['dashboard']['type'] == 'online':
stop = int(aggregator.now() - config['dashboard']['delay'])
start = stop - config['dashboard']['lookback']
refresh = 2000
else:
delay = 0
stop = gpstime
start = config['dashboard']['start']
stop = config['dashboard']['end']
refresh = -1
start = stop - int(config['dashboard']['duration'])
### generate html
yield bottle.template(
......@@ -108,7 +112,9 @@ def index():
start=start,
stop=stop,
refresh=refresh,
delay=delay,
lookback=config['dashboard']['lookback'],
delay=config['dashboard']['delay'],
query_type=config['dashboard']['type'],
dashboard_config=config['dashboard'],
)
......
......@@ -28,11 +28,13 @@ body {
.dashboard {
background-image: linear-gradient(to bottom, #d5d4d0 0%, #d5d4d0 1%, #eeeeec 31%, #efeeec 75%, #e9e9e7 100%);
background-size: cover;
font-family: 'Nunito', sans-serif;
}
.dashboard .chart-wrapper {
background: #f5f6fa;
//background: #f5f6fa;
background: rgba(236, 240, 241, 0.5);
box-shadow: 0px 1px 2px rgba(44, 62, 80, 0.5);
border: 1px solid #e2e2e2;
border-radius: 3px;
......@@ -63,6 +65,11 @@ body {
.navbar {
min-height: 20px;
max-height: 50px;
background: rgba(236, 240, 241, 0.9);
}
.btn {
background: rgba(236, 240, 241, 0.9);
}
.scrollable {
......@@ -78,6 +85,10 @@ body {
justify-content: left;
}
.fas, .nav-clock, .nav-link {
color: #495057;
}
.unstyled-button{
border: none;
padding: 0;
......
......@@ -31,6 +31,7 @@ function updateClock() {
$(document).ready(function()
{
updateClock();
setInterval('updateClock()', 1000);
});
......@@ -84,6 +85,24 @@ function duration_to_dt(duration) {
}
function duration_to_str(duration) {
if (duration % 31540000 == 0) {
return (duration / 31540000) + ' yr';
} else if (duration % 2628000 == 0) {
return (duration / 2628000) + ' mo';
} else if (duration % 604800 == 0) {
return (duration / 604800) + ' wk';
} else if (duration % 86400 == 0) {
return (duration / 86400) + ' day';
} else if (duration % 3600 == 0) {
return (duration / 3600) + ' hr';
} else if (duration % 60 == 0) {
return (duration / 60) + ' min';
} else {
return duration + ' s';
}
}
function gpsnow() {
//FIXME doesn't account correctly for leapseconds (assumes 18)
return Math.round(Date.now() / 1000.) - 315964800 + 18;
......
......@@ -37,7 +37,7 @@
</head>
<body class="dashboard" style="padding-top: 55px">
<body class="dashboard" style="padding-top:55px; background-image:url({{ static_dir }}static/bns-light.jpg)">
% if 'audio' in dashboard_config:
<audio id="main_audio" autoplay="autoplay" preload="auto" loop="loop">
<source src="{{ dashboard_config['audio'] }}" type="audio/mpeg" />
......@@ -51,5 +51,5 @@
</div>
</body>
% include('scripts.js')
% include('scripts.js', **dashboard_config)
</html>
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-dark py-0">
<nav class="navbar fixed-top navbar-expand-lg py-0">
<!-- add logo/title -->
% if 'image' in dashboard_config:
<a class="navbar-brand mt-3 mt-lg-0" href="#"><img style="width:60px" src="{{ dashboard_config['image'] }}"></a>
<a class="navbar-brand mt-3 mt-lg-0" href="#"><img style="height:40px" src="{{ dashboard_config['image'] }}"></a>
% else:
<a class="navbar-brand mt-3 mt-lg-0" href="">{{ dashboard_config['title'] }}</a>
% end
......@@ -16,62 +16,135 @@
<!-- add tabs -->
% for tab in tabs:
<li><a class="nav-link mt-2" href="{{ tab['url'] }}">{{ tab['name'] }}</a></li>
<li><a class="nav-link mt-0" href="{{ tab['url'] }}">{{ tab['name'] }}</a></li>
% end
<!-- add gps range form -->
<li class="mr-3 ml-3">
<form class="form-inline" role="search">
<div class="form-group">
<input type="text" class="form-control form-control-sm mr-md-2" name="gps" value="{{ gps }}" size=12>
</div>
<div class="form-group">
<input type="text" class="form-control form-control-sm mr-md-2" name="duration" value="{{ duration }}" size=6 >
</div>
<div class="form-group mr-md-2">
<b-nav-item-dropdown size="sm" id="dropdown-left" class="m-md-2">
<template slot="button-content">
<i class="fas fa-chart-line fa-lg"></i>
</template>
<ul class="scrollable">
% for i, plot in enumerate(plots):
<li>
<b-button
class="m-lg-2"
size="sm"
name="livecharts{{ plot['title'].replace(' ', '_').lower() }}"
:checked={{ 'true' if plot['value'] == 'checked' else 'false' }}
@click="addItem(plots[{{ i }}])"
>
{{ plot['title'] }}
</b-button>
</li>
% end
</ul>
</b-nav-item-dropdown>
</div>
<div class="form-group mr-md-2">
<button class="btn btn-sm btn-outline-success" type="submit">Search</button>
</div>
</form>
</li>
</ul>
<span v-if="analysis" title="Unlock Graph Layout">
<b-button class="mr-3" size="sm" :pressed.sync="analysis">
<i class="fas fa-lock" style="color:white"></i>
<!-- lock/unlock -->
<span v-if="analysis" title="Unlock Grid Layout">
<b-button class="ml-1 mr-1 border rounded border-secondary" size="sm" variant="light" :pressed.sync="analysis">
<i class="fas fa-lock"></i>
</b-button>
</span>
<span v-else title="Lock Grid Layout">
<b-button class="ml-1 mr-1 border rounded border-secondary" size="sm" variant="light" :pressed.sync="analysis">
<i class="fas fa-unlock"></i>
</b-button>
</span>
<!-- plot menu -->
<span title="Available Plots">
<b-dropdown id="dropdown-left" size="sm" class="mx-1 border rounded border-secondary" variant="light">
<template slot="button-content">
<i class="fas fa-chart-line"></i>
</template>
% for i, plot in enumerate(plots):
<b-dropdown-item
class ="m-lg-2"
name="livecharts{{ plot['title'].replace(' ', '_').lower() }}"
href="#"
:checked={{ 'true' if plot['value'] == 'checked' else 'false' }}
@click="addItem(plots[{{ i }}])"
>
{{ plot['title'] }}
</b-dropdown-item>
</li>
% end
</ul>
</b-dropdown>
</span>
<!-- time selection -->
<span title="Decrease Duration">
<b-button class="mx-1 border rounded border-secondary" size="sm" variant="light" v-on:click="decreaseTime">
<i class="fas fa-angle-left"></i>
</b-button>
</span>
<span v-else title="Lock Graph Layout">
<b-button class="mr-3" size="sm" :pressed.sync="analysis">
<i class="fas fa-unlock" style="color:white"></i>
</b-button>
<div>
<b-form-select class="border rounded border-secondary" size="sm" v-model="form.lookback" :options="options"></b-form-select>
</div>
<span title="Increase Duration">
<b-button class="mx-1 border rounded border-secondary" size="sm" variant="light" v-on:click="increaseTime">
<i class="fas fa-angle-right"></i>
</b-button>
</span>
<!-- online/historical options form -->
<b-nav-form id="nav-form" class="ml-1 mr-3">
<span title="Query Options">
<b-dropdown id="dropdown-form" class="border rounded border-secondary" size="sm" ref="dropdown" variant="light">
<template slot="button-content">
<i class="fas fa-history"></i>
</template>
<span v-if="form.type == 'online'" title="Online Options">
<b-form-group id="input-group-1" class="my-2 mx-2" label="Lookback [s]" label-for="dropdown-lookback">
<b-form-input
name="lookback"
id="dropdown-lookback"
size="sm"
class="my-2 mx-1 w-75"
v-model="form.lookback"
placeholder="lookback"
></b-form-input>
</b-form-group>
<b-form-group id="input-group-2" class="my-2 mx-2" label="Delay [s]" label-for="dropdown-delay">
<b-form-input
name="delay"
id="dropdown-delay"
size="sm"
class="my-2 mx-1 w-75"
v-model="form.delay"
placeholder="delay"
></b-form-input>
</b-form-group>
</span>
<span v-else title="Historical Options">
<b-form-group id="input-group-1" class="my-2 mx-2" label="GPS Start [s]" label-for="dropdown-start">
<b-form-input
name="start"
id="dropdown-start"
size="sm"
class="my-2 mx-1 w-75"
v-model="form.start"
placeholder="start time"
></b-form-input>
</b-form-group>
<b-form-group id="input-group-2" class="my-2 mx-2" label="GPS End [s]" label-for="dropdown-end">
<b-form-input
name="end"
id="dropdown-end"
size="sm"
class="my-2 mx-1 w-75"
v-model="form.end"
placeholder="end time"
></b-form-input>
</b-form-group>
</span>
</b-dropdown>
</span>
<!-- online/historical toggle -->
<b-form-group id="input-group-3" class="mx-1" label-for="type">
<b-form-radio-group
id="type"
size="sm"
v-model="form.type"
:options="timeOptions"
buttons
button-variant="light"
class="mx-1 border rounded border-secondary"
></b-form-radio-group>
</b-form-group>
<b-button size="sm" class="mr-4" variant="outline-success" type="submit">Go</b-button>
</b-form>
<!-- add clock to right edge -->
<a href="#"><div id="clock" style="color: grey"></div></a>
<a class="nav-clock" href="#"><div id="clock"></div></a>
</b-collapse>
</nav>
......@@ -36,7 +36,7 @@
>
<div class="chart-wrapper">
<div class="chart-header">
{{"{{"}}item.title{{"}}"}}
[[ item.title ]]
<div class="buttons float-right">
<button class="unstyled-button" @click="deleteItem(item.i, item.divname)">
<i class="far fa-times-circle"></i>
......
......@@ -36,14 +36,77 @@
plots: [],
layout: [],
analysis: true,
liveData: true,
responsive: true,
modalShow: false,
timeOptions: [
{ value: 'historical', html: '<i class="fas fa-hourglass-half"></i>' },
{ value: 'online', html: '<i class="fas fa-step-forward"></i>' },
],
form: {
lookback: {{ lookback }},
delay: {{ delay }},
start: {{ start }},
end: {{ stop }},
type: '{{ query_type }}'
},
selected: {{ lookback }},
options: [
{ value: 30, text: '30 s' },
{ value: 60, text: '1 min' },
{ value: 300, text: '5 min' },
{ value: 600, text: '10 min' },
{ value: 900, text: '15 min' },
{ value: 1800, text: '30 min' },
{ value: 3600, text: '1 hr' },
{ value: 14400, text: '4 hr' },
{ value: 43200, text: '12 hr' },
{ value: 86400, text: '1 day' },
{ value: 604800, text: '1 wk' },
{ value: 2628000, text: '1 mo' },
{ value: 7884000, text: '3 mo' },
{ value: 15770000, text: '6 mo' },
{ value: 31540000, text: '1 yr' },
]
}
},
created: function() {
this.attachPlots();
var ranges = this.options.map(function(e) { return e.value; });
var idx = ranges.indexOf(this.form.lookback);
if (idx == -1) {
var insertIdx = d3.bisectLeft(ranges, this.form.lookback);
var text = duration_to_str(this.form.lookback);
this.options.splice(insertIdx, 0, {value: this.form.lookback, text: text});
}
},
watch: {
"form.lookback": function() {
if (this.form.type == 'historical') {
this.form.end = this.form.start + this.form.lookback;
this.selected = this.form.lookback;
}
},
},
methods: {
increaseTime: function() {
idx = this.options.map(function(e) { return e.value; }).indexOf(this.selected);
idx = Math.min(idx + 1, this.options.length - 1);
this.selected = this.options[idx].value;
this.form.lookback = this.selected;
if (this.form.type == 'historical') {
this.form.end = this.form.start + this.selected;
}
},
decreaseTime: function() {
idx = this.options.map(function(e) { return e.value; }).indexOf(this.selected);
idx = Math.max(idx - 1, 0);
this.selected = this.options[idx].value;
this.form.lookback = this.selected;
if (this.form.type == 'historical') {
this.form.end = this.form.start + this.selected;
}
},
resizeEvent: function() {
window.addEventListener('selectstart', disableSelect);
},
......@@ -212,6 +275,7 @@
}, this);
},
},
delimiters: ['[[',']]'],
});
var FAR_Table = new Vue({
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment