Compare commits

...

8 Commits

Author SHA1 Message Date
Jesse Mazzella
de5914b82d almost there!!! 2023-08-02 14:39:46 -07:00
Jesse Mazzella
41bbbb136b 🤷‍♂️ 2023-08-02 13:19:34 -07:00
Jamie V
0f199b6aff created a throttle util and using it in timer plugin to throttle refreshing the timer domain object 2023-08-02 12:29:26 -04:00
Jesse Mazzella
95e686038d fix: toggling markers, alarm markers, marker style + update Vue.extend() usage to Vue 3 (#6868)
* fix: update to `defineComponent` from `Vue.extend()`
* fix: unwrap Proxy arg before WeakMap.get()
* refactor: `defineComponent` not needed here
2023-08-01 14:07:59 -07:00
Shefali Joshi
f705bf9a61 Wait for bounds change to reset telemetry collection data (#6857)
* Reset and re-request telemetry only after receiving bounds following a mode change

* Don't check for tick - just in case the mode is set without bounds

* Use the imagery view timeContext to get related telemetry.

---------

Co-authored-by: Khalid Adil <khalidadil29@gmail.com>
2023-07-31 18:15:08 +00:00
Shefali Joshi
50559ac502 Don't allow editing line more when not editing display layout (#6858) 2023-07-31 10:16:52 -07:00
Jesse Mazzella
f0ef93dd3f fix: remove tree-item-destroyed event (#6856)
* fix: remove `tree-item-destroyed` event

- Composition listeners should only be removed if the item has been deleted or its parent has been collapsed. Both are handled by `mct-tree` already, so doing this additionally when tree-items unmount is redundant.

- In addition to that, any time the `visibleTreeItems` array changes, all tree-items will unmount, so this just doesn't work as intended-- it will unregister all composition listeners whenever the tree changes!

* test: stabilize imagery test

- Use keyboard gestures to navigate

* fix: lint:fix
2023-07-31 11:57:11 -05:00
Jesse Mazzella
3ae14cf786 Revert "[CI] Temporarily disable some tests" (#6853)
* Revert "[CI] Temporarily disable some tests (#6806)"

This reverts commit 85974fc5f1.

* fix(e2e): fix visual tests

* refactor: lint:fix

* fix: revert localStorage data changes

---------

Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
2023-07-28 17:20:06 -07:00
18 changed files with 149 additions and 79 deletions

View File

@@ -242,6 +242,10 @@ workflows:
name: e2e-stable
node-version: lts/hydrogen
suite: stable
- perf-test:
node-version: lts/hydrogen
- visual-test:
node-version: lts/hydrogen
the-nightly: #These jobs do not run on PRs, but against master at night
jobs:

View File

@@ -5,18 +5,18 @@
"origin": "http://localhost:8080",
"localStorage": [
{
"name": "mct",
"value": "{\"mine\":{\"identifier\":{\"key\":\"mine\",\"namespace\":\"\"},\"name\":\"My Items\",\"type\":\"folder\",\"composition\":[{\"key\":\"58f55f3a-46d9-4c37-a726-27b5d38b895a\",\"namespace\":\"\"}],\"location\":\"ROOT\",\"modified\":1689710399654,\"created\":1689710398656,\"persisted\":1689710399654},\"58f55f3a-46d9-4c37-a726-27b5d38b895a\":{\"identifier\":{\"key\":\"58f55f3a-46d9-4c37-a726-27b5d38b895a\",\"namespace\":\"\"},\"name\":\"Overlay Plot:b0ba67ab-e383-40c1-a181-82b174e8fdf0\",\"type\":\"telemetry.plot.overlay\",\"composition\":[{\"key\":\"19f2e461-190e-4662-8d62-251e90bb7aac\",\"namespace\":\"\"}],\"configuration\":{\"series\":[{\"identifier\":{\"key\":\"19f2e461-190e-4662-8d62-251e90bb7aac\",\"namespace\":\"\"}}]},\"notes\":\"framework/generateVisualTestData.e2e.spec.js\\nGenerate Visual Test Data @localStorage\\nchrome\",\"modified\":1689710400878,\"location\":\"mine\",\"created\":1689710399651,\"persisted\":1689710400878},\"19f2e461-190e-4662-8d62-251e90bb7aac\":{\"name\":\"Unnamed Sine Wave Generator\",\"type\":\"generator\",\"identifier\":{\"key\":\"19f2e461-190e-4662-8d62-251e90bb7aac\",\"namespace\":\"\"},\"telemetry\":{\"period\":10,\"amplitude\":1,\"offset\":0,\"dataRateInHz\":1,\"phase\":0,\"randomness\":0,\"loadDelay\":\"5000\",\"infinityValues\":false,\"staleness\":false},\"modified\":1689710400433,\"location\":\"58f55f3a-46d9-4c37-a726-27b5d38b895a\",\"created\":1689710400433,\"persisted\":1689710400433}}"
"name": "tcHistory",
"value": "{\"utc\":[{\"start\":1658617611983,\"end\":1658619411983}]}"
},
{
"name": "mct-recent-objects",
"value": "[{\"objectPath\":[{\"identifier\":{\"key\":\"58f55f3a-46d9-4c37-a726-27b5d38b895a\",\"namespace\":\"\"},\"name\":\"Overlay Plot:b0ba67ab-e383-40c1-a181-82b174e8fdf0\",\"type\":\"telemetry.plot.overlay\",\"composition\":[{\"key\":\"19f2e461-190e-4662-8d62-251e90bb7aac\",\"namespace\":\"\"}],\"configuration\":{\"series\":[]},\"notes\":\"framework/generateVisualTestData.e2e.spec.js\\nGenerate Visual Test Data @localStorage\\nchrome\",\"modified\":1689710400435,\"location\":\"mine\",\"created\":1689710399651,\"persisted\":1689710400436},{\"identifier\":{\"key\":\"mine\",\"namespace\":\"\"},\"name\":\"My Items\",\"type\":\"folder\",\"composition\":[{\"key\":\"58f55f3a-46d9-4c37-a726-27b5d38b895a\",\"namespace\":\"\"}],\"location\":\"ROOT\",\"modified\":1689710399654,\"created\":1689710398656,\"persisted\":1689710399654},{\"identifier\":{\"key\":\"ROOT\",\"namespace\":\"\"},\"name\":\"Open MCT\",\"type\":\"root\",\"composition\":[{\"key\":\"mine\",\"namespace\":\"\"}]}],\"navigationPath\":\"/browse/mine/58f55f3a-46d9-4c37-a726-27b5d38b895a\",\"domainObject\":{\"identifier\":{\"key\":\"58f55f3a-46d9-4c37-a726-27b5d38b895a\",\"namespace\":\"\"},\"name\":\"Overlay Plot:b0ba67ab-e383-40c1-a181-82b174e8fdf0\",\"type\":\"telemetry.plot.overlay\",\"composition\":[{\"key\":\"19f2e461-190e-4662-8d62-251e90bb7aac\",\"namespace\":\"\"}],\"configuration\":{\"series\":[]},\"notes\":\"framework/generateVisualTestData.e2e.spec.js\\nGenerate Visual Test Data @localStorage\\nchrome\",\"modified\":1689710400435,\"location\":\"mine\",\"created\":1689710399651,\"persisted\":1689710400436}},{\"objectPath\":[{\"identifier\":{\"key\":\"19f2e461-190e-4662-8d62-251e90bb7aac\",\"namespace\":\"\"},\"name\":\"Unnamed Sine Wave Generator\",\"type\":\"generator\",\"telemetry\":{\"period\":10,\"amplitude\":1,\"offset\":0,\"dataRateInHz\":1,\"phase\":0,\"randomness\":0,\"loadDelay\":\"5000\",\"infinityValues\":false,\"staleness\":false},\"modified\":1689710400433,\"location\":\"58f55f3a-46d9-4c37-a726-27b5d38b895a\",\"created\":1689710400433,\"persisted\":1689710400433},{\"identifier\":{\"key\":\"58f55f3a-46d9-4c37-a726-27b5d38b895a\",\"namespace\":\"\"},\"name\":\"Overlay Plot:b0ba67ab-e383-40c1-a181-82b174e8fdf0\",\"type\":\"telemetry.plot.overlay\",\"composition\":[{\"key\":\"19f2e461-190e-4662-8d62-251e90bb7aac\",\"namespace\":\"\"}],\"configuration\":{\"series\":[]},\"notes\":\"framework/generateVisualTestData.e2e.spec.js\\nGenerate Visual Test Data @localStorage\\nchrome\",\"modified\":1689710400435,\"location\":\"mine\",\"created\":1689710399651,\"persisted\":1689710400436},{\"identifier\":{\"key\":\"mine\",\"namespace\":\"\"},\"name\":\"My Items\",\"type\":\"folder\",\"composition\":[{\"key\":\"58f55f3a-46d9-4c37-a726-27b5d38b895a\",\"namespace\":\"\"}],\"location\":\"ROOT\",\"modified\":1689710399654,\"created\":1689710398656,\"persisted\":1689710399654},{\"identifier\":{\"key\":\"ROOT\",\"namespace\":\"\"},\"name\":\"Open MCT\",\"type\":\"root\",\"composition\":[{\"key\":\"mine\",\"namespace\":\"\"}]}],\"navigationPath\":\"/browse/mine/58f55f3a-46d9-4c37-a726-27b5d38b895a/19f2e461-190e-4662-8d62-251e90bb7aac\",\"domainObject\":{\"identifier\":{\"key\":\"19f2e461-190e-4662-8d62-251e90bb7aac\",\"namespace\":\"\"},\"name\":\"Unnamed Sine Wave Generator\",\"type\":\"generator\",\"telemetry\":{\"period\":10,\"amplitude\":1,\"offset\":0,\"dataRateInHz\":1,\"phase\":0,\"randomness\":0,\"loadDelay\":\"5000\",\"infinityValues\":false,\"staleness\":false},\"modified\":1689710400433,\"location\":\"58f55f3a-46d9-4c37-a726-27b5d38b895a\",\"created\":1689710400433,\"persisted\":1689710400433}},{\"objectPath\":[{\"identifier\":{\"key\":\"mine\",\"namespace\":\"\"},\"name\":\"My Items\",\"type\":\"folder\",\"composition\":[{\"key\":\"58f55f3a-46d9-4c37-a726-27b5d38b895a\",\"namespace\":\"\"}],\"location\":\"ROOT\",\"modified\":1689710399654,\"created\":1689710398656,\"persisted\":1689710399654},{\"identifier\":{\"key\":\"ROOT\",\"namespace\":\"\"},\"name\":\"Open MCT\",\"type\":\"root\",\"composition\":[{\"key\":\"mine\",\"namespace\":\"\"}]}],\"navigationPath\":\"/browse/mine\",\"domainObject\":{\"identifier\":{\"key\":\"mine\",\"namespace\":\"\"},\"name\":\"My Items\",\"type\":\"folder\",\"composition\":[{\"key\":\"58f55f3a-46d9-4c37-a726-27b5d38b895a\",\"namespace\":\"\"}],\"location\":\"ROOT\",\"modified\":1689710399654,\"created\":1689710398656,\"persisted\":1689710399654}}]"
"name": "mct",
"value": "{\"mine\":{\"identifier\":{\"key\":\"mine\",\"namespace\":\"\"},\"name\":\"My Items\",\"type\":\"folder\",\"composition\":[{\"key\":\"7fa5749b-8969-494c-9d85-c272516d333c\",\"namespace\":\"\"}],\"location\":\"ROOT\",\"persisted\":1658619412848,\"modified\":1658619412848},\"7fa5749b-8969-494c-9d85-c272516d333c\":{\"identifier\":{\"key\":\"7fa5749b-8969-494c-9d85-c272516d333c\",\"namespace\":\"\"},\"name\":\"Unnamed Overlay Plot\",\"type\":\"telemetry.plot.overlay\",\"composition\":[{\"key\":\"67cbb9fc-af46-4148-b9e5-aea11179ae4b\",\"namespace\":\"\"}],\"configuration\":{\"series\":[{\"identifier\":{\"key\":\"67cbb9fc-af46-4148-b9e5-aea11179ae4b\",\"namespace\":\"\"}}]},\"modified\":1658619413566,\"location\":\"mine\",\"persisted\":1658619413567},\"67cbb9fc-af46-4148-b9e5-aea11179ae4b\":{\"name\":\"Unnamed Sine Wave Generator\",\"type\":\"generator\",\"identifier\":{\"key\":\"67cbb9fc-af46-4148-b9e5-aea11179ae4b\",\"namespace\":\"\"},\"telemetry\":{\"period\":10,\"amplitude\":1,\"offset\":0,\"dataRateInHz\":1,\"phase\":0,\"randomness\":0,\"loadDelay\":\"5000\"},\"modified\":1658619413552,\"location\":\"7fa5749b-8969-494c-9d85-c272516d333c\",\"persisted\":1658619413552}}"
},
{
"name": "mct-tree-expanded",
"value": "[]"
"value": "[\"/browse/mine\"]"
}
]
}
]
}
}

View File

@@ -80,19 +80,21 @@ test.describe('Example Imagery Object', () => {
// flip on independent time conductor
await page.getByRole('switch', { name: 'Enable Independent Time Conductor' }).click();
await page.getByRole('button', { name: 'Independent Time Conductor Settings' }).click();
await page.getByRole('textbox', { name: 'Start date' }).click();
await page.getByRole('textbox', { name: 'Start date' }).fill('');
await page.getByRole('textbox', { name: 'Start date' }).fill('2021-12-30');
await page.getByRole('textbox', { name: 'Start time' }).click();
await page.keyboard.press('Tab');
await page.getByRole('textbox', { name: 'Start time' }).fill('');
await page.getByRole('textbox', { name: 'Start time' }).fill('01:01:00');
await page.getByRole('textbox', { name: 'End date' }).click();
await page.getByRole('textbox', { name: 'Start time' }).type('01:01:00');
await page.keyboard.press('Tab');
await page.getByRole('textbox', { name: 'End date' }).fill('');
await page.getByRole('textbox', { name: 'End date' }).fill('2021-12-30');
await page.getByRole('textbox', { name: 'End time' }).click();
await page.getByRole('textbox', { name: 'End date' }).type('2021-12-30');
await page.keyboard.press('Tab');
await page.getByRole('textbox', { name: 'End time' }).fill('');
await page.getByRole('textbox', { name: 'End time' }).fill('01:11:00');
await page.getByRole('button', { name: 'Submit time bounds' }).click();
await page.getByRole('textbox', { name: 'End time' }).type('01:11:00');
await page.keyboard.press('Tab');
await page.keyboard.press('Enter');
// expect(await page.getByRole('button', { name: 'Submit time bounds' }).isEnabled()).toBe(true);
// await page.getByRole('button', { name: 'Submit time bounds' }).click();
// check image date
await expect(page.getByText('2021-12-30 01:11:00.000Z').first()).toBeVisible();

View File

@@ -52,7 +52,8 @@ test.describe('Visual - addInit', () => {
path: path.join(__dirname, '../../helper', './addInitRestrictedNotebook.js')
});
//Go to baseURL
await page.goto('./#/browse/mine?hideTree=true', { waitUntil: 'networkidle' });
await page.goto('./#/browse/mine', { waitUntil: 'networkidle' });
await page.getByTitle('Collapse Browse Pane').click();
await createDomainObjectWithDefaults(page, { type: CUSTOM_NAME });

View File

@@ -41,7 +41,8 @@ test.describe('Visual - Controlled Clock @localStorage', () => {
test('Overlay Plot Loading Indicator @localStorage', async ({ page, theme }) => {
// Go to baseURL
await page.goto('./#/browse/mine?hideTree=true', { waitUntil: 'networkidle' });
await page.goto('./#/browse/mine', { waitUntil: 'networkidle' });
await page.getByTitle('Collapse Browse Pane').click();
await page.locator('a:has-text("Unnamed Overlay Plot Overlay Plot")').click();
//Ensure that we're on the Unnamed Overlay Plot object

View File

@@ -39,7 +39,8 @@ const { createDomainObjectWithDefaults } = require('../../appActions');
test.describe('Visual - Default', () => {
test.beforeEach(async ({ page }) => {
//Go to baseURL and Hide Tree
await page.goto('./#/browse/mine?hideTree=true', { waitUntil: 'networkidle' });
await page.goto('./#/browse/mine', { waitUntil: 'networkidle' });
await page.getByTitle('Collapse Browse Pane').click();
});
test.use({
clockOptions: {
@@ -99,6 +100,8 @@ test.describe('Visual - Default', () => {
let endDate = 'xxxx-01-01 02:00:00.000Z';
endDate = year + endDate.substring(4);
await page.getByRole('button', { name: 'Time Conductor Settings' }).click();
await page.locator('input[type="text"]').nth(1).fill(endDate.toString());
await page.locator('input[type="text"]').first().fill(startDate.toString());

View File

@@ -32,7 +32,8 @@ const percySnapshot = require('@percy/playwright');
test.describe('Grand Search', () => {
test.beforeEach(async ({ page, theme }) => {
//Go to baseURL and Hide Tree
await page.goto('./#/browse/mine?hideTree=true', { waitUntil: 'networkidle' });
await page.goto('./#/browse/mine', { waitUntil: 'networkidle' });
await page.getByTitle('Collapse Browse Pane').click();
});
test.use({
clockOptions: {

View File

@@ -204,7 +204,8 @@ export default class TelemetryAPI {
*/
standardizeRequestOptions(options = {}) {
if (!Object.hasOwn(options, 'start')) {
if (options.timeContext?.getBounds()) {
const bounds = options.timeContext?.getBounds();
if (bounds?.start) {
options.start = options.timeContext.getBounds().start;
} else {
options.start = this.openmct.time.getBounds().start;
@@ -212,7 +213,8 @@ export default class TelemetryAPI {
}
if (!Object.hasOwn(options, 'end')) {
if (options.timeContext?.getBounds()) {
const bounds = options.timeContext?.getBounds();
if (bounds?.end) {
options.end = options.timeContext.getBounds().end;
} else {
options.end = this.openmct.time.getBounds().end;

View File

@@ -71,6 +71,7 @@ export default class TelemetryCollection extends EventEmitter {
this.requestAbort = undefined;
this.isStrategyLatest = this.options.strategy === 'latest';
this.dataOutsideTimeBounds = false;
this.modeChanged = false;
}
/**
@@ -306,6 +307,12 @@ export default class TelemetryCollection extends EventEmitter {
* @private
*/
_bounds(bounds, isTick) {
if (this.modeChanged) {
this.modeChanged = false;
this._reset();
return;
}
let startChanged = this.lastBounds.start !== bounds.start;
let endChanged = this.lastBounds.end !== bounds.end;
@@ -439,7 +446,8 @@ export default class TelemetryCollection extends EventEmitter {
}
_timeModeChanged() {
this._reset();
//We're need this so that when the bounds change comes in after this mode change, we can reset and request historic telemetry
this.modeChanged = true;
}
/**

View File

@@ -101,7 +101,11 @@ export default {
type: Number,
required: true
},
multiSelect: Boolean
multiSelect: Boolean,
isEditing: {
type: Boolean,
required: true
}
},
data() {
return {
@@ -114,7 +118,7 @@ export default {
showFrameEdit() {
let layoutItem = this.selection.length > 0 && this.selection[0][0].context.layoutItem;
return !this.multiSelect && layoutItem && layoutItem.id === this.item.id;
return this.isEditing && !this.multiSelect && layoutItem && layoutItem.id === this.item.id;
},
position() {
let { x, y, x2, y2 } = this.item;

View File

@@ -209,6 +209,7 @@ import ImageControls from './ImageControls.vue';
import ImageThumbnail from './ImageThumbnail.vue';
import imageryData from '../../imagery/mixins/imageryData';
import AnnotationsCanvas from './AnnotationsCanvas.vue';
import { TIME_CONTEXT_EVENTS } from '../../../api/time/constants';
const REFRESH_CSS_MS = 500;
const DURATION_TRACK_MS = 1000;
@@ -754,32 +755,28 @@ export default {
this.stopFollowingTimeContext();
this.timeContext = this.openmct.time.getContextForView(this.objectPath);
//listen
this.timeContext.on('timeSystem', this.timeContextChanged);
this.timeContext.on('clock', this.timeContextChanged);
this.timeContextChanged();
this.timeContext.on('timeSystem', this.setModeAndTrackDuration);
this.timeContext.on(TIME_CONTEXT_EVENTS.clockChanged, this.setModeAndTrackDuration);
this.timeContext.on(TIME_CONTEXT_EVENTS.modeChanged, this.setModeAndTrackDuration);
this.setModeAndTrackDuration();
},
stopFollowingTimeContext() {
if (this.timeContext) {
this.timeContext.off('timeSystem', this.timeContextChanged);
this.timeContext.off('clock', this.timeContextChanged);
this.timeContext.off('timeSystem', this.setModeAndTrackDuration);
this.timeContext.off(TIME_CONTEXT_EVENTS.clockChanged, this.setModeAndTrackDuration);
this.timeContext.off(TIME_CONTEXT_EVENTS.modeChanged, this.setModeAndTrackDuration);
}
},
timeContextChanged() {
setModeAndTrackDuration() {
this.setIsFixed();
this.setCanTrackDuration();
this.trackDuration();
},
setIsFixed() {
this.isFixed = this.timeContext ? this.timeContext.isFixed() : this.openmct.time.isFixed();
this.isFixed = this.timeContext.isRealTime() === false;
},
setCanTrackDuration() {
let isRealTime;
if (this.timeContext) {
isRealTime = this.timeContext.isRealTime();
} else {
isRealTime = this.openmct.time.isRealTime();
}
let isRealTime = this.timeContext.isRealTime();
this.canTrackDuration = isRealTime && this.timeSystem.isUTCBased;
},
updateSelection(selection) {
@@ -809,13 +806,18 @@ export default {
}
},
async initializeRelatedTelemetry() {
this.relatedTelemetry = new RelatedTelemetry(this.openmct, this.domainObject, [
...this.spacecraftPositionKeys,
...this.spacecraftOrientationKeys,
...this.cameraKeys,
...this.sunKeys,
...this.transformationsKeys
]);
this.relatedTelemetry = new RelatedTelemetry(
this.openmct,
this.domainObject,
[
...this.spacecraftPositionKeys,
...this.spacecraftOrientationKeys,
...this.cameraKeys,
...this.sunKeys,
...this.transformationsKeys
],
this.timeContext
);
if (this.relatedTelemetry.hasRelatedTelemetry) {
await this.relatedTelemetry.load();

View File

@@ -30,9 +30,10 @@ function copyRelatedMetadata(metadata) {
import IndependentTimeContext from '@/api/time/IndependentTimeContext';
export default class RelatedTelemetry {
constructor(openmct, domainObject, telemetryKeys) {
constructor(openmct, domainObject, telemetryKeys, timeContext) {
this._openmct = openmct;
this._domainObject = domainObject;
this.timeContext = timeContext;
let metadata = this._openmct.telemetry.getMetadata(this._domainObject);
let imageHints = metadata.valuesForHints(['image'])[0];
@@ -43,7 +44,7 @@ export default class RelatedTelemetry {
this.keys = telemetryKeys;
this._timeFormatter = undefined;
this._timeSystemChange(this._openmct.time.timeSystem());
this._timeSystemChange(this.timeContext.timeSystem());
// grab related telemetry metadata
for (let key of this.keys) {
@@ -57,7 +58,7 @@ export default class RelatedTelemetry {
this._timeSystemChange = this._timeSystemChange.bind(this);
this.destroy = this.destroy.bind(this);
this._openmct.time.on('timeSystem', this._timeSystemChange);
this.timeContext.on('timeSystem', this._timeSystemChange);
}
}
@@ -109,7 +110,7 @@ export default class RelatedTelemetry {
// and set bounds.
ephemeralContext.resetContext();
const newBounds = {
start: this._openmct.time.bounds().start,
start: this.timeContext.bounds().start,
end: this._parseTime(datum)
};
ephemeralContext.bounds(newBounds);
@@ -183,7 +184,7 @@ export default class RelatedTelemetry {
}
destroy() {
this._openmct.time.off('timeSystem', this._timeSystemChange);
this.timeContext.off('timeSystem', this._timeSystemChange);
for (let key of this.keys) {
if (this[key] && this[key].unsubscribe) {
this[key].unsubscribe();

View File

@@ -42,7 +42,8 @@ import configStore from '../configuration/ConfigStore';
import PlotConfigurationModel from '../configuration/PlotConfigurationModel';
import LimitLine from './LimitLine.vue';
import LimitLabel from './LimitLabel.vue';
import Vue from 'vue';
import mount from 'utils/mount';
import { toRaw } from 'vue';
const MARKER_SIZE = 6.0;
const HIGHLIGHT_SIZE = MARKER_SIZE * 2.0;
@@ -315,7 +316,7 @@ export default {
return;
}
const elements = this.seriesElements.get(series);
const elements = this.seriesElements.get(toRaw(series));
elements.lines.forEach(function (line) {
this.lines.splice(this.lines.indexOf(line), 1);
line.destroy();
@@ -333,7 +334,7 @@ export default {
return;
}
const elements = this.seriesElements.get(series);
const elements = this.seriesElements.get(toRaw(series));
if (elements.alarmSet) {
elements.alarmSet.destroy();
this.alarmSets.splice(this.alarmSets.indexOf(elements.alarmSet), 1);
@@ -349,7 +350,7 @@ export default {
return;
}
const elements = this.seriesElements.get(series);
const elements = this.seriesElements.get(toRaw(series));
elements.pointSets.forEach(function (pointSet) {
this.pointSets.splice(this.pointSets.indexOf(pointSet), 1);
pointSet.destroy();
@@ -473,7 +474,7 @@ export default {
this.$emit('plotReinitializeCanvas');
},
removeChartElement(series) {
const elements = this.seriesElements.get(series);
const elements = this.seriesElements.get(toRaw(series));
elements.lines.forEach(function (line) {
this.lines.splice(this.lines.indexOf(line), 1);
@@ -576,7 +577,7 @@ export default {
this.seriesLimits.set(series, limitElements);
},
clearLimitLines(series) {
const seriesLimits = this.seriesLimits.get(series);
const seriesLimits = this.seriesLimits.get(toRaw(series));
if (seriesLimits) {
seriesLimits.limitLines.forEach(function (line) {
@@ -747,16 +748,14 @@ export default {
left: 0,
top: this.drawAPI.y(limit.point.y)
};
let LimitLineClass = Vue.extend(LimitLine);
const component = new LimitLineClass({
propsData: {
const { vNode } = mount(LimitLine, {
props: {
point,
limit
}
});
component.$mount();
return component.$el;
return vNode.el;
},
getLimitOverlap(limit, overlapMap) {
//calculate if limit lines are too close to each other
@@ -792,16 +791,14 @@ export default {
left: 0,
top: this.drawAPI.y(limit.point.y)
};
let LimitLabelClass = Vue.extend(LimitLabel);
const component = new LimitLabelClass({
propsData: {
const { vNode } = mount(LimitLabel, {
props: {
limit: Object.assign({}, overlap, limit),
point
}
});
component.$mount();
return component.$el;
return vNode.el;
},
drawAlarmPoints(alarmSet) {
this.drawAPI.drawLimitPoints(

View File

@@ -22,6 +22,7 @@
import Timer from './components/Timer.vue';
import mount from 'utils/mount';
import { markRaw, toRaw } from 'vue';
export default function TimerViewProvider(openmct) {
return {
@@ -32,11 +33,12 @@ export default function TimerViewProvider(openmct) {
return domainObject.type === 'timer';
},
view: function (domainObject, objectPath) {
view(domainObject, objectPath) {
let _destroy = null;
return {
show: function (element) {
show(element) {
const rawDomainObject = markRaw(toRaw(domainObject));
const { destroy } = mount(
{
el: element,
@@ -45,11 +47,11 @@ export default function TimerViewProvider(openmct) {
},
provide: {
openmct,
domainObject: rawDomainObject,
currentView: this
},
data() {
return {
domainObject,
objectPath
};
},
@@ -62,7 +64,7 @@ export default function TimerViewProvider(openmct) {
);
_destroy = destroy;
},
destroy: function () {
destroy() {
if (_destroy) {
_destroy();
}

View File

@@ -43,19 +43,17 @@
<script>
import raf from 'utils/raf';
import throttle from '../../../utils/throttle';
const moment = require('moment-timezone');
const momentDurationFormatSetup = require('moment-duration-format');
const refreshRateSeconds = 2;
momentDurationFormatSetup(moment);
export default {
inject: ['openmct', 'currentView'],
inject: ['openmct', 'currentView', 'domainObject'],
props: {
domainObject: {
type: Object,
required: true
},
objectPath: {
type: Array,
required: true
@@ -82,6 +80,10 @@ export default {
return this.lastTimestamp - this.relativeTimestamp;
},
timeTextValue() {
if(this.timerState !== 'started') {
// THIS IS NOT RIGHT!!!
return moment.duration(this.lastTimestamp - this.configuration.pausedTime, 'ms').format(this.format, { trim: false });
}
if (isNaN(this.timeDelta)) {
return null;
}
@@ -178,12 +180,15 @@ export default {
this.showOrHideAvailableActions();
}
},
created() {
this.refreshTimerObject = throttle(this.refreshTimerObject, refreshRateSeconds * 1000);
},
mounted() {
this.unobserve = this.openmct.objects.observe(
this.domainObject,
'configuration',
(configuration) => {
this.configuration = configuration;
'*',
(domainObject) => {
this.configuration = domainObject.configuration;
}
);
this.$nextTick(() => {
@@ -219,6 +224,11 @@ export default {
if (this.timerState === 'paused' && !this.lastTimestamp) {
this.lastTimestamp = this.pausedTime;
}
this.refreshTimerObject();
},
refreshTimerObject() {
this.openmct.objects.refresh(this.domainObject);
},
restartTimer() {
this.triggerAction('timer.restart');

View File

@@ -97,7 +97,6 @@
:loading-items="treeItemLoading"
:targeted-path="targetedPath"
@tree-item-mounted="scrollToCheck($event)"
@tree-item-destroyed="removeCompositionListenerFor($event)"
@tree-item-action="treeItemAction(treeItem, $event)"
@tree-item-selection="treeItemSelection(treeItem)"
@targeted-path-animation-end="targetedPathAnimationEnd()"

View File

@@ -191,7 +191,6 @@ export default {
},
unmounted() {
this.openmct.router.off('change:path', this.highlightIfNavigated);
this.$emit('tree-item-destroyed', this.navigationPath);
},
methods: {
targetedPathAnimationEnd($event) {

34
src/utils/throttle.js Normal file
View File

@@ -0,0 +1,34 @@
/**
* Creates a throttled function that only invokes the provided function at most once every
* specified number of milliseconds. Subsequent calls within the waiting period will be ignored.
* @param {Function} func The function to throttle.
* @param {number} wait The number of milliseconds to wait between successive calls to the function.
* @return {Function} Returns the new throttled function.
*/
export default function throttle(func, wait) {
let timeout;
let result;
let previous = 0;
return function (...args) {
const now = new Date().getTime();
const remaining = wait - (now - previous);
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func(...args);
} else if (!timeout) {
timeout = setTimeout(() => {
previous = new Date().getTime();
timeout = null;
result = func(...args);
}, remaining);
}
return result;
};
}