Merge branch 'master' into code-standards-update

This commit is contained in:
Andrew Henry 2020-06-02 13:05:32 -07:00 committed by GitHub
commit 7073b0717f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
96 changed files with 1932 additions and 423 deletions

View File

@ -11,7 +11,8 @@ module.exports = {
}, },
"extends": [ "extends": [
"eslint:recommended", "eslint:recommended",
"plugin:vue/recommended" "plugin:vue/recommended",
"plugin:you-dont-need-lodash-underscore/compatible"
], ],
"parser": "vue-eslint-parser", "parser": "vue-eslint-parser",
"parserOptions": { "parserOptions": {
@ -23,6 +24,9 @@ module.exports = {
} }
}, },
"rules": { "rules": {
"you-dont-need-lodash-underscore/omit": "off",
"you-dont-need-lodash-underscore/throttle": "off",
"you-dont-need-lodash-underscore/flatten": "off",
"no-bitwise": "error", "no-bitwise": "error",
"curly": "error", "curly": "error",
"eqeqeq": "error", "eqeqeq": "error",

View File

@ -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 requests __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 requests __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.
@ -299,6 +308,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
@ -306,3 +316,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)

View File

@ -100,7 +100,7 @@ define([
}; };
GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) { GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
return _.extend( return Object.assign(
{}, {},
domainObject.telemetry, domainObject.telemetry,
METADATA_BY_TYPE[domainObject.type] METADATA_BY_TYPE[domainObject.type]

View File

@ -52,6 +52,7 @@ define([
return { return {
name: name, name: name,
utc: Math.floor(timestamp / 5000) * 5000, utc: Math.floor(timestamp / 5000) * 5000,
local: Math.floor(timestamp / 5000) * 5000,
url: IMAGE_SAMPLES[Math.floor(timestamp / 5000) % IMAGE_SAMPLES.length] url: IMAGE_SAMPLES[Math.floor(timestamp / 5000) % IMAGE_SAMPLES.length]
}; };
} }
@ -78,7 +79,7 @@ define([
}, },
request: function (domainObject, options) { request: function (domainObject, options) {
var start = options.start; var start = options.start;
var end = options.end; var end = Math.min(options.end, Date.now());
var data = []; var data = [];
while (start <= end && data.length < 5000) { while (start <= end && data.length < 5000) {
data.push(pointForTimestamp(start, domainObject.name)); data.push(pointForTimestamp(start, domainObject.name));
@ -118,6 +119,14 @@ define([
name: 'Time', name: 'Time',
key: 'utc', key: 'utc',
format: 'utc', format: 'utc',
hints: {
domain: 2
}
},
{
name: 'Local Time',
key: 'local',
format: 'local-format',
hints: { hints: {
domain: 1 domain: 1
} }

View File

@ -24,6 +24,7 @@
"d3-time-format": "2.1.x", "d3-time-format": "2.1.x",
"eslint": "5.2.0", "eslint": "5.2.0",
"eslint-plugin-vue": "^6.0.0", "eslint-plugin-vue": "^6.0.0",
"eslint-plugin-you-dont-need-lodash-underscore": "^6.10.0",
"eventemitter3": "^1.2.0", "eventemitter3": "^1.2.0",
"exports-loader": "^0.7.0", "exports-loader": "^0.7.0",
"express": "^4.13.1", "express": "^4.13.1",
@ -48,7 +49,7 @@
"karma-sourcemap-loader": "^0.3.7", "karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^3.0.0", "karma-webpack": "^3.0.0",
"location-bar": "^3.0.1", "location-bar": "^3.0.1",
"lodash": "^3.10.1", "lodash": "^4.17.12",
"markdown-toc": "^0.11.7", "markdown-toc": "^0.11.7",
"marked": "^0.3.5", "marked": "^0.3.5",
"mini-css-extract-plugin": "^0.4.1", "mini-css-extract-plugin": "^0.4.1",

View File

@ -6,6 +6,12 @@
ng-show="ngModel.dialog.messages.length > 1 || ng-show="ngModel.dialog.messages.length > 1 ||
ngModel.dialog.messages.length == 0">s</span> ngModel.dialog.messages.length == 0">s</span>
</div> </div>
<button
ng-if="ngModel.dialog.topBarButton"
class="c-button c-button--major"
ng-click="ngModel.topBarButton.onClick">
{{ ngModel.topBarButton.label }}
</button>
</div> </div>
<div class="w-messages c-overlay__messages"> <div class="w-messages c-overlay__messages">
<mct-include <mct-include
@ -16,7 +22,7 @@
<button ng-repeat="dialogAction in ngModel.dialog.actions" <button ng-repeat="dialogAction in ngModel.dialog.actions"
class="c-button c-button--major" class="c-button c-button--major"
ng-click="dialogAction.action()"> ng-click="dialogAction.action()">
{{dialogAction.label}} {{ dialogAction.label }}
</button> </button>
</div> </div>
</div> </div>

View File

@ -21,7 +21,7 @@
*****************************************************************************/ *****************************************************************************/
define( define(
['../../../../../src/api/objects/object-utils'], ['objectUtils'],
function (objectUtils) { function (objectUtils) {
/** /**

View File

@ -21,44 +21,15 @@
*****************************************************************************/ *****************************************************************************/
define([ define([
"./src/NotificationIndicatorController", "./src/NotificationService"
"./src/NotificationIndicator",
"./src/NotificationService",
"./res/notification-indicator.html"
], function ( ], function (
NotificationIndicatorController, NotificationService
NotificationIndicator,
NotificationService,
notificationIndicatorTemplate
) { ) {
return { return {
name:"platform/commonUI/notification", name:"platform/commonUI/notification",
definition: { definition: {
"extensions": { "extensions": {
"templates": [
{
"key": "notificationIndicatorTemplate",
"template": notificationIndicatorTemplate
}
],
"controllers": [
{
"key": "NotificationIndicatorController",
"implementation": NotificationIndicatorController,
"depends": [
"$scope",
"openmct",
"dialogService"
]
}
],
"indicators": [
{
"implementation": NotificationIndicator,
"priority": "fallback"
}
],
"services": [ "services": [
{ {
"key": "notificationService", "key": "notificationService",

View File

@ -1,8 +0,0 @@
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div ng-show="notifications.length > 0" class="c-indicator c-indicator--clickable s-status-{{highest.severity}} icon-bell"
ng-controller="NotificationIndicatorController">
<span class="label c-indicator__label">
<button ng-click="showNotificationsList()">
{{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></button>
</span><span class="c-indicator__count">{{notifications.length}}</span>
</div>

View File

@ -1,73 +0,0 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define(
[],
function () {
/**
* Provides an indicator that is visible when there are
* banner notifications that have been minimized. Will also indicate
* the number of notifications. Notifications can be viewed by
* clicking on the indicator to launch a dialog showing a list of
* notifications.
* @param $scope
* @param notificationService
* @param dialogService
* @constructor
*/
function NotificationIndicatorController($scope, openmct, dialogService) {
$scope.notifications = openmct.notifications.notifications;
$scope.highest = openmct.notifications.highest;
/**
* Launch a dialog showing a list of current notifications.
*/
$scope.showNotificationsList = function () {
let notificationsList = openmct.notifications.notifications.map(notification => {
if (notification.model.severity === 'alert' || notification.model.severity === 'info') {
notification.model.primaryOption = {
label: 'Dismiss',
callback: () => {
let currentIndex = notificationsList.indexOf(notification);
notification.dismiss();
notificationsList.splice(currentIndex, 1);
}
}
}
return notification;
})
dialogService.getDialogResponse('overlay-message-list', {
dialog: {
title: "Messages",
//Launch the message list dialog with the models
// from the notifications
messages: notificationsList
}
});
};
}
return NotificationIndicatorController;
}
);

View File

@ -1,60 +0,0 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define(
['../src/NotificationIndicatorController'],
function (NotificationIndicatorController) {
xdescribe("The notification indicator controller ", function () {
var mockNotificationService,
mockScope,
mockDialogService,
controller;
beforeEach(function () {
mockNotificationService = jasmine.createSpy("notificationService");
mockScope = jasmine.createSpy("$scope");
mockDialogService = jasmine.createSpyObj(
"dialogService",
["getDialogResponse","dismiss"]
);
mockNotificationService.highest = {
severity: "error"
};
controller = new NotificationIndicatorController(mockScope, mockNotificationService, mockDialogService);
});
it("exposes the highest notification severity to the template", function () {
expect(mockScope.highest).toBeTruthy();
expect(mockScope.highest.severity).toBe("error");
});
it("invokes the dialog service to show list of messages", function () {
expect(mockScope.showNotificationsList).toBeDefined();
mockScope.showNotificationsList();
expect(mockDialogService.getDialogResponse).toHaveBeenCalled();
expect(mockDialogService.getDialogResponse.calls.mostRecent().args[0]).toBe('overlay-message-list');
expect(mockDialogService.getDialogResponse.calls.mostRecent().args[1].dialog).toBeDefined();
});
});
}
);

View File

@ -26,7 +26,7 @@
* @namespace platform/containment * @namespace platform/containment
*/ */
define( define(
['../../../src/api/objects/object-utils'], ['objectUtils'],
function (objectUtils) { function (objectUtils) {
function PersistableCompositionPolicy(openmct) { function PersistableCompositionPolicy(openmct) {

View File

@ -81,7 +81,7 @@ define(
baseContext = context || {}; baseContext = context || {};
} }
var actionContext = _.extend({}, baseContext); var actionContext = Object.assign({}, baseContext);
actionContext.domainObject = this.domainObject; actionContext.domainObject = this.domainObject;
return this.actionService.getActions(actionContext); return this.actionService.getActions(actionContext);

View File

@ -121,7 +121,7 @@ define(['lodash'], function (_) {
*/ */
ExportAsJSONAction.prototype.rewriteLink = function (child, parent) { ExportAsJSONAction.prototype.rewriteLink = function (child, parent) {
this.externalIdentifiers.push(this.getId(child)); this.externalIdentifiers.push(this.getId(child));
var index = _.findIndex(parent.composition, function (id) { var index = parent.composition.findIndex(id => {
return _.isEqual(child.identifier, id); return _.isEqual(child.identifier, id);
}); });
var copyOfChild = this.copyObject(child); var copyOfChild = this.copyObject(child);

View File

@ -19,7 +19,7 @@
* 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.
*****************************************************************************/ *****************************************************************************/
define(['zepto', '../../../../src/api/objects/object-utils.js'], function ($, objectUtils) { define(['zepto', 'objectUtils'], function ($, objectUtils) {
/** /**
* The ImportAsJSONAction is available from context menus and allows a user * The ImportAsJSONAction is available from context menus and allows a user

View File

@ -25,7 +25,7 @@
* Module defining GenericSearchProvider. Created by shale on 07/16/2015. * Module defining GenericSearchProvider. Created by shale on 07/16/2015.
*/ */
define([ define([
'../../../../src/api/objects/object-utils', 'objectUtils',
'lodash' 'lodash'
], function ( ], function (
objectUtils, objectUtils,
@ -191,7 +191,7 @@ define([
} }
var domainObject = objectUtils.toNewFormat(model, id); var domainObject = objectUtils.toNewFormat(model, id);
var composition = _.find(this.openmct.composition.registry, function (p) { var composition = this.openmct.composition.registry.find(p => {
return p.appliesTo(domainObject); return p.appliesTo(domainObject);
}); });

View File

@ -25,7 +25,7 @@
*/ */
define( define(
[ [
'../../../src/api/objects/object-utils', 'objectUtils',
'lodash' 'lodash'
], ],
function ( function (
@ -235,7 +235,7 @@ define(
var defaultRange = metadata.valuesForHints(['range'])[0]; var defaultRange = metadata.valuesForHints(['range'])[0];
defaultRange = defaultRange ? defaultRange.key : undefined; defaultRange = defaultRange ? defaultRange.key : undefined;
var sourceMap = _.indexBy(metadata.values(), 'key'); var sourceMap = _.keyBy(metadata.values(), 'key');
var isLegacyProvider = telemetryAPI.findRequestProvider(domainObject) === var isLegacyProvider = telemetryAPI.findRequestProvider(domainObject) ===
telemetryAPI.legacyProvider; telemetryAPI.legacyProvider;
@ -300,7 +300,7 @@ define(
var defaultRange = metadata.valuesForHints(['range'])[0]; var defaultRange = metadata.valuesForHints(['range'])[0];
defaultRange = defaultRange ? defaultRange.key : undefined; defaultRange = defaultRange ? defaultRange.key : undefined;
var sourceMap = _.indexBy(metadata.values(), 'key'); var sourceMap = _.keyBy(metadata.values(), 'key');
var isLegacyProvider = telemetryAPI.findSubscriptionProvider(domainObject) === var isLegacyProvider = telemetryAPI.findSubscriptionProvider(domainObject) ===
telemetryAPI.legacyProvider; telemetryAPI.legacyProvider;

View File

@ -0,0 +1,621 @@
{
"header": {
"event": "Allocation failed - JavaScript heap out of memory",
"location": "OnFatalError",
"filename": "report.20200527.134750.93992.001.json",
"dumpEventTime": "2020-05-27T13:47:50Z",
"dumpEventTimeStamp": "1590612470877",
"processId": 93992,
"commandLine": [
"node",
"/Users/dtailor/Desktop/openmct/node_modules/.bin/karma",
"start",
"--single-run"
],
"nodejsVersion": "v11.9.0",
"wordSize": 64,
"componentVersions": {
"node": "11.9.0",
"v8": "7.0.276.38-node.16",
"uv": "1.25.0",
"zlib": "1.2.11",
"brotli": "1.0.7",
"ares": "1.15.0",
"modules": "67",
"nghttp2": "1.34.0",
"napi": "4",
"llhttp": "1.0.1",
"http_parser": "2.8.0",
"openssl": "1.1.1a",
"cldr": "34.0",
"icu": "63.1",
"tz": "2018e",
"unicode": "11.0",
"arch": "x64",
"platform": "darwin",
"release": "node"
},
"osVersion": "Darwin 18.7.0 Darwin Kernel Version 18.7.0: Thu Jan 23 06:52:12 PST 2020; root:xnu-4903.278.25~1/RELEASE_X86_64",
"machine": "Darwin 18.7.0 Darwin Kernel Version 18.7.0: Thu Jan 23 06:52:12 PST 2020; root:xnu-4903.278.25~1/RELEASE_X86_64tailor x86_64"
},
"javascriptStack": {
"message": "No stack.",
"stack": [
"Unavailable."
]
},
"nativeStack": [
" [pc=0x10013090e] report::TriggerNodeReport(v8::Isolate*, node::Environment*, char const*, char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, v8::Local<v8::String>) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
" [pc=0x100063744] node::OnFatalError(char const*, char const*) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
" [pc=0x1001a8c47] v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
" [pc=0x1001a8be4] v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
" [pc=0x1005add42] v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
" [pc=0x1005b0273] v8::internal::Heap::CheckIneffectiveMarkCompact(unsigned long, double) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
" [pc=0x1005ac7a8] v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
" [pc=0x1005aa965] v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
" [pc=0x1005b720c] v8::internal::Heap::AllocateRawWithLightRetry(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
" [pc=0x1005b728f] v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
" [pc=0x100586484] v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationSpace) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
" [pc=0x1008389a4] v8::internal::Runtime_AllocateInNewSpace(int, v8::internal::Object**, v8::internal::Isolate*) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
" [pc=0x14acfddcfc7d] "
],
"javascriptHeap": {
"totalMemory": 1479229440,
"totalCommittedMemory": 1477309024,
"usedMemory": 1445511032,
"availableMemory": 50296592,
"memoryLimit": 1526909922,
"heapSpaces": {
"read_only_space": {
"memorySize": 524288,
"committedMemory": 42224,
"capacity": 515584,
"used": 33520,
"available": 482064
},
"new_space": {
"memorySize": 4194304,
"committedMemory": 4194288,
"capacity": 2062336,
"used": 59016,
"available": 2003320
},
"old_space": {
"memorySize": 305860608,
"committedMemory": 305138544,
"capacity": 283264904,
"used": 282942208,
"available": 322696
},
"code_space": {
"memorySize": 6291456,
"committedMemory": 5687328,
"capacity": 5237152,
"used": 5237152,
"available": 0
},
"map_space": {
"memorySize": 5255168,
"committedMemory": 5143024,
"capacity": 2523280,
"used": 2523280,
"available": 0
},
"large_object_space": {
"memorySize": 1157103616,
"committedMemory": 1157103616,
"capacity": 1202204368,
"used": 1154715856,
"available": 47488512
},
"new_large_object_space": {
"memorySize": 0,
"committedMemory": 0,
"capacity": 0,
"used": 0,
"available": 0
}
}
},
"resourceUsage": {
"userCpuSeconds": 43.1616,
"kernelCpuSeconds": 43.1616,
"cpuConsumptionPercent": 5.42705e-06,
"maxRss": 1966080000000,
"pageFaults": {
"IORequired": 245,
"IONotRequired": 832598
},
"fsActivity": {
"reads": 0,
"writes": 0
}
},
"libuv": [
],
"environmentVariables": {
"npm_config_save_dev": "",
"npm_config_legacy_bundling": "",
"npm_config_dry_run": "",
"npm_package_devDependencies_markdown_toc": "^0.11.7",
"npm_config_only": "",
"npm_config_browser": "",
"npm_config_viewer": "man",
"npm_config_commit_hooks": "true",
"npm_package_gitHead": "7126abe7ec1d66d3252f3598fbd6bd27217018bc",
"npm_config_also": "",
"npm_package_scripts_otherdoc": "node docs/gendocs.js --in docs/src --out dist/docs --suppress-toc 'docs/src/index.md|docs/src/process/index.md'",
"npm_package_devDependencies_minimist": "^1.1.1",
"npm_config_sign_git_commit": "",
"npm_config_rollback": "true",
"npm_package_devDependencies_fast_sass_loader": "1.4.6",
"TERM_PROGRAM": "Apple_Terminal",
"npm_config_usage": "",
"npm_config_audit": "true",
"npm_package_devDependencies_git_rev_sync": "^1.4.0",
"npm_package_devDependencies_file_loader": "^1.1.11",
"npm_package_devDependencies_d3_selection": "1.3.x",
"NODE": "/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node",
"npm_package_homepage": "https://github.com/nasa/openmct#readme",
"INIT_CWD": "/Users/dtailor/Desktop/openmct",
"NVM_CD_FLAGS": "",
"npm_config_globalignorefile": "/Users/dtailor/.nvm/versions/node/v11.9.0/etc/npmignore",
"npm_package_devDependencies_comma_separated_values": "^3.6.4",
"SHELL": "/bin/bash",
"TERM": "xterm-256color",
"npm_config_init_author_url": "",
"npm_config_shell": "/bin/bash",
"npm_config_maxsockets": "50",
"npm_package_devDependencies_vue_template_compiler": "2.5.6",
"npm_package_devDependencies_style_loader": "^1.0.1",
"npm_package_devDependencies_moment_duration_format": "^2.2.2",
"npm_config_parseable": "",
"npm_config_shrinkwrap": "true",
"npm_config_metrics_registry": "https://registry.npmjs.org/",
"TMPDIR": "/var/folders/ks/ytghmh9x4lj3cchr5km5lhkcb7v9y2/T/",
"npm_config_timing": "",
"npm_config_init_license": "ISC",
"npm_package_scripts_lint": "eslint platform example src --ext .js,.vue openmct.js",
"npm_package_devDependencies_d3_array": "1.2.x",
"Apple_PubSub_Socket_Render": "/private/tmp/com.apple.launchd.PsV6Dfq4Tm/Render",
"npm_config_if_present": "",
"npm_package_devDependencies_concurrently": "^3.6.1",
"TERM_PROGRAM_VERSION": "421.2",
"npm_package_scripts_jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",
"npm_config_sign_git_tag": "",
"npm_config_init_author_email": "",
"npm_config_cache_max": "Infinity",
"npm_config_preid": "",
"npm_config_long": "",
"npm_config_local_address": "",
"npm_config_cert": "",
"npm_config_git_tag_version": "true",
"npm_package_devDependencies_exports_loader": "^0.7.0",
"TERM_SESSION_ID": "0630D2FA-BAC2-48D3-A21D-9AB58A79FB14",
"npm_config_noproxy": "",
"npm_config_registry": "https://registry.npmjs.org/",
"npm_config_fetch_retries": "2",
"npm_package_private": "true",
"npm_package_devDependencies_karma_jasmine": "^1.1.2",
"npm_package_repository_url": "git+https://github.com/nasa/openmct.git",
"npm_config_versions": "",
"npm_config_key": "",
"npm_config_message": "%s",
"npm_package_readmeFilename": "README.md",
"npm_package_devDependencies_painterro": "^0.2.65",
"npm_package_scripts_verify": "concurrently 'npm:test' 'npm:lint'",
"npm_package_devDependencies_webpack": "^4.16.2",
"npm_package_devDependencies_eventemitter3": "^1.2.0",
"npm_package_description": "The Open MCT core platform",
"USER": "dtailor",
"NVM_DIR": "/Users/dtailor/.nvm",
"npm_package_license": "Apache-2.0",
"npm_package_scripts_build_dev": "webpack",
"npm_package_devDependencies_webpack_cli": "^3.1.0",
"npm_package_devDependencies_location_bar": "^3.0.1",
"npm_package_devDependencies_jasmine_core": "^3.1.0",
"npm_config_globalconfig": "/Users/dtailor/.nvm/versions/node/v11.9.0/etc/npmrc",
"npm_package_devDependencies_karma": "^2.0.3",
"npm_config_prefer_online": "",
"npm_config_always_auth": "",
"npm_config_logs_max": "10",
"npm_package_devDependencies_angular": "1.7.9",
"SSH_AUTH_SOCK": "/private/tmp/com.apple.launchd.JH8E4KgH06/Listeners",
"npm_package_devDependencies_request": "^2.69.0",
"npm_package_devDependencies_eslint": "5.2.0",
"__CF_USER_TEXT_ENCODING": "0x167DA7C2:0x0:0x0",
"npm_execpath": "/Users/dtailor/.nvm/versions/node/v11.9.0/lib/node_modules/npm/bin/npm-cli.js",
"npm_config_global_style": "",
"npm_config_cache_lock_retries": "10",
"npm_config_cafile": "",
"npm_config_update_notifier": "true",
"npm_package_scripts_test_debug": "cross-env NODE_ENV=debug karma start --no-single-run",
"npm_package_devDependencies_glob": ">= 3.0.0",
"npm_config_heading": "npm",
"npm_config_audit_level": "low",
"npm_package_devDependencies_mini_css_extract_plugin": "^0.4.1",
"npm_package_devDependencies_copy_webpack_plugin": "^4.5.2",
"npm_config_read_only": "",
"npm_config_offline": "",
"npm_config_searchlimit": "20",
"npm_config_fetch_retry_mintimeout": "10000",
"npm_package_devDependencies_webpack_dev_middleware": "^3.1.3",
"npm_config_json": "",
"npm_config_access": "",
"npm_config_argv": "{\"remain\":[],\"cooked\":[\"run\",\"test\"],\"original\":[\"run\",\"test\"]}",
"npm_package_scripts_lint_fix": "eslint platform example src --ext .js,.vue openmct.js --fix",
"npm_package_devDependencies_uuid": "^3.3.3",
"npm_package_devDependencies_karma_coverage": "^1.1.2",
"PATH": "/Users/dtailor/.nvm/versions/node/v11.9.0/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/dtailor/Desktop/openmct/node_modules/.bin:/Users/dtailor/.nvm/versions/node/v11.9.0/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/dtailor/Desktop/openmct/node_modules/.bin:/Users/dtailor/.nvm/versions/node/v11.9.0/bin:/Users/dtailor/.homebrew/bin:/Users/dtailor/local/bin:/Users/dtailor/.homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Users/dtailor/Applications/Visual Studio Code.app/Contents/Resources/app/bin:/opt/local/bin:/Users/dtailor/.homebrew/bin:/Users/dtailor/.homebrew/bin:/Users/dtailor/.homebrew/bin:/Users/dtailor/local/bin:/Users/dtailor/.homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin",
"npm_config_allow_same_version": "",
"npm_config_https_proxy": "",
"npm_config_engine_strict": "",
"npm_config_description": "true",
"npm_package_devDependencies_html2canvas": "^1.0.0-alpha.12",
"_": "/Users/dtailor/Desktop/openmct/node_modules/.bin/karma",
"npm_config_userconfig": "/Users/dtailor/.npmrc",
"npm_config_init_module": "/Users/dtailor/.npm-init.js",
"npm_package_author": "",
"npm_package_devDependencies_karma_chrome_launcher": "^2.2.0",
"npm_package_devDependencies_d3_scale": "1.0.x",
"npm_config_cidr": "",
"npm_package_devDependencies_printj": "^1.2.1",
"PWD": "/Users/dtailor/Desktop/openmct",
"npm_config_user": "377333698",
"npm_config_node_version": "11.9.0",
"npm_package_bugs_url": "https://github.com/nasa/openmct/issues",
"npm_package_scripts_test_watch": "karma start --no-single-run",
"npm_lifecycle_event": "test",
"npm_package_devDependencies_v8_compile_cache": "^1.1.0",
"npm_config_ignore_prepublish": "",
"npm_config_save": "true",
"npm_config_editor": "vi",
"npm_config_auth_type": "legacy",
"npm_package_repository_type": "git",
"npm_package_devDependencies_vue": "2.5.6",
"npm_package_devDependencies_marked": "^0.3.5",
"npm_package_devDependencies_angular_route": "1.4.14",
"npm_package_name": "openmct",
"LANG": "en_US.UTF-8",
"npm_config_script_shell": "",
"npm_config_tag": "latest",
"npm_config_global": "",
"npm_config_progress": "true",
"npm_package_scripts_start": "node app.js",
"npm_package_devDependencies_karma_coverage_istanbul_reporter": "^2.1.1",
"npm_config_ham_it_up": "",
"npm_config_searchstaleness": "900",
"npm_config_optional": "true",
"npm_package_scripts_docs": "npm run jsdoc ; npm run otherdoc",
"npm_package_devDependencies_istanbul_instrumenter_loader": "^3.0.1",
"XPC_FLAGS": "0x0",
"npm_config_save_prod": "",
"npm_config_force": "",
"npm_config_bin_links": "true",
"npm_package_devDependencies_moment": "2.25.3",
"npm_package_devDependencies_karma_webpack": "^3.0.0",
"npm_package_devDependencies_express": "^4.13.1",
"npm_config_searchopts": "",
"npm_package_devDependencies_d3_time": "1.0.x",
"FORCE_COLOR": "2",
"npm_config_node_gyp": "/Users/dtailor/.nvm/versions/node/v11.9.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js",
"npm_config_depth": "Infinity",
"npm_package_scripts_build_prod": "cross-env NODE_ENV=production webpack",
"npm_config_sso_poll_frequency": "500",
"npm_config_rebuild_bundle": "true",
"npm_package_version": "1.0.0-snapshot",
"XPC_SERVICE_NAME": "0",
"npm_config_unicode": "true",
"npm_package_devDependencies_jsdoc": "^3.3.2",
"SHLVL": "4",
"HOME": "/Users/dtailor",
"npm_config_fetch_retry_maxtimeout": "60000",
"npm_package_scripts_test": "karma start --single-run",
"npm_package_devDependencies_zepto": "^1.2.0",
"npm_package_devDependencies_eslint_plugin_vue": "^6.0.0",
"npm_config_ca": "",
"npm_config_tag_version_prefix": "v",
"npm_config_strict_ssl": "true",
"npm_config_sso_type": "oauth",
"npm_config_scripts_prepend_node_path": "warn-only",
"npm_config_save_prefix": "^",
"npm_config_loglevel": "notice",
"npm_package_devDependencies_lodash": "^3.10.1",
"npm_package_devDependencies_karma_cli": "^1.0.1",
"npm_package_devDependencies_d3_color": "1.0.x",
"npm_config_save_exact": "",
"npm_config_dev": "",
"npm_config_group": "1286109195",
"npm_config_fetch_retry_factor": "10",
"npm_package_devDependencies_webpack_hot_middleware": "^2.22.3",
"npm_package_devDependencies_cross_env": "^6.0.3",
"npm_package_devDependencies_babel_eslint": "8.2.6",
"HOMEBREW_PREFIX": "/Users/dtailor/.homebrew",
"npm_config_version": "",
"npm_config_prefer_offline": "",
"npm_config_cache_lock_stale": "60000",
"npm_config_otp": "",
"npm_config_cache_min": "10",
"npm_package_devDependencies_vue_loader": "^15.2.6",
"npm_config_searchexclude": "",
"npm_config_cache": "/Users/dtailor/.npm",
"npm_package_scripts_test_coverage": "./scripts/test-coverage.sh",
"npm_package_devDependencies_d3_interpolate": "1.1.x",
"npm_package_devDependencies_d3_format": "1.2.x",
"LOGNAME": "dtailor",
"npm_lifecycle_script": "karma start --single-run",
"npm_config_color": "true",
"npm_package_devDependencies_node_bourbon": "^4.2.3",
"npm_package_devDependencies_karma_sourcemap_loader": "^0.3.7",
"npm_package_devDependencies_karma_html_reporter": "^0.2.7",
"npm_config_proxy": "",
"npm_config_package_lock": "true",
"npm_package_devDependencies_d3_time_format": "2.1.x",
"npm_package_devDependencies_d3_axis": "1.0.x",
"npm_config_package_lock_only": "",
"npm_package_devDependencies_moment_timezone": "0.5.28",
"npm_config_save_optional": "",
"NVM_BIN": "/Users/dtailor/.nvm/versions/node/v11.9.0/bin",
"npm_config_ignore_scripts": "",
"npm_config_user_agent": "npm/6.5.0 node/v11.9.0 darwin x64",
"npm_package_devDependencies_imports_loader": "^0.8.0",
"npm_package_devDependencies_file_saver": "^1.3.8",
"npm_config_cache_lock_wait": "10000",
"npm_config_production": "",
"npm_package_scripts_build_watch": "webpack --watch",
"DISPLAY": "/private/tmp/com.apple.launchd.E3N8oC6RMf/org.macosforge.xquartz:0",
"npm_config_send_metrics": "",
"npm_config_save_bundle": "",
"npm_package_scripts_prepare": "npm run build:prod",
"npm_config_node_options": "",
"npm_config_umask": "0022",
"npm_config_init_version": "1.0.0",
"npm_package_devDependencies_split": "^1.0.0",
"npm_package_devDependencies_raw_loader": "^0.5.1",
"npm_config_init_author_name": "",
"npm_config_git": "git",
"npm_config_scope": "",
"npm_package_scripts_clean": "rm -rf ./dist",
"npm_package_devDependencies_node_sass": "^4.9.2",
"npm_package_devDependencies_css_loader": "^1.0.0",
"DISABLE_UPDATE_CHECK": "1",
"npm_config_onload_script": "",
"npm_config_unsafe_perm": "true",
"npm_config_tmp": "/var/folders/ks/ytghmh9x4lj3cchr5km5lhkcb7v9y2/T",
"npm_package_devDependencies_d3_collection": "1.0.x",
"npm_node_execpath": "/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node",
"npm_config_link": "",
"npm_config_prefix": "/Users/dtailor/.nvm/versions/node/v11.9.0",
"npm_package_devDependencies_html_loader": "^0.5.5"
},
"userLimits": {
"core_file_size_blocks": {
"soft": 0,
"hard": "unlimited"
},
"data_seg_size_kbytes": {
"soft": "unlimited",
"hard": "unlimited"
},
"file_size_blocks": {
"soft": "unlimited",
"hard": "unlimited"
},
"max_locked_memory_bytes": {
"soft": "unlimited",
"hard": "unlimited"
},
"max_memory_size_kbytes": {
"soft": "unlimited",
"hard": "unlimited"
},
"open_files": {
"soft": 24576,
"hard": "unlimited"
},
"stack_size_bytes": {
"soft": 8388608,
"hard": 67104768
},
"cpu_time_seconds": {
"soft": "unlimited",
"hard": "unlimited"
},
"max_user_processes": {
"soft": 1418,
"hard": 2128
},
"virtual_memory_kbytes": {
"soft": "unlimited",
"hard": "unlimited"
}
},
"sharedObjects": [
"/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node",
"/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation",
"/usr/lib/libSystem.B.dylib",
"/usr/lib/libc++.1.dylib",
"/usr/lib/libobjc.A.dylib",
"/usr/lib/libDiagnosticMessagesClient.dylib",
"/usr/lib/libicucore.A.dylib",
"/usr/lib/libz.1.dylib",
"/usr/lib/libc++abi.dylib",
"/usr/lib/system/libcache.dylib",
"/usr/lib/system/libcommonCrypto.dylib",
"/usr/lib/system/libcompiler_rt.dylib",
"/usr/lib/system/libcopyfile.dylib",
"/usr/lib/system/libcorecrypto.dylib",
"/usr/lib/system/libdispatch.dylib",
"/usr/lib/system/libdyld.dylib",
"/usr/lib/system/libkeymgr.dylib",
"/usr/lib/system/liblaunch.dylib",
"/usr/lib/system/libmacho.dylib",
"/usr/lib/system/libquarantine.dylib",
"/usr/lib/system/libremovefile.dylib",
"/usr/lib/system/libsystem_asl.dylib",
"/usr/lib/system/libsystem_blocks.dylib",
"/usr/lib/system/libsystem_c.dylib",
"/usr/lib/system/libsystem_configuration.dylib",
"/usr/lib/system/libsystem_coreservices.dylib",
"/usr/lib/system/libsystem_darwin.dylib",
"/usr/lib/system/libsystem_dnssd.dylib",
"/usr/lib/system/libsystem_info.dylib",
"/usr/lib/system/libsystem_m.dylib",
"/usr/lib/system/libsystem_malloc.dylib",
"/usr/lib/system/libsystem_networkextension.dylib",
"/usr/lib/system/libsystem_notify.dylib",
"/usr/lib/system/libsystem_sandbox.dylib",
"/usr/lib/system/libsystem_secinit.dylib",
"/usr/lib/system/libsystem_kernel.dylib",
"/usr/lib/system/libsystem_platform.dylib",
"/usr/lib/system/libsystem_pthread.dylib",
"/usr/lib/system/libsystem_symptoms.dylib",
"/usr/lib/system/libsystem_trace.dylib",
"/usr/lib/system/libunwind.dylib",
"/usr/lib/system/libxpc.dylib",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices",
"/System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics",
"/System/Library/Frameworks/CoreText.framework/Versions/A/CoreText",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/ImageIO",
"/System/Library/Frameworks/ColorSync.framework/Versions/A/ColorSync",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/ATS",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ColorSyncLegacy.framework/Versions/A/ColorSyncLegacy",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/HIServices",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/LangAnalysis.framework/Versions/A/LangAnalysis",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/PrintCore.framework/Versions/A/PrintCore",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/QD.framework/Versions/A/QD",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/SpeechSynthesis.framework/Versions/A/SpeechSynthesis",
"/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight",
"/System/Library/Frameworks/IOSurface.framework/Versions/A/IOSurface",
"/usr/lib/libxml2.2.dylib",
"/System/Library/Frameworks/CFNetwork.framework/Versions/A/CFNetwork",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Accelerate",
"/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation",
"/usr/lib/libcompression.dylib",
"/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration",
"/System/Library/Frameworks/CoreDisplay.framework/Versions/A/CoreDisplay",
"/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit",
"/System/Library/Frameworks/Metal.framework/Versions/A/Metal",
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/MetalPerformanceShaders",
"/System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/A/MultitouchSupport",
"/System/Library/Frameworks/Security.framework/Versions/A/Security",
"/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore",
"/usr/lib/libbsm.0.dylib",
"/usr/lib/liblzma.5.dylib",
"/usr/lib/libauto.dylib",
"/System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration",
"/usr/lib/libarchive.2.dylib",
"/usr/lib/liblangid.dylib",
"/usr/lib/libCRFSuite.dylib",
"/usr/lib/libenergytrace.dylib",
"/usr/lib/system/libkxld.dylib",
"/System/Library/PrivateFrameworks/AppleFSCompression.framework/Versions/A/AppleFSCompression",
"/usr/lib/libOpenScriptingUtil.dylib",
"/usr/lib/libcoretls.dylib",
"/usr/lib/libcoretls_cfhelpers.dylib",
"/usr/lib/libpam.2.dylib",
"/usr/lib/libsqlite3.dylib",
"/usr/lib/libxar.1.dylib",
"/usr/lib/libbz2.1.0.dylib",
"/usr/lib/libnetwork.dylib",
"/usr/lib/libapple_nghttp2.dylib",
"/usr/lib/libpcap.A.dylib",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/FSEvents",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/Metadata.framework/Versions/A/Metadata",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/OSServices.framework/Versions/A/OSServices",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SearchKit.framework/Versions/A/SearchKit",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/AE",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/LaunchServices",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/DictionaryServices.framework/Versions/A/DictionaryServices",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SharedFileList.framework/Versions/A/SharedFileList",
"/System/Library/Frameworks/NetFS.framework/Versions/A/NetFS",
"/System/Library/PrivateFrameworks/NetAuth.framework/Versions/A/NetAuth",
"/System/Library/PrivateFrameworks/login.framework/Versions/A/Frameworks/loginsupport.framework/Versions/A/loginsupport",
"/System/Library/PrivateFrameworks/TCC.framework/Versions/A/TCC",
"/System/Library/PrivateFrameworks/CoreNLP.framework/Versions/A/CoreNLP",
"/System/Library/PrivateFrameworks/MetadataUtilities.framework/Versions/A/MetadataUtilities",
"/usr/lib/libmecabra.dylib",
"/usr/lib/libmecab.1.0.0.dylib",
"/usr/lib/libgermantok.dylib",
"/usr/lib/libThaiTokenizer.dylib",
"/usr/lib/libChineseTokenizer.dylib",
"/usr/lib/libiconv.2.dylib",
"/usr/lib/libcharset.1.dylib",
"/System/Library/PrivateFrameworks/LanguageModeling.framework/Versions/A/LanguageModeling",
"/System/Library/PrivateFrameworks/CoreEmoji.framework/Versions/A/CoreEmoji",
"/System/Library/PrivateFrameworks/Lexicon.framework/Versions/A/Lexicon",
"/System/Library/PrivateFrameworks/LinguisticData.framework/Versions/A/LinguisticData",
"/usr/lib/libcmph.dylib",
"/System/Library/Frameworks/CoreData.framework/Versions/A/CoreData",
"/System/Library/Frameworks/OpenDirectory.framework/Versions/A/Frameworks/CFOpenDirectory.framework/Versions/A/CFOpenDirectory",
"/System/Library/PrivateFrameworks/APFS.framework/Versions/A/APFS",
"/usr/lib/libutil.dylib",
"/System/Library/Frameworks/ServiceManagement.framework/Versions/A/ServiceManagement",
"/System/Library/PrivateFrameworks/BackgroundTaskManagement.framework/Versions/A/BackgroundTaskManagement",
"/usr/lib/libxslt.1.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vImage.framework/Versions/A/vImage",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/vecLib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvMisc.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvDSP.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLinearAlgebra.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparseBLAS.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libQuadrature.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBNNS.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparse.dylib",
"/System/Library/PrivateFrameworks/GPUWrangler.framework/Versions/A/GPUWrangler",
"/System/Library/PrivateFrameworks/IOAccelerator.framework/Versions/A/IOAccelerator",
"/System/Library/PrivateFrameworks/IOPresentment.framework/Versions/A/IOPresentment",
"/System/Library/PrivateFrameworks/DSExternalDisplay.framework/Versions/A/DSExternalDisplay",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreFSCache.dylib",
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSCore.framework/Versions/A/MPSCore",
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSImage.framework/Versions/A/MPSImage",
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSNeuralNetwork.framework/Versions/A/MPSNeuralNetwork",
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSMatrix.framework/Versions/A/MPSMatrix",
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSRayIntersector.framework/Versions/A/MPSRayIntersector",
"/System/Library/PrivateFrameworks/MetalTools.framework/Versions/A/MetalTools",
"/System/Library/PrivateFrameworks/AggregateDictionary.framework/Versions/A/AggregateDictionary",
"/usr/lib/libMobileGestalt.dylib",
"/System/Library/Frameworks/CoreImage.framework/Versions/A/CoreImage",
"/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL",
"/System/Library/PrivateFrameworks/GraphVisualizer.framework/Versions/A/GraphVisualizer",
"/System/Library/PrivateFrameworks/FaceCore.framework/Versions/A/FaceCore",
"/System/Library/Frameworks/OpenCL.framework/Versions/A/OpenCL",
"/usr/lib/libFosl_dynamic.dylib",
"/System/Library/PrivateFrameworks/OTSVG.framework/Versions/A/OTSVG",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/libFontParser.dylib",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/libFontRegistry.dylib",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJPEG.dylib",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libTIFF.dylib",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libPng.dylib",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libGIF.dylib",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJP2.dylib",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libRadiance.dylib",
"/System/Library/PrivateFrameworks/AppleJPEG.framework/Versions/A/AppleJPEG",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGFXShared.dylib",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLImage.dylib",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCVMSPluginSupport.dylib",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreVMClient.dylib",
"/usr/lib/libcups.2.dylib",
"/System/Library/Frameworks/Kerberos.framework/Versions/A/Kerberos",
"/System/Library/Frameworks/GSS.framework/Versions/A/GSS",
"/usr/lib/libresolv.9.dylib",
"/System/Library/PrivateFrameworks/Heimdal.framework/Versions/A/Heimdal",
"/usr/lib/libheimdal-asn1.dylib",
"/System/Library/Frameworks/OpenDirectory.framework/Versions/A/OpenDirectory",
"/System/Library/PrivateFrameworks/CommonAuth.framework/Versions/A/CommonAuth",
"/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation",
"/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio",
"/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox",
"/System/Library/PrivateFrameworks/AppleSauce.framework/Versions/A/AppleSauce",
"/System/Library/PrivateFrameworks/AssertionServices.framework/Versions/A/AssertionServices",
"/System/Library/PrivateFrameworks/BaseBoard.framework/Versions/A/BaseBoard"
]
}

View File

@ -28,7 +28,7 @@ define([
'./api/api', './api/api',
'./api/overlays/OverlayAPI', './api/overlays/OverlayAPI',
'./selection/Selection', './selection/Selection',
'./api/objects/object-utils', 'objectUtils',
'./plugins/plugins', './plugins/plugins',
'./adapter/indicators/legacy-indicators-plugin', './adapter/indicators/legacy-indicators-plugin',
'./plugins/buildInfo/plugin', './plugins/buildInfo/plugin',
@ -249,7 +249,7 @@ define([
this.legacyRegistry = new BundleRegistry(); this.legacyRegistry = new BundleRegistry();
installDefaultBundles(this.legacyRegistry); installDefaultBundles(this.legacyRegistry);
// Plugin's that are installed by default // Plugins that are installed by default
this.install(this.plugins.Plot()); this.install(this.plugins.Plot());
this.install(this.plugins.TelemetryTable()); this.install(this.plugins.TelemetryTable());
@ -266,6 +266,7 @@ define([
this.install(this.plugins.WebPage()); this.install(this.plugins.WebPage());
this.install(this.plugins.Condition()); this.install(this.plugins.Condition());
this.install(this.plugins.ConditionWidget()); this.install(this.plugins.ConditionWidget());
this.install(this.plugins.NotificationIndicator());
} }
MCT.prototype = Object.create(EventEmitter.prototype); MCT.prototype = Object.create(EventEmitter.prototype);
@ -350,17 +351,13 @@ define([
* @param {HTMLElement} [domElement] the DOM element in which to run * @param {HTMLElement} [domElement] the DOM element in which to run
* MCT; if undefined, MCT will be run in the body of the document * MCT; if undefined, MCT will be run in the body of the document
*/ */
MCT.prototype.start = function (domElement) { MCT.prototype.start = function (domElement = document.body, isHeadlessMode = false) {
if (!this.plugins.DisplayLayout._installed) { if (!this.plugins.DisplayLayout._installed) {
this.install(this.plugins.DisplayLayout({ this.install(this.plugins.DisplayLayout({
showAsView: ['summary-widget'] showAsView: ['summary-widget']
})); }));
} }
if (!domElement) {
domElement = document.body;
}
this.element = domElement; this.element = domElement;
this.legacyExtension('runs', { this.legacyExtension('runs', {
@ -400,24 +397,31 @@ define([
// something has depended upon objectService. Cool, right? // something has depended upon objectService. Cool, right?
this.$injector.get('objectService'); this.$injector.get('objectService');
var appLayout = new Vue({ if (!isHeadlessMode) {
components: { var appLayout = new Vue({
'Layout': Layout.default components: {
}, 'Layout': Layout.default
provide: { },
openmct: this provide: {
}, openmct: this
template: '<Layout ref="layout"></Layout>' },
}); template: '<Layout ref="layout"></Layout>'
domElement.appendChild(appLayout.$mount().$el); });
domElement.appendChild(appLayout.$mount().$el);
this.layout = appLayout.$refs.layout; this.layout = appLayout.$refs.layout;
Browse(this); Browse(this);
}
this.router.start(); this.router.start();
this.emit('start'); this.emit('start');
}.bind(this)); }.bind(this));
}; };
MCT.prototype.startHeadless = function () {
let unreachableNode = document.createElement('div');
return this.start(unreachableNode, true);
}
/** /**
* Install a plugin in MCT. * Install a plugin in MCT.
* *

View File

@ -21,11 +21,11 @@
*****************************************************************************/ *****************************************************************************/
define([ define([
'./MCT',
'./plugins/plugins', './plugins/plugins',
'legacyRegistry' 'legacyRegistry',
], function (MCT, plugins, legacyRegistry) { 'testUtils'
xdescribe("MCT", function () { ], function (plugins, legacyRegistry, testUtils) {
describe("MCT", function () {
var openmct; var openmct;
var mockPlugin; var mockPlugin;
var mockPlugin2; var mockPlugin2;
@ -38,7 +38,7 @@ define([
mockListener = jasmine.createSpy('listener'); mockListener = jasmine.createSpy('listener');
oldBundles = legacyRegistry.list(); oldBundles = legacyRegistry.list();
openmct = new MCT(); openmct = testUtils.createOpenMct();
openmct.install(mockPlugin); openmct.install(mockPlugin);
openmct.install(mockPlugin2); openmct.install(mockPlugin2);
@ -63,8 +63,11 @@ define([
}); });
describe("start", function () { describe("start", function () {
beforeEach(function () { let appHolder;
openmct.start(); beforeEach(function (done) {
appHolder = document.createElement("div");
openmct.on('start', done);
openmct.start(appHolder);
}); });
it("calls plugins for configuration", function () { it("calls plugins for configuration", function () {
@ -75,25 +78,51 @@ define([
it("emits a start event", function () { it("emits a start event", function () {
expect(mockListener).toHaveBeenCalled(); expect(mockListener).toHaveBeenCalled();
}); });
it("Renders the application into the provided container element", function () {
let openMctShellElements = appHolder.querySelectorAll('div.l-shell');
expect(openMctShellElements.length).toBe(1);
});
});
describe("startHeadless", function () {
beforeEach(function (done) {
openmct.on('start', done);
openmct.startHeadless();
});
it("calls plugins for configuration", function () {
expect(mockPlugin).toHaveBeenCalledWith(openmct);
expect(mockPlugin2).toHaveBeenCalledWith(openmct);
});
it("emits a start event", function () {
expect(mockListener).toHaveBeenCalled();
});
it("Does not render Open MCT", function () {
let openMctShellElements = document.body.querySelectorAll('div.l-shell');
expect(openMctShellElements.length).toBe(0);
});
}); });
describe("setAssetPath", function () { describe("setAssetPath", function () {
var testAssetPath; var testAssetPath;
beforeEach(function () { beforeEach(function () {
testAssetPath = "some/path";
openmct.legacyExtension = jasmine.createSpy('legacyExtension'); openmct.legacyExtension = jasmine.createSpy('legacyExtension');
openmct.setAssetPath(testAssetPath);
}); });
it("internally configures the path for assets", function () { it("configures the path for assets", function () {
expect(openmct.legacyExtension).toHaveBeenCalledWith( testAssetPath = "some/path/";
'constants', openmct.setAssetPath(testAssetPath);
{ expect(openmct.getAssetPath()).toBe(testAssetPath);
key: "ASSETS_PATH", });
value: testAssetPath
} it("adds a trailing /", function () {
); testAssetPath = "some/path";
openmct.setAssetPath(testAssetPath);
expect(openmct.getAssetPath()).toBe(testAssetPath + "/");
}); });
}); });
}); });

View File

@ -21,7 +21,7 @@
*****************************************************************************/ *****************************************************************************/
define([ define([
'../../api/objects/object-utils' 'objectUtils'
], function (objectUtils) { ], function (objectUtils) {
function ActionDialogDecorator(mct, actionService) { function ActionDialogDecorator(mct, actionService) {
this.mct = mct; this.mct = mct;

View File

@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
define(['../../api/objects/object-utils'], function (objectUtils) { define(['objectUtils'], function (objectUtils) {
function AdapterCapability(domainObject) { function AdapterCapability(domainObject) {
this.domainObject = domainObject; this.domainObject = domainObject;
} }

View File

@ -24,7 +24,7 @@
* Module defining AlternateCompositionCapability. Created by vwoeltje on 11/7/14. * Module defining AlternateCompositionCapability. Created by vwoeltje on 11/7/14.
*/ */
define([ define([
'../../api/objects/object-utils', 'objectUtils',
'../../../platform/core/src/capabilities/ContextualDomainObject' '../../../platform/core/src/capabilities/ContextualDomainObject'
], function (objectUtils, ContextualDomainObject) { ], function (objectUtils, ContextualDomainObject) {
function AlternateCompositionCapability($injector, domainObject) { function AlternateCompositionCapability($injector, domainObject) {

View File

@ -31,6 +31,7 @@ define([
var capability = viewConstructor(domainObject); var capability = viewConstructor(domainObject);
var oldInvoke = capability.invoke.bind(capability); var oldInvoke = capability.invoke.bind(capability);
/* eslint-disable you-dont-need-lodash-underscore/map */
capability.invoke = function () { capability.invoke = function () {
var availableViews = oldInvoke(); var availableViews = oldInvoke();
var newDomainObject = capability var newDomainObject = capability
@ -52,6 +53,8 @@ define([
.map('view') .map('view')
.value(); .value();
}; };
/* eslint-enable you-dont-need-lodash-underscore/map */
return capability; return capability;
}; };
} }

View File

@ -22,7 +22,7 @@
define([ define([
'../capabilities/AlternateCompositionCapability', '../capabilities/AlternateCompositionCapability',
'../../api/objects/object-utils' 'objectUtils'
], function ( ], function (
AlternateCompositionCapability, AlternateCompositionCapability,
objectUtils objectUtils

View File

@ -21,7 +21,7 @@
*****************************************************************************/ *****************************************************************************/
define([ define([
'../../api/objects/object-utils' 'objectUtils'
], function ( ], function (
utils utils
) { ) {

View File

@ -78,7 +78,7 @@ define([
}; };
TimeSettingsURLHandler.prototype.parseQueryParams = function () { TimeSettingsURLHandler.prototype.parseQueryParams = function () {
var searchParams = _.pick(this.$location.search(), _.values(SEARCH)); var searchParams = _.pick(this.$location.search(), Object.values(SEARCH));
var parsedParams = { var parsedParams = {
clock: searchParams[SEARCH.MODE], clock: searchParams[SEARCH.MODE],
timeSystem: searchParams[SEARCH.TIME_SYSTEM] timeSystem: searchParams[SEARCH.TIME_SYSTEM]

View File

@ -21,7 +21,7 @@
*****************************************************************************/ *****************************************************************************/
define([ define([
'../../api/objects/object-utils' 'objectUtils'
], function ( ], function (
utils utils
) { ) {

View File

@ -21,7 +21,7 @@
*****************************************************************************/ *****************************************************************************/
define([ define([
'../../api/objects/object-utils' 'objectUtils'
], function ( ], function (
objectUtils objectUtils
) { ) {

View File

@ -1,7 +1,7 @@
define([ define([
'./LegacyViewProvider', './LegacyViewProvider',
'./TypeInspectorViewProvider', './TypeInspectorViewProvider',
'../../api/objects/object-utils' 'objectUtils'
], function ( ], function (
LegacyViewProvider, LegacyViewProvider,
TypeInspectorViewProvider, TypeInspectorViewProvider,

View File

@ -70,7 +70,7 @@ define([
* @memberof module:openmct.CompositionAPI# * @memberof module:openmct.CompositionAPI#
*/ */
CompositionAPI.prototype.get = function (domainObject) { CompositionAPI.prototype.get = function (domainObject) {
var provider = _.find(this.registry, function (p) { var provider = this.registry.find(p => {
return p.appliesTo(domainObject); return p.appliesTo(domainObject);
}); });

View File

@ -122,7 +122,7 @@ define([
throw new Error('Event not supported by composition: ' + event); throw new Error('Event not supported by composition: ' + event);
} }
var index = _.findIndex(this.listeners[event], function (l) { var index = this.listeners[event].findIndex(l => {
return l.callback === callback && l.context === context; return l.callback === callback && l.context === context;
}); });

View File

@ -22,7 +22,7 @@
define([ define([
'lodash', 'lodash',
'../objects/object-utils' 'objectUtils'
], function ( ], function (
_, _,
objectUtils objectUtils
@ -143,7 +143,7 @@ define([
var keyString = objectUtils.makeKeyString(domainObject.identifier); var keyString = objectUtils.makeKeyString(domainObject.identifier);
var objectListeners = this.listeningTo[keyString]; var objectListeners = this.listeningTo[keyString];
var index = _.findIndex(objectListeners[event], function (l) { var index = objectListeners[event].findIndex(l => {
return l.callback === callback && l.context === context; return l.callback === callback && l.context === context;
}); });
@ -196,8 +196,8 @@ define([
* @private * @private
*/ */
DefaultCompositionProvider.prototype.includes = function (parent, childId) { DefaultCompositionProvider.prototype.includes = function (parent, childId) {
return parent.composition.findIndex(composee => return parent.composition.some(composee =>
this.publicAPI.objects.areIdsEqual(composee, childId)) !== -1; this.publicAPI.objects.areIdsEqual(composee, childId));
}; };
DefaultCompositionProvider.prototype.reorder = function (domainObject, oldIndex, newIndex) { DefaultCompositionProvider.prototype.reorder = function (domainObject, oldIndex, newIndex) {

View File

@ -128,6 +128,11 @@ export default class NotificationAPI extends EventEmitter {
return this._notify(notificationModel); return this._notify(notificationModel);
} }
dismissAllNotifications() {
this.notifications = [];
this.emit('dismiss-all');
}
/** /**
* Minimize a notification. The notification will still be available * Minimize a notification. The notification will still be available
* from the notification list. Typically notifications with a * from the notification list. Typically notifications with a

View File

@ -21,7 +21,7 @@
*****************************************************************************/ *****************************************************************************/
define([ define([
'./object-utils.js', 'objectUtils',
'lodash' 'lodash'
], function ( ], function (
utils, utils,

View File

@ -22,7 +22,7 @@
define([ define([
'lodash', 'lodash',
'./object-utils', 'objectUtils',
'./MutableObject', './MutableObject',
'./RootRegistry', './RootRegistry',
'./RootObjectProvider', './RootObjectProvider',

View File

@ -43,7 +43,7 @@ define([
} }
RootRegistry.prototype.addRoot = function (key) { RootRegistry.prototype.addRoot = function (key) {
if (isKey(key) || (_.isArray(key) && _.every(key, isKey))) { if (isKey(key) || (Array.isArray(key) && key.every(isKey))) {
this.providers.push(function () { this.providers.push(function () {
return key; return key;
}); });

View File

@ -1,5 +1,5 @@
define([ define([
'../object-utils' 'objectUtils'
], function ( ], function (
objectUtils objectUtils
) { ) {

View File

@ -85,9 +85,9 @@ define([
value: +e.value value: +e.value
}; };
}), 'e.value'); }), 'e.value');
valueMetadata.values = _.pluck(valueMetadata.enumerations, 'value'); valueMetadata.values = valueMetadata.enumerations.map(e => e.value);
valueMetadata.max = _.max(valueMetadata.values); valueMetadata.max = Math.max(valueMetadata.values);
valueMetadata.min = _.min(valueMetadata.values); valueMetadata.min = Math.min(valueMetadata.values);
} }
valueMetadatas.push(valueMetadata); valueMetadatas.push(valueMetadata);
@ -103,7 +103,7 @@ define([
var metadata = domainObject.telemetry || {}; var metadata = domainObject.telemetry || {};
if (this.typeHasTelemetry(domainObject)) { if (this.typeHasTelemetry(domainObject)) {
var typeMetadata = this.typeService.getType(domainObject.type).typeDef.telemetry; var typeMetadata = this.typeService.getType(domainObject.type).typeDef.telemetry;
_.extend(metadata, typeMetadata); Object.assign(metadata, typeMetadata);
if (!metadata.values) { if (!metadata.values) {
metadata.values = valueMetadatasFromOldFormat(metadata); metadata.values = valueMetadatasFromOldFormat(metadata);
} }

View File

@ -24,7 +24,7 @@ define([
'./TelemetryMetadataManager', './TelemetryMetadataManager',
'./TelemetryValueFormatter', './TelemetryValueFormatter',
'./DefaultMetadataProvider', './DefaultMetadataProvider',
'../objects/object-utils', 'objectUtils',
'lodash' 'lodash'
], function ( ], function (
TelemetryMetadataManager, TelemetryMetadataManager,
@ -370,7 +370,7 @@ define([
TelemetryAPI.prototype.commonValuesForHints = function (metadatas, hints) { TelemetryAPI.prototype.commonValuesForHints = function (metadatas, hints) {
var options = metadatas.map(function (metadata) { var options = metadatas.map(function (metadata) {
var values = metadata.valuesForHints(hints); var values = metadata.valuesForHints(hints);
return _.indexBy(values, 'key'); return _.keyBy(values, 'key');
}).reduce(function (a, b) { }).reduce(function (a, b) {
var results = {}; var results = {};
Object.keys(a).forEach(function (key) { Object.keys(a).forEach(function (key) {
@ -383,7 +383,7 @@ define([
var sortKeys = hints.map(function (h) { var sortKeys = hints.map(function (h) {
return 'hints.' + h; return 'hints.' + h;
}); });
return _.sortByAll(options, sortKeys); return _.sortBy(options, sortKeys);
}; };
/** /**

View File

@ -57,13 +57,13 @@ define([
if (valueMetadata.format === 'enum') { if (valueMetadata.format === 'enum') {
if (!valueMetadata.values) { if (!valueMetadata.values) {
valueMetadata.values = _.pluck(valueMetadata.enumerations, 'value'); valueMetadata.values = valueMetadata.enumerations.map(e => e.value);
} }
if (!valueMetadata.hasOwnProperty('max')) { if (!valueMetadata.hasOwnProperty('max')) {
valueMetadata.max = _.max(valueMetadata.values) + 1; valueMetadata.max = Math.max(valueMetadata.values) + 1;
} }
if (!valueMetadata.hasOwnProperty('min')) { if (!valueMetadata.hasOwnProperty('min')) {
valueMetadata.min = _.min(valueMetadata.values) - 1; valueMetadata.min = Math.min(valueMetadata.values) - 1;
} }
} }
@ -121,7 +121,7 @@ define([
return metadata.hints[hint]; return metadata.hints[hint];
} }
}); });
return _.sortByAll(matchingMetadata, ...iteratees); return _.sortBy(matchingMetadata, ...iteratees);
}; };
TelemetryMetadataManager.prototype.getFilterableValues = function () { TelemetryMetadataManager.prototype.getFilterableValues = function () {

View File

@ -75,7 +75,7 @@ export default {
this.items.push(item); this.items.push(item);
}, },
removeItem(identifier) { removeItem(identifier) {
let index = _.findIndex(this.items, (item) => this.openmct.objects.makeKeyString(identifier) === item.key); let index = this.items.findIndex(item => this.openmct.objects.makeKeyString(identifier) === item.key);
this.items.splice(index, 1); this.items.splice(index, 1);
}, },

View File

@ -102,7 +102,7 @@ export default {
this.compositions.push({composition, addCallback, removeCallback}); this.compositions.push({composition, addCallback, removeCallback});
}, },
removePrimary(identifier) { removePrimary(identifier) {
let index = _.findIndex(this.primaryTelemetryObjects, (primary) => this.openmct.objects.makeKeyString(identifier) === primary.key), let index = this.primaryTelemetryObjects.findIndex(primary => this.openmct.objects.makeKeyString(identifier) === primary.key),
primary = this.primaryTelemetryObjects[index]; primary = this.primaryTelemetryObjects[index];
this.$set(this.secondaryTelemetryObjects, primary.key, undefined); this.$set(this.secondaryTelemetryObjects, primary.key, undefined);
@ -130,7 +130,7 @@ export default {
removeSecondary(primary) { removeSecondary(primary) {
return (identifier) => { return (identifier) => {
let array = this.secondaryTelemetryObjects[primary.key], let array = this.secondaryTelemetryObjects[primary.key],
index = _.findIndex(array, (secondary) => this.openmct.objects.makeKeyString(identifier) === secondary.key); index = array.findIndex(secondary => this.openmct.objects.makeKeyString(identifier) === secondary.key);
array.splice(index, 1); array.splice(index, 1);

View File

@ -29,6 +29,7 @@ export default class StyleRuleManager extends EventEmitter {
this.callback = callback; this.callback = callback;
if (suppressSubscriptionOnEdit) { if (suppressSubscriptionOnEdit) {
this.openmct.editor.on('isEditing', this.toggleSubscription.bind(this)); this.openmct.editor.on('isEditing', this.toggleSubscription.bind(this));
this.isEditing = this.openmct.editor.editing;
} }
if (styleConfiguration) { if (styleConfiguration) {
this.initialize(styleConfiguration); this.initialize(styleConfiguration);
@ -156,7 +157,6 @@ export default class StyleRuleManager extends EventEmitter {
} }
delete this.stopProvidingTelemetry; delete this.stopProvidingTelemetry;
this.conditionSetIdentifier = undefined; this.conditionSetIdentifier = undefined;
this.isEditing = undefined;
} }
} }

View File

@ -200,7 +200,7 @@ export default {
this.$emit('telemetryUpdated', this.telemetryObjs); this.$emit('telemetryUpdated', this.telemetryObjs);
}, },
removeTelemetryObject(identifier) { removeTelemetryObject(identifier) {
let index = _.findIndex(this.telemetryObjs, (obj) => { let index = this.telemetryObjs.findIndex(obj => {
let objId = this.openmct.objects.makeKeyString(obj.identifier); let objId = this.openmct.objects.makeKeyString(obj.identifier);
let id = this.openmct.objects.makeKeyString(identifier); let id = this.openmct.objects.makeKeyString(identifier);
return objId === id; return objId === id;

View File

@ -108,6 +108,7 @@ import ConditionError from "@/plugins/condition/components/ConditionError.vue";
import Vue from 'vue'; import Vue from 'vue';
import PreviewAction from "@/ui/preview/PreviewAction.js"; import PreviewAction from "@/ui/preview/PreviewAction.js";
import {getApplicableStylesForItem} from "@/plugins/condition/utils/styleUtils"; import {getApplicableStylesForItem} from "@/plugins/condition/utils/styleUtils";
import isEmpty from 'lodash/isEmpty';
export default { export default {
name: 'ConditionalStylesView', name: 'ConditionalStylesView',
@ -288,7 +289,7 @@ export default {
delete domainObjectStyles[this.itemId].conditionSetIdentifier; delete domainObjectStyles[this.itemId].conditionSetIdentifier;
domainObjectStyles[this.itemId].styles = undefined; domainObjectStyles[this.itemId].styles = undefined;
delete domainObjectStyles[this.itemId].styles; delete domainObjectStyles[this.itemId].styles;
if (_.isEmpty(domainObjectStyles[this.itemId])) { if (isEmpty(domainObjectStyles[this.itemId])) {
delete domainObjectStyles[this.itemId]; delete domainObjectStyles[this.itemId];
} }
} else { } else {
@ -299,7 +300,7 @@ export default {
domainObjectStyles.styles = undefined; domainObjectStyles.styles = undefined;
delete domainObjectStyles.styles; delete domainObjectStyles.styles;
} }
if (_.isEmpty(domainObjectStyles)) { if (isEmpty(domainObjectStyles)) {
domainObjectStyles = undefined; domainObjectStyles = undefined;
} }
@ -337,7 +338,7 @@ export default {
delete domainObjectStyles[this.itemId]; delete domainObjectStyles[this.itemId];
} }
}); });
if (_.isEmpty(domainObjectStyles)) { if (isEmpty(domainObjectStyles)) {
domainObjectStyles = undefined; domainObjectStyles = undefined;
} }
this.persist(domainObjectStyles); this.persist(domainObjectStyles);

View File

@ -50,6 +50,7 @@
import StyleEditor from "./StyleEditor.vue"; import StyleEditor from "./StyleEditor.vue";
import PreviewAction from "@/ui/preview/PreviewAction.js"; import PreviewAction from "@/ui/preview/PreviewAction.js";
import { getApplicableStylesForItem, getConsolidatedStyleValues, getConditionalStyleForItem } from "@/plugins/condition/utils/styleUtils"; import { getApplicableStylesForItem, getConsolidatedStyleValues, getConditionalStyleForItem } from "@/plugins/condition/utils/styleUtils";
import isEmpty from 'lodash/isEmpty';
export default { export default {
name: 'MultiSelectStylesView', name: 'MultiSelectStylesView',
@ -178,7 +179,7 @@ export default {
domainObjectStyles[itemId] = undefined; domainObjectStyles[itemId] = undefined;
delete domainObjectStyles[this.itemId]; delete domainObjectStyles[this.itemId];
if (_.isEmpty(domainObjectStyles)) { if (isEmpty(domainObjectStyles)) {
domainObjectStyles = undefined; domainObjectStyles = undefined;
} }
this.persist(this.domainObject, domainObjectStyles); this.persist(this.domainObject, domainObjectStyles);
@ -239,7 +240,7 @@ export default {
if (this.isStaticAndConditionalStyles) { if (this.isStaticAndConditionalStyles) {
this.removeConditionalStyles(domainObjectStyles, item.id); this.removeConditionalStyles(domainObjectStyles, item.id);
} }
if (_.isEmpty(itemStaticStyle)) { if (isEmpty(itemStaticStyle)) {
itemStaticStyle = undefined; itemStaticStyle = undefined;
domainObjectStyles[item.id] = undefined; domainObjectStyles[item.id] = undefined;
} else { } else {

View File

@ -0,0 +1,601 @@
/*****************************************************************************
* 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.
*****************************************************************************/
<template>
<div class="c-inspector__styles c-inspect-styles">
<div v-if="isStaticAndConditionalStyles"
class="c-inspect-styles__mixed-static-and-conditional u-alert u-alert--block u-alert--with-icon"
>
Your selection includes one or more items that use Conditional Styling. Applying a static style below will replace any Conditional Styling with the new choice.
</div>
<template v-if="!conditionSetDomainObject">
<div class="c-inspect-styles__header">
Object Style
</div>
<div class="c-inspect-styles__content">
<div v-if="staticStyle"
class="c-inspect-styles__style"
>
<style-editor class="c-inspect-styles__editor"
:style-item="staticStyle"
:is-editing="isEditing"
:mixed-styles="mixedStyles"
@persist="updateStaticStyle"
/>
</div>
<button
id="addConditionSet"
class="c-button c-button--major c-toggle-styling-button labeled"
@click="addConditionSet"
>
<span class="c-cs-button__label">Use Conditional Styling...</span>
</button>
</div>
</template>
<template v-else>
<div class="c-inspect-styles__header">
Conditional Object Styles
</div>
<div class="c-inspect-styles__content c-inspect-styles__condition-set">
<a v-if="conditionSetDomainObject"
class="c-object-label icon-conditional"
:href="navigateToPath"
@click="navigateOrPreview"
>
<span class="c-object-label__name">{{ conditionSetDomainObject.name }}</span>
</a>
<template v-if="isEditing">
<button
id="changeConditionSet"
class="c-button labeled"
@click="addConditionSet"
>
<span class="c-button__label">Change...</span>
</button>
<button class="c-click-icon icon-x"
title="Remove conditional styles"
@click="removeConditionSet"
></button>
</template>
</div>
<div v-if="conditionsLoaded"
class="c-inspect-styles__conditions"
>
<div v-for="(conditionStyle, index) in conditionalStyles"
:key="index"
class="c-inspect-styles__condition"
:class="{'is-current': conditionStyle.conditionId === selectedConditionId}"
@click="applySelectedConditionStyle(conditionStyle.conditionId)"
>
<condition-error :show-label="true"
:condition="getCondition(conditionStyle.conditionId)"
/>
<condition-description :show-label="true"
:condition="getCondition(conditionStyle.conditionId)"
/>
<style-editor class="c-inspect-styles__editor"
:style-item="conditionStyle"
:is-editing="isEditing"
@persist="updateConditionalStyle"
/>
</div>
</div>
</template>
</div>
</template>
<script>
import StyleEditor from "./StyleEditor.vue";
import PreviewAction from "@/ui/preview/PreviewAction.js";
import { getApplicableStylesForItem, getConsolidatedStyleValues, getConditionSetIdentifierForItem } from "@/plugins/condition/utils/styleUtils";
import ConditionSetSelectorDialog from "@/plugins/condition/components/inspector/ConditionSetSelectorDialog.vue";
import ConditionError from "@/plugins/condition/components/ConditionError.vue";
import ConditionDescription from "@/plugins/condition/components/ConditionDescription.vue";
import Vue from 'vue';
export default {
name: 'StylesView',
components: {
StyleEditor,
ConditionError,
ConditionDescription
},
inject: [
'openmct',
'selection'
],
data() {
return {
staticStyle: undefined,
isEditing: this.openmct.editor.isEditing(),
mixedStyles: [],
isStaticAndConditionalStyles: false,
conditionalStyles: [],
conditionSetDomainObject: undefined,
conditions: undefined,
conditionsLoaded: false,
navigateToPath: '',
selectedConditionId: ''
}
},
destroyed() {
this.removeListeners();
},
mounted() {
this.items = [];
this.previewAction = new PreviewAction(this.openmct);
this.isMultipleSelection = this.selection.length > 1;
this.getObjectsAndItemsFromSelection();
if (!this.isMultipleSelection) {
let objectStyles = this.getObjectStyles();
this.initializeStaticStyle(objectStyles);
if (objectStyles && objectStyles.conditionSetIdentifier) {
this.openmct.objects.get(objectStyles.conditionSetIdentifier).then(this.initialize);
this.conditionalStyles = objectStyles.styles;
}
} else {
this.initializeStaticStyle();
}
this.openmct.editor.on('isEditing', this.setEditState);
},
methods: {
getObjectStyles() {
let objectStyles;
if (this.domainObjectsById) {
const domainObject = Object.values(this.domainObjectsById)[0];
if (domainObject.configuration && domainObject.configuration.objectStyles) {
objectStyles = domainObject.configuration.objectStyles;
}
} else if (this.items.length) {
const itemId = this.items[0].id;
if (this.domainObject.configuration && this.domainObject.configuration.objectStyles && this.domainObject.configuration.objectStyles[itemId]) {
objectStyles = this.domainObject.configuration.objectStyles[itemId];
}
} else if (this.domainObject.configuration && this.domainObject.configuration.objectStyles) {
objectStyles = this.domainObject.configuration.objectStyles;
}
return objectStyles;
},
setEditState(isEditing) {
this.isEditing = isEditing;
if (this.isEditing) {
if (this.stopProvidingTelemetry) {
this.stopProvidingTelemetry();
}
} else {
this.subscribeToConditionSet();
}
},
enableConditionSetNav() {
this.openmct.objects.getOriginalPath(this.conditionSetDomainObject.identifier).then(
(objectPath) => {
this.objectPath = objectPath;
this.navigateToPath = '#/browse/' + this.objectPath
.map(o => o && this.openmct.objects.makeKeyString(o.identifier))
.reverse()
.join('/');
}
);
},
navigateOrPreview(event) {
// If editing, display condition set in Preview overlay; otherwise nav to it while browsing
if (this.openmct.editor.isEditing()) {
event.preventDefault();
this.previewAction.invoke(this.objectPath);
}
},
isItemType(type, item) {
return item && (item.type === type);
},
hasConditionalStyle(domainObject, layoutItem) {
const id = layoutItem ? layoutItem.id : undefined;
return getConditionSetIdentifierForItem(domainObject, id) !== undefined;
},
getObjectsAndItemsFromSelection() {
let domainObject;
let subObjects = [];
let itemsWithConditionalStyles = 0;
//multiple selection
let itemInitialStyles = [];
let itemStyle;
this.selection.forEach((selectionItem) => {
const item = selectionItem[0].context.item;
const layoutItem = selectionItem[0].context.layoutItem;
const isChildItem = selectionItem.length > 1;
if (!isChildItem) {
domainObject = item;
itemStyle = getApplicableStylesForItem(item);
if (this.hasConditionalStyle(item)) {
itemsWithConditionalStyles += 1;
}
} else {
this.canHide = true;
domainObject = selectionItem[1].context.item;
if (item && !layoutItem || this.isItemType('subobject-view', layoutItem)) {
subObjects.push(item);
itemStyle = getApplicableStylesForItem(item);
if (this.hasConditionalStyle(item)) {
itemsWithConditionalStyles += 1;
}
} else {
itemStyle = getApplicableStylesForItem(domainObject, layoutItem || item);
this.items.push({
id: layoutItem.id,
applicableStyles: itemStyle
});
if (this.hasConditionalStyle(item, layoutItem)) {
itemsWithConditionalStyles += 1;
}
}
}
itemInitialStyles.push(itemStyle);
});
this.isStaticAndConditionalStyles = this.isMultipleSelection && itemsWithConditionalStyles;
const {styles, mixedStyles} = getConsolidatedStyleValues(itemInitialStyles);
this.initialStyles = styles;
this.mixedStyles = mixedStyles;
this.domainObject = domainObject;
this.removeListeners();
if (this.domainObject) {
this.stopObserving = this.openmct.objects.observe(this.domainObject, '*', newDomainObject => this.domainObject = newDomainObject);
this.stopObservingItems = this.openmct.objects.observe(this.domainObject, 'configuration.items', this.updateDomainObjectItemStyles);
}
subObjects.forEach(this.registerListener);
},
updateDomainObjectItemStyles(newItems) {
let keys = Object.keys(this.domainObject.configuration.objectStyles || {});
keys.forEach((key) => {
if (this.isKeyItemId(key)) {
if (!(newItems.find(item => item.id === key))) {
this.removeItemStyles(key);
}
}
});
},
isKeyItemId(key) {
return (key !== 'styles') &&
(key !== 'staticStyle') &&
(key !== 'defaultConditionId') &&
(key !== 'selectedConditionId') &&
(key !== 'conditionSetIdentifier');
},
registerListener(domainObject) {
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
if (!this.domainObjectsById) {
this.domainObjectsById = {};
}
if (!this.domainObjectsById[id]) {
this.domainObjectsById[id] = domainObject;
this.observeObject(domainObject, id);
}
},
observeObject(domainObject, id) {
let unobserveObject = this.openmct.objects.observe(domainObject, '*', (newObject) => {
this.domainObjectsById[id] = JSON.parse(JSON.stringify(newObject));
});
this.unObserveObjects.push(unobserveObject);
},
removeListeners() {
if (this.stopObserving) {
this.stopObserving();
}
if (this.stopObservingItems) {
this.stopObservingItems();
}
if (this.stopProvidingTelemetry) {
this.stopProvidingTelemetry();
}
if (this.unObserveObjects) {
this.unObserveObjects.forEach((unObserveObject) => {
unObserveObject();
});
}
this.unObserveObjects = [];
},
subscribeToConditionSet() {
if (this.stopProvidingTelemetry) {
this.stopProvidingTelemetry();
}
if (this.conditionSetDomainObject) {
this.openmct.telemetry.request(this.conditionSetDomainObject)
.then(output => {
if (output && output.length) {
this.handleConditionSetResultUpdated(output[0]);
}
});
this.stopProvidingTelemetry = this.openmct.telemetry.subscribe(this.conditionSetDomainObject, this.handleConditionSetResultUpdated.bind(this));
}
},
handleConditionSetResultUpdated(resultData) {
this.selectedConditionId = resultData ? resultData.conditionId : '';
},
initialize(conditionSetDomainObject) {
//If there are new conditions in the conditionSet we need to set those styles to default
this.conditionSetDomainObject = conditionSetDomainObject;
this.enableConditionSetNav();
this.initializeConditionalStyles();
},
initializeConditionalStyles() {
if (!this.conditions) {
this.conditions = {};
}
let conditionalStyles = [];
this.conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
if (conditionConfiguration.isDefault) {
this.selectedConditionId = conditionConfiguration.id;
}
this.conditions[conditionConfiguration.id] = conditionConfiguration;
let foundStyle = this.findStyleByConditionId(conditionConfiguration.id);
if (foundStyle) {
foundStyle.style = Object.assign((this.canHide ? { isStyleInvisible: '' } : {}), this.initialStyles, foundStyle.style);
conditionalStyles.push(foundStyle);
} else {
conditionalStyles.splice(index, 0, {
conditionId: conditionConfiguration.id,
style: Object.assign((this.canHide ? { isStyleInvisible: '' } : {}), this.initialStyles)
});
}
});
//we're doing this so that we remove styles for any conditions that have been removed from the condition set
this.conditionalStyles = conditionalStyles;
this.conditionsLoaded = true;
this.getAndPersistStyles(null, this.selectedConditionId);
if (!this.isEditing) {
this.subscribeToConditionSet();
}
},
//TODO: Double check how this works for single styles
initializeStaticStyle(objectStyles) {
let staticStyle = objectStyles && objectStyles.staticStyle;
if (staticStyle) {
this.staticStyle = {
style: Object.assign({}, this.initialStyles, staticStyle.style)
};
} else {
this.staticStyle = {
style: Object.assign({}, this.initialStyles)
};
}
},
removeItemStyles(itemId) {
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
if (itemId && domainObjectStyles[itemId]) {
delete domainObjectStyles[itemId];
if (Object.keys(domainObjectStyles).length <= 0) {
domainObjectStyles = undefined;
}
this.persist(this.domainObject, domainObjectStyles);
}
},
findStyleByConditionId(id) {
return this.conditionalStyles.find(conditionalStyle => conditionalStyle.conditionId === id);
},
getCondition(id) {
return this.conditions ? this.conditions[id] : {};
},
addConditionSet() {
let conditionSetDomainObject;
const handleItemSelection = (item) => {
if (item) {
conditionSetDomainObject = item;
}
};
const dismissDialog = (overlay, initialize) => {
overlay.dismiss();
if (initialize && conditionSetDomainObject) {
this.conditionSetDomainObject = conditionSetDomainObject;
this.conditionalStyles = [];
this.initializeConditionalStyles();
}
};
let vm = new Vue({
provide: {
openmct: this.openmct
},
components: {ConditionSetSelectorDialog},
data() {
return {
handleItemSelection
}
},
template: '<condition-set-selector-dialog @conditionSetSelected="handleItemSelection"></condition-set-selector-dialog>'
}).$mount();
let overlay = this.openmct.overlays.overlay({
element: vm.$el,
size: 'small',
buttons: [
{
label: 'OK',
emphasis: 'true',
callback: () => dismissDialog(overlay, true)
},
{
label: 'Cancel',
callback: () => dismissDialog(overlay, false)
}
],
onDestroy: () => vm.$destroy()
});
},
removeConditionSet() {
this.conditionSetDomainObject = undefined;
this.conditionalStyles = [];
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
if (this.domainObjectsById) {
const domainObjects = Object.values(this.domainObjectsById);
domainObjects.forEach(domainObject => {
let objectStyles = (domainObject.configuration && domainObject.configuration.objectStyles) || {};
this.removeConditionalStyles(objectStyles);
if (Object.keys(objectStyles).length <= 0) {
objectStyles = undefined;
}
this.persist(domainObject, objectStyles);
});
}
if (this.items.length) {
this.items.forEach((item) => {
const itemId = item.id;
this.removeConditionalStyles(domainObjectStyles, itemId);
if (Object.keys(domainObjectStyles[itemId]).length <= 0) {
delete domainObjectStyles[itemId];
}
});
} else {
this.removeConditionalStyles(domainObjectStyles);
}
if (Object.keys(domainObjectStyles).length <= 0) {
domainObjectStyles = undefined;
}
this.persist(this.domainObject, domainObjectStyles);
if (this.stopProvidingTelemetry) {
this.stopProvidingTelemetry();
}
},
removeConditionalStyles(domainObjectStyles, itemId) {
if (itemId && domainObjectStyles[itemId]) {
domainObjectStyles[itemId].conditionSetIdentifier = undefined;
delete domainObjectStyles[itemId].conditionSetIdentifier;
domainObjectStyles[itemId].selectedConditionId = undefined;
domainObjectStyles[itemId].defaultConditionId = undefined;
domainObjectStyles[itemId].styles = undefined;
delete domainObjectStyles[itemId].styles;
} else {
domainObjectStyles.conditionSetIdentifier = undefined;
delete domainObjectStyles.conditionSetIdentifier;
domainObjectStyles.selectedConditionId = undefined;
domainObjectStyles.defaultConditionId = undefined;
domainObjectStyles.styles = undefined;
delete domainObjectStyles.styles;
}
},
updateStaticStyle(staticStyle, property) {
//update the static style for each of the layoutItems as well as each sub object item
this.staticStyle = staticStyle;
this.removeConditionSet();
this.getAndPersistStyles(property);
},
updateConditionalStyle(conditionStyle, property) {
let foundStyle = this.findStyleByConditionId(conditionStyle.conditionId);
if (foundStyle) {
foundStyle.style = conditionStyle.style;
this.selectedConditionId = foundStyle.conditionId;
this.getAndPersistStyles(property);
}
},
getAndPersistStyles(property, defaultConditionId) {
this.persist(this.domainObject, this.getDomainObjectStyle(this.domainObject, property, this.items, defaultConditionId));
if (this.domainObjectsById) {
const domainObjects = Object.values(this.domainObjectsById);
domainObjects.forEach(domainObject => {
this.persist(domainObject, this.getDomainObjectStyle(domainObject, property, null, defaultConditionId));
});
}
if (!this.items.length && !this.domainObjectsById) {
this.persist(this.domainObject, this.getDomainObjectStyle(this.domainObject, property, null, defaultConditionId));
}
this.isStaticAndConditionalStyles = false;
if (property) {
let foundIndex = this.mixedStyles.indexOf(property);
if (foundIndex > -1) {
this.mixedStyles.splice(foundIndex, 1);
}
}
},
getDomainObjectStyle(domainObject, property, items, defaultConditionId) {
let objectStyle = {
styles: this.conditionalStyles,
staticStyle: this.staticStyle,
selectedConditionId: this.selectedConditionId
};
if (defaultConditionId) {
objectStyle.defaultConditionId = defaultConditionId;
}
if (this.conditionSetDomainObject) {
objectStyle.conditionSetIdentifier = this.conditionSetDomainObject.identifier;
}
let domainObjectStyles = (domainObject.configuration && domainObject.configuration.objectStyles) || {};
if (items) {
items.forEach(item => {
let itemStaticStyle = {};
let itemConditionalStyle = { styles: []};
if (!this.conditionSetDomainObject) {
if (domainObjectStyles[item.id] && domainObjectStyles[item.id].staticStyle) {
itemStaticStyle = domainObjectStyles[item.id].staticStyle.style;
}
if (item.applicableStyles[property]) {
itemStaticStyle[property] = this.staticStyle.style[property];
}
if (Object.keys(itemStaticStyle).length <= 0) {
itemStaticStyle = undefined;
}
domainObjectStyles[item.id] = { staticStyle: { style: itemStaticStyle } };
} else {
objectStyle.styles.forEach((conditionalStyle, index) => {
let style = {};
Object.keys(item.applicableStyles).concat(['isStyleInvisible']).forEach(key => {
style[key] = conditionalStyle.style[key];
});
itemConditionalStyle.styles.push({
...conditionalStyle,
style
});
});
domainObjectStyles[item.id] = {
...domainObjectStyles[item.id],
...objectStyle,
...itemConditionalStyle
};
}
});
} else {
domainObjectStyles = {
...domainObjectStyles,
...objectStyle
};
}
return domainObjectStyles;
},
applySelectedConditionStyle(conditionId) {
this.selectedConditionId = conditionId;
this.getAndPersistStyles();
},
persist(domainObject, style) {
this.openmct.objects.mutate(domainObject, 'configuration.objectStyles', style);
}
}
}
</script>

View File

@ -20,25 +20,21 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import { createOpenMct } from "testTools"; import { createOpenMct } from "testUtils";
import ConditionPlugin from "./plugin"; import ConditionPlugin from "./plugin";
let openmct = createOpenMct();
openmct.install(new ConditionPlugin());
let conditionSetDefinition;
let mockConditionSetDomainObject;
let element;
let child;
describe('the plugin', function () { describe('the plugin', function () {
let conditionSetDefinition;
let mockConditionSetDomainObject;
let element;
let child;
let openmct;
beforeAll((done) => { beforeAll((done) => {
openmct = createOpenMct();
openmct.install(new ConditionPlugin());
conditionSetDefinition = openmct.types.get('conditionSet').definition; conditionSetDefinition = openmct.types.get('conditionSet').definition;
const appHolder = document.createElement('div');
appHolder.style.width = '640px';
appHolder.style.height = '480px';
element = document.createElement('div'); element = document.createElement('div');
child = document.createElement('div'); child = document.createElement('div');
@ -55,7 +51,7 @@ describe('the plugin', function () {
conditionSetDefinition.initialize(mockConditionSetDomainObject); conditionSetDefinition.initialize(mockConditionSetDomainObject);
openmct.on('start', done); openmct.on('start', done);
openmct.start(appHolder); openmct.startHeadless();
}); });
let mockConditionSetObject = { let mockConditionSetObject = {

View File

@ -20,8 +20,6 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import _ from 'lodash';
const convertToNumbers = (input) => { const convertToNumbers = (input) => {
let numberInputs = []; let numberInputs = [];
input.forEach(inputValue => numberInputs.push(Number(inputValue))); input.forEach(inputValue => numberInputs.push(Number(inputValue)));
@ -257,7 +255,7 @@ export const OPERATIONS = [
const lhsValue = input[0] !== undefined ? input[0].toString() : ''; const lhsValue = input[0] !== undefined ? input[0].toString() : '';
if (input[1]) { if (input[1]) {
const values = input[1].split(','); const values = input[1].split(',');
return values.find((value) => lhsValue === _.trim(value.toString())); return values.find((value) => lhsValue === value.toString().trim());
} }
return false; return false;
}, },
@ -274,7 +272,7 @@ export const OPERATIONS = [
const lhsValue = input[0] !== undefined ? input[0].toString() : ''; const lhsValue = input[0] !== undefined ? input[0].toString() : '';
if (input[1]) { if (input[1]) {
const values = input[1].split(','); const values = input[1].split(',');
const found = values.find((value) => lhsValue === _.trim(value.toString())); const found = values.find((value) => lhsValue === value.toString().trim());
return !found; return !found;
} }
return false; return false;

View File

@ -19,6 +19,8 @@
* 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 isEmpty from 'lodash/isEmpty';
const NONE_VALUE = '__no_value'; const NONE_VALUE = '__no_value';
const styleProps = { const styleProps = {
@ -122,12 +124,25 @@ export const getConditionalStyleForItem = (domainObject, id) => {
if (domainObjectStyles[id] && domainObjectStyles[id].conditionSetIdentifier) { if (domainObjectStyles[id] && domainObjectStyles[id].conditionSetIdentifier) {
return domainObjectStyles[id].styles; return domainObjectStyles[id].styles;
} }
} else if (domainObjectStyles.staticStyle) { } else if (domainObjectStyles.conditionSetIdentifier) {
return domainObjectStyles.styles; return domainObjectStyles.styles;
} }
} }
}; };
export const getConditionSetIdentifierForItem = (domainObject, id) => {
let domainObjectStyles = domainObject && domainObject.configuration && domainObject.configuration.objectStyles;
if (domainObjectStyles) {
if (id) {
if (domainObjectStyles[id] && domainObjectStyles[id].conditionSetIdentifier) {
return domainObjectStyles[id].conditionSetIdentifier;
}
} else if (domainObjectStyles.conditionSetIdentifier) {
return domainObjectStyles.conditionSetIdentifier;
}
}
};
//Returns either existing static styles or uses SVG defaults if available //Returns either existing static styles or uses SVG defaults if available
export const getApplicableStylesForItem = (domainObject, item) => { export const getApplicableStylesForItem = (domainObject, item) => {
const type = item && item.type; const type = item && item.type;
@ -154,7 +169,7 @@ export const getApplicableStylesForItem = (domainObject, item) => {
}; };
export const getStylesWithoutNoneValue = (style) => { export const getStylesWithoutNoneValue = (style) => {
if (_.isEmpty(style) || !style) { if (isEmpty(style) || !style) {
return; return;
} }
let styleObj = {}; let styleObj = {};

View File

@ -68,7 +68,6 @@
<script> <script>
import uuid from 'uuid'; import uuid from 'uuid';
import SubobjectView from './SubobjectView.vue' import SubobjectView from './SubobjectView.vue'
import TelemetryView from './TelemetryView.vue' import TelemetryView from './TelemetryView.vue'
import BoxView from './BoxView.vue' import BoxView from './BoxView.vue'
@ -76,6 +75,7 @@ import TextView from './TextView.vue'
import LineView from './LineView.vue' import LineView from './LineView.vue'
import ImageView from './ImageView.vue' import ImageView from './ImageView.vue'
import EditMarquee from './EditMarquee.vue' import EditMarquee from './EditMarquee.vue'
import _ from 'lodash'
const ITEM_TYPE_VIEW_MAP = { const ITEM_TYPE_VIEW_MAP = {
'subobject-view': SubobjectView, 'subobject-view': SubobjectView,
@ -512,7 +512,7 @@ export default {
} }
}, },
updateTelemetryFormat(item, format) { updateTelemetryFormat(item, format) {
let index = _.findIndex(this.layoutItems, item); let index = this.layoutItems.findIndex(item);
item.format = format; item.format = format;
this.mutate(`configuration.items[${index}]`, item); this.mutate(`configuration.items[${index}]`, item);
} }

View File

@ -40,6 +40,7 @@
<script> <script>
import LayoutDrag from './../LayoutDrag' import LayoutDrag from './../LayoutDrag'
import _ from 'lodash'
export default { export default {
inject: ['openmct'], inject: ['openmct'],

View File

@ -62,6 +62,7 @@
<script> <script>
import conditionalStylesMixin from "../mixins/objectStyles-mixin"; import conditionalStylesMixin from "../mixins/objectStyles-mixin";
import _ from 'lodash';
const START_HANDLE_QUADRANTS = { const START_HANDLE_QUADRANTS = {
1: 'c-frame-edit__handle--sw', 1: 'c-frame-edit__handle--sw',

View File

@ -22,7 +22,7 @@
import Layout from './components/DisplayLayout.vue' import Layout from './components/DisplayLayout.vue'
import Vue from 'vue' import Vue from 'vue'
import objectUtils from '../../api/objects/object-utils.js' import objectUtils from 'objectUtils'
import DisplayLayoutType from './DisplayLayoutType.js' import DisplayLayoutType from './DisplayLayoutType.js'
import DisplayLayoutToolbar from './DisplayLayoutToolbar.js' import DisplayLayoutToolbar from './DisplayLayoutToolbar.js'
import AlphaNumericFormatViewProvider from './AlphanumericFormatViewProvider.js' import AlphaNumericFormatViewProvider from './AlphanumericFormatViewProvider.js'

View File

@ -62,6 +62,7 @@
<script> <script>
import FilterField from './FilterField.vue'; import FilterField from './FilterField.vue';
import ToggleSwitch from '../../../ui/components/ToggleSwitch.vue'; import ToggleSwitch from '../../../ui/components/ToggleSwitch.vue';
import isEmpty from 'lodash/isEmpty';
export default { export default {
inject: ['openmct'], inject: ['openmct'],
@ -102,7 +103,7 @@ export default {
hasActiveFilters() { hasActiveFilters() {
// Should be true when the user has entered any filter values. // Should be true when the user has entered any filter values.
return Object.values(this.persistedFilters).some(comparator => { return Object.values(this.persistedFilters).some(comparator => {
return (typeof(comparator) === 'object' && !_.isEmpty(comparator)); return (typeof(comparator) === 'object' && !isEmpty(comparator));
}); });
} }
}, },

View File

@ -27,7 +27,8 @@
<script> <script>
import FilterObject from './FilterObject.vue'; import FilterObject from './FilterObject.vue';
import GlobalFilters from './GlobalFilters.vue' import GlobalFilters from './GlobalFilters.vue';
import _ from 'lodash';
const FILTER_VIEW_TITLE = 'Filters applied'; const FILTER_VIEW_TITLE = 'Filters applied';
const FILTER_VIEW_TITLE_MIXED = 'Mixed filters applied'; const FILTER_VIEW_TITLE_MIXED = 'Mixed filters applied';

View File

@ -64,6 +64,7 @@
<script> <script>
import compositionLoader from './composition-loader'; import compositionLoader from './composition-loader';
import ListItem from './ListItem.vue'; import ListItem from './ListItem.vue';
import _ from 'lodash';
export default { export default {
components: {ListItem}, components: {ListItem},

View File

@ -66,7 +66,6 @@ export default {
data() { data() {
return { return {
autoScroll: true, autoScroll: true,
date: '',
filters : { filters : {
brightness: 100, brightness: 100,
contrast: 100 contrast: 100
@ -78,22 +77,39 @@ export default {
imageHistory: [], imageHistory: [],
imageUrl: '', imageUrl: '',
isPaused: false, isPaused: false,
metadata: {},
requestCount: 0, requestCount: 0,
timeFormat: '' timeFormat: ''
} }
}, },
mounted() { mounted() {
// set
this.keystring = this.openmct.objects.makeKeyString(this.domainObject.identifier); this.keystring = this.openmct.objects.makeKeyString(this.domainObject.identifier);
this.subscribe(this.domainObject); this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
this.imageFormat = this.openmct.telemetry.getValueFormatter(this.metadata.valuesForHints(['image'])[0]);
// initialize
this.timeKey = this.openmct.time.timeSystem().key;
this.timeFormat = this.openmct.telemetry.getValueFormatter(this.metadata.value(this.timeKey));
// listen
this.openmct.time.on('bounds', this.boundsChange);
this.openmct.time.on('timeSystem', this.timeSystemChange);
// kickoff
this.subscribe();
this.requestHistory();
}, },
updated() { updated() {
this.scrollToRight(); this.scrollToRight();
}, },
beforeDestroy() { beforeDestroy() {
this.stopListening(); if (this.unsubscribe) {
this.unsubscribe();
delete this.unsubscribe;
}
this.openmct.time.off('bounds', this.boundsChange);
this.openmct.time.off('timeSystem', this.timeSystemChange);
}, },
methods: { methods: {
datumMatchesMostRecent(datum) { datumIsNotValid(datum) {
if (this.imageHistory.length === 0) { if (this.imageHistory.length === 0) {
return false; return false;
} }
@ -103,7 +119,14 @@ export default {
const lastHistoryTime = this.timeFormat.format(this.imageHistory.slice(-1)[0]); const lastHistoryTime = this.timeFormat.format(this.imageHistory.slice(-1)[0]);
const lastHistoryURL = this.imageFormat.format(this.imageHistory.slice(-1)[0]); const lastHistoryURL = this.imageFormat.format(this.imageHistory.slice(-1)[0]);
return (datumTime === lastHistoryTime) && (datumURL === lastHistoryURL); // datum is not valid if it matches the last datum in history,
// or it is before the last datum in the history
const datumTimeCheck = this.timeFormat.parse(datum);
const historyTimeCheck = this.timeFormat.parse(this.imageHistory.slice(-1)[0]);
const matchesLast = (datumTime === lastHistoryTime) && (datumURL === lastHistoryURL);
const isStale = datumTimeCheck < historyTimeCheck;
return matchesLast || isStale;
}, },
getImageUrl(datum) { getImageUrl(datum) {
return datum ? return datum ?
@ -147,21 +170,6 @@ export default {
return this.isPaused; return this.isPaused;
}, },
requestHistory(bounds) {
this.requestCount++;
this.imageHistory = [];
const requestId = this.requestCount;
this.openmct.telemetry
.request(this.domainObject, bounds)
.then((values = []) => {
if (this.requestCount > requestId) {
return Promise.resolve('Stale request');
}
values.forEach(this.updateHistory);
this.updateValues(values[values.length - 1]);
});
},
scrollToRight() { scrollToRight() {
if (this.isPaused || !this.$refs.thumbsWrapper || !this.autoScroll) { if (this.isPaused || !this.$refs.thumbsWrapper || !this.autoScroll) {
return; return;
@ -188,40 +196,56 @@ export default {
image.selected = true; image.selected = true;
} }
}, },
stopListening() { boundsChange(bounds, isTick) {
if (this.unsubscribe) { if(!isTick) {
this.unsubscribe(); this.requestHistory();
delete this.unsubscribe;
} }
}, },
subscribe(domainObject) { requestHistory() {
this.date = '' let bounds = this.openmct.time.bounds();
this.imageUrl = ''; this.requestCount++;
this.openmct.objects.get(this.keystring) const requestId = this.requestCount;
.then((object) => { this.imageHistory = [];
const metadata = this.openmct.telemetry.getMetadata(this.domainObject); this.openmct.telemetry
this.timeKey = this.openmct.time.timeSystem().key; .request(this.domainObject, bounds)
this.timeFormat = this.openmct.telemetry.getValueFormatter(metadata.value(this.timeKey)); .then((values = []) => {
this.imageFormat = this.openmct.telemetry.getValueFormatter(metadata.valuesForHints(['image'])[0]); if (this.requestCount === requestId) {
this.unsubscribe = this.openmct.telemetry values.forEach(this.updateHistory, false);
.subscribe(this.domainObject, (datum) => { this.updateValues(values[values.length - 1]);
this.updateHistory(datum); }
this.updateValues(datum); });
}); },
timeSystemChange(system) {
// reset timesystem dependent variables
this.timeKey = system.key;
this.timeFormat = this.openmct.telemetry.getValueFormatter(this.metadata.value(this.timeKey));
},
subscribe() {
this.unsubscribe = this.openmct.telemetry
.subscribe(this.domainObject, (datum) => {
let parsedTimestamp = this.timeFormat.parse(datum[this.timeKey]),
bounds = this.openmct.time.bounds();
this.requestHistory(this.openmct.time.bounds()); if(parsedTimestamp >= bounds.start && parsedTimestamp <= bounds.end) {
this.updateHistory(datum);
this.updateValues(datum);
}
}); });
}, },
unselectAllImages() { unselectAllImages() {
this.imageHistory.forEach(image => image.selected = false); this.imageHistory.forEach(image => image.selected = false);
}, },
updateHistory(datum) { updateHistory(datum, updateValues = true) {
if (this.datumMatchesMostRecent(datum)) { if (this.datumIsNotValid(datum)) {
return; return;
} }
const index = _.sortedIndex(this.imageHistory, datum, this.timeFormat.format.bind(this.timeFormat)); const index = _.sortedIndexBy(this.imageHistory, datum, this.timeFormat.format.bind(this.timeFormat));
this.imageHistory.splice(index, 0, datum); this.imageHistory.splice(index, 0, datum);
if(updateValues) {
this.updateValues(datum);
}
}, },
updateValues(datum) { updateValues(datum) {
if (this.isPaused) { if (this.isPaused) {

View File

@ -169,12 +169,10 @@ export default {
const bounds = this.openmct.time.bounds(); const bounds = this.openmct.time.bounds();
const isTimeBoundChanged = this.embed.bounds.start !== bounds.start const isTimeBoundChanged = this.embed.bounds.start !== bounds.start
&& 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(); this.openmct.time.stopClock();
window.location.href = link;
let message = ''; let message = '';
if (isTimeBoundChanged) { if (isTimeBoundChanged) {
this.openmct.time.bounds({ this.openmct.time.bounds({
@ -188,7 +186,11 @@ export default {
message = 'Time bound values changed to fixed timespan mode'; message = 'Time bound values changed to fixed timespan mode';
} }
this.openmct.notifications.alert(message); if (message.length) {
this.openmct.notifications.alert(message);
}
window.location.href = link;
}, },
formatTime(unixTime, timeFormat) { formatTime(unixTime, timeFormat) {
return Moment.utc(unixTime).format(timeFormat); return Moment.utc(unixTime).format(timeFormat);

View File

@ -0,0 +1,70 @@
<template>
<div
v-if="notifications.length > 0"
class="c-indicator c-indicator--clickable icon-bell"
:class="[severityClass]"
>
<span class="c-indicator__label">
<button @click="toggleNotificationsList(true)">
{{ notificationsCountMessage(notifications.length) }}
</button>
<button @click="dismissAllNotifications()">
Clear All
</button>
</span>
<span class="c-indicator__count">{{ notifications.length }}</span>
<notifications-list
v-if="showNotificationsOverlay"
:notifications="notifications"
@close="toggleNotificationsList"
@clear-all="dismissAllNotifications"
/>
</div>
</template>
<script>
import NotificationsList from './NotificationsList.vue';
export default {
inject: ['openmct'],
components: {
NotificationsList
},
data() {
return {
notifications: this.openmct.notifications.notifications,
highest: this.openmct.notifications.highest,
showNotificationsOverlay: false
}
},
computed: {
severityClass() {
return `s-status-${this.highest.severity}`;
}
},
mounted() {
this.openmct.notifications.on('notification', this.updateNotifications);
this.openmct.notifications.on('dismiss-all', this.updateNotifications);
},
methods: {
dismissAllNotifications() {
this.openmct.notifications.dismissAllNotifications();
},
toggleNotificationsList(flag) {
this.showNotificationsOverlay = flag;
},
updateNotifications() {
this.notifications = this.openmct.notifications.notifications;
this.highest = this.openmct.notifications.highest;
},
notificationsCountMessage(count) {
if (count > 1) {
return `${count} Notifications`;
} else {
return `${count} Notification`;
}
}
}
}
</script>

View File

@ -0,0 +1,85 @@
<template>
<div
class="c-message"
:class="'message-severity-' + notification.model.severity"
>
<div class="c-ne__time-and-content">
<div class="c-ne__time">
<span>{{ notification.model.timestamp }}</span>
</div>
<div class="c-ne__content">
<div class="w-message-contents">
<div class="c-message__top-bar">
<div class="c-message__title">{{ notification.model.message }}</div>
</div>
<div class="message-body">
<progress-bar
v-if="isProgressNotification"
:model="progressObject"
/>
</div>
</div>
</div>
<div class="c-overlay__button-bar">
<button
v-for="(dialogOption, index) in notification.model.options"
:key="index"
class="c-button"
@click="dialogOption.callback()"
>
{{ dialogOption.label }}
</button>
<button
v-if="notification.model.primaryOption"
class="c-button c-button--major"
@click="notification.model.primaryOption.callback()"
>
{{ notification.model.primaryOption.label }}
</button>
</div>
</div>
</div>
</template>
<script>
import ProgressBar from '../../../ui/components/ProgressBar.vue';
export default {
components: {
ProgressBar
},
props:{
notification: {
type: Object,
required: true
}
},
data() {
return {
isProgressNotification: false,
progressPerc: this.notification.model.progressPerc,
progressText: this.notification.model.progressText
}
},
computed: {
progressObject() {
return {
progressPerc: this.progressPerc,
progressText: this.progressText
}
}
},
mounted() {
if (this.notification.model.progressPerc) {
this.isProgressNotification = true;
this.notification.on('progress', this.updateProgressBar)
}
},
methods: {
updateProgressBar(progressPerc, progressText) {
this.progressPerc = progressPerc;
this.progressText = progressText;
}
}
}
</script>

View File

@ -0,0 +1,69 @@
<template>
<div class="t-message-list c-overlay__contents">
<div class="c-overlay__top-bar">
<div class="c-overlay__dialog-title">Notifications</div>
<div class="c-overlay__dialog-hint">
{{ notificationsCountDisplayMessage(notifications.length) }}
</div>
</div>
<div class="w-messages c-overlay__messages">
<notification-message
v-for="notification in notifications"
:key="notification.model.timestamp"
:notification="notification"
/>
</div>
</div>
</template>
<script>
import NotificationMessage from './NotificationMessage.vue';
export default {
components: {
NotificationMessage
},
inject: ['openmct'],
props: {
notifications: {
type: Array,
required: true
}
},
data() {
return {}
},
mounted() {
this.openOverlay();
},
methods: {
openOverlay() {
this.overlay = this.openmct.overlays.overlay({
element: this.$el,
size: 'large',
dismissable: true,
buttons: [
{
label: 'Clear All Notifications',
emphasis: true,
callback:() => {
this.$emit('clear-all');
this.overlay.dismiss();
}
}
],
onDestroy: () => {
this.$emit('close', false);
}
});
},
notificationsCountDisplayMessage(count) {
if (count > 1 || count === 0) {
return `Displaying ${count} notifications`;
} else {
return `Displaying ${count} notification`;
}
}
}
}
</script>

View File

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* 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.
* *
@ -19,15 +19,25 @@
* 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 Vue from 'vue';
import NotificationIndicator from './components/NotificationIndicator.vue';
define( export default function plugin() {
[], return function install(openmct) {
function () { let component = new Vue ({
provide: {
openmct
},
components: {
NotificationIndicator: NotificationIndicator
},
template: '<NotificationIndicator></NotificationIndicator>'
}),
indicator = {
key: 'notifications-indicator',
element: component.$mount().$el
};
function NotificationIndicator() {} openmct.indicators.add(indicator);
};
NotificationIndicator.template = 'notificationIndicatorTemplate'; }
return NotificationIndicator;
}
);

View File

@ -0,0 +1,71 @@
/*****************************************************************************
* 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 NotificationIndicatorPlugin from './plugin.js';
import Vue from 'vue';
import {
createOpenMct
} from 'testUtils';
describe('the plugin', () => {
let notificationIndicatorPlugin,
openmct,
indicatorObject,
indicatorElement,
parentElement,
mockMessages = ['error', 'test', 'notifications'];
beforeEach((done) => {
openmct = createOpenMct();
notificationIndicatorPlugin = new NotificationIndicatorPlugin();
openmct.install(notificationIndicatorPlugin);
parentElement = document.createElement('div');
indicatorObject = openmct.indicators.indicatorObjects.find(indicator => indicator.key === 'notifications-indicator');
indicatorElement = indicatorObject.element;
openmct.on('start', () => {
mockMessages.forEach(message => {
openmct.notifications.error(message);
});
done();
});
openmct.startHeadless();
});
describe('the indicator plugin element', () => {
beforeEach(() => {
parentElement.append(indicatorElement);
return Vue.nextTick();
});
it('notifies the user of the number of notifications', () => {
let notificationCountElement = parentElement.querySelector('.c-indicator__count');
expect(notificationCountElement.innerText).toEqual(mockMessages.length.toString());
});
});
});

View File

@ -152,7 +152,7 @@ function (
MCTChartController.prototype.destroy = function () { MCTChartController.prototype.destroy = function () {
this.isDestroyed = true; this.isDestroyed = true;
this.stopListening(); this.stopListening();
_.invoke(this.lines, 'destroy'); this.lines.forEach(line => line.destroy());
DrawLoader.releaseDrawAPI(this.drawAPI); DrawLoader.releaseDrawAPI(this.drawAPI);
}; };

View File

@ -44,7 +44,7 @@ define([
this.initialize(options); this.initialize(options);
} }
_.extend(Collection.prototype, EventEmitter.prototype); Object.assign(Collection.prototype, EventEmitter.prototype);
eventHelpers.extend(Collection.prototype); eventHelpers.extend(Collection.prototype);
Collection.extend = extend; Collection.extend = extend;
@ -105,12 +105,7 @@ define([
}; };
Collection.prototype.indexOf = function (model) { Collection.prototype.indexOf = function (model) {
return _.findIndex( return this.models.findIndex(m => m === model);
this.models,
function (m) {
return m === model;
}
);
}; };
Collection.prototype.remove = function (model) { Collection.prototype.remove = function (model) {

View File

@ -49,7 +49,7 @@ define([
this.initialize(options); this.initialize(options);
} }
_.extend(Model.prototype, EventEmitter.prototype); Object.assign(Model.prototype, EventEmitter.prototype);
eventHelpers.extend(Model.prototype); eventHelpers.extend(Model.prototype);
Model.extend = extend; Model.extend = extend;

View File

@ -146,7 +146,7 @@ define([
strategy = 'minmax'; strategy = 'minmax';
} }
options = _.extend({}, { size: 1000, strategy, filters: this.filters }, options || {}); options = Object.assign({}, { size: 1000, strategy, filters: this.filters }, options || {});
if (!this.unsubscribe) { if (!this.unsubscribe) {
this.unsubscribe = this.openmct this.unsubscribe = this.openmct
@ -160,6 +160,7 @@ define([
); );
} }
/* eslint-disable you-dont-need-lodash-underscore/concat */
return this.openmct return this.openmct
.telemetry .telemetry
.request(this.domainObject, options) .request(this.domainObject, options)
@ -171,6 +172,7 @@ define([
.value(); .value();
this.reset(newPoints); this.reset(newPoints);
}.bind(this)); }.bind(this));
/* eslint-enable you-dont-need-lodash-underscore/concat */
}, },
/** /**
* Update x formatter on x change. * Update x formatter on x change.
@ -270,7 +272,7 @@ define([
* @private * @private
*/ */
sortedIndex: function (point) { sortedIndex: function (point) {
return _.sortedIndex(this.data, point, this.getXVal); return _.sortedIndexBy(this.data, point, this.getXVal);
}, },
/** /**
* Update min/max stats for the series. * Update min/max stats for the series.
@ -322,7 +324,15 @@ define([
* a point to the end without dupe checking. * a point to the end without dupe checking.
*/ */
add: function (point, appendOnly) { add: function (point, appendOnly) {
var insertIndex = this.data.length; var insertIndex = this.data.length,
currentYVal = this.getYVal(point),
lastYVal = this.getYVal(this.data[insertIndex - 1]);
if (this.isValueInvalid(currentYVal) && this.isValueInvalid(lastYVal)) {
console.warn('[Plot] Invalid Y Values detected');
return;
}
if (!appendOnly) { if (!appendOnly) {
insertIndex = this.sortedIndex(point); insertIndex = this.sortedIndex(point);
if (this.getXVal(this.data[insertIndex]) === this.getXVal(point)) { if (this.getXVal(this.data[insertIndex]) === this.getXVal(point)) {
@ -332,11 +342,21 @@ define([
return; return;
} }
} }
this.updateStats(point); this.updateStats(point);
point.mctLimitState = this.evaluate(point); point.mctLimitState = this.evaluate(point);
this.data.splice(insertIndex, 0, point); this.data.splice(insertIndex, 0, point);
this.emit('add', point, insertIndex, this); this.emit('add', point, insertIndex, this);
}, },
/**
*
* @private
*/
isValueInvalid: function (val) {
return Number.isNaN(val) || val === undefined;
},
/** /**
* Remove a point from the data array and notify listeners. * Remove a point from the data array and notify listeners.
* @private * @private

View File

@ -101,11 +101,11 @@ define([
var plotObject = this.plot.get('domainObject'); var plotObject = this.plot.get('domainObject');
if (plotObject.type === 'telemetry.plot.overlay') { if (plotObject.type === 'telemetry.plot.overlay') {
var persistedIndex = _.findIndex(plotObject.configuration.series, function (s) { var persistedIndex = plotObject.configuration.series.findIndex(s => {
return _.isEqual(identifier, s.identifier); return _.isEqual(identifier, s.identifier);
}); });
var configIndex = _.findIndex(this.models, function (m) { var configIndex = this.models.findIndex(m => {
return _.isEqual(m.domainObject.identifier, identifier); return _.isEqual(m.domainObject.identifier, identifier);
}); });

View File

@ -182,21 +182,6 @@ define([
this.set('format', yFormat.format.bind(yFormat)); this.set('format', yFormat.format.bind(yFormat));
this.set('values', yMetadata.values); this.set('values', yMetadata.values);
if (!label) { if (!label) {
var labelUnits = series.map(function (s) {
return s.metadata.value(s.get('yKey')).units;
}).reduce(function (a, b) {
if (a === undefined) {
return b;
}
if (a === b) {
return a;
}
return '';
}, undefined);
if (labelUnits) {
this.set('label', labelUnits);
return;
}
var labelName = series.map(function (s) { var labelName = series.map(function (s) {
return s.metadata.value(s.get('yKey')).name; return s.metadata.value(s.get('yKey')).name;
}).reduce(function (a, b) { }).reduce(function (a, b) {
@ -208,7 +193,28 @@ define([
} }
return ''; return '';
}, undefined); }, undefined);
this.set('label', labelName);
if (labelName) {
this.set('label', labelName);
return;
}
var labelUnits = series.map(function (s) {
return s.metadata.value(s.get('yKey')).units;
}).reduce(function (a, b) {
if (a === undefined) {
return b;
}
if (a === b) {
return a;
}
return '';
}, undefined);
if (labelUnits) {
this.set('label', labelUnits);
return;
}
} }
}, },
defaults: function (options) { defaults: function (options) {

View File

@ -51,7 +51,7 @@ define([
} }
} }
_.extend(Draw2D.prototype, EventEmitter.prototype); Object.assign(Draw2D.prototype, EventEmitter.prototype);
eventHelpers.extend(Draw2D.prototype); eventHelpers.extend(Draw2D.prototype);
// Convert from logical to physical x coordinates // Convert from logical to physical x coordinates

View File

@ -78,7 +78,7 @@ define([
this.listenTo(this.canvas, "webglcontextlost", this.onContextLost, this); this.listenTo(this.canvas, "webglcontextlost", this.onContextLost, this);
} }
_.extend(DrawWebGL.prototype, EventEmitter.prototype); Object.assign(DrawWebGL.prototype, EventEmitter.prototype);
eventHelpers.extend(DrawWebGL.prototype); eventHelpers.extend(DrawWebGL.prototype);
DrawWebGL.prototype.onContextLost = function (event) { DrawWebGL.prototype.onContextLost = function (event) {

View File

@ -23,7 +23,7 @@
define([ define([
'../configuration/configStore', '../configuration/configStore',
'../lib/eventHelpers', '../lib/eventHelpers',
'../../../../api/objects/object-utils', 'objectUtils',
'lodash' 'lodash'
], function ( ], function (
configStore, configStore,

View File

@ -31,7 +31,7 @@ define([
function dynamicPathForKey(key) { function dynamicPathForKey(key) {
return function (object, model) { return function (object, model) {
var modelIdentifier = model.get('identifier'); var modelIdentifier = model.get('identifier');
var index = _.findIndex(object.configuration.series, function (s) { var index = object.configuration.series.findIndex(s => {
return _.isEqual(s.identifier, modelIdentifier); return _.isEqual(s.identifier, modelIdentifier);
}); });
return 'configuration.series[' + index + '].' + key; return 'configuration.series[' + index + '].' + key;

View File

@ -73,10 +73,10 @@ define([
if (range.max === '' || range.max === null || typeof range.max === 'undefined') { if (range.max === '' || range.max === null || typeof range.max === 'undefined') {
return 'Must specify Maximum'; return 'Must specify Maximum';
} }
if (_.isNaN(Number(range.min))) { if (Number.isNaN(Number(range.min))) {
return 'Minimum must be a number.'; return 'Minimum must be a number.';
} }
if (_.isNaN(Number(range.max))) { if (Number.isNaN(Number(range.max))) {
return 'Maximum must be a number.'; return 'Maximum must be a number.';
} }
if (Number(range.min) > Number(range.max)) { if (Number(range.min) > Number(range.max)) {

View File

@ -76,7 +76,7 @@ define([
if (childObj) { if (childObj) {
var index = telemetryObjects.indexOf(childObj); var index = telemetryObjects.indexOf(childObj);
telemetryObjects.splice(index, 1); telemetryObjects.splice(index, 1);
$scope.$broadcast('plot:tickWidth', _.max(tickWidthMap)); $scope.$broadcast('plot:tickWidth', Math.max(...Object.values(tickWidthMap)));
} }
} }

View File

@ -51,7 +51,8 @@ define([
'./conditionWidget/plugin', './conditionWidget/plugin',
'./themes/espresso', './themes/espresso',
'./themes/maelstrom', './themes/maelstrom',
'./themes/snow' './themes/snow',
'./notificationIndicator/plugin'
], function ( ], function (
_, _,
UTCTimeSystem, UTCTimeSystem,
@ -83,7 +84,8 @@ define([
ConditionWidgetPlugin, ConditionWidgetPlugin,
Espresso, Espresso,
Maelstrom, Maelstrom,
Snow Snow,
NotificationIndicator
) { ) {
var bundleMap = { var bundleMap = {
LocalStorage: 'platform/persistence/local', LocalStorage: 'platform/persistence/local',
@ -192,6 +194,7 @@ define([
plugins.Snow = Snow.default; plugins.Snow = Snow.default;
plugins.Condition = ConditionPlugin.default; plugins.Condition = ConditionPlugin.default;
plugins.ConditionWidget = ConditionWidgetPlugin.default; plugins.ConditionWidget = ConditionWidgetPlugin.default;
plugins.NotificationIndicator = NotificationIndicator.default;
return plugins; return plugins;
}); });

View File

@ -1,5 +1,5 @@
define([ define([
'../../api/objects/object-utils' 'objectUtils'
], function ( ], function (
objectUtils objectUtils
) { ) {

View File

@ -1,6 +1,6 @@
define ([ define ([
'./ConditionEvaluator', './ConditionEvaluator',
'../../../api/objects/object-utils', 'objectUtils',
'EventEmitter', 'EventEmitter',
'zepto', 'zepto',
'lodash' 'lodash'
@ -9,7 +9,8 @@ define ([
objectUtils, objectUtils,
EventEmitter, EventEmitter,
$, $,
_ _,
) { ) {
/** /**

View File

@ -5,7 +5,7 @@ define([
'./TestDataManager', './TestDataManager',
'./WidgetDnD', './WidgetDnD',
'./eventHelpers', './eventHelpers',
'../../../api/objects/object-utils', 'objectUtils',
'lodash', 'lodash',
'zepto' 'zepto'
], function ( ], function (

View File

@ -1,6 +1,6 @@
define([ define([
'./Select', './Select',
'../../../../api/objects/object-utils' 'objectUtils'
], function ( ], function (
Select, Select,
objectUtils objectUtils

View File

@ -22,7 +22,7 @@
define([ define([
'./SummaryWidgetEvaluator', './SummaryWidgetEvaluator',
'../../../../api/objects/object-utils' 'objectUtils'
], function ( ], function (
SummaryWidgetEvaluator, SummaryWidgetEvaluator,
objectUtils objectUtils

View File

@ -23,7 +23,7 @@
define([ define([
'./SummaryWidgetRule', './SummaryWidgetRule',
'../eventHelpers', '../eventHelpers',
'../../../../api/objects/object-utils', 'objectUtils',
'lodash' 'lodash'
], function ( ], function (
SummaryWidgetRule, SummaryWidgetRule,
@ -80,10 +80,12 @@ define([
} }
}.bind(this); }.bind(this);
/* eslint-disable you-dont-need-lodash-underscore/map */
unsubscribes = _.map( unsubscribes = _.map(
realtimeStates, realtimeStates,
this.subscribeToObjectState.bind(this, updateCallback) this.subscribeToObjectState.bind(this, updateCallback)
); );
/* eslint-enable you-dont-need-lodash-underscore/map */
}.bind(this)); }.bind(this));
return function () { return function () {
@ -151,11 +153,13 @@ define([
SummaryWidgetEvaluator.prototype.getBaseStateClone = function () { SummaryWidgetEvaluator.prototype.getBaseStateClone = function () {
return this.load() return this.load()
.then(function () { .then(function () {
/* eslint-disable you-dont-need-lodash-underscore/values */
return _(this.baseState) return _(this.baseState)
.values() .values()
.map(_.clone) .map(_.clone)
.indexBy('id') .keyBy('id')
.value(); .value();
/* eslint-enable you-dont-need-lodash-underscore/values */
}.bind(this)); }.bind(this));
}; };
@ -182,7 +186,7 @@ define([
* @private. * @private.
*/ */
SummaryWidgetEvaluator.prototype.updateObjectStateFromLAD = function (options, objectState) { SummaryWidgetEvaluator.prototype.updateObjectStateFromLAD = function (options, objectState) {
options = _.extend({}, options, { options = Object.assign({}, options, {
strategy: 'latest', strategy: 'latest',
size: 1 size: 1
}); });
@ -255,10 +259,12 @@ define([
} }
} }
/* eslint-disable you-dont-need-lodash-underscore/map */
var latestTimestamp = _(state) var latestTimestamp = _(state)
.map('timestamps') .map('timestamps')
.sortBy(timestampKey) .sortBy(timestampKey)
.last(); .last();
/* eslint-enable you-dont-need-lodash-underscore/map */
if (!latestTimestamp) { if (!latestTimestamp) {
latestTimestamp = {}; latestTimestamp = {};

View File

@ -1,7 +1,7 @@
define([ define([
'../SummaryWidget', '../SummaryWidget',
'./SummaryWidgetView', './SummaryWidgetView',
'../../../../api/objects/object-utils' 'objectUtils'
], function ( ], function (
SummaryWidgetEditView, SummaryWidgetEditView,
SummaryWidgetView, SummaryWidgetView,

View File

@ -22,7 +22,7 @@
/*jshint latedef: nofunc */ /*jshint latedef: nofunc */
/*global console */ /*global console */
define([ define([
'../../../api/objects/object-utils', 'objectUtils',
'./TelemetryAverager' './TelemetryAverager'
], function (objectUtils, TelemetryAverager) { ], function (objectUtils, TelemetryAverager) {

View File

@ -21,7 +21,7 @@
*****************************************************************************/ *****************************************************************************/
define([ define([
'../../api/objects/object-utils', 'objectUtils',
'./components/table-configuration.vue', './components/table-configuration.vue',
'./TelemetryTableConfiguration', './TelemetryTableConfiguration',
'vue' 'vue'

View File

@ -100,7 +100,7 @@ define([
hasColumnWithKey(columnKey) { hasColumnWithKey(columnKey) {
return _.flatten(Object.values(this.columns)) return _.flatten(Object.values(this.columns))
.findIndex(column => column.getKey() === columnKey) !== -1; .some(column => column.getKey() === columnKey);
} }
getColumns() { getColumns() {
@ -109,9 +109,10 @@ define([
getAllHeaders() { getAllHeaders() {
let flattenedColumns = _.flatten(Object.values(this.columns)); let flattenedColumns = _.flatten(Object.values(this.columns));
/* eslint-disable you-dont-need-lodash-underscore/uniq */
let headers = _.uniq(flattenedColumns, false, column => column.getKey()) let headers = _.uniq(flattenedColumns, false, column => column.getKey())
.reduce(fromColumnsToHeadersMap, {}); .reduce(fromColumnsToHeadersMap, {});
/* eslint-enable you-dont-need-lodash-underscore/uniq */
function fromColumnsToHeadersMap(headersMap, column) { function fromColumnsToHeadersMap(headersMap, column) {
headersMap[column.getKey()] = column.getTitle(); headersMap[column.getKey()] = column.getTitle();
return headersMap; return headersMap;

View File

@ -93,7 +93,7 @@ define(
// same time stamp // same time stamp
let potentialDupes = this.rows.slice(startIx, endIx + 1); let potentialDupes = this.rows.slice(startIx, endIx + 1);
// Search potential dupes for exact dupe // Search potential dupes for exact dupe
isDuplicate = _.findIndex(potentialDupes, _.isEqual.bind(undefined, row)) > -1; isDuplicate = potentialDupes.some(_.isEqual.bind(undefined, row));
} }
if (!isDuplicate) { if (!isDuplicate) {
@ -120,7 +120,7 @@ define(
const firstValue = this.getValueForSortColumn(this.rows[0]); const firstValue = this.getValueForSortColumn(this.rows[0]);
const lastValue = this.getValueForSortColumn(this.rows[this.rows.length - 1]); const lastValue = this.getValueForSortColumn(this.rows[this.rows.length - 1]);
lodashFunction = lodashFunction || _.sortedIndex; lodashFunction = lodashFunction || _.sortedIndexBy;
if (this.sortOptions.direction === 'asc') { if (this.sortOptions.direction === 'asc') {
if (testRowValue > lastValue) { if (testRowValue > lastValue) {
@ -201,7 +201,7 @@ define(
sortBy(sortOptions) { sortBy(sortOptions) {
if (arguments.length > 0) { if (arguments.length > 0) {
this.sortOptions = sortOptions; this.sortOptions = sortOptions;
this.rows = _.sortByOrder(this.rows, (row) => row.getParsedValue(sortOptions.key) , sortOptions.direction); this.rows = _.orderBy(this.rows, (row) => row.getParsedValue(sortOptions.key) , sortOptions.direction);
this.emit('sort'); this.emit('sort');
} }
// Return duplicate to avoid direct modification of underlying object // Return duplicate to avoid direct modification of underlying object

View File

@ -17,6 +17,8 @@
</template> </template>
<script> <script>
import _ from 'lodash';
const FILTER_INDICATOR_LABEL = 'Filters:'; const FILTER_INDICATOR_LABEL = 'Filters:';
const FILTER_INDICATOR_LABEL_MIXED = 'Mixed Filters:'; const FILTER_INDICATOR_LABEL_MIXED = 'Mixed Filters:';
const FILTER_INDICATOR_TITLE = 'Data filters are being applied to this view.'; const FILTER_INDICATOR_TITLE = 'Data filters are being applied to this view.';

View File

@ -24,34 +24,39 @@ import Vue from 'vue';
import { import {
createOpenMct, createOpenMct,
createMouseEvent createMouseEvent
} from 'testTools'; } from 'testUtils';
let openmct;
let tablePlugin;
let element;
let child;
describe("the plugin", () => { describe("the plugin", () => {
beforeEach((done) => { let openmct;
const appHolder = document.createElement('div'); let tablePlugin;
appHolder.style.width = '640px'; let element;
appHolder.style.height = '480px'; let child;
beforeEach((done) => {
openmct = createOpenMct(); openmct = createOpenMct();
// Table Plugin is actually installed by default, but because installing it
// again is harmless it is left here as an examplar for non-default plugins.
tablePlugin = new TablePlugin();
openmct.install(tablePlugin);
element = document.createElement('div'); element = document.createElement('div');
child = document.createElement('div'); child = document.createElement('div');
element.appendChild(child); element.appendChild(child);
tablePlugin = new TablePlugin();
openmct.install(tablePlugin);
spyOn(openmct.telemetry, 'request').and.returnValue(Promise.resolve([])); spyOn(openmct.telemetry, 'request').and.returnValue(Promise.resolve([]));
openmct.on('start', done); openmct.on('start', done);
openmct.start(appHolder); openmct.startHeadless();
}); });
describe("defines a table object", function () {
it("that is creatable", () => {
let tableType = openmct.types.get('table');
expect(tableType.definition.creatable).toBe(true);
});
})
it("provides a table view for objects with telemetry", () => { it("provides a table view for objects with telemetry", () => {
const testTelemetryObject = { const testTelemetryObject = {
id:"test-object", id:"test-object",

View File

@ -25,8 +25,7 @@
</template> </template>
<script> <script>
import ConditionalStylesView from '../../plugins/condition/components/inspector/ConditionalStylesView.vue'; import StylesView from '../../plugins/condition/components/inspector/StylesView.vue';
import MultiSelectStylesView from '../../plugins/condition/components/inspector/MultiSelectStylesView.vue';
import Vue from 'vue'; import Vue from 'vue';
export default { export default {
@ -46,7 +45,6 @@ export default {
methods: { methods: {
updateSelection(selection) { updateSelection(selection) {
if (selection.length > 0 && selection[0].length > 0) { if (selection.length > 0 && selection[0].length > 0) {
let template = selection.length > 1 ? '<multi-select-styles-view></multi-select-styles-view>' : '<conditional-styles-view></conditional-styles-view>';
if (this.component) { if (this.component) {
this.component.$destroy(); this.component.$destroy();
this.component = undefined; this.component = undefined;
@ -61,10 +59,9 @@ export default {
}, },
el: viewContainer, el: viewContainer,
components: { components: {
ConditionalStylesView, StylesView
MultiSelectStylesView
}, },
template: template template: '<styles-view/>'
}); });
} }
} }

View File

@ -39,7 +39,7 @@
<script> <script>
import CreateAction from '../../../platform/commonUI/edit/src/creation/CreateAction'; import CreateAction from '../../../platform/commonUI/edit/src/creation/CreateAction';
import objectUtils from '../../api/objects/object-utils'; import objectUtils from 'objectUtils';
export default { export default {
inject: ['openmct'], inject: ['openmct'],

View File

@ -91,6 +91,7 @@ export default {
}, },
mounted() { mounted() {
this.openmct.notifications.on('notification', this.showNotification); this.openmct.notifications.on('notification', this.showNotification);
this.openmct.notifications.on('dismiss-all', this.clearModel);
}, },
methods: { methods: {
showNotification(notification) { showNotification(notification) {

View File

@ -42,7 +42,8 @@ const webpackConfig = {
"printj": path.join(__dirname, "node_modules/printj/dist/printj.min.js"), "printj": path.join(__dirname, "node_modules/printj/dist/printj.min.js"),
"styles": path.join(__dirname, "src/styles"), "styles": path.join(__dirname, "src/styles"),
"MCT": path.join(__dirname, "src/MCT"), "MCT": path.join(__dirname, "src/MCT"),
"testTools": path.join(__dirname, "src/testTools.js") "testUtils": path.join(__dirname, "src/testUtils.js"),
"objectUtils": path.join(__dirname, "src/api/objects/object-utils.js")
} }
}, },
devtool: devMode ? 'eval-source-map' : 'source-map', devtool: devMode ? 'eval-source-map' : 'source-map',