Compare commits

..

35 Commits

Author SHA1 Message Date
Deep Tailor
043d6aa9c3 extend traces on subscribe 2020-05-07 12:23:32 -07:00
Deep Tailor
ecfab8f7f3 add subscribe 2020-05-07 12:00:39 -07:00
Deep Tailor
05c38c37aa working historical 2020-05-07 11:37:01 -07:00
Joel McKinnon
ce78925119 wip: added telemetry provider 2020-05-07 10:45:15 -07:00
Joel McKinnon
26aca0f433 working on viewProvider 2020-05-06 11:31:17 -07:00
Joel McKinnon
41259bbd40 added hardcoded test plot 2020-05-05 16:00:48 -07:00
Joel McKinnon
580640ff47 basic plotly plugin structure 2020-05-05 12:50:55 -07:00
Joel McKinnon
a4aec5d492 Merge branch 'master' of https://github.com/nasa/openmct 2020-05-01 10:46:57 -07:00
Joel McKinnon
00b3f3ac0b Merge branch 'master' of https://github.com/nasa/openmct 2020-05-01 09:25:44 -07:00
Joel McKinnon
c185f77a15 Merge branch 'master' of https://github.com/nasa/openmct 2020-04-29 16:52:05 -07:00
Joel McKinnon
0dff431f4a Merge branch 'master' of https://github.com/nasa/openmct 2020-04-27 12:02:12 -07:00
Joel McKinnon
61d238a097 Merge branch 'master' of https://github.com/nasa/openmct 2020-04-23 16:30:01 -07:00
Joel McKinnon
f9deb80350 Merge branch 'master' of https://github.com/nasa/openmct 2020-04-16 15:01:42 -07:00
Joel McKinnon
021d730814 resolve merge conflicts 2020-04-13 09:05:43 -07:00
David Tsay
ae62b15abf Merge branch 'fix-default-output' of github.com:nasa/openmct into fix-default-output 2020-04-10 15:44:42 -07:00
David Tsay
ba41c1a30e fix unit tests 2020-04-10 15:43:48 -07:00
Andrew Henry
b9a85d9c4d Merge branch 'master' into fix-default-output 2020-04-10 15:34:10 -07:00
David Tsay
80eab8bad1 fix telemetrycriterion and unit testing 2020-04-10 15:26:18 -07:00
Andrew Henry
b2d8d640ae Merge branch 'master' into fix-default-output 2020-04-10 15:23:10 -07:00
Andrew Henry
56e6fa66c2 Merge branch 'master' into fix-default-output 2020-04-10 15:13:36 -07:00
David Tsay
9fa4707c82 Merge branch 'master' into fix-default-output 2020-04-10 13:04:14 -07:00
David Tsay
7e2cfa36de AllTelemetryCriterion extends TelemetryCriterion 2020-04-10 12:17:55 -07:00
David Tsay
aaa60a1545 scope function names 2020-04-10 11:28:13 -07:00
David Tsay
717231fed2 use current timesystem to compare latest 2020-04-10 11:20:51 -07:00
David Tsay
7fb2bc9729 tie in requests and eliminate unused code 2020-04-10 10:42:31 -07:00
David Tsay
addeb635e9 refactor all/any telemetry criterion to use new evaluator 2020-04-10 09:48:31 -07:00
David Tsay
608d63a7b0 telemetry criterion stores its own result 2020-04-10 09:00:39 -07:00
David Tsay
10679e5f4f remove commented code 2020-04-10 00:12:55 -07:00
David Tsay
38b8f03b1a linting 2020-04-09 21:03:56 -07:00
David Tsay
779a42c28c remove unused listeners, events, and helpers 2020-04-09 18:14:19 -07:00
David Tsay
80c2504768 get results directly instead of using events 2020-04-09 17:54:47 -07:00
David Tsay
80359e3f16 remove generating timestamp for telemetry data 2020-04-09 16:20:16 -07:00
Joshi
66aa4f099f Remove unused code 2020-04-09 15:22:35 -07:00
Joshi
aa6c6cb88b Removes timestamp based evalutation from conditionManager 2020-04-09 15:21:25 -07:00
Joshi
4e5cc840d7 Ensures that results for a specific datapoint are evaluated atomically. 2020-04-09 12:10:29 -07:00
20 changed files with 306 additions and 65 deletions

View File

@@ -2,7 +2,9 @@
"name": "openmct",
"version": "1.0.0-snapshot",
"description": "The Open MCT core platform",
"dependencies": {},
"dependencies": {
"plotly.js-dist": "^1.54.1"
},
"devDependencies": {
"angular": "1.7.9",
"angular-route": "1.4.14",
@@ -53,7 +55,7 @@
"marked": "^0.3.5",
"mini-css-extract-plugin": "^0.4.1",
"minimist": "^1.1.1",
"moment": "2.24.0",
"moment": "^2.25.3",
"moment-duration-format": "^2.2.2",
"moment-timezone": "^0.5.21",
"node-bourbon": "^4.2.3",

View File

@@ -252,6 +252,7 @@ define([
// Plugin's that are installed by default
this.install(this.plugins.Plot());
this.install(this.plugins.PlotlyPlot());
this.install(this.plugins.TelemetryTable());
this.install(PreviewPlugin.default());
this.install(LegacyIndicatorsPlugin());

View File

@@ -6,7 +6,7 @@
:key="action.name"
:class="action.cssClass"
:title="action.description"
@click="action.invoke(objectPath, context)"
@click="action.invoke(objectPath)"
>
{{ action.name }}
</li>
@@ -19,6 +19,6 @@
<script>
export default {
inject: ['actions', 'objectPath', 'context']
inject: ['actions', 'objectPath']
}
</script>

View File

@@ -75,7 +75,7 @@ class ContextMenuAPI {
/**
* @private
*/
_showContextMenuForObjectPath(objectPath, x, y, actionsToBeIncluded, context) {
_showContextMenuForObjectPath(objectPath, x, y, actionsToBeIncluded) {
let applicableActions = this._allActions.filter((action) => {
@@ -96,7 +96,7 @@ class ContextMenuAPI {
this._hideActiveContextMenu();
}
this._activeContextMenu = this._createContextMenuForObject(objectPath, applicableActions, context);
this._activeContextMenu = this._createContextMenuForObject(objectPath, applicableActions);
this._activeContextMenu.$mount();
document.body.appendChild(this._activeContextMenu.$el);
@@ -141,15 +141,14 @@ class ContextMenuAPI {
/**
* @private
*/
_createContextMenuForObject(objectPath, actions, context) {
_createContextMenuForObject(objectPath, actions) {
return new Vue({
components: {
ContextMenu: ContextMenuComponent
},
provide: {
actions: actions,
objectPath: objectPath,
context
objectPath: objectPath
},
template: '<ContextMenu></ContextMenu>'
});

View File

@@ -69,7 +69,6 @@ export default class ConditionClass extends EventEmitter {
console.log('no data received');
return;
}
this.criteria.forEach(criterion => {
if (this.isAnyOrAllTelemetry(criterion)) {
criterion.getResult(datum, this.conditionManager.telemetryObjects);

View File

@@ -57,6 +57,7 @@ export default class ConditionManager extends EventEmitter {
endpoint,
this.telemetryReceived.bind(this, endpoint)
);
// TODO check if this is needed
this.updateConditionTelemetry();
}

View File

@@ -0,0 +1,35 @@
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));
}
}

View File

@@ -0,0 +1,73 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2019, 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 PlotlyViewLayout from './components/PlotlyViewLayout.vue';
import Vue from 'vue';
export default function PlotlyViewProvider(openmct) {
return {
key: 'plotlyPlot',
name: 'Plotly Plot',
cssClass: 'icon-plot-overlay',
canView: function (domainObject) {
return domainObject.type === 'plotlyPlot';
},
canEdit: function (domainObject) {
return domainObject.type === 'plotlyPlot';
},
view: function (domainObject, objectPath) {
let component;
return {
show: function (element, isEditing) {
component = new Vue({
provide: {
openmct,
domainObject,
objectPath
},
el: element,
components: {
PlotlyViewLayout
},
data() {
return {
isEditing
}
},
template: '<plotly-view-layout :isEditing="isEditing"></plotly-view-layout>'
});
},
onEditModeChange: function (isEditing) {
component.isEditing = isEditing;
},
destroy: function (element) {
component.$destroy();
component = undefined;
}
};
},
priority: function () {
return 1;
}
};
}

View File

@@ -0,0 +1,138 @@
<template>
<div class="l-view-section"></div>
</template>
<script>
import Plotly from 'plotly.js-dist';
import moment from 'moment'
export default {
inject: ['openmct', 'domainObject', 'objectPath'],
data: function () {
return {
telemetryObjects: []
// currentDomainObject: this.domainObject
}
},
mounted() {
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('add', this.addTelemetry);
this.composition.load();
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
console.log('this.metadata', this.metadata);
// this.keystring = this.openmct.objects.makeKeyString(this.domainObject.identifier);
// 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: {
getLayout() {
return {
hovermode: 'compare',
hoverdistance: -1,
autosize: "true",
showlegend: false,
font: {
family: "'Helvetica Neue', Helvetica, Arial, sans-serif",
size: "12px",
color: "#666"
},
xaxis: {
// title: this.plotAxisTitle.xAxisTitle,
zeroline: false
},
yaxis: {
// title: this.plotAxisTitle.yAxisTitle,
zeroline: false
},
margin: {
l: 20,
r: 10,
b: 20,
t: 10
},
paper_bgcolor: 'transparent',
plot_bgcolor: 'transparent'
}
},
addTelemetry(telemetryObject) {
return this.openmct.telemetry.request(telemetryObject)
.then(telemetryData => {
this.createPlot(telemetryData, telemetryObject);
}, () => {console.log(error)});
},
formatDatumX(datum) {
let timestamp = moment.utc(datum.utc).format('YYYY-MM-DD hh:mm:ss.ms');
return timestamp;
},
formatDatumY(datum) {
return datum.sin;
},
createPlot(telemetryData, telemetryObject) {
let x = [],
y = [];
telemetryData.forEach((datum, index) => {
x.push(this.formatDatumX(datum));
y.push(this.formatDatumY(datum));
})
let data = [{
x,
y,
mode: 'line'
}];
var layout = {
title:'Line and Scatter Plot'
};
Plotly.newPlot(
this.plotElement,
data,
this.getLayout()
)
this.subscribe(telemetryObject);
},
subscribe(domainObject) {
// this.date = ''
// this.openmct.objects.get(this.keystring)
// .then((object) => {
// const metadata = this.openmct.telemetry.getMetadata(this.domainObject);
// console.log('metadata', metadata);
// // this.timeKey = this.openmct.time.timeSystem().key;
// // this.timeFormat = this.openmct.telemetry.getValueFormatter(metadata.value(this.timeKey));
// // // this.imageFormat = this.openmct.telemetry.getValueFormatter(metadata.valuesForHints(['image'])[0]);
// // this.unsubscribe = this.openmct.telemetry
// // .subscribe(this.domainObject, (datum) => {
// // this.updateHistory(datum);
// // this.updateValues(datum);
// // });
// // this.requestHistory(this.openmct.time.bounds());
// });
this.openmct.telemetry.subscribe(domainObject, (datum) => {
this.updateData(datum)
})
},
updateData(datum) {
Plotly.extendTraces(
this.plotElement,
{
x: [[this.formatDatumX(datum)]],
y: [[this.formatDatumY(datum)]]
},
[0]
);
}
}
}
</script>

View File

@@ -0,0 +1,2 @@
.plot svg {
}

View File

@@ -0,0 +1,20 @@
import PlotlyViewProvider from './PlotlyViewProvider.js';
import PlotlyTelemetryProvider from './PlotlyTelemetryProvider.js';
export default function () {
return function install(openmct) {
openmct.objectViews.addProvider(new PlotlyViewProvider(openmct));
openmct.telemetry.addProvider(new PlotlyTelemetryProvider(openmct));
openmct.types.addType('plotlyPlot', {
name: "Plotly Plot",
description: "Simple plot rendered by plotly.js",
creatable: true,
cssClass: 'icon-plot-overlay',
initialize: function (domainObject) {
domainObject.composition = [];
domainObject.telemetry = {};
}
});
};
}

View File

@@ -34,6 +34,7 @@ define([
'./URLIndicatorPlugin/URLIndicatorPlugin',
'./telemetryMean/plugin',
'./plot/plugin',
'./plotlyPlot/plugin',
'./telemetryTable/plugin',
'./staticRootPlugin/plugin',
'./notebook/plugin',
@@ -66,6 +67,7 @@ define([
URLIndicatorPlugin,
TelemetryMean,
PlotPlugin,
PlotlyPlotPlugin,
TelemetryTablePlugin,
StaticRootPlugin,
Notebook,
@@ -171,8 +173,8 @@ define([
plugins.ExampleImagery = ExampleImagery;
plugins.ImageryPlugin = ImageryPlugin;
plugins.Plot = PlotPlugin;
plugins.PlotlyPlot = PlotlyPlotPlugin.default;
plugins.TelemetryTable = TelemetryTablePlugin;
plugins.SummaryWidget = SummaryWidget;
plugins.TelemetryMean = TelemetryMean;
plugins.URLIndicator = URLIndicatorPlugin;

View File

@@ -29,11 +29,11 @@ export default class RemoveAction {
this.openmct = openmct;
}
invoke(objectPath, context) {
invoke(objectPath) {
let object = objectPath[0];
let parent = objectPath[1];
this.showConfirmDialog(object).then(() => {
this.removeFromComposition(parent, object, context.sequenceNumber);
this.removeFromComposition(parent, object);
if (this.inNavigationPath(object)) {
this.navigateTo(objectPath.slice(1));
}
@@ -79,21 +79,23 @@ export default class RemoveAction {
window.location.href = '#/browse/' + urlPath;
}
removeFromComposition(parent, child, sequenceNumber) {
this.openmct.composition.get(parent).then(compositionCollection => {
compositionCollection.remove(child, sequenceNumber);
})
removeFromComposition(parent, child) {
let composition = parent.composition.filter(id =>
!this.openmct.objects.areIdsEqual(id, child.identifier)
);
this.openmct.objects.mutate(parent, 'composition', composition);
if (this.inNavigationPath(child) && this.openmct.editor.isEditing()) {
this.openmct.editor.save();
}
// Find another way of doing this with notebooks
// const parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
// const isAlias = parentKeyString !== child.location;
// if (!isAlias) {
// this.openmct.objects.mutate(child, 'location', null);
// }
const parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
const isAlias = parentKeyString !== child.location;
if (!isAlias) {
this.openmct.objects.mutate(child, 'location', null);
}
}
appliesTo(objectPath) {

View File

@@ -18,6 +18,7 @@
@import "../plugins/folderView/components/list-item.scss";
@import "../plugins/folderView/components/list-view.scss";
@import "../plugins/imagery/components/imagery-view-layout.scss";
@import "../plugins/plotlyPlot/components/plotly.scss";
@import "../plugins/telemetryTable/components/table-row.scss";
@import "../plugins/telemetryTable/components/telemetry-filter-indicator.scss";
@import "../plugins/tabs/components/tabs.scss";

View File

@@ -36,10 +36,6 @@ export default {
navigateToPath: {
type: String,
default: undefined
},
sequenceNumber: {
type: Number,
default: undefined
}
},
data() {

View File

@@ -110,8 +110,7 @@ export default {
domainObject: PLACEHOLDER_OBJECT,
viewKey: undefined,
isEditing: this.openmct.editor.isEditing(),
notebookEnabled: this.openmct.types.get('notebook'),
sequenceNumber: undefined
notebookEnabled: this.openmct.types.get('notebook')
}
},
computed: {
@@ -268,14 +267,7 @@ export default {
});
},
showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(
this.openmct.router.path,
event.clientX,
event.clientY,
undefined,
{
sequenceNumber: this.sequenceNumber
});
this.openmct.contextMenu._showContextMenuForObjectPath(this.openmct.router.path, event.clientX, event.clientY);
},
goToParent() {
window.location.hash = this.parentUrl;

View File

@@ -34,7 +34,6 @@
v-for="treeItem in allTreeItems"
:key="treeItem.id"
:node="treeItem"
:sequence-number="0"
/>
</ul>
<!-- end main tree -->
@@ -48,7 +47,6 @@
v-for="treeItem in filteredTreeItems"
:key="treeItem.id"
:node="treeItem"
:sequence-number="0"
/>
</ul>
<!-- end search tree -->

View File

@@ -13,7 +13,6 @@
:domain-object="node.object"
:object-path="node.objectPath"
:navigate-to-path="navigateToPath"
:sequence-number="sequenceNumber"
/>
</div>
<ul
@@ -29,10 +28,9 @@
</div>
</li>
<tree-item
v-for="(child, index) in children"
v-for="child in children"
:key="child.id"
:node="child"
:sequence-number="index"
/>
</ul>
</li>
@@ -55,10 +53,6 @@ export default {
node: {
type: Object,
required: true
},
sequenceNumber: {
type: Number,
required: true
}
},
data() {

View File

@@ -13,20 +13,13 @@ export default {
if (!this.objectPath.length) {
return;
}
let url;
if (this.navigateToPath) {
url = '#' + this.navigateToPath;
} else {
url = '#/browse/' + this.objectPath
.map(o => o && this.openmct.objects.makeKeyString(o.identifier))
.reverse()
.join('/');
return '#' + this.navigateToPath;
}
if (this.sequenceNumber) {
url += `?sequenceNumber=${this.sequenceNumber}`;
}
return url;
return '#/browse/' + this.objectPath
.map(o => o && this.openmct.objects.makeKeyString(o.identifier))
.reverse()
.join('/');
}
}
};

View File

@@ -27,13 +27,6 @@ define([
return;
}
if (newParams.sequenceNumber) {
openmct.layout.$refs.browseBar.sequenceNumber = parseInt(newParams.sequenceNumber);
} else {
openmct.layout.$refs.browseBar.sequenceNumber = undefined;
}
if (changed.view && browseObject) {
let provider = openmct
.objectViews