mirror of
https://github.com/nasa/openmct.git
synced 2025-06-01 15:10:50 +00:00
[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:
parent
8cd6a4c6a3
commit
0e6ce7f58b
55
index.html
55
index.html
@ -35,7 +35,13 @@
|
|||||||
</body>
|
</body>
|
||||||
<script>
|
<script>
|
||||||
const THIRTY_SECONDS = 30 * 1000;
|
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'
|
'example/eventGenerator'
|
||||||
@ -73,21 +79,21 @@
|
|||||||
{
|
{
|
||||||
label: 'Last Day',
|
label: 'Last Day',
|
||||||
bounds: {
|
bounds: {
|
||||||
start: () => Date.now() - 1000 * 60 * 60 * 24,
|
start: () => Date.now() - ONE_DAY,
|
||||||
end: () => Date.now()
|
end: () => Date.now()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Last 2 hours',
|
label: 'Last 2 hours',
|
||||||
bounds: {
|
bounds: {
|
||||||
start: () => Date.now() - 1000 * 60 * 60 * 2,
|
start: () => Date.now() - TWO_HOURS,
|
||||||
end: () => Date.now()
|
end: () => Date.now()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Last hour',
|
label: 'Last hour',
|
||||||
bounds: {
|
bounds: {
|
||||||
start: () => Date.now() - 1000 * 60 * 60,
|
start: () => Date.now() - ONE_HOUR,
|
||||||
end: () => Date.now()
|
end: () => Date.now()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,7 +102,7 @@
|
|||||||
records: 10,
|
records: 10,
|
||||||
// maximum duration between start and end bounds
|
// maximum duration between start and end bounds
|
||||||
// for utc-based time systems this is in milliseconds
|
// for utc-based time systems this is in milliseconds
|
||||||
limit: 1000 * 60 * 60 * 24
|
limit: ONE_DAY
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Realtime",
|
name: "Realtime",
|
||||||
@ -105,7 +111,44 @@
|
|||||||
clockOffsets: {
|
clockOffsets: {
|
||||||
start: - THIRTY_MINUTES,
|
start: - THIRTY_MINUTES,
|
||||||
end: THIRTY_SECONDS
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}));
|
}));
|
||||||
|
@ -141,10 +141,11 @@
|
|||||||
<ConductorMode class="c-conductor__mode-select" />
|
<ConductorMode class="c-conductor__mode-select" />
|
||||||
<ConductorTimeSystem class="c-conductor__time-system-select" />
|
<ConductorTimeSystem class="c-conductor__time-system-select" />
|
||||||
<ConductorHistory
|
<ConductorHistory
|
||||||
v-if="isFixed"
|
|
||||||
class="c-conductor__history-select"
|
class="c-conductor__history-select"
|
||||||
|
:offsets="openmct.time.clockOffsets()"
|
||||||
:bounds="bounds"
|
:bounds="bounds"
|
||||||
:time-system="timeSystem"
|
:time-system="timeSystem"
|
||||||
|
:mode="timeMode"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
@ -210,6 +211,11 @@ export default {
|
|||||||
isZooming: false
|
isZooming: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
timeMode() {
|
||||||
|
return this.isFixed ? 'fixed' : 'realtime';
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
document.addEventListener('keydown', this.handleKeyDown);
|
document.addEventListener('keydown', this.handleKeyDown);
|
||||||
document.addEventListener('keyup', this.handleKeyUp);
|
document.addEventListener('keyup', this.handleKeyUp);
|
||||||
|
@ -66,7 +66,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import toggleMixin from '../../ui/mixins/toggle-mixin';
|
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;
|
const DEFAULT_RECORDS = 10;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -77,72 +79,115 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
offsets: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: () => {}
|
||||||
|
},
|
||||||
timeSystem: {
|
timeSystem: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
* previous bounds entries available for easy re-use
|
* previous bounds entries available for easy re-use
|
||||||
* @history array of timespans
|
* @realtimeHistory array of timespans
|
||||||
* @timespans {start, end} number representing timestamp
|
* @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: []
|
presets: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
currentHistory() {
|
||||||
|
return this.mode + 'History';
|
||||||
|
},
|
||||||
|
isFixed() {
|
||||||
|
return this.openmct.time.clock() === undefined;
|
||||||
|
},
|
||||||
hasHistoryPresets() {
|
hasHistoryPresets() {
|
||||||
return this.timeSystem.isUTCBased && this.presets.length;
|
return this.timeSystem.isUTCBased && this.presets.length;
|
||||||
},
|
},
|
||||||
historyForCurrentTimeSystem() {
|
historyForCurrentTimeSystem() {
|
||||||
const history = this.history[this.timeSystem.key];
|
const history = this[this.currentHistory][this.timeSystem.key];
|
||||||
|
|
||||||
return history;
|
return history;
|
||||||
|
},
|
||||||
|
storageKey() {
|
||||||
|
let key = LOCAL_STORAGE_HISTORY_KEY_FIXED;
|
||||||
|
if (this.mode !== 'fixed') {
|
||||||
|
key = LOCAL_STORAGE_HISTORY_KEY_REALTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
bounds: {
|
bounds: {
|
||||||
|
handler() {
|
||||||
|
// only for fixed time since we track offsets for realtime
|
||||||
|
if (this.isFixed) {
|
||||||
|
this.addTimespan();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
offsets: {
|
||||||
handler() {
|
handler() {
|
||||||
this.addTimespan();
|
this.addTimespan();
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
},
|
},
|
||||||
timeSystem: {
|
timeSystem: {
|
||||||
handler() {
|
handler(ts) {
|
||||||
this.loadConfiguration();
|
this.loadConfiguration();
|
||||||
this.addTimespan();
|
this.addTimespan();
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
|
},
|
||||||
|
mode: function () {
|
||||||
|
this.getHistoryFromLocalStorage();
|
||||||
|
this.initializeHistoryIfNoHistory();
|
||||||
|
this.loadConfiguration();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.getHistoryFromLocalStorage();
|
||||||
this.initializeHistoryIfNoHistory();
|
this.initializeHistoryIfNoHistory();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getHistoryFromLocalStorage() {
|
getHistoryFromLocalStorage() {
|
||||||
const localStorageHistory = localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY);
|
const localStorageHistory = localStorage.getItem(this.storageKey);
|
||||||
const history = localStorageHistory ? JSON.parse(localStorageHistory) : undefined;
|
const history = localStorageHistory ? JSON.parse(localStorageHistory) : undefined;
|
||||||
|
this[this.currentHistory] = history;
|
||||||
return history;
|
|
||||||
},
|
},
|
||||||
initializeHistoryIfNoHistory() {
|
initializeHistoryIfNoHistory() {
|
||||||
if (!this.history) {
|
if (!this[this.currentHistory]) {
|
||||||
this.history = {};
|
this[this.currentHistory] = {};
|
||||||
this.persistHistoryToLocalStorage();
|
this.persistHistoryToLocalStorage();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
persistHistoryToLocalStorage() {
|
persistHistoryToLocalStorage() {
|
||||||
localStorage.setItem(LOCAL_STORAGE_HISTORY_KEY, JSON.stringify(this.history));
|
localStorage.setItem(this.storageKey, JSON.stringify(this[this.currentHistory]));
|
||||||
},
|
},
|
||||||
addTimespan() {
|
addTimespan() {
|
||||||
const key = this.timeSystem.key;
|
const key = this.timeSystem.key;
|
||||||
let [...currentHistory] = this.history[key] || [];
|
let [...currentHistory] = this[this.currentHistory][key] || [];
|
||||||
const timespan = {
|
const timespan = {
|
||||||
start: this.bounds.start,
|
start: this.isFixed ? this.bounds.start : this.offsets.start,
|
||||||
end: this.bounds.end
|
end: this.isFixed ? this.bounds.end : this.offsets.end
|
||||||
};
|
};
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
@ -160,20 +205,24 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
currentHistory.unshift(timespan);
|
currentHistory.unshift(timespan);
|
||||||
this.history[key] = currentHistory;
|
this.$set(this[this.currentHistory], key, currentHistory);
|
||||||
|
|
||||||
this.persistHistoryToLocalStorage();
|
this.persistHistoryToLocalStorage();
|
||||||
},
|
},
|
||||||
selectTimespan(timespan) {
|
selectTimespan(timespan) {
|
||||||
this.openmct.time.bounds(timespan);
|
if (this.isFixed) {
|
||||||
|
this.openmct.time.bounds(timespan);
|
||||||
|
} else {
|
||||||
|
this.openmct.time.clockOffsets(timespan);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
selectPresetBounds(bounds) {
|
selectPresetBounds(bounds) {
|
||||||
const start = typeof bounds.start === 'function' ? bounds.start() : bounds.start;
|
const start = typeof bounds.start === 'function' ? bounds.start() : bounds.start;
|
||||||
const end = typeof bounds.end === 'function' ? bounds.end() : bounds.end;
|
const end = typeof bounds.end === 'function' ? bounds.end() : bounds.end;
|
||||||
|
|
||||||
this.selectTimespan({
|
this.selectTimespan({
|
||||||
start: start,
|
start,
|
||||||
end: end
|
end
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
loadConfiguration() {
|
loadConfiguration() {
|
||||||
@ -184,7 +233,9 @@ export default {
|
|||||||
this.records = this.loadRecords(configurations);
|
this.records = this.loadRecords(configurations);
|
||||||
},
|
},
|
||||||
loadPresets(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 : [];
|
const presets = configuration ? configuration.presets : [];
|
||||||
|
|
||||||
return presets;
|
return presets;
|
||||||
@ -196,11 +247,24 @@ export default {
|
|||||||
return records;
|
return records;
|
||||||
},
|
},
|
||||||
formatTime(time) {
|
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({
|
const formatter = this.openmct.telemetry.getValueFormatter({
|
||||||
format: this.timeSystem.timeFormat
|
format: format
|
||||||
}).formatter;
|
}).formatter;
|
||||||
|
|
||||||
return formatter.format(time);
|
return (isNegativeOffset ? '-' : '') + formatter.format(time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user