mirror of
https://github.com/nasa/openmct.git
synced 2025-03-22 12:05:19 +00:00
Restrict timestrip composition to time based plots, plans and imagery (#5161)
* Restrict timestrip composition to time based plots, plans and imagery * Adds unit tests for timeline composition policy * Addresses review comments Improves tests * Reuse test objects Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
This commit is contained in:
parent
e5e93f311c
commit
417b225505
70
src/plugins/timeline/TimelineCompositionPolicy.js
Normal file
70
src/plugins/timeline/TimelineCompositionPolicy.js
Normal file
@ -0,0 +1,70 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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.
|
||||
*****************************************************************************/
|
||||
const ALLOWED_TYPES = [
|
||||
'telemetry.plot.overlay',
|
||||
'telemetry.plot.stacked',
|
||||
'plan'
|
||||
];
|
||||
const DISALLOWED_TYPES = [
|
||||
'telemetry.plot.bar-graph',
|
||||
'telemetry.plot.scatter-plot'
|
||||
];
|
||||
export default function TimelineCompositionPolicy(openmct) {
|
||||
function hasNumericTelemetry(domainObject, metadata) {
|
||||
const hasTelemetry = openmct.telemetry.isTelemetryObject(domainObject);
|
||||
if (!hasTelemetry || !metadata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return metadata.values().length > 0 && hasDomainAndRange(metadata);
|
||||
}
|
||||
|
||||
function hasDomainAndRange(metadata) {
|
||||
return (metadata.valuesForHints(['range']).length > 0
|
||||
&& metadata.valuesForHints(['domain']).length > 0);
|
||||
}
|
||||
|
||||
function hasImageTelemetry(domainObject, metadata) {
|
||||
if (!metadata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return metadata.valuesForHints(['image']).length > 0;
|
||||
}
|
||||
|
||||
return {
|
||||
allow: function (parent, child) {
|
||||
if (parent.type === 'time-strip') {
|
||||
const metadata = openmct.telemetry.getMetadata(child);
|
||||
|
||||
if (!DISALLOWED_TYPES.includes(child.type)
|
||||
&& (hasNumericTelemetry(child, metadata) || hasImageTelemetry(child, metadata) || ALLOWED_TYPES.includes(child.type))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
|
||||
import TimelineViewProvider from './TimelineViewProvider';
|
||||
import timelineInterceptor from "./timelineInterceptor";
|
||||
import TimelineCompositionPolicy from "./TimelineCompositionPolicy";
|
||||
|
||||
export default function () {
|
||||
return function install(openmct) {
|
||||
@ -39,6 +40,8 @@ export default function () {
|
||||
}
|
||||
});
|
||||
timelineInterceptor(openmct);
|
||||
openmct.composition.addPolicy(new TimelineCompositionPolicy(openmct).allow);
|
||||
|
||||
openmct.objectViews.addProvider(new TimelineViewProvider(openmct));
|
||||
};
|
||||
}
|
||||
|
@ -62,6 +62,34 @@ describe('the plugin', function () {
|
||||
})
|
||||
}
|
||||
};
|
||||
let timelineObject = {
|
||||
"composition": [],
|
||||
configuration: {
|
||||
useIndependentTime: false,
|
||||
timeOptions: {
|
||||
mode: {
|
||||
key: 'fixed'
|
||||
},
|
||||
fixedOffsets: {
|
||||
start: 10,
|
||||
end: 11
|
||||
},
|
||||
clockOffsets: {
|
||||
start: -(30 * 60 * 1000),
|
||||
end: (30 * 60 * 1000)
|
||||
}
|
||||
}
|
||||
},
|
||||
"name": "Some timestrip",
|
||||
"type": "time-strip",
|
||||
"location": "mine",
|
||||
"modified": 1631005183584,
|
||||
"persisted": 1631005183502,
|
||||
"identifier": {
|
||||
"namespace": "",
|
||||
"key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9"
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach((done) => {
|
||||
mockObjectPath = [
|
||||
@ -134,28 +162,7 @@ describe('the plugin', function () {
|
||||
|
||||
beforeEach(() => {
|
||||
testViewObject = {
|
||||
id: "test-object",
|
||||
identifier: {
|
||||
key: "test-object",
|
||||
namespace: ''
|
||||
},
|
||||
type: "time-strip",
|
||||
configuration: {
|
||||
useIndependentTime: false,
|
||||
timeOptions: {
|
||||
mode: {
|
||||
key: 'fixed'
|
||||
},
|
||||
fixedOffsets: {
|
||||
start: 10,
|
||||
end: 11
|
||||
},
|
||||
clockOffsets: {
|
||||
start: -(30 * 60 * 1000),
|
||||
end: (30 * 60 * 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
...timelineObject
|
||||
};
|
||||
|
||||
const applicableViews = openmct.objectViews.get(testViewObject, mockObjectPath);
|
||||
@ -187,15 +194,7 @@ describe('the plugin', function () {
|
||||
|
||||
beforeEach(() => {
|
||||
timelineDomainObject = {
|
||||
identifier: {
|
||||
key: 'test-object',
|
||||
namespace: ''
|
||||
},
|
||||
type: 'time-strip',
|
||||
id: "test-object",
|
||||
configuration: {
|
||||
useIndependentTime: false
|
||||
},
|
||||
...timelineObject,
|
||||
composition: [
|
||||
{
|
||||
identifier: {
|
||||
@ -236,27 +235,10 @@ describe('the plugin', function () {
|
||||
describe('the independent time conductor', () => {
|
||||
let timelineView;
|
||||
let testViewObject = {
|
||||
id: "test-object",
|
||||
identifier: {
|
||||
key: "test-object",
|
||||
namespace: ''
|
||||
},
|
||||
type: "time-strip",
|
||||
...timelineObject,
|
||||
configuration: {
|
||||
useIndependentTime: true,
|
||||
timeOptions: {
|
||||
mode: {
|
||||
key: 'local'
|
||||
},
|
||||
fixedOffsets: {
|
||||
start: 10,
|
||||
end: 11
|
||||
},
|
||||
clockOffsets: {
|
||||
start: -(30 * 60 * 1000),
|
||||
end: (30 * 60 * 1000)
|
||||
}
|
||||
}
|
||||
...timelineObject.configuration,
|
||||
useIndependentTime: true
|
||||
}
|
||||
};
|
||||
|
||||
@ -284,27 +266,15 @@ describe('the plugin', function () {
|
||||
describe('the independent time conductor - fixed', () => {
|
||||
let timelineView;
|
||||
let testViewObject2 = {
|
||||
...timelineObject,
|
||||
id: "test-object2",
|
||||
identifier: {
|
||||
key: "test-object2",
|
||||
namespace: ''
|
||||
},
|
||||
type: "time-strip",
|
||||
configuration: {
|
||||
useIndependentTime: true,
|
||||
timeOptions: {
|
||||
mode: {
|
||||
key: 'fixed'
|
||||
},
|
||||
fixedOffsets: {
|
||||
start: 10,
|
||||
end: 11
|
||||
},
|
||||
clockOffsets: {
|
||||
start: -(30 * 60 * 1000),
|
||||
end: (30 * 60 * 1000)
|
||||
}
|
||||
}
|
||||
...timelineObject.configuration,
|
||||
useIndependentTime: true
|
||||
}
|
||||
};
|
||||
|
||||
@ -328,4 +298,68 @@ describe('the plugin', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("The timestrip composition policy", () => {
|
||||
let testObject;
|
||||
beforeEach(() => {
|
||||
testObject = {
|
||||
...timelineObject,
|
||||
composition: []
|
||||
};
|
||||
});
|
||||
|
||||
it("allows composition for plots", () => {
|
||||
const testTelemetryObject = {
|
||||
identifier: {
|
||||
namespace: "",
|
||||
key: "test-object"
|
||||
},
|
||||
type: "test-object",
|
||||
name: "Test Object",
|
||||
telemetry: {
|
||||
values: [{
|
||||
key: "some-key",
|
||||
name: "Some attribute",
|
||||
hints: {
|
||||
domain: 1
|
||||
}
|
||||
}, {
|
||||
key: "some-other-key",
|
||||
name: "Another attribute",
|
||||
hints: {
|
||||
range: 1
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
const composition = openmct.composition.get(testObject);
|
||||
expect(() => {
|
||||
composition.add(testTelemetryObject);
|
||||
}).not.toThrow();
|
||||
expect(testObject.composition.length).toBe(1);
|
||||
});
|
||||
|
||||
it("allows composition for plans", () => {
|
||||
const composition = openmct.composition.get(testObject);
|
||||
expect(() => {
|
||||
composition.add(planObject);
|
||||
}).not.toThrow();
|
||||
expect(testObject.composition.length).toBe(1);
|
||||
});
|
||||
|
||||
it("disallows composition for non time-based plots", () => {
|
||||
const barGraphObject = {
|
||||
identifier: {
|
||||
namespace: "",
|
||||
key: "test-object"
|
||||
},
|
||||
type: "telemetry.plot.bar-graph",
|
||||
name: "Test Object"
|
||||
};
|
||||
const composition = openmct.composition.get(testObject);
|
||||
expect(() => {
|
||||
composition.add(barGraphObject);
|
||||
}).toThrow();
|
||||
expect(testObject.composition.length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user