mirror of
https://github.com/nasa/openmct.git
synced 2025-07-04 05:53:23 +00:00
Compare commits
19 Commits
vue-hack
...
tree-searc
Author | SHA1 | Date | |
---|---|---|---|
6b719259e3 | |||
9fc31809f6 | |||
ccd4bbd279 | |||
72848849dd | |||
66130ba542 | |||
895bdc164f | |||
c9728144a5 | |||
76fec7f3bc | |||
1b4717065a | |||
e24542c1a6 | |||
b08f3106ed | |||
700bc7616d | |||
3436e976cf | |||
b8e232831e | |||
f6bc49fc82 | |||
7018c217c4 | |||
18c230c0f7 | |||
b8c2f3f49a | |||
e5e27ea498 |
@ -32,7 +32,8 @@
|
|||||||
function indexItem(id, model) {
|
function indexItem(id, model) {
|
||||||
indexedItems.push({
|
indexedItems.push({
|
||||||
id: id,
|
id: id,
|
||||||
name: model.name.toLowerCase()
|
name: model.name.toLowerCase(),
|
||||||
|
type: model.type
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,15 +125,17 @@ define([
|
|||||||
* @param topic the topicService.
|
* @param topic the topicService.
|
||||||
*/
|
*/
|
||||||
GenericSearchProvider.prototype.indexOnMutation = function (topic) {
|
GenericSearchProvider.prototype.indexOnMutation = function (topic) {
|
||||||
var mutationTopic = topic('mutation'),
|
let mutationTopic = topic('mutation');
|
||||||
provider = this;
|
|
||||||
|
|
||||||
mutationTopic.listen(function (mutatedObject) {
|
mutationTopic.listen(mutatedObject => {
|
||||||
var editor = mutatedObject.getCapability('editor');
|
let editor = mutatedObject.getCapability('editor');
|
||||||
if (!editor || !editor.inEditContext()) {
|
if (!editor || !editor.inEditContext()) {
|
||||||
provider.index(
|
let mutatedObjectModel = mutatedObject.getModel();
|
||||||
|
this.index(
|
||||||
mutatedObject.getId(),
|
mutatedObject.getId(),
|
||||||
mutatedObject.getModel()
|
mutatedObjectModel,
|
||||||
|
mutatedObjectModel.type
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -178,14 +180,15 @@ define([
|
|||||||
* @param id a model id
|
* @param id a model id
|
||||||
* @param model a model
|
* @param model a model
|
||||||
*/
|
*/
|
||||||
GenericSearchProvider.prototype.index = function (id, model) {
|
GenericSearchProvider.prototype.index = function (id, model, type) {
|
||||||
var provider = this;
|
var provider = this;
|
||||||
|
|
||||||
if (id !== 'ROOT') {
|
if (id !== 'ROOT') {
|
||||||
this.worker.postMessage({
|
this.worker.postMessage({
|
||||||
request: 'index',
|
request: 'index',
|
||||||
model: model,
|
model: model,
|
||||||
id: id
|
id: id,
|
||||||
|
type: type
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,7 +226,7 @@ define([
|
|||||||
.then(function (objects) {
|
.then(function (objects) {
|
||||||
delete provider.pendingIndex[idToIndex];
|
delete provider.pendingIndex[idToIndex];
|
||||||
if (objects[idToIndex]) {
|
if (objects[idToIndex]) {
|
||||||
provider.index(idToIndex, objects[idToIndex].model);
|
provider.index(idToIndex, objects[idToIndex].model, objects[idToIndex].model.type);
|
||||||
}
|
}
|
||||||
}, function () {
|
}, function () {
|
||||||
provider
|
provider
|
||||||
@ -262,6 +265,7 @@ define([
|
|||||||
return {
|
return {
|
||||||
id: hit.item.id,
|
id: hit.item.id,
|
||||||
model: hit.item.model,
|
model: hit.item.model,
|
||||||
|
type: hit.item.type,
|
||||||
score: hit.matchCount
|
score: hit.matchCount
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -273,7 +277,9 @@ define([
|
|||||||
|
|
||||||
modelResults.hits = event.data.results.map(function (hit) {
|
modelResults.hits = event.data.results.map(function (hit) {
|
||||||
return {
|
return {
|
||||||
id: hit.id
|
id: hit.id,
|
||||||
|
name: hit.name,
|
||||||
|
type: hit.type
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,8 @@
|
|||||||
indexedItems.push({
|
indexedItems.push({
|
||||||
id: id,
|
id: id,
|
||||||
vector: vector,
|
vector: vector,
|
||||||
model: model
|
model: model,
|
||||||
|
type: model.type
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,8 @@ define([
|
|||||||
SearchAggregator.prototype.query = function (
|
SearchAggregator.prototype.query = function (
|
||||||
inputText,
|
inputText,
|
||||||
maxResults,
|
maxResults,
|
||||||
filter
|
filter,
|
||||||
|
indexOnly
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var aggregator = this,
|
var aggregator = this,
|
||||||
@ -120,10 +121,24 @@ define([
|
|||||||
modelResults = aggregator.applyFilter(modelResults, filter);
|
modelResults = aggregator.applyFilter(modelResults, filter);
|
||||||
modelResults = aggregator.removeDuplicates(modelResults);
|
modelResults = aggregator.removeDuplicates(modelResults);
|
||||||
|
|
||||||
|
if (indexOnly) {
|
||||||
|
return Promise.resolve(modelResults);
|
||||||
|
}
|
||||||
|
|
||||||
return aggregator.asObjectResults(modelResults);
|
return aggregator.asObjectResults(modelResults);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SearchAggregator.prototype.queryLite = function (
|
||||||
|
inputText,
|
||||||
|
maxResults,
|
||||||
|
filter
|
||||||
|
) {
|
||||||
|
const INDEX_ONLY = true;
|
||||||
|
|
||||||
|
return this.query(inputText, maxResults, filter, INDEX_ONLY);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Order model results by score descending and return them.
|
* Order model results by score descending and return them.
|
||||||
*/
|
*/
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
const { TelemetryCollection } = require("./TelemetryCollection");
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'../../plugins/displayLayout/CustomStringFormatter',
|
'../../plugins/displayLayout/CustomStringFormatter',
|
||||||
'./TelemetryMetadataManager',
|
'./TelemetryMetadataManager',
|
||||||
@ -273,6 +275,48 @@ define([
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request telemetry collection for a domain object.
|
||||||
|
* The `options` argument allows you to specify filters
|
||||||
|
* (start, end, etc.), sort order, and strategies for retrieving
|
||||||
|
* telemetry (aggregation, latest available, etc.).
|
||||||
|
*
|
||||||
|
* @method request
|
||||||
|
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
|
||||||
|
* @param {module:openmct.DomainObject} domainObject the object
|
||||||
|
* which has associated telemetry
|
||||||
|
* @param {module:openmct.TelemetryAPI~TelemetryRequest} options
|
||||||
|
* options for this historical request
|
||||||
|
* @returns {Promise.<object[]>} a promise for an array of
|
||||||
|
* telemetry data
|
||||||
|
*/
|
||||||
|
TelemetryAPI.prototype.requestTelemetryCollection = function (domainObject) {
|
||||||
|
if (arguments.length === 1) {
|
||||||
|
arguments.length = 2;
|
||||||
|
arguments[1] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// historical setup
|
||||||
|
this.standardizeRequestOptions(arguments[1]);
|
||||||
|
const historicalProvider = this.findRequestProvider(domainObject, arguments);
|
||||||
|
|
||||||
|
// subscription setup
|
||||||
|
const subscriptionProvider = this.findSubscriptionProvider(domainObject);
|
||||||
|
|
||||||
|
// check for no providers
|
||||||
|
if (!historicalProvider && !subscriptionProvider) {
|
||||||
|
return Promise.reject('No providers found');
|
||||||
|
}
|
||||||
|
|
||||||
|
let telemetryCollectionOptions = {
|
||||||
|
historicalProvider,
|
||||||
|
subscriptionProvider,
|
||||||
|
arguments: arguments
|
||||||
|
};
|
||||||
|
|
||||||
|
return Promise.resolve(new TelemetryCollection(this.openmct, domainObject, telemetryCollectionOptions));
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request historical telemetry for a domain object.
|
* Request historical telemetry for a domain object.
|
||||||
* The `options` argument allows you to specify filters
|
* The `options` argument allows you to specify filters
|
||||||
|
315
src/api/telemetry/TelemetryCollection.js
Normal file
315
src/api/telemetry/TelemetryCollection.js
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
// import _ from 'lodash';
|
||||||
|
import TelemetrySubscriptionService from './TelemetrySubscriptionService';
|
||||||
|
|
||||||
|
function bindUs() {
|
||||||
|
return [
|
||||||
|
'trackHistoricalTelemetry',
|
||||||
|
'trackSubscriptionTelemetry',
|
||||||
|
'addPage',
|
||||||
|
'processNewTelemetry',
|
||||||
|
'hasMorePages',
|
||||||
|
'nextPage',
|
||||||
|
'bounds',
|
||||||
|
'timeSystem',
|
||||||
|
'on',
|
||||||
|
'off',
|
||||||
|
'emit',
|
||||||
|
'subscribeToBounds',
|
||||||
|
'unsubscribeFromBounds',
|
||||||
|
'subscribeToTimeSystem',
|
||||||
|
'unsubscribeFromTimeSystem',
|
||||||
|
'destroy'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TelemetryCollection {
|
||||||
|
|
||||||
|
constructor(openmct, domainObject, options) {
|
||||||
|
bindUs().forEach(method => this[method] = this[method].bind(this));
|
||||||
|
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
this.boundedTelemetry = [];
|
||||||
|
this.futureBuffer = [];
|
||||||
|
|
||||||
|
this.parseTime = undefined;
|
||||||
|
this.timeSystem(openmct.time.timeSystem());
|
||||||
|
this.lastBounds = openmct.time.bounds();
|
||||||
|
|
||||||
|
this.historicalProvider = options.historicalProvider;
|
||||||
|
this.subscriptionProvider = options.subscriptionProvider;
|
||||||
|
|
||||||
|
this.arguments = options.arguments;
|
||||||
|
|
||||||
|
this.listeners = {
|
||||||
|
add: [],
|
||||||
|
remove: []
|
||||||
|
};
|
||||||
|
|
||||||
|
this.trackHistoricalTelemetry();
|
||||||
|
this.trackSubscriptionTelemetry();
|
||||||
|
|
||||||
|
this.subscribeToBounds();
|
||||||
|
this.subscribeToTimeSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
// should we wait to track history until an 'add' listener is added?
|
||||||
|
async trackHistoricalTelemetry() {
|
||||||
|
if (!this.historicalProvider) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove for reset
|
||||||
|
if (this.boundedTelemetry.length !== 0) {
|
||||||
|
this.emit('remove', this.boundedTelemetry);
|
||||||
|
this.boundedTelemetry = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
let historicalData = await this.historicalProvider.request.apply(this.domainObject, this.arguments).catch((rejected) => {
|
||||||
|
this.openmct.notifications.error('Error requesting telemetry data, see console for details');
|
||||||
|
console.error(rejected);
|
||||||
|
|
||||||
|
return Promise.reject(rejected);
|
||||||
|
});
|
||||||
|
|
||||||
|
// make sure it wasn't rejected
|
||||||
|
if (Array.isArray(historicalData)) {
|
||||||
|
// reset on requests, should only happen on initial load,
|
||||||
|
// bounds manually changed and time system changes
|
||||||
|
this.boundedTelemetry = historicalData;
|
||||||
|
this.emit('add', [...this.boundedTelemetry]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trackSubscriptionTelemetry() {
|
||||||
|
if (!this.subscriptionProvider) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.subscriptionService = new TelemetrySubscriptionService(this.openmct);
|
||||||
|
this.unsubscribe = this.subscriptionService.subscribe(
|
||||||
|
this.domainObject,
|
||||||
|
this.processNewTelemetry,
|
||||||
|
this.subscriptionProvider,
|
||||||
|
this.arguments
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// utilized by telemetry provider to add more data
|
||||||
|
addPage(telemetryData) {
|
||||||
|
this.processNewTelemetry(telemetryData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// used to sort any new telemetry (add/page, historical, subscription)
|
||||||
|
processNewTelemetry(telemetryData) {
|
||||||
|
|
||||||
|
let data = Array.isArray(telemetryData) ? telemetryData : [telemetryData];
|
||||||
|
let parsedValue;
|
||||||
|
let beforeStartOfBounds;
|
||||||
|
let afterEndOfBounds;
|
||||||
|
let added = [];
|
||||||
|
|
||||||
|
for (let datum of data) {
|
||||||
|
parsedValue = this.parseTime(datum);
|
||||||
|
beforeStartOfBounds = parsedValue < this.lastBounds.start;
|
||||||
|
afterEndOfBounds = parsedValue > this.lastBounds.end;
|
||||||
|
|
||||||
|
if (!afterEndOfBounds && !beforeStartOfBounds) {
|
||||||
|
if (!this.boundedTelemetry.includes(datum)) {
|
||||||
|
this.boundedTelemetry.push(datum);
|
||||||
|
added.push(datum);
|
||||||
|
}
|
||||||
|
} else if (afterEndOfBounds) {
|
||||||
|
this.futureBuffer.push(datum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (added.length) {
|
||||||
|
this.emit('add', added);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns a boolean if there is more telemetry within the time bounds
|
||||||
|
// if the provider supports it
|
||||||
|
hasMorePages() {
|
||||||
|
return this.historicalProvider
|
||||||
|
&& this.historicalProvider.supportsPaging()
|
||||||
|
&& this.historicalProvider.hasMorePages(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// will return the next "page" of telemetry if the provider supports it
|
||||||
|
nextPage() {
|
||||||
|
if (!this.historicalProvider || !this.historicalProvider.supportsPaging()) {
|
||||||
|
throw new Error('Provider does not support paging');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.historicalProvider.nextPage(this.arguments, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// when user changes bounds, or when bounds increment from a tick
|
||||||
|
bounds(bounds, isTick) {
|
||||||
|
|
||||||
|
this.lastBounds = bounds;
|
||||||
|
|
||||||
|
if (isTick) {
|
||||||
|
// need to check futureBuffer and need to check
|
||||||
|
// if anything has fallen out of bounds
|
||||||
|
} else {
|
||||||
|
// TODO: also reset right?
|
||||||
|
// need to reset and request history again
|
||||||
|
// no need to mess with subscription
|
||||||
|
}
|
||||||
|
|
||||||
|
let startChanged = this.lastBounds.start !== bounds.start;
|
||||||
|
let endChanged = this.lastBounds.end !== bounds.end;
|
||||||
|
|
||||||
|
let startIndex = 0;
|
||||||
|
let endIndex = 0;
|
||||||
|
|
||||||
|
let discarded = [];
|
||||||
|
let added = [];
|
||||||
|
let testValue = {
|
||||||
|
datum: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.lastBounds = bounds;
|
||||||
|
|
||||||
|
if (startChanged) {
|
||||||
|
testValue.datum[this.sortOptions.key] = bounds.start;
|
||||||
|
// Calculate the new index of the first item within the bounds
|
||||||
|
startIndex = this.sortedIndex(this.rows, testValue);
|
||||||
|
discarded = this.rows.splice(0, startIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endChanged) {
|
||||||
|
testValue.datum[this.sortOptions.key] = bounds.end;
|
||||||
|
// Calculate the new index of the last item in bounds
|
||||||
|
endIndex = this.sortedLastIndex(this.futureBuffer.rows, testValue);
|
||||||
|
added = this.futureBuffer.rows.splice(0, endIndex);
|
||||||
|
added.forEach((datum) => this.rows.push(datum));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (discarded.length > 0) {
|
||||||
|
/**
|
||||||
|
* A `discarded` event is emitted when telemetry data fall out of
|
||||||
|
* bounds due to a bounds change event
|
||||||
|
* @type {object[]} discarded the telemetry data
|
||||||
|
* discarded as a result of the bounds change
|
||||||
|
*/
|
||||||
|
this.emit('remove', discarded);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (added.length > 0) {
|
||||||
|
/**
|
||||||
|
* An `added` event is emitted when a bounds change results in
|
||||||
|
* received telemetry falling within the new bounds.
|
||||||
|
* @type {object[]} added the telemetry data that is now within bounds
|
||||||
|
*/
|
||||||
|
this.emit('add', added);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timeSystem(timeSystem) {
|
||||||
|
let timeKey = timeSystem.key;
|
||||||
|
let formatter = this.openmct.telemetry.getValueFormatter({
|
||||||
|
key: timeKey,
|
||||||
|
source: timeKey,
|
||||||
|
format: timeKey
|
||||||
|
});
|
||||||
|
|
||||||
|
this.parseTime = formatter.parse;
|
||||||
|
|
||||||
|
// TODO: Reset right?
|
||||||
|
}
|
||||||
|
|
||||||
|
on(event, callback, context) {
|
||||||
|
if (!this.listeners[event]) {
|
||||||
|
throw new Error('Event not supported by Telemetry Collections: ' + event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.listeners[event].includes(callback)) {
|
||||||
|
throw new Error('Tried to add a listener that is already registered');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.listeners[event].push({
|
||||||
|
callback: callback,
|
||||||
|
context: context
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unregister TelemetryCollection events.
|
||||||
|
off(event, callback) {
|
||||||
|
if (!this.listeners[event]) {
|
||||||
|
throw new Error('Event not supported by Telemetry Collections: ' + event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.listeners[event].includes(callback)) {
|
||||||
|
throw new Error('Tried to remove a listener that does not exist');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.listeners[event].remove(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(event, payload) {
|
||||||
|
if (!this.listeners[event].length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
payload = [...payload];
|
||||||
|
|
||||||
|
this.listeners[event].forEach((listener) => {
|
||||||
|
if (listener.context) {
|
||||||
|
listener.callback.apply(listener.context, payload);
|
||||||
|
} else {
|
||||||
|
listener.callback(payload);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribeToBounds() {
|
||||||
|
this.openmct.time.on('bounds', this.bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsubscribeFromBounds() {
|
||||||
|
this.openmct.time.off('bounds', this.bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribeToTimeSystem() {
|
||||||
|
this.openmct.time.on('timeSystem', this.timeSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsubscribeFromTimeSystem() {
|
||||||
|
this.openmct.time.off('bounds', this.timeSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.unsubscribeFromBounds();
|
||||||
|
this.unsubscribeFromTimeSystem();
|
||||||
|
if (this.unsubscribe) {
|
||||||
|
this.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
src/api/telemetry/TelemetrySubscriptionService.js
Normal file
72
src/api/telemetry/TelemetrySubscriptionService.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import objectUtils from 'objectUtils';
|
||||||
|
class TelemetrySubscriptionService {
|
||||||
|
constructor(openmct) {
|
||||||
|
if (!TelemetrySubscriptionService.instance) {
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.subscriptionCache = {};
|
||||||
|
|
||||||
|
TelemetrySubscriptionService.instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TelemetrySubscriptionService.instance; // eslint-disable-line no-constructor-return
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribe(domainObject, callback, provider, options) {
|
||||||
|
const keyString = objectUtils.makeKeyString(domainObject.identifier);
|
||||||
|
let subscriber = this.subscriptionCache[keyString];
|
||||||
|
|
||||||
|
if (!subscriber) {
|
||||||
|
subscriber = this.subscriptionCache[keyString] = {
|
||||||
|
callbacks: [callback]
|
||||||
|
};
|
||||||
|
|
||||||
|
subscriber.unsubscribe = provider
|
||||||
|
.subscribe(domainObject, function (value) {
|
||||||
|
subscriber.callbacks.forEach(function (cb) {
|
||||||
|
cb(value);
|
||||||
|
});
|
||||||
|
}, options);
|
||||||
|
} else {
|
||||||
|
subscriber.callbacks.push(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
subscriber.callbacks = subscriber.callbacks.filter((cb) => {
|
||||||
|
return cb !== callback;
|
||||||
|
});
|
||||||
|
if (subscriber.callbacks.length === 0) {
|
||||||
|
subscriber.unsubscribe();
|
||||||
|
delete this.subscriptionCache[keyString];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function instance(openmct) {
|
||||||
|
return new TelemetrySubscriptionService(openmct);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default instance;
|
@ -137,7 +137,8 @@ export default {
|
|||||||
refreshCSS: false,
|
refreshCSS: false,
|
||||||
keyString: undefined,
|
keyString: undefined,
|
||||||
focusedImageIndex: undefined,
|
focusedImageIndex: undefined,
|
||||||
numericDuration: undefined
|
numericDuration: undefined,
|
||||||
|
telemetryCollection: undefined
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -222,6 +223,7 @@ export default {
|
|||||||
// kickoff
|
// kickoff
|
||||||
this.subscribe();
|
this.subscribe();
|
||||||
this.requestHistory();
|
this.requestHistory();
|
||||||
|
this.requestTelemetry();
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
this.scrollToRight();
|
this.scrollToRight();
|
||||||
@ -353,6 +355,15 @@ export default {
|
|||||||
this.requestHistory();
|
this.requestHistory();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async requestTelemetry() {
|
||||||
|
this.telemetryCollection = await this.openmct.telemetry.requestTelemetryCollection(this.domainObject);
|
||||||
|
this.telemetryCollection.on('add', (data) => {
|
||||||
|
console.log('added data', data);
|
||||||
|
});
|
||||||
|
this.telemetryCollection.on('remove', (data) => {
|
||||||
|
console.log('removed data', data);
|
||||||
|
});
|
||||||
|
},
|
||||||
async requestHistory() {
|
async requestHistory() {
|
||||||
let bounds = this.openmct.time.bounds();
|
let bounds = this.openmct.time.bounds();
|
||||||
this.requestCount++;
|
this.requestCount++;
|
||||||
|
@ -42,6 +42,15 @@ export default {
|
|||||||
navigateToPath: {
|
navigateToPath: {
|
||||||
type: String,
|
type: String,
|
||||||
default: undefined
|
default: undefined
|
||||||
|
},
|
||||||
|
liteObject: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
beforeInteraction: {
|
||||||
|
type: Function,
|
||||||
|
required: false,
|
||||||
|
default: undefined
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -52,7 +61,8 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
typeClass() {
|
typeClass() {
|
||||||
let type = this.openmct.types.get(this.observedObject.type);
|
let domainObjectType = this.liteObject ? this.domainObject.type : this.observedObject.type;
|
||||||
|
let type = this.openmct.types.get(domainObjectType);
|
||||||
if (!type) {
|
if (!type) {
|
||||||
return 'icon-object-unknown';
|
return 'icon-object-unknown';
|
||||||
}
|
}
|
||||||
@ -64,13 +74,15 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.observedObject) {
|
// if it's a liteObject nothing to observe
|
||||||
|
if (this.observedObject && !this.liteObject) {
|
||||||
let removeListener = this.openmct.objects.observe(this.observedObject, '*', (newObject) => {
|
let removeListener = this.openmct.objects.observe(this.observedObject, '*', (newObject) => {
|
||||||
this.observedObject = newObject;
|
this.observedObject = newObject;
|
||||||
});
|
});
|
||||||
this.$once('hook:destroyed', removeListener);
|
this.$once('hook:destroyed', removeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// liteObjects do have identifiers, so statuses can be observed
|
||||||
this.removeStatusListener = this.openmct.status.observe(this.observedObject.identifier, this.setStatus);
|
this.removeStatusListener = this.openmct.status.observe(this.observedObject.identifier, this.setStatus);
|
||||||
this.status = this.openmct.status.get(this.observedObject.identifier);
|
this.status = this.openmct.status.get(this.observedObject.identifier);
|
||||||
this.previewAction = new PreviewAction(this.openmct);
|
this.previewAction = new PreviewAction(this.openmct);
|
||||||
@ -79,21 +91,45 @@ export default {
|
|||||||
this.removeStatusListener();
|
this.removeStatusListener();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
navigateOrPreview(event) {
|
async navigateOrPreview(event) {
|
||||||
if (this.openmct.editor.isEditing()) {
|
// skip if editing or is a lite object with an interaction function
|
||||||
|
if (this.openmct.editor.isEditing() || !(this.liteObject && this.beforeInteraction)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (this.openmct.editor.isEditing()) {
|
||||||
this.preview();
|
this.preview();
|
||||||
|
} else if (this.liteObject && this.beforeInteraction) {
|
||||||
|
let fullObjectInfo = await this.getFullObjectInfo();
|
||||||
|
// need to update when new route functions are merged (back button PR)
|
||||||
|
window.location.href = '#/browse/' + fullObjectInfo.navigationPath;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
preview() {
|
async preview() {
|
||||||
if (this.previewAction.appliesTo(this.objectPath)) {
|
let objectPath = this.objectPath;
|
||||||
this.previewAction.invoke(this.objectPath);
|
|
||||||
|
if (this.liteObject && this.beforeInteraction) {
|
||||||
|
let fullObjectInfo = await this.getFullObjectInfo();
|
||||||
|
objectPath = fullObjectInfo.objectPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.previewAction.appliesTo(objectPath)) {
|
||||||
|
this.previewAction.invoke(objectPath);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dragStart(event) {
|
dragStart(event) {
|
||||||
|
const LITE_DOMAIN_OBJECT_TYPE = "openmct/domain-object-lite";
|
||||||
|
|
||||||
let navigatedObject = this.openmct.router.path[0];
|
let navigatedObject = this.openmct.router.path[0];
|
||||||
let serializedPath = JSON.stringify(this.objectPath);
|
|
||||||
let keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
let keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||||
|
let serializedPath = JSON.stringify(this.objectPath);
|
||||||
|
|
||||||
|
if (this.liteObject) {
|
||||||
|
event.dataTransfer.setData(LITE_DOMAIN_OBJECT_TYPE, JSON.stringify(this.domainObject.identifier));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cannot inspect data transfer objects on dragover/dragenter so impossible to determine composability at
|
* Cannot inspect data transfer objects on dragover/dragenter so impossible to determine composability at
|
||||||
@ -108,6 +144,21 @@ export default {
|
|||||||
// (eg. notabook.)
|
// (eg. notabook.)
|
||||||
event.dataTransfer.setData("openmct/domain-object-path", serializedPath);
|
event.dataTransfer.setData("openmct/domain-object-path", serializedPath);
|
||||||
event.dataTransfer.setData(`openmct/domain-object/${keyString}`, this.domainObject);
|
event.dataTransfer.setData(`openmct/domain-object/${keyString}`, this.domainObject);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getFullObjectInfo() {
|
||||||
|
let fullObjectInfo = await this.beforeInteraction();
|
||||||
|
let objectPath = fullObjectInfo.objectPath;
|
||||||
|
let navigationPath = objectPath
|
||||||
|
.reverse()
|
||||||
|
.map(object =>
|
||||||
|
this.openmct.objects.makeKeyString(object.identifier)
|
||||||
|
).join('/');
|
||||||
|
|
||||||
|
fullObjectInfo.objectPath = objectPath;
|
||||||
|
fullObjectInfo.navigationPath = navigationPath;
|
||||||
|
|
||||||
|
return fullObjectInfo;
|
||||||
},
|
},
|
||||||
setStatus(status) {
|
setStatus(status) {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
|
@ -98,7 +98,11 @@
|
|||||||
:style="scrollableStyles()"
|
:style="scrollableStyles()"
|
||||||
@scroll="scrollItems"
|
@scroll="scrollItems"
|
||||||
>
|
>
|
||||||
<div :style="{ height: childrenHeight + 'px' }">
|
<!-- Regular Tree Items -->
|
||||||
|
<div
|
||||||
|
v-if="!activeSearch"
|
||||||
|
:style="{ height: childrenHeight + 'px' }"
|
||||||
|
>
|
||||||
<tree-item
|
<tree-item
|
||||||
v-for="(treeItem, index) in visibleItems"
|
v-for="(treeItem, index) in visibleItems"
|
||||||
:key="treeItem.id"
|
:key="treeItem.id"
|
||||||
@ -108,7 +112,32 @@
|
|||||||
:item-index="index"
|
:item-index="index"
|
||||||
:item-height="itemHeight"
|
:item-height="itemHeight"
|
||||||
:virtual-scroll="true"
|
:virtual-scroll="true"
|
||||||
:show-down="activeSearch ? false : true"
|
:show-down="true"
|
||||||
|
@expanded="beginNavigationRequest('handleExpanded', treeItem)"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-if="showNoItems"
|
||||||
|
:style="indicatorLeftOffset"
|
||||||
|
class="c-tree__item c-tree__item--empty"
|
||||||
|
>
|
||||||
|
No items
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Search Result Items (Index Only) -->
|
||||||
|
<div
|
||||||
|
v-if="activeSearch"
|
||||||
|
:style="{ height: childrenHeight + 'px' }"
|
||||||
|
>
|
||||||
|
<tree-item-lite
|
||||||
|
v-for="(treeItem, index) in visibleItems"
|
||||||
|
:key="treeItem.id"
|
||||||
|
:node="treeItem"
|
||||||
|
:left-offset="itemLeftOffset"
|
||||||
|
:item-offset="itemOffset"
|
||||||
|
:item-index="index"
|
||||||
|
:item-height="itemHeight"
|
||||||
|
:virtual-scroll="true"
|
||||||
|
:show-down="false"
|
||||||
@expanded="beginNavigationRequest('handleExpanded', treeItem)"
|
@expanded="beginNavigationRequest('handleExpanded', treeItem)"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
@ -131,6 +160,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import treeItem from './tree-item.vue';
|
import treeItem from './tree-item.vue';
|
||||||
|
import treeItemLite from './tree-item-lite.vue';
|
||||||
import search from '../components/search.vue';
|
import search from '../components/search.vue';
|
||||||
import objectUtils from 'objectUtils';
|
import objectUtils from 'objectUtils';
|
||||||
import uuid from 'uuid';
|
import uuid from 'uuid';
|
||||||
@ -145,7 +175,8 @@ export default {
|
|||||||
name: 'MctTree',
|
name: 'MctTree',
|
||||||
components: {
|
components: {
|
||||||
search,
|
search,
|
||||||
treeItem
|
treeItem,
|
||||||
|
treeItemLite
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
syncTreeNavigation: {
|
syncTreeNavigation: {
|
||||||
@ -596,6 +627,21 @@ export default {
|
|||||||
navigationPath
|
navigationPath
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
buildTreeItemLite(indexResult) {
|
||||||
|
let liteObject = {
|
||||||
|
identifier: objectUtils.parseKeyString(indexResult.id),
|
||||||
|
name: indexResult.name,
|
||||||
|
type: indexResult.type
|
||||||
|
};
|
||||||
|
let navigationPath = '';
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: indexResult.id,
|
||||||
|
object: liteObject,
|
||||||
|
objectPath: [],
|
||||||
|
navigationPath
|
||||||
|
};
|
||||||
|
},
|
||||||
// domainObject: the item we're building the path for (will be used in url and links)
|
// domainObject: the item we're building the path for (will be used in url and links)
|
||||||
// objects: array of domainObjects representing path to domainobject passed in
|
// objects: array of domainObjects representing path to domainobject passed in
|
||||||
buildNavigationPath(domainObject, objects) {
|
buildNavigationPath(domainObject, objects) {
|
||||||
@ -693,30 +739,37 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async getSearchResults() {
|
async getSearchResults() {
|
||||||
let results = await this.searchService.query(this.searchValue);
|
let results = await this.searchService.queryLite(this.searchValue);
|
||||||
this.searchResultItems = [];
|
this.searchResultItems = [];
|
||||||
|
|
||||||
|
// build out tree-item-lite results
|
||||||
for (let i = 0; i < results.hits.length; i++) {
|
for (let i = 0; i < results.hits.length; i++) {
|
||||||
let result = results.hits[i];
|
let result = results.hits[i];
|
||||||
let newStyleObject = objectUtils.toNewFormat(result.object.getModel(), result.object.getId());
|
let resultObject = this.buildTreeItemLite(result);
|
||||||
let objectPath = await this.openmct.objects.getOriginalPath(newStyleObject.identifier);
|
|
||||||
|
|
||||||
// removing the item itself, as the path we pass to buildTreeItem is a parent path
|
|
||||||
objectPath.shift();
|
|
||||||
|
|
||||||
// if root, remove, we're not using in object path for tree
|
|
||||||
let lastObject = objectPath.length ? objectPath[objectPath.length - 1] : false;
|
|
||||||
if (lastObject && lastObject.type === 'root') {
|
|
||||||
objectPath.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// we reverse the objectPath in the tree, so have to do it here first,
|
|
||||||
// since this one is already in the correct direction
|
|
||||||
let resultObject = this.buildTreeItem(newStyleObject, objectPath.reverse());
|
|
||||||
|
|
||||||
this.searchResultItems.push(resultObject);
|
this.searchResultItems.push(resultObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for (let i = 0; i < results.hits.length; i++) {
|
||||||
|
// let result = results.hits[i];
|
||||||
|
// let newStyleObject = objectUtils.toNewFormat(result.object.getModel(), result.object.getId());
|
||||||
|
// let objectPath = await this.openmct.objects.getOriginalPath(newStyleObject.identifier);
|
||||||
|
|
||||||
|
// // removing the item itself, as the path we pass to buildTreeItem is a parent path
|
||||||
|
// objectPath.shift();
|
||||||
|
|
||||||
|
// // if root, remove, we're not using in object path for tree
|
||||||
|
// let lastObject = objectPath.length ? objectPath[objectPath.length - 1] : false;
|
||||||
|
// if (lastObject && lastObject.type === 'root') {
|
||||||
|
// objectPath.pop();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // we reverse the objectPath in the tree, so have to do it here first,
|
||||||
|
// // since this one is already in the correct direction
|
||||||
|
// let resultObject = this.buildTreeItem(newStyleObject, objectPath.reverse());
|
||||||
|
|
||||||
|
// this.searchResultItems.push(resultObject);
|
||||||
|
// }
|
||||||
|
|
||||||
this.searchLoading = false;
|
this.searchLoading = false;
|
||||||
},
|
},
|
||||||
searchTree(value) {
|
searchTree(value) {
|
||||||
|
108
src/ui/layout/tree-item-lite.vue
Normal file
108
src/ui/layout/tree-item-lite.vue
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
ref="me"
|
||||||
|
:style="{
|
||||||
|
'top': virtualScroll ? itemTop : 'auto',
|
||||||
|
'position': virtualScroll ? 'absolute' : 'relative'
|
||||||
|
}"
|
||||||
|
class="c-tree__item-h"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="c-tree__item"
|
||||||
|
>
|
||||||
|
<view-control
|
||||||
|
v-model="expanded"
|
||||||
|
class="c-tree__item__view-control"
|
||||||
|
:control-class="'c-nav__up'"
|
||||||
|
:enabled="showUp"
|
||||||
|
/>
|
||||||
|
<object-label
|
||||||
|
:domain-object="node.object"
|
||||||
|
:object-path="node.objectPath"
|
||||||
|
:navigate-to-path="''"
|
||||||
|
:style="{ paddingLeft: leftOffset }"
|
||||||
|
:lite-object="true"
|
||||||
|
:before-interaction="onInteraction"
|
||||||
|
/>
|
||||||
|
<view-control
|
||||||
|
v-model="expanded"
|
||||||
|
class="c-tree__item__view-control"
|
||||||
|
:control-class="'c-nav__down'"
|
||||||
|
:enabled="showDown"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import viewControl from '../components/viewControl.vue';
|
||||||
|
import ObjectLabel from '../components/ObjectLabel.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TreeItem',
|
||||||
|
inject: ['openmct'],
|
||||||
|
components: {
|
||||||
|
viewControl,
|
||||||
|
ObjectLabel
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
node: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
leftOffset: {
|
||||||
|
type: String,
|
||||||
|
default: '0px'
|
||||||
|
},
|
||||||
|
showUp: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
showDown: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
itemIndex: {
|
||||||
|
type: Number,
|
||||||
|
required: false,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
itemOffset: {
|
||||||
|
type: Number,
|
||||||
|
required: false,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
itemHeight: {
|
||||||
|
type: Number,
|
||||||
|
required: false,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
virtualScroll: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
expanded: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
itemTop() {
|
||||||
|
return (this.itemOffset + this.itemIndex) * this.itemHeight + 'px';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async onInteraction() {
|
||||||
|
let domainObject = await this.openmct.objects.get(this.node.object.identifier);
|
||||||
|
let objectPath = await this.openmct.objects.getOriginalPath(this.node.object.identifier);
|
||||||
|
objectPath.pop();
|
||||||
|
|
||||||
|
return {
|
||||||
|
domainObject,
|
||||||
|
objectPath
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@ -13,25 +13,35 @@ export default {
|
|||||||
this.$el.addEventListener('contextmenu', this.showContextMenu);
|
this.$el.addEventListener('contextmenu', this.showContextMenu);
|
||||||
|
|
||||||
function updateObject(oldObject, newObject) {
|
function updateObject(oldObject, newObject) {
|
||||||
|
if (oldObject.name == 'drag n drop sg') console.log({ oldObject, newObject});
|
||||||
Object.assign(oldObject, newObject);
|
Object.assign(oldObject, newObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.liteObject) {
|
||||||
this.objectPath.forEach(object => {
|
this.objectPath.forEach(object => {
|
||||||
if (object) {
|
if (object) {
|
||||||
this.$once('hook:destroyed',
|
this.$once('hook:destroyed',
|
||||||
this.openmct.objects.observe(object, '*', updateObject.bind(this, object)));
|
this.openmct.objects.observe(object, '*', updateObject.bind(this, object)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.$el.removeEventListener('contextMenu', this.showContextMenu);
|
this.$el.removeEventListener('contextMenu', this.showContextMenu);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showContextMenu(event) {
|
async showContextMenu(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
let actionsCollection = this.openmct.actions.get(this.objectPath);
|
let objectPath = this.objectPath;
|
||||||
|
|
||||||
|
if (this.liteObject && this.beforeInteraction) {
|
||||||
|
let fullObjectInfo = await this.beforeInteraction();
|
||||||
|
objectPath = fullObjectInfo.objectPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
let actionsCollection = this.openmct.actions.get(objectPath);
|
||||||
let actions = actionsCollection.getVisibleActions();
|
let actions = actionsCollection.getVisibleActions();
|
||||||
let sortedActions = this.openmct.actions._groupAndSortActions(actions);
|
let sortedActions = this.openmct.actions._groupAndSortActions(actions);
|
||||||
|
|
||||||
|
84
src/utils/EnhancedDataTransfer.js
Normal file
84
src/utils/EnhancedDataTransfer.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import uuid from 'uuid';
|
||||||
|
|
||||||
|
const ENHANCED_DATA_TRANSFER_TYPE = "openmct/enhanced-data-transfer-id/";
|
||||||
|
|
||||||
|
const _enhancedEventData = {};
|
||||||
|
const _storedPromises = {};
|
||||||
|
|
||||||
|
const EnhancedDataTransfer = {
|
||||||
|
start: (event) => {
|
||||||
|
const eventId = uuid();
|
||||||
|
event.dataTransfer.setData(ENHANCED_DATA_TRANSFER_TYPE + eventId, eventId);
|
||||||
|
|
||||||
|
_enhancedEventData[eventId] = {};
|
||||||
|
|
||||||
|
let eventResolve;
|
||||||
|
let eventReject;
|
||||||
|
const eventPromise = new Promise((resolve, reject) => {
|
||||||
|
eventResolve = resolve;
|
||||||
|
eventReject = reject;
|
||||||
|
});
|
||||||
|
|
||||||
|
_storedPromises[eventId] = eventPromise;
|
||||||
|
|
||||||
|
return {
|
||||||
|
setData: EnhancedDataTransfer._setData(eventId),
|
||||||
|
finish: () => eventResolve(),
|
||||||
|
fail: () => eventReject(),
|
||||||
|
eventId
|
||||||
|
};
|
||||||
|
},
|
||||||
|
load: async (event) => {
|
||||||
|
|
||||||
|
const eventId = event.dataTransfer.types
|
||||||
|
.filter(type => type.startsWith(ENHANCED_DATA_TRANSFER_TYPE))
|
||||||
|
.map(type => type.substring(ENHANCED_DATA_TRANSFER_TYPE.length))[0];
|
||||||
|
|
||||||
|
if (!eventId) {
|
||||||
|
throw new Error('Event is not an enhanced data transfer event');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_storedPromises[eventId] !== 'complete') {
|
||||||
|
try {
|
||||||
|
await _storedPromises[eventId];
|
||||||
|
_storedPromises[eventId] = 'complete';
|
||||||
|
} catch (err) {
|
||||||
|
delete _storedPromises[eventId];
|
||||||
|
console.warn(err);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getData: EnhancedDataTransfer._getData(eventId),
|
||||||
|
allData: EnhancedDataTransfer._allData(eventId),
|
||||||
|
types: () => Object.keys(_enhancedEventData[eventId]),
|
||||||
|
delete: EnhancedDataTransfer._delete(eventId)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
_setData: (eventId) => {
|
||||||
|
return (key, value) => {
|
||||||
|
_enhancedEventData[eventId][key] = value;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
_getData: (eventId) => {
|
||||||
|
return key => _enhancedEventData[eventId][key];
|
||||||
|
},
|
||||||
|
_allData: (eventId) => {
|
||||||
|
return () => _enhancedEventData[eventId];
|
||||||
|
},
|
||||||
|
_delete: (eventId) => {
|
||||||
|
return () => {
|
||||||
|
delete _enhancedEventData[eventId];
|
||||||
|
delete _storedPromises[eventId];
|
||||||
|
};
|
||||||
|
},
|
||||||
|
isEnhancedDataTransfer: (event) => {
|
||||||
|
return event.dataTransfer.types
|
||||||
|
.filter(type => type.startsWith(ENHANCED_DATA_TRANSFER_TYPE)).length > 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.freeze(EnhancedDataTransfer);
|
||||||
|
export default EnhancedDataTransfer;
|
Reference in New Issue
Block a user