[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:
Pete Richards 2018-03-09 12:39:25 -08:00 committed by Andrew Henry
parent 39a7f43cd0
commit f9060a485d
6 changed files with 270 additions and 4 deletions

View File

@ -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'
], ],

View File

@ -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.

View 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;
});

View 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');
});
});
});
});

View 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;
});

View 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"}