change timeContexts to be reactive to objectPath

reactivity fixes to composables
This commit is contained in:
David Tsay 2024-05-17 16:13:50 -07:00
parent 852ee74094
commit 11adbd283a
7 changed files with 171 additions and 78 deletions

View File

@ -67,7 +67,7 @@
</template>
<script>
import { inject, onMounted, provide } from 'vue';
import { inject, provide } from 'vue';
import ConductorAxis from './ConductorAxis.vue';
import ConductorClock from './ConductorClock.vue';
@ -99,31 +99,13 @@ export default {
inject: ['openmct', 'configuration'],
setup() {
const openmct = inject('openmct');
const {
observeTimeSystem,
timeSystemFormatter,
timeSystemDurationFormatter,
isTimeSystemUTCBased
} = useTimeSystem(openmct);
const {
observeTimeMode,
timeMode,
isFixedTimeMode,
isRealTimeMode,
getAllModeMetadata,
getModeMetadata
} = useTimeMode(openmct);
const { observeTimeBounds, bounds, isTick } = useTimeBounds(openmct);
const { observeClock, clock, getAllClockMetadata, getClockMetadata } = useClock(openmct);
const { observeClockOffsets, offsets } = useClockOffsets(openmct);
onMounted(() => {
observeTimeSystem();
observeTimeMode();
observeTimeBounds();
observeClock();
observeClockOffsets();
});
const { timeSystemFormatter, timeSystemDurationFormatter, isTimeSystemUTCBased } =
useTimeSystem(openmct);
const { timeMode, isFixedTimeMode, isRealTimeMode, getAllModeMetadata, getModeMetadata } =
useTimeMode(openmct);
const { bounds, isTick } = useTimeBounds(openmct);
const { clock, getAllClockMetadata, getClockMetadata } = useClock(openmct);
const { offsets } = useClockOffsets(openmct);
provide('timeSystemFormatter', timeSystemFormatter);
provide('timeSystemDurationFormatter', timeSystemDurationFormatter);

View File

@ -20,34 +20,45 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import { onBeforeUnmount, ref } from 'vue';
import { onBeforeUnmount, ref, watch } from 'vue';
import { TIME_CONTEXT_EVENTS } from '../../api/time/constants.js';
import { useTimeContext } from './useTimeContext.js';
/**
* Provides reactive TODO,
* Provides reactive `clock` which is reactive to a time context,
* as well as a function to observe and update the component's clock,
* which automatically stops observing when the component is unmounted.
*
* @param {OpenMCT} [openmct] the Open MCT API
* @param {TimeContext} [timeContext] the time context to use for time API clock events
* @param {Array} objectPath The view's objectPath
* @returns {{
* observeClock: () => void,
* timeMode: import('vue').Ref<string>,
* isFixedTimeMode: import('vue').Ref<boolean>,
* isRealTimeMode: import('vue').Ref<boolean>
* clock: import('vue').Ref<string>,
* getAllClockMetadata: () => Object,
* getClockMetadata: () => Object
* }}
*/
export function useClock(openmct, timeContext = openmct.time) {
export function useClock(openmct, objectPath) {
let stopObservingClock;
const clock = ref(timeContext.getClock());
const { timeContext } = useTimeContext(openmct, objectPath);
const clock = ref(timeContext.value.getClock());
onBeforeUnmount(() => stopObservingClock?.());
watch(
timeContext,
(newContext, oldContext) => {
oldContext?.value?.off(TIME_CONTEXT_EVENTS.clockChanged, updateClock);
observeClock();
},
{ immediate: true }
);
function observeClock() {
timeContext.on(TIME_CONTEXT_EVENTS.clockChanged, updateClock);
stopObservingClock = () => timeContext.off(TIME_CONTEXT_EVENTS.clockChanged, updateClock);
timeContext.value.on(TIME_CONTEXT_EVENTS.clockChanged, updateClock);
stopObservingClock = () => timeContext.value.off(TIME_CONTEXT_EVENTS.clockChanged, updateClock);
}
function getAllClockMetadata(menuOptions) {
@ -55,8 +66,8 @@ export function useClock(openmct, timeContext = openmct.time) {
? menuOptions
.map((menuOption) => menuOption.clock)
.filter((key, index, array) => key !== undefined && array.indexOf(key) === index)
.map((clockKey) => timeContext.getAllClocks().find((_clock) => _clock.key === clockKey))
: timeContext.getAllClocks();
.map((clockKey) => timeContext.value.getAllClocks().find((_clock) => _clock.key === clockKey))
: timeContext.value.getAllClocks();
const clockMetadata = clocks.map(getClockMetadata);
@ -80,7 +91,7 @@ export function useClock(openmct, timeContext = openmct.time) {
}
function setClock(key) {
timeContext.setClock(key);
timeContext.value.setClock(key);
}
function updateClock(_clock) {
@ -136,7 +147,6 @@ export function useClock(openmct, timeContext = openmct.time) {
*/
return {
observeClock,
clock,
getAllClockMetadata,
getClockMetadata

View File

@ -20,9 +20,10 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import { onBeforeUnmount, shallowRef } from 'vue';
import { onBeforeUnmount, shallowRef, watch } from 'vue';
import { TIME_CONTEXT_EVENTS } from '../../api/time/constants.js';
import { useTimeContext } from './useTimeContext.js';
/**
* Provides reactive `offsets`,
@ -36,17 +37,28 @@ import { TIME_CONTEXT_EVENTS } from '../../api/time/constants.js';
* offsets: import('vue').Ref<object>,
* }}
*/
export function useClockOffsets(openmct, timeContext = openmct.time) {
export function useClockOffsets(openmct, objectPath) {
let stopObservingClockOffsets;
const offsets = shallowRef(timeContext.getClockOffsets());
const { timeContext } = useTimeContext(openmct, objectPath);
const offsets = shallowRef(timeContext.value.getClockOffsets());
onBeforeUnmount(() => stopObservingClockOffsets?.());
watch(
timeContext,
(newContext, oldContext) => {
oldContext?.value?.off(TIME_CONTEXT_EVENTS.clockOffsetsChanged, updateClockOffsets);
observeClockOffsets();
},
{ immediate: true }
);
function observeClockOffsets() {
timeContext.on(TIME_CONTEXT_EVENTS.clockOffsetsChanged, updateClockOffsets);
timeContext.value.on(TIME_CONTEXT_EVENTS.clockOffsetsChanged, updateClockOffsets);
stopObservingClockOffsets = () =>
timeContext.off(TIME_CONTEXT_EVENTS.clockOffsetsChanged, updateClockOffsets);
timeContext.value.off(TIME_CONTEXT_EVENTS.clockOffsetsChanged, updateClockOffsets);
}
function updateClockOffsets(_offsets) {
@ -54,7 +66,6 @@ export function useClockOffsets(openmct, timeContext = openmct.time) {
}
return {
observeClockOffsets,
offsets
};
}

View File

@ -20,36 +20,49 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import { onBeforeUnmount, ref, shallowRef } from 'vue';
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue';
import { TIME_CONTEXT_EVENTS } from '../../api/time/constants.js';
import { useTimeContext } from './useTimeContext.js';
import throttle from '../../utils/throttle.js';
const THROTTLE_RATE = 300;
/**
* Provides reactive `bounds`,
* as well as a function to observe and update bounds changes,
* which automatically stops observing when the component is unmounted.
*
* @param {OpenMCT} [openmct] the Open MCT API
* @param {TimeContext} [timeContext] the time context to use for time API bounds events
* @param {Array} objectPath The view's objectPath
* @returns {{
* observeTimeBounds: () => void,
* bounds: import('vue').Ref<object>,
* isTick: import('vue').Ref<boolean>
* }}
*/
export function useTimeBounds(openmct, timeContext = openmct.time) {
export function useTimeBounds(openmct, objectPath) {
let stopObservingTimeBounds;
const bounds = shallowRef(timeContext.getBounds());
const { timeContext } = useTimeContext(openmct, objectPath);
const bounds = shallowRef(timeContext.value.getBounds());
const isTick = ref(false);
onBeforeUnmount(() => stopObservingTimeBounds?.());
function observeTimeBounds(milliseconds = 300) {
timeContext.on(TIME_CONTEXT_EVENTS.boundsChanged, throttle(updateTimeBounds), milliseconds);
watch(
timeContext,
(newContext, oldContext) => {
oldContext?.value?.off(TIME_CONTEXT_EVENTS.boundsChanged, throttle(updateTimeBounds, THROTTLE_RATE));
observeTimeBounds();
},
{ immediate: true }
);
function observeTimeBounds() {
timeContext.value.on(TIME_CONTEXT_EVENTS.boundsChanged, throttle(updateTimeBounds, THROTTLE_RATE));
stopObservingTimeBounds = () =>
timeContext.off(TIME_CONTEXT_EVENTS.boundsChanged, throttle(updateTimeBounds), milliseconds);
timeContext.value.off(TIME_CONTEXT_EVENTS.boundsChanged, throttle(updateTimeBounds, THROTTLE_RATE));
}
function updateTimeBounds(_timeBounds, _isTick) {
@ -58,7 +71,6 @@ export function useTimeBounds(openmct, timeContext = openmct.time) {
}
return {
observeTimeBounds,
isTick,
bounds
};

View File

@ -0,0 +1,53 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2024, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import { shallowRef, toValue, watchEffect } from 'vue';
/**
* @typedef {import('@/api/time/TimeContext.js').default} TimeContext
* @typedef {import('@/api/time/GlobalTimeContext.js').default} GlobalTimeContext
*/
/**
* Provides the reactive TimeContext
* for the view's objectPath,
* or the GlobalTimeContext if objectPath is undefined.
*
* @param {OpenMCT} openmct the Open MCT API
* @param {Array} objectPath The view's objectPath
* @returns {{
* timeContext: TimeContext | GlobalTimeContext
* }}
*/
export function useTimeContext(openmct, objectPath) {
const timeContext = shallowRef(null);
watchEffect(() => getTimeContext());
function getTimeContext() {
const path = toValue(objectPath);
timeContext.value = path !== undefined ? openmct.time.getContextForView(path) : openmct.time;
}
return { timeContext };
}

View File

@ -20,40 +20,51 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import { computed, onBeforeUnmount, ref } from 'vue';
import { computed, onBeforeUnmount, ref, watch } from 'vue';
import {
FIXED_MODE_KEY,
REALTIME_MODE_KEY,
TIME_CONTEXT_EVENTS
} from '../../api/time/constants.js';
import { useTimeContext } from './useTimeContext.js';
/**
* Provides reactive `isFixedTimeMode` and `isRealTimeMode`,
* Provides reactive `timeMode` which is reactive to a time context,
* as well as a function to observe and update the component's time mode,
* which automatically stops observing when the component is unmounted.
*
* @param {OpenMCT} openmct the Open MCT API
* @param {TimeContext} [timeContext] the time context to use for time API mode events
* @param {Array} objectPath The view's objectPath
* @returns {{
* observeTimeMode: () => void,
* timeMode: import('vue').Ref<string>,
* isFixedTimeMode: import('vue').Ref<boolean>,
* isRealTimeMode: import('vue').Ref<boolean>
* }}
*/
export function useTimeMode(openmct, timeContext = openmct.time) {
export function useTimeMode(openmct, objectPath) {
let stopObservingTimeMode;
const timeMode = ref(timeContext.getMode());
const { timeContext } = useTimeContext(openmct, objectPath);
const timeMode = ref(timeContext.value.getMode());
const isFixedTimeMode = computed(() => timeMode.value === FIXED_MODE_KEY);
const isRealTimeMode = computed(() => timeMode.value === REALTIME_MODE_KEY);
onBeforeUnmount(() => stopObservingTimeMode?.());
watch(
timeContext,
(newContext, oldContext) => {
oldContext?.value?.off(TIME_CONTEXT_EVENTS.modeChanged, updateTimeMode);
observeTimeMode();
},
{ immediate: true }
);
function observeTimeMode() {
timeContext.on(TIME_CONTEXT_EVENTS.modeChanged, updateTimeMode);
stopObservingTimeMode = () => timeContext.off(TIME_CONTEXT_EVENTS.modeChanged, updateTimeMode);
timeContext.value.on(TIME_CONTEXT_EVENTS.modeChanged, updateTimeMode);
stopObservingTimeMode = () => timeContext.value.off(TIME_CONTEXT_EVENTS.modeChanged, updateTimeMode);
}
function getAllModeMetadata() {
@ -82,7 +93,7 @@ export function useTimeMode(openmct, timeContext = openmct.time) {
}
function setTimeMode(_timeMode) {
timeContext.setMode(_timeMode);
timeContext.value.setMode(_timeMode);
}
function updateTimeMode(_timeMode) {
@ -90,7 +101,6 @@ export function useTimeMode(openmct, timeContext = openmct.time) {
}
return {
observeTimeMode,
timeMode,
getAllModeMetadata,
getModeMetadata,

View File

@ -20,42 +20,58 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import { onBeforeUnmount, ref } from 'vue';
import { onBeforeUnmount, ref, watch } from 'vue';
import { TIME_CONTEXT_EVENTS } from '../../api/time/constants.js';
import { useTimeContext } from './useTimeContext.js';
const DEFAULT_DURATION_FORMATTER = 'duration';
/**
* TODO: could probably use a shallowRef for the timeSystem... and all the other components as well.
*
* Provides a reactive destructuring of the component's current time system,
* as well as a function to observe and update the component's time system,
* which automatically stops observing when the component is unmounted.
*
* @param {OpenMCT} openmct the Open MCT API
* @param {TimeContext} [timeContext] the time context to use for time API time system events
* @param {Array} objectPath The view's objectPath
* @returns {{
* observeTimeSystem: () => void,
* timeSystemKey: import('vue').Ref<string>,
* timeSystemFormatter: import('vue').Ref<() => void>,
* timeSystemDurationFormatter: import('vue').Ref<() => void>,
* isTimeSystemUTCBased: import('vue').Ref<boolean>
* }}
*/
export function useTimeSystem(openmct, timeContext = openmct.time) {
export function useTimeSystem(openmct, objectPath) {
let stopObservingTimeSystem;
const currentTimeSystem = timeContext.getTimeSystem();
const { timeContext } = useTimeContext(openmct, objectPath);
const timeSystemKey = ref(currentTimeSystem.key);
const timeSystemFormatter = ref(getFormatter(openmct, currentTimeSystem.timeFormat));
const initialTimeSystem = timeContext.value.getTimeSystem();
const timeSystemKey = ref(initialTimeSystem.key);
const timeSystemFormatter = ref(getFormatter(openmct, initialTimeSystem.timeFormat));
const timeSystemDurationFormatter = ref(
getFormatter(openmct, currentTimeSystem.durationFormat || DEFAULT_DURATION_FORMATTER)
getFormatter(openmct, initialTimeSystem.durationFormat || DEFAULT_DURATION_FORMATTER)
);
const isTimeSystemUTCBased = ref(currentTimeSystem.isUTCBased);
const isTimeSystemUTCBased = ref(initialTimeSystem.isUTCBased);
onBeforeUnmount(() => stopObservingTimeSystem?.());
watch(
timeContext,
(newContext, oldContext) => {
oldContext?.valu?.off(TIME_CONTEXT_EVENTS.timeSystemChanged, updateTimeSystem);
observeTimeSystem();
},
{ immediate: true }
);
function observeTimeSystem() {
timeContext.on('timeSystemChanged', updateTimeSystem);
stopObservingTimeSystem = () => timeContext.off('timeSystemChanged', updateTimeSystem);
timeContext.value.on(TIME_CONTEXT_EVENTS.timeSystemChanged, updateTimeSystem);
stopObservingTimeSystem = () =>
timeContext.value.off(TIME_CONTEXT_EVENTS.timeSystemChanged, updateTimeSystem);
}
function updateTimeSystem(timeSystem) {
@ -69,7 +85,6 @@ export function useTimeSystem(openmct, timeContext = openmct.time) {
}
return {
observeTimeSystem,
timeSystemKey,
timeSystemFormatter,
timeSystemDurationFormatter,