mirror of
https://github.com/nasa/openmct.git
synced 2024-12-24 23:36:41 +00:00
Merge branch 'master' into mct6555
This commit is contained in:
commit
bd1433db62
1
.github/workflows/e2e-couchdb.yml
vendored
1
.github/workflows/e2e-couchdb.yml
vendored
@ -49,6 +49,7 @@ jobs:
|
||||
- name: Run CouchDB Tests and publish to deploysentinel
|
||||
env:
|
||||
DEPLOYSENTINEL_API_KEY: ${{ secrets.DEPLOYSENTINEL_API_KEY }}
|
||||
COMMIT_INFO_SHA: ${{github.event.pull_request.head.sha }}
|
||||
run: npm run test:e2e:couchdb
|
||||
|
||||
- name: Publish Results to Codecov.io
|
||||
|
@ -29,7 +29,8 @@ relates to how we've extended it (i.e. ./e2e/baseFixtures.js) and assumptions ma
|
||||
const { test } = require('../../baseFixtures.js');
|
||||
|
||||
test.describe('baseFixtures tests', () => {
|
||||
test('Verify that tests fail if console.error is thrown', async ({ page }) => {
|
||||
//Skip this test for now https://github.com/nasa/openmct/issues/6785
|
||||
test.fixme('Verify that tests fail if console.error is thrown', async ({ page }) => {
|
||||
test.fail();
|
||||
//Go to baseURL
|
||||
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||
|
@ -26,7 +26,11 @@ necessarily be used for reference when writing new tests in this area.
|
||||
*/
|
||||
|
||||
const { test, expect } = require('../../../../pluginFixtures');
|
||||
const { createDomainObjectWithDefaults, selectInspectorTab } = require('../../../../appActions');
|
||||
const {
|
||||
createDomainObjectWithDefaults,
|
||||
selectInspectorTab,
|
||||
waitForPlotsToRender
|
||||
} = require('../../../../appActions');
|
||||
|
||||
test.describe('Stacked Plot', () => {
|
||||
let stackedPlot;
|
||||
@ -227,4 +231,45 @@ test.describe('Stacked Plot', () => {
|
||||
page.locator('[aria-label="Plot Series Properties"] .c-object-label')
|
||||
).toContainText(swgC.name);
|
||||
});
|
||||
|
||||
test('the legend toggles between aggregate and per child', async ({ page }) => {
|
||||
await page.goto(stackedPlot.url);
|
||||
|
||||
// Go into edit mode
|
||||
await page.click('button[title="Edit"]');
|
||||
|
||||
await selectInspectorTab(page, 'Config');
|
||||
|
||||
let legendProperties = await page.locator('[aria-label="Legend Properties"]');
|
||||
await legendProperties.locator('[title="Display legends per sub plot."]~div input').uncheck();
|
||||
|
||||
await assertAggregateLegendIsVisible(page);
|
||||
|
||||
// Save (exit edit mode)
|
||||
await page.locator('button[title="Save"]').click();
|
||||
await page.locator('li[title="Save and Finish Editing"]').click();
|
||||
|
||||
await assertAggregateLegendIsVisible(page);
|
||||
|
||||
await page.reload();
|
||||
|
||||
await assertAggregateLegendIsVisible(page);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Asserts that aggregate stacked plot legend is visible
|
||||
* @param {import('@playwright/test').Page} page
|
||||
*/
|
||||
async function assertAggregateLegendIsVisible(page) {
|
||||
// Wait for plot series data to load
|
||||
await waitForPlotsToRender(page);
|
||||
// Wait for plot legend to be shown
|
||||
await page.waitForSelector('.js-stacked-plot-legend', { state: 'attached' });
|
||||
// There should be 3 legend items
|
||||
expect(
|
||||
await page
|
||||
.locator('.js-stacked-plot-legend .c-plot-legend__wrapper div.plot-legend-item')
|
||||
.count()
|
||||
).toBe(3);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import CouchDocument from './CouchDocument';
|
||||
import CouchObjectQueue from './CouchObjectQueue';
|
||||
import { PENDING, CONNECTED, DISCONNECTED, UNKNOWN } from './CouchStatusIndicator';
|
||||
import { isNotebookOrAnnotationType } from '../../notebook/notebook-constants.js';
|
||||
import _ from 'lodash';
|
||||
|
||||
const REV = '_rev';
|
||||
const ID = '_id';
|
||||
@ -42,6 +43,8 @@ class CouchObjectProvider {
|
||||
this.batchIds = [];
|
||||
this.onEventMessage = this.onEventMessage.bind(this);
|
||||
this.onEventError = this.onEventError.bind(this);
|
||||
this.flushPersistenceQueue = _.debounce(this.flushPersistenceQueue.bind(this));
|
||||
this.persistenceQueue = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -668,9 +671,12 @@ class CouchObjectProvider {
|
||||
if (!this.objectQueue[key].pending) {
|
||||
this.objectQueue[key].pending = true;
|
||||
const queued = this.objectQueue[key].dequeue();
|
||||
let document = new CouchDocument(key, queued.model);
|
||||
document.metadata.created = Date.now();
|
||||
this.request(key, 'PUT', document)
|
||||
let couchDocument = new CouchDocument(key, queued.model);
|
||||
couchDocument.metadata.created = Date.now();
|
||||
this.#enqueueForPersistence({
|
||||
key,
|
||||
document: couchDocument
|
||||
})
|
||||
.then((response) => {
|
||||
this.#checkResponse(response, queued.intermediateResponse, key);
|
||||
})
|
||||
@ -683,6 +689,42 @@ class CouchObjectProvider {
|
||||
return intermediateResponse.promise;
|
||||
}
|
||||
|
||||
#enqueueForPersistence({ key, document }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.persistenceQueue.push({
|
||||
key,
|
||||
document,
|
||||
resolve,
|
||||
reject
|
||||
});
|
||||
this.flushPersistenceQueue();
|
||||
});
|
||||
}
|
||||
|
||||
async flushPersistenceQueue() {
|
||||
if (this.persistenceQueue.length > 1) {
|
||||
const batch = {
|
||||
docs: this.persistenceQueue.map((queued) => queued.document)
|
||||
};
|
||||
const response = await this.request('_bulk_docs', 'POST', batch);
|
||||
response.forEach((responseMetadatum) => {
|
||||
const queued = this.persistenceQueue.find(
|
||||
(queuedMetadatum) => queuedMetadatum.key === responseMetadatum.id
|
||||
);
|
||||
if (responseMetadatum.ok) {
|
||||
queued.resolve(responseMetadatum);
|
||||
} else {
|
||||
queued.reject(responseMetadatum);
|
||||
}
|
||||
});
|
||||
} else if (this.persistenceQueue.length === 1) {
|
||||
const { key, document, resolve, reject } = this.persistenceQueue[0];
|
||||
|
||||
this.request(key, 'PUT', document).then(resolve).catch(reject);
|
||||
}
|
||||
this.persistenceQueue = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
@ -243,6 +243,135 @@ describe('the plugin', () => {
|
||||
expect(requestMethod).toEqual('GET');
|
||||
});
|
||||
});
|
||||
describe('batches persistence', () => {
|
||||
let successfulMockPromise;
|
||||
let partialFailureMockPromise;
|
||||
let objectsToPersist;
|
||||
|
||||
beforeEach(() => {
|
||||
successfulMockPromise = Promise.resolve({
|
||||
json: () => {
|
||||
return [
|
||||
{
|
||||
id: 'object-1',
|
||||
ok: true
|
||||
},
|
||||
{
|
||||
id: 'object-2',
|
||||
ok: true
|
||||
},
|
||||
{
|
||||
id: 'object-3',
|
||||
ok: true
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
partialFailureMockPromise = Promise.resolve({
|
||||
json: () => {
|
||||
return [
|
||||
{
|
||||
id: 'object-1',
|
||||
ok: true
|
||||
},
|
||||
{
|
||||
id: 'object-2',
|
||||
ok: false
|
||||
},
|
||||
{
|
||||
id: 'object-3',
|
||||
ok: true
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
objectsToPersist = [
|
||||
{
|
||||
identifier: {
|
||||
namespace: '',
|
||||
key: 'object-1'
|
||||
},
|
||||
name: 'object-1',
|
||||
type: 'folder',
|
||||
modified: 0
|
||||
},
|
||||
{
|
||||
identifier: {
|
||||
namespace: '',
|
||||
key: 'object-2'
|
||||
},
|
||||
name: 'object-2',
|
||||
type: 'folder',
|
||||
modified: 0
|
||||
},
|
||||
{
|
||||
identifier: {
|
||||
namespace: '',
|
||||
key: 'object-3'
|
||||
},
|
||||
name: 'object-3',
|
||||
type: 'folder',
|
||||
modified: 0
|
||||
}
|
||||
];
|
||||
});
|
||||
it('for multiple simultaneous successful saves', async () => {
|
||||
fetch.and.returnValue(successfulMockPromise);
|
||||
|
||||
await Promise.all(
|
||||
objectsToPersist.map((objectToPersist) => openmct.objects.save(objectToPersist))
|
||||
);
|
||||
|
||||
const requestUrl = fetch.calls.mostRecent().args[0];
|
||||
const requestMethod = fetch.calls.mostRecent().args[1].method;
|
||||
const requestBody = JSON.parse(fetch.calls.mostRecent().args[1].body);
|
||||
|
||||
expect(fetch).toHaveBeenCalledTimes(1);
|
||||
expect(requestUrl.includes('_bulk_docs')).toBeTrue();
|
||||
expect(requestMethod).toEqual('POST');
|
||||
expect(
|
||||
objectsToPersist.every(
|
||||
(object, index) => object.identifier.key === requestBody.docs[index]._id
|
||||
)
|
||||
).toBeTrue();
|
||||
});
|
||||
it('for multiple simultaneous saves with partial failure', async () => {
|
||||
fetch.and.returnValue(partialFailureMockPromise);
|
||||
|
||||
let saveResults = await Promise.all(
|
||||
objectsToPersist.map((objectToPersist) =>
|
||||
openmct.objects
|
||||
.save(objectToPersist)
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
)
|
||||
);
|
||||
expect(saveResults[0]).toBeTrue();
|
||||
expect(saveResults[1]).toBeFalse();
|
||||
expect(saveResults[2]).toBeTrue();
|
||||
});
|
||||
it('except for a single save', async () => {
|
||||
fetch.and.returnValue({
|
||||
json: () => {
|
||||
return {
|
||||
id: 'object-1',
|
||||
ok: true
|
||||
};
|
||||
}
|
||||
});
|
||||
await openmct.objects.save(objectsToPersist[0]);
|
||||
|
||||
const requestUrl = fetch.calls.mostRecent().args[0];
|
||||
const requestMethod = fetch.calls.mostRecent().args[1].method;
|
||||
|
||||
expect(fetch).toHaveBeenCalledTimes(1);
|
||||
expect(requestUrl.includes('_bulk_docs')).toBeFalse();
|
||||
expect(requestUrl.endsWith('object-1')).toBeTrue();
|
||||
expect(requestMethod).toEqual('PUT');
|
||||
});
|
||||
});
|
||||
describe('implements server-side search', () => {
|
||||
let mockPromise;
|
||||
beforeEach(() => {
|
||||
|
@ -77,6 +77,7 @@
|
||||
<mct-chart
|
||||
:rectangles="rectangles"
|
||||
:highlights="highlights"
|
||||
:show-limit-line-labels="limitLineLabels"
|
||||
:annotated-points="annotatedPoints"
|
||||
:annotation-selections="annotationSelections"
|
||||
:hidden-y-axis-ids="hiddenYAxisIds"
|
||||
@ -231,7 +232,7 @@ export default {
|
||||
limitLineLabels: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
colorPalette: {
|
||||
|
@ -33,18 +33,23 @@
|
||||
/>
|
||||
<mct-plot
|
||||
:class="[plotLegendExpandedStateClass, plotLegendPositionClass]"
|
||||
:init-grid-lines="gridLines"
|
||||
:init-grid-lines="gridLinesProp"
|
||||
:init-cursor-guide="cursorGuide"
|
||||
:options="options"
|
||||
:limit-line-labels="limitLineLabels"
|
||||
:limit-line-labels="limitLineLabelsProp"
|
||||
:parent-y-tick-width="parentYTickWidth"
|
||||
:color-palette="colorPalette"
|
||||
@loadingUpdated="loadingUpdated"
|
||||
@statusUpdated="setStatus"
|
||||
@configLoaded="updateReady"
|
||||
@lockHighlightPoint="lockHighlightPointUpdated"
|
||||
@highlights="highlightsUpdated"
|
||||
@plotYTickWidth="onYTickWidthChange"
|
||||
@cursorGuide="onCursorGuideChange"
|
||||
@gridLines="onGridLinesChange"
|
||||
>
|
||||
<plot-legend
|
||||
v-if="configReady"
|
||||
v-if="configReady && hideLegend === false"
|
||||
:cursor-locked="lockHighlightPoint"
|
||||
:highlights="highlights"
|
||||
@legendHoverChanged="legendHoverChanged"
|
||||
@ -79,14 +84,50 @@ export default {
|
||||
compact: false
|
||||
};
|
||||
}
|
||||
},
|
||||
gridLines: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
cursorGuide: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
parentLimitLineLabels: {
|
||||
type: Object,
|
||||
default() {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
colorPalette: {
|
||||
type: Object,
|
||||
default() {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
parentYTickWidth: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
leftTickWidth: 0,
|
||||
rightTickWidth: 0,
|
||||
hasMultipleLeftAxes: false
|
||||
};
|
||||
}
|
||||
},
|
||||
hideLegend: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
//Don't think we need this as it appears to be stacked plot specific
|
||||
// hideExportButtons: false
|
||||
cursorGuide: false,
|
||||
gridLines: !this.options.compact,
|
||||
loading: false,
|
||||
status: '',
|
||||
staleObjects: [],
|
||||
@ -99,6 +140,12 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
limitLineLabelsProp() {
|
||||
return this.parentLimitLineLabels ?? this.limitLineLabels;
|
||||
},
|
||||
gridLinesProp() {
|
||||
return this.gridLines ?? !this.options.compact;
|
||||
},
|
||||
staleClass() {
|
||||
if (this.staleObjects.length !== 0) {
|
||||
return 'is-stale';
|
||||
@ -117,6 +164,14 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
gridLines(newGridLines) {
|
||||
this.gridLines = newGridLines;
|
||||
},
|
||||
cursorGuide(newCursorGuide) {
|
||||
this.cursorGuide = newCursorGuide;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
eventHelpers.extend(this);
|
||||
this.imageExporter = new ImageExporter(this.openmct);
|
||||
@ -188,6 +243,7 @@ export default {
|
||||
},
|
||||
loadingUpdated(loading) {
|
||||
this.loading = loading;
|
||||
this.$emit('loadingUpdated', ...arguments);
|
||||
},
|
||||
destroy() {
|
||||
if (this.stalenessSubscription) {
|
||||
@ -223,9 +279,11 @@ export default {
|
||||
},
|
||||
lockHighlightPointUpdated(data) {
|
||||
this.lockHighlightPoint = data;
|
||||
this.$emit('lockHighlightPoint', ...arguments);
|
||||
},
|
||||
highlightsUpdated(data) {
|
||||
this.highlights = data;
|
||||
this.$emit('highlights', ...arguments);
|
||||
},
|
||||
legendHoverChanged(data) {
|
||||
this.limitLineLabels = data;
|
||||
@ -238,6 +296,16 @@ export default {
|
||||
},
|
||||
updateReady(ready) {
|
||||
this.configReady = ready;
|
||||
this.$emit('configLoaded', ...arguments);
|
||||
},
|
||||
onYTickWidthChange() {
|
||||
this.$emit('plotYTickWidth', ...arguments);
|
||||
},
|
||||
onCursorGuideChange() {
|
||||
this.$emit('cursorGuide', ...arguments);
|
||||
},
|
||||
onGridLinesChange() {
|
||||
this.$emit('gridLines', ...arguments);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -114,7 +114,7 @@ export default {
|
||||
showLimitLineLabels: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
hiddenYAxisIds: {
|
||||
@ -725,7 +725,7 @@ export default {
|
||||
});
|
||||
},
|
||||
showLabels(seriesKey) {
|
||||
return this.showLimitLineLabels.seriesKey && this.showLimitLineLabels.seriesKey === seriesKey;
|
||||
return this.showLimitLineLabels?.seriesKey === seriesKey;
|
||||
},
|
||||
getLimitElement(limit) {
|
||||
let point = {
|
||||
|
@ -55,7 +55,8 @@ export default class LegendModel extends Model {
|
||||
showValueWhenExpanded: true,
|
||||
showMaximumWhenExpanded: true,
|
||||
showMinimumWhenExpanded: true,
|
||||
showUnitsWhenExpanded: true
|
||||
showUnitsWhenExpanded: true,
|
||||
showLegendsForChildren: true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,12 @@
|
||||
<div v-if="isStackedPlotObject || !isNestedWithinAStackedPlot" class="grid-properties">
|
||||
<ul class="l-inspector-part js-legend-properties">
|
||||
<h2 class="--first" title="Legend settings for this object">Legend</h2>
|
||||
<li v-if="isStackedPlotObject" class="grid-row">
|
||||
<div class="grid-cell label" title="Display legends per sub plot.">
|
||||
Show legend per plot
|
||||
</div>
|
||||
<div class="grid-cell value">{{ showLegendsForChildren ? 'Yes' : 'No' }}</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div
|
||||
class="grid-cell label"
|
||||
@ -139,6 +145,7 @@ export default {
|
||||
showMinimumWhenExpanded: '',
|
||||
showMaximumWhenExpanded: '',
|
||||
showUnitsWhenExpanded: '',
|
||||
showLegendsForChildren: '',
|
||||
loaded: false,
|
||||
plotSeries: [],
|
||||
yAxes: []
|
||||
@ -218,6 +225,7 @@ export default {
|
||||
this.showMinimumWhenExpanded = this.config.legend.get('showMinimumWhenExpanded');
|
||||
this.showMaximumWhenExpanded = this.config.legend.get('showMaximumWhenExpanded');
|
||||
this.showUnitsWhenExpanded = this.config.legend.get('showUnitsWhenExpanded');
|
||||
this.showLegendsForChildren = this.config.legend.get('showLegendsForChildren');
|
||||
}
|
||||
},
|
||||
getConfig() {
|
||||
|
@ -35,7 +35,11 @@
|
||||
:y-axis="config.yAxis"
|
||||
@seriesUpdated="updateSeriesConfigForObject"
|
||||
/>
|
||||
<ul v-if="isStackedPlotObject || !isStackedPlotNestedObject" class="l-inspector-part">
|
||||
<ul
|
||||
v-if="isStackedPlotObject || !isStackedPlotNestedObject"
|
||||
class="l-inspector-part"
|
||||
aria-label="Legend Properties"
|
||||
>
|
||||
<h2 class="--first" title="Legend options">Legend</h2>
|
||||
<legend-form class="grid-properties" :legend="config.legend" />
|
||||
</ul>
|
||||
|
@ -21,6 +21,16 @@
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<li v-if="isStackedPlotObject" class="grid-row">
|
||||
<div class="grid-cell label" title="Display legends per sub plot.">Show legend per plot</div>
|
||||
<div class="grid-cell value">
|
||||
<input
|
||||
v-model="showLegendsForChildren"
|
||||
type="checkbox"
|
||||
@change="updateForm('showLegendsForChildren')"
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div
|
||||
class="grid-cell label"
|
||||
@ -128,7 +138,7 @@ import { coerce, objectPath, validate } from './formUtil';
|
||||
import _ from 'lodash';
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'domainObject'],
|
||||
inject: ['openmct', 'domainObject', 'path'],
|
||||
props: {
|
||||
legend: {
|
||||
type: Object,
|
||||
@ -148,9 +158,18 @@ export default {
|
||||
showMinimumWhenExpanded: '',
|
||||
showMaximumWhenExpanded: '',
|
||||
showUnitsWhenExpanded: '',
|
||||
showLegendsForChildren: '',
|
||||
validation: {}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isStackedPlotObject() {
|
||||
return this.path.find(
|
||||
(pathObject, pathObjIndex) =>
|
||||
pathObjIndex === 0 && pathObject?.type === 'telemetry.plot.stacked'
|
||||
);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initialize();
|
||||
this.initFormValues();
|
||||
@ -200,6 +219,11 @@ export default {
|
||||
modelProp: 'showUnitsWhenExpanded',
|
||||
coerce: Boolean,
|
||||
objectPath: 'configuration.legend.showUnitsWhenExpanded'
|
||||
},
|
||||
{
|
||||
modelProp: 'showLegendsForChildren',
|
||||
coerce: Boolean,
|
||||
objectPath: 'configuration.legend.showLegendsForChildren'
|
||||
}
|
||||
];
|
||||
},
|
||||
@ -213,6 +237,7 @@ export default {
|
||||
this.showMinimumWhenExpanded = this.legend.get('showMinimumWhenExpanded');
|
||||
this.showMaximumWhenExpanded = this.legend.get('showMaximumWhenExpanded');
|
||||
this.showUnitsWhenExpanded = this.legend.get('showUnitsWhenExpanded');
|
||||
this.showLegendsForChildren = this.legend.get('showLegendsForChildren');
|
||||
},
|
||||
updateForm(formKey) {
|
||||
const newVal = this[formKey];
|
||||
|
@ -181,9 +181,14 @@ export default {
|
||||
},
|
||||
toggleHover(hover) {
|
||||
this.hover = hover;
|
||||
this.$emit('legendHoverChanged', {
|
||||
seriesKey: this.hover ? this.seriesObject.keyString : ''
|
||||
});
|
||||
this.$emit(
|
||||
'legendHoverChanged',
|
||||
this.hover
|
||||
? {
|
||||
seriesKey: this.seriesObject.keyString
|
||||
}
|
||||
: undefined
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -27,9 +27,10 @@
|
||||
:class="[plotLegendExpandedStateClass, plotLegendPositionClass]"
|
||||
>
|
||||
<plot-legend
|
||||
v-if="compositionObjectsConfigLoaded"
|
||||
v-if="compositionObjectsConfigLoaded && showLegendsForChildren === false"
|
||||
:cursor-locked="!!lockHighlightPoint"
|
||||
:highlights="highlights"
|
||||
class="js-stacked-plot-legend"
|
||||
@legendHoverChanged="legendHoverChanged"
|
||||
@expanded="updateExpanded"
|
||||
@position="updatePosition"
|
||||
@ -46,6 +47,7 @@
|
||||
:cursor-guide="cursorGuide"
|
||||
:show-limit-line-labels="showLimitLineLabels"
|
||||
:parent-y-tick-width="maxTickWidth"
|
||||
:hide-legend="showLegendsForChildren === false"
|
||||
@plotYTickWidth="onYTickWidthChange"
|
||||
@loadingUpdated="loadingUpdated"
|
||||
@cursorGuide="onCursorGuideChange"
|
||||
@ -66,6 +68,7 @@ import ColorPalette from '@/ui/color/ColorPalette';
|
||||
import PlotLegend from '../legend/PlotLegend.vue';
|
||||
import StackedPlotItem from './StackedPlotItem.vue';
|
||||
import ImageExporter from '../../../exporters/ImageExporter';
|
||||
import eventHelpers from '../lib/eventHelpers';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -96,19 +99,28 @@ export default {
|
||||
colorPalette: new ColorPalette(),
|
||||
compositionObjectsConfigLoaded: false,
|
||||
position: 'top',
|
||||
showLegendsForChildren: true,
|
||||
expanded: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
plotLegendPositionClass() {
|
||||
if (this.showLegendsForChildren) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return `plot-legend-${this.position}`;
|
||||
},
|
||||
plotLegendExpandedStateClass() {
|
||||
if (this.expanded) {
|
||||
return 'plot-legend-expanded';
|
||||
} else {
|
||||
return 'plot-legend-collapsed';
|
||||
let legendExpandedStateClass = '';
|
||||
|
||||
if (this.showLegendsForChildren !== true && this.expanded) {
|
||||
legendExpandedStateClass = 'plot-legend-expanded';
|
||||
} else if (this.showLegendsForChildren !== true && !this.expanded) {
|
||||
legendExpandedStateClass = 'plot-legend-collapsed';
|
||||
}
|
||||
|
||||
return legendExpandedStateClass;
|
||||
},
|
||||
/**
|
||||
* Returns the maximum width of the left and right y axes ticks of this stacked plots children
|
||||
@ -137,9 +149,11 @@ export default {
|
||||
this.destroy();
|
||||
},
|
||||
mounted() {
|
||||
eventHelpers.extend(this);
|
||||
//We only need to initialize the stacked plot config for legend properties
|
||||
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
this.config = this.getConfig(configId);
|
||||
this.showLegendsForChildren = this.config.legend.get('showLegendsForChildren');
|
||||
|
||||
this.loaded = true;
|
||||
this.imageExporter = new ImageExporter(this.openmct);
|
||||
@ -183,11 +197,21 @@ export default {
|
||||
|
||||
return this.configLoaded[id] === true;
|
||||
});
|
||||
if (this.compositionObjectsConfigLoaded) {
|
||||
this.listenTo(
|
||||
this.config.legend,
|
||||
'change:showLegendsForChildren',
|
||||
this.updateShowLegendsForChildren,
|
||||
this
|
||||
);
|
||||
}
|
||||
},
|
||||
destroy() {
|
||||
this.composition.off('add', this.addChild);
|
||||
this.composition.off('remove', this.removeChild);
|
||||
this.composition.off('reorder', this.compositionReorder);
|
||||
|
||||
this.stopListening();
|
||||
},
|
||||
|
||||
addChild(child) {
|
||||
@ -305,6 +329,9 @@ export default {
|
||||
updatePosition(position) {
|
||||
this.position = position;
|
||||
},
|
||||
updateShowLegendsForChildren(showLegendsForChildren) {
|
||||
this.showLegendsForChildren = showLegendsForChildren;
|
||||
},
|
||||
updateReady(ready) {
|
||||
this.configReady = ready;
|
||||
},
|
||||
|
@ -23,14 +23,13 @@
|
||||
<div :aria-label="`Stacked Plot Item ${childObject.name}`"></div>
|
||||
</template>
|
||||
<script>
|
||||
import MctPlot from '../MctPlot.vue';
|
||||
import Vue from 'vue';
|
||||
import conditionalStylesMixin from './mixins/objectStyles-mixin';
|
||||
import stalenessMixin from '@/ui/mixins/staleness-mixin';
|
||||
import StalenessUtils from '@/utils/staleness';
|
||||
import configStore from '@/plugins/plot/configuration/ConfigStore';
|
||||
import PlotConfigurationModel from '@/plugins/plot/configuration/PlotConfigurationModel';
|
||||
import ProgressBar from '../../../ui/components/ProgressBar.vue';
|
||||
import Plot from '../Plot.vue';
|
||||
|
||||
export default {
|
||||
mixins: [conditionalStylesMixin, stalenessMixin],
|
||||
@ -63,7 +62,7 @@ export default {
|
||||
showLimitLineLabels: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
colorPalette: {
|
||||
@ -81,6 +80,12 @@ export default {
|
||||
hasMultipleLeftAxes: false
|
||||
};
|
||||
}
|
||||
},
|
||||
hideLegend: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@ -104,6 +109,9 @@ export default {
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
hideLegend(newHideLegend) {
|
||||
this.updateComponentProp('hideLegend', newHideLegend);
|
||||
},
|
||||
staleObjects() {
|
||||
this.isStale = this.staleObjects.length > 0;
|
||||
this.updateComponentProp('isStale', this.isStale);
|
||||
@ -163,7 +171,6 @@ export default {
|
||||
const onConfigLoaded = this.onConfigLoaded;
|
||||
const onCursorGuideChange = this.onCursorGuideChange;
|
||||
const onGridLinesChange = this.onGridLinesChange;
|
||||
const setStatus = this.setStatus;
|
||||
|
||||
const openmct = this.openmct;
|
||||
const path = this.path;
|
||||
@ -192,8 +199,7 @@ export default {
|
||||
this.component = new Vue({
|
||||
el: viewContainer,
|
||||
components: {
|
||||
MctPlot,
|
||||
ProgressBar
|
||||
Plot
|
||||
},
|
||||
provide: {
|
||||
openmct,
|
||||
@ -209,7 +215,6 @@ export default {
|
||||
onConfigLoaded,
|
||||
onCursorGuideChange,
|
||||
onGridLinesChange,
|
||||
setStatus,
|
||||
isMissing,
|
||||
loading: false
|
||||
};
|
||||
@ -220,29 +225,22 @@ export default {
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div v-if="!isMissing" ref="plotWrapper"
|
||||
class="l-view-section u-style-receiver js-style-receiver"
|
||||
:class="{'s-status-timeconductor-unsynced': status && status === 'timeconductor-unsynced', 'is-stale': isStale}">
|
||||
<progress-bar
|
||||
v-show="loading !== false"
|
||||
class="c-telemetry-table__progress-bar"
|
||||
:model="{progressPerc: undefined}" />
|
||||
<mct-plot
|
||||
:init-grid-lines="gridLines"
|
||||
:init-cursor-guide="cursorGuide"
|
||||
:parent-y-tick-width="parentYTickWidth"
|
||||
:limit-line-labels="limitLineLabels"
|
||||
:color-palette="colorPalette"
|
||||
<Plot ref="plotComponent" v-if="!isMissing"
|
||||
:class="{'is-stale': isStale}"
|
||||
:grid-lines="gridLines"
|
||||
:hide-legend="hideLegend"
|
||||
:cursor-guide="cursorGuide"
|
||||
:parent-limit-line-labels="limitLineLabels"
|
||||
:options="options"
|
||||
@plotYTickWidth="onYTickWidthChange"
|
||||
:parent-y-tick-width="parentYTickWidth"
|
||||
:color-palette="colorPalette"
|
||||
@loadingUpdated="loadingUpdated"
|
||||
@configLoaded="onConfigLoaded"
|
||||
@lockHighlightPoint="onLockHighlightPointUpdated"
|
||||
@highlights="onHighlightsUpdated"
|
||||
@configLoaded="onConfigLoaded"
|
||||
@plotYTickWidth="onYTickWidthChange"
|
||||
@cursorGuide="onCursorGuideChange"
|
||||
@gridLines="onGridLinesChange"
|
||||
@statusUpdated="setStatus"
|
||||
@loadingUpdated="loadingUpdated"/>
|
||||
</div>`
|
||||
@gridLines="onGridLinesChange"/>`
|
||||
});
|
||||
|
||||
if (this.isEditing) {
|
||||
@ -315,10 +313,6 @@ export default {
|
||||
onGridLinesChange() {
|
||||
this.$emit('gridLines', ...arguments);
|
||||
},
|
||||
setStatus(status) {
|
||||
this.status = status;
|
||||
this.updateComponentProp('status', status);
|
||||
},
|
||||
setSelection() {
|
||||
let childContext = {};
|
||||
childContext.item = this.childObject;
|
||||
@ -331,12 +325,12 @@ export default {
|
||||
},
|
||||
getProps() {
|
||||
return {
|
||||
hideLegend: this.hideLegend,
|
||||
limitLineLabels: this.showLimitLineLabels,
|
||||
gridLines: this.gridLines,
|
||||
cursorGuide: this.cursorGuide,
|
||||
parentYTickWidth: this.parentYTickWidth,
|
||||
options: this.options,
|
||||
status: this.status,
|
||||
colorPalette: this.colorPalette,
|
||||
isStale: this.isStale
|
||||
};
|
||||
|
@ -490,12 +490,12 @@ describe('the plugin', function () {
|
||||
max: 10
|
||||
});
|
||||
Vue.nextTick(() => {
|
||||
expect(plotViewComponentObject.$children[0].component.$children[1].xScale.domain()).toEqual(
|
||||
{
|
||||
expect(
|
||||
plotViewComponentObject.$children[0].component.$children[0].$children[1].xScale.domain()
|
||||
).toEqual({
|
||||
min: 0,
|
||||
max: 10
|
||||
}
|
||||
);
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -509,7 +509,8 @@ describe('the plugin', function () {
|
||||
});
|
||||
});
|
||||
Vue.nextTick(() => {
|
||||
const yAxesScales = plotViewComponentObject.$children[0].component.$children[1].yScale;
|
||||
const yAxesScales =
|
||||
plotViewComponentObject.$children[0].component.$children[0].$children[1].yScale;
|
||||
yAxesScales.forEach((yAxisScale) => {
|
||||
expect(yAxisScale.scale.domain()).toEqual({
|
||||
min: 10,
|
||||
|
@ -93,10 +93,6 @@ mct-plot {
|
||||
min-height: $plotMinH;
|
||||
overflow: hidden;
|
||||
|
||||
.is-stale {
|
||||
@include isStaleHolder();
|
||||
}
|
||||
|
||||
&[s-selected] {
|
||||
.is-editing & {
|
||||
border: $editMarqueeBorder;
|
||||
|
Loading…
Reference in New Issue
Block a user