[Time Conductor] Realtime presets and history tracking (#3270)

Time conductor realtime preset/history updates

Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov>
Co-authored-by: Deep Tailor <deep.j.tailor@nasa.gov>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
This commit is contained in:
Jamie V 2020-10-28 17:46:28 -07:00 committed by GitHub
parent 8cd6a4c6a3
commit 0e6ce7f58b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 141 additions and 28 deletions

View File

@ -35,7 +35,13 @@
</body>
<script>
const THIRTY_SECONDS = 30 * 1000;
const THIRTY_MINUTES = THIRTY_SECONDS * 60;
const ONE_MINUTE = THIRTY_SECONDS * 2;
const FIVE_MINUTES = ONE_MINUTE * 5;
const FIFTEEN_MINUTES = FIVE_MINUTES * 3;
const THIRTY_MINUTES = FIFTEEN_MINUTES * 2;
const ONE_HOUR = THIRTY_MINUTES * 2;
const TWO_HOURS = ONE_HOUR * 2;
const ONE_DAY = ONE_HOUR * 24;
[
'example/eventGenerator'
@ -73,21 +79,21 @@
{
label: 'Last Day',
bounds: {
start: () => Date.now() - 1000 * 60 * 60 * 24,
start: () => Date.now() - ONE_DAY,
end: () => Date.now()
}
},
{
label: 'Last 2 hours',
bounds: {
start: () => Date.now() - 1000 * 60 * 60 * 2,
start: () => Date.now() - TWO_HOURS,
end: () => Date.now()
}
},
{
label: 'Last hour',
bounds: {
start: () => Date.now() - 1000 * 60 * 60,
start: () => Date.now() - ONE_HOUR,
end: () => Date.now()
}
}
@ -96,7 +102,7 @@
records: 10,
// maximum duration between start and end bounds
// for utc-based time systems this is in milliseconds
limit: 1000 * 60 * 60 * 24
limit: ONE_DAY
},
{
name: "Realtime",
@ -105,7 +111,44 @@
clockOffsets: {
start: - THIRTY_MINUTES,
end: THIRTY_SECONDS
}
},
presets: [
{
label: '1 Hour',
bounds: {
start: - ONE_HOUR,
end: THIRTY_SECONDS
}
},
{
label: '30 Minutes',
bounds: {
start: - THIRTY_MINUTES,
end: THIRTY_SECONDS
}
},
{
label: '15 Minutes',
bounds: {
start: - FIFTEEN_MINUTES,
end: THIRTY_SECONDS
}
},
{
label: '5 Minutes',
bounds: {
start: - FIVE_MINUTES,
end: THIRTY_SECONDS
}
},
{
label: '1 Minute',
bounds: {
start: - ONE_MINUTE,
end: THIRTY_SECONDS
}
}
]
}
]
}));

View File

@ -141,10 +141,11 @@
<ConductorMode class="c-conductor__mode-select" />
<ConductorTimeSystem class="c-conductor__time-system-select" />
<ConductorHistory
v-if="isFixed"
class="c-conductor__history-select"
:offsets="openmct.time.clockOffsets()"
:bounds="bounds"
:time-system="timeSystem"
:mode="timeMode"
/>
</div>
<input
@ -210,6 +211,11 @@ export default {
isZooming: false
};
},
computed: {
timeMode() {
return this.isFixed ? 'fixed' : 'realtime';
}
},
mounted() {
document.addEventListener('keydown', this.handleKeyDown);
document.addEventListener('keyup', this.handleKeyUp);

View File

@ -66,7 +66,9 @@
<script>
import toggleMixin from '../../ui/mixins/toggle-mixin';
const LOCAL_STORAGE_HISTORY_KEY = 'tcHistory';
const DEFAULT_DURATION_FORMATTER = 'duration';
const LOCAL_STORAGE_HISTORY_KEY_FIXED = 'tcHistory';
const LOCAL_STORAGE_HISTORY_KEY_REALTIME = 'tcHistoryRealtime';
const DEFAULT_RECORDS = 10;
export default {
@ -77,72 +79,115 @@ export default {
type: Object,
required: true
},
offsets: {
type: Object,
required: false,
default: () => {}
},
timeSystem: {
type: Object,
required: true
},
mode: {
type: String,
required: true
}
},
data() {
return {
/**
* previous bounds entries available for easy re-use
* @history array of timespans
* @realtimeHistory array of timespans
* @timespans {start, end} number representing timestamp
*/
history: this.getHistoryFromLocalStorage(),
realtimeHistory: {},
/**
* previous bounds entries available for easy re-use
* @fixedHistory array of timespans
* @timespans {start, end} number representing timestamp
*/
fixedHistory: {},
presets: []
};
},
computed: {
currentHistory() {
return this.mode + 'History';
},
isFixed() {
return this.openmct.time.clock() === undefined;
},
hasHistoryPresets() {
return this.timeSystem.isUTCBased && this.presets.length;
},
historyForCurrentTimeSystem() {
const history = this.history[this.timeSystem.key];
const history = this[this.currentHistory][this.timeSystem.key];
return history;
},
storageKey() {
let key = LOCAL_STORAGE_HISTORY_KEY_FIXED;
if (this.mode !== 'fixed') {
key = LOCAL_STORAGE_HISTORY_KEY_REALTIME;
}
return key;
}
},
watch: {
bounds: {
handler() {
// only for fixed time since we track offsets for realtime
if (this.isFixed) {
this.addTimespan();
}
},
deep: true
},
offsets: {
handler() {
this.addTimespan();
},
deep: true
},
timeSystem: {
handler() {
handler(ts) {
this.loadConfiguration();
this.addTimespan();
},
deep: true
},
mode: function () {
this.getHistoryFromLocalStorage();
this.initializeHistoryIfNoHistory();
this.loadConfiguration();
}
},
mounted() {
this.getHistoryFromLocalStorage();
this.initializeHistoryIfNoHistory();
},
methods: {
getHistoryFromLocalStorage() {
const localStorageHistory = localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY);
const localStorageHistory = localStorage.getItem(this.storageKey);
const history = localStorageHistory ? JSON.parse(localStorageHistory) : undefined;
return history;
this[this.currentHistory] = history;
},
initializeHistoryIfNoHistory() {
if (!this.history) {
this.history = {};
if (!this[this.currentHistory]) {
this[this.currentHistory] = {};
this.persistHistoryToLocalStorage();
}
},
persistHistoryToLocalStorage() {
localStorage.setItem(LOCAL_STORAGE_HISTORY_KEY, JSON.stringify(this.history));
localStorage.setItem(this.storageKey, JSON.stringify(this[this.currentHistory]));
},
addTimespan() {
const key = this.timeSystem.key;
let [...currentHistory] = this.history[key] || [];
let [...currentHistory] = this[this.currentHistory][key] || [];
const timespan = {
start: this.bounds.start,
end: this.bounds.end
start: this.isFixed ? this.bounds.start : this.offsets.start,
end: this.isFixed ? this.bounds.end : this.offsets.end
};
let self = this;
@ -160,20 +205,24 @@ export default {
}
currentHistory.unshift(timespan);
this.history[key] = currentHistory;
this.$set(this[this.currentHistory], key, currentHistory);
this.persistHistoryToLocalStorage();
},
selectTimespan(timespan) {
this.openmct.time.bounds(timespan);
if (this.isFixed) {
this.openmct.time.bounds(timespan);
} else {
this.openmct.time.clockOffsets(timespan);
}
},
selectPresetBounds(bounds) {
const start = typeof bounds.start === 'function' ? bounds.start() : bounds.start;
const end = typeof bounds.end === 'function' ? bounds.end() : bounds.end;
this.selectTimespan({
start: start,
end: end
start,
end
});
},
loadConfiguration() {
@ -184,7 +233,9 @@ export default {
this.records = this.loadRecords(configurations);
},
loadPresets(configurations) {
const configuration = configurations.find(option => option.presets);
const configuration = configurations.find(option => {
return option.presets && option.name.toLowerCase() === this.mode;
});
const presets = configuration ? configuration.presets : [];
return presets;
@ -196,11 +247,24 @@ export default {
return records;
},
formatTime(time) {
let format = this.timeSystem.timeFormat;
let isNegativeOffset = false;
if (!this.isFixed) {
if (time < 0) {
isNegativeOffset = true;
}
time = Math.abs(time);
format = this.timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER;
}
const formatter = this.openmct.telemetry.getValueFormatter({
format: this.timeSystem.timeFormat
format: format
}).formatter;
return formatter.format(time);
return (isNegativeOffset ? '-' : '') + formatter.format(time);
}
}
};