mirror of
https://github.com/nasa/openmct.git
synced 2025-06-25 18:50:11 +00:00
Compare commits
3 Commits
git-error-
...
simulate-c
Author | SHA1 | Date | |
---|---|---|---|
d5a03e0dd0 | |||
ff975656d4 | |||
58aeab3d31 |
@ -23,7 +23,8 @@
|
|||||||
const { test } = require('../../../fixtures');
|
const { test } = require('../../../fixtures');
|
||||||
const { expect } = require('@playwright/test');
|
const { expect } = require('@playwright/test');
|
||||||
|
|
||||||
test.describe('Telemetry Table', () => {
|
// eslint-disable-next-line playwright/no-focused-test
|
||||||
|
test.describe.only('Telemetry Table', () => {
|
||||||
test('unpauses when paused by button and user changes bounds', async ({ page }) => {
|
test('unpauses when paused by button and user changes bounds', async ({ page }) => {
|
||||||
test.info().annotations.push({
|
test.info().annotations.push({
|
||||||
type: 'issue',
|
type: 'issue',
|
||||||
|
@ -19,4 +19,4 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "openmct",
|
"name": "openmct",
|
||||||
"version": "2.0.5",
|
"version": "2.0.5-SNAPSHOT",
|
||||||
"description": "The Open MCT core platform",
|
"description": "The Open MCT core platform",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/eslint-parser": "7.18.2",
|
"@babel/eslint-parser": "7.18.2",
|
||||||
@ -89,7 +89,7 @@
|
|||||||
"test": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run",
|
"test": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run",
|
||||||
"test:firefox": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run --browsers=FirefoxHeadless",
|
"test:firefox": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run --browsers=FirefoxHeadless",
|
||||||
"test:debug": "cross-env NODE_ENV=debug karma start --no-single-run",
|
"test:debug": "cross-env NODE_ENV=debug karma start --no-single-run",
|
||||||
"test:e2e:ci": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome smoke branding default condition timeConductor clock exampleImagery persistence performance",
|
"test:e2e:ci": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome telemetryTable",
|
||||||
"test:e2e:local": "npx playwright test --config=e2e/playwright-local.config.js --project=chrome",
|
"test:e2e:local": "npx playwright test --config=e2e/playwright-local.config.js --project=chrome",
|
||||||
"test:e2e:updatesnapshots": "npx playwright test --config=e2e/playwright-local.config.js --project=chrome --grep @snapshot --update-snapshots",
|
"test:e2e:updatesnapshots": "npx playwright test --config=e2e/playwright-local.config.js --project=chrome --grep @snapshot --update-snapshots",
|
||||||
"test:e2e:visual": "percy exec --config ./e2e/.percy.yml -- npx playwright test --config=e2e/playwright-visual.config.js",
|
"test:e2e:visual": "percy exec --config ./e2e/.percy.yml -- npx playwright test --config=e2e/playwright-visual.config.js",
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
&[s-selected] {
|
&[s-selected] {
|
||||||
// All frames selected while editing
|
// All frames selected while editing
|
||||||
|
border: $editFrameSelectedBorder;
|
||||||
box-shadow: $editFrameSelectedShdw;
|
box-shadow: $editFrameSelectedShdw;
|
||||||
|
|
||||||
.c-frame__move-bar {
|
.c-frame__move-bar {
|
||||||
|
@ -41,7 +41,7 @@ describe('the plugin', function () {
|
|||||||
element.appendChild(child);
|
element.appendChild(child);
|
||||||
|
|
||||||
openmct.on('start', done);
|
openmct.on('start', done);
|
||||||
openmct.start(child);
|
openmct.startHeadless();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -141,10 +141,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[s-selected].c-fl-frame__drag-wrapper {
|
|
||||||
border: $editFrameSelectedBorder;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****** THEIR FRAMES */
|
/****** THEIR FRAMES */
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
import { createOpenMct, resetApplicationState } from 'utils/testing';
|
import { createOpenMct, resetApplicationState } from 'utils/testing';
|
||||||
import FlexibleLayout from './plugin';
|
import FlexibleLayout from './plugin';
|
||||||
import Vue from 'vue';
|
|
||||||
|
|
||||||
describe('the plugin', function () {
|
describe('the plugin', function () {
|
||||||
let element;
|
let element;
|
||||||
@ -62,7 +61,7 @@ describe('the plugin', function () {
|
|||||||
element.appendChild(child);
|
element.appendChild(child);
|
||||||
|
|
||||||
openmct.on('start', done);
|
openmct.on('start', done);
|
||||||
openmct.start(child);
|
openmct.startHeadless();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@ -84,16 +83,6 @@ describe('the plugin', function () {
|
|||||||
it('provides a view', () => {
|
it('provides a view', () => {
|
||||||
expect(flexibleLayoutViewProvider).toBeDefined();
|
expect(flexibleLayoutViewProvider).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders a view', async () => {
|
|
||||||
const flexibleView = flexibleLayoutViewProvider.view(testViewObject, []);
|
|
||||||
flexibleView.show(child, false);
|
|
||||||
|
|
||||||
await Vue.nextTick();
|
|
||||||
const flexTitle = child.querySelector('.l-browse-bar .c-object-label__name');
|
|
||||||
|
|
||||||
expect(flexTitle).not.toBeNull();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('the toolbar', () => {
|
describe('the toolbar', () => {
|
||||||
|
@ -14,8 +14,6 @@
|
|||||||
type="range"
|
type="range"
|
||||||
min="0"
|
min="0"
|
||||||
max="500"
|
max="500"
|
||||||
draggable="true"
|
|
||||||
@dragstart.stop.prevent
|
|
||||||
@change="notifyFiltersChanged"
|
@change="notifyFiltersChanged"
|
||||||
@input="notifyFiltersChanged"
|
@input="notifyFiltersChanged"
|
||||||
>
|
>
|
||||||
@ -26,8 +24,6 @@
|
|||||||
type="range"
|
type="range"
|
||||||
min="0"
|
min="0"
|
||||||
max="500"
|
max="500"
|
||||||
draggable="true"
|
|
||||||
@dragstart.stop.prevent
|
|
||||||
@change="notifyFiltersChanged"
|
@change="notifyFiltersChanged"
|
||||||
@input="notifyFiltersChanged"
|
@input="notifyFiltersChanged"
|
||||||
>
|
>
|
||||||
|
@ -21,11 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div class="h-local-controls h-local-controls--overlay-content h-local-controls--menus-aligned c-local-controls--show-on-hover">
|
||||||
class="h-local-controls h-local-controls--overlay-content h-local-controls--menus-aligned c-local-controls--show-on-hover"
|
|
||||||
role="toolbar"
|
|
||||||
aria-label="Image controls"
|
|
||||||
>
|
|
||||||
<imagery-view-menu-switcher
|
<imagery-view-menu-switcher
|
||||||
:icon-class="'icon-brightness'"
|
:icon-class="'icon-brightness'"
|
||||||
:title="'Brightness and contrast'"
|
:title="'Brightness and contrast'"
|
||||||
@ -177,7 +173,7 @@ export default {
|
|||||||
this.$emit('filtersUpdated', this.filters);
|
this.$emit('filtersUpdated', this.filters);
|
||||||
},
|
},
|
||||||
handleResetFilters() {
|
handleResetFilters() {
|
||||||
this.filters = {...DEFAULT_FILTER_VALUES};
|
this.filters = DEFAULT_FILTER_VALUES;
|
||||||
this.notifyFiltersChanged();
|
this.notifyFiltersChanged();
|
||||||
},
|
},
|
||||||
limitZoomRange(factor) {
|
limitZoomRange(factor) {
|
||||||
|
@ -403,9 +403,6 @@ export default {
|
|||||||
formattedDuration() {
|
formattedDuration() {
|
||||||
let result = 'N/A';
|
let result = 'N/A';
|
||||||
let negativeAge = -1;
|
let negativeAge = -1;
|
||||||
if (!Number.isInteger(this.numericDuration)) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.numericDuration > TWENTYFOUR_HOURS) {
|
if (this.numericDuration > TWENTYFOUR_HOURS) {
|
||||||
negativeAge *= (this.numericDuration / TWENTYFOUR_HOURS);
|
negativeAge *= (this.numericDuration / TWENTYFOUR_HOURS);
|
||||||
@ -908,10 +905,8 @@ export default {
|
|||||||
let currentTime = this.timeContext.clock() && this.timeContext.clock().currentValue();
|
let currentTime = this.timeContext.clock() && this.timeContext.clock().currentValue();
|
||||||
if (currentTime === undefined) {
|
if (currentTime === undefined) {
|
||||||
this.numericDuration = currentTime;
|
this.numericDuration = currentTime;
|
||||||
} else if (Number.isInteger(this.parsedSelectedTime)) {
|
|
||||||
this.numericDuration = currentTime - this.parsedSelectedTime;
|
|
||||||
} else {
|
} else {
|
||||||
this.numericDuration = undefined;
|
this.numericDuration = currentTime - this.parsedSelectedTime;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
resetAgeCSS() {
|
resetAgeCSS() {
|
||||||
|
@ -68,24 +68,15 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
&__background-image {
|
&__background-image {
|
||||||
// Actually does the image display
|
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
height: 100%; //fallback value
|
|
||||||
}
|
}
|
||||||
&__image {
|
&__image {
|
||||||
// Present to allow Save As... image
|
|
||||||
position: absolute;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
opacity: 0;
|
visibility: hidden;
|
||||||
}
|
display: contents;
|
||||||
|
|
||||||
&__image-save-proxy {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,18 +70,22 @@ export default {
|
|||||||
this.timeContext.off('timeSystem', this.timeSystemChange);
|
this.timeContext.off('timeSystem', this.timeSystemChange);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isDatumValid(datum) {
|
datumIsNotValid(datum) {
|
||||||
//TODO: Add a check to see if there are duplicate images (identical image timestamp and url subsequently)
|
if (this.imageHistory.length === 0) {
|
||||||
if (!datum) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const datumURL = this.formatImageUrl(datum);
|
||||||
|
const lastHistoryURL = this.formatImageUrl(this.imageHistory.slice(-1)[0]);
|
||||||
|
|
||||||
|
// datum is not valid if it matches the last datum in history,
|
||||||
|
// or it is before the last datum in the history
|
||||||
const datumTimeCheck = this.parseTime(datum);
|
const datumTimeCheck = this.parseTime(datum);
|
||||||
const bounds = this.timeContext.bounds();
|
const historyTimeCheck = this.parseTime(this.imageHistory.slice(-1)[0]);
|
||||||
|
const matchesLast = (datumTimeCheck === historyTimeCheck) && (datumURL === lastHistoryURL);
|
||||||
|
const isStale = datumTimeCheck < historyTimeCheck;
|
||||||
|
|
||||||
const isOutOfBounds = datumTimeCheck < bounds.start || datumTimeCheck > bounds.end;
|
return matchesLast || isStale;
|
||||||
|
|
||||||
return !isOutOfBounds;
|
|
||||||
},
|
},
|
||||||
formatImageUrl(datum) {
|
formatImageUrl(datum) {
|
||||||
if (!datum) {
|
if (!datum) {
|
||||||
@ -128,19 +132,25 @@ export default {
|
|||||||
return this.requestHistory();
|
return this.requestHistory();
|
||||||
},
|
},
|
||||||
async requestHistory() {
|
async requestHistory() {
|
||||||
|
let bounds = this.timeContext.bounds();
|
||||||
this.requestCount++;
|
this.requestCount++;
|
||||||
const requestId = this.requestCount;
|
const requestId = this.requestCount;
|
||||||
const bounds = this.timeContext.bounds();
|
this.imageHistory = [];
|
||||||
|
|
||||||
const data = await this.openmct.telemetry
|
let data = await this.openmct.telemetry
|
||||||
.request(this.domainObject, bounds) || [];
|
.request(this.domainObject, bounds) || [];
|
||||||
// wait until new request resolves to do comparison
|
|
||||||
if (this.requestCount !== requestId) {
|
|
||||||
return this.imageHistory = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const imagery = data.filter(this.isDatumValid).map(this.normalizeDatum);
|
if (this.requestCount === requestId) {
|
||||||
this.imageHistory = imagery;
|
let imagery = [];
|
||||||
|
data.forEach((datum) => {
|
||||||
|
let image = this.normalizeDatum(datum);
|
||||||
|
if (image) {
|
||||||
|
imagery.push(image);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//this is to optimize anything that reacts to imageHistory length
|
||||||
|
this.imageHistory = imagery;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
clearData(domainObjectToClear) {
|
clearData(domainObjectToClear) {
|
||||||
// global clearData button is accepted therefore no truthy check on inputted param
|
// global clearData button is accepted therefore no truthy check on inputted param
|
||||||
@ -170,29 +180,27 @@ export default {
|
|||||||
.subscribe(this.domainObject, (datum) => {
|
.subscribe(this.domainObject, (datum) => {
|
||||||
let parsedTimestamp = this.parseTime(datum);
|
let parsedTimestamp = this.parseTime(datum);
|
||||||
let bounds = this.timeContext.bounds();
|
let bounds = this.timeContext.bounds();
|
||||||
if (!(parsedTimestamp >= bounds.start && parsedTimestamp <= bounds.end)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isDatumValid(datum)) {
|
if (parsedTimestamp >= bounds.start && parsedTimestamp <= bounds.end) {
|
||||||
this.imageHistory.push(this.normalizeDatum(datum));
|
let image = this.normalizeDatum(datum);
|
||||||
|
if (image) {
|
||||||
|
this.imageHistory.push(image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
normalizeDatum(datum) {
|
normalizeDatum(datum) {
|
||||||
|
if (this.datumIsNotValid(datum)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const formattedTime = this.formatTime(datum);
|
let image = { ...datum };
|
||||||
const url = this.formatImageUrl(datum);
|
image.formattedTime = this.formatTime(datum);
|
||||||
const time = this.parseTime(formattedTime);
|
image.url = this.formatImageUrl(datum);
|
||||||
const imageDownloadName = this.getImageDownloadName(datum);
|
image.time = this.parseTime(image.formattedTime);
|
||||||
|
image.imageDownloadName = this.getImageDownloadName(datum);
|
||||||
|
|
||||||
return {
|
return image;
|
||||||
...datum,
|
|
||||||
formattedTime,
|
|
||||||
url,
|
|
||||||
time,
|
|
||||||
imageDownloadName
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
getFormatter(key) {
|
getFormatter(key) {
|
||||||
let metadataValue = this.metadata.value(key) || { format: key };
|
let metadataValue = this.metadata.value(key) || { format: key };
|
||||||
|
@ -84,6 +84,7 @@ describe("The Imagery View Layouts", () => {
|
|||||||
let telemetryPromise;
|
let telemetryPromise;
|
||||||
let telemetryPromiseResolve;
|
let telemetryPromiseResolve;
|
||||||
let cleanupFirst;
|
let cleanupFirst;
|
||||||
|
let isClearDataTriggered;
|
||||||
|
|
||||||
let openmct;
|
let openmct;
|
||||||
let parent;
|
let parent;
|
||||||
@ -204,12 +205,20 @@ describe("The Imagery View Layouts", () => {
|
|||||||
cleanupFirst = [];
|
cleanupFirst = [];
|
||||||
|
|
||||||
openmct = createOpenMct();
|
openmct = createOpenMct();
|
||||||
|
openmct.time.timeSystem('utc', {
|
||||||
|
start: START - (5 * ONE_MINUTE),
|
||||||
|
end: START + (5 * ONE_MINUTE)
|
||||||
|
});
|
||||||
|
|
||||||
telemetryPromise = new Promise((resolve) => {
|
telemetryPromise = new Promise((resolve) => {
|
||||||
telemetryPromiseResolve = resolve;
|
telemetryPromiseResolve = resolve;
|
||||||
});
|
});
|
||||||
|
|
||||||
spyOn(openmct.telemetry, 'request').and.callFake(() => {
|
spyOn(openmct.telemetry, 'request').and.callFake(() => {
|
||||||
|
if (isClearDataTriggered) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
telemetryPromiseResolve(imageTelemetry);
|
telemetryPromiseResolve(imageTelemetry);
|
||||||
|
|
||||||
return telemetryPromise;
|
return telemetryPromise;
|
||||||
@ -328,93 +337,44 @@ describe("The Imagery View Layouts", () => {
|
|||||||
expect(imageryView).toBeDefined();
|
expect(imageryView).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Clear data action for imagery", () => {
|
describe("imagery view", () => {
|
||||||
let applicableViews;
|
let applicableViews;
|
||||||
let imageryViewProvider;
|
let imageryViewProvider;
|
||||||
let imageryView;
|
let imageryView;
|
||||||
let componentView;
|
|
||||||
let clearDataPlugin;
|
let clearDataPlugin;
|
||||||
let clearDataAction;
|
let clearDataAction;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
openmct.time.timeSystem('utc', {
|
|
||||||
start: START - (5 * ONE_MINUTE),
|
|
||||||
end: START + (5 * ONE_MINUTE)
|
|
||||||
});
|
|
||||||
|
|
||||||
applicableViews = openmct.objectViews.get(imageryObject, [imageryObject]);
|
applicableViews = openmct.objectViews.get(imageryObject, [imageryObject]);
|
||||||
imageryViewProvider = applicableViews.find(viewProvider => viewProvider.key === imageryKey);
|
imageryViewProvider = applicableViews.find(viewProvider => viewProvider.key === imageryKey);
|
||||||
imageryView = imageryViewProvider.view(imageryObject, [imageryObject]);
|
imageryView = imageryViewProvider.view(imageryObject, [imageryObject]);
|
||||||
imageryView.show(child);
|
imageryView.show(child);
|
||||||
componentView = imageryView._getInstance().$children[0];
|
|
||||||
|
|
||||||
clearDataPlugin = new ClearDataPlugin(
|
clearDataPlugin = new ClearDataPlugin(
|
||||||
['example.imagery'],
|
['example.imagery'],
|
||||||
{indicator: true}
|
{indicator: true}
|
||||||
);
|
);
|
||||||
openmct.install(clearDataPlugin);
|
openmct.install(clearDataPlugin);
|
||||||
clearDataAction = openmct.actions.getAction('clear-data-action');
|
clearDataAction = openmct.actions.getAction('clear-data-action');
|
||||||
|
|
||||||
return Vue.nextTick();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('clear data action is installed', () => {
|
|
||||||
expect(clearDataAction).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('on clearData action should clear data for object is selected', (done) => {
|
|
||||||
// force show the thumbnails
|
// force show the thumbnails
|
||||||
componentView.forceShowThumbnails = true;
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
let clearDataResolve;
|
|
||||||
let telemetryRequestPromise = new Promise((resolve) => {
|
|
||||||
clearDataResolve = resolve;
|
|
||||||
});
|
|
||||||
expect(parent.querySelectorAll('.c-imagery__thumb').length).not.toBe(0);
|
|
||||||
|
|
||||||
openmct.objectViews.on('clearData', (_domainObject) => {
|
|
||||||
return Vue.nextTick(() => {
|
|
||||||
expect(parent.querySelectorAll('.c-imagery__thumb').length).toBe(0);
|
|
||||||
|
|
||||||
clearDataResolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
clearDataAction.invoke(imageryObject);
|
|
||||||
|
|
||||||
telemetryRequestPromise.then(() => {
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("imagery view", () => {
|
|
||||||
let applicableViews;
|
|
||||||
let imageryViewProvider;
|
|
||||||
let imageryView;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
openmct.time.timeSystem('utc', {
|
|
||||||
start: START - (5 * ONE_MINUTE),
|
|
||||||
end: START + (5 * ONE_MINUTE)
|
|
||||||
});
|
|
||||||
|
|
||||||
applicableViews = openmct.objectViews.get(imageryObject, [imageryObject]);
|
|
||||||
imageryViewProvider = applicableViews.find(viewProvider => viewProvider.key === imageryKey);
|
|
||||||
imageryView = imageryViewProvider.view(imageryObject, [imageryObject]);
|
|
||||||
imageryView.show(child);
|
|
||||||
|
|
||||||
imageryView._getInstance().$children[0].forceShowThumbnails = true;
|
imageryView._getInstance().$children[0].forceShowThumbnails = true;
|
||||||
|
|
||||||
return Vue.nextTick();
|
return Vue.nextTick();
|
||||||
});
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
isClearDataTriggered = false;
|
||||||
|
// openmct.time.stopClock();
|
||||||
|
// openmct.router.removeListener('change:hash', resolveFunction);
|
||||||
|
// imageryView.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
it("on mount should show the the most recent image", () => {
|
it("on mount should show the the most recent image", (done) => {
|
||||||
//Looks like we need Vue.nextTick here so that computed properties settle down
|
//Looks like we need Vue.nextTick here so that computed properties settle down
|
||||||
return Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
const imageInfo = getImageInfo(parent);
|
const imageInfo = getImageInfo(parent);
|
||||||
|
|
||||||
expect(imageInfo.url.indexOf(imageTelemetry[COUNT - 1].timeId)).not.toEqual(-1);
|
expect(imageInfo.url.indexOf(imageTelemetry[COUNT - 1].timeId)).not.toEqual(-1);
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -462,7 +422,7 @@ describe("The Imagery View Layouts", () => {
|
|||||||
|
|
||||||
it("should show that an image is not new", (done) => {
|
it("should show that an image is not new", (done) => {
|
||||||
Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
const target = imageTelemetry[4].url;
|
const target = imageTelemetry[2].url;
|
||||||
parent.querySelectorAll(`img[src='${target}']`)[0].click();
|
parent.querySelectorAll(`img[src='${target}']`)[0].click();
|
||||||
|
|
||||||
Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
@ -584,6 +544,25 @@ describe("The Imagery View Layouts", () => {
|
|||||||
expect(imageSizeAfter.width).toBeLessThan(imageSizeBefore.width);
|
expect(imageSizeAfter.width).toBeLessThan(imageSizeBefore.width);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('clear data action is installed', () => {
|
||||||
|
expect(clearDataAction).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('on clearData action should clear data for object is selected', async (done) => {
|
||||||
|
// force show the thumbnails
|
||||||
|
imageryView._getInstance().$children[0].forceShowThumbnails = true;
|
||||||
|
await Vue.nextTick();
|
||||||
|
expect(parent.querySelectorAll('.c-imagery__thumb').length).not.toBe(0);
|
||||||
|
openmct.objectViews.on('clearData', async (_domainObject) => {
|
||||||
|
await Vue.nextTick();
|
||||||
|
expect(parent.querySelectorAll('.c-imagery__thumb').length).toBe(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
// stubbed telemetry data will return empty array when true
|
||||||
|
isClearDataTriggered = true;
|
||||||
|
clearDataAction.invoke(imageryObject);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("imagery time strip view", () => {
|
describe("imagery time strip view", () => {
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
:class="[plotLegendExpandedStateClass, plotLegendPositionClass]"
|
:class="[plotLegendExpandedStateClass, plotLegendPositionClass]"
|
||||||
>
|
>
|
||||||
<plot-legend
|
<plot-legend
|
||||||
v-if="!isNestedWithinAStackedPlot"
|
|
||||||
:cursor-locked="!!lockHighlightPoint"
|
:cursor-locked="!!lockHighlightPoint"
|
||||||
:series="seriesModels"
|
:series="seriesModels"
|
||||||
:highlights="highlights"
|
:highlights="highlights"
|
||||||
@ -247,18 +246,6 @@ export default {
|
|||||||
default() {
|
default() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
limitLineLabels: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
colorPalette: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -279,7 +266,7 @@ export default {
|
|||||||
isRealTime: this.openmct.time.clock() !== undefined,
|
isRealTime: this.openmct.time.clock() !== undefined,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
isTimeOutOfSync: false,
|
isTimeOutOfSync: false,
|
||||||
showLimitLineLabels: this.limitLineLabels,
|
showLimitLineLabels: undefined,
|
||||||
isFrozenOnMouseDown: false,
|
isFrozenOnMouseDown: false,
|
||||||
hasSameRangeValue: true,
|
hasSameRangeValue: true,
|
||||||
cursorGuide: this.initCursorGuide,
|
cursorGuide: this.initCursorGuide,
|
||||||
@ -287,22 +274,13 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isNestedWithinAStackedPlot() {
|
|
||||||
const isNavigatedObject = this.openmct.router.isNavigatedObject([this.domainObject].concat(this.path));
|
|
||||||
|
|
||||||
return !isNavigatedObject && this.path.find((pathObject, pathObjIndex) => pathObject.type === 'telemetry.plot.stacked');
|
|
||||||
},
|
|
||||||
isFrozen() {
|
isFrozen() {
|
||||||
return this.config.xAxis.get('frozen') === true && this.config.yAxis.get('frozen') === true;
|
return this.config.xAxis.get('frozen') === true && this.config.yAxis.get('frozen') === true;
|
||||||
},
|
},
|
||||||
plotLegendPositionClass() {
|
plotLegendPositionClass() {
|
||||||
return !this.isNestedWithinAStackedPlot ? `plot-legend-${this.config.legend.get('position')}` : '';
|
return `plot-legend-${this.config.legend.get('position')}`;
|
||||||
},
|
},
|
||||||
plotLegendExpandedStateClass() {
|
plotLegendExpandedStateClass() {
|
||||||
if (this.isNestedWithinAStackedPlot) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.config.legend.get('expanded')) {
|
if (this.config.legend.get('expanded')) {
|
||||||
return 'plot-legend-expanded';
|
return 'plot-legend-expanded';
|
||||||
} else {
|
} else {
|
||||||
@ -314,12 +292,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
limitLineLabels: {
|
|
||||||
handler(limitLineLabels) {
|
|
||||||
this.legendHoverChanged(limitLineLabels);
|
|
||||||
},
|
|
||||||
deep: true
|
|
||||||
},
|
|
||||||
initGridLines(newGridLines) {
|
initGridLines(newGridLines) {
|
||||||
this.gridLines = newGridLines;
|
this.gridLines = newGridLines;
|
||||||
},
|
},
|
||||||
@ -338,11 +310,6 @@ export default {
|
|||||||
this.config = this.getConfig();
|
this.config = this.getConfig();
|
||||||
this.legend = this.config.legend;
|
this.legend = this.config.legend;
|
||||||
|
|
||||||
if (this.isNestedWithinAStackedPlot) {
|
|
||||||
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
|
||||||
this.$emit('configLoaded', configId);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.listenTo(this.config.series, 'add', this.addSeries, this);
|
this.listenTo(this.config.series, 'add', this.addSeries, this);
|
||||||
this.listenTo(this.config.series, 'remove', this.removeSeries, this);
|
this.listenTo(this.config.series, 'remove', this.removeSeries, this);
|
||||||
|
|
||||||
@ -408,7 +375,6 @@ export default {
|
|||||||
id: configId,
|
id: configId,
|
||||||
domainObject: this.domainObject,
|
domainObject: this.domainObject,
|
||||||
openmct: this.openmct,
|
openmct: this.openmct,
|
||||||
palette: this.colorPalette,
|
|
||||||
callback: (data) => {
|
callback: (data) => {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
@ -792,8 +758,6 @@ export default {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$emit('highlights', this.highlights);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
untrackMousePosition() {
|
untrackMousePosition() {
|
||||||
@ -828,7 +792,6 @@ export default {
|
|||||||
|
|
||||||
if (this.isMouseClick()) {
|
if (this.isMouseClick()) {
|
||||||
this.lockHighlightPoint = !this.lockHighlightPoint;
|
this.lockHighlightPoint = !this.lockHighlightPoint;
|
||||||
this.$emit('lockHighlightPoint', this.lockHighlightPoint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.pan) {
|
if (this.pan) {
|
||||||
|
@ -68,8 +68,7 @@ export default class PlotConfigurationModel extends Model {
|
|||||||
this.series = new SeriesCollection({
|
this.series = new SeriesCollection({
|
||||||
models: options.model.series,
|
models: options.model.series,
|
||||||
plot: this,
|
plot: this,
|
||||||
openmct: options.openmct,
|
openmct: options.openmct
|
||||||
palette: options.palette
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.get('domainObject').type === 'telemetry.plot.overlay') {
|
if (this.get('domainObject').type === 'telemetry.plot.overlay') {
|
||||||
|
@ -39,7 +39,7 @@ export default class SeriesCollection extends Collection {
|
|||||||
this.modelClass = PlotSeries;
|
this.modelClass = PlotSeries;
|
||||||
this.plot = options.plot;
|
this.plot = options.plot;
|
||||||
this.openmct = options.openmct;
|
this.openmct = options.openmct;
|
||||||
this.palette = options.palette || new ColorPalette();
|
this.palette = new ColorPalette();
|
||||||
this.listenTo(this, 'add', this.onSeriesAdd, this);
|
this.listenTo(this, 'add', this.onSeriesAdd, this);
|
||||||
this.listenTo(this, 'remove', this.onSeriesRemove, this);
|
this.listenTo(this, 'remove', this.onSeriesRemove, this);
|
||||||
this.listenTo(this.plot, 'change:domainObject', this.trackPersistedConfig, this);
|
this.listenTo(this.plot, 'change:domainObject', this.trackPersistedConfig, this);
|
||||||
|
@ -260,7 +260,7 @@ export default class YAxisModel extends Model {
|
|||||||
const plotModel = this.plot.get('domainObject');
|
const plotModel = this.plot.get('domainObject');
|
||||||
const label = plotModel.configuration?.yAxis?.label;
|
const label = plotModel.configuration?.yAxis?.label;
|
||||||
const sampleSeries = seriesCollection.first();
|
const sampleSeries = seriesCollection.first();
|
||||||
if (!sampleSeries || !sampleSeries.metadata) {
|
if (!sampleSeries) {
|
||||||
if (!label) {
|
if (!label) {
|
||||||
this.unset('label');
|
this.unset('label');
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,7 @@
|
|||||||
v-if="loaded"
|
v-if="loaded"
|
||||||
class="js-plot-options-browse"
|
class="js-plot-options-browse"
|
||||||
>
|
>
|
||||||
<ul
|
<ul class="c-tree">
|
||||||
v-if="!isStackedPlotObject"
|
|
||||||
class="c-tree"
|
|
||||||
>
|
|
||||||
<h2 title="Plot series display properties in this object">Plot Series</h2>
|
<h2 title="Plot series display properties in this object">Plot Series</h2>
|
||||||
<plot-options-item
|
<plot-options-item
|
||||||
v-for="series in plotSeries"
|
v-for="series in plotSeries"
|
||||||
@ -39,10 +36,7 @@
|
|||||||
v-if="plotSeries.length"
|
v-if="plotSeries.length"
|
||||||
class="grid-properties"
|
class="grid-properties"
|
||||||
>
|
>
|
||||||
<ul
|
<ul class="l-inspector-part">
|
||||||
v-if="!isStackedPlotObject"
|
|
||||||
class="l-inspector-part js-yaxis-properties"
|
|
||||||
>
|
|
||||||
<h2 title="Y axis settings for this object">Y Axis</h2>
|
<h2 title="Y axis settings for this object">Y Axis</h2>
|
||||||
<li class="grid-row">
|
<li class="grid-row">
|
||||||
<div
|
<div
|
||||||
@ -90,10 +84,7 @@
|
|||||||
<div class="grid-cell value">{{ rangeMax }}</div>
|
<div class="grid-cell value">{{ rangeMax }}</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul
|
<ul class="l-inspector-part">
|
||||||
v-if="isStackedPlotObject || !isNestedWithinAStackedPlot"
|
|
||||||
class="l-inspector-part js-legend-properties"
|
|
||||||
>
|
|
||||||
<h2 title="Legend settings for this object">Legend</h2>
|
<h2 title="Legend settings for this object">Legend</h2>
|
||||||
<li class="grid-row">
|
<li class="grid-row">
|
||||||
<div
|
<div
|
||||||
@ -153,7 +144,7 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
PlotOptionsItem
|
PlotOptionsItem
|
||||||
},
|
},
|
||||||
inject: ['openmct', 'domainObject', 'path'],
|
inject: ['openmct', 'domainObject'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
config: {},
|
config: {},
|
||||||
@ -176,21 +167,12 @@ export default {
|
|||||||
plotSeries: []
|
plotSeries: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
isNestedWithinAStackedPlot() {
|
|
||||||
return this.path.find((pathObject, pathObjIndex) => pathObjIndex > 0 && pathObject.type === 'telemetry.plot.stacked');
|
|
||||||
},
|
|
||||||
isStackedPlotObject() {
|
|
||||||
return this.path.find((pathObject, pathObjIndex) => pathObjIndex === 0 && pathObject.type === 'telemetry.plot.stacked');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
mounted() {
|
||||||
eventHelpers.extend(this);
|
eventHelpers.extend(this);
|
||||||
this.config = this.getConfig();
|
this.config = this.getConfig();
|
||||||
this.registerListeners();
|
this.registerListeners();
|
||||||
this.initConfiguration();
|
this.initConfiguration();
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.stopListening();
|
this.stopListening();
|
||||||
|
@ -24,31 +24,21 @@
|
|||||||
v-if="loaded"
|
v-if="loaded"
|
||||||
class="js-plot-options-edit"
|
class="js-plot-options-edit"
|
||||||
>
|
>
|
||||||
<ul
|
<ul class="c-tree">
|
||||||
v-if="!isStackedPlotObject"
|
|
||||||
class="c-tree"
|
|
||||||
>
|
|
||||||
<h2 title="Display properties for this object">Plot Series</h2>
|
<h2 title="Display properties for this object">Plot Series</h2>
|
||||||
<li
|
<li
|
||||||
v-for="series in plotSeries"
|
v-for="series in plotSeries"
|
||||||
:key="series.key"
|
:key="series.key"
|
||||||
>
|
>
|
||||||
<series-form
|
<series-form :series="series" />
|
||||||
:series="series"
|
|
||||||
@seriesUpdated="updateSeriesConfigForObject"
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<y-axis-form
|
<y-axis-form
|
||||||
v-if="plotSeries.length && !isStackedPlotObject"
|
v-if="plotSeries.length"
|
||||||
class="grid-properties"
|
class="grid-properties"
|
||||||
:y-axis="config.yAxis"
|
:y-axis="config.yAxis"
|
||||||
@seriesUpdated="updateSeriesConfigForObject"
|
|
||||||
/>
|
/>
|
||||||
<ul
|
<ul class="l-inspector-part">
|
||||||
v-if="isStackedPlotObject || !isStackedPlotNestedObject"
|
|
||||||
class="l-inspector-part"
|
|
||||||
>
|
|
||||||
<h2 title="Legend options">Legend</h2>
|
<h2 title="Legend options">Legend</h2>
|
||||||
<legend-form
|
<legend-form
|
||||||
v-if="plotSeries.length"
|
v-if="plotSeries.length"
|
||||||
@ -71,7 +61,7 @@ export default {
|
|||||||
SeriesForm,
|
SeriesForm,
|
||||||
YAxisForm
|
YAxisForm
|
||||||
},
|
},
|
||||||
inject: ['openmct', 'domainObject', 'path'],
|
inject: ['openmct', 'domainObject'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
config: {},
|
config: {},
|
||||||
@ -79,14 +69,6 @@ export default {
|
|||||||
loaded: false
|
loaded: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
isStackedPlotNestedObject() {
|
|
||||||
return this.path.find((pathObject, pathObjIndex) => pathObjIndex > 0 && pathObject.type === 'telemetry.plot.stacked');
|
|
||||||
},
|
|
||||||
isStackedPlotObject() {
|
|
||||||
return this.path.find((pathObject, pathObjIndex) => pathObjIndex === 0 && pathObject.type === 'telemetry.plot.stacked');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
mounted() {
|
||||||
eventHelpers.extend(this);
|
eventHelpers.extend(this);
|
||||||
this.config = this.getConfig();
|
this.config = this.getConfig();
|
||||||
@ -116,24 +98,6 @@ export default {
|
|||||||
resetAllSeries() {
|
resetAllSeries() {
|
||||||
this.plotSeries = [];
|
this.plotSeries = [];
|
||||||
this.config.series.forEach(this.addSeries, this);
|
this.config.series.forEach(this.addSeries, this);
|
||||||
},
|
|
||||||
|
|
||||||
updateSeriesConfigForObject(config) {
|
|
||||||
const stackedPlotObject = this.path.find((pathObject) => pathObject.type === 'telemetry.plot.stacked');
|
|
||||||
let index = stackedPlotObject.configuration.series.findIndex((seriesConfig) => {
|
|
||||||
return this.openmct.objects.areIdsEqual(seriesConfig.identifier, config.identifier);
|
|
||||||
});
|
|
||||||
if (index < 0) {
|
|
||||||
index = stackedPlotObject.configuration.series.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
const configPath = `configuration.series[${index}].${config.path}`;
|
|
||||||
this.openmct.objects.mutate(
|
|
||||||
stackedPlotObject,
|
|
||||||
configPath,
|
|
||||||
config.value
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -13,10 +13,8 @@ export default function PlotsInspectorViewProvider(openmct) {
|
|||||||
|
|
||||||
let object = selection[0][0].context.item;
|
let object = selection[0][0].context.item;
|
||||||
|
|
||||||
const isOverlayPlotObject = object && object.type === 'telemetry.plot.overlay';
|
return object
|
||||||
const isStackedPlotObject = object && object.type === 'telemetry.plot.stacked';
|
&& object.type === 'telemetry.plot.overlay';
|
||||||
|
|
||||||
return isStackedPlotObject || isOverlayPlotObject;
|
|
||||||
},
|
},
|
||||||
view: function (selection) {
|
view: function (selection) {
|
||||||
let component;
|
let component;
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
|
|
||||||
import PlotOptions from "./PlotOptions.vue";
|
|
||||||
import Vue from 'vue';
|
|
||||||
|
|
||||||
export default function StackedPlotsInspectorViewProvider(openmct) {
|
|
||||||
return {
|
|
||||||
key: 'stacked-plots-inspector',
|
|
||||||
name: 'Stacked Plots Inspector View',
|
|
||||||
canView: function (selection) {
|
|
||||||
if (selection.length === 0 || selection[0].length === 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const object = selection[0][0].context.item;
|
|
||||||
const parent = selection[0].length > 1 && selection[0][1].context.item;
|
|
||||||
|
|
||||||
const isOverlayPlotObject = object && object.type === 'telemetry.plot.overlay';
|
|
||||||
const isParentStackedPlotObject = parent && parent.type === 'telemetry.plot.stacked';
|
|
||||||
|
|
||||||
return !isOverlayPlotObject && isParentStackedPlotObject;
|
|
||||||
},
|
|
||||||
view: function (selection) {
|
|
||||||
let component;
|
|
||||||
let objectPath;
|
|
||||||
|
|
||||||
if (selection.length) {
|
|
||||||
objectPath = selection[0].map((selectionItem) => {
|
|
||||||
return selectionItem.context.item;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
show: function (element) {
|
|
||||||
component = new Vue({
|
|
||||||
el: element,
|
|
||||||
components: {
|
|
||||||
PlotOptions: PlotOptions
|
|
||||||
},
|
|
||||||
provide: {
|
|
||||||
openmct,
|
|
||||||
domainObject: selection[0][0].context.item,
|
|
||||||
path: objectPath
|
|
||||||
},
|
|
||||||
template: '<plot-options></plot-options>'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
destroy: function () {
|
|
||||||
if (component) {
|
|
||||||
component.$destroy();
|
|
||||||
component = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
priority: function () {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
@ -298,45 +298,28 @@ export default {
|
|||||||
|
|
||||||
this.series.set('color', color);
|
this.series.set('color', color);
|
||||||
|
|
||||||
if (!this.domainObject.configuration || !this.domainObject.configuration.series) {
|
const getPath = this.dynamicPathForKey('color');
|
||||||
this.$emit('seriesUpdated', {
|
const seriesColorPath = getPath(this.domainObject, this.series);
|
||||||
identifier: this.domainObject.identifier,
|
|
||||||
path: `series.color`,
|
|
||||||
value: color.asHexString()
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const getPath = this.dynamicPathForKey('color');
|
|
||||||
const seriesColorPath = getPath(this.domainObject, this.series);
|
|
||||||
|
|
||||||
this.openmct.objects.mutate(
|
this.openmct.objects.mutate(
|
||||||
this.domainObject,
|
this.domainObject,
|
||||||
seriesColorPath,
|
seriesColorPath,
|
||||||
color.asHexString()
|
color.asHexString()
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
if (otherSeriesWithColor) {
|
if (otherSeriesWithColor) {
|
||||||
otherSeriesWithColor.set('color', oldColor);
|
otherSeriesWithColor.set('color', oldColor);
|
||||||
|
|
||||||
if (!this.domainObject.configuration || !this.domainObject.configuration.series) {
|
const otherSeriesColorPath = getPath(
|
||||||
this.$emit('seriesUpdated', {
|
this.domainObject,
|
||||||
identifier: this.domainObject.identifier,
|
otherSeriesWithColor
|
||||||
path: `series.color`,
|
);
|
||||||
value: oldColor.asHexString()
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const getPath = this.dynamicPathForKey('color');
|
|
||||||
const otherSeriesColorPath = getPath(
|
|
||||||
this.domainObject,
|
|
||||||
otherSeriesWithColor
|
|
||||||
);
|
|
||||||
|
|
||||||
this.openmct.objects.mutate(
|
this.openmct.objects.mutate(
|
||||||
this.domainObject,
|
this.domainObject,
|
||||||
otherSeriesColorPath,
|
otherSeriesColorPath,
|
||||||
oldColor.asHexString()
|
oldColor.asHexString()
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleExpanded() {
|
toggleExpanded() {
|
||||||
@ -360,19 +343,11 @@ export default {
|
|||||||
if (!_.isEqual(coerce(newVal, formField.coerce), coerce(oldVal, formField.coerce))) {
|
if (!_.isEqual(coerce(newVal, formField.coerce), coerce(oldVal, formField.coerce))) {
|
||||||
this.series.set(formKey, coerce(newVal, formField.coerce));
|
this.series.set(formKey, coerce(newVal, formField.coerce));
|
||||||
if (path) {
|
if (path) {
|
||||||
if (!this.domainObject.configuration || !this.domainObject.configuration.series) {
|
this.openmct.objects.mutate(
|
||||||
this.$emit('seriesUpdated', {
|
this.domainObject,
|
||||||
identifier: this.domainObject.identifier,
|
path(this.domainObject, this.series),
|
||||||
path: `series.${formKey}`,
|
coerce(newVal, formField.coerce)
|
||||||
value: coerce(newVal, formField.coerce)
|
);
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.openmct.objects.mutate(
|
|
||||||
this.domainObject,
|
|
||||||
path(this.domainObject, this.series),
|
|
||||||
coerce(newVal, formField.coerce)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -230,19 +230,11 @@ export default {
|
|||||||
// TODO: Why do we mutate yAxis twice, once directly, once via objects.mutate? Or are they different objects?
|
// TODO: Why do we mutate yAxis twice, once directly, once via objects.mutate? Or are they different objects?
|
||||||
this.yAxis.set(formKey, newVal);
|
this.yAxis.set(formKey, newVal);
|
||||||
if (path) {
|
if (path) {
|
||||||
if (!this.domainObject.configuration || !this.domainObject.configuration.series) {
|
this.openmct.objects.mutate(
|
||||||
this.$emit('seriesUpdated', {
|
this.domainObject,
|
||||||
identifier: this.domainObject.identifier,
|
path(this.domainObject, this.yAxis),
|
||||||
path: `yAxis.${formKey}`,
|
newVal
|
||||||
value: newVal
|
);
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.openmct.objects.mutate(
|
|
||||||
this.domainObject,
|
|
||||||
path(this.domainObject, this.yAxis),
|
|
||||||
newVal
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,8 +49,8 @@
|
|||||||
title="Cursor is point locked. Click anywhere in the plot to unlock."
|
title="Cursor is point locked. Click anywhere in the plot to unlock."
|
||||||
></div>
|
></div>
|
||||||
<plot-legend-item-collapsed
|
<plot-legend-item-collapsed
|
||||||
v-for="(seriesObject, seriesIndex) in series"
|
v-for="seriesObject in series"
|
||||||
:key="`seriesObject.keyString-${seriesIndex}`"
|
:key="seriesObject.keyString"
|
||||||
:highlights="highlights"
|
:highlights="highlights"
|
||||||
:value-to-show-when-collapsed="legend.get('valueToShowWhenCollapsed')"
|
:value-to-show-when-collapsed="legend.get('valueToShowWhenCollapsed')"
|
||||||
:series-object="seriesObject"
|
:series-object="seriesObject"
|
||||||
@ -95,8 +95,8 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<plot-legend-item-expanded
|
<plot-legend-item-expanded
|
||||||
v-for="(seriesObject, seriesIndex) in series"
|
v-for="seriesObject in series"
|
||||||
:key="`seriesObject.keyString-${seriesIndex}`"
|
:key="seriesObject.keyString"
|
||||||
:series-object="seriesObject"
|
:series-object="seriesObject"
|
||||||
:highlights="highlights"
|
:highlights="highlights"
|
||||||
:legend="legend"
|
:legend="legend"
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
<span class="plot-series-name">{{ nameWithUnit }}</span>
|
<span class="plot-series-name">{{ nameWithUnit }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="!!highlights.length && (valueToShowWhenCollapsed !== 'none' && valueToShowWhenCollapsed !== 'units')"
|
v-show="!!highlights.length && (valueToShowWhenCollapsed !== 'none')"
|
||||||
class="plot-series-value hover-value-enabled"
|
class="plot-series-value hover-value-enabled"
|
||||||
:class="[{ 'cursor-hover': notNearest }, valueToDisplayWhenCollapsedClass, mctLimitStateClass]"
|
:class="[{ 'cursor-hover': notNearest }, valueToDisplayWhenCollapsedClass, mctLimitStateClass]"
|
||||||
>
|
>
|
||||||
|
@ -26,7 +26,6 @@ import PlotsInspectorViewProvider from './inspector/PlotsInspectorViewProvider';
|
|||||||
import OverlayPlotCompositionPolicy from './overlayPlot/OverlayPlotCompositionPolicy';
|
import OverlayPlotCompositionPolicy from './overlayPlot/OverlayPlotCompositionPolicy';
|
||||||
import StackedPlotCompositionPolicy from './stackedPlot/StackedPlotCompositionPolicy';
|
import StackedPlotCompositionPolicy from './stackedPlot/StackedPlotCompositionPolicy';
|
||||||
import PlotViewActions from "./actions/ViewActions";
|
import PlotViewActions from "./actions/ViewActions";
|
||||||
import StackedPlotsInspectorViewProvider from "./inspector/StackedPlotsInspectorViewProvider";
|
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
return function install(openmct) {
|
return function install(openmct) {
|
||||||
@ -40,8 +39,9 @@ export default function () {
|
|||||||
initialize: function (domainObject) {
|
initialize: function (domainObject) {
|
||||||
domainObject.composition = [];
|
domainObject.composition = [];
|
||||||
domainObject.configuration = {
|
domainObject.configuration = {
|
||||||
//series is an array of objects of type: {identifier, series: {color...}, yAxis:{}}
|
series: [],
|
||||||
series: []
|
yAxis: {},
|
||||||
|
xAxis: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
priority: 891
|
priority: 891
|
||||||
@ -55,11 +55,7 @@ export default function () {
|
|||||||
creatable: true,
|
creatable: true,
|
||||||
initialize: function (domainObject) {
|
initialize: function (domainObject) {
|
||||||
domainObject.composition = [];
|
domainObject.composition = [];
|
||||||
domainObject.configuration = {
|
domainObject.configuration = {};
|
||||||
series: [],
|
|
||||||
yAxis: {},
|
|
||||||
xAxis: {}
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
priority: 890
|
priority: 890
|
||||||
});
|
});
|
||||||
@ -69,7 +65,6 @@ export default function () {
|
|||||||
openmct.objectViews.addProvider(new PlotViewProvider(openmct));
|
openmct.objectViews.addProvider(new PlotViewProvider(openmct));
|
||||||
|
|
||||||
openmct.inspectorViews.addProvider(new PlotsInspectorViewProvider(openmct));
|
openmct.inspectorViews.addProvider(new PlotsInspectorViewProvider(openmct));
|
||||||
openmct.inspectorViews.addProvider(new StackedPlotsInspectorViewProvider(openmct));
|
|
||||||
|
|
||||||
openmct.composition.addPolicy(new OverlayPlotCompositionPolicy(openmct).allow);
|
openmct.composition.addPolicy(new OverlayPlotCompositionPolicy(openmct).allow);
|
||||||
openmct.composition.addPolicy(new StackedPlotCompositionPolicy(openmct).allow);
|
openmct.composition.addPolicy(new StackedPlotCompositionPolicy(openmct).allow);
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
import {createMouseEvent, createOpenMct, resetApplicationState, spyOnBuiltins} from "utils/testing";
|
import {createMouseEvent, createOpenMct, resetApplicationState, spyOnBuiltins} from "utils/testing";
|
||||||
import PlotVuePlugin from "./plugin";
|
import PlotVuePlugin from "./plugin";
|
||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
|
import StackedPlot from "./stackedPlot/StackedPlot.vue";
|
||||||
import configStore from "./configuration/ConfigStore";
|
import configStore from "./configuration/ConfigStore";
|
||||||
import EventEmitter from "EventEmitter";
|
import EventEmitter from "EventEmitter";
|
||||||
import PlotOptions from "./inspector/PlotOptions.vue";
|
import PlotOptions from "./inspector/PlotOptions.vue";
|
||||||
@ -347,20 +348,14 @@ describe("the plugin", function () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
openmct.router.path = [testTelemetryObject];
|
|
||||||
|
|
||||||
applicableViews = openmct.objectViews.get(testTelemetryObject, mockObjectPath);
|
applicableViews = openmct.objectViews.get(testTelemetryObject, mockObjectPath);
|
||||||
plotViewProvider = applicableViews.find((viewProvider) => viewProvider.key === "plot-single");
|
plotViewProvider = applicableViews.find((viewProvider) => viewProvider.key === "plot-single");
|
||||||
plotView = plotViewProvider.view(testTelemetryObject, []);
|
plotView = plotViewProvider.view(testTelemetryObject, [testTelemetryObject]);
|
||||||
plotView.show(child, true);
|
plotView.show(child, true);
|
||||||
|
|
||||||
return Vue.nextTick();
|
return Vue.nextTick();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
openmct.router.path = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Makes only one request for telemetry on load", () => {
|
it("Makes only one request for telemetry on load", () => {
|
||||||
expect(openmct.telemetry.request).toHaveBeenCalledTimes(1);
|
expect(openmct.telemetry.request).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
@ -528,6 +523,360 @@ describe("the plugin", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("The stacked plot view", () => {
|
||||||
|
let testTelemetryObject;
|
||||||
|
let testTelemetryObject2;
|
||||||
|
let config;
|
||||||
|
let stackedPlotObject;
|
||||||
|
let component;
|
||||||
|
let mockComposition;
|
||||||
|
let plotViewComponentObject;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
|
||||||
|
stackedPlotObject = {
|
||||||
|
identifier: {
|
||||||
|
namespace: "",
|
||||||
|
key: "test-plot"
|
||||||
|
},
|
||||||
|
type: "telemetry.plot.stacked",
|
||||||
|
name: "Test Stacked Plot"
|
||||||
|
};
|
||||||
|
|
||||||
|
testTelemetryObject = {
|
||||||
|
identifier: {
|
||||||
|
namespace: "",
|
||||||
|
key: "test-object"
|
||||||
|
},
|
||||||
|
type: "test-object",
|
||||||
|
name: "Test Object",
|
||||||
|
telemetry: {
|
||||||
|
values: [{
|
||||||
|
key: "utc",
|
||||||
|
format: "utc",
|
||||||
|
name: "Time",
|
||||||
|
hints: {
|
||||||
|
domain: 1
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "some-key",
|
||||||
|
name: "Some attribute",
|
||||||
|
hints: {
|
||||||
|
range: 1
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "some-other-key",
|
||||||
|
name: "Another attribute",
|
||||||
|
hints: {
|
||||||
|
range: 2
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
configuration: {
|
||||||
|
objectStyles: {
|
||||||
|
staticStyle: {
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'rgb(0, 200, 0)',
|
||||||
|
color: '',
|
||||||
|
border: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
conditionSetIdentifier: {
|
||||||
|
namespace: '',
|
||||||
|
key: 'testConditionSetId'
|
||||||
|
},
|
||||||
|
selectedConditionId: 'conditionId1',
|
||||||
|
defaultConditionId: 'conditionId1',
|
||||||
|
styles: [
|
||||||
|
{
|
||||||
|
conditionId: 'conditionId1',
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'rgb(0, 155, 0)',
|
||||||
|
color: '',
|
||||||
|
output: '',
|
||||||
|
border: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
testTelemetryObject2 = {
|
||||||
|
identifier: {
|
||||||
|
namespace: "",
|
||||||
|
key: "test-object2"
|
||||||
|
},
|
||||||
|
type: "test-object",
|
||||||
|
name: "Test Object2",
|
||||||
|
telemetry: {
|
||||||
|
values: [{
|
||||||
|
key: "utc",
|
||||||
|
format: "utc",
|
||||||
|
name: "Time",
|
||||||
|
hints: {
|
||||||
|
domain: 1
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "some-key2",
|
||||||
|
name: "Some attribute2",
|
||||||
|
hints: {
|
||||||
|
range: 1
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "some-other-key2",
|
||||||
|
name: "Another attribute2",
|
||||||
|
hints: {
|
||||||
|
range: 2
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mockComposition = new EventEmitter();
|
||||||
|
mockComposition.load = () => {
|
||||||
|
mockComposition.emit('add', testTelemetryObject);
|
||||||
|
|
||||||
|
return [testTelemetryObject];
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(openmct.composition, 'get').and.returnValue(mockComposition);
|
||||||
|
|
||||||
|
let viewContainer = document.createElement("div");
|
||||||
|
child.append(viewContainer);
|
||||||
|
component = new Vue({
|
||||||
|
el: viewContainer,
|
||||||
|
components: {
|
||||||
|
StackedPlot
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct: openmct,
|
||||||
|
domainObject: stackedPlotObject,
|
||||||
|
composition: openmct.composition.get(stackedPlotObject),
|
||||||
|
path: [stackedPlotObject]
|
||||||
|
},
|
||||||
|
template: "<stacked-plot></stacked-plot>"
|
||||||
|
});
|
||||||
|
|
||||||
|
return telemetryPromise
|
||||||
|
.then(Vue.nextTick())
|
||||||
|
.then(() => {
|
||||||
|
plotViewComponentObject = component.$root.$children[0];
|
||||||
|
const configId = openmct.objects.makeKeyString(testTelemetryObject.identifier);
|
||||||
|
config = configStore.get(configId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Renders a collapsed legend for every telemetry", () => {
|
||||||
|
let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name");
|
||||||
|
expect(legend.length).toBe(1);
|
||||||
|
expect(legend[0].innerHTML).toEqual("Test Object");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Renders an expanded legend for every telemetry", () => {
|
||||||
|
let legendControl = element.querySelector(".c-plot-legend__view-control.gl-plot-legend__view-control.c-disclosure-triangle");
|
||||||
|
const clickEvent = createMouseEvent("click");
|
||||||
|
|
||||||
|
legendControl.dispatchEvent(clickEvent);
|
||||||
|
|
||||||
|
let legend = element.querySelectorAll(".plot-wrapper-expanded-legend .plot-legend-item td");
|
||||||
|
expect(legend.length).toBe(6);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Renders X-axis ticks for the telemetry object", (done) => {
|
||||||
|
let xAxisElement = element.querySelectorAll(".gl-plot-axis-area.gl-plot-x .gl-plot-tick-wrapper");
|
||||||
|
expect(xAxisElement.length).toBe(1);
|
||||||
|
|
||||||
|
config.xAxis.set('displayRange', {
|
||||||
|
min: 0,
|
||||||
|
max: 4
|
||||||
|
});
|
||||||
|
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
let ticks = xAxisElement[0].querySelectorAll(".gl-plot-tick");
|
||||||
|
expect(ticks.length).toBe(9);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Renders Y-axis ticks for the telemetry object", (done) => {
|
||||||
|
config.yAxis.set('displayRange', {
|
||||||
|
min: 10,
|
||||||
|
max: 20
|
||||||
|
});
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
let yAxisElement = element.querySelectorAll(".gl-plot-axis-area.gl-plot-y .gl-plot-tick-wrapper");
|
||||||
|
expect(yAxisElement.length).toBe(1);
|
||||||
|
let ticks = yAxisElement[0].querySelectorAll(".gl-plot-tick");
|
||||||
|
expect(ticks.length).toBe(6);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Renders Y-axis options for the telemetry object", () => {
|
||||||
|
let yAxisElement = element.querySelectorAll(".gl-plot-axis-area.gl-plot-y .gl-plot-y-label__select");
|
||||||
|
expect(yAxisElement.length).toBe(1);
|
||||||
|
let options = yAxisElement[0].querySelectorAll("option");
|
||||||
|
expect(options.length).toBe(2);
|
||||||
|
expect(options[0].value).toBe("Some attribute");
|
||||||
|
expect(options[1].value).toBe("Another attribute");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("turns on cursor Guides all telemetry objects", (done) => {
|
||||||
|
expect(plotViewComponentObject.$children[0].cursorGuide).toBeFalse();
|
||||||
|
plotViewComponentObject.$children[0].cursorGuide = true;
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
expect(plotViewComponentObject.$children[0].cursorGuide).toBeTrue();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows grid lines for all telemetry objects", () => {
|
||||||
|
expect(plotViewComponentObject.$children[0].gridLines).toBeTrue();
|
||||||
|
let gridLinesContainer = element.querySelectorAll(".gl-plot-display-area .js-ticks");
|
||||||
|
let visible = 0;
|
||||||
|
gridLinesContainer.forEach(el => {
|
||||||
|
if (el.style.display !== "none") {
|
||||||
|
visible++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(visible).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("hides grid lines for all telemetry objects", (done) => {
|
||||||
|
expect(plotViewComponentObject.$children[0].gridLines).toBeTrue();
|
||||||
|
plotViewComponentObject.$children[0].gridLines = false;
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
expect(plotViewComponentObject.$children[0].gridLines).toBeFalse();
|
||||||
|
let gridLinesContainer = element.querySelectorAll(".gl-plot-display-area .js-ticks");
|
||||||
|
let visible = 0;
|
||||||
|
gridLinesContainer.forEach(el => {
|
||||||
|
if (el.style.display !== "none") {
|
||||||
|
visible++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(visible).toBe(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('plots a new series when a new telemetry object is added', (done) => {
|
||||||
|
mockComposition.emit('add', testTelemetryObject2);
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name");
|
||||||
|
expect(legend.length).toBe(2);
|
||||||
|
expect(legend[1].innerHTML).toEqual("Test Object2");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('removes plots from series when a telemetry object is removed', (done) => {
|
||||||
|
mockComposition.emit('remove', testTelemetryObject.identifier);
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name");
|
||||||
|
expect(legend.length).toBe(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Changes the label of the y axis when the option changes", (done) => {
|
||||||
|
let selectEl = element.querySelector('.gl-plot-y-label__select');
|
||||||
|
selectEl.value = 'Another attribute';
|
||||||
|
selectEl.dispatchEvent(new Event("change"));
|
||||||
|
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
expect(config.yAxis.get('label')).toEqual('Another attribute');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Renders a new series when added to one of the plots", (done) => {
|
||||||
|
mockComposition.emit('add', testTelemetryObject2);
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name");
|
||||||
|
expect(legend.length).toBe(2);
|
||||||
|
expect(legend[1].innerHTML).toEqual("Test Object2");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Adds a new point to the plot", (done) => {
|
||||||
|
let originalLength = config.series.models[0].getSeriesData().length;
|
||||||
|
config.series.models[0].add({
|
||||||
|
utc: 2,
|
||||||
|
'some-key': 1,
|
||||||
|
'some-other-key': 2
|
||||||
|
});
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
const seriesData = config.series.models[0].getSeriesData();
|
||||||
|
expect(seriesData.length).toEqual(originalLength + 1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates the xscale", (done) => {
|
||||||
|
config.xAxis.set('displayRange', {
|
||||||
|
min: 0,
|
||||||
|
max: 10
|
||||||
|
});
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
expect(plotViewComponentObject.$children[0].component.$children[0].xScale.domain()).toEqual({
|
||||||
|
min: 0,
|
||||||
|
max: 10
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates the yscale", (done) => {
|
||||||
|
config.yAxis.set('displayRange', {
|
||||||
|
min: 10,
|
||||||
|
max: 20
|
||||||
|
});
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
expect(plotViewComponentObject.$children[0].component.$children[0].yScale.domain()).toEqual({
|
||||||
|
min: 10,
|
||||||
|
max: 20
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows styles for telemetry objects if available", (done) => {
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
let conditionalStylesContainer = element.querySelectorAll(".c-plot--stacked-container .js-style-receiver");
|
||||||
|
let hasStyles = 0;
|
||||||
|
conditionalStylesContainer.forEach(el => {
|
||||||
|
if (el.style.backgroundColor !== '') {
|
||||||
|
hasStyles++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(hasStyles).toBe(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('limits', () => {
|
||||||
|
|
||||||
|
it('lines are not displayed by default', () => {
|
||||||
|
let limitEl = element.querySelectorAll(".js-limit-area hr");
|
||||||
|
expect(limitEl.length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('lines are displayed when configuration is set to true', (done) => {
|
||||||
|
config.series.models[0].set('limitLines', true);
|
||||||
|
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
let limitEl = element.querySelectorAll(".js-limit-area .js-limit-line");
|
||||||
|
expect(limitEl.length).toBe(4);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('the inspector view', () => {
|
describe('the inspector view', () => {
|
||||||
let component;
|
let component;
|
||||||
let viewComponentObject;
|
let viewComponentObject;
|
||||||
@ -606,7 +955,6 @@ describe("the plugin", function () {
|
|||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
openmct.router.path = [testTelemetryObject];
|
|
||||||
mockComposition = new EventEmitter();
|
mockComposition = new EventEmitter();
|
||||||
mockComposition.load = () => {
|
mockComposition.load = () => {
|
||||||
mockComposition.emit('add', testTelemetryObject);
|
mockComposition.emit('add', testTelemetryObject);
|
||||||
@ -645,10 +993,6 @@ describe("the plugin", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
openmct.router.path = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('in view only mode', () => {
|
describe('in view only mode', () => {
|
||||||
let browseOptionsEl;
|
let browseOptionsEl;
|
||||||
let editOptionsEl;
|
let editOptionsEl;
|
||||||
@ -752,24 +1096,5 @@ describe("the plugin", function () {
|
|||||||
expect(colorSwatch).toBeDefined();
|
expect(colorSwatch).toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('limits', () => {
|
|
||||||
|
|
||||||
it('lines are not displayed by default', () => {
|
|
||||||
let limitEl = element.querySelectorAll(".js-limit-area .js-limit-line");
|
|
||||||
expect(limitEl.length).toBe(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
xit('lines are displayed when configuration is set to true', (done) => {
|
|
||||||
config.series.models[0].set('limitLines', true);
|
|
||||||
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
let limitEl = element.querySelectorAll(".js-limit-area .js-limit-line");
|
|
||||||
expect(limitEl.length).toBe(4);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -21,37 +21,21 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div class="c-plot c-plot--stacked holder holder-plot has-control-bar">
|
||||||
v-if="loaded"
|
|
||||||
class="c-plot c-plot--stacked holder holder-plot has-control-bar"
|
|
||||||
:class="[plotLegendExpandedStateClass, plotLegendPositionClass]"
|
|
||||||
>
|
|
||||||
<plot-legend
|
|
||||||
:cursor-locked="!!lockHighlightPoint"
|
|
||||||
:series="seriesModels"
|
|
||||||
:highlights="highlights"
|
|
||||||
:legend="legend"
|
|
||||||
@legendHoverChanged="legendHoverChanged"
|
|
||||||
/>
|
|
||||||
<div class="l-view-section">
|
<div class="l-view-section">
|
||||||
<stacked-plot-item
|
<stacked-plot-item
|
||||||
v-for="object in compositionObjects"
|
v-for="object in compositionObjects"
|
||||||
:key="object.id"
|
:key="object.id"
|
||||||
class="c-plot--stacked-container"
|
class="c-plot--stacked-container"
|
||||||
:child-object="object"
|
:object="object"
|
||||||
:options="options"
|
:options="options"
|
||||||
:grid-lines="gridLines"
|
:grid-lines="gridLines"
|
||||||
:color-palette="colorPalette"
|
|
||||||
:cursor-guide="cursorGuide"
|
:cursor-guide="cursorGuide"
|
||||||
:show-limit-line-labels="showLimitLineLabels"
|
|
||||||
:plot-tick-width="maxTickWidth"
|
:plot-tick-width="maxTickWidth"
|
||||||
@plotTickWidth="onTickWidthChange"
|
@plotTickWidth="onTickWidthChange"
|
||||||
@loadingUpdated="loadingUpdated"
|
@loadingUpdated="loadingUpdated"
|
||||||
@cursorGuide="onCursorGuideChange"
|
@cursorGuide="onCursorGuideChange"
|
||||||
@gridLines="onGridLinesChange"
|
@gridLines="onGridLinesChange"
|
||||||
@lockHighlightPoint="lockHighlightPointUpdated"
|
|
||||||
@highlights="highlightsUpdated"
|
|
||||||
@configLoaded="registerSeriesListeners"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -59,19 +43,12 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import PlotConfigurationModel from '../configuration/PlotConfigurationModel';
|
|
||||||
import configStore from '../configuration/ConfigStore';
|
|
||||||
import ColorPalette from "@/ui/color/ColorPalette";
|
|
||||||
|
|
||||||
import PlotLegend from "../legend/PlotLegend.vue";
|
|
||||||
import StackedPlotItem from './StackedPlotItem.vue';
|
import StackedPlotItem from './StackedPlotItem.vue';
|
||||||
import ImageExporter from '../../../exporters/ImageExporter';
|
import ImageExporter from '../../../exporters/ImageExporter';
|
||||||
import eventHelpers from "@/plugins/plot/lib/eventHelpers";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
StackedPlotItem,
|
StackedPlotItem
|
||||||
PlotLegend
|
|
||||||
},
|
},
|
||||||
inject: ['openmct', 'domainObject', 'composition', 'path'],
|
inject: ['openmct', 'domainObject', 'composition', 'path'],
|
||||||
props: {
|
props: {
|
||||||
@ -83,35 +60,16 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
this.seriesConfig = {};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hideExportButtons: false,
|
hideExportButtons: false,
|
||||||
cursorGuide: false,
|
cursorGuide: false,
|
||||||
gridLines: true,
|
gridLines: true,
|
||||||
loading: false,
|
loading: false,
|
||||||
compositionObjects: [],
|
compositionObjects: [],
|
||||||
tickWidthMap: {},
|
tickWidthMap: {}
|
||||||
legend: {},
|
|
||||||
loaded: false,
|
|
||||||
lockHighlightPoint: false,
|
|
||||||
highlights: [],
|
|
||||||
seriesModels: [],
|
|
||||||
showLimitLineLabels: undefined,
|
|
||||||
colorPalette: new ColorPalette()
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
plotLegendPositionClass() {
|
|
||||||
return `plot-legend-${this.config.legend.get('position')}`;
|
|
||||||
},
|
|
||||||
plotLegendExpandedStateClass() {
|
|
||||||
if (this.config.legend.get('expanded')) {
|
|
||||||
return 'plot-legend-expanded';
|
|
||||||
} else {
|
|
||||||
return 'plot-legend-collapsed';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
maxTickWidth() {
|
maxTickWidth() {
|
||||||
return Math.max(...Object.values(this.tickWidthMap));
|
return Math.max(...Object.values(this.tickWidthMap));
|
||||||
}
|
}
|
||||||
@ -120,13 +78,6 @@ export default {
|
|||||||
this.destroy();
|
this.destroy();
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
eventHelpers.extend(this);
|
|
||||||
|
|
||||||
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
|
||||||
this.config = this.getConfig(configId);
|
|
||||||
this.legend = this.config.legend;
|
|
||||||
|
|
||||||
this.loaded = true;
|
|
||||||
this.imageExporter = new ImageExporter(this.openmct);
|
this.imageExporter = new ImageExporter(this.openmct);
|
||||||
|
|
||||||
this.composition.on('add', this.addChild);
|
this.composition.on('add', this.addChild);
|
||||||
@ -135,29 +86,10 @@ export default {
|
|||||||
this.composition.load();
|
this.composition.load();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getConfig(configId) {
|
|
||||||
let config = configStore.get(configId);
|
|
||||||
if (!config) {
|
|
||||||
config = new PlotConfigurationModel({
|
|
||||||
id: configId,
|
|
||||||
domainObject: this.domainObject,
|
|
||||||
openmct: this.openmct,
|
|
||||||
callback: (data) => {
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
configStore.add(configId, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
},
|
|
||||||
loadingUpdated(loaded) {
|
loadingUpdated(loaded) {
|
||||||
this.loading = loaded;
|
this.loading = loaded;
|
||||||
},
|
},
|
||||||
destroy() {
|
destroy() {
|
||||||
this.stopListening();
|
|
||||||
configStore.deleteStore(this.config.id);
|
|
||||||
|
|
||||||
this.composition.off('add', this.addChild);
|
this.composition.off('add', this.addChild);
|
||||||
this.composition.off('remove', this.removeChild);
|
this.composition.off('remove', this.removeChild);
|
||||||
this.composition.off('reorder', this.compositionReorder);
|
this.composition.off('reorder', this.compositionReorder);
|
||||||
@ -167,19 +99,6 @@ export default {
|
|||||||
const id = this.openmct.objects.makeKeyString(child.identifier);
|
const id = this.openmct.objects.makeKeyString(child.identifier);
|
||||||
|
|
||||||
this.$set(this.tickWidthMap, id, 0);
|
this.$set(this.tickWidthMap, id, 0);
|
||||||
const persistedConfig = this.domainObject.configuration.series && this.domainObject.configuration.series.find((seriesConfig) => {
|
|
||||||
return this.openmct.objects.areIdsEqual(seriesConfig.identifier, child.identifier);
|
|
||||||
});
|
|
||||||
if (persistedConfig === undefined) {
|
|
||||||
this.openmct.objects.mutate(
|
|
||||||
this.domainObject,
|
|
||||||
'configuration.series[' + this.compositionObjects.length + ']',
|
|
||||||
{
|
|
||||||
identifier: child.identifier
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.compositionObjects.push(child);
|
this.compositionObjects.push(child);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -188,13 +107,6 @@ export default {
|
|||||||
|
|
||||||
this.$delete(this.tickWidthMap, id);
|
this.$delete(this.tickWidthMap, id);
|
||||||
|
|
||||||
const configIndex = this.domainObject.configuration.series.findIndex((seriesConfig) => {
|
|
||||||
return this.openmct.objects.areIdsEqual(seriesConfig.identifier, childIdentifier);
|
|
||||||
});
|
|
||||||
if (configIndex > -1) {
|
|
||||||
this.domainObject.configuration.series.splice(configIndex, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const childObj = this.compositionObjects.filter((c) => {
|
const childObj = this.compositionObjects.filter((c) => {
|
||||||
const identifier = this.openmct.objects.makeKeyString(c.identifier);
|
const identifier = this.openmct.objects.makeKeyString(c.identifier);
|
||||||
|
|
||||||
@ -246,34 +158,6 @@ export default {
|
|||||||
|
|
||||||
this.$set(this.tickWidthMap, plotId, width);
|
this.$set(this.tickWidthMap, plotId, width);
|
||||||
},
|
},
|
||||||
legendHoverChanged(data) {
|
|
||||||
this.showLimitLineLabels = data;
|
|
||||||
},
|
|
||||||
lockHighlightPointUpdated(data) {
|
|
||||||
this.lockHighlightPoint = data;
|
|
||||||
},
|
|
||||||
highlightsUpdated(data) {
|
|
||||||
this.highlights = data;
|
|
||||||
},
|
|
||||||
registerSeriesListeners(configId) {
|
|
||||||
this.seriesConfig[configId] = this.getConfig(configId);
|
|
||||||
this.listenTo(this.seriesConfig[configId].series, 'add', this.addSeries, this);
|
|
||||||
this.listenTo(this.seriesConfig[configId].series, 'remove', this.removeSeries, this);
|
|
||||||
|
|
||||||
this.seriesConfig[configId].series.models.forEach(this.addSeries, this);
|
|
||||||
},
|
|
||||||
addSeries(series) {
|
|
||||||
const index = this.seriesModels.length;
|
|
||||||
this.$set(this.seriesModels, index, series);
|
|
||||||
},
|
|
||||||
removeSeries(plotSeries) {
|
|
||||||
const index = this.seriesModels.findIndex(seriesModel => this.openmct.objects.areIdsEqual(seriesModel.identifier, plotSeries.identifier));
|
|
||||||
if (index > -1) {
|
|
||||||
this.$delete(this.seriesModels, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.stopListening(plotSeries);
|
|
||||||
},
|
|
||||||
onCursorGuideChange(cursorGuide) {
|
onCursorGuideChange(cursorGuide) {
|
||||||
this.cursorGuide = cursorGuide === true;
|
this.cursorGuide = cursorGuide === true;
|
||||||
},
|
},
|
||||||
|
@ -27,14 +27,12 @@
|
|||||||
import MctPlot from '../MctPlot.vue';
|
import MctPlot from '../MctPlot.vue';
|
||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import conditionalStylesMixin from "./mixins/objectStyles-mixin";
|
import conditionalStylesMixin from "./mixins/objectStyles-mixin";
|
||||||
import configStore from "@/plugins/plot/configuration/ConfigStore";
|
|
||||||
import PlotConfigurationModel from "@/plugins/plot/configuration/PlotConfigurationModel";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [conditionalStylesMixin],
|
mixins: [conditionalStylesMixin],
|
||||||
inject: ['openmct', 'domainObject', 'path'],
|
inject: ['openmct', 'domainObject', 'path'],
|
||||||
props: {
|
props: {
|
||||||
childObject: {
|
object: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default() {
|
default() {
|
||||||
return {};
|
return {};
|
||||||
@ -58,18 +56,6 @@ export default {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showLimitLineLabels: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
colorPalette: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
plotTickWidth: {
|
plotTickWidth: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default() {
|
default() {
|
||||||
@ -86,22 +72,12 @@ export default {
|
|||||||
},
|
},
|
||||||
plotTickWidth(width) {
|
plotTickWidth(width) {
|
||||||
this.updateComponentProp('plotTickWidth', width);
|
this.updateComponentProp('plotTickWidth', width);
|
||||||
},
|
|
||||||
showLimitLineLabels: {
|
|
||||||
handler(data) {
|
|
||||||
this.updateComponentProp('limitLineLabels', data);
|
|
||||||
},
|
|
||||||
deep: true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.updateView();
|
this.updateView();
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.removeSelectable) {
|
|
||||||
this.removeSelectable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.component) {
|
if (this.component) {
|
||||||
this.component.$destroy();
|
this.component.$destroy();
|
||||||
}
|
}
|
||||||
@ -120,19 +96,15 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onTickWidthChange = this.onTickWidthChange;
|
const onTickWidthChange = this.onTickWidthChange;
|
||||||
const onLockHighlightPointUpdated = this.onLockHighlightPointUpdated;
|
|
||||||
const onHighlightsUpdated = this.onHighlightsUpdated;
|
|
||||||
const onConfigLoaded = this.onConfigLoaded;
|
|
||||||
const onCursorGuideChange = this.onCursorGuideChange;
|
const onCursorGuideChange = this.onCursorGuideChange;
|
||||||
const onGridLinesChange = this.onGridLinesChange;
|
const onGridLinesChange = this.onGridLinesChange;
|
||||||
const loadingUpdated = this.loadingUpdated;
|
const loadingUpdated = this.loadingUpdated;
|
||||||
const setStatus = this.setStatus;
|
const setStatus = this.setStatus;
|
||||||
|
|
||||||
const openmct = this.openmct;
|
const openmct = this.openmct;
|
||||||
|
const object = this.object;
|
||||||
const path = this.path;
|
const path = this.path;
|
||||||
|
|
||||||
//If this object is not persistable, then package it with it's parent
|
|
||||||
const object = this.getPlotObject();
|
|
||||||
const getProps = this.getProps;
|
const getProps = this.getProps;
|
||||||
let viewContainer = document.createElement('div');
|
let viewContainer = document.createElement('div');
|
||||||
this.$el.append(viewContainer);
|
this.$el.append(viewContainer);
|
||||||
@ -151,28 +123,14 @@ export default {
|
|||||||
return {
|
return {
|
||||||
...getProps(),
|
...getProps(),
|
||||||
onTickWidthChange,
|
onTickWidthChange,
|
||||||
onLockHighlightPointUpdated,
|
|
||||||
onHighlightsUpdated,
|
|
||||||
onConfigLoaded,
|
|
||||||
onCursorGuideChange,
|
onCursorGuideChange,
|
||||||
onGridLinesChange,
|
onGridLinesChange,
|
||||||
loadingUpdated,
|
loadingUpdated,
|
||||||
setStatus
|
setStatus
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
template: '<div ref="plotWrapper" class="l-view-section u-style-receiver js-style-receiver" :class="{\'s-status-timeconductor-unsynced\': status && status === \'timeconductor-unsynced\'}"><div v-show="!!loading" class="c-loading--overlay loading"></div><mct-plot :init-grid-lines="gridLines" :init-cursor-guide="cursorGuide" :plot-tick-width="plotTickWidth" :limit-line-labels="limitLineLabels" :color-palette="colorPalette" :options="options" @plotTickWidth="onTickWidthChange" @lockHighlightPoint="onLockHighlightPointUpdated" @highlights="onHighlightsUpdated" @configLoaded="onConfigLoaded" @cursorGuide="onCursorGuideChange" @gridLines="onGridLinesChange" @statusUpdated="setStatus" @loadingUpdated="loadingUpdated"/></div>'
|
template: '<div ref="plotWrapper" class="l-view-section u-style-receiver js-style-receiver" :class="{\'s-status-timeconductor-unsynced\': status && status === \'timeconductor-unsynced\'}"><div v-show="!!loading" class="c-loading--overlay loading"></div><mct-plot :init-grid-lines="gridLines" :init-cursor-guide="cursorGuide" :plot-tick-width="plotTickWidth" :options="options" @plotTickWidth="onTickWidthChange" @cursorGuide="onCursorGuideChange" @gridLines="onGridLinesChange" @statusUpdated="setStatus" @loadingUpdated="loadingUpdated"/></div>'
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setSelection();
|
|
||||||
},
|
|
||||||
onLockHighlightPointUpdated() {
|
|
||||||
this.$emit('lockHighlightPoint', ...arguments);
|
|
||||||
},
|
|
||||||
onHighlightsUpdated() {
|
|
||||||
this.$emit('highlights', ...arguments);
|
|
||||||
},
|
|
||||||
onConfigLoaded() {
|
|
||||||
this.$emit('configLoaded', ...arguments);
|
|
||||||
},
|
},
|
||||||
onTickWidthChange() {
|
onTickWidthChange() {
|
||||||
this.$emit('plotTickWidth', ...arguments);
|
this.$emit('plotTickWidth', ...arguments);
|
||||||
@ -187,73 +145,19 @@ export default {
|
|||||||
this.status = status;
|
this.status = status;
|
||||||
this.updateComponentProp('status', status);
|
this.updateComponentProp('status', status);
|
||||||
},
|
},
|
||||||
setSelection() {
|
|
||||||
let childContext = {};
|
|
||||||
childContext.item = this.childObject;
|
|
||||||
this.context = childContext;
|
|
||||||
if (this.removeSelectable) {
|
|
||||||
this.removeSelectable();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.removeSelectable = this.openmct.selection.selectable(
|
|
||||||
this.$el, this.context);
|
|
||||||
},
|
|
||||||
loadingUpdated(loaded) {
|
loadingUpdated(loaded) {
|
||||||
this.loading = loaded;
|
this.loading = loaded;
|
||||||
this.updateComponentProp('loading', loaded);
|
this.updateComponentProp('loading', loaded);
|
||||||
},
|
},
|
||||||
getProps() {
|
getProps() {
|
||||||
return {
|
return {
|
||||||
limitLineLabels: this.showLimitLineLabels,
|
|
||||||
gridLines: this.gridLines,
|
gridLines: this.gridLines,
|
||||||
cursorGuide: this.cursorGuide,
|
cursorGuide: this.cursorGuide,
|
||||||
plotTickWidth: this.plotTickWidth,
|
plotTickWidth: this.plotTickWidth,
|
||||||
loading: this.loading,
|
loading: this.loading,
|
||||||
options: this.options,
|
options: this.options,
|
||||||
status: this.status,
|
status: this.status
|
||||||
colorPalette: this.colorPalette
|
|
||||||
};
|
};
|
||||||
},
|
|
||||||
getPlotObject() {
|
|
||||||
if (this.childObject.configuration && this.childObject.configuration.series) {
|
|
||||||
//If the object has a configuration, allow initialization of the config from it's persisted config
|
|
||||||
return this.childObject;
|
|
||||||
} else {
|
|
||||||
// If the object does not have configuration, initialize the series config with the persisted config from the stacked plot
|
|
||||||
const configId = this.openmct.objects.makeKeyString(this.childObject.identifier);
|
|
||||||
let config = configStore.get(configId);
|
|
||||||
if (!config) {
|
|
||||||
const persistedConfig = this.domainObject.configuration.series.find((seriesConfig) => {
|
|
||||||
return this.openmct.objects.areIdsEqual(seriesConfig.identifier, this.childObject.identifier);
|
|
||||||
});
|
|
||||||
if (persistedConfig) {
|
|
||||||
config = new PlotConfigurationModel({
|
|
||||||
id: configId,
|
|
||||||
domainObject: {
|
|
||||||
...this.childObject,
|
|
||||||
configuration: {
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
identifier: this.childObject.identifier,
|
|
||||||
...persistedConfig.series
|
|
||||||
}
|
|
||||||
],
|
|
||||||
yAxis: persistedConfig.yAxis
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openmct: this.openmct,
|
|
||||||
palette: this.colorPalette,
|
|
||||||
callback: (data) => {
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
configStore.add(configId, config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.childObject;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -31,7 +31,7 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.objectStyles = this.getObjectStyleForItem(this.childObject.configuration);
|
this.objectStyles = this.getObjectStyleForItem(this.object.configuration);
|
||||||
this.initObjectStyles();
|
this.initObjectStyles();
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
@ -62,18 +62,18 @@ export default {
|
|||||||
this.stopListeningStyles();
|
this.stopListeningStyles();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stopListeningStyles = this.openmct.objects.observe(this.childObject, 'configuration.objectStyles', (newObjectStyle) => {
|
this.stopListeningStyles = this.openmct.objects.observe(this.object, 'configuration.objectStyles', (newObjectStyle) => {
|
||||||
//Updating styles in the inspector view will trigger this so that the changes are reflected immediately
|
//Updating styles in the inspector view will trigger this so that the changes are reflected immediately
|
||||||
this.styleRuleManager.updateObjectStyleConfig(newObjectStyle);
|
this.styleRuleManager.updateObjectStyleConfig(newObjectStyle);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.childObject && this.childObject.configuration && this.childObject.configuration.fontStyle) {
|
if (this.object && this.object.configuration && this.object.configuration.fontStyle) {
|
||||||
const { fontSize, font } = this.childObject.configuration.fontStyle;
|
const { fontSize, font } = this.object.configuration.fontStyle;
|
||||||
this.setFontSize(fontSize);
|
this.setFontSize(fontSize);
|
||||||
this.setFont(font);
|
this.setFont(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stopListeningFontStyles = this.openmct.objects.observe(this.childObject, 'configuration.fontStyle', (newFontStyle) => {
|
this.stopListeningFontStyles = this.openmct.objects.observe(this.object, 'configuration.fontStyle', (newFontStyle) => {
|
||||||
this.setFontSize(newFontStyle.fontSize);
|
this.setFontSize(newFontStyle.fontSize);
|
||||||
this.setFont(newFontStyle.font);
|
this.setFont(newFontStyle.font);
|
||||||
});
|
});
|
||||||
|
@ -1,771 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT 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 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 {createMouseEvent, createOpenMct, resetApplicationState, spyOnBuiltins} from "utils/testing";
|
|
||||||
import PlotVuePlugin from "../plugin";
|
|
||||||
import Vue from "vue";
|
|
||||||
import StackedPlot from "./StackedPlot.vue";
|
|
||||||
import configStore from "../configuration/ConfigStore";
|
|
||||||
import EventEmitter from "EventEmitter";
|
|
||||||
import PlotConfigurationModel from "../configuration/PlotConfigurationModel";
|
|
||||||
import PlotOptions from "../inspector/PlotOptions.vue";
|
|
||||||
|
|
||||||
describe("the plugin", function () {
|
|
||||||
let element;
|
|
||||||
let child;
|
|
||||||
let openmct;
|
|
||||||
let telemetryPromise;
|
|
||||||
let telemetryPromiseResolve;
|
|
||||||
let mockObjectPath;
|
|
||||||
let stackedPlotObject = {
|
|
||||||
identifier: {
|
|
||||||
namespace: "",
|
|
||||||
key: "test-plot"
|
|
||||||
},
|
|
||||||
type: "telemetry.plot.stacked",
|
|
||||||
name: "Test Stacked Plot",
|
|
||||||
configuration: {
|
|
||||||
series: []
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach((done) => {
|
|
||||||
mockObjectPath = [
|
|
||||||
{
|
|
||||||
name: 'mock folder',
|
|
||||||
type: 'fake-folder',
|
|
||||||
identifier: {
|
|
||||||
key: 'mock-folder',
|
|
||||||
namespace: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'mock parent folder',
|
|
||||||
type: 'time-strip',
|
|
||||||
identifier: {
|
|
||||||
key: 'mock-parent-folder',
|
|
||||||
namespace: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
const testTelemetry = [
|
|
||||||
{
|
|
||||||
'utc': 1,
|
|
||||||
'some-key': 'some-value 1',
|
|
||||||
'some-other-key': 'some-other-value 1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'utc': 2,
|
|
||||||
'some-key': 'some-value 2',
|
|
||||||
'some-other-key': 'some-other-value 2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'utc': 3,
|
|
||||||
'some-key': 'some-value 3',
|
|
||||||
'some-other-key': 'some-other-value 3'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const timeSystem = {
|
|
||||||
timeSystemKey: 'utc',
|
|
||||||
bounds: {
|
|
||||||
start: 0,
|
|
||||||
end: 4
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
openmct = createOpenMct(timeSystem);
|
|
||||||
|
|
||||||
telemetryPromise = new Promise((resolve) => {
|
|
||||||
telemetryPromiseResolve = resolve;
|
|
||||||
});
|
|
||||||
|
|
||||||
spyOn(openmct.telemetry, 'request').and.callFake(() => {
|
|
||||||
telemetryPromiseResolve(testTelemetry);
|
|
||||||
|
|
||||||
return telemetryPromise;
|
|
||||||
});
|
|
||||||
|
|
||||||
openmct.install(new PlotVuePlugin());
|
|
||||||
|
|
||||||
element = document.createElement("div");
|
|
||||||
element.style.width = "640px";
|
|
||||||
element.style.height = "480px";
|
|
||||||
child = document.createElement("div");
|
|
||||||
child.style.width = "640px";
|
|
||||||
child.style.height = "480px";
|
|
||||||
element.appendChild(child);
|
|
||||||
document.body.appendChild(element);
|
|
||||||
|
|
||||||
spyOn(window, 'ResizeObserver').and.returnValue({
|
|
||||||
observe() {},
|
|
||||||
unobserve() {},
|
|
||||||
disconnect() {}
|
|
||||||
});
|
|
||||||
|
|
||||||
openmct.types.addType("test-object", {
|
|
||||||
creatable: true
|
|
||||||
});
|
|
||||||
|
|
||||||
spyOnBuiltins(["requestAnimationFrame"]);
|
|
||||||
window.requestAnimationFrame.and.callFake((callBack) => {
|
|
||||||
callBack();
|
|
||||||
});
|
|
||||||
|
|
||||||
openmct.router.path = [stackedPlotObject];
|
|
||||||
openmct.on("start", done);
|
|
||||||
openmct.startHeadless();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach((done) => {
|
|
||||||
openmct.time.timeSystem('utc', {
|
|
||||||
start: 0,
|
|
||||||
end: 1
|
|
||||||
});
|
|
||||||
configStore.deleteAll();
|
|
||||||
resetApplicationState(openmct).then(done).catch(done);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
openmct.router.path = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("the plot views", () => {
|
|
||||||
it("provides a stacked plot view for objects with telemetry", () => {
|
|
||||||
const testTelemetryObject = {
|
|
||||||
id: "test-object",
|
|
||||||
type: "telemetry.plot.stacked",
|
|
||||||
telemetry: {
|
|
||||||
values: [{
|
|
||||||
key: "some-key"
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const applicableViews = openmct.objectViews.get(testTelemetryObject, mockObjectPath);
|
|
||||||
let plotView = applicableViews.find((viewProvider) => viewProvider.key === "plot-stacked");
|
|
||||||
expect(plotView).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("The stacked plot view", () => {
|
|
||||||
let testTelemetryObject;
|
|
||||||
let testTelemetryObject2;
|
|
||||||
let config;
|
|
||||||
let component;
|
|
||||||
let mockComposition;
|
|
||||||
let plotViewComponentObject;
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
openmct.router.path = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
testTelemetryObject = {
|
|
||||||
identifier: {
|
|
||||||
namespace: "",
|
|
||||||
key: "test-object"
|
|
||||||
},
|
|
||||||
type: "test-object",
|
|
||||||
name: "Test Object",
|
|
||||||
telemetry: {
|
|
||||||
values: [{
|
|
||||||
key: "utc",
|
|
||||||
format: "utc",
|
|
||||||
name: "Time",
|
|
||||||
hints: {
|
|
||||||
domain: 1
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: "some-key",
|
|
||||||
name: "Some attribute",
|
|
||||||
hints: {
|
|
||||||
range: 1
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: "some-other-key",
|
|
||||||
name: "Another attribute",
|
|
||||||
hints: {
|
|
||||||
range: 2
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
configuration: {
|
|
||||||
objectStyles: {
|
|
||||||
staticStyle: {
|
|
||||||
style: {
|
|
||||||
backgroundColor: 'rgb(0, 200, 0)',
|
|
||||||
color: '',
|
|
||||||
border: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
conditionSetIdentifier: {
|
|
||||||
namespace: '',
|
|
||||||
key: 'testConditionSetId'
|
|
||||||
},
|
|
||||||
selectedConditionId: 'conditionId1',
|
|
||||||
defaultConditionId: 'conditionId1',
|
|
||||||
styles: [
|
|
||||||
{
|
|
||||||
conditionId: 'conditionId1',
|
|
||||||
style: {
|
|
||||||
backgroundColor: 'rgb(0, 155, 0)',
|
|
||||||
color: '',
|
|
||||||
output: '',
|
|
||||||
border: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
testTelemetryObject2 = {
|
|
||||||
identifier: {
|
|
||||||
namespace: "",
|
|
||||||
key: "test-object2"
|
|
||||||
},
|
|
||||||
type: "test-object",
|
|
||||||
name: "Test Object2",
|
|
||||||
telemetry: {
|
|
||||||
values: [{
|
|
||||||
key: "utc",
|
|
||||||
format: "utc",
|
|
||||||
name: "Time",
|
|
||||||
hints: {
|
|
||||||
domain: 1
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: "some-key2",
|
|
||||||
name: "Some attribute2",
|
|
||||||
hints: {
|
|
||||||
range: 1
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: "some-other-key2",
|
|
||||||
name: "Another attribute2",
|
|
||||||
hints: {
|
|
||||||
range: 2
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mockComposition = new EventEmitter();
|
|
||||||
mockComposition.load = () => {
|
|
||||||
mockComposition.emit('add', testTelemetryObject);
|
|
||||||
|
|
||||||
return [testTelemetryObject];
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn(openmct.composition, 'get').and.returnValue(mockComposition);
|
|
||||||
|
|
||||||
let viewContainer = document.createElement("div");
|
|
||||||
child.append(viewContainer);
|
|
||||||
component = new Vue({
|
|
||||||
el: viewContainer,
|
|
||||||
components: {
|
|
||||||
StackedPlot
|
|
||||||
},
|
|
||||||
provide: {
|
|
||||||
openmct: openmct,
|
|
||||||
domainObject: stackedPlotObject,
|
|
||||||
composition: openmct.composition.get(stackedPlotObject),
|
|
||||||
path: [stackedPlotObject]
|
|
||||||
},
|
|
||||||
template: "<stacked-plot></stacked-plot>"
|
|
||||||
});
|
|
||||||
|
|
||||||
return telemetryPromise
|
|
||||||
.then(Vue.nextTick())
|
|
||||||
.then(() => {
|
|
||||||
plotViewComponentObject = component.$root.$children[0];
|
|
||||||
const configId = openmct.objects.makeKeyString(testTelemetryObject.identifier);
|
|
||||||
config = configStore.get(configId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Renders a collapsed legend for every telemetry", () => {
|
|
||||||
let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name");
|
|
||||||
expect(legend.length).toBe(1);
|
|
||||||
expect(legend[0].innerHTML).toEqual("Test Object");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Renders an expanded legend for every telemetry", () => {
|
|
||||||
let legendControl = element.querySelector(".c-plot-legend__view-control.gl-plot-legend__view-control.c-disclosure-triangle");
|
|
||||||
const clickEvent = createMouseEvent("click");
|
|
||||||
|
|
||||||
legendControl.dispatchEvent(clickEvent);
|
|
||||||
|
|
||||||
let legend = element.querySelectorAll(".plot-wrapper-expanded-legend .plot-legend-item td");
|
|
||||||
expect(legend.length).toBe(6);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Renders X-axis ticks for the telemetry object", (done) => {
|
|
||||||
let xAxisElement = element.querySelectorAll(".gl-plot-axis-area.gl-plot-x .gl-plot-tick-wrapper");
|
|
||||||
expect(xAxisElement.length).toBe(1);
|
|
||||||
|
|
||||||
config.xAxis.set('displayRange', {
|
|
||||||
min: 0,
|
|
||||||
max: 4
|
|
||||||
});
|
|
||||||
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
let ticks = xAxisElement[0].querySelectorAll(".gl-plot-tick");
|
|
||||||
expect(ticks.length).toBe(9);
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Renders Y-axis ticks for the telemetry object", (done) => {
|
|
||||||
config.yAxis.set('displayRange', {
|
|
||||||
min: 10,
|
|
||||||
max: 20
|
|
||||||
});
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
let yAxisElement = element.querySelectorAll(".gl-plot-axis-area.gl-plot-y .gl-plot-tick-wrapper");
|
|
||||||
expect(yAxisElement.length).toBe(1);
|
|
||||||
let ticks = yAxisElement[0].querySelectorAll(".gl-plot-tick");
|
|
||||||
expect(ticks.length).toBe(6);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Renders Y-axis options for the telemetry object", () => {
|
|
||||||
let yAxisElement = element.querySelectorAll(".gl-plot-axis-area.gl-plot-y .gl-plot-y-label__select");
|
|
||||||
expect(yAxisElement.length).toBe(1);
|
|
||||||
let options = yAxisElement[0].querySelectorAll("option");
|
|
||||||
expect(options.length).toBe(2);
|
|
||||||
expect(options[0].value).toBe("Some attribute");
|
|
||||||
expect(options[1].value).toBe("Another attribute");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("turns on cursor Guides all telemetry objects", (done) => {
|
|
||||||
expect(plotViewComponentObject.cursorGuide).toBeFalse();
|
|
||||||
plotViewComponentObject.cursorGuide = true;
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
let childCursorGuides = element.querySelectorAll(".c-cursor-guide--v");
|
|
||||||
expect(childCursorGuides.length).toBe(1);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("shows grid lines for all telemetry objects", () => {
|
|
||||||
expect(plotViewComponentObject.gridLines).toBeTrue();
|
|
||||||
let gridLinesContainer = element.querySelectorAll(".gl-plot-display-area .js-ticks");
|
|
||||||
let visible = 0;
|
|
||||||
gridLinesContainer.forEach(el => {
|
|
||||||
if (el.style.display !== "none") {
|
|
||||||
visible++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
expect(visible).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("hides grid lines for all telemetry objects", (done) => {
|
|
||||||
expect(plotViewComponentObject.gridLines).toBeTrue();
|
|
||||||
plotViewComponentObject.gridLines = false;
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
expect(plotViewComponentObject.gridLines).toBeFalse();
|
|
||||||
let gridLinesContainer = element.querySelectorAll(".gl-plot-display-area .js-ticks");
|
|
||||||
let visible = 0;
|
|
||||||
gridLinesContainer.forEach(el => {
|
|
||||||
if (el.style.display !== "none") {
|
|
||||||
visible++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
expect(visible).toBe(0);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('plots a new series when a new telemetry object is added', (done) => {
|
|
||||||
mockComposition.emit('add', testTelemetryObject2);
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name");
|
|
||||||
expect(legend.length).toBe(2);
|
|
||||||
expect(legend[1].innerHTML).toEqual("Test Object2");
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('removes plots from series when a telemetry object is removed', (done) => {
|
|
||||||
mockComposition.emit('remove', testTelemetryObject.identifier);
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
expect(plotViewComponentObject.compositionObjects.length).toBe(0);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Changes the label of the y axis when the option changes", (done) => {
|
|
||||||
let selectEl = element.querySelector('.gl-plot-y-label__select');
|
|
||||||
selectEl.value = 'Another attribute';
|
|
||||||
selectEl.dispatchEvent(new Event("change"));
|
|
||||||
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
expect(config.yAxis.get('label')).toEqual('Another attribute');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Renders a new series when added to one of the plots", (done) => {
|
|
||||||
mockComposition.emit('add', testTelemetryObject2);
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name");
|
|
||||||
expect(legend.length).toBe(2);
|
|
||||||
expect(legend[1].innerHTML).toEqual("Test Object2");
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Adds a new point to the plot", (done) => {
|
|
||||||
let originalLength = config.series.models[0].getSeriesData().length;
|
|
||||||
config.series.models[0].add({
|
|
||||||
utc: 2,
|
|
||||||
'some-key': 1,
|
|
||||||
'some-other-key': 2
|
|
||||||
});
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
const seriesData = config.series.models[0].getSeriesData();
|
|
||||||
expect(seriesData.length).toEqual(originalLength + 1);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates the xscale", (done) => {
|
|
||||||
config.xAxis.set('displayRange', {
|
|
||||||
min: 0,
|
|
||||||
max: 10
|
|
||||||
});
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
expect(plotViewComponentObject.$children[1].component.$children[0].xScale.domain()).toEqual({
|
|
||||||
min: 0,
|
|
||||||
max: 10
|
|
||||||
});
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates the yscale", (done) => {
|
|
||||||
config.yAxis.set('displayRange', {
|
|
||||||
min: 10,
|
|
||||||
max: 20
|
|
||||||
});
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
expect(plotViewComponentObject.$children[1].component.$children[0].yScale.domain()).toEqual({
|
|
||||||
min: 10,
|
|
||||||
max: 20
|
|
||||||
});
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("shows styles for telemetry objects if available", (done) => {
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
let conditionalStylesContainer = element.querySelectorAll(".c-plot--stacked-container .js-style-receiver");
|
|
||||||
let hasStyles = 0;
|
|
||||||
conditionalStylesContainer.forEach(el => {
|
|
||||||
if (el.style.backgroundColor !== '') {
|
|
||||||
hasStyles++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
expect(hasStyles).toBe(1);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('the stacked plot inspector view', () => {
|
|
||||||
let component;
|
|
||||||
let viewComponentObject;
|
|
||||||
let mockComposition;
|
|
||||||
let testTelemetryObject;
|
|
||||||
let selection;
|
|
||||||
let config;
|
|
||||||
beforeEach((done) => {
|
|
||||||
testTelemetryObject = {
|
|
||||||
identifier: {
|
|
||||||
namespace: "",
|
|
||||||
key: "test-object"
|
|
||||||
},
|
|
||||||
type: "test-object",
|
|
||||||
name: "Test Object",
|
|
||||||
telemetry: {
|
|
||||||
values: [{
|
|
||||||
key: "utc",
|
|
||||||
format: "utc",
|
|
||||||
name: "Time",
|
|
||||||
hints: {
|
|
||||||
domain: 1
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: "some-key",
|
|
||||||
name: "Some attribute",
|
|
||||||
hints: {
|
|
||||||
range: 1
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: "some-other-key",
|
|
||||||
name: "Another attribute",
|
|
||||||
hints: {
|
|
||||||
range: 2
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
selection = [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
context: {
|
|
||||||
item: {
|
|
||||||
type: 'telemetry.plot.stacked',
|
|
||||||
identifier: {
|
|
||||||
key: 'some-stacked-plot',
|
|
||||||
namespace: ''
|
|
||||||
},
|
|
||||||
configuration: {
|
|
||||||
series: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
openmct.router.path = [testTelemetryObject];
|
|
||||||
mockComposition = new EventEmitter();
|
|
||||||
mockComposition.load = () => {
|
|
||||||
mockComposition.emit('add', testTelemetryObject);
|
|
||||||
|
|
||||||
return [testTelemetryObject];
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn(openmct.composition, 'get').and.returnValue(mockComposition);
|
|
||||||
|
|
||||||
const configId = openmct.objects.makeKeyString(selection[0][0].context.item.identifier);
|
|
||||||
config = new PlotConfigurationModel({
|
|
||||||
id: configId,
|
|
||||||
domainObject: selection[0][0].context.item,
|
|
||||||
openmct: openmct
|
|
||||||
});
|
|
||||||
configStore.add(configId, config);
|
|
||||||
|
|
||||||
let viewContainer = document.createElement('div');
|
|
||||||
child.append(viewContainer);
|
|
||||||
component = new Vue({
|
|
||||||
el: viewContainer,
|
|
||||||
components: {
|
|
||||||
PlotOptions
|
|
||||||
},
|
|
||||||
provide: {
|
|
||||||
openmct: openmct,
|
|
||||||
domainObject: selection[0][0].context.item,
|
|
||||||
path: [selection[0][0].context.item]
|
|
||||||
},
|
|
||||||
template: '<plot-options/>'
|
|
||||||
});
|
|
||||||
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
viewComponentObject = component.$root.$children[0];
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
openmct.router.path = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('in view only mode', () => {
|
|
||||||
let browseOptionsEl;
|
|
||||||
beforeEach(() => {
|
|
||||||
browseOptionsEl = viewComponentObject.$el.querySelector('.js-plot-options-browse');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shows legend properties', () => {
|
|
||||||
const legendPropertiesEl = browseOptionsEl.querySelector('.js-legend-properties');
|
|
||||||
expect(legendPropertiesEl).not.toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not show series properties', () => {
|
|
||||||
const seriesPropertiesEl = browseOptionsEl.querySelector('.c-tree');
|
|
||||||
expect(seriesPropertiesEl).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not show yaxis properties', () => {
|
|
||||||
const yAxisPropertiesEl = browseOptionsEl.querySelector('.js-yaxis-properties');
|
|
||||||
expect(yAxisPropertiesEl).toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inspector view of stacked plot child', () => {
|
|
||||||
let component;
|
|
||||||
let viewComponentObject;
|
|
||||||
let mockComposition;
|
|
||||||
let testTelemetryObject;
|
|
||||||
let selection;
|
|
||||||
let config;
|
|
||||||
beforeEach((done) => {
|
|
||||||
testTelemetryObject = {
|
|
||||||
identifier: {
|
|
||||||
namespace: "",
|
|
||||||
key: "test-object"
|
|
||||||
},
|
|
||||||
type: "test-object",
|
|
||||||
name: "Test Object",
|
|
||||||
telemetry: {
|
|
||||||
values: [{
|
|
||||||
key: "utc",
|
|
||||||
format: "utc",
|
|
||||||
name: "Time",
|
|
||||||
hints: {
|
|
||||||
domain: 1
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: "some-key",
|
|
||||||
name: "Some attribute",
|
|
||||||
hints: {
|
|
||||||
range: 1
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: "some-other-key",
|
|
||||||
name: "Another attribute",
|
|
||||||
hints: {
|
|
||||||
range: 2
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
selection = [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
context: {
|
|
||||||
item: {
|
|
||||||
id: "test-object",
|
|
||||||
identifier: {
|
|
||||||
key: "test-object",
|
|
||||||
namespace: ''
|
|
||||||
},
|
|
||||||
type: "telemetry.plot.overlay",
|
|
||||||
configuration: {
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
identifier: {
|
|
||||||
key: "test-object",
|
|
||||||
namespace: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
composition: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
context: {
|
|
||||||
item: {
|
|
||||||
type: 'telemetry.plot.stacked',
|
|
||||||
identifier: {
|
|
||||||
key: 'some-stacked-plot',
|
|
||||||
namespace: ''
|
|
||||||
},
|
|
||||||
configuration: {
|
|
||||||
series: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
openmct.router.path = [testTelemetryObject];
|
|
||||||
mockComposition = new EventEmitter();
|
|
||||||
mockComposition.load = () => {
|
|
||||||
mockComposition.emit('add', testTelemetryObject);
|
|
||||||
|
|
||||||
return [testTelemetryObject];
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn(openmct.composition, 'get').and.returnValue(mockComposition);
|
|
||||||
|
|
||||||
const configId = openmct.objects.makeKeyString(selection[0][0].context.item.identifier);
|
|
||||||
config = new PlotConfigurationModel({
|
|
||||||
id: configId,
|
|
||||||
domainObject: selection[0][0].context.item,
|
|
||||||
openmct: openmct
|
|
||||||
});
|
|
||||||
configStore.add(configId, config);
|
|
||||||
|
|
||||||
let viewContainer = document.createElement('div');
|
|
||||||
child.append(viewContainer);
|
|
||||||
component = new Vue({
|
|
||||||
el: viewContainer,
|
|
||||||
components: {
|
|
||||||
PlotOptions
|
|
||||||
},
|
|
||||||
provide: {
|
|
||||||
openmct: openmct,
|
|
||||||
domainObject: selection[0][0].context.item,
|
|
||||||
path: [selection[0][0].context.item, selection[0][1].context.item]
|
|
||||||
},
|
|
||||||
template: '<plot-options/>'
|
|
||||||
});
|
|
||||||
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
viewComponentObject = component.$root.$children[0];
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
openmct.router.path = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('in view only mode', () => {
|
|
||||||
let browseOptionsEl;
|
|
||||||
beforeEach(() => {
|
|
||||||
browseOptionsEl = viewComponentObject.$el.querySelector('.js-plot-options-browse');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('hides legend properties', () => {
|
|
||||||
const legendPropertiesEl = browseOptionsEl.querySelector('.js-legend-properties');
|
|
||||||
expect(legendPropertiesEl).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shows series properties', () => {
|
|
||||||
const seriesPropertiesEl = browseOptionsEl.querySelector('.c-tree');
|
|
||||||
expect(seriesPropertiesEl).not.toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shows yaxis properties', () => {
|
|
||||||
const yAxisPropertiesEl = browseOptionsEl.querySelector('.js-yaxis-properties');
|
|
||||||
expect(yAxisPropertiesEl).not.toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
@ -476,6 +476,7 @@ export default {
|
|||||||
this.filterChanged = _.debounce(this.filterChanged, 500);
|
this.filterChanged = _.debounce(this.filterChanged, 500);
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
console.error('oh noes an error!');
|
||||||
this.csvExporter = new CSVExporter();
|
this.csvExporter = new CSVExporter();
|
||||||
this.rowsAdded = _.throttle(this.rowsAdded, 200);
|
this.rowsAdded = _.throttle(this.rowsAdded, 200);
|
||||||
this.rowsRemoved = _.throttle(this.rowsRemoved, 200);
|
this.rowsRemoved = _.throttle(this.rowsRemoved, 200);
|
||||||
@ -536,6 +537,7 @@ export default {
|
|||||||
this.table.configuration.destroy();
|
this.table.configuration.destroy();
|
||||||
|
|
||||||
this.table.destroy();
|
this.table.destroy();
|
||||||
|
this.isNotARealFunction();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateVisibleRows() {
|
updateVisibleRows() {
|
||||||
|
@ -164,7 +164,7 @@ $borderMissing: 1px dashed $colorAlert !important;
|
|||||||
$editUIColor: $uiColor; // Base color
|
$editUIColor: $uiColor; // Base color
|
||||||
$editUIColorBg: $editUIColor;
|
$editUIColorBg: $editUIColor;
|
||||||
$editUIColorFg: #fff;
|
$editUIColorFg: #fff;
|
||||||
$editUIColorHov: pullForward(saturate($uiColor, 10%), 10%); // Hover color when $editUIColor is applied as a base color
|
$editUIColorHov: pullForward(saturate($uiColor, 10%), 20%); // Hover color when $editUIColor is applied as a base color
|
||||||
$editUIBaseColor: #344b8d; // Base color, toolbar bg
|
$editUIBaseColor: #344b8d; // Base color, toolbar bg
|
||||||
$editUIBaseColorHov: pullForward($editUIBaseColor, 20%);
|
$editUIBaseColorHov: pullForward($editUIBaseColor, 20%);
|
||||||
$editUIBaseColorFg: #ffffff; // Toolbar button icon colors, etc.
|
$editUIBaseColorFg: #ffffff; // Toolbar button icon colors, etc.
|
||||||
@ -178,10 +178,11 @@ $editFrameColor: $browseFrameColor; // Solid or dotted border applied to non-sel
|
|||||||
$editFrameBorder: 1px dotted $editFrameColor;
|
$editFrameBorder: 1px dotted $editFrameColor;
|
||||||
$editFrameColorHov: $editUIColor; // Solid border hover on frames; hover should not be applied to selected objects
|
$editFrameColorHov: $editUIColor; // Solid border hover on frames; hover should not be applied to selected objects
|
||||||
$editFrameBorderHov: 1px solid $editFrameColorHov; // Hover on selectable frames
|
$editFrameBorderHov: 1px solid $editFrameColorHov; // Hover on selectable frames
|
||||||
$editFrameColorSelected: #ffefc2; // Border of selected frames while editing
|
$editFrameColorSelected: #ccc; // Border of selected frames
|
||||||
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
|
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
|
||||||
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
|
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
|
||||||
$editFrameSelectedShdw: rgba(black, 0.4) 0 1px 5px 1px;
|
$editFrameSelectedShdw: rgba(black, 0.4) 0 1px 5px 1px;
|
||||||
|
$editFrameSelectedBorder: 1px solid $editFrameColorHov; // Selected frame element
|
||||||
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
|
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
|
||||||
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
|
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
|
||||||
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
|
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
|
||||||
@ -190,7 +191,6 @@ $editFrameSelectedMovebarColorBg: pullForward($editFrameMovebarColorBg, 15%); //
|
|||||||
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
|
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
|
||||||
$editFrameMovebarH: 10px; // Height of move bar in layout frame
|
$editFrameMovebarH: 10px; // Height of move bar in layout frame
|
||||||
$editMarqueeBorder: 1px dashed $editFrameColorSelected;
|
$editMarqueeBorder: 1px dashed $editFrameColorSelected;
|
||||||
$editFrameSelectedBorder: $editMarqueeBorder; // Selected frame element
|
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
$colorIconAlias: #4af6f3;
|
$colorIconAlias: #4af6f3;
|
||||||
|
@ -168,7 +168,7 @@ $borderMissing: 1px dashed $colorAlert !important;
|
|||||||
$editUIColor: $uiColor; // Base color
|
$editUIColor: $uiColor; // Base color
|
||||||
$editUIColorBg: $editUIColor;
|
$editUIColorBg: $editUIColor;
|
||||||
$editUIColorFg: #fff;
|
$editUIColorFg: #fff;
|
||||||
$editUIColorHov: pullForward(saturate($uiColor, 10%), 10%); // Hover color when $editUIColor is applied as a base color
|
$editUIColorHov: pullForward(saturate($uiColor, 10%), 20%); // Hover color when $editUIColor is applied as a base color
|
||||||
$editUIBaseColor: #344b8d; // Base color, toolbar bg
|
$editUIBaseColor: #344b8d; // Base color, toolbar bg
|
||||||
$editUIBaseColorHov: pullForward($editUIBaseColor, 20%);
|
$editUIBaseColorHov: pullForward($editUIBaseColor, 20%);
|
||||||
$editUIBaseColorFg: #ffffff; // Toolbar button icon colors, etc.
|
$editUIBaseColorFg: #ffffff; // Toolbar button icon colors, etc.
|
||||||
@ -182,10 +182,11 @@ $editFrameColor: $browseFrameColor; // Solid or dotted border applied to non-sel
|
|||||||
$editFrameBorder: 1px dotted $editFrameColor;
|
$editFrameBorder: 1px dotted $editFrameColor;
|
||||||
$editFrameColorHov: $editUIColor; // Solid border hover on frames; hover should not be applied to selected objects
|
$editFrameColorHov: $editUIColor; // Solid border hover on frames; hover should not be applied to selected objects
|
||||||
$editFrameBorderHov: 1px solid $editFrameColorHov; // Hover on selectable frames
|
$editFrameBorderHov: 1px solid $editFrameColorHov; // Hover on selectable frames
|
||||||
$editFrameColorSelected: #ffefc2; // Border of selected frames while editing
|
$editFrameColorSelected: #ccc; // Border of selected frames
|
||||||
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
|
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
|
||||||
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
|
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
|
||||||
$editFrameSelectedShdw: rgba(black, 0.4) 0 1px 5px 1px;
|
$editFrameSelectedShdw: rgba(black, 0.4) 0 1px 5px 1px;
|
||||||
|
$editFrameSelectedBorder: 1px solid $editFrameColorHov; // Selected frame element
|
||||||
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
|
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
|
||||||
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
|
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
|
||||||
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
|
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
|
||||||
@ -194,7 +195,6 @@ $editFrameSelectedMovebarColorBg: pullForward($editFrameMovebarColorBg, 15%); //
|
|||||||
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
|
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
|
||||||
$editFrameMovebarH: 10px; // Height of move bar in layout frame
|
$editFrameMovebarH: 10px; // Height of move bar in layout frame
|
||||||
$editMarqueeBorder: 1px dashed $editFrameColorSelected;
|
$editMarqueeBorder: 1px dashed $editFrameColorSelected;
|
||||||
$editFrameSelectedBorder: $editMarqueeBorder; // Selected frame element
|
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
$colorIconAlias: #4af6f3;
|
$colorIconAlias: #4af6f3;
|
||||||
|
@ -178,10 +178,11 @@ $editFrameColor: $browseFrameColor; // Solid or dotted border applied to non-sel
|
|||||||
$editFrameBorder: 1px dotted $editFrameColor;
|
$editFrameBorder: 1px dotted $editFrameColor;
|
||||||
$editFrameColorHov: $editUIColor; // Solid border hover on frames; hover should not be applied to selected objects
|
$editFrameColorHov: $editUIColor; // Solid border hover on frames; hover should not be applied to selected objects
|
||||||
$editFrameBorderHov: 1px solid $editFrameColorHov; // Hover on selectable frames
|
$editFrameBorderHov: 1px solid $editFrameColorHov; // Hover on selectable frames
|
||||||
$editFrameColorSelected: #ff7c00; // Border of selected frames
|
$editFrameColorSelected: #333; // Border of selected frames
|
||||||
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
|
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
|
||||||
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
|
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
|
||||||
$editFrameSelectedShdw: rgba(black, 0.5) 0 1px 5px 2px;
|
$editFrameSelectedShdw: rgba(black, 0.5) 0 1px 5px 2px;
|
||||||
|
$editFrameSelectedBorder: 1px dashed $editFrameColorSelected; // Selected frame element
|
||||||
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
|
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
|
||||||
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
|
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
|
||||||
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
|
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
|
||||||
@ -190,7 +191,6 @@ $editFrameSelectedMovebarColorBg: pullForward($editFrameMovebarColorBg, 15%); //
|
|||||||
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
|
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
|
||||||
$editFrameMovebarH: 10px; // Height of move bar in layout frame
|
$editFrameMovebarH: 10px; // Height of move bar in layout frame
|
||||||
$editMarqueeBorder: 1px dashed $editFrameColorSelected;
|
$editMarqueeBorder: 1px dashed $editFrameColorSelected;
|
||||||
$editFrameSelectedBorder: 1px dashed $editMarqueeBorder; // Selected frame element
|
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
$colorIconAlias: #4af6f3;
|
$colorIconAlias: #4af6f3;
|
||||||
|
@ -65,6 +65,7 @@ mct-plot {
|
|||||||
.c-plot {
|
.c-plot {
|
||||||
@include abs($mainViewPad);
|
@include abs($mainViewPad);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-height: $plotMinH;
|
min-height: $plotMinH;
|
||||||
|
|
||||||
@ -82,18 +83,11 @@ mct-plot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.c-plot--stacked-container {
|
.c-plot--stacked-container {
|
||||||
border: 1px solid transparent;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: $plotMinH;
|
min-height: $plotMinH;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&[s-selected] {
|
|
||||||
.is-editing & {
|
|
||||||
border: $editMarqueeBorder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -7,19 +7,12 @@ const webpack = require('webpack');
|
|||||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||||
|
|
||||||
const {VueLoaderPlugin} = require('vue-loader');
|
const {VueLoaderPlugin} = require('vue-loader');
|
||||||
let gitRevision = 'error-retrieving-revision';
|
const gitRevision = require('child_process')
|
||||||
let gitBranch = 'error-retrieving-branch';
|
.execSync('git rev-parse HEAD')
|
||||||
|
.toString().trim();
|
||||||
try {
|
const gitBranch = require('child_process')
|
||||||
gitRevision = require('child_process')
|
.execSync('git rev-parse --abbrev-ref HEAD')
|
||||||
.execSync('git rev-parse HEAD')
|
.toString().trim();
|
||||||
.toString().trim();
|
|
||||||
gitBranch = require('child_process')
|
|
||||||
.execSync('git rev-parse --abbrev-ref HEAD')
|
|
||||||
.toString().trim();
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @type {import('webpack').Configuration} */
|
/** @type {import('webpack').Configuration} */
|
||||||
const config = {
|
const config = {
|
||||||
@ -33,10 +26,9 @@ const config = {
|
|||||||
maelstromTheme: './src/plugins/themes/maelstrom-theme.scss'
|
maelstromTheme: './src/plugins/themes/maelstrom-theme.scss'
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
globalObject: 'this',
|
globalObject: "this",
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
path: path.resolve(__dirname, 'dist'),
|
library: '[name]',
|
||||||
library: 'openmct',
|
|
||||||
libraryTarget: 'umd',
|
libraryTarget: 'umd',
|
||||||
publicPath: '',
|
publicPath: '',
|
||||||
hashFunction: 'xxhash64',
|
hashFunction: 'xxhash64',
|
||||||
|
@ -16,5 +16,5 @@ module.exports = merge(common, {
|
|||||||
__OPENMCT_ROOT_RELATIVE__: '""'
|
__OPENMCT_ROOT_RELATIVE__: '""'
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
devtool: 'eval-source-map'
|
devtool: 'source-map'
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user