mirror of
https://github.com/nasa/openmct.git
synced 2025-06-27 11:32:13 +00:00
Compare commits
95 Commits
deep-plotl
...
joel/plot-
Author | SHA1 | Date | |
---|---|---|---|
a1d1301542 | |||
aef8589872 | |||
38f3e60884 | |||
331c086a60 | |||
0890ebfd0f | |||
1547ea5cf7 | |||
b1551478e4 | |||
213c469758 | |||
03ac43d306 | |||
f3de6f2548 | |||
62dfb7d8f9 | |||
0a33cbeea2 | |||
4908d5afb0 | |||
aa4bf5eaf6 | |||
4eb4cbfffc | |||
eda01abcbc | |||
694b8f4666 | |||
4e4031e700 | |||
46a20bb76d | |||
1d482f318e | |||
6826b579a6 | |||
bbb271a678 | |||
fec1438806 | |||
28f19ec310 | |||
3d4c721232 | |||
190d34c939 | |||
47bc0e9793 | |||
35115aaa50 | |||
f934454c25 | |||
b252051c83 | |||
4ca1181eb6 | |||
eb49ffae02 | |||
5751012872 | |||
f973f42729 | |||
4788561631 | |||
e8699d54d5 | |||
14bc49451b | |||
dd2e8c0460 | |||
031753a9a8 | |||
8edae5f02c | |||
7ed3de01b9 | |||
aa041e04cf | |||
24e7ea143a | |||
79d5d9c4d0 | |||
b5bfdc4418 | |||
59730c60ec | |||
4a87a5d847 | |||
4a1931f594 | |||
f174dcc2f6 | |||
0c741c67f8 | |||
85da5e43b3 | |||
d26e45f636 | |||
0bd6814097 | |||
4e7410b4bf | |||
436550adba | |||
421c09ec2c | |||
f6b1be0486 | |||
eca12201c7 | |||
68ff69664b | |||
0679b246b8 | |||
51fbb9cee6 | |||
437156e04c | |||
d244ee622a | |||
b30018c315 | |||
eb5eb7d540 | |||
609a47c62c | |||
83f9c6c528 | |||
a5f3ba6259 | |||
a70facf0c8 | |||
447fe94325 | |||
8e2b666766 | |||
dcbfbdbb89 | |||
4c76bf34ab | |||
688a03c8ac | |||
81b7a9d3e0 | |||
dc573c479c | |||
4f12f41685 | |||
189882afc8 | |||
2b3541a323 | |||
7c9a140481 | |||
5e9b313ee9 | |||
c64db6c07d | |||
9e2751acf7 | |||
51fb72dc04 | |||
d51052ab46 | |||
f62010fb99 | |||
ba4ef43673 | |||
f6c16b7483 | |||
58e63e649f | |||
7a04aea90e | |||
0bb475327c | |||
c474b998f0 | |||
a02d421093 | |||
9026099fd2 | |||
295ccea195 |
4
API.md
4
API.md
@ -427,8 +427,8 @@ Each telemetry value description has an object defining hints. Keys in this thi
|
|||||||
|
|
||||||
Known hints:
|
Known hints:
|
||||||
|
|
||||||
* `domain`: Indicates that the value represents the "input" of a datum. Values with a `domain` hint will be used for the x-axis of a plot, and tables will render columns for these values first.
|
* `domain`: Values with a `domain` hint will be used for the x-axis of a plot, and tables will render columns for these values first.
|
||||||
* `range`: Indicates that the value is the "output" of a datum. Values with a `range` hint will be used as the y-axis on a plot, and tables will render columns for these values after the `domain` values.
|
* `range`: Values with a `range` hint will be used as the y-axis on a plot, and tables will render columns for these values after the `domain` values.
|
||||||
* `image`: Indicates that the value may be interpreted as the URL to an image file, in which case appropriate views will be made available.
|
* `image`: Indicates that the value may be interpreted as the URL to an image file, in which case appropriate views will be made available.
|
||||||
|
|
||||||
##### The Time Conductor and Telemetry
|
##### The Time Conductor and Telemetry
|
||||||
|
@ -103,7 +103,7 @@ the name chosen could not be mistaken for a topic or master branch.
|
|||||||
### Merging
|
### Merging
|
||||||
|
|
||||||
When development is complete on an issue, the first step toward merging it
|
When development is complete on an issue, the first step toward merging it
|
||||||
back into the master branch is to file a Pull Request. The contributions
|
back into the master branch is to file a Pull Request (PR). The contributions
|
||||||
should meet code, test, and commit message standards as described below,
|
should meet code, test, and commit message standards as described below,
|
||||||
and the pull request should include a completed author checklist, also
|
and the pull request should include a completed author checklist, also
|
||||||
as described below. Pull requests may be assigned to specific team
|
as described below. Pull requests may be assigned to specific team
|
||||||
@ -114,6 +114,15 @@ request. When the reviewer is satisfied, they should add a comment to
|
|||||||
the pull request containing the reviewer checklist (from below) and complete
|
the pull request containing the reviewer checklist (from below) and complete
|
||||||
the merge back to the master branch.
|
the merge back to the master branch.
|
||||||
|
|
||||||
|
Additionally:
|
||||||
|
* Every pull request must link to the issue that it addresses. Eg. “Addresses #1234” or “Closes #1234”. This is the responsibility of the pull request’s __author__. If no issue exists, create one.
|
||||||
|
* Every __author__ must include testing instructions. These instructions should identify the areas of code affected, and some minimal test steps. If addressing a bug, reproduction steps should be included, if they were not included in the original issue. If reproduction steps were included on the original issue, and are sufficient, refer to them.
|
||||||
|
* A pull request that closes an issue should say so in the description. Including the text “Closes #1234” will cause the linked issue to be automatically closed when the pull request is merged. This is the responsibility of the pull request’s __author__.
|
||||||
|
* When a pull request is merged, and the corresponding issue closed, the __reviewer__ must add the tag “unverified” to the original issue. This will indicate that although the issue is closed, it has not been tested yet.
|
||||||
|
* Every PR must have two reviewers assigned, though only one approval is necessary for merge.
|
||||||
|
* Changes to API require approval by a senior developer.
|
||||||
|
* When creating a PR, it is the author's responsibility to apply any priority label from the issue to the PR as well. This helps with prioritization.
|
||||||
|
|
||||||
## Standards
|
## Standards
|
||||||
|
|
||||||
Contributions to Open MCT are expected to meet the following standards.
|
Contributions to Open MCT are expected to meet the following standards.
|
||||||
@ -292,6 +301,7 @@ checklist).
|
|||||||
2. Unit tests included and/or updated with changes?
|
2. Unit tests included and/or updated with changes?
|
||||||
3. Command line build passes?
|
3. Command line build passes?
|
||||||
4. Changes have been smoke-tested?
|
4. Changes have been smoke-tested?
|
||||||
|
5. Testing instructions included?
|
||||||
|
|
||||||
### Reviewer Checklist
|
### Reviewer Checklist
|
||||||
|
|
||||||
@ -299,3 +309,4 @@ checklist).
|
|||||||
2. Appropriate unit tests included?
|
2. Appropriate unit tests included?
|
||||||
3. Code style and in-line documentation are appropriate?
|
3. Code style and in-line documentation are appropriate?
|
||||||
4. Commit messages meet standards?
|
4. Commit messages meet standards?
|
||||||
|
5. Has associated issue been labelled `unverified`? (only applicable if this PR closes the issue)
|
||||||
|
@ -50,7 +50,8 @@ define([
|
|||||||
values: [
|
values: [
|
||||||
{
|
{
|
||||||
key: "name",
|
key: "name",
|
||||||
name: "Name"
|
name: "Name",
|
||||||
|
format: "string"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "utc",
|
key: "utc",
|
||||||
|
@ -55,9 +55,9 @@
|
|||||||
"marked": "^0.3.5",
|
"marked": "^0.3.5",
|
||||||
"mini-css-extract-plugin": "^0.4.1",
|
"mini-css-extract-plugin": "^0.4.1",
|
||||||
"minimist": "^1.1.1",
|
"minimist": "^1.1.1",
|
||||||
"moment": "^2.25.3",
|
"moment": "2.25.3",
|
||||||
"moment-duration-format": "^2.2.2",
|
"moment-duration-format": "^2.2.2",
|
||||||
"moment-timezone": "^0.5.21",
|
"moment-timezone": "0.5.28",
|
||||||
"node-bourbon": "^4.2.3",
|
"node-bourbon": "^4.2.3",
|
||||||
"node-sass": "^4.9.2",
|
"node-sass": "^4.9.2",
|
||||||
"painterro": "^0.2.65",
|
"painterro": "^0.2.65",
|
||||||
|
39
src/plugins/LADTable/LADTableCompositionPolicy.js
Normal file
39
src/plugins/LADTable/LADTableCompositionPolicy.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2020, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
export default class LADTableCompositionPolicy {
|
||||||
|
|
||||||
|
constructor(openmct) {
|
||||||
|
this.openmct = openmct;
|
||||||
|
return this.allow.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
allow(parent, child) {
|
||||||
|
if(parent.type === 'LadTable') {
|
||||||
|
return this.openmct.telemetry.isTelemetryObject(child);
|
||||||
|
} else if(parent.type === 'LadTableSet') {
|
||||||
|
return child.type === 'LadTable';
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -19,53 +19,46 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
import LadTableSet from './components/LadTableSet.vue';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
define([
|
export default function LADTableSetViewProvider(openmct) {
|
||||||
'./components/LadTableSet.vue',
|
return {
|
||||||
'vue'
|
key: 'LadTableSet',
|
||||||
], function (
|
name: 'LAD Table Set',
|
||||||
LadTableSet,
|
cssClass: 'icon-tabular-lad-set',
|
||||||
Vue
|
canView: function (domainObject) {
|
||||||
) {
|
return domainObject.type === 'LadTableSet';
|
||||||
function LADTableSetViewProvider(openmct) {
|
},
|
||||||
return {
|
canEdit: function (domainObject) {
|
||||||
key: 'LadTableSet',
|
return domainObject.type === 'LadTableSet';
|
||||||
name: 'LAD Table Set',
|
},
|
||||||
cssClass: 'icon-tabular-lad-set',
|
view: function (domainObject, objectPath) {
|
||||||
canView: function (domainObject) {
|
let component;
|
||||||
return domainObject.type === 'LadTableSet';
|
|
||||||
},
|
|
||||||
canEdit: function (domainObject) {
|
|
||||||
return domainObject.type === 'LadTableSet';
|
|
||||||
},
|
|
||||||
view: function (domainObject, objectPath) {
|
|
||||||
let component;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
show: function (element) {
|
show: function (element) {
|
||||||
component = new Vue({
|
component = new Vue({
|
||||||
el: element,
|
el: element,
|
||||||
components: {
|
components: {
|
||||||
LadTableSet: LadTableSet.default
|
LadTableSet: LadTableSet
|
||||||
},
|
},
|
||||||
provide: {
|
provide: {
|
||||||
openmct,
|
openmct,
|
||||||
domainObject,
|
domainObject,
|
||||||
objectPath
|
objectPath
|
||||||
},
|
},
|
||||||
template: '<lad-table-set></lad-table-set>'
|
template: '<lad-table-set></lad-table-set>'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
destroy: function (element) {
|
destroy: function (element) {
|
||||||
component.$destroy();
|
component.$destroy();
|
||||||
component = undefined;
|
component = undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
priority: function () {
|
priority: function () {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return LADTableSetViewProvider;
|
|
||||||
});
|
|
||||||
|
@ -19,53 +19,46 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
import LadTable from './components/LADTable.vue';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
define([
|
export default function LADTableViewProvider(openmct) {
|
||||||
'./components/LADTable.vue',
|
return {
|
||||||
'vue'
|
key: 'LadTable',
|
||||||
], function (
|
name: 'LAD Table',
|
||||||
LadTableComponent,
|
cssClass: 'icon-tabular-lad',
|
||||||
Vue
|
canView: function (domainObject) {
|
||||||
) {
|
return domainObject.type === 'LadTable';
|
||||||
function LADTableViewProvider(openmct) {
|
},
|
||||||
return {
|
canEdit: function (domainObject) {
|
||||||
key: 'LadTable',
|
return domainObject.type === 'LadTable';
|
||||||
name: 'LAD Table',
|
},
|
||||||
cssClass: 'icon-tabular-lad',
|
view: function (domainObject, objectPath) {
|
||||||
canView: function (domainObject) {
|
let component;
|
||||||
return domainObject.type === 'LadTable';
|
|
||||||
},
|
|
||||||
canEdit: function (domainObject) {
|
|
||||||
return domainObject.type === 'LadTable';
|
|
||||||
},
|
|
||||||
view: function (domainObject, objectPath) {
|
|
||||||
let component;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
show: function (element) {
|
show: function (element) {
|
||||||
component = new Vue({
|
component = new Vue({
|
||||||
el: element,
|
el: element,
|
||||||
components: {
|
components: {
|
||||||
LadTableComponent: LadTableComponent.default
|
LadTableComponent: LadTable
|
||||||
},
|
},
|
||||||
provide: {
|
provide: {
|
||||||
openmct,
|
openmct,
|
||||||
domainObject,
|
domainObject,
|
||||||
objectPath
|
objectPath
|
||||||
},
|
},
|
||||||
template: '<lad-table-component></lad-table-component>'
|
template: '<lad-table-component></lad-table-component>'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
destroy: function (element) {
|
destroy: function (element) {
|
||||||
component.$destroy();
|
component.$destroy();
|
||||||
component = undefined;
|
component = undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
priority: function () {
|
priority: function () {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return LADTableViewProvider;
|
|
||||||
});
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -24,10 +24,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<tr @contextmenu.prevent="showContextMenu">
|
<tr @contextmenu.prevent="showContextMenu">
|
||||||
<td>{{ name }}</td>
|
<td>{{ name }}</td>
|
||||||
<td>{{ timestamp }}</td>
|
<td>{{ formattedTimestamp }}</td>
|
||||||
<td :class="valueClass">
|
<td :class="valueClass">{{ value }}</td>
|
||||||
{{ value }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -58,10 +56,16 @@ export default {
|
|||||||
currentObjectPath
|
currentObjectPath
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
formattedTimestamp() {
|
||||||
|
return this.timestamp !== '---' ? this.formats[this.timestampKey].format(this.timestamp) : this.timestamp;
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
||||||
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
|
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
|
||||||
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||||
|
this.bounds = this.openmct.time.bounds();
|
||||||
|
|
||||||
this.limitEvaluator = this.openmct
|
this.limitEvaluator = this.openmct
|
||||||
.telemetry
|
.telemetry
|
||||||
@ -76,6 +80,7 @@ export default {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.openmct.time.on('timeSystem', this.updateTimeSystem);
|
this.openmct.time.on('timeSystem', this.updateTimeSystem);
|
||||||
|
this.openmct.time.on('bounds', this.updateBounds);
|
||||||
|
|
||||||
this.timestampKey = this.openmct.time.timeSystem().key;
|
this.timestampKey = this.openmct.time.timeSystem().key;
|
||||||
|
|
||||||
@ -89,43 +94,64 @@ export default {
|
|||||||
.telemetry
|
.telemetry
|
||||||
.subscribe(this.domainObject, this.updateValues);
|
.subscribe(this.domainObject, this.updateValues);
|
||||||
|
|
||||||
this.openmct
|
this.requestHistory();
|
||||||
.telemetry
|
|
||||||
.request(this.domainObject, {strategy: 'latest'})
|
|
||||||
.then((array) => this.updateValues(array[array.length - 1]));
|
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.stopWatchingMutation();
|
this.stopWatchingMutation();
|
||||||
this.unsubscribe();
|
this.unsubscribe();
|
||||||
this.openmct.off('timeSystem', this.updateTimeSystem);
|
this.openmct.time.off('timeSystem', this.updateTimeSystem);
|
||||||
|
this.openmct.time.off('bounds', this.updateBounds);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateValues(datum) {
|
updateValues(datum) {
|
||||||
this.timestamp = this.formats[this.timestampKey].format(datum);
|
let newTimestamp = this.formats[this.timestampKey].parse(datum),
|
||||||
this.value = this.formats[this.valueKey].format(datum);
|
shouldUpdate = this.timestamp === '---' || newTimestamp >= this.timestamp,
|
||||||
|
limit;
|
||||||
|
|
||||||
var limit = this.limitEvaluator.evaluate(datum, this.valueMetadata);
|
if(!this.inBounds(newTimestamp)) {
|
||||||
|
return;
|
||||||
if (limit) {
|
|
||||||
this.valueClass = limit.cssClass;
|
|
||||||
} else {
|
|
||||||
this.valueClass = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(shouldUpdate) {
|
||||||
|
this.timestamp = this.formats[this.timestampKey].parse(datum);
|
||||||
|
this.value = this.formats[this.valueKey].format(datum);
|
||||||
|
limit = this.limitEvaluator.evaluate(datum, this.valueMetadata);
|
||||||
|
|
||||||
|
if (limit) {
|
||||||
|
this.valueClass = limit.cssClass;
|
||||||
|
} else {
|
||||||
|
this.valueClass = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
requestHistory() {
|
||||||
|
this.timestamp = '---';
|
||||||
|
this.openmct
|
||||||
|
.telemetry
|
||||||
|
.request(this.domainObject, {
|
||||||
|
start: this.bounds.start,
|
||||||
|
end: this.bounds.end,
|
||||||
|
strategy: 'latest'
|
||||||
|
})
|
||||||
|
.then((data) => this.updateValues(data[data.length - 1]));
|
||||||
},
|
},
|
||||||
updateName(name) {
|
updateName(name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
},
|
},
|
||||||
|
updateBounds(bounds, isTick) {
|
||||||
|
this.bounds = bounds;
|
||||||
|
if(!isTick) {
|
||||||
|
this.requestHistory();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
inBounds(timestamp) {
|
||||||
|
return timestamp >= this.bounds.start && timestamp <= this.bounds.end;
|
||||||
|
},
|
||||||
updateTimeSystem(timeSystem) {
|
updateTimeSystem(timeSystem) {
|
||||||
this.value = '---';
|
this.value = '---';
|
||||||
this.timestamp = '---';
|
this.timestamp = '---';
|
||||||
this.valueClass = '';
|
this.valueClass = '';
|
||||||
this.timestampKey = timeSystem.key;
|
this.timestampKey = timeSystem.key;
|
||||||
|
|
||||||
this.openmct
|
|
||||||
.telemetry
|
|
||||||
.request(this.domainObject, {strategy: 'latest'})
|
|
||||||
.then((array) => this.updateValues(array[array.length - 1]));
|
|
||||||
|
|
||||||
},
|
},
|
||||||
showContextMenu(event) {
|
showContextMenu(event) {
|
||||||
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
|
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
|
||||||
|
@ -88,4 +88,3 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -19,38 +19,36 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
import LADTableViewProvider from './LADTableViewProvider';
|
||||||
|
import LADTableSetViewProvider from './LADTableSetViewProvider';
|
||||||
|
import LADTableCompositionPolicy from './LADTableCompositionPolicy';
|
||||||
|
|
||||||
define([
|
export default function plugin() {
|
||||||
'./LADTableViewProvider',
|
return function install(openmct) {
|
||||||
'./LADTableSetViewProvider'
|
|
||||||
], function (
|
|
||||||
LADTableViewProvider,
|
|
||||||
LADTableSetViewProvider
|
|
||||||
) {
|
|
||||||
return function plugin() {
|
|
||||||
return function install(openmct) {
|
|
||||||
openmct.objectViews.addProvider(new LADTableViewProvider(openmct));
|
|
||||||
openmct.objectViews.addProvider(new LADTableSetViewProvider(openmct));
|
|
||||||
|
|
||||||
openmct.types.addType('LadTable', {
|
openmct.objectViews.addProvider(new LADTableViewProvider(openmct));
|
||||||
name: "LAD Table",
|
openmct.objectViews.addProvider(new LADTableSetViewProvider(openmct));
|
||||||
creatable: true,
|
|
||||||
description: "A Latest Available Data tabular view in which each row displays the values for one or more contained telemetry objects.",
|
|
||||||
cssClass: 'icon-tabular-lad',
|
|
||||||
initialize(domainObject) {
|
|
||||||
domainObject.composition = [];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
openmct.types.addType('LadTableSet', {
|
openmct.types.addType('LadTable', {
|
||||||
name: "LAD Table Set",
|
name: "LAD Table",
|
||||||
creatable: true,
|
creatable: true,
|
||||||
description: "A Latest Available Data tabular view in which each row displays the values for one or more contained telemetry objects.",
|
description: "A Latest Available Data tabular view in which each row displays the values for one or more contained telemetry objects.",
|
||||||
cssClass: 'icon-tabular-lad-set',
|
cssClass: 'icon-tabular-lad',
|
||||||
initialize(domainObject) {
|
initialize(domainObject) {
|
||||||
domainObject.composition = [];
|
domainObject.composition = [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
openmct.types.addType('LadTableSet', {
|
||||||
|
name: "LAD Table Set",
|
||||||
|
creatable: true,
|
||||||
|
description: "A Latest Available Data tabular view in which each row displays the values for one or more contained telemetry objects.",
|
||||||
|
cssClass: 'icon-tabular-lad-set',
|
||||||
|
initialize(domainObject) {
|
||||||
|
domainObject.composition = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
openmct.composition.addPolicy(new LADTableCompositionPolicy(openmct));
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
356
src/plugins/LADTable/pluginSpec.js
Normal file
356
src/plugins/LADTable/pluginSpec.js
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, 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 LadPlugin from './plugin.js';
|
||||||
|
import Vue from 'vue';
|
||||||
|
import {
|
||||||
|
createOpenMct,
|
||||||
|
getMockObjects,
|
||||||
|
getMockTelemetry,
|
||||||
|
getLatestTelemetry
|
||||||
|
} from 'testTools';
|
||||||
|
|
||||||
|
let openmct,
|
||||||
|
ladPlugin,
|
||||||
|
parent,
|
||||||
|
child;
|
||||||
|
|
||||||
|
let selectors = {};
|
||||||
|
selectors.ladTableClass = '.c-table.c-lad-table';
|
||||||
|
selectors.ladTableBodyRows = selectors.ladTableClass + ' tbody tr';
|
||||||
|
selectors.ladTableBodyRowsFirstData = selectors.ladTableBodyRows + ' td:first-child';
|
||||||
|
selectors.ladTableBodyRowsSecondtData = selectors.ladTableBodyRows + ' td:nth-child(2)';
|
||||||
|
selectors.ladTableBodyRowsThirdData = selectors.ladTableBodyRows + ' td:nth-child(3)';
|
||||||
|
selectors.ladTableFirstBodyRow = selectors.ladTableClass + ' tbody tr:first-child';
|
||||||
|
selectors.ladTableFirstRowFirstData = selectors.ladTableBodyRows + ' td:first-child';
|
||||||
|
selectors.ladTableFirstRowSecondData = selectors.ladTableBodyRows + ' td:nth-child(2)';
|
||||||
|
selectors.ladTableFirstRowThirdData = selectors.ladTableBodyRows + ' td:nth-child(3)';
|
||||||
|
|
||||||
|
selectors.ladTableSetTableHeaders = selectors.ladTableClass + ' .c-table__group-header';
|
||||||
|
|
||||||
|
function utcTimeFormat(value) {
|
||||||
|
return new Date(value).toISOString().replace('T', ' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("The LAD Table", () => {
|
||||||
|
|
||||||
|
const ladTableKey = 'LadTable';
|
||||||
|
let telemetryCount = 3,
|
||||||
|
timeFormat = 'utc',
|
||||||
|
mockTelemetry = getMockTelemetry({ count: telemetryCount, format: timeFormat }),
|
||||||
|
mockObj = getMockObjects({
|
||||||
|
objectKeyStrings: ['ladTable', 'telemetry'],
|
||||||
|
format: timeFormat
|
||||||
|
}),
|
||||||
|
bounds = {
|
||||||
|
start: 0,
|
||||||
|
end: 4
|
||||||
|
};
|
||||||
|
|
||||||
|
// add telemetry object as composition in lad table
|
||||||
|
mockObj.ladTable.composition.push(mockObj.telemetry.identifier);
|
||||||
|
|
||||||
|
// this setups up the app
|
||||||
|
beforeEach((done) => {
|
||||||
|
const appHolder = document.createElement('div');
|
||||||
|
appHolder.style.width = '640px';
|
||||||
|
appHolder.style.height = '480px';
|
||||||
|
|
||||||
|
openmct = createOpenMct();
|
||||||
|
|
||||||
|
parent = document.createElement('div');
|
||||||
|
child = document.createElement('div');
|
||||||
|
parent.appendChild(child);
|
||||||
|
|
||||||
|
spyOn(openmct.telemetry, 'request').and.returnValue(Promise.resolve([]));
|
||||||
|
|
||||||
|
ladPlugin = new LadPlugin();
|
||||||
|
openmct.install(ladPlugin);
|
||||||
|
|
||||||
|
spyOn(openmct.objects, 'get').and.returnValue(Promise.resolve({}));
|
||||||
|
|
||||||
|
openmct.time.bounds({ start: bounds.start, end: bounds.end });
|
||||||
|
|
||||||
|
openmct.on('start', done);
|
||||||
|
openmct.start(appHolder);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should provide a table view only for lad table objects", () => {
|
||||||
|
let applicableViews = openmct.objectViews.get(mockObj.ladTable),
|
||||||
|
ladTableView = applicableViews.find(
|
||||||
|
(viewProvider) => viewProvider.key === ladTableKey
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(applicableViews.length).toEqual(1);
|
||||||
|
expect(ladTableView).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('composition', () => {
|
||||||
|
let ladTableCompositionCollection;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ladTableCompositionCollection = openmct.composition.get(mockObj.ladTable);
|
||||||
|
ladTableCompositionCollection.load();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should accept telemetry producing objects", () => {
|
||||||
|
expect(() => {
|
||||||
|
ladTableCompositionCollection.add(mockObj.telemetry);
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should reject non-telemtry producing objects", () => {
|
||||||
|
expect(()=> {
|
||||||
|
ladTableCompositionCollection.add(mockObj.ladTable);
|
||||||
|
}).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("table view", () => {
|
||||||
|
let applicableViews,
|
||||||
|
ladTableViewProvider,
|
||||||
|
ladTableView,
|
||||||
|
anotherTelemetryObj = getMockObjects({
|
||||||
|
objectKeyStrings: ['telemetry'],
|
||||||
|
overwrite: {
|
||||||
|
telemetry: {
|
||||||
|
name: "New Telemetry Object",
|
||||||
|
identifier: { namespace: "", key: "another-telemetry-object" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).telemetry;
|
||||||
|
|
||||||
|
// add another telemetry object as composition in lad table to test multi rows
|
||||||
|
mockObj.ladTable.composition.push(anotherTelemetryObj.identifier);
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
let telemetryRequestResolve,
|
||||||
|
telemetryObjectResolve,
|
||||||
|
anotherTelemetryObjectResolve;
|
||||||
|
let telemetryRequestPromise = new Promise((resolve) => {
|
||||||
|
telemetryRequestResolve = resolve;
|
||||||
|
}),
|
||||||
|
telemetryObjectPromise = new Promise((resolve) => {
|
||||||
|
telemetryObjectResolve = resolve;
|
||||||
|
}),
|
||||||
|
anotherTelemetryObjectPromise = new Promise((resolve) => {
|
||||||
|
anotherTelemetryObjectResolve = resolve;
|
||||||
|
})
|
||||||
|
openmct.telemetry.request.and.callFake(() => {
|
||||||
|
telemetryRequestResolve(mockTelemetry);
|
||||||
|
return telemetryRequestPromise;
|
||||||
|
});
|
||||||
|
openmct.objects.get.and.callFake((obj) => {
|
||||||
|
if(obj.key === 'telemetry-object') {
|
||||||
|
telemetryObjectResolve(mockObj.telemetry);
|
||||||
|
return telemetryObjectPromise;
|
||||||
|
} else {
|
||||||
|
anotherTelemetryObjectResolve(anotherTelemetryObj);
|
||||||
|
return anotherTelemetryObjectPromise;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
openmct.time.bounds({ start: bounds.start, end: bounds.end });
|
||||||
|
|
||||||
|
applicableViews = openmct.objectViews.get(mockObj.ladTable);
|
||||||
|
ladTableViewProvider = applicableViews.find((viewProvider) => viewProvider.key === ladTableKey);
|
||||||
|
ladTableView = ladTableViewProvider.view(mockObj.ladTable, [mockObj.ladTable]);
|
||||||
|
ladTableView.show(child, true);
|
||||||
|
|
||||||
|
await Promise.all([telemetryRequestPromise, telemetryObjectPromise, anotherTelemetryObjectPromise]);
|
||||||
|
return await Vue.nextTick();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show one row per object in the composition", () => {
|
||||||
|
const rowCount = parent.querySelectorAll(selectors.ladTableBodyRows).length;
|
||||||
|
expect(rowCount).toBe(mockObj.ladTable.composition.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the most recent datum from the telemetry producing object", async () => {
|
||||||
|
const latestDatum = getLatestTelemetry(mockTelemetry, { timeFormat });
|
||||||
|
const expectedDate = utcTimeFormat(latestDatum[timeFormat]);
|
||||||
|
await Vue.nextTick();
|
||||||
|
const latestDate = parent.querySelector(selectors.ladTableFirstRowSecondData).innerText;
|
||||||
|
expect(latestDate).toBe(expectedDate);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the name provided for the the telemetry producing object", () => {
|
||||||
|
const rowName = parent.querySelector(selectors.ladTableFirstRowFirstData).innerText,
|
||||||
|
expectedName = mockObj.telemetry.name;
|
||||||
|
expect(rowName).toBe(expectedName);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the correct values for the datum based on domain and range hints", async () => {
|
||||||
|
const range = mockObj.telemetry.telemetry.values.find((val) => {
|
||||||
|
return val.hints && val.hints.range !== undefined;
|
||||||
|
}).key;
|
||||||
|
const domain = mockObj.telemetry.telemetry.values.find((val) => {
|
||||||
|
return val.hints && val.hints.domain !== undefined;
|
||||||
|
}).key;
|
||||||
|
const mostRecentTelemetry = getLatestTelemetry(mockTelemetry, { timeFormat });
|
||||||
|
const rangeValue = mostRecentTelemetry[range];
|
||||||
|
const domainValue = utcTimeFormat(mostRecentTelemetry[domain]);
|
||||||
|
await Vue.nextTick();
|
||||||
|
const actualDomainValue = parent.querySelector(selectors.ladTableFirstRowSecondData).innerText;
|
||||||
|
const actualRangeValue = parent.querySelector(selectors.ladTableFirstRowThirdData).innerText;
|
||||||
|
expect(actualRangeValue).toBe(rangeValue);
|
||||||
|
expect(actualDomainValue).toBe(domainValue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("The LAD Table Set", () => {
|
||||||
|
const ladTableSetKey = 'LadTableSet';
|
||||||
|
let telemetryCount = 3,
|
||||||
|
timeFormat = 'utc',
|
||||||
|
mockTelemetry = getMockTelemetry({ count: telemetryCount, format: timeFormat }),
|
||||||
|
mockObj = getMockObjects({
|
||||||
|
objectKeyStrings: ['ladTable', 'ladTableSet', 'telemetry']
|
||||||
|
}),
|
||||||
|
bounds = {
|
||||||
|
start: 0,
|
||||||
|
end: 4
|
||||||
|
};
|
||||||
|
// add mock telemetry to lad table and lad table to lad table set (composition)
|
||||||
|
mockObj.ladTable.composition.push(mockObj.telemetry.identifier);
|
||||||
|
mockObj.ladTableSet.composition.push(mockObj.ladTable.identifier);
|
||||||
|
|
||||||
|
beforeEach((done) => {
|
||||||
|
const appHolder = document.createElement('div');
|
||||||
|
appHolder.style.width = '640px';
|
||||||
|
appHolder.style.height = '480px';
|
||||||
|
|
||||||
|
openmct = createOpenMct();
|
||||||
|
|
||||||
|
parent = document.createElement('div');
|
||||||
|
child = document.createElement('div');
|
||||||
|
parent.appendChild(child);
|
||||||
|
|
||||||
|
spyOn(openmct.telemetry, 'request').and.returnValue(Promise.resolve([]));
|
||||||
|
|
||||||
|
ladPlugin = new LadPlugin();
|
||||||
|
openmct.install(ladPlugin);
|
||||||
|
|
||||||
|
spyOn(openmct.objects, 'get').and.returnValue(Promise.resolve({}));
|
||||||
|
|
||||||
|
openmct.time.bounds({ start: bounds.start, end: bounds.end });
|
||||||
|
|
||||||
|
openmct.on('start', done);
|
||||||
|
openmct.start(appHolder);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should provide a lad table set view only for lad table set objects", () => {
|
||||||
|
let applicableViews = openmct.objectViews.get(mockObj.ladTableSet),
|
||||||
|
ladTableSetView = applicableViews.find(
|
||||||
|
(viewProvider) => viewProvider.key === ladTableSetKey
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(applicableViews.length).toEqual(1);
|
||||||
|
expect(ladTableSetView).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('composition', () => {
|
||||||
|
let ladTableSetCompositionCollection;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ladTableSetCompositionCollection = openmct.composition.get(mockObj.ladTableSet);
|
||||||
|
ladTableSetCompositionCollection.load();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should accept lad table objects", () => {
|
||||||
|
expect(() => {
|
||||||
|
ladTableSetCompositionCollection.add(mockObj.ladTable);
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should reject non lad table objects", () => {
|
||||||
|
expect(()=> {
|
||||||
|
ladTableSetCompositionCollection.add(mockObj.telemetry);
|
||||||
|
}).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("table view", () => {
|
||||||
|
let applicableViews,
|
||||||
|
ladTableSetViewProvider,
|
||||||
|
ladTableSetView,
|
||||||
|
otherObj = getMockObjects({
|
||||||
|
objectKeyStrings: ['ladTable'],
|
||||||
|
overwrite: {
|
||||||
|
ladTable: {
|
||||||
|
name: "New LAD Table Object",
|
||||||
|
identifier: { namespace: "", key: "another-lad-object" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// add another lad table (with telemetry object) object to the lad table set for multi row test
|
||||||
|
otherObj.ladTable.composition.push(mockObj.telemetry.identifier);
|
||||||
|
mockObj.ladTableSet.composition.push(otherObj.ladTable.identifier);
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
let telemetryRequestResolve,
|
||||||
|
ladObjectResolve,
|
||||||
|
anotherLadObjectResolve;
|
||||||
|
let telemetryRequestPromise = new Promise((resolve) => {
|
||||||
|
telemetryRequestResolve = resolve;
|
||||||
|
}),
|
||||||
|
ladObjectPromise = new Promise((resolve) => {
|
||||||
|
ladObjectResolve = resolve;
|
||||||
|
}),
|
||||||
|
anotherLadObjectPromise = new Promise((resolve) => {
|
||||||
|
anotherLadObjectResolve = resolve;
|
||||||
|
})
|
||||||
|
openmct.telemetry.request.and.callFake(() => {
|
||||||
|
telemetryRequestResolve(mockTelemetry);
|
||||||
|
return telemetryRequestPromise;
|
||||||
|
});
|
||||||
|
openmct.objects.get.and.callFake((obj) => {
|
||||||
|
if(obj.key === 'lad-object') {
|
||||||
|
ladObjectResolve(mockObj.ladObject);
|
||||||
|
return ladObjectPromise;
|
||||||
|
} else if(obj.key === 'another-lad-object') {
|
||||||
|
anotherLadObjectResolve(otherObj.ladObject);
|
||||||
|
return anotherLadObjectPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve({});
|
||||||
|
});
|
||||||
|
|
||||||
|
openmct.time.bounds({ start: bounds.start, end: bounds.end });
|
||||||
|
|
||||||
|
applicableViews = openmct.objectViews.get(mockObj.ladTableSet);
|
||||||
|
ladTableSetViewProvider = applicableViews.find((viewProvider) => viewProvider.key === ladTableSetKey);
|
||||||
|
ladTableSetView = ladTableSetViewProvider.view(mockObj.ladTableSet, [mockObj.ladTableSet]);
|
||||||
|
ladTableSetView.show(child, true);
|
||||||
|
|
||||||
|
await Promise.all([telemetryRequestPromise, ladObjectPromise, anotherLadObjectPromise]);
|
||||||
|
return await Vue.nextTick();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show one row per lad table object in the composition", () => {
|
||||||
|
const rowCount = parent.querySelectorAll(selectors.ladTableSetTableHeaders).length;
|
||||||
|
expect(rowCount).toBe(mockObj.ladTableSet.composition.length);
|
||||||
|
pending();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -69,15 +69,19 @@ export default class ConditionClass extends EventEmitter {
|
|||||||
console.log('no data received');
|
console.log('no data received');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.criteria.forEach(criterion => {
|
|
||||||
if (this.isAnyOrAllTelemetry(criterion)) {
|
|
||||||
criterion.getResult(datum, this.conditionManager.telemetryObjects);
|
|
||||||
} else {
|
|
||||||
criterion.getResult(datum);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.result = evaluateResults(this.criteria.map(criterion => criterion.result), this.trigger);
|
if (this.isTelemetryUsed(datum.id)) {
|
||||||
|
|
||||||
|
this.criteria.forEach(criterion => {
|
||||||
|
if (this.isAnyOrAllTelemetry(criterion)) {
|
||||||
|
criterion.getResult(datum, this.conditionManager.telemetryObjects);
|
||||||
|
} else {
|
||||||
|
criterion.getResult(datum);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.result = evaluateResults(this.criteria.map(criterion => criterion.result), this.trigger);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isAnyOrAllTelemetry(criterion) {
|
isAnyOrAllTelemetry(criterion) {
|
||||||
|
@ -47,17 +47,24 @@ describe("The condition", function () {
|
|||||||
name: "Test Object",
|
name: "Test Object",
|
||||||
telemetry: {
|
telemetry: {
|
||||||
values: [{
|
values: [{
|
||||||
key: "some-key",
|
key: "value",
|
||||||
name: "Some attribute",
|
name: "Value",
|
||||||
|
hints: {
|
||||||
|
range: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "utc",
|
||||||
|
name: "Time",
|
||||||
|
format: "utc",
|
||||||
hints: {
|
hints: {
|
||||||
domain: 1
|
domain: 1
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "some-other-key",
|
key: "testSource",
|
||||||
name: "Another attribute",
|
source: "value",
|
||||||
hints: {
|
name: "Test",
|
||||||
range: 1
|
format: "string"
|
||||||
}
|
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -136,4 +143,38 @@ describe("The condition", function () {
|
|||||||
expect(result).toBeTrue();
|
expect(result).toBeTrue();
|
||||||
expect(conditionObj.criteria.length).toEqual(0);
|
expect(conditionObj.criteria.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("gets the result of a condition when new telemetry data is received", function () {
|
||||||
|
conditionObj.getResult({
|
||||||
|
value: '0',
|
||||||
|
utc: 'Hi',
|
||||||
|
id: testTelemetryObject.identifier.key
|
||||||
|
});
|
||||||
|
expect(conditionObj.result).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("gets the result of a condition when new telemetry data is received", function () {
|
||||||
|
conditionObj.getResult({
|
||||||
|
value: '1',
|
||||||
|
utc: 'Hi',
|
||||||
|
id: testTelemetryObject.identifier.key
|
||||||
|
});
|
||||||
|
expect(conditionObj.result).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps the old result new telemetry data is not used by it", function () {
|
||||||
|
conditionObj.getResult({
|
||||||
|
value: '0',
|
||||||
|
utc: 'Hi',
|
||||||
|
id: testTelemetryObject.identifier.key
|
||||||
|
});
|
||||||
|
expect(conditionObj.result).toBeTrue();
|
||||||
|
|
||||||
|
conditionObj.getResult({
|
||||||
|
value: '1',
|
||||||
|
utc: 'Hi',
|
||||||
|
id: '1234'
|
||||||
|
});
|
||||||
|
expect(conditionObj.result).toBeTrue();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -157,7 +157,6 @@ export default class StyleRuleManager extends EventEmitter {
|
|||||||
delete this.stopProvidingTelemetry;
|
delete this.stopProvidingTelemetry;
|
||||||
this.conditionSetIdentifier = undefined;
|
this.conditionSetIdentifier = undefined;
|
||||||
this.isEditing = undefined;
|
this.isEditing = undefined;
|
||||||
this.callback = undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
>
|
>
|
||||||
<div class="c-condition-h__drop-target"></div>
|
<div class="c-condition-h__drop-target"></div>
|
||||||
<div v-if="isEditing"
|
<div v-if="isEditing"
|
||||||
|
:class="{'is-current': condition.id === currentConditionId}"
|
||||||
class="c-condition c-condition--edit"
|
class="c-condition c-condition--edit"
|
||||||
>
|
>
|
||||||
<!-- Edit view -->
|
<!-- Edit view -->
|
||||||
@ -167,6 +168,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-else
|
<div v-else
|
||||||
class="c-condition c-condition--browse"
|
class="c-condition c-condition--browse"
|
||||||
|
:class="{'is-current': condition.id === currentConditionId}"
|
||||||
>
|
>
|
||||||
<!-- Browse view -->
|
<!-- Browse view -->
|
||||||
<div class="c-condition__header">
|
<div class="c-condition__header">
|
||||||
@ -199,6 +201,10 @@ export default {
|
|||||||
ConditionDescription
|
ConditionDescription
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
currentConditionId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
condition: {
|
condition: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
<Condition v-for="(condition, index) in conditionCollection"
|
<Condition v-for="(condition, index) in conditionCollection"
|
||||||
:key="condition.id"
|
:key="condition.id"
|
||||||
:condition="condition"
|
:condition="condition"
|
||||||
|
:current-condition-id="currentConditionId"
|
||||||
:condition-index="index"
|
:condition-index="index"
|
||||||
:telemetry="telemetryObjs"
|
:telemetry="telemetryObjs"
|
||||||
:is-editing="isEditing"
|
:is-editing="isEditing"
|
||||||
@ -107,7 +108,8 @@ export default {
|
|||||||
moveIndex: undefined,
|
moveIndex: undefined,
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
defaultOutput: undefined,
|
defaultOutput: undefined,
|
||||||
dragCounter: 0
|
dragCounter: 0,
|
||||||
|
currentConditionId: ''
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -145,6 +147,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleConditionSetResultUpdated(data) {
|
handleConditionSetResultUpdated(data) {
|
||||||
|
this.currentConditionId = data.conditionId;
|
||||||
this.$emit('conditionSetResultUpdated', data)
|
this.$emit('conditionSetResultUpdated', data)
|
||||||
},
|
},
|
||||||
observeForChanges() {
|
observeForChanges() {
|
||||||
|
@ -190,6 +190,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.c-condition {
|
.c-condition {
|
||||||
|
border: 1px solid transparent;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-width: 400px;
|
min-width: 400px;
|
||||||
|
|
||||||
@ -234,6 +235,12 @@
|
|||||||
&__summary {
|
&__summary {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-current {
|
||||||
|
$c: $colorBodyFg;
|
||||||
|
border-color: rgba($c, 0.2);
|
||||||
|
background: rgba($c, 0.2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************** CONDITION DEFINITION, EDITING */
|
/***************************** CONDITION DEFINITION, EDITING */
|
||||||
|
@ -65,7 +65,7 @@
|
|||||||
|
|
||||||
&.is-current {
|
&.is-current {
|
||||||
$c: $colorBodyFg;
|
$c: $colorBodyFg;
|
||||||
border-color: rgba($c, 0.5);
|
border-color: rgba($c, 0.2);
|
||||||
background: rgba($c, 0.2);
|
background: rgba($c, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,6 +172,7 @@ export default {
|
|||||||
&& this.embed.bounds.end !== bounds.end;
|
&& this.embed.bounds.end !== bounds.end;
|
||||||
const isFixedTimespanMode = !this.openmct.time.clock();
|
const isFixedTimespanMode = !this.openmct.time.clock();
|
||||||
|
|
||||||
|
this.openmct.time.stopClock();
|
||||||
window.location.href = link;
|
window.location.href = link;
|
||||||
|
|
||||||
let message = '';
|
let message = '';
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Snapshot from '../snapshot';
|
import Snapshot from '../snapshot';
|
||||||
import { clearDefaultNotebook, getDefaultNotebook } from '../utils/notebook-storage';
|
import { getDefaultNotebook } from '../utils/notebook-storage';
|
||||||
import { NOTEBOOK_DEFAULT, NOTEBOOK_SNAPSHOT } from '../notebook-constants';
|
import { NOTEBOOK_DEFAULT, NOTEBOOK_SNAPSHOT } from '../notebook-constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -72,28 +72,22 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
async setNotebookTypes() {
|
async setNotebookTypes() {
|
||||||
const notebookTypes = [];
|
const notebookTypes = [];
|
||||||
let defaultPath = '';
|
|
||||||
const defaultNotebook = getDefaultNotebook();
|
const defaultNotebook = getDefaultNotebook();
|
||||||
|
|
||||||
if (defaultNotebook) {
|
if (defaultNotebook) {
|
||||||
const domainObject = await this.openmct.objects.get(defaultNotebook.notebookMeta.identifier)
|
const domainObject = defaultNotebook.domainObject;
|
||||||
.then(d => d);
|
|
||||||
|
|
||||||
if (!domainObject.location) {
|
if (domainObject.location) {
|
||||||
clearDefaultNotebook();
|
const defaultPath = `${domainObject.name} - ${defaultNotebook.section.name} - ${defaultNotebook.page.name}`;
|
||||||
} else {
|
|
||||||
defaultPath = `${domainObject.name} - ${defaultNotebook.section.name} - ${defaultNotebook.page.name}`;
|
notebookTypes.push({
|
||||||
|
cssClass: 'icon-notebook',
|
||||||
|
name: `Save to Notebook ${defaultPath}`,
|
||||||
|
type: NOTEBOOK_DEFAULT
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultPath.length !== 0) {
|
|
||||||
notebookTypes.push({
|
|
||||||
cssClass: 'icon-notebook',
|
|
||||||
name: `Save to Notebook ${defaultPath}`,
|
|
||||||
type: NOTEBOOK_DEFAULT
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
notebookTypes.push({
|
notebookTypes.push({
|
||||||
cssClass: 'icon-notebook',
|
cssClass: 'icon-notebook',
|
||||||
name: 'Save to Notebook Snapshots',
|
name: 'Save to Notebook Snapshots',
|
||||||
|
@ -239,6 +239,7 @@ export default {
|
|||||||
const section = this.getSelectedSection();
|
const section = this.getSelectedSection();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
domainObject: this.internalDomainObject,
|
||||||
notebookMeta,
|
notebookMeta,
|
||||||
section,
|
section,
|
||||||
page
|
page
|
||||||
@ -440,7 +441,7 @@ export default {
|
|||||||
async updateDefaultNotebook(notebookStorage) {
|
async updateDefaultNotebook(notebookStorage) {
|
||||||
const defaultNotebookObject = await this.getDefaultNotebookObject();
|
const defaultNotebookObject = await this.getDefaultNotebookObject();
|
||||||
this.removeDefaultClass(defaultNotebookObject);
|
this.removeDefaultClass(defaultNotebookObject);
|
||||||
setDefaultNotebook(notebookStorage);
|
setDefaultNotebook(this.openmct, notebookStorage);
|
||||||
this.addDefaultClass();
|
this.addDefaultClass();
|
||||||
this.defaultSectionId = notebookStorage.section.id;
|
this.defaultSectionId = notebookStorage.section.id;
|
||||||
this.defaultPageId = notebookStorage.page.id;
|
this.defaultPageId = notebookStorage.page.id;
|
||||||
|
@ -1,6 +1,46 @@
|
|||||||
const NOTEBOOK_LOCAL_STORAGE = 'notebook-storage';
|
const NOTEBOOK_LOCAL_STORAGE = 'notebook-storage';
|
||||||
|
let currentNotebookObject = null;
|
||||||
|
let unlisten = null;
|
||||||
|
|
||||||
|
function defaultNotebookObjectChanged(newDomainObject) {
|
||||||
|
if (newDomainObject.location !== null) {
|
||||||
|
currentNotebookObject = newDomainObject;
|
||||||
|
const notebookStorage = getDefaultNotebook();
|
||||||
|
notebookStorage.domainObject = newDomainObject;
|
||||||
|
saveDefaultNotebook(notebookStorage);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlisten) {
|
||||||
|
unlisten();
|
||||||
|
unlisten = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearDefaultNotebook();
|
||||||
|
}
|
||||||
|
|
||||||
|
function observeDefaultNotebookObject(openmct, notebookStorage) {
|
||||||
|
const domainObject = notebookStorage.domainObject;
|
||||||
|
if (currentNotebookObject
|
||||||
|
&& currentNotebookObject.identifier.key === domainObject.identifier.key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlisten) {
|
||||||
|
unlisten();
|
||||||
|
unlisten = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlisten = openmct.objects.observe(notebookStorage.domainObject, '*', defaultNotebookObjectChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveDefaultNotebook(notebookStorage) {
|
||||||
|
window.localStorage.setItem(NOTEBOOK_LOCAL_STORAGE, JSON.stringify(notebookStorage));
|
||||||
|
}
|
||||||
|
|
||||||
export function clearDefaultNotebook() {
|
export function clearDefaultNotebook() {
|
||||||
|
currentNotebookObject = null;
|
||||||
window.localStorage.setItem(NOTEBOOK_LOCAL_STORAGE, null);
|
window.localStorage.setItem(NOTEBOOK_LOCAL_STORAGE, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10,20 +50,21 @@ export function getDefaultNotebook() {
|
|||||||
return JSON.parse(notebookStorage);
|
return JSON.parse(notebookStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setDefaultNotebook(notebookStorage) {
|
export function setDefaultNotebook(openmct, notebookStorage) {
|
||||||
window.localStorage.setItem(NOTEBOOK_LOCAL_STORAGE, JSON.stringify(notebookStorage));
|
observeDefaultNotebookObject(openmct, notebookStorage);
|
||||||
|
saveDefaultNotebook(notebookStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setDefaultNotebookSection(section) {
|
export function setDefaultNotebookSection(section) {
|
||||||
const notebookStorage = getDefaultNotebook();
|
const notebookStorage = getDefaultNotebook();
|
||||||
|
|
||||||
notebookStorage.section = section;
|
notebookStorage.section = section;
|
||||||
window.localStorage.setItem(NOTEBOOK_LOCAL_STORAGE, JSON.stringify(notebookStorage));
|
saveDefaultNotebook(notebookStorage);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setDefaultNotebookPage(page) {
|
export function setDefaultNotebookPage(page) {
|
||||||
const notebookStorage = getDefaultNotebook();
|
const notebookStorage = getDefaultNotebook();
|
||||||
notebookStorage.page = page;
|
notebookStorage.page = page;
|
||||||
window.localStorage.setItem(NOTEBOOK_LOCAL_STORAGE, JSON.stringify(notebookStorage));
|
saveDefaultNotebook(notebookStorage);
|
||||||
}
|
}
|
||||||
|
@ -67,10 +67,10 @@ define([
|
|||||||
}
|
}
|
||||||
this.$canvas = this.$element.find('canvas');
|
this.$canvas = this.$element.find('canvas');
|
||||||
|
|
||||||
this.listenTo(this.$canvas, 'click', this.onMouseClick, this);
|
|
||||||
this.listenTo(this.$canvas, 'mousemove', this.trackMousePosition, this);
|
this.listenTo(this.$canvas, 'mousemove', this.trackMousePosition, this);
|
||||||
this.listenTo(this.$canvas, 'mouseleave', this.untrackMousePosition, this);
|
this.listenTo(this.$canvas, 'mouseleave', this.untrackMousePosition, this);
|
||||||
this.listenTo(this.$canvas, 'mousedown', this.onMouseDown, this);
|
this.listenTo(this.$canvas, 'mousedown', this.onMouseDown, this);
|
||||||
|
this.listenTo(this.$canvas, 'wheel', this.wheelZoom, this);
|
||||||
|
|
||||||
this.watchForMarquee();
|
this.watchForMarquee();
|
||||||
};
|
};
|
||||||
@ -78,7 +78,6 @@ define([
|
|||||||
MCTPlotController.prototype.initialize = function () {
|
MCTPlotController.prototype.initialize = function () {
|
||||||
this.$canvas = this.$element.find('canvas');
|
this.$canvas = this.$element.find('canvas');
|
||||||
|
|
||||||
this.listenTo(this.$canvas, 'click', this.onMouseClick, this);
|
|
||||||
this.listenTo(this.$canvas, 'mousemove', this.trackMousePosition, this);
|
this.listenTo(this.$canvas, 'mousemove', this.trackMousePosition, this);
|
||||||
this.listenTo(this.$canvas, 'mouseleave', this.untrackMousePosition, this);
|
this.listenTo(this.$canvas, 'mouseleave', this.untrackMousePosition, this);
|
||||||
this.listenTo(this.$canvas, 'mousedown', this.onMouseDown, this);
|
this.listenTo(this.$canvas, 'mousedown', this.onMouseDown, this);
|
||||||
@ -210,23 +209,6 @@ define([
|
|||||||
this.highlightValues(point);
|
this.highlightValues(point);
|
||||||
};
|
};
|
||||||
|
|
||||||
MCTPlotController.prototype.onMouseClick = function ($event) {
|
|
||||||
const isClick = this.isMouseClick();
|
|
||||||
if (this.pan) {
|
|
||||||
this.endPan($event);
|
|
||||||
}
|
|
||||||
if (this.marquee) {
|
|
||||||
this.endMarquee($event);
|
|
||||||
}
|
|
||||||
this.$scope.$apply();
|
|
||||||
|
|
||||||
if (!this.$scope.highlights.length || !isClick) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$scope.lockHighlightPoint = !this.$scope.lockHighlightPoint;
|
|
||||||
};
|
|
||||||
|
|
||||||
MCTPlotController.prototype.highlightValues = function (point) {
|
MCTPlotController.prototype.highlightValues = function (point) {
|
||||||
this.highlightPoint = point;
|
this.highlightPoint = point;
|
||||||
this.$scope.$emit('plot:highlight:update', point);
|
this.$scope.$emit('plot:highlight:update', point);
|
||||||
@ -274,11 +256,23 @@ define([
|
|||||||
MCTPlotController.prototype.onMouseUp = function ($event) {
|
MCTPlotController.prototype.onMouseUp = function ($event) {
|
||||||
this.stopListening(this.$window, 'mouseup', this.onMouseUp, this);
|
this.stopListening(this.$window, 'mouseup', this.onMouseUp, this);
|
||||||
this.stopListening(this.$window, 'mousemove', this.trackMousePosition, this);
|
this.stopListening(this.$window, 'mousemove', this.trackMousePosition, this);
|
||||||
|
|
||||||
|
if (this.isMouseClick()) {
|
||||||
|
this.$scope.lockHighlightPoint = !this.$scope.lockHighlightPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.allowPan) {
|
||||||
|
return this.endPan($event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.allowMarquee) {
|
||||||
|
return this.endMarquee($event);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
MCTPlotController.prototype.isMouseClick = function () {
|
MCTPlotController.prototype.isMouseClick = function () {
|
||||||
if (!this.marquee) {
|
if (!this.marquee) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { start, end } = this.marquee;
|
const { start, end } = this.marquee;
|
||||||
@ -331,7 +325,7 @@ define([
|
|||||||
} else {
|
} else {
|
||||||
// A history entry is created by startMarquee, need to remove
|
// A history entry is created by startMarquee, need to remove
|
||||||
// if marquee zoom doesn't occur.
|
// if marquee zoom doesn't occur.
|
||||||
this.back();
|
this.plotHistory.pop();
|
||||||
}
|
}
|
||||||
this.$scope.rectangles = [];
|
this.$scope.rectangles = [];
|
||||||
this.marquee = undefined;
|
this.marquee = undefined;
|
||||||
|
@ -227,8 +227,9 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
PlotController.prototype.stopLoading = function () {
|
PlotController.prototype.stopLoading = function () {
|
||||||
this.$scope.pending -= 1;
|
this.$scope.$evalAsync(() => {
|
||||||
this.$scope.$digest();
|
this.$scope.pending -= 1;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
export default class PlotlyTelemetryProvider {
|
|
||||||
constructor(openmct) {
|
|
||||||
this.openmct = openmct;
|
|
||||||
}
|
|
||||||
|
|
||||||
isTelemetryObject(domainObject) {
|
|
||||||
return domainObject.type === 'plotlyPlot';
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsRequest(domainObject) {
|
|
||||||
return domainObject.type === 'plotlyPlot';
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsSubscribe(domainObject) {
|
|
||||||
return domainObject.type === 'plotlyPlot';
|
|
||||||
}
|
|
||||||
|
|
||||||
request(domainObject) {
|
|
||||||
// let conditionManager = this.getConditionManager(domainObject);
|
|
||||||
|
|
||||||
// return conditionManager.requestLADConditionSetOutput()
|
|
||||||
// .then(latestOutput => {
|
|
||||||
// return latestOutput;
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribe(domainObject, callback) {
|
|
||||||
// let conditionManager = this.getConditionManager(domainObject);
|
|
||||||
|
|
||||||
// conditionManager.on('conditionSetResultUpdated', callback);
|
|
||||||
|
|
||||||
// return this.destroyConditionManager.bind(this, this.openmct.objects.makeKeyString(domainObject.identifier));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -34,7 +34,7 @@ export default function PlotlyViewProvider(openmct) {
|
|||||||
canEdit: function (domainObject) {
|
canEdit: function (domainObject) {
|
||||||
return domainObject.type === 'plotlyPlot';
|
return domainObject.type === 'plotlyPlot';
|
||||||
},
|
},
|
||||||
view: function (domainObject, objectPath) {
|
view: function (domainObject) {
|
||||||
let component;
|
let component;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -42,8 +42,7 @@ export default function PlotlyViewProvider(openmct) {
|
|||||||
component = new Vue({
|
component = new Vue({
|
||||||
provide: {
|
provide: {
|
||||||
openmct,
|
openmct,
|
||||||
domainObject,
|
domainObject
|
||||||
objectPath
|
|
||||||
},
|
},
|
||||||
el: element,
|
el: element,
|
||||||
components: {
|
components: {
|
||||||
|
@ -7,34 +7,89 @@ import Plotly from 'plotly.js-dist';
|
|||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct', 'domainObject', 'objectPath'],
|
inject: ['openmct', 'domainObject'],
|
||||||
data: function () {
|
data: function () {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
telemetryObjects: []
|
telemetryObjects: [],
|
||||||
// currentDomainObject: this.domainObject
|
bounds: this.openmct.time.bounds(),
|
||||||
|
timeRange: 0,
|
||||||
|
plotData: {},
|
||||||
|
subscriptions: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.plotElement = document.querySelector('.l-view-section');
|
||||||
|
|
||||||
this.composition = this.openmct.composition.get(this.domainObject);
|
this.composition = this.openmct.composition.get(this.domainObject);
|
||||||
this.composition.on('add', this.addTelemetry);
|
this.composition.on('add', this.addTelemetry);
|
||||||
|
this.composition.on('remove', this.removeTelemetry);
|
||||||
this.composition.load();
|
this.composition.load();
|
||||||
|
|
||||||
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
this.openmct.time.on('bounds', this.refreshData);
|
||||||
|
this.openmct.time.on('clock', this.changeClock);
|
||||||
console.log('this.metadata', this.metadata);
|
},
|
||||||
|
destroyed() {
|
||||||
// this.keystring = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
this.unsubscribe();
|
||||||
// this.subscribe(this.domainObject);
|
|
||||||
this.plotElement = document.querySelector('.l-view-section');
|
|
||||||
// Plotly.newPlot(this.plotElement, [{
|
|
||||||
// x: [1, 2, 3, 4, 5],
|
|
||||||
// y: [1, 2, 4, 8, 16]
|
|
||||||
// }], this.getLayout(), {displayModeBar: false});
|
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getLayout() {
|
changeClock() {
|
||||||
|
if (this.openmct.time.clock()) {
|
||||||
|
Plotly.purge(this.plotElement);
|
||||||
|
this.telemetryObjects.forEach((telemetryObject, index) => {
|
||||||
|
this.subscribeTo(telemetryObject, index);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addTelemetry(telemetryObject) {
|
||||||
|
this.telemetryObjects.push(telemetryObject);
|
||||||
|
const index = this.telemetryObjects.findIndex(obj => obj === telemetryObject);
|
||||||
|
this.requestHistory(telemetryObject, index, true);
|
||||||
|
this.subscribeTo(telemetryObject, index);
|
||||||
|
},
|
||||||
|
subscribeTo(telemetryObject, index) {
|
||||||
|
let keyString = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||||
|
this.subscriptions[keyString] = this.openmct.telemetry.subscribe(telemetryObject, (datum) => {
|
||||||
|
//Check that telemetry object has not been removed since telemetry was requested.
|
||||||
|
if (!this.telemetryObjects.includes(telemetryObject)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const length = this.plotData[telemetryObject.identifier.key].x.length;
|
||||||
|
this.updateData(datum, index, length);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
unsubscribe(keyString) {
|
||||||
|
this.subscriptions[keyString]();
|
||||||
|
delete this.subscriptions[keyString];
|
||||||
|
},
|
||||||
|
refreshData(bounds, isTick) {
|
||||||
|
this.bounds = bounds;
|
||||||
|
|
||||||
|
this.telemetryObjects.forEach((telemetryObject, index) => {
|
||||||
|
if(!isTick) {
|
||||||
|
this.requestHistory(telemetryObject, index, false);
|
||||||
|
} else {
|
||||||
|
if (this.timeRange === 0 || this.timeRange !== this.bounds.end - this.bounds.start) {
|
||||||
|
this.timeRange = this.bounds.end - this.bounds.start;
|
||||||
|
|
||||||
|
this.requestHistory(telemetryObject, index, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
requestHistory(telemetryObject, index, isAdd) {
|
||||||
|
this.openmct
|
||||||
|
.telemetry
|
||||||
|
.request(telemetryObject, {
|
||||||
|
start: this.bounds.start,
|
||||||
|
end: this.bounds.end
|
||||||
|
})
|
||||||
|
.then((telemetryData) => {
|
||||||
|
this.addTrace(telemetryData, telemetryObject, index, isAdd);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getLayout(telemetryObject, isFixed) {
|
||||||
return {
|
return {
|
||||||
hovermode: 'compare',
|
hovermode: 'compare',
|
||||||
hoverdistance: -1,
|
hoverdistance: -1,
|
||||||
@ -45,93 +100,121 @@ export default {
|
|||||||
size: "12px",
|
size: "12px",
|
||||||
color: "#666"
|
color: "#666"
|
||||||
},
|
},
|
||||||
xaxis: {
|
xaxis: { // hardcoded as UTC for now
|
||||||
// title: this.plotAxisTitle.xAxisTitle,
|
title: 'UTC',
|
||||||
zeroline: false
|
zeroline: false,
|
||||||
|
range: isFixed ? 'undefined' : [
|
||||||
|
this.formatDatumX({utc: this.bounds.start}),
|
||||||
|
this.formatDatumX({utc: this.bounds.start})
|
||||||
|
]
|
||||||
},
|
},
|
||||||
yaxis: {
|
yaxis: {
|
||||||
// title: this.plotAxisTitle.yAxisTitle,
|
title: this.getYAxisLabel(telemetryObject),
|
||||||
zeroline: false
|
zeroline: false
|
||||||
},
|
},
|
||||||
margin: {
|
margin: {
|
||||||
l: 20,
|
l: 40,
|
||||||
r: 10,
|
r: 10,
|
||||||
b: 20,
|
b: 40,
|
||||||
t: 10
|
t: 10
|
||||||
},
|
},
|
||||||
paper_bgcolor: 'transparent',
|
paper_bgcolor: 'transparent',
|
||||||
plot_bgcolor: 'transparent'
|
plot_bgcolor: 'transparent'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTelemetry(telemetryObject) {
|
removeTelemetry(identifier) {
|
||||||
return this.openmct.telemetry.request(telemetryObject)
|
let keyString = this.openmct.objects.makeKeyString(identifier);
|
||||||
.then(telemetryData => {
|
this.unsubscribe(keyString);
|
||||||
this.createPlot(telemetryData, telemetryObject);
|
this.telemetryObjects = this.telemetryObjects.filter((object) => !_.eq(identifier, object.identifier));
|
||||||
}, () => {console.log(error)});
|
if (!this.domainObject.composition.length) {
|
||||||
|
Plotly.purge(this.plotElement);
|
||||||
|
} else {
|
||||||
|
Plotly.deleteTraces(this.plotElement, this.domainObject.composition.length);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getYAxisLabel(telemetryObject) {
|
||||||
|
this.setYAxisProp(telemetryObject);
|
||||||
|
const valueMetadatas = this.openmct.telemetry.getMetadata(telemetryObject).values();
|
||||||
|
const index = valueMetadatas.findIndex(value => value.key === this.yAxisProp);
|
||||||
|
const yLabel = valueMetadatas[index].name;
|
||||||
|
|
||||||
|
return yLabel;
|
||||||
|
},
|
||||||
|
setYAxisProp(telemetryObject) {
|
||||||
|
if (telemetryObject.type === 'generator') {
|
||||||
|
this.yAxisProp = 'sin';
|
||||||
|
} else if (telemetryObject.type === 'example.state-generator') {
|
||||||
|
this.yAxisProp = 'state';
|
||||||
|
} else if (telemetryObject.type === 'conditionSet') {
|
||||||
|
this.yAxisProp = 'output';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
formatDatumX(datum) {
|
formatDatumX(datum) {
|
||||||
let timestamp = moment.utc(datum.utc).format('YYYY-MM-DD hh:mm:ss.ms');
|
let timestamp = moment.utc(datum.utc).format('YYYY-MM-DDTHH:mm:ss[Z]');
|
||||||
return timestamp;
|
return timestamp;
|
||||||
},
|
},
|
||||||
formatDatumY(datum) {
|
formatDatumY(datum) {
|
||||||
return datum.sin;
|
return datum.sin;
|
||||||
},
|
},
|
||||||
createPlot(telemetryData, telemetryObject) {
|
addTrace(telemetryData, telemetryObject, index, isAdd) {
|
||||||
let x = [],
|
let x = [];
|
||||||
y = [];
|
let y = [];
|
||||||
|
|
||||||
telemetryData.forEach((datum, index) => {
|
const colors = ['red', 'green', 'blue'];
|
||||||
|
|
||||||
|
telemetryData.forEach((datum) => {
|
||||||
x.push(this.formatDatumX(datum));
|
x.push(this.formatDatumX(datum));
|
||||||
y.push(this.formatDatumY(datum));
|
y.push(this.formatDatumY(datum));
|
||||||
})
|
})
|
||||||
|
|
||||||
let data = [{
|
let traceData = [{ // trace configuration
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
mode: 'line'
|
type: 'scattergl',
|
||||||
|
mode: 'lines+markers',
|
||||||
|
line: {
|
||||||
|
color: colors[index], // to set new color for each trace
|
||||||
|
shape: 'linear'
|
||||||
|
}
|
||||||
}];
|
}];
|
||||||
var layout = {
|
|
||||||
title:'Line and Scatter Plot'
|
|
||||||
};
|
|
||||||
Plotly.newPlot(
|
|
||||||
this.plotElement,
|
|
||||||
data,
|
|
||||||
this.getLayout()
|
|
||||||
)
|
|
||||||
|
|
||||||
this.subscribe(telemetryObject);
|
this.plotData[telemetryObject.identifier.key] = traceData[0];
|
||||||
|
|
||||||
|
if (!this.plotElement.childNodes.length) { // not traces yet, so create new plot
|
||||||
|
Plotly.newPlot(
|
||||||
|
this.plotElement,
|
||||||
|
traceData,
|
||||||
|
this.getLayout(telemetryObject, true),
|
||||||
|
{
|
||||||
|
displayModeBar: false, // turns off hover-activated toolbar
|
||||||
|
staticPlot: true // turns off hover effects on datapoints
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (isAdd) { // add a new trace to existing plot
|
||||||
|
Plotly.addTraces(this.plotElement, traceData);
|
||||||
|
} else { // update existing trace with new data (bounds change)
|
||||||
|
Plotly.react(this.plotElement, Object.values(this.plotData), this.getLayout(telemetryObject, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
subscribe(domainObject) {
|
updateData(datum, index, length) {
|
||||||
// this.date = ''
|
// plot all datapoints within bounds
|
||||||
// this.openmct.objects.get(this.keystring)
|
if (datum.utc <= this.bounds.end && this.openmct.time.clock()) {
|
||||||
// .then((object) => {
|
Plotly.extendTraces(
|
||||||
// const metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
this.plotElement,
|
||||||
// console.log('metadata', metadata);
|
{
|
||||||
// // this.timeKey = this.openmct.time.timeSystem().key;
|
x: [[this.formatDatumX(datum)]],
|
||||||
// // this.timeFormat = this.openmct.telemetry.getValueFormatter(metadata.value(this.timeKey));
|
y: [[this.formatDatumY(datum)]]
|
||||||
// // // this.imageFormat = this.openmct.telemetry.getValueFormatter(metadata.valuesForHints(['image'])[0]);
|
},
|
||||||
// // this.unsubscribe = this.openmct.telemetry
|
[index], // apply changes to particular trace
|
||||||
// // .subscribe(this.domainObject, (datum) => {
|
length // set the fixed number of points (will drop points from beginning as new points are added)
|
||||||
// // this.updateHistory(datum);
|
);
|
||||||
// // this.updateValues(datum);
|
let newRange = {
|
||||||
// // });
|
'xaxis.range': [this.formatDatumX({utc: this.bounds.start}),this.formatDatumX({utc: this.bounds.end})]
|
||||||
|
};
|
||||||
// // this.requestHistory(this.openmct.time.bounds());
|
Plotly.relayout(this.plotElement, newRange);
|
||||||
// });
|
}
|
||||||
|
|
||||||
this.openmct.telemetry.subscribe(domainObject, (datum) => {
|
|
||||||
this.updateData(datum)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
updateData(datum) {
|
|
||||||
Plotly.extendTraces(
|
|
||||||
this.plotElement,
|
|
||||||
{
|
|
||||||
x: [[this.formatDatumX(datum)]],
|
|
||||||
y: [[this.formatDatumY(datum)]]
|
|
||||||
},
|
|
||||||
[0]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import PlotlyViewProvider from './PlotlyViewProvider.js';
|
import PlotlyViewProvider from './PlotlyViewProvider.js';
|
||||||
import PlotlyTelemetryProvider from './PlotlyTelemetryProvider.js';
|
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
return function install(openmct) {
|
return function install(openmct) {
|
||||||
openmct.objectViews.addProvider(new PlotlyViewProvider(openmct));
|
openmct.objectViews.addProvider(new PlotlyViewProvider(openmct));
|
||||||
openmct.telemetry.addProvider(new PlotlyTelemetryProvider(openmct));
|
|
||||||
|
|
||||||
openmct.types.addType('plotlyPlot', {
|
openmct.types.addType('plotlyPlot', {
|
||||||
name: "Plotly Plot",
|
name: "Plotly Plot",
|
||||||
|
@ -183,7 +183,7 @@ define([
|
|||||||
plugins.FolderView = FolderView;
|
plugins.FolderView = FolderView;
|
||||||
plugins.Tabs = Tabs;
|
plugins.Tabs = Tabs;
|
||||||
plugins.FlexibleLayout = FlexibleLayout;
|
plugins.FlexibleLayout = FlexibleLayout;
|
||||||
plugins.LADTable = LADTable;
|
plugins.LADTable = LADTable.default;
|
||||||
plugins.Filters = Filters;
|
plugins.Filters = Filters;
|
||||||
plugins.ObjectMigration = ObjectMigration.default;
|
plugins.ObjectMigration = ObjectMigration.default;
|
||||||
plugins.GoToOriginalAction = GoToOriginalAction.default;
|
plugins.GoToOriginalAction = GoToOriginalAction.default;
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
{'is-current': isCurrent(tab)},
|
{'is-current': isCurrent(tab)},
|
||||||
tab.type.definition.cssClass
|
tab.type.definition.cssClass
|
||||||
]"
|
]"
|
||||||
@click="showTab(tab)"
|
@click="showTab(tab, index)"
|
||||||
>
|
>
|
||||||
<span class="c-button__label">{{ tab.domainObject.name }}</span>
|
<span class="c-button__label">{{ tab.domainObject.name }}</span>
|
||||||
</button>
|
</button>
|
||||||
@ -48,6 +48,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<object-view
|
<object-view
|
||||||
|
v-if="internalDomainObject.keep_alive ? currentTab : isCurrent(tab)"
|
||||||
class="c-tabs-view__object"
|
class="c-tabs-view__object"
|
||||||
:object="tab.domainObject"
|
:object="tab.domainObject"
|
||||||
/>
|
/>
|
||||||
@ -57,7 +58,6 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ObjectView from '../../../ui/components/ObjectView.vue';
|
import ObjectView from '../../../ui/components/ObjectView.vue';
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
var unknownObjectType = {
|
var unknownObjectType = {
|
||||||
definition: {
|
definition: {
|
||||||
@ -73,6 +73,7 @@ export default {
|
|||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
internalDomainObject: this.domainObject,
|
||||||
currentTab: {},
|
currentTab: {},
|
||||||
tabsList: [],
|
tabsList: [],
|
||||||
setCurrentTab: true,
|
setCurrentTab: true,
|
||||||
@ -85,9 +86,17 @@ export default {
|
|||||||
this.composition.on('add', this.addItem);
|
this.composition.on('add', this.addItem);
|
||||||
this.composition.on('remove', this.removeItem);
|
this.composition.on('remove', this.removeItem);
|
||||||
this.composition.on('reorder', this.onReorder);
|
this.composition.on('reorder', this.onReorder);
|
||||||
this.composition.load();
|
this.composition.load().then(() => {
|
||||||
|
let currentTabIndex = this.domainObject.currentTabIndex;
|
||||||
|
|
||||||
|
if (currentTabIndex !== undefined && this.tabsList.length > currentTabIndex) {
|
||||||
|
this.currentTab = this.tabsList[currentTabIndex];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.unsubscribe = this.openmct.objects.observe(this.internalDomainObject, '*', this.updateInternalDomainObject);
|
||||||
|
|
||||||
document.addEventListener('dragstart', this.dragstart);
|
document.addEventListener('dragstart', this.dragstart);
|
||||||
document.addEventListener('dragend', this.dragend);
|
document.addEventListener('dragend', this.dragend);
|
||||||
},
|
},
|
||||||
@ -96,18 +105,25 @@ export default {
|
|||||||
this.composition.off('remove', this.removeItem);
|
this.composition.off('remove', this.removeItem);
|
||||||
this.composition.off('reorder', this.onReorder);
|
this.composition.off('reorder', this.onReorder);
|
||||||
|
|
||||||
|
this.unsubscribe();
|
||||||
|
|
||||||
document.removeEventListener('dragstart', this.dragstart);
|
document.removeEventListener('dragstart', this.dragstart);
|
||||||
document.removeEventListener('dragend', this.dragend);
|
document.removeEventListener('dragend', this.dragend);
|
||||||
},
|
},
|
||||||
methods:{
|
methods:{
|
||||||
showTab(tab) {
|
showTab(tab, index) {
|
||||||
|
if (index !== undefined) {
|
||||||
|
this.storeCurrentTabIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
this.currentTab = tab;
|
this.currentTab = tab;
|
||||||
},
|
},
|
||||||
addItem(domainObject) {
|
addItem(domainObject) {
|
||||||
let type = this.openmct.types.get(domainObject.type) || unknownObjectType,
|
let type = this.openmct.types.get(domainObject.type) || unknownObjectType,
|
||||||
tabItem = {
|
tabItem = {
|
||||||
domainObject,
|
domainObject,
|
||||||
type: type
|
type: type,
|
||||||
|
key: this.openmct.objects.makeKeyString(domainObject.identifier)
|
||||||
};
|
};
|
||||||
|
|
||||||
this.tabsList.push(tabItem);
|
this.tabsList.push(tabItem);
|
||||||
@ -126,7 +142,7 @@ export default {
|
|||||||
this.tabsList.splice(pos, 1);
|
this.tabsList.splice(pos, 1);
|
||||||
|
|
||||||
if (this.isCurrent(tabToBeRemoved)) {
|
if (this.isCurrent(tabToBeRemoved)) {
|
||||||
this.showTab(this.tabsList[this.tabsList.length - 1]);
|
this.showTab(this.tabsList[this.tabsList.length - 1], this.tabsList.length - 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onReorder(reorderPlan) {
|
onReorder(reorderPlan) {
|
||||||
@ -138,6 +154,7 @@ export default {
|
|||||||
},
|
},
|
||||||
onDrop(e) {
|
onDrop(e) {
|
||||||
this.setCurrentTab = true;
|
this.setCurrentTab = true;
|
||||||
|
this.storeCurrentTabIndex(this.tabsList.length);
|
||||||
},
|
},
|
||||||
dragstart(e) {
|
dragstart(e) {
|
||||||
if (e.dataTransfer.types.includes('openmct/domain-object-path')) {
|
if (e.dataTransfer.types.includes('openmct/domain-object-path')) {
|
||||||
@ -155,7 +172,13 @@ export default {
|
|||||||
this.allowDrop = false;
|
this.allowDrop = false;
|
||||||
},
|
},
|
||||||
isCurrent(tab) {
|
isCurrent(tab) {
|
||||||
return _.isEqual(this.currentTab, tab)
|
return this.currentTab.key === tab.key;
|
||||||
|
},
|
||||||
|
updateInternalDomainObject(domainObject) {
|
||||||
|
this.internalDomainObject = domainObject;
|
||||||
|
},
|
||||||
|
storeCurrentTabIndex(index) {
|
||||||
|
this.openmct.objects.mutate(this.internalDomainObject, 'currentTabIndex', index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,27 @@ define([
|
|||||||
cssClass: 'icon-tabs-view',
|
cssClass: 'icon-tabs-view',
|
||||||
initialize(domainObject) {
|
initialize(domainObject) {
|
||||||
domainObject.composition = [];
|
domainObject.composition = [];
|
||||||
}
|
domainObject.keep_alive = true;
|
||||||
|
},
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
"key": "keep_alive",
|
||||||
|
"name": "Keep Tabs Alive",
|
||||||
|
"control": "select",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
'name': 'True',
|
||||||
|
'value': true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'False',
|
||||||
|
'value': false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"required": true,
|
||||||
|
"cssClass": "l-input"
|
||||||
|
}
|
||||||
|
]
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
224
src/testTools.js
224
src/testTools.js
@ -1,4 +1,6 @@
|
|||||||
import MCT from 'MCT';
|
import MCT from 'MCT';
|
||||||
|
let nativeFunctions = [],
|
||||||
|
mockObjects = setMockObjects();
|
||||||
|
|
||||||
export function createOpenMct() {
|
export function createOpenMct() {
|
||||||
const openmct = new MCT();
|
const openmct = new MCT();
|
||||||
@ -16,3 +18,225 @@ export function createMouseEvent(eventName) {
|
|||||||
view: window
|
view: window
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const spyOnBuiltins = (functionNames, object = window) => {
|
||||||
|
functionNames.forEach(functionName => {
|
||||||
|
if (nativeFunctions[functionName]) {
|
||||||
|
throw `Builtin spy function already defined for ${functionName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
nativeFunctions.push({functionName, object, nativeFunction: object[functionName]});
|
||||||
|
spyOn(object, functionName);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const clearBuiltinSpies = () => {
|
||||||
|
nativeFunctions.forEach(clearBuiltinSpy);
|
||||||
|
nativeFunctions = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
function clearBuiltinSpy(funcDefinition) {
|
||||||
|
funcDefinition.object[funcDefinition.functionName] = funcDefinition.nativeFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getLatestTelemetry = (telemetry = [], opts = {}) => {
|
||||||
|
let latest = [],
|
||||||
|
timeFormat = opts.timeFormat || 'utc';
|
||||||
|
|
||||||
|
if(telemetry.length) {
|
||||||
|
latest = telemetry.reduce((prev, cur) => {
|
||||||
|
return prev[timeFormat] > cur[timeFormat] ? prev : cur;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return latest;
|
||||||
|
};
|
||||||
|
|
||||||
|
// EXAMPLE:
|
||||||
|
// getMockObjects({
|
||||||
|
// name: 'Jamie Telemetry',
|
||||||
|
// keys: ['test','other','yeah','sup'],
|
||||||
|
// format: 'local',
|
||||||
|
// telemetryConfig: {
|
||||||
|
// hints: {
|
||||||
|
// test: {
|
||||||
|
// domain: 1
|
||||||
|
// },
|
||||||
|
// other: {
|
||||||
|
// range: 2
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
export const getMockObjects = (opts = {}) => {
|
||||||
|
opts.type = opts.type || 'default';
|
||||||
|
if(opts.objectKeyStrings && !Array.isArray(opts.objectKeyStrings)) {
|
||||||
|
throw `"getMockObjects" optional parameter "objectKeyStrings" must be an array of string object keys`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let requestedMocks = {};
|
||||||
|
|
||||||
|
if (!opts.objectKeyStrings) {
|
||||||
|
requestedMocks = copyObj(mockObjects[opts.type]);
|
||||||
|
} else {
|
||||||
|
opts.objectKeyStrings.forEach(objKey => {
|
||||||
|
if(mockObjects[opts.type] && mockObjects[opts.type][objKey]) {
|
||||||
|
requestedMocks[objKey] = copyObj(mockObjects[opts.type][objKey]);
|
||||||
|
} else {
|
||||||
|
throw `No mock object for object key "${objKey}" of type "${opts.type}"`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// build out custom telemetry mappings if necessary
|
||||||
|
if(requestedMocks.telemetry && opts.telemetryConfig) {
|
||||||
|
let keys = opts.telemetryConfig.keys,
|
||||||
|
format = opts.telemetryConfig.format || 'utc',
|
||||||
|
hints = opts.telemetryConfig.hints,
|
||||||
|
values;
|
||||||
|
|
||||||
|
// if utc, keep default
|
||||||
|
if(format === 'utc') {
|
||||||
|
// save for later if new keys
|
||||||
|
if(keys) {
|
||||||
|
format = requestedMocks.telemetry
|
||||||
|
.telemetry.values.find((vals) => vals.key === 'utc');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
format = {
|
||||||
|
key: format,
|
||||||
|
name: "Time",
|
||||||
|
format: format === 'local' ? 'local-format' : format,
|
||||||
|
hints: {
|
||||||
|
domain: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(keys) {
|
||||||
|
values = keys.map((key) => ({ key, name: key + ' attribute' }));
|
||||||
|
values.push(format); // add time format back in
|
||||||
|
} else {
|
||||||
|
values = requestedMocks.telemetry.telemetry.values;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hints) {
|
||||||
|
for(let val of values) {
|
||||||
|
if(hints[val.key]) {
|
||||||
|
val.hints = hints[val.key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestedMocks.telemetry.telemetry.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
// overwrite any field keys
|
||||||
|
if(opts.overwrite) {
|
||||||
|
for(let mock in requestedMocks) {
|
||||||
|
if(opts.overwrite[mock]) {
|
||||||
|
for(let key in opts.overwrite[mock]) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(opts.overwrite[mock], key)) {
|
||||||
|
requestedMocks[mock][key] = opts.overwrite[mock][key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestedMocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXAMPLE:
|
||||||
|
// getMockTelemetry({
|
||||||
|
// name: 'My Telemetry',
|
||||||
|
// keys: ['test','other','yeah','sup'],
|
||||||
|
// count: 8,
|
||||||
|
// format: 'local'
|
||||||
|
// })
|
||||||
|
export const getMockTelemetry = (opts = {}) => {
|
||||||
|
let count = opts.count || 2,
|
||||||
|
format = opts.format || 'utc',
|
||||||
|
name = opts.name || 'Mock Telemetry Datum',
|
||||||
|
keyCount = 2,
|
||||||
|
keys = false,
|
||||||
|
telemetry = [];
|
||||||
|
|
||||||
|
if(opts.keys && Array.isArray(opts.keys)) {
|
||||||
|
keyCount = opts.keys.length;
|
||||||
|
keys = opts.keys;
|
||||||
|
} else if(opts.keyCount) {
|
||||||
|
keyCount = opts.keyCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let i = 1; i < count + 1; i++) {
|
||||||
|
let datum = {
|
||||||
|
[format]: i,
|
||||||
|
name
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let k = 1; k < keyCount + 1; k++) {
|
||||||
|
let key = keys ? keys[k - 1] : 'some-key-' + k,
|
||||||
|
value = keys ? keys[k - 1] + ' value ' + i : 'some value ' + i + '-' + k;
|
||||||
|
datum[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
telemetry.push(datum);
|
||||||
|
}
|
||||||
|
|
||||||
|
return telemetry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy objects a bit more easily
|
||||||
|
function copyObj(obj) {
|
||||||
|
return JSON.parse(JSON.stringify(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// add any other necessary types to this mockObjects object
|
||||||
|
function setMockObjects() {
|
||||||
|
return {
|
||||||
|
default: {
|
||||||
|
ladTable: {
|
||||||
|
identifier: { namespace: "", key: "lad-object"},
|
||||||
|
type: 'LadTable',
|
||||||
|
composition: []
|
||||||
|
},
|
||||||
|
ladTableSet: {
|
||||||
|
identifier: { namespace: "", key: "lad-set-object"},
|
||||||
|
type: 'LadTableSet',
|
||||||
|
composition: []
|
||||||
|
},
|
||||||
|
telemetry: {
|
||||||
|
identifier: { namespace: "", key: "telemetry-object"},
|
||||||
|
type: "test-telemetry-object",
|
||||||
|
name: "Test Telemetry Object",
|
||||||
|
telemetry: {
|
||||||
|
values: [{
|
||||||
|
key: "name",
|
||||||
|
name: "Name",
|
||||||
|
format: "string"
|
||||||
|
},{
|
||||||
|
key: "utc",
|
||||||
|
name: "Time",
|
||||||
|
format: "utc",
|
||||||
|
hints: {
|
||||||
|
domain: 1
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
name: "Some attribute 1",
|
||||||
|
key: "some-key-1",
|
||||||
|
hints: {
|
||||||
|
range: 1
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: "Some attribute 2",
|
||||||
|
key: "some-key-2"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
otherType: {
|
||||||
|
example: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import PreviewHeader from './preview-header.vue';
|
import PreviewHeader from './preview-header.vue';
|
||||||
|
import {STYLE_CONSTANTS} from "@/plugins/condition/utils/constants";
|
||||||
|
import StyleRuleManager from "@/plugins/condition/StyleRuleManager";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -69,6 +71,14 @@ export default {
|
|||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.view.destroy();
|
this.view.destroy();
|
||||||
|
if (this.stopListeningStyles) {
|
||||||
|
this.stopListeningStyles();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.styleRuleManager) {
|
||||||
|
this.styleRuleManager.destroy();
|
||||||
|
delete this.styleRuleManager;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
clear() {
|
clear() {
|
||||||
@ -90,6 +100,46 @@ export default {
|
|||||||
|
|
||||||
this.view = this.currentView.view(this.domainObject, this.objectPath);
|
this.view = this.currentView.view(this.domainObject, this.objectPath);
|
||||||
this.view.show(this.viewContainer, false);
|
this.view.show(this.viewContainer, false);
|
||||||
|
this.initObjectStyles();
|
||||||
|
},
|
||||||
|
initObjectStyles() {
|
||||||
|
if (!this.styleRuleManager) {
|
||||||
|
this.styleRuleManager = new StyleRuleManager((this.domainObject.configuration && this.domainObject.configuration.objectStyles), this.openmct, this.updateStyle.bind(this));
|
||||||
|
} else {
|
||||||
|
this.styleRuleManager.updateObjectStyleConfig(this.domainObject.configuration && this.domainObject.configuration.objectStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.stopListeningStyles) {
|
||||||
|
this.stopListeningStyles();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopListeningStyles = this.openmct.objects.observe(this.domainObject, 'configuration.objectStyles', (newObjectStyle) => {
|
||||||
|
//Updating styles in the inspector view will trigger this so that the changes are reflected immediately
|
||||||
|
this.styleRuleManager.updateObjectStyleConfig(newObjectStyle);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
updateStyle(styleObj) {
|
||||||
|
if (!styleObj) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let keys = Object.keys(styleObj);
|
||||||
|
keys.forEach(key => {
|
||||||
|
let firstChild = this.$refs.objectView.querySelector(':first-child');
|
||||||
|
if (firstChild) {
|
||||||
|
if ((typeof styleObj[key] === 'string') && (styleObj[key].indexOf('__no_value') > -1)) {
|
||||||
|
if (firstChild.style[key]) {
|
||||||
|
firstChild.style[key] = '';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!styleObj.isStyleInvisible && firstChild.classList.contains(STYLE_CONSTANTS.isStyleInvisible)) {
|
||||||
|
firstChild.classList.remove(STYLE_CONSTANTS.isStyleInvisible);
|
||||||
|
} else if (styleObj.isStyleInvisible && !firstChild.classList.contains(styleObj.isStyleInvisible)) {
|
||||||
|
firstChild.classList.add(styleObj.isStyleInvisible);
|
||||||
|
}
|
||||||
|
firstChild.style[key] = styleObj[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user