mirror of
https://github.com/nasa/openmct.git
synced 2024-12-19 05:07:52 +00:00
[Plugin] Add imported root plugin (#1784)
* [Plugin] Add static root plugin Add StaticRootPlugin, which allows a file exported with the ImportExport plugin to be mounted as a static root in Open MCT. Allows deployers to configure standard displays for deployments by exporting displays they have already created. * Include all src files
This commit is contained in:
parent
39a7f43cd0
commit
f9060a485d
@ -37,14 +37,13 @@ module.exports = function(config) {
|
|||||||
{pattern: 'bower_components/**/*.js', included: false},
|
{pattern: 'bower_components/**/*.js', included: false},
|
||||||
{pattern: 'node_modules/d3-*/**/*.js', included: false},
|
{pattern: 'node_modules/d3-*/**/*.js', included: false},
|
||||||
{pattern: 'node_modules/vue/**/*.js', included: false},
|
{pattern: 'node_modules/vue/**/*.js', included: false},
|
||||||
{pattern: 'src/**/*.js', included: false},
|
{pattern: 'src/**/*', included: false},
|
||||||
{pattern: 'example/**/*.html', included: false},
|
{pattern: 'example/**/*.html', included: false},
|
||||||
{pattern: 'example/**/*.js', included: false},
|
{pattern: 'example/**/*.js', included: false},
|
||||||
{pattern: 'example/**/*.json', included: false},
|
{pattern: 'example/**/*.json', included: false},
|
||||||
{pattern: 'platform/**/*.js', included: false},
|
{pattern: 'platform/**/*.js', included: false},
|
||||||
{pattern: 'warp/**/*.js', included: false},
|
{pattern: 'warp/**/*.js', included: false},
|
||||||
{pattern: 'platform/**/*.html', included: false},
|
{pattern: 'platform/**/*.html', included: false},
|
||||||
{pattern: 'src/**/*.html', included: false},
|
|
||||||
'test-main.js'
|
'test-main.js'
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -31,7 +31,8 @@ define([
|
|||||||
'./summaryWidget/plugin',
|
'./summaryWidget/plugin',
|
||||||
'./URLIndicatorPlugin/URLIndicatorPlugin',
|
'./URLIndicatorPlugin/URLIndicatorPlugin',
|
||||||
'./telemetryMean/plugin',
|
'./telemetryMean/plugin',
|
||||||
'./plot/plugin'
|
'./plot/plugin',
|
||||||
|
'./staticRootPlugin/plugin'
|
||||||
], function (
|
], function (
|
||||||
_,
|
_,
|
||||||
UTCTimeSystem,
|
UTCTimeSystem,
|
||||||
@ -43,7 +44,8 @@ define([
|
|||||||
SummaryWidget,
|
SummaryWidget,
|
||||||
URLIndicatorPlugin,
|
URLIndicatorPlugin,
|
||||||
TelemetryMean,
|
TelemetryMean,
|
||||||
PlotPlugin
|
PlotPlugin,
|
||||||
|
StaticRootPlugin
|
||||||
) {
|
) {
|
||||||
var bundleMap = {
|
var bundleMap = {
|
||||||
CouchDB: 'platform/persistence/couch',
|
CouchDB: 'platform/persistence/couch',
|
||||||
@ -66,6 +68,8 @@ define([
|
|||||||
|
|
||||||
plugins.ImportExport = ImportExport;
|
plugins.ImportExport = ImportExport;
|
||||||
|
|
||||||
|
plugins.StaticRootPlugin = StaticRootPlugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A tabular view showing the latest values of multiple telemetry points at
|
* A tabular view showing the latest values of multiple telemetry points at
|
||||||
* once. Formatted so that labels and values are aligned.
|
* once. Formatted so that labels and values are aligned.
|
||||||
|
78
src/plugins/staticRootPlugin/StaticModelProvider.js
Normal file
78
src/plugins/staticRootPlugin/StaticModelProvider.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
define([
|
||||||
|
'../../api/objects/object-utils'
|
||||||
|
], function (
|
||||||
|
objectUtils
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* Transforms an import json blob into a object map that can be used to
|
||||||
|
* provide objects. Rewrites root identifier in import data with provided
|
||||||
|
* rootIdentifier, and rewrites all child object identifiers so that they
|
||||||
|
* exist in the same namespace as the rootIdentifier.
|
||||||
|
*/
|
||||||
|
function rewriteObjectIdentifiers(importData, rootIdentifier) {
|
||||||
|
var rootId = importData.rootId;
|
||||||
|
var objectString = JSON.stringify(importData.openmct);
|
||||||
|
|
||||||
|
Object.keys(importData.openmct).forEach(function (originalId, i) {
|
||||||
|
var newId;
|
||||||
|
if (originalId === rootId) {
|
||||||
|
newId = objectUtils.makeKeyString(rootIdentifier);
|
||||||
|
} else {
|
||||||
|
newId = objectUtils.makeKeyString({
|
||||||
|
namespace: rootIdentifier.namespace,
|
||||||
|
key: i
|
||||||
|
});
|
||||||
|
}
|
||||||
|
while (objectString.indexOf(originalId) !== -1) {
|
||||||
|
objectString = objectString.replace(
|
||||||
|
'"' + originalId + '"',
|
||||||
|
'"' + newId + '"'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return JSON.parse(objectString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convets all objects in an object make from old format objects to new
|
||||||
|
* format objects.
|
||||||
|
*/
|
||||||
|
function convertToNewObjects(oldObjectMap) {
|
||||||
|
return Object.keys(oldObjectMap)
|
||||||
|
.reduce(function (newObjectMap, key) {
|
||||||
|
newObjectMap[key] = objectUtils.toNewFormat(oldObjectMap[key], key);
|
||||||
|
return newObjectMap;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the root location correctly for a top-level object */
|
||||||
|
function setRootLocation(objectMap, rootIdentifier) {
|
||||||
|
objectMap[objectUtils.makeKeyString(rootIdentifier)].location = 'ROOT';
|
||||||
|
return objectMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes importData (as provided by the ImportExport plugin) and exposes
|
||||||
|
* an object provider to fetch those objects.
|
||||||
|
*/
|
||||||
|
function StaticModelProvider(importData, rootIdentifier) {
|
||||||
|
var oldFormatObjectMap = rewriteObjectIdentifiers(importData, rootIdentifier);
|
||||||
|
var newFormatObjectMap = convertToNewObjects(oldFormatObjectMap);
|
||||||
|
this.objectMap = setRootLocation(newFormatObjectMap, rootIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard "Get".
|
||||||
|
*/
|
||||||
|
StaticModelProvider.prototype.get = function (identifier) {
|
||||||
|
var keyString = objectUtils.makeKeyString(identifier);
|
||||||
|
if (this.objectMap[keyString]) {
|
||||||
|
return this.objectMap[keyString];
|
||||||
|
}
|
||||||
|
throw new Error(keyString + ' not found in import models.');
|
||||||
|
};
|
||||||
|
|
||||||
|
return StaticModelProvider;
|
||||||
|
|
||||||
|
});
|
133
src/plugins/staticRootPlugin/StaticModelProviderSpec.js
Normal file
133
src/plugins/staticRootPlugin/StaticModelProviderSpec.js
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
define([
|
||||||
|
'./StaticModelProvider',
|
||||||
|
'text!./static-provider-test.json'
|
||||||
|
], function (
|
||||||
|
StaticModelProvider,
|
||||||
|
testStaticDataText
|
||||||
|
) {
|
||||||
|
|
||||||
|
describe('StaticModelProvider', function () {
|
||||||
|
|
||||||
|
var staticProvider;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
var staticData = JSON.parse(testStaticDataText);
|
||||||
|
staticProvider = new StaticModelProvider(staticData, {
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: 'root'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('rootObject', function () {
|
||||||
|
var rootModel;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
rootModel = staticProvider.get({
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: 'root'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is located at top level', function () {
|
||||||
|
expect(rootModel.location).toBe('ROOT');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has new-format identifier', function () {
|
||||||
|
expect(rootModel.identifier).toEqual({
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: 'root'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has new-format composition', function () {
|
||||||
|
expect(rootModel.composition).toContain({
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: '1'
|
||||||
|
});
|
||||||
|
expect(rootModel.composition).toContain({
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: '2'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('childObjects', function () {
|
||||||
|
var swg;
|
||||||
|
var layout;
|
||||||
|
var fixed;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
swg = staticProvider.get({
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: '1'
|
||||||
|
});
|
||||||
|
layout = staticProvider.get({
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: '2'
|
||||||
|
});
|
||||||
|
fixed = staticProvider.get({
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: '3'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('match expected ordering', function () {
|
||||||
|
// this is a sanity check to make sure the identifiers map in
|
||||||
|
// the correct order.
|
||||||
|
expect(swg.type).toBe('generator');
|
||||||
|
expect(layout.type).toBe('layout');
|
||||||
|
expect(fixed.type).toBe('telemetry.fixed');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('have new-style identifiers', function () {
|
||||||
|
expect(swg.identifier).toEqual({
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: '1'
|
||||||
|
});
|
||||||
|
expect(layout.identifier).toEqual({
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: '2'
|
||||||
|
});
|
||||||
|
expect(fixed.identifier).toEqual({
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: '3'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('have new-style composition', function () {
|
||||||
|
expect(layout.composition).toContain({
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: '1'
|
||||||
|
});
|
||||||
|
expect(layout.composition).toContain({
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: '3'
|
||||||
|
});
|
||||||
|
expect(fixed.composition).toContain({
|
||||||
|
namespace: 'my-import',
|
||||||
|
key: '1'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rewrites locations', function () {
|
||||||
|
expect(swg.location).toBe('my-import:root');
|
||||||
|
expect(layout.location).toBe('my-import:root');
|
||||||
|
expect(fixed.location).toBe('my-import:2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rewrites matched identifiers in objects', function () {
|
||||||
|
expect(layout.configuration.layout.panels['my-import:1'])
|
||||||
|
.toBeDefined();
|
||||||
|
expect(layout.configuration.layout.panels['my-import:3'])
|
||||||
|
.toBeDefined();
|
||||||
|
expect(layout.configuration.layout.panels['483c00d4-bb1d-4b42-b29a-c58e06b322a0'])
|
||||||
|
.not.toBeDefined();
|
||||||
|
expect(layout.configuration.layout.panels['20273193-f069-49e9-b4f7-b97a87ed755d'])
|
||||||
|
.not.toBeDefined();
|
||||||
|
expect(fixed.configuration['fixed-display'].elements[0].id)
|
||||||
|
.toBe('my-import:1');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
51
src/plugins/staticRootPlugin/plugin.js
Normal file
51
src/plugins/staticRootPlugin/plugin.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
define([
|
||||||
|
'./StaticModelProvider'
|
||||||
|
], function (
|
||||||
|
StaticModelProvider
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* Static Root Plugin: takes an export file and exposes it as a new root
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
function StaticRootPlugin(namespace, exportUrl) {
|
||||||
|
|
||||||
|
var rootIdentifier = {
|
||||||
|
namespace: namespace,
|
||||||
|
key: 'root'
|
||||||
|
};
|
||||||
|
|
||||||
|
var cachedProvider;
|
||||||
|
|
||||||
|
var loadProvider = function () {
|
||||||
|
return fetch(exportUrl)
|
||||||
|
.then(function (response) {
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(function (importData) {
|
||||||
|
cachedProvider = new StaticModelProvider(importData, rootIdentifier);
|
||||||
|
return cachedProvider;
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
var getProvider = function () {
|
||||||
|
if (!cachedProvider) {
|
||||||
|
cachedProvider = loadProvider();
|
||||||
|
}
|
||||||
|
return Promise.resolve(cachedProvider);
|
||||||
|
};
|
||||||
|
|
||||||
|
return function install(openmct) {
|
||||||
|
openmct.objects.addRoot(rootIdentifier);
|
||||||
|
openmct.objects.addProvider(namespace, {
|
||||||
|
get: function (identifier) {
|
||||||
|
return getProvider().then(function (provider) {
|
||||||
|
return provider.get(identifier);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return StaticRootPlugin;
|
||||||
|
});
|
1
src/plugins/staticRootPlugin/static-provider-test.json
Normal file
1
src/plugins/staticRootPlugin/static-provider-test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"openmct":{"a9122832-4b6e-43ea-8219-5359c14c5de8":{"composition":["483c00d4-bb1d-4b42-b29a-c58e06b322a0","d2ac3ae4-0af2-49fe-81af-adac09936215"],"name":"import-provider-test","type":"folder","notes":"test data for import provider.","modified":1508522673278,"location":"mine","persisted":1508522673278},"483c00d4-bb1d-4b42-b29a-c58e06b322a0":{"telemetry":{"period":10,"amplitude":1,"offset":0,"dataRateInHz":1,"values":[{"key":"utc","name":"Time","format":"utc","hints":{"domain":1,"priority":0},"source":"utc"},{"key":"yesterday","name":"Yesterday","format":"utc","hints":{"domain":2,"priority":1},"source":"yesterday"},{"key":"sin","name":"Sine","hints":{"range":1,"priority":2},"source":"sin"},{"key":"cos","name":"Cosine","hints":{"range":2,"priority":3},"source":"cos"}]},"name":"SWG-10","type":"generator","modified":1508522652874,"location":"a9122832-4b6e-43ea-8219-5359c14c5de8","persisted":1508522652874},"d2ac3ae4-0af2-49fe-81af-adac09936215":{"composition":["483c00d4-bb1d-4b42-b29a-c58e06b322a0","20273193-f069-49e9-b4f7-b97a87ed755d"],"name":"Layout","type":"layout","configuration":{"layout":{"panels":{"483c00d4-bb1d-4b42-b29a-c58e06b322a0":{"position":[0,0],"dimensions":[17,8]},"20273193-f069-49e9-b4f7-b97a87ed755d":{"position":[0,8],"dimensions":[17,1],"hasFrame":false}}}},"modified":1508522745580,"location":"a9122832-4b6e-43ea-8219-5359c14c5de8","persisted":1508522745580},"20273193-f069-49e9-b4f7-b97a87ed755d":{"layoutGrid":[64,16],"composition":["483c00d4-bb1d-4b42-b29a-c58e06b322a0"],"name":"FP Test","type":"telemetry.fixed","configuration":{"fixed-display":{"elements":[{"type":"fixed.telemetry","x":0,"y":0,"id":"483c00d4-bb1d-4b42-b29a-c58e06b322a0","stroke":"transparent","color":"","titled":true,"width":8,"height":2,"useGrid":true,"size":"24px"}]}},"modified":1508522717619,"location":"d2ac3ae4-0af2-49fe-81af-adac09936215","persisted":1508522717619}},"rootId":"a9122832-4b6e-43ea-8219-5359c14c5de8"}
|
Loading…
Reference in New Issue
Block a user