mirror of
https://github.com/nasa/openmct.git
synced 2025-06-25 18:50:11 +00:00
Compare commits
23 Commits
improve-te
...
context-me
Author | SHA1 | Date | |
---|---|---|---|
8493b481dd | |||
28723b59b7 | |||
9fa7de0b77 | |||
54bfc84ada | |||
6137700c82 | |||
91a1b3f31d | |||
357b25a76b | |||
bab53ad9bd | |||
d0d4579f13 | |||
02b537580c | |||
7073b0717f | |||
d6bb1b2a12 | |||
c256696790 | |||
d5480e7524 | |||
ab463e93fe | |||
8363c65312 | |||
2fa29124bf | |||
33faeafa98 | |||
a40ff07353 | |||
41dc9c794d | |||
f1faf3965d | |||
da2ecbbcad | |||
32c892fe98 |
58
.eslintrc.js
58
.eslintrc.js
@ -1,3 +1,4 @@
|
||||
const LEGACY_FILES = ["platform/**", "example/**"];
|
||||
module.exports = {
|
||||
"env": {
|
||||
"browser": true,
|
||||
@ -70,6 +71,56 @@ module.exports = {
|
||||
],
|
||||
"dot-notation": "error",
|
||||
"indent": ["error", 4],
|
||||
|
||||
// https://eslint.org/docs/rules/no-case-declarations
|
||||
"no-case-declarations": "error",
|
||||
// https://eslint.org/docs/rules/max-classes-per-file
|
||||
"max-classes-per-file": ["error", 1],
|
||||
// https://eslint.org/docs/rules/no-eq-null
|
||||
"no-eq-null": "error",
|
||||
// https://eslint.org/docs/rules/no-eval
|
||||
"no-eval": "error",
|
||||
// https://eslint.org/docs/rules/no-floating-decimal
|
||||
"no-floating-decimal": "error",
|
||||
// https://eslint.org/docs/rules/no-implicit-globals
|
||||
"no-implicit-globals": "error",
|
||||
// https://eslint.org/docs/rules/no-implied-eval
|
||||
"no-implied-eval": "error",
|
||||
// https://eslint.org/docs/rules/no-lone-blocks
|
||||
"no-lone-blocks": "error",
|
||||
// https://eslint.org/docs/rules/no-loop-func
|
||||
"no-loop-func": "error",
|
||||
// https://eslint.org/docs/rules/no-new-func
|
||||
"no-new-func": "error",
|
||||
// https://eslint.org/docs/rules/no-new-wrappers
|
||||
"no-new-wrappers": "error",
|
||||
// https://eslint.org/docs/rules/no-octal-escape
|
||||
"no-octal-escape": "error",
|
||||
// https://eslint.org/docs/rules/no-proto
|
||||
"no-proto": "error",
|
||||
// https://eslint.org/docs/rules/no-return-await
|
||||
"no-return-await": "error",
|
||||
// https://eslint.org/docs/rules/no-script-url
|
||||
"no-script-url": "error",
|
||||
// https://eslint.org/docs/rules/no-self-compare
|
||||
"no-self-compare": "error",
|
||||
// https://eslint.org/docs/rules/no-sequences
|
||||
"no-sequences": "error",
|
||||
// https://eslint.org/docs/rules/no-unmodified-loop-condition
|
||||
"no-unmodified-loop-condition": "error",
|
||||
// https://eslint.org/docs/rules/no-useless-call
|
||||
"no-useless-call": "error",
|
||||
// https://eslint.org/docs/rules/wrap-iife
|
||||
"wrap-iife": "error",
|
||||
// https://eslint.org/docs/rules/no-nested-ternary
|
||||
"no-nested-ternary": "error",
|
||||
// https://eslint.org/docs/rules/switch-colon-spacing
|
||||
"switch-colon-spacing": "error",
|
||||
// https://eslint.org/docs/rules/no-useless-computed-key
|
||||
"no-useless-computed-key": "error",
|
||||
// https://eslint.org/docs/rules/rest-spread-spacing
|
||||
"rest-spread-spacing": ["error"],
|
||||
|
||||
"vue/html-indent": [
|
||||
"error",
|
||||
4,
|
||||
@ -116,6 +167,13 @@ module.exports = {
|
||||
}
|
||||
]
|
||||
}
|
||||
}, {
|
||||
"files": LEGACY_FILES,
|
||||
"rules": {
|
||||
// https://eslint.org/docs/rules/no-nested-ternary
|
||||
"no-nested-ternary": "off",
|
||||
"no-var": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
159
CONTRIBUTING.md
159
CONTRIBUTING.md
@ -131,89 +131,96 @@ changes.
|
||||
|
||||
### Code Standards
|
||||
|
||||
JavaScript sources in Open MCT must satisfy JSLint under its default
|
||||
settings. This is verified by the command line build.
|
||||
JavaScript sources in Open MCT must satisfy the ESLint rules defined in
|
||||
this repository. This is verified by the command line build.
|
||||
|
||||
#### Code Guidelines
|
||||
|
||||
JavaScript sources in Open MCT should:
|
||||
|
||||
* Use four spaces for indentation. Tabs should not be used.
|
||||
* Include JSDoc for any exposed API (e.g. public methods, constructors).
|
||||
* Include non-JSDoc comments as-needed for explaining private variables,
|
||||
methods, or algorithms when they are non-obvious.
|
||||
* Define one public class per script, expressed as a constructor function
|
||||
returned from an AMD-style module.
|
||||
* Follow “Java-like” naming conventions. These includes:
|
||||
* Classes should use camel case, first letter capitalized
|
||||
(e.g. SomeClassName).
|
||||
* Methods, variables, fields, and function names should use camel case,
|
||||
first letter lower-case (e.g. someVariableName).
|
||||
* Constants (variables or fields which are meant to be declared and
|
||||
initialized statically, and never changed) should use only capital
|
||||
letters, with underscores between words (e.g. SOME_CONSTANT).
|
||||
* File names should be the name of the exported class, plus a .js extension
|
||||
(e.g. SomeClassName.js).
|
||||
* Avoid anonymous functions, except when functions are short (a few lines)
|
||||
and/or their inclusion makes sense within the flow of the code
|
||||
(e.g. as arguments to a forEach call).
|
||||
* Avoid deep nesting (especially of functions), except where necessary
|
||||
(e.g. due to closure scope).
|
||||
* End with a single new-line character.
|
||||
* Expose public methods by declaring them on the class's prototype.
|
||||
* Within a given function's scope, do not mix declarations and imperative
|
||||
code, and present these in the following order:
|
||||
* First, variable declarations and initialization.
|
||||
* Second, function declarations.
|
||||
* Third, imperative statements.
|
||||
* Finally, the returned value.
|
||||
The following guidelines are provided for anyone contributing source code to the Open MCT project:
|
||||
|
||||
1. Write clean code. Here’s a good summary - https://github.com/ryanmcdermott/clean-code-javascript.
|
||||
1. Include JSDoc for any exposed API (e.g. public methods, classes).
|
||||
1. Include non-JSDoc comments as-needed for explaining private variables,
|
||||
methods, or algorithms when they are non-obvious. Otherwise code
|
||||
should be self-documenting.
|
||||
1. Classes and Vue components should use camel case, first letter capitalized
|
||||
(e.g. SomeClassName).
|
||||
1. Methods, variables, fields, events, and function names should use camelCase,
|
||||
first letter lower-case (e.g. someVariableName).
|
||||
1. Source files that export functions should use camelCase, first letter lower-case (eg. testTools.js)
|
||||
1. Constants (variables or fields which are meant to be declared and
|
||||
initialized statically, and never changed) should use only capital
|
||||
letters, with underscores between words (e.g. SOME_CONSTANT). They should always be declared as `const`s
|
||||
1. File names should be the name of the exported class, plus a .js extension
|
||||
(e.g. SomeClassName.js).
|
||||
1. Avoid anonymous functions, except when functions are short (one or two lines)
|
||||
and their inclusion makes sense within the flow of the code
|
||||
(e.g. as arguments to a forEach call). Anonymous functions should always be arrow functions.
|
||||
1. Named functions are preferred over functions assigned to variables.
|
||||
eg.
|
||||
```JavaScript
|
||||
function renameObject(object, newName) {
|
||||
Object.name = newName;
|
||||
}
|
||||
```
|
||||
is preferable to
|
||||
```JavaScript
|
||||
const rename = (object, newName) => {
|
||||
Object.name = newName;
|
||||
}
|
||||
```
|
||||
1. Avoid deep nesting (especially of functions), except where necessary
|
||||
(e.g. due to closure scope).
|
||||
1. End with a single new-line character.
|
||||
1. Always use ES6 `Class`es and inheritence rather than the pre-ES6 prototypal
|
||||
pattern.
|
||||
1. Within a given function's scope, do not mix declarations and imperative
|
||||
code, and present these in the following order:
|
||||
* First, variable declarations and initialization.
|
||||
* Secondly, imperative statements.
|
||||
* Finally, the returned value. Functions should only have a single return statement.
|
||||
1. Avoid the use of "magic" values.
|
||||
eg.
|
||||
```JavaScript
|
||||
Const UNAUTHORIZED = 401
|
||||
if (responseCode === UNAUTHORIZED)
|
||||
```
|
||||
is preferable to
|
||||
```JavaScript
|
||||
if (responseCode === 401)
|
||||
```
|
||||
1. Don’t use the ternary operator. Yes it's terse, but there's probably a clearer way of writing it.
|
||||
1. Test specs should reside alongside the source code they test, not in a separate directory.
|
||||
1. Organize code by feature, not by type.
|
||||
eg.
|
||||
```
|
||||
- telemetryTable
|
||||
- row
|
||||
TableRow.js
|
||||
TableRowCollection.js
|
||||
TableRow.vue
|
||||
- column
|
||||
TableColumn.js
|
||||
TableColumn.vue
|
||||
plugin.js
|
||||
pluginSpec.js
|
||||
```
|
||||
is preferable to
|
||||
```
|
||||
- telemetryTable
|
||||
- components
|
||||
TableRow.vue
|
||||
TableColumn.vue
|
||||
- collections
|
||||
TableRowCollection.js
|
||||
TableColumn.js
|
||||
TableRow.js
|
||||
plugin.js
|
||||
pluginSpec.js
|
||||
```
|
||||
Deviations from Open MCT code style guidelines require two-party agreement,
|
||||
typically from the author of the change and its reviewer.
|
||||
|
||||
#### Code Example
|
||||
|
||||
```js
|
||||
/*global define*/
|
||||
|
||||
/**
|
||||
* Bundles should declare themselves as namespaces in whichever source
|
||||
* file is most like the "main point of entry" to the bundle.
|
||||
* @namespace some/bundle
|
||||
*/
|
||||
define(
|
||||
['./OtherClass'],
|
||||
function (OtherClass) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A summary of how to use this class goes here.
|
||||
*
|
||||
* @constructor
|
||||
* @memberof some/bundle
|
||||
*/
|
||||
function ExampleClass() {
|
||||
}
|
||||
|
||||
// Methods which are not intended for external use should
|
||||
// not have JSDoc (or should be marked @private)
|
||||
ExampleClass.prototype.privateMethod = function () {
|
||||
};
|
||||
|
||||
/**
|
||||
* A summary of this method goes here.
|
||||
* @param {number} n a parameter
|
||||
* @returns {number} a return value
|
||||
*/
|
||||
ExampleClass.prototype.publicMethod = function (n) {
|
||||
return n * 2;
|
||||
}
|
||||
|
||||
return ExampleClass;
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### Test Standards
|
||||
|
||||
Automated testing shall occur whenever changes are merged into the main
|
||||
|
@ -52,6 +52,7 @@ define([
|
||||
return {
|
||||
name: name,
|
||||
utc: Math.floor(timestamp / 5000) * 5000,
|
||||
local: Math.floor(timestamp / 5000) * 5000,
|
||||
url: IMAGE_SAMPLES[Math.floor(timestamp / 5000) % IMAGE_SAMPLES.length]
|
||||
};
|
||||
}
|
||||
@ -78,7 +79,7 @@ define([
|
||||
},
|
||||
request: function (domainObject, options) {
|
||||
var start = options.start;
|
||||
var end = options.end;
|
||||
var end = Math.min(options.end, Date.now());
|
||||
var data = [];
|
||||
while (start <= end && data.length < 5000) {
|
||||
data.push(pointForTimestamp(start, domainObject.name));
|
||||
@ -118,6 +119,14 @@ define([
|
||||
name: 'Time',
|
||||
key: 'utc',
|
||||
format: 'utc',
|
||||
hints: {
|
||||
domain: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Local Time',
|
||||
key: 'local',
|
||||
format: 'local-format',
|
||||
hints: {
|
||||
domain: 1
|
||||
}
|
||||
|
@ -6,6 +6,12 @@
|
||||
ng-show="ngModel.dialog.messages.length > 1 ||
|
||||
ngModel.dialog.messages.length == 0">s</span>
|
||||
</div>
|
||||
<button
|
||||
ng-if="ngModel.dialog.topBarButton"
|
||||
class="c-button c-button--major"
|
||||
ng-click="ngModel.topBarButton.onClick">
|
||||
{{ ngModel.topBarButton.label }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="w-messages c-overlay__messages">
|
||||
<mct-include
|
||||
@ -16,7 +22,7 @@
|
||||
<button ng-repeat="dialogAction in ngModel.dialog.actions"
|
||||
class="c-button c-button--major"
|
||||
ng-click="dialogAction.action()">
|
||||
{{dialogAction.label}}
|
||||
{{ dialogAction.label }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -21,44 +21,15 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
"./src/NotificationIndicatorController",
|
||||
"./src/NotificationIndicator",
|
||||
"./src/NotificationService",
|
||||
"./res/notification-indicator.html"
|
||||
"./src/NotificationService"
|
||||
], function (
|
||||
NotificationIndicatorController,
|
||||
NotificationIndicator,
|
||||
NotificationService,
|
||||
notificationIndicatorTemplate
|
||||
NotificationService
|
||||
) {
|
||||
|
||||
return {
|
||||
name:"platform/commonUI/notification",
|
||||
definition: {
|
||||
"extensions": {
|
||||
"templates": [
|
||||
{
|
||||
"key": "notificationIndicatorTemplate",
|
||||
"template": notificationIndicatorTemplate
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "NotificationIndicatorController",
|
||||
"implementation": NotificationIndicatorController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"openmct",
|
||||
"dialogService"
|
||||
]
|
||||
}
|
||||
],
|
||||
"indicators": [
|
||||
{
|
||||
"implementation": NotificationIndicator,
|
||||
"priority": "fallback"
|
||||
}
|
||||
],
|
||||
"services": [
|
||||
{
|
||||
"key": "notificationService",
|
||||
|
@ -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>
|
@ -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;
|
||||
}
|
||||
);
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
621
report.20200527.134750.93992.001.json
Normal file
621
report.20200527.134750.93992.001.json
Normal 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"
|
||||
]
|
||||
}
|
@ -240,7 +240,7 @@ define([
|
||||
|
||||
this.overlays = new OverlayAPI.default();
|
||||
|
||||
this.contextMenu = new api.ContextMenuRegistry();
|
||||
this.menus = new api.MenuAPI(this);
|
||||
|
||||
this.router = new ApplicationRouter();
|
||||
|
||||
@ -266,6 +266,7 @@ define([
|
||||
this.install(this.plugins.WebPage());
|
||||
this.install(this.plugins.Condition());
|
||||
this.install(this.plugins.ConditionWidget());
|
||||
this.install(this.plugins.NotificationIndicator());
|
||||
}
|
||||
|
||||
MCT.prototype = Object.create(EventEmitter.prototype);
|
||||
|
@ -33,5 +33,5 @@ export default function LegacyActionAdapter(openmct, legacyActions) {
|
||||
|
||||
legacyActions.filter(contextualCategoryOnly)
|
||||
.map(LegacyAction => new LegacyContextMenuAction(openmct, LegacyAction))
|
||||
.forEach(openmct.contextMenu.registerAction);
|
||||
.forEach(openmct.menus.registerObjectAction);
|
||||
}
|
||||
|
@ -28,8 +28,8 @@ define([
|
||||
'./telemetry/TelemetryAPI',
|
||||
'./indicators/IndicatorAPI',
|
||||
'./notifications/NotificationAPI',
|
||||
'./contextMenu/ContextMenuAPI',
|
||||
'./Editor'
|
||||
'./Editor',
|
||||
'./menu/MenuAPI'
|
||||
|
||||
], function (
|
||||
TimeAPI,
|
||||
@ -39,8 +39,8 @@ define([
|
||||
TelemetryAPI,
|
||||
IndicatorAPI,
|
||||
NotificationAPI,
|
||||
ContextMenuAPI,
|
||||
EditorAPI
|
||||
EditorAPI,
|
||||
MenuAPI
|
||||
) {
|
||||
return {
|
||||
TimeAPI: TimeAPI,
|
||||
@ -51,6 +51,6 @@ define([
|
||||
IndicatorAPI: IndicatorAPI,
|
||||
NotificationAPI: NotificationAPI.default,
|
||||
EditorAPI: EditorAPI,
|
||||
ContextMenuRegistry: ContextMenuAPI.default
|
||||
MenuAPI: MenuAPI.default
|
||||
};
|
||||
});
|
||||
|
@ -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
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
@ -20,29 +20,32 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
import ContextMenuComponent from './ContextMenu.vue';
|
||||
import Vue from 'vue';
|
||||
import Menu from './menu.js';
|
||||
|
||||
/**
|
||||
* The ContextMenuAPI allows the addition of new context menu actions, and for the context menu to be launched from
|
||||
* The MenuAPI allows the addition of new context menu actions, and for the context menu to be launched from
|
||||
* custom HTML elements.
|
||||
* @interface ContextMenuAPI
|
||||
* @interface MenuAPI
|
||||
* @memberof module:openmct
|
||||
*/
|
||||
class ContextMenuAPI {
|
||||
constructor() {
|
||||
this._allActions = [];
|
||||
this._activeContextMenu = undefined;
|
||||
|
||||
this._hideActiveContextMenu = this._hideActiveContextMenu.bind(this);
|
||||
this.registerAction = this.registerAction.bind(this);
|
||||
class MenuAPI {
|
||||
constructor(openmct) {
|
||||
this.openmct = openmct;
|
||||
this._allObjectActions = [];
|
||||
|
||||
this.showMenu = this.showMenu.bind(this);
|
||||
this.registerObjectAction = this.registerObjectAction.bind(this);
|
||||
this._clearMenuComponent = this._clearMenuComponent.bind(this);
|
||||
this._applicableObjectActions = this._applicableObjectActions.bind(this);
|
||||
this._showObjectMenu = this._showObjectMenu.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines an item to be added to context menus. Allows specification of text, appearance, and behavior when
|
||||
* selected. Applicabilioty can be restricted by specification of an `appliesTo` function.
|
||||
*
|
||||
* @interface ContextMenuAction
|
||||
* @interface ObjectAction
|
||||
* @memberof module:openmct
|
||||
* @property {string} name the human-readable name of this view
|
||||
* @property {string} description a longer-form description (typically
|
||||
@ -68,17 +71,32 @@ class ContextMenuAPI {
|
||||
/**
|
||||
* @param {ContextMenuAction} actionDefinition
|
||||
*/
|
||||
registerAction(actionDefinition) {
|
||||
this._allActions.push(actionDefinition);
|
||||
registerObjectAction(actionDefinition) {
|
||||
this._allObjectActions.push(actionDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_showContextMenuForObjectPath(objectPath, x, y, actionsToBeIncluded) {
|
||||
showMenu(x, y, actions) {
|
||||
if (this.menuComponent) {
|
||||
this.menuComponent.dismiss();
|
||||
}
|
||||
|
||||
let applicableActions = this._allActions.filter((action) => {
|
||||
let options = {
|
||||
x,
|
||||
y,
|
||||
actions
|
||||
}
|
||||
|
||||
this.menuComponent = new Menu(options);
|
||||
this.menuComponent.on('destroy', this._clearMenuComponent);
|
||||
}
|
||||
|
||||
_clearMenuComponent() {
|
||||
this.menuComponent = undefined;
|
||||
delete this.menuComponent;
|
||||
}
|
||||
|
||||
_applicableObjectActions(objectPath, actionsToBeIncluded) {
|
||||
let applicableActions = this._allObjectActions.filter((action) => {
|
||||
if (actionsToBeIncluded) {
|
||||
if (action.appliesTo === undefined && actionsToBeIncluded.includes(action.key)) {
|
||||
return true;
|
||||
@ -92,66 +110,19 @@ class ContextMenuAPI {
|
||||
}
|
||||
});
|
||||
|
||||
if (this._activeContextMenu) {
|
||||
this._hideActiveContextMenu();
|
||||
}
|
||||
|
||||
this._activeContextMenu = this._createContextMenuForObject(objectPath, applicableActions);
|
||||
this._activeContextMenu.$mount();
|
||||
document.body.appendChild(this._activeContextMenu.$el);
|
||||
|
||||
let position = this._calculatePopupPosition(x, y, this._activeContextMenu.$el);
|
||||
this._activeContextMenu.$el.style.left = `${position.x}px`;
|
||||
this._activeContextMenu.$el.style.top = `${position.y}px`;
|
||||
|
||||
document.addEventListener('click', this._hideActiveContextMenu);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_calculatePopupPosition(eventPosX, eventPosY, menuElement) {
|
||||
let menuDimensions = menuElement.getBoundingClientRect();
|
||||
let overflowX = (eventPosX + menuDimensions.width) - document.body.clientWidth;
|
||||
let overflowY = (eventPosY + menuDimensions.height) - document.body.clientHeight;
|
||||
|
||||
if (overflowX > 0) {
|
||||
eventPosX = eventPosX - overflowX;
|
||||
}
|
||||
|
||||
if (overflowY > 0) {
|
||||
eventPosY = eventPosY - overflowY;
|
||||
}
|
||||
|
||||
return {
|
||||
x: eventPosX,
|
||||
y: eventPosY
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_hideActiveContextMenu() {
|
||||
document.removeEventListener('click', this._hideActiveContextMenu);
|
||||
document.body.removeChild(this._activeContextMenu.$el);
|
||||
this._activeContextMenu.$destroy();
|
||||
this._activeContextMenu = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_createContextMenuForObject(objectPath, actions) {
|
||||
return new Vue({
|
||||
components: {
|
||||
ContextMenu: ContextMenuComponent
|
||||
},
|
||||
provide: {
|
||||
actions: actions,
|
||||
objectPath: objectPath
|
||||
},
|
||||
template: '<ContextMenu></ContextMenu>'
|
||||
applicableActions.forEach(action => {
|
||||
action.callBack = () => {
|
||||
return action.invoke(objectPath);
|
||||
};
|
||||
});
|
||||
|
||||
return applicableActions;
|
||||
}
|
||||
|
||||
_showObjectMenu(objectPath, x, y, actionsToBeIncluded) {
|
||||
let applicableActions = this._applicableObjectActions(objectPath, actionsToBeIncluded);
|
||||
|
||||
this.showMenu(x, y, applicableActions);
|
||||
}
|
||||
}
|
||||
export default ContextMenuAPI;
|
||||
export default MenuAPI;
|
@ -6,7 +6,7 @@
|
||||
:key="action.name"
|
||||
:class="action.cssClass"
|
||||
:title="action.description"
|
||||
@click="action.invoke(objectPath)"
|
||||
@click="action.callBack"
|
||||
>
|
||||
{{ action.name }}
|
||||
</li>
|
||||
@ -19,6 +19,6 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['actions', 'objectPath']
|
||||
inject: ['actions']
|
||||
}
|
||||
</script>
|
94
src/api/menu/menu.js
Normal file
94
src/api/menu/menu.js
Normal file
@ -0,0 +1,94 @@
|
||||
/*****************************************************************************
|
||||
* 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 EventEmitter from 'EventEmitter';
|
||||
import MenuComponent from './components/Menu.vue';
|
||||
import Vue from 'vue';
|
||||
|
||||
class Menu extends EventEmitter {
|
||||
constructor(options) {
|
||||
super();
|
||||
|
||||
this.options = options;
|
||||
|
||||
this.component = new Vue({
|
||||
provide: {
|
||||
actions: options.actions
|
||||
},
|
||||
components: {
|
||||
MenuComponent
|
||||
},
|
||||
template: '<menu-component />'
|
||||
});
|
||||
|
||||
if (options.onDestroy) {
|
||||
this.once('destroy', options.onDestroy);
|
||||
}
|
||||
|
||||
this.dismiss = this.dismiss.bind(this);
|
||||
this.show = this.show.bind(this);
|
||||
|
||||
this.show();
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.emit('destroy');
|
||||
document.body.removeChild(this.component.$el);
|
||||
document.removeEventListener('click', this.dismiss);
|
||||
this.component.$destroy();
|
||||
}
|
||||
|
||||
show() {
|
||||
this.component.$mount();
|
||||
document.body.appendChild(this.component.$el);
|
||||
|
||||
let position = this._calculatePopupPosition(this.options.x, this.options.y, this.component.$el);
|
||||
|
||||
this.component.$el.style.left = `${position.x}px`;
|
||||
this.component.$el.style.top = `${position.y}px`;
|
||||
|
||||
document.addEventListener('click', this.dismiss);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_calculatePopupPosition(eventPosX, eventPosY, menuElement) {
|
||||
let menuDimensions = menuElement.getBoundingClientRect();
|
||||
let overflowX = (eventPosX + menuDimensions.width) - document.body.clientWidth;
|
||||
let overflowY = (eventPosY + menuDimensions.height) - document.body.clientHeight;
|
||||
|
||||
if (overflowX > 0) {
|
||||
eventPosX = eventPosX - overflowX;
|
||||
}
|
||||
|
||||
if (overflowY > 0) {
|
||||
eventPosY = eventPosY - overflowY;
|
||||
}
|
||||
|
||||
return {
|
||||
x: eventPosX,
|
||||
y: eventPosY
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default Menu;
|
@ -128,6 +128,11 @@ export default class NotificationAPI extends EventEmitter {
|
||||
return this._notify(notificationModel);
|
||||
}
|
||||
|
||||
dismissAllNotifications() {
|
||||
this.notifications = [];
|
||||
this.emit('dismiss-all');
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimize a notification. The notification will still be available
|
||||
* from the notification list. Typically notifications with a
|
||||
|
@ -22,6 +22,7 @@ class OverlayAPI {
|
||||
this.dismissLastOverlay();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,6 +129,7 @@ class OverlayAPI {
|
||||
|
||||
return progressDialog;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default OverlayAPI;
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
/*****************************************************************************
|
||||
* 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
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
@ -24,10 +24,8 @@
|
||||
<template>
|
||||
<tr @contextmenu.prevent="showContextMenu">
|
||||
<td>{{ name }}</td>
|
||||
<td>{{ timestamp }}</td>
|
||||
<td :class="valueClass">
|
||||
{{ value }}
|
||||
</td>
|
||||
<td>{{ formattedTimestamp }}</td>
|
||||
<td :class="valueClass">{{ value }}</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
@ -52,16 +50,22 @@ export default {
|
||||
|
||||
return {
|
||||
name: this.domainObject.name,
|
||||
timestamp: '---',
|
||||
timestamp: undefined,
|
||||
value: '---',
|
||||
valueClass: '',
|
||||
currentObjectPath
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
formattedTimestamp() {
|
||||
return this.timestamp !== undefined ? this.formats[this.timestampKey].format(this.timestamp) : '---';
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
||||
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
|
||||
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
this.bounds = this.openmct.time.bounds();
|
||||
|
||||
this.limitEvaluator = this.openmct
|
||||
.telemetry
|
||||
@ -76,6 +80,7 @@ export default {
|
||||
);
|
||||
|
||||
this.openmct.time.on('timeSystem', this.updateTimeSystem);
|
||||
this.openmct.time.on('bounds', this.updateBounds);
|
||||
|
||||
this.timestampKey = this.openmct.time.timeSystem().key;
|
||||
|
||||
@ -89,46 +94,66 @@ export default {
|
||||
.telemetry
|
||||
.subscribe(this.domainObject, this.updateValues);
|
||||
|
||||
this.openmct
|
||||
.telemetry
|
||||
.request(this.domainObject, {strategy: 'latest'})
|
||||
.then((array) => this.updateValues(array[array.length - 1]));
|
||||
this.requestHistory();
|
||||
},
|
||||
destroyed() {
|
||||
this.stopWatchingMutation();
|
||||
this.unsubscribe();
|
||||
this.openmct.off('timeSystem', this.updateTimeSystem);
|
||||
this.openmct.time.off('timeSystem', this.updateTimeSystem);
|
||||
this.openmct.time.off('bounds', this.updateBounds);
|
||||
},
|
||||
methods: {
|
||||
updateValues(datum) {
|
||||
this.timestamp = this.formats[this.timestampKey].format(datum);
|
||||
this.value = this.formats[this.valueKey].format(datum);
|
||||
let newTimestamp = this.formats[this.timestampKey].parse(datum),
|
||||
limit;
|
||||
|
||||
var limit = this.limitEvaluator.evaluate(datum, this.valueMetadata);
|
||||
|
||||
if (limit) {
|
||||
this.valueClass = limit.cssClass;
|
||||
} else {
|
||||
this.valueClass = '';
|
||||
if(this.shouldUpdate(newTimestamp)) {
|
||||
this.timestamp = this.formats[this.timestampKey].parse(datum);
|
||||
this.value = this.formats[this.valueKey].format(datum);
|
||||
limit = this.limitEvaluator.evaluate(datum, this.valueMetadata);
|
||||
if (limit) {
|
||||
this.valueClass = limit.cssClass;
|
||||
} else {
|
||||
this.valueClass = '';
|
||||
}
|
||||
}
|
||||
},
|
||||
shouldUpdate(newTimestamp) {
|
||||
return (this.timestamp === undefined) ||
|
||||
(this.inBounds(newTimestamp) &&
|
||||
newTimestamp > this.timestamp);
|
||||
},
|
||||
requestHistory() {
|
||||
this.openmct
|
||||
.telemetry
|
||||
.request(this.domainObject, {
|
||||
start: this.bounds.start,
|
||||
end: this.bounds.end,
|
||||
size: 1,
|
||||
strategy: 'latest'
|
||||
})
|
||||
.then((array) => this.updateValues(array[array.length - 1]));
|
||||
},
|
||||
updateName(name) {
|
||||
this.name = name;
|
||||
},
|
||||
updateBounds(bounds, isTick) {
|
||||
this.bounds = bounds;
|
||||
if(!isTick) {
|
||||
this.requestHistory();
|
||||
}
|
||||
},
|
||||
inBounds(timestamp) {
|
||||
return timestamp >= this.bounds.start && timestamp <= this.bounds.end;
|
||||
},
|
||||
updateTimeSystem(timeSystem) {
|
||||
this.value = '---';
|
||||
this.timestamp = '---';
|
||||
this.valueClass = '';
|
||||
this.timestampKey = timeSystem.key;
|
||||
|
||||
this.openmct
|
||||
.telemetry
|
||||
.request(this.domainObject, {strategy: 'latest'})
|
||||
.then((array) => this.updateValues(array[array.length - 1]));
|
||||
|
||||
},
|
||||
showContextMenu(event) {
|
||||
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
|
||||
this.openmct.menus._showObjectMenu(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ define([
|
||||
|
||||
openmct.indicators.add(indicator);
|
||||
|
||||
openmct.contextMenu.registerAction(new ClearDataAction.default(openmct, appliesToObjects));
|
||||
openmct.menus.registerObjectAction(new ClearDataAction.default(openmct, appliesToObjects));
|
||||
};
|
||||
};
|
||||
});
|
||||
|
@ -29,6 +29,7 @@ export default class StyleRuleManager extends EventEmitter {
|
||||
this.callback = callback;
|
||||
if (suppressSubscriptionOnEdit) {
|
||||
this.openmct.editor.on('isEditing', this.toggleSubscription.bind(this));
|
||||
this.isEditing = this.openmct.editor.editing;
|
||||
}
|
||||
if (styleConfiguration) {
|
||||
this.initialize(styleConfiguration);
|
||||
@ -156,7 +157,6 @@ export default class StyleRuleManager extends EventEmitter {
|
||||
}
|
||||
delete this.stopProvidingTelemetry;
|
||||
this.conditionSetIdentifier = undefined;
|
||||
this.isEditing = undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
601
src/plugins/condition/components/inspector/StylesView.vue
Normal file
601
src/plugins/condition/components/inspector/StylesView.vue
Normal 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 (objectStyles && 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 (domainObjectStyles[itemId] && Object.keys(domainObjectStyles[itemId]).length <= 0) {
|
||||
delete domainObjectStyles[itemId];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.removeConditionalStyles(domainObjectStyles);
|
||||
}
|
||||
if (domainObjectStyles && 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 = Object.assign({}, domainObjectStyles[item.id].staticStyle.style);
|
||||
}
|
||||
if (item.applicableStyles[property] !== undefined) {
|
||||
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>
|
@ -22,6 +22,9 @@
|
||||
|
||||
import { createOpenMct } from "testUtils";
|
||||
import ConditionPlugin from "./plugin";
|
||||
import StylesView from "./components/inspector/StylesView.vue";
|
||||
import Vue from 'vue';
|
||||
import {getApplicableStylesForItem} from "./utils/styleUtils";
|
||||
|
||||
describe('the plugin', function () {
|
||||
let conditionSetDefinition;
|
||||
@ -30,7 +33,7 @@ describe('the plugin', function () {
|
||||
let child;
|
||||
let openmct;
|
||||
|
||||
beforeAll((done) => {
|
||||
beforeEach((done) => {
|
||||
openmct = createOpenMct();
|
||||
openmct.install(new ConditionPlugin());
|
||||
|
||||
@ -90,4 +93,259 @@ describe('the plugin', function () {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('the condition set usage for multiple display layout items', () => {
|
||||
let displayLayoutItem;
|
||||
let lineLayoutItem;
|
||||
let boxLayoutItem;
|
||||
let selection;
|
||||
let component;
|
||||
let styleViewComponentObject;
|
||||
const conditionSetDomainObject = {
|
||||
"configuration":{
|
||||
"conditionTestData":[
|
||||
{
|
||||
"telemetry":"",
|
||||
"metadata":"",
|
||||
"input":""
|
||||
}
|
||||
],
|
||||
"conditionCollection":[
|
||||
{
|
||||
"id":"39584410-cbf9-499e-96dc-76f27e69885d",
|
||||
"configuration":{
|
||||
"name":"Unnamed Condition",
|
||||
"output":"Sine > 0",
|
||||
"trigger":"all",
|
||||
"criteria":[
|
||||
{
|
||||
"id":"85fbb2f7-7595-42bd-9767-a932266c5225",
|
||||
"telemetry":{
|
||||
"namespace":"",
|
||||
"key":"be0ba97f-b510-4f40-a18d-4ff121d5ea1a"
|
||||
},
|
||||
"operation":"greaterThan",
|
||||
"input":[
|
||||
"0"
|
||||
],
|
||||
"metadata":"sin"
|
||||
},
|
||||
{
|
||||
"id":"35400132-63b0-425c-ac30-8197df7d5862",
|
||||
"telemetry":"any",
|
||||
"operation":"enumValueIs",
|
||||
"input":[
|
||||
"0"
|
||||
],
|
||||
"metadata":"state"
|
||||
}
|
||||
]
|
||||
},
|
||||
"summary":"Match if all criteria are met: Sine Wave Generator Sine > 0 and any telemetry State is OFF "
|
||||
},
|
||||
{
|
||||
"isDefault":true,
|
||||
"id":"2532d90a-e0d6-4935-b546-3123522da2de",
|
||||
"configuration":{
|
||||
"name":"Default",
|
||||
"output":"Default",
|
||||
"trigger":"all",
|
||||
"criteria":[
|
||||
]
|
||||
},
|
||||
"summary":""
|
||||
}
|
||||
]
|
||||
},
|
||||
"composition":[
|
||||
{
|
||||
"namespace":"",
|
||||
"key":"be0ba97f-b510-4f40-a18d-4ff121d5ea1a"
|
||||
},
|
||||
{
|
||||
"namespace":"",
|
||||
"key":"077ffa67-e78f-4e99-80e0-522ac33a3888"
|
||||
}
|
||||
],
|
||||
"telemetry":{
|
||||
},
|
||||
"name":"Condition Set",
|
||||
"type":"conditionSet",
|
||||
"identifier":{
|
||||
"namespace":"",
|
||||
"key":"863012c1-f6ca-4ab0-aed7-fd43d5e4cd12"
|
||||
}
|
||||
|
||||
};
|
||||
const staticStyle = {
|
||||
"style":{
|
||||
"backgroundColor":"#717171",
|
||||
"border":"1px solid #00ffff"
|
||||
}
|
||||
};
|
||||
const conditionalStyle = {
|
||||
"conditionId":"39584410-cbf9-499e-96dc-76f27e69885d",
|
||||
"style":{
|
||||
"isStyleInvisible":"",
|
||||
"backgroundColor":"#717171",
|
||||
"border":"1px solid #ffff00"
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
displayLayoutItem = {
|
||||
"composition":[
|
||||
],
|
||||
"configuration":{
|
||||
"items":[
|
||||
{
|
||||
"fill":"#717171",
|
||||
"stroke":"",
|
||||
"x":1,
|
||||
"y":1,
|
||||
"width":10,
|
||||
"height":5,
|
||||
"type":"box-view",
|
||||
"id":"89b88746-d325-487b-aec4-11b79afff9e8"
|
||||
},
|
||||
{
|
||||
"x":18,
|
||||
"y":9,
|
||||
"x2":23,
|
||||
"y2":4,
|
||||
"stroke":"#717171",
|
||||
"type":"line-view",
|
||||
"id":"57d49a28-7863-43bd-9593-6570758916f0"
|
||||
}
|
||||
],
|
||||
"layoutGrid":[
|
||||
10,
|
||||
10
|
||||
]
|
||||
},
|
||||
"name":"Display Layout",
|
||||
"type":"layout",
|
||||
"identifier":{
|
||||
"namespace":"",
|
||||
"key":"c5e636c1-6771-4c9c-b933-8665cab189b3"
|
||||
}
|
||||
};
|
||||
lineLayoutItem = {
|
||||
"x":18,
|
||||
"y":9,
|
||||
"x2":23,
|
||||
"y2":4,
|
||||
"stroke":"#717171",
|
||||
"type":"line-view",
|
||||
"id":"57d49a28-7863-43bd-9593-6570758916f0"
|
||||
};
|
||||
boxLayoutItem = {
|
||||
"fill": "#717171",
|
||||
"stroke": "",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"width": 10,
|
||||
"height": 5,
|
||||
"type": "box-view",
|
||||
"id": "89b88746-d325-487b-aec4-11b79afff9e8"
|
||||
};
|
||||
selection = [
|
||||
[{
|
||||
context: {
|
||||
"layoutItem": lineLayoutItem,
|
||||
"index":1
|
||||
}
|
||||
},
|
||||
{
|
||||
context: {
|
||||
"item": displayLayoutItem,
|
||||
"supportsMultiSelect":true
|
||||
}
|
||||
}],
|
||||
[{
|
||||
context: {
|
||||
"layoutItem": boxLayoutItem,
|
||||
"index": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
context: {
|
||||
item: displayLayoutItem,
|
||||
"supportsMultiSelect":true
|
||||
}
|
||||
}]
|
||||
];
|
||||
let viewContainer = document.createElement('div');
|
||||
child.append(viewContainer);
|
||||
component = new Vue({
|
||||
provide: {
|
||||
openmct: openmct,
|
||||
selection: selection
|
||||
},
|
||||
el: viewContainer,
|
||||
components: {
|
||||
StylesView
|
||||
},
|
||||
template: '<styles-view/>'
|
||||
});
|
||||
return Vue.nextTick().then(() => {
|
||||
styleViewComponentObject = component.$root.$children[0];
|
||||
styleViewComponentObject.setEditState(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('initializes the items in the view', () => {
|
||||
expect(styleViewComponentObject.items.length).toBe(2);
|
||||
});
|
||||
|
||||
it('initializes conditional styles', () => {
|
||||
styleViewComponentObject.conditionSetDomainObject = conditionSetDomainObject;
|
||||
styleViewComponentObject.conditionalStyles = [];
|
||||
styleViewComponentObject.initializeConditionalStyles();
|
||||
expect(styleViewComponentObject.conditionalStyles.length).toBe(2);
|
||||
});
|
||||
|
||||
it('updates applicable conditional styles', () => {
|
||||
styleViewComponentObject.conditionSetDomainObject = conditionSetDomainObject;
|
||||
styleViewComponentObject.conditionalStyles = [];
|
||||
styleViewComponentObject.initializeConditionalStyles();
|
||||
expect(styleViewComponentObject.conditionalStyles.length).toBe(2);
|
||||
styleViewComponentObject.updateConditionalStyle(conditionalStyle, 'border');
|
||||
return Vue.nextTick().then(() => {
|
||||
expect(styleViewComponentObject.domainObject.configuration.objectStyles).toBeDefined();
|
||||
[boxLayoutItem, lineLayoutItem].forEach((item) => {
|
||||
const itemStyles = styleViewComponentObject.domainObject.configuration.objectStyles[item.id].styles;
|
||||
expect(itemStyles.length).toBe(2);
|
||||
const foundStyle = itemStyles.find((style) => {
|
||||
return style.conditionId === conditionalStyle.conditionId;
|
||||
});
|
||||
expect(foundStyle).toBeDefined();
|
||||
const applicableStyles = getApplicableStylesForItem(styleViewComponentObject.domainObject, item);
|
||||
const applicableStylesKeys = Object.keys(applicableStyles).concat(['isStyleInvisible']);
|
||||
Object.keys(foundStyle.style).forEach((key) => {
|
||||
expect(applicableStylesKeys.indexOf(key)).toBeGreaterThan(-1);
|
||||
expect(foundStyle.style[key]).toEqual(conditionalStyle.style[key]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('updates applicable static styles', () => {
|
||||
styleViewComponentObject.updateStaticStyle(staticStyle, 'border');
|
||||
return Vue.nextTick().then(() => {
|
||||
expect(styleViewComponentObject.domainObject.configuration.objectStyles).toBeDefined();
|
||||
[boxLayoutItem, lineLayoutItem].forEach((item) => {
|
||||
const itemStyle = styleViewComponentObject.domainObject.configuration.objectStyles[item.id].staticStyle;
|
||||
expect(itemStyle).toBeDefined();
|
||||
const applicableStyles = getApplicableStylesForItem(styleViewComponentObject.domainObject, item);
|
||||
const applicableStylesKeys = Object.keys(applicableStyles).concat(['isStyleInvisible']);
|
||||
Object.keys(itemStyle.style).forEach((key) => {
|
||||
expect(applicableStylesKeys.indexOf(key)).toBeGreaterThan(-1);
|
||||
expect(itemStyle.style[key]).toEqual(staticStyle.style[key]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
@ -124,12 +124,25 @@ export const getConditionalStyleForItem = (domainObject, id) => {
|
||||
if (domainObjectStyles[id] && domainObjectStyles[id].conditionSetIdentifier) {
|
||||
return domainObjectStyles[id].styles;
|
||||
}
|
||||
} else if (domainObjectStyles.staticStyle) {
|
||||
} else if (domainObjectStyles.conditionSetIdentifier) {
|
||||
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
|
||||
export const getApplicableStylesForItem = (domainObject, item) => {
|
||||
const type = item && item.type;
|
||||
|
@ -248,7 +248,7 @@ export default {
|
||||
this.$emit('formatChanged', this.item, format);
|
||||
},
|
||||
showContextMenu(event) {
|
||||
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
|
||||
this.openmct.menus._showObjectMenu(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,6 @@ import GoToOriginalAction from './goToOriginalAction';
|
||||
|
||||
export default function () {
|
||||
return function (openmct) {
|
||||
openmct.contextMenu.registerAction(new GoToOriginalAction(openmct));
|
||||
openmct.menus.registerObjectAction(new GoToOriginalAction(openmct));
|
||||
};
|
||||
}
|
||||
|
@ -66,7 +66,6 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
autoScroll: true,
|
||||
date: '',
|
||||
filters : {
|
||||
brightness: 100,
|
||||
contrast: 100
|
||||
@ -78,22 +77,39 @@ export default {
|
||||
imageHistory: [],
|
||||
imageUrl: '',
|
||||
isPaused: false,
|
||||
metadata: {},
|
||||
requestCount: 0,
|
||||
timeFormat: ''
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// set
|
||||
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() {
|
||||
this.scrollToRight();
|
||||
},
|
||||
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: {
|
||||
datumMatchesMostRecent(datum) {
|
||||
datumIsNotValid(datum) {
|
||||
if (this.imageHistory.length === 0) {
|
||||
return false;
|
||||
}
|
||||
@ -103,7 +119,14 @@ export default {
|
||||
const lastHistoryTime = this.timeFormat.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) {
|
||||
return datum ?
|
||||
@ -147,21 +170,6 @@ export default {
|
||||
|
||||
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() {
|
||||
if (this.isPaused || !this.$refs.thumbsWrapper || !this.autoScroll) {
|
||||
return;
|
||||
@ -188,40 +196,56 @@ export default {
|
||||
image.selected = true;
|
||||
}
|
||||
},
|
||||
stopListening() {
|
||||
if (this.unsubscribe) {
|
||||
this.unsubscribe();
|
||||
delete this.unsubscribe;
|
||||
boundsChange(bounds, isTick) {
|
||||
if(!isTick) {
|
||||
this.requestHistory();
|
||||
}
|
||||
},
|
||||
subscribe(domainObject) {
|
||||
this.date = ''
|
||||
this.imageUrl = '';
|
||||
this.openmct.objects.get(this.keystring)
|
||||
.then((object) => {
|
||||
const metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
||||
this.timeKey = this.openmct.time.timeSystem().key;
|
||||
this.timeFormat = this.openmct.telemetry.getValueFormatter(metadata.value(this.timeKey));
|
||||
this.imageFormat = this.openmct.telemetry.getValueFormatter(metadata.valuesForHints(['image'])[0]);
|
||||
this.unsubscribe = this.openmct.telemetry
|
||||
.subscribe(this.domainObject, (datum) => {
|
||||
this.updateHistory(datum);
|
||||
this.updateValues(datum);
|
||||
});
|
||||
requestHistory() {
|
||||
let bounds = this.openmct.time.bounds();
|
||||
this.requestCount++;
|
||||
const requestId = this.requestCount;
|
||||
this.imageHistory = [];
|
||||
this.openmct.telemetry
|
||||
.request(this.domainObject, bounds)
|
||||
.then((values = []) => {
|
||||
if (this.requestCount === requestId) {
|
||||
values.forEach(this.updateHistory, false);
|
||||
this.updateValues(values[values.length - 1]);
|
||||
}
|
||||
});
|
||||
},
|
||||
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() {
|
||||
this.imageHistory.forEach(image => image.selected = false);
|
||||
},
|
||||
updateHistory(datum) {
|
||||
if (this.datumMatchesMostRecent(datum)) {
|
||||
updateHistory(datum, updateValues = true) {
|
||||
if (this.datumIsNotValid(datum)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = _.sortedIndexBy(this.imageHistory, datum, this.timeFormat.format.bind(this.timeFormat));
|
||||
this.imageHistory.splice(index, 0, datum);
|
||||
|
||||
if(updateValues) {
|
||||
this.updateValues(datum);
|
||||
}
|
||||
},
|
||||
updateValues(datum) {
|
||||
if (this.isPaused) {
|
||||
|
@ -169,12 +169,10 @@ export default {
|
||||
|
||||
const bounds = this.openmct.time.bounds();
|
||||
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();
|
||||
|
||||
this.openmct.time.stopClock();
|
||||
window.location.href = link;
|
||||
|
||||
let message = '';
|
||||
if (isTimeBoundChanged) {
|
||||
this.openmct.time.bounds({
|
||||
@ -188,7 +186,11 @@ export default {
|
||||
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) {
|
||||
return Moment.utc(unixTime).format(timeFormat);
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
@ -19,15 +19,25 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
import Vue from 'vue';
|
||||
import NotificationIndicator from './components/NotificationIndicator.vue';
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
export default function plugin() {
|
||||
return function install(openmct) {
|
||||
let component = new Vue ({
|
||||
provide: {
|
||||
openmct
|
||||
},
|
||||
components: {
|
||||
NotificationIndicator: NotificationIndicator
|
||||
},
|
||||
template: '<NotificationIndicator></NotificationIndicator>'
|
||||
}),
|
||||
indicator = {
|
||||
key: 'notifications-indicator',
|
||||
element: component.$mount().$el
|
||||
};
|
||||
|
||||
function NotificationIndicator() {}
|
||||
|
||||
NotificationIndicator.template = 'notificationIndicatorTemplate';
|
||||
|
||||
return NotificationIndicator;
|
||||
}
|
||||
);
|
||||
openmct.indicators.add(indicator);
|
||||
};
|
||||
}
|
71
src/plugins/notificationIndicator/pluginSpec.js
Normal file
71
src/plugins/notificationIndicator/pluginSpec.js
Normal 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());
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@ -51,7 +51,8 @@ define([
|
||||
'./conditionWidget/plugin',
|
||||
'./themes/espresso',
|
||||
'./themes/maelstrom',
|
||||
'./themes/snow'
|
||||
'./themes/snow',
|
||||
'./notificationIndicator/plugin'
|
||||
], function (
|
||||
_,
|
||||
UTCTimeSystem,
|
||||
@ -83,7 +84,8 @@ define([
|
||||
ConditionWidgetPlugin,
|
||||
Espresso,
|
||||
Maelstrom,
|
||||
Snow
|
||||
Snow,
|
||||
NotificationIndicator
|
||||
) {
|
||||
var bundleMap = {
|
||||
LocalStorage: 'platform/persistence/local',
|
||||
@ -192,6 +194,7 @@ define([
|
||||
plugins.Snow = Snow.default;
|
||||
plugins.Condition = ConditionPlugin.default;
|
||||
plugins.ConditionWidget = ConditionWidgetPlugin.default;
|
||||
plugins.NotificationIndicator = NotificationIndicator.default;
|
||||
|
||||
return plugins;
|
||||
});
|
||||
|
@ -23,6 +23,6 @@ import RemoveAction from "./RemoveAction";
|
||||
|
||||
export default function () {
|
||||
return function (openmct) {
|
||||
openmct.contextMenu.registerAction(new RemoveAction(openmct));
|
||||
openmct.menus.registerObjectAction(new RemoveAction(openmct));
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div class="c-inspect-properties">
|
||||
<template v-if="isEditing">
|
||||
<div class="c-inspect-properties__header">
|
||||
Table Column Size
|
||||
Table Layout
|
||||
</div>
|
||||
<ul class="c-inspect-properties__section">
|
||||
<li class="c-inspect-properties__row">
|
||||
@ -21,6 +21,22 @@
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
<li class="c-inspect-properties__row">
|
||||
<div
|
||||
class="c-inspect-properties__label"
|
||||
title="Show or hide headers"
|
||||
>
|
||||
<label for="header-visibility">Hide Header</label>
|
||||
</div>
|
||||
<div class="c-inspect-properties__value">
|
||||
<input
|
||||
id="header-visibility"
|
||||
type="checkbox"
|
||||
:checked="configuration.hideHeaders === true"
|
||||
@change="toggleHeaderVisibility"
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="c-inspect-properties__header">
|
||||
Table Column Visibility
|
||||
@ -120,6 +136,12 @@ export default {
|
||||
let column = new TelemetryTableColumn(this.openmct, metadatum);
|
||||
this.tableConfiguration.addSingleColumnForObject(telemetryObject, column);
|
||||
});
|
||||
},
|
||||
toggleHeaderVisibility() {
|
||||
let hideHeaders = this.configuration.hideHeaders;
|
||||
|
||||
this.configuration.hideHeaders = !hideHeaders;
|
||||
this.tableConfiguration.updateConfiguration(this.configuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ export default {
|
||||
let contextualObjectPath = this.objectPath.slice();
|
||||
contextualObjectPath.unshift(domainObject);
|
||||
|
||||
this.openmct.contextMenu._showContextMenuForObjectPath(contextualObjectPath, event.x, event.y, this.row.getContextMenuActions());
|
||||
this.openmct.menus._showObjectMenu(contextualObjectPath, event.x, event.y, this.row.getContextMenuActions());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -139,6 +139,7 @@
|
||||
></div>
|
||||
<!-- Headers table -->
|
||||
<div
|
||||
v-show="!hideHeaders"
|
||||
ref="headersTable"
|
||||
class="c-telemetry-table__headers-w js-table__headers-w"
|
||||
:style="{ 'max-width': widthWithScroll}"
|
||||
@ -336,7 +337,8 @@ export default {
|
||||
markCounter: 0,
|
||||
paused: false,
|
||||
markedRows: [],
|
||||
isShowingMarkedRowsOnly: false
|
||||
isShowingMarkedRowsOnly: false,
|
||||
hideHeaders: configuration.hideHeaders
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -615,6 +617,7 @@ export default {
|
||||
},
|
||||
updateConfiguration(configuration) {
|
||||
this.isAutosizeEnabled = configuration.autosize;
|
||||
this.hideHeaders = configuration.hideHeaders;
|
||||
|
||||
this.updateHeaders();
|
||||
this.$nextTick().then(this.calculateColumnWidths);
|
||||
|
@ -25,8 +25,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ConditionalStylesView from '../../plugins/condition/components/inspector/ConditionalStylesView.vue';
|
||||
import MultiSelectStylesView from '../../plugins/condition/components/inspector/MultiSelectStylesView.vue';
|
||||
import StylesView from '../../plugins/condition/components/inspector/StylesView.vue';
|
||||
import Vue from 'vue';
|
||||
|
||||
export default {
|
||||
@ -46,7 +45,6 @@ export default {
|
||||
methods: {
|
||||
updateSelection(selection) {
|
||||
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) {
|
||||
this.component.$destroy();
|
||||
this.component = undefined;
|
||||
@ -61,10 +59,9 @@ export default {
|
||||
},
|
||||
el: viewContainer,
|
||||
components: {
|
||||
ConditionalStylesView,
|
||||
MultiSelectStylesView
|
||||
StylesView
|
||||
},
|
||||
template: template
|
||||
template: '<styles-view/>'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ export default {
|
||||
});
|
||||
},
|
||||
showContextMenu(event) {
|
||||
this.openmct.contextMenu._showContextMenuForObjectPath(this.openmct.router.path, event.clientX, event.clientY);
|
||||
this.openmct.menus._showObjectMenu(this.openmct.router.path, event.clientX, event.clientY);
|
||||
},
|
||||
goToParent() {
|
||||
window.location.hash = this.parentUrl;
|
||||
|
@ -91,6 +91,7 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.openmct.notifications.on('notification', this.showNotification);
|
||||
this.openmct.notifications.on('dismiss-all', this.clearModel);
|
||||
},
|
||||
methods: {
|
||||
showNotification(notification) {
|
||||
|
@ -30,7 +30,7 @@ export default {
|
||||
showContextMenu(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.openmct.contextMenu._showContextMenuForObjectPath(this.objectPath, event.clientX, event.clientY);
|
||||
this.openmct.menus._showObjectMenu(this.objectPath, event.clientX, event.clientY);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -24,7 +24,7 @@ import ViewHistoricalDataAction from './ViewHistoricalDataAction';
|
||||
|
||||
export default function () {
|
||||
return function (openmct) {
|
||||
openmct.contextMenu.registerAction(new PreviewAction(openmct));
|
||||
openmct.contextMenu.registerAction(new ViewHistoricalDataAction(openmct));
|
||||
openmct.menus.registerObjectAction(new PreviewAction(openmct));
|
||||
openmct.menus.registerObjectAction(new ViewHistoricalDataAction(openmct));
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user