Compare commits
	
		
			36 Commits
		
	
	
		
			update-con
			...
			fix-state-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					77d0e6440a | ||
| 
						 | 
					d0d4579f13 | ||
| 
						 | 
					e29770f21b | ||
| 
						 | 
					02b537580c | ||
| 
						 | 
					7073b0717f | ||
| 
						 | 
					d6bb1b2a12 | ||
| 
						 | 
					c256696790 | ||
| 
						 | 
					d5480e7524 | ||
| 
						 | 
					ab463e93fe | ||
| 
						 | 
					8363c65312 | ||
| 
						 | 
					04598b6cf1 | ||
| 
						 | 
					43628ad9d6 | ||
| 
						 | 
					67bea86bc8 | ||
| 
						 | 
					4eb4cbfffc | ||
| 
						 | 
					eda01abcbc | ||
| 
						 | 
					2fa29124bf | ||
| 
						 | 
					694b8f4666 | ||
| 
						 | 
					33faeafa98 | ||
| 
						 | 
					a40ff07353 | ||
| 
						 | 
					41dc9c794d | ||
| 
						 | 
					f1faf3965d | ||
| 
						 | 
					da2ecbbcad | ||
| 
						 | 
					32c892fe98 | ||
| 
						 | 
					bbb271a678 | ||
| 
						 | 
					fec1438806 | ||
| 
						 | 
					faade64a60 | ||
| 
						 | 
					28f19ec310 | ||
| 
						 | 
					f934454c25 | ||
| 
						 | 
					eb49ffae02 | ||
| 
						 | 
					5751012872 | ||
| 
						 | 
					aa041e04cf | ||
| 
						 | 
					79d5d9c4d0 | ||
| 
						 | 
					b5bfdc4418 | ||
| 
						 | 
					59730c60ec | ||
| 
						 | 
					8f9a1e6fe6 | ||
| 
						 | 
					a3ea3b7d3d | 
							
								
								
									
										64
									
								
								.eslintrc.js
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								.eslintrc.js
									
									
									
									
									
								
							@@ -1,3 +1,4 @@
 | 
			
		||||
const LEGACY_FILES = ["platform/**", "example/**"];
 | 
			
		||||
module.exports = {
 | 
			
		||||
    "env": {
 | 
			
		||||
        "browser": true,
 | 
			
		||||
@@ -10,7 +11,8 @@ module.exports = {
 | 
			
		||||
    },
 | 
			
		||||
    "extends": [
 | 
			
		||||
        "eslint:recommended",
 | 
			
		||||
        "plugin:vue/recommended"
 | 
			
		||||
        "plugin:vue/recommended",
 | 
			
		||||
        "plugin:you-dont-need-lodash-underscore/compatible"
 | 
			
		||||
    ],
 | 
			
		||||
    "parser": "vue-eslint-parser",
 | 
			
		||||
    "parserOptions": {
 | 
			
		||||
@@ -22,6 +24,9 @@ module.exports = {
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "rules": {
 | 
			
		||||
        "you-dont-need-lodash-underscore/omit": "off",
 | 
			
		||||
        "you-dont-need-lodash-underscore/throttle": "off",
 | 
			
		||||
        "you-dont-need-lodash-underscore/flatten": "off",
 | 
			
		||||
        "no-bitwise": "error",
 | 
			
		||||
        "curly": "error",
 | 
			
		||||
        "eqeqeq": "error",
 | 
			
		||||
@@ -66,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,
 | 
			
		||||
@@ -112,6 +167,13 @@ module.exports = {
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
        }, {
 | 
			
		||||
            "files": LEGACY_FILES,
 | 
			
		||||
            "rules": {
 | 
			
		||||
                // https://eslint.org/docs/rules/no-nested-ternary
 | 
			
		||||
                "no-nested-ternary": "off",
 | 
			
		||||
                "no-var": "off"
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								API.md
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								API.md
									
									
									
									
									
								
							@@ -427,8 +427,8 @@ Each telemetry value description has an object defining hints.  Keys in this thi
 | 
			
		||||
 | 
			
		||||
Known hints:
 | 
			
		||||
 | 
			
		||||
* `domain`: Indicates that the value represents the "input" of a datum. Values with a `domain` hint will be used for the x-axis of a plot, and tables will render columns for these values first.
 | 
			
		||||
* `range`: Indicates that the value is the "output" of a datum.  Values with a `range` hint will be used as the y-axis on a plot, and tables will render columns for these values after the `domain` values.
 | 
			
		||||
* `domain`: Values with a `domain` hint will be used for the x-axis of a plot, and tables will render columns for these values first.
 | 
			
		||||
* `range`: Values with a `range` hint will be used as the y-axis on a plot, and tables will render columns for these values after the `domain` values.
 | 
			
		||||
* `image`: Indicates that the value may be interpreted as the URL to an image file, in which case appropriate views will be made available.
 | 
			
		||||
 | 
			
		||||
##### The Time Conductor and Telemetry 
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										162
									
								
								CONTRIBUTING.md
									
									
									
									
									
								
							
							
						
						
									
										162
									
								
								CONTRIBUTING.md
									
									
									
									
									
								
							@@ -119,6 +119,9 @@ Additionally:
 | 
			
		||||
* Every __author__ must include testing instructions. These instructions should identify the areas of code affected, and some minimal test steps. If addressing a bug, reproduction steps should be included, if they were not included in the original issue. If reproduction steps were included on the original issue, and are sufficient, refer to them.
 | 
			
		||||
* A pull request that closes an issue should say so in the description. Including the text “Closes #1234” will cause the linked issue to be automatically closed when the pull request is merged. This is the responsibility of the pull request’s __author__.
 | 
			
		||||
* When a pull request is merged, and the corresponding issue closed, the __reviewer__ must add the tag “unverified” to the original issue. This will indicate that although the issue is closed, it has not been tested yet.
 | 
			
		||||
* Every PR must have two reviewers assigned, though only one approval is necessary for merge.
 | 
			
		||||
* Changes to API require approval by a senior developer.
 | 
			
		||||
* When creating a PR, it is the author's responsibility to apply any priority label from the issue to the PR as well. This helps with prioritization.
 | 
			
		||||
 | 
			
		||||
## Standards
 | 
			
		||||
 | 
			
		||||
@@ -128,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.
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
@@ -298,6 +308,7 @@ checklist).
 | 
			
		||||
2. Unit tests included and/or updated with changes?
 | 
			
		||||
3. Command line build passes?
 | 
			
		||||
4. Changes have been smoke-tested?
 | 
			
		||||
5. Testing instructions included?
 | 
			
		||||
 | 
			
		||||
### Reviewer Checklist
 | 
			
		||||
 | 
			
		||||
@@ -305,3 +316,4 @@ checklist).
 | 
			
		||||
2. Appropriate unit tests included?
 | 
			
		||||
3. Code style and in-line documentation are appropriate?
 | 
			
		||||
4. Commit messages meet standards?
 | 
			
		||||
5. Has associated issue been labelled `unverified`? (only applicable if this PR closes the issue)
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,8 @@ define([
 | 
			
		||||
            values: [
 | 
			
		||||
                {
 | 
			
		||||
                    key: "name",
 | 
			
		||||
                    name: "Name"
 | 
			
		||||
                    name: "Name",
 | 
			
		||||
                    format: "string"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    key: "utc",
 | 
			
		||||
@@ -99,7 +100,7 @@ define([
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
 | 
			
		||||
        return _.extend(
 | 
			
		||||
        return Object.assign(
 | 
			
		||||
            {},
 | 
			
		||||
            domainObject.telemetry,
 | 
			
		||||
            METADATA_BY_TYPE[domainObject.type]
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
                                }
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
    "d3-time-format": "2.1.x",
 | 
			
		||||
    "eslint": "5.2.0",
 | 
			
		||||
    "eslint-plugin-vue": "^6.0.0",
 | 
			
		||||
    "eslint-plugin-you-dont-need-lodash-underscore": "^6.10.0",
 | 
			
		||||
    "eventemitter3": "^1.2.0",
 | 
			
		||||
    "exports-loader": "^0.7.0",
 | 
			
		||||
    "express": "^4.13.1",
 | 
			
		||||
@@ -48,7 +49,7 @@
 | 
			
		||||
    "karma-sourcemap-loader": "^0.3.7",
 | 
			
		||||
    "karma-webpack": "^3.0.0",
 | 
			
		||||
    "location-bar": "^3.0.1",
 | 
			
		||||
    "lodash": "^3.10.1",
 | 
			
		||||
    "lodash": "^4.17.12",
 | 
			
		||||
    "markdown-toc": "^0.11.7",
 | 
			
		||||
    "marked": "^0.3.5",
 | 
			
		||||
    "mini-css-extract-plugin": "^0.4.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,7 +21,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ['../../../../../src/api/objects/object-utils'],
 | 
			
		||||
    ['objectUtils'],
 | 
			
		||||
    function (objectUtils) {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -26,7 +26,7 @@
 | 
			
		||||
 * @namespace platform/containment
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ['../../../src/api/objects/object-utils'],
 | 
			
		||||
    ['objectUtils'],
 | 
			
		||||
    function (objectUtils) {
 | 
			
		||||
 | 
			
		||||
        function PersistableCompositionPolicy(openmct) {
 | 
			
		||||
 
 | 
			
		||||
@@ -81,7 +81,7 @@ define(
 | 
			
		||||
                baseContext = context || {};
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var actionContext = _.extend({}, baseContext);
 | 
			
		||||
            var actionContext = Object.assign({}, baseContext);
 | 
			
		||||
            actionContext.domainObject = this.domainObject;
 | 
			
		||||
 | 
			
		||||
            return this.actionService.getActions(actionContext);
 | 
			
		||||
 
 | 
			
		||||
@@ -121,7 +121,7 @@ define(['lodash'], function (_) {
 | 
			
		||||
     */
 | 
			
		||||
    ExportAsJSONAction.prototype.rewriteLink = function (child, parent) {
 | 
			
		||||
        this.externalIdentifiers.push(this.getId(child));
 | 
			
		||||
        var index = _.findIndex(parent.composition, function (id) {
 | 
			
		||||
        var index = parent.composition.findIndex(id => {
 | 
			
		||||
            return _.isEqual(child.identifier, id);
 | 
			
		||||
        });
 | 
			
		||||
        var copyOfChild = this.copyObject(child);
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
define(['zepto', '../../../../src/api/objects/object-utils.js'], function ($, objectUtils) {
 | 
			
		||||
define(['zepto', 'objectUtils'], function ($, objectUtils) {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The ImportAsJSONAction is available from context menus and allows a user
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@
 | 
			
		||||
 * Module defining GenericSearchProvider. Created by shale on 07/16/2015.
 | 
			
		||||
 */
 | 
			
		||||
define([
 | 
			
		||||
    '../../../../src/api/objects/object-utils',
 | 
			
		||||
    'objectUtils',
 | 
			
		||||
    'lodash'
 | 
			
		||||
], function (
 | 
			
		||||
    objectUtils,
 | 
			
		||||
@@ -191,7 +191,7 @@ define([
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var domainObject = objectUtils.toNewFormat(model, id);
 | 
			
		||||
        var composition = _.find(this.openmct.composition.registry, function (p) {
 | 
			
		||||
        var composition = this.openmct.composition.registry.find(p => {
 | 
			
		||||
            return p.appliesTo(domainObject);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    [
 | 
			
		||||
        '../../../src/api/objects/object-utils',
 | 
			
		||||
        'objectUtils',
 | 
			
		||||
        'lodash'
 | 
			
		||||
    ],
 | 
			
		||||
    function (
 | 
			
		||||
@@ -235,7 +235,7 @@ define(
 | 
			
		||||
            var defaultRange = metadata.valuesForHints(['range'])[0];
 | 
			
		||||
            defaultRange = defaultRange ? defaultRange.key : undefined;
 | 
			
		||||
 | 
			
		||||
            var sourceMap = _.indexBy(metadata.values(), 'key');
 | 
			
		||||
            var sourceMap = _.keyBy(metadata.values(), 'key');
 | 
			
		||||
 | 
			
		||||
            var isLegacyProvider = telemetryAPI.findRequestProvider(domainObject) ===
 | 
			
		||||
                telemetryAPI.legacyProvider;
 | 
			
		||||
@@ -300,7 +300,7 @@ define(
 | 
			
		||||
            var defaultRange = metadata.valuesForHints(['range'])[0];
 | 
			
		||||
            defaultRange = defaultRange ? defaultRange.key : undefined;
 | 
			
		||||
 | 
			
		||||
            var sourceMap = _.indexBy(metadata.values(), 'key');
 | 
			
		||||
            var sourceMap = _.keyBy(metadata.values(), 'key');
 | 
			
		||||
 | 
			
		||||
            var isLegacyProvider = telemetryAPI.findSubscriptionProvider(domainObject) ===
 | 
			
		||||
                telemetryAPI.legacyProvider;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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"
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								src/MCT.js
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								src/MCT.js
									
									
									
									
									
								
							@@ -28,7 +28,7 @@ define([
 | 
			
		||||
    './api/api',
 | 
			
		||||
    './api/overlays/OverlayAPI',
 | 
			
		||||
    './selection/Selection',
 | 
			
		||||
    './api/objects/object-utils',
 | 
			
		||||
    'objectUtils',
 | 
			
		||||
    './plugins/plugins',
 | 
			
		||||
    './adapter/indicators/legacy-indicators-plugin',
 | 
			
		||||
    './plugins/buildInfo/plugin',
 | 
			
		||||
@@ -249,7 +249,7 @@ define([
 | 
			
		||||
        this.legacyRegistry = new BundleRegistry();
 | 
			
		||||
        installDefaultBundles(this.legacyRegistry);
 | 
			
		||||
 | 
			
		||||
        // Plugin's that are installed by default
 | 
			
		||||
        // Plugins that are installed by default
 | 
			
		||||
 | 
			
		||||
        this.install(this.plugins.Plot());
 | 
			
		||||
        this.install(this.plugins.TelemetryTable());
 | 
			
		||||
@@ -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);
 | 
			
		||||
@@ -350,17 +351,13 @@ define([
 | 
			
		||||
     * @param {HTMLElement} [domElement] the DOM element in which to run
 | 
			
		||||
     *        MCT; if undefined, MCT will be run in the body of the document
 | 
			
		||||
     */
 | 
			
		||||
    MCT.prototype.start = function (domElement) {
 | 
			
		||||
    MCT.prototype.start = function (domElement = document.body, isHeadlessMode = false) {
 | 
			
		||||
        if (!this.plugins.DisplayLayout._installed) {
 | 
			
		||||
            this.install(this.plugins.DisplayLayout({
 | 
			
		||||
                showAsView: ['summary-widget']
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!domElement) {
 | 
			
		||||
            domElement = document.body;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.element = domElement;
 | 
			
		||||
 | 
			
		||||
        this.legacyExtension('runs', {
 | 
			
		||||
@@ -400,24 +397,31 @@ define([
 | 
			
		||||
                // something has depended upon objectService.  Cool, right?
 | 
			
		||||
                this.$injector.get('objectService');
 | 
			
		||||
 | 
			
		||||
                var appLayout = new Vue({
 | 
			
		||||
                    components: {
 | 
			
		||||
                        'Layout': Layout.default
 | 
			
		||||
                    },
 | 
			
		||||
                    provide: {
 | 
			
		||||
                        openmct: this
 | 
			
		||||
                    },
 | 
			
		||||
                    template: '<Layout ref="layout"></Layout>'
 | 
			
		||||
                });
 | 
			
		||||
                domElement.appendChild(appLayout.$mount().$el);
 | 
			
		||||
                if (!isHeadlessMode) {
 | 
			
		||||
                    var appLayout = new Vue({
 | 
			
		||||
                        components: {
 | 
			
		||||
                            'Layout': Layout.default
 | 
			
		||||
                        },
 | 
			
		||||
                        provide: {
 | 
			
		||||
                            openmct: this
 | 
			
		||||
                        },
 | 
			
		||||
                        template: '<Layout ref="layout"></Layout>'
 | 
			
		||||
                    });
 | 
			
		||||
                    domElement.appendChild(appLayout.$mount().$el);
 | 
			
		||||
 | 
			
		||||
                this.layout = appLayout.$refs.layout;
 | 
			
		||||
                Browse(this);
 | 
			
		||||
                    this.layout = appLayout.$refs.layout;
 | 
			
		||||
                    Browse(this);
 | 
			
		||||
                }
 | 
			
		||||
                this.router.start();
 | 
			
		||||
                this.emit('start');
 | 
			
		||||
            }.bind(this));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCT.prototype.startHeadless = function () {
 | 
			
		||||
        let unreachableNode = document.createElement('div');
 | 
			
		||||
        return this.start(unreachableNode, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Install a plugin in MCT.
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -21,11 +21,11 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './MCT',
 | 
			
		||||
    './plugins/plugins',
 | 
			
		||||
    'legacyRegistry'
 | 
			
		||||
], function (MCT, plugins, legacyRegistry) {
 | 
			
		||||
    xdescribe("MCT", function () {
 | 
			
		||||
    'legacyRegistry',
 | 
			
		||||
    'testUtils'
 | 
			
		||||
], function (plugins, legacyRegistry, testUtils) {
 | 
			
		||||
    describe("MCT", function () {
 | 
			
		||||
        var openmct;
 | 
			
		||||
        var mockPlugin;
 | 
			
		||||
        var mockPlugin2;
 | 
			
		||||
@@ -38,7 +38,7 @@ define([
 | 
			
		||||
            mockListener = jasmine.createSpy('listener');
 | 
			
		||||
            oldBundles = legacyRegistry.list();
 | 
			
		||||
 | 
			
		||||
            openmct = new MCT();
 | 
			
		||||
            openmct = testUtils.createOpenMct();
 | 
			
		||||
 | 
			
		||||
            openmct.install(mockPlugin);
 | 
			
		||||
            openmct.install(mockPlugin2);
 | 
			
		||||
@@ -63,8 +63,11 @@ define([
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe("start", function () {
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                openmct.start();
 | 
			
		||||
            let appHolder;
 | 
			
		||||
            beforeEach(function (done) {
 | 
			
		||||
                appHolder = document.createElement("div");
 | 
			
		||||
                openmct.on('start', done);
 | 
			
		||||
                openmct.start(appHolder);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("calls plugins for configuration", function () {
 | 
			
		||||
@@ -75,25 +78,51 @@ define([
 | 
			
		||||
            it("emits a start event", function () {
 | 
			
		||||
                expect(mockListener).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("Renders the application into the provided container element", function () {
 | 
			
		||||
                let openMctShellElements = appHolder.querySelectorAll('div.l-shell');
 | 
			
		||||
                expect(openMctShellElements.length).toBe(1);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe("startHeadless", function () {
 | 
			
		||||
            beforeEach(function (done) {
 | 
			
		||||
                openmct.on('start', done);
 | 
			
		||||
                openmct.startHeadless();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("calls plugins for configuration", function () {
 | 
			
		||||
                expect(mockPlugin).toHaveBeenCalledWith(openmct);
 | 
			
		||||
                expect(mockPlugin2).toHaveBeenCalledWith(openmct);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("emits a start event", function () {
 | 
			
		||||
                expect(mockListener).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("Does not render Open MCT", function () {
 | 
			
		||||
                let openMctShellElements = document.body.querySelectorAll('div.l-shell');
 | 
			
		||||
                expect(openMctShellElements.length).toBe(0);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe("setAssetPath", function () {
 | 
			
		||||
            var testAssetPath;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                testAssetPath = "some/path";
 | 
			
		||||
                openmct.legacyExtension = jasmine.createSpy('legacyExtension');
 | 
			
		||||
                openmct.setAssetPath(testAssetPath);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("internally configures the path for assets", function () {
 | 
			
		||||
                expect(openmct.legacyExtension).toHaveBeenCalledWith(
 | 
			
		||||
                    'constants',
 | 
			
		||||
                    {
 | 
			
		||||
                        key: "ASSETS_PATH",
 | 
			
		||||
                        value: testAssetPath
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
            it("configures the path for assets", function () {
 | 
			
		||||
                testAssetPath = "some/path/";
 | 
			
		||||
                openmct.setAssetPath(testAssetPath);
 | 
			
		||||
                expect(openmct.getAssetPath()).toBe(testAssetPath);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("adds a trailing /", function () {
 | 
			
		||||
                testAssetPath = "some/path";
 | 
			
		||||
                openmct.setAssetPath(testAssetPath);
 | 
			
		||||
                expect(openmct.getAssetPath()).toBe(testAssetPath + "/");
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    '../../api/objects/object-utils'
 | 
			
		||||
    'objectUtils'
 | 
			
		||||
], function (objectUtils) {
 | 
			
		||||
    function ActionDialogDecorator(mct, actionService) {
 | 
			
		||||
        this.mct = mct;
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(['../../api/objects/object-utils'], function (objectUtils) {
 | 
			
		||||
define(['objectUtils'], function (objectUtils) {
 | 
			
		||||
    function AdapterCapability(domainObject) {
 | 
			
		||||
        this.domainObject = domainObject;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
 * Module defining AlternateCompositionCapability. Created by vwoeltje on 11/7/14.
 | 
			
		||||
 */
 | 
			
		||||
define([
 | 
			
		||||
    '../../api/objects/object-utils',
 | 
			
		||||
    'objectUtils',
 | 
			
		||||
    '../../../platform/core/src/capabilities/ContextualDomainObject'
 | 
			
		||||
], function (objectUtils, ContextualDomainObject) {
 | 
			
		||||
    function AlternateCompositionCapability($injector, domainObject) {
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@ define([
 | 
			
		||||
            var capability = viewConstructor(domainObject);
 | 
			
		||||
            var oldInvoke = capability.invoke.bind(capability);
 | 
			
		||||
 | 
			
		||||
            /* eslint-disable you-dont-need-lodash-underscore/map */
 | 
			
		||||
            capability.invoke = function () {
 | 
			
		||||
                var availableViews = oldInvoke();
 | 
			
		||||
                var newDomainObject = capability
 | 
			
		||||
@@ -52,6 +53,8 @@ define([
 | 
			
		||||
                    .map('view')
 | 
			
		||||
                    .value();
 | 
			
		||||
            };
 | 
			
		||||
            /* eslint-enable you-dont-need-lodash-underscore/map */
 | 
			
		||||
 | 
			
		||||
            return capability;
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    '../capabilities/AlternateCompositionCapability',
 | 
			
		||||
    '../../api/objects/object-utils'
 | 
			
		||||
    'objectUtils'
 | 
			
		||||
], function (
 | 
			
		||||
    AlternateCompositionCapability,
 | 
			
		||||
    objectUtils
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    '../../api/objects/object-utils'
 | 
			
		||||
    'objectUtils'
 | 
			
		||||
], function (
 | 
			
		||||
    utils
 | 
			
		||||
) {
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@ define([
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    TimeSettingsURLHandler.prototype.parseQueryParams = function () {
 | 
			
		||||
        var searchParams = _.pick(this.$location.search(), _.values(SEARCH));
 | 
			
		||||
        var searchParams = _.pick(this.$location.search(), Object.values(SEARCH));
 | 
			
		||||
        var parsedParams = {
 | 
			
		||||
            clock: searchParams[SEARCH.MODE],
 | 
			
		||||
            timeSystem: searchParams[SEARCH.TIME_SYSTEM]
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    '../../api/objects/object-utils'
 | 
			
		||||
    'objectUtils'
 | 
			
		||||
], function (
 | 
			
		||||
    utils
 | 
			
		||||
) {
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    '../../api/objects/object-utils'
 | 
			
		||||
    'objectUtils'
 | 
			
		||||
], function (
 | 
			
		||||
    objectUtils
 | 
			
		||||
) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
define([
 | 
			
		||||
    './LegacyViewProvider',
 | 
			
		||||
    './TypeInspectorViewProvider',
 | 
			
		||||
    '../../api/objects/object-utils'
 | 
			
		||||
    'objectUtils'
 | 
			
		||||
], function (
 | 
			
		||||
    LegacyViewProvider,
 | 
			
		||||
    TypeInspectorViewProvider,
 | 
			
		||||
 
 | 
			
		||||
@@ -70,7 +70,7 @@ define([
 | 
			
		||||
     * @memberof module:openmct.CompositionAPI#
 | 
			
		||||
     */
 | 
			
		||||
    CompositionAPI.prototype.get = function (domainObject) {
 | 
			
		||||
        var provider = _.find(this.registry, function (p) {
 | 
			
		||||
        var provider = this.registry.find(p => {
 | 
			
		||||
            return p.appliesTo(domainObject);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -122,7 +122,7 @@ define([
 | 
			
		||||
            throw new Error('Event not supported by composition: ' + event);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var index = _.findIndex(this.listeners[event], function (l) {
 | 
			
		||||
        var index = this.listeners[event].findIndex(l => {
 | 
			
		||||
            return l.callback === callback && l.context === context;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    'lodash',
 | 
			
		||||
    '../objects/object-utils'
 | 
			
		||||
    'objectUtils'
 | 
			
		||||
], function (
 | 
			
		||||
    _,
 | 
			
		||||
    objectUtils
 | 
			
		||||
@@ -143,7 +143,7 @@ define([
 | 
			
		||||
        var keyString = objectUtils.makeKeyString(domainObject.identifier);
 | 
			
		||||
        var objectListeners = this.listeningTo[keyString];
 | 
			
		||||
 | 
			
		||||
        var index = _.findIndex(objectListeners[event], function (l) {
 | 
			
		||||
        var index = objectListeners[event].findIndex(l => {
 | 
			
		||||
            return l.callback === callback && l.context === context;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@@ -196,8 +196,8 @@ define([
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    DefaultCompositionProvider.prototype.includes = function (parent, childId) {
 | 
			
		||||
        return parent.composition.findIndex(composee =>
 | 
			
		||||
            this.publicAPI.objects.areIdsEqual(composee, childId)) !== -1;
 | 
			
		||||
        return parent.composition.some(composee =>
 | 
			
		||||
            this.publicAPI.objects.areIdsEqual(composee, childId));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    DefaultCompositionProvider.prototype.reorder = function (domainObject, oldIndex, newIndex) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './object-utils.js',
 | 
			
		||||
    'objectUtils',
 | 
			
		||||
    'lodash'
 | 
			
		||||
], function (
 | 
			
		||||
    utils,
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    'lodash',
 | 
			
		||||
    './object-utils',
 | 
			
		||||
    'objectUtils',
 | 
			
		||||
    './MutableObject',
 | 
			
		||||
    './RootRegistry',
 | 
			
		||||
    './RootObjectProvider',
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ define([
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    RootRegistry.prototype.addRoot = function (key) {
 | 
			
		||||
        if (isKey(key) || (_.isArray(key) && _.every(key, isKey))) {
 | 
			
		||||
        if (isKey(key) || (Array.isArray(key) && key.every(isKey))) {
 | 
			
		||||
            this.providers.push(function () {
 | 
			
		||||
                return key;
 | 
			
		||||
            });
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
define([
 | 
			
		||||
    '../object-utils'
 | 
			
		||||
    'objectUtils'
 | 
			
		||||
], function (
 | 
			
		||||
    objectUtils
 | 
			
		||||
) {
 | 
			
		||||
 
 | 
			
		||||
@@ -85,9 +85,9 @@ define([
 | 
			
		||||
                            value: +e.value
 | 
			
		||||
                        };
 | 
			
		||||
                    }), 'e.value');
 | 
			
		||||
                valueMetadata.values = _.pluck(valueMetadata.enumerations, 'value');
 | 
			
		||||
                valueMetadata.max = _.max(valueMetadata.values);
 | 
			
		||||
                valueMetadata.min = _.min(valueMetadata.values);
 | 
			
		||||
                valueMetadata.values = valueMetadata.enumerations.map(e => e.value);
 | 
			
		||||
                valueMetadata.max = Math.max(valueMetadata.values);
 | 
			
		||||
                valueMetadata.min = Math.min(valueMetadata.values);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            valueMetadatas.push(valueMetadata);
 | 
			
		||||
@@ -103,7 +103,7 @@ define([
 | 
			
		||||
        var metadata = domainObject.telemetry || {};
 | 
			
		||||
        if (this.typeHasTelemetry(domainObject)) {
 | 
			
		||||
            var typeMetadata = this.typeService.getType(domainObject.type).typeDef.telemetry;
 | 
			
		||||
            _.extend(metadata, typeMetadata);
 | 
			
		||||
            Object.assign(metadata, typeMetadata);
 | 
			
		||||
            if (!metadata.values) {
 | 
			
		||||
                metadata.values = valueMetadatasFromOldFormat(metadata);
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@ define([
 | 
			
		||||
    './TelemetryMetadataManager',
 | 
			
		||||
    './TelemetryValueFormatter',
 | 
			
		||||
    './DefaultMetadataProvider',
 | 
			
		||||
    '../objects/object-utils',
 | 
			
		||||
    'objectUtils',
 | 
			
		||||
    'lodash'
 | 
			
		||||
], function (
 | 
			
		||||
    TelemetryMetadataManager,
 | 
			
		||||
@@ -370,7 +370,7 @@ define([
 | 
			
		||||
    TelemetryAPI.prototype.commonValuesForHints = function (metadatas, hints) {
 | 
			
		||||
        var options = metadatas.map(function (metadata) {
 | 
			
		||||
            var values = metadata.valuesForHints(hints);
 | 
			
		||||
            return _.indexBy(values, 'key');
 | 
			
		||||
            return _.keyBy(values, 'key');
 | 
			
		||||
        }).reduce(function (a, b) {
 | 
			
		||||
            var results = {};
 | 
			
		||||
            Object.keys(a).forEach(function (key) {
 | 
			
		||||
@@ -383,7 +383,7 @@ define([
 | 
			
		||||
        var sortKeys = hints.map(function (h) {
 | 
			
		||||
            return 'hints.' + h;
 | 
			
		||||
        });
 | 
			
		||||
        return _.sortByAll(options, sortKeys);
 | 
			
		||||
        return _.sortBy(options, sortKeys);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -57,13 +57,13 @@ define([
 | 
			
		||||
 | 
			
		||||
        if (valueMetadata.format === 'enum') {
 | 
			
		||||
            if (!valueMetadata.values) {
 | 
			
		||||
                valueMetadata.values = _.pluck(valueMetadata.enumerations, 'value');
 | 
			
		||||
                valueMetadata.values = valueMetadata.enumerations.map(e => e.value);
 | 
			
		||||
            }
 | 
			
		||||
            if (!valueMetadata.hasOwnProperty('max')) {
 | 
			
		||||
                valueMetadata.max = _.max(valueMetadata.values) + 1;
 | 
			
		||||
                valueMetadata.max = Math.max(valueMetadata.values) + 1;
 | 
			
		||||
            }
 | 
			
		||||
            if (!valueMetadata.hasOwnProperty('min')) {
 | 
			
		||||
                valueMetadata.min = _.min(valueMetadata.values) - 1;
 | 
			
		||||
                valueMetadata.min = Math.min(valueMetadata.values) - 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -121,7 +121,7 @@ define([
 | 
			
		||||
                return metadata.hints[hint];
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        return _.sortByAll(matchingMetadata, ...iteratees);
 | 
			
		||||
        return _.sortBy(matchingMetadata, ...iteratees);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    TelemetryMetadataManager.prototype.getFilterableValues = function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -75,7 +75,7 @@ export default {
 | 
			
		||||
            this.items.push(item);
 | 
			
		||||
        },
 | 
			
		||||
        removeItem(identifier) {
 | 
			
		||||
            let index = _.findIndex(this.items, (item) => this.openmct.objects.makeKeyString(identifier) === item.key);
 | 
			
		||||
            let index = this.items.findIndex(item => this.openmct.objects.makeKeyString(identifier) === item.key);
 | 
			
		||||
 | 
			
		||||
            this.items.splice(index, 1);
 | 
			
		||||
        },
 | 
			
		||||
 
 | 
			
		||||
@@ -102,7 +102,7 @@ export default {
 | 
			
		||||
            this.compositions.push({composition, addCallback, removeCallback});
 | 
			
		||||
        },
 | 
			
		||||
        removePrimary(identifier) {
 | 
			
		||||
            let index = _.findIndex(this.primaryTelemetryObjects, (primary) => this.openmct.objects.makeKeyString(identifier) === primary.key),
 | 
			
		||||
            let index = this.primaryTelemetryObjects.findIndex(primary => this.openmct.objects.makeKeyString(identifier) === primary.key),
 | 
			
		||||
                primary = this.primaryTelemetryObjects[index];
 | 
			
		||||
 | 
			
		||||
            this.$set(this.secondaryTelemetryObjects, primary.key, undefined);
 | 
			
		||||
@@ -130,7 +130,7 @@ export default {
 | 
			
		||||
        removeSecondary(primary) {
 | 
			
		||||
            return (identifier) => {
 | 
			
		||||
                let array = this.secondaryTelemetryObjects[primary.key],
 | 
			
		||||
                    index = _.findIndex(array, (secondary) => this.openmct.objects.makeKeyString(identifier) === secondary.key);
 | 
			
		||||
                    index = array.findIndex(secondary => this.openmct.objects.makeKeyString(identifier) === secondary.key);
 | 
			
		||||
 | 
			
		||||
                array.splice(index, 1);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -70,15 +70,18 @@ export default class ConditionClass extends EventEmitter {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.criteria.forEach(criterion => {
 | 
			
		||||
            if (this.isAnyOrAllTelemetry(criterion)) {
 | 
			
		||||
                criterion.getResult(datum, this.conditionManager.telemetryObjects);
 | 
			
		||||
            } else {
 | 
			
		||||
                criterion.getResult(datum);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        if (this.isTelemetryUsed(datum.id)) {
 | 
			
		||||
 | 
			
		||||
        this.result = evaluateResults(this.criteria.map(criterion => criterion.result), this.trigger);
 | 
			
		||||
            this.criteria.forEach(criterion => {
 | 
			
		||||
                if (this.isAnyOrAllTelemetry(criterion)) {
 | 
			
		||||
                    criterion.getResult(datum, this.conditionManager.telemetryObjects);
 | 
			
		||||
                } else {
 | 
			
		||||
                    criterion.getResult(datum);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this.result = evaluateResults(this.criteria.map(criterion => criterion.result), this.trigger);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    isAnyOrAllTelemetry(criterion) {
 | 
			
		||||
 
 | 
			
		||||
@@ -47,17 +47,24 @@ describe("The condition", function () {
 | 
			
		||||
            name: "Test Object",
 | 
			
		||||
            telemetry: {
 | 
			
		||||
                values: [{
 | 
			
		||||
                    key: "some-key",
 | 
			
		||||
                    name: "Some attribute",
 | 
			
		||||
                    key: "value",
 | 
			
		||||
                    name: "Value",
 | 
			
		||||
                    hints: {
 | 
			
		||||
                        range: 2
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    key: "utc",
 | 
			
		||||
                    name: "Time",
 | 
			
		||||
                    format: "utc",
 | 
			
		||||
                    hints: {
 | 
			
		||||
                        domain: 1
 | 
			
		||||
                    }
 | 
			
		||||
                }, {
 | 
			
		||||
                    key: "some-other-key",
 | 
			
		||||
                    name: "Another attribute",
 | 
			
		||||
                    hints: {
 | 
			
		||||
                        range: 1
 | 
			
		||||
                    }
 | 
			
		||||
                    key: "testSource",
 | 
			
		||||
                    source: "value",
 | 
			
		||||
                    name: "Test",
 | 
			
		||||
                    format: "string"
 | 
			
		||||
                }]
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
@@ -136,4 +143,38 @@ describe("The condition", function () {
 | 
			
		||||
        expect(result).toBeTrue();
 | 
			
		||||
        expect(conditionObj.criteria.length).toEqual(0);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it("gets the result of a condition when new telemetry data is received", function () {
 | 
			
		||||
        conditionObj.getResult({
 | 
			
		||||
            value: '0',
 | 
			
		||||
            utc: 'Hi',
 | 
			
		||||
            id: testTelemetryObject.identifier.key
 | 
			
		||||
        });
 | 
			
		||||
        expect(conditionObj.result).toBeTrue();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it("gets the result of a condition when new telemetry data is received", function () {
 | 
			
		||||
        conditionObj.getResult({
 | 
			
		||||
            value: '1',
 | 
			
		||||
            utc: 'Hi',
 | 
			
		||||
            id: testTelemetryObject.identifier.key
 | 
			
		||||
        });
 | 
			
		||||
        expect(conditionObj.result).toBeFalse();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it("keeps the old result new telemetry data is not used by it", function () {
 | 
			
		||||
        conditionObj.getResult({
 | 
			
		||||
            value: '0',
 | 
			
		||||
            utc: 'Hi',
 | 
			
		||||
            id: testTelemetryObject.identifier.key
 | 
			
		||||
        });
 | 
			
		||||
        expect(conditionObj.result).toBeTrue();
 | 
			
		||||
 | 
			
		||||
        conditionObj.getResult({
 | 
			
		||||
            value: '1',
 | 
			
		||||
            utc: 'Hi',
 | 
			
		||||
            id: '1234'
 | 
			
		||||
        });
 | 
			
		||||
        expect(conditionObj.result).toBeTrue();
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -200,7 +200,7 @@ export default {
 | 
			
		||||
            this.$emit('telemetryUpdated', this.telemetryObjs);
 | 
			
		||||
        },
 | 
			
		||||
        removeTelemetryObject(identifier) {
 | 
			
		||||
            let index = _.findIndex(this.telemetryObjs, (obj) => {
 | 
			
		||||
            let index = this.telemetryObjs.findIndex(obj => {
 | 
			
		||||
                let objId = this.openmct.objects.makeKeyString(obj.identifier);
 | 
			
		||||
                let id = this.openmct.objects.makeKeyString(identifier);
 | 
			
		||||
                return objId === id;
 | 
			
		||||
 
 | 
			
		||||
@@ -108,6 +108,7 @@ import ConditionError from "@/plugins/condition/components/ConditionError.vue";
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import PreviewAction from "@/ui/preview/PreviewAction.js";
 | 
			
		||||
import {getApplicableStylesForItem} from "@/plugins/condition/utils/styleUtils";
 | 
			
		||||
import isEmpty from 'lodash/isEmpty';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: 'ConditionalStylesView',
 | 
			
		||||
@@ -288,7 +289,7 @@ export default {
 | 
			
		||||
                delete domainObjectStyles[this.itemId].conditionSetIdentifier;
 | 
			
		||||
                domainObjectStyles[this.itemId].styles = undefined;
 | 
			
		||||
                delete domainObjectStyles[this.itemId].styles;
 | 
			
		||||
                if (_.isEmpty(domainObjectStyles[this.itemId])) {
 | 
			
		||||
                if (isEmpty(domainObjectStyles[this.itemId])) {
 | 
			
		||||
                    delete domainObjectStyles[this.itemId];
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -299,7 +300,7 @@ export default {
 | 
			
		||||
                domainObjectStyles.styles = undefined;
 | 
			
		||||
                delete domainObjectStyles.styles;
 | 
			
		||||
            }
 | 
			
		||||
            if (_.isEmpty(domainObjectStyles)) {
 | 
			
		||||
            if (isEmpty(domainObjectStyles)) {
 | 
			
		||||
                domainObjectStyles = undefined;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -337,7 +338,7 @@ export default {
 | 
			
		||||
                    delete domainObjectStyles[this.itemId];
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            if (_.isEmpty(domainObjectStyles)) {
 | 
			
		||||
            if (isEmpty(domainObjectStyles)) {
 | 
			
		||||
                domainObjectStyles = undefined;
 | 
			
		||||
            }
 | 
			
		||||
            this.persist(domainObjectStyles);
 | 
			
		||||
 
 | 
			
		||||
@@ -50,6 +50,7 @@
 | 
			
		||||
import StyleEditor from "./StyleEditor.vue";
 | 
			
		||||
import PreviewAction from "@/ui/preview/PreviewAction.js";
 | 
			
		||||
import { getApplicableStylesForItem, getConsolidatedStyleValues, getConditionalStyleForItem } from "@/plugins/condition/utils/styleUtils";
 | 
			
		||||
import isEmpty from 'lodash/isEmpty';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: 'MultiSelectStylesView',
 | 
			
		||||
@@ -178,7 +179,7 @@ export default {
 | 
			
		||||
                domainObjectStyles[itemId] = undefined;
 | 
			
		||||
                delete domainObjectStyles[this.itemId];
 | 
			
		||||
 | 
			
		||||
                if (_.isEmpty(domainObjectStyles)) {
 | 
			
		||||
                if (isEmpty(domainObjectStyles)) {
 | 
			
		||||
                    domainObjectStyles = undefined;
 | 
			
		||||
                }
 | 
			
		||||
                this.persist(this.domainObject, domainObjectStyles);
 | 
			
		||||
@@ -239,7 +240,7 @@ export default {
 | 
			
		||||
                    if (this.isStaticAndConditionalStyles) {
 | 
			
		||||
                        this.removeConditionalStyles(domainObjectStyles, item.id);
 | 
			
		||||
                    }
 | 
			
		||||
                    if (_.isEmpty(itemStaticStyle)) {
 | 
			
		||||
                    if (isEmpty(itemStaticStyle)) {
 | 
			
		||||
                        itemStaticStyle = undefined;
 | 
			
		||||
                        domainObjectStyles[item.id] = undefined;
 | 
			
		||||
                    } else {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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 (Object.keys(objectStyles).length <= 0) {
 | 
			
		||||
                        objectStyles = undefined;
 | 
			
		||||
                    }
 | 
			
		||||
                    this.persist(domainObject, objectStyles);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            if (this.items.length) {
 | 
			
		||||
                this.items.forEach((item) => {
 | 
			
		||||
                    const itemId = item.id;
 | 
			
		||||
                    this.removeConditionalStyles(domainObjectStyles, itemId);
 | 
			
		||||
                    if (Object.keys(domainObjectStyles[itemId]).length <= 0) {
 | 
			
		||||
                        delete domainObjectStyles[itemId];
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }  else {
 | 
			
		||||
                this.removeConditionalStyles(domainObjectStyles);
 | 
			
		||||
            }
 | 
			
		||||
            if (Object.keys(domainObjectStyles).length <= 0) {
 | 
			
		||||
                domainObjectStyles = undefined;
 | 
			
		||||
            }
 | 
			
		||||
            this.persist(this.domainObject, domainObjectStyles);
 | 
			
		||||
 | 
			
		||||
            if (this.stopProvidingTelemetry) {
 | 
			
		||||
                this.stopProvidingTelemetry();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        removeConditionalStyles(domainObjectStyles, itemId) {
 | 
			
		||||
            if (itemId && domainObjectStyles[itemId]) {
 | 
			
		||||
                domainObjectStyles[itemId].conditionSetIdentifier = undefined;
 | 
			
		||||
                delete domainObjectStyles[itemId].conditionSetIdentifier;
 | 
			
		||||
                domainObjectStyles[itemId].selectedConditionId = undefined;
 | 
			
		||||
                domainObjectStyles[itemId].defaultConditionId = undefined;
 | 
			
		||||
                domainObjectStyles[itemId].styles = undefined;
 | 
			
		||||
                delete domainObjectStyles[itemId].styles;
 | 
			
		||||
            } else {
 | 
			
		||||
                domainObjectStyles.conditionSetIdentifier = undefined;
 | 
			
		||||
                delete domainObjectStyles.conditionSetIdentifier;
 | 
			
		||||
                domainObjectStyles.selectedConditionId = undefined;
 | 
			
		||||
                domainObjectStyles.defaultConditionId = undefined;
 | 
			
		||||
                domainObjectStyles.styles = undefined;
 | 
			
		||||
                delete domainObjectStyles.styles;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        updateStaticStyle(staticStyle, property) {
 | 
			
		||||
            //update the static style for each of the layoutItems as well as each sub object item
 | 
			
		||||
            this.staticStyle = staticStyle;
 | 
			
		||||
            this.removeConditionSet();
 | 
			
		||||
            this.getAndPersistStyles(property);
 | 
			
		||||
        },
 | 
			
		||||
        updateConditionalStyle(conditionStyle, property) {
 | 
			
		||||
            let foundStyle = this.findStyleByConditionId(conditionStyle.conditionId);
 | 
			
		||||
            if (foundStyle) {
 | 
			
		||||
                foundStyle.style = conditionStyle.style;
 | 
			
		||||
                this.selectedConditionId = foundStyle.conditionId;
 | 
			
		||||
                this.getAndPersistStyles(property);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        getAndPersistStyles(property, defaultConditionId) {
 | 
			
		||||
            this.persist(this.domainObject, this.getDomainObjectStyle(this.domainObject, property, this.items, defaultConditionId));
 | 
			
		||||
            if (this.domainObjectsById) {
 | 
			
		||||
                const domainObjects = Object.values(this.domainObjectsById);
 | 
			
		||||
                domainObjects.forEach(domainObject => {
 | 
			
		||||
                    this.persist(domainObject, this.getDomainObjectStyle(domainObject, property, null, defaultConditionId));
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            if (!this.items.length && !this.domainObjectsById) {
 | 
			
		||||
                this.persist(this.domainObject, this.getDomainObjectStyle(this.domainObject, property, null, defaultConditionId));
 | 
			
		||||
            }
 | 
			
		||||
            this.isStaticAndConditionalStyles = false;
 | 
			
		||||
            if (property) {
 | 
			
		||||
                let foundIndex = this.mixedStyles.indexOf(property);
 | 
			
		||||
                if (foundIndex > -1) {
 | 
			
		||||
                    this.mixedStyles.splice(foundIndex, 1);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        getDomainObjectStyle(domainObject, property, items, defaultConditionId) {
 | 
			
		||||
            let objectStyle = {
 | 
			
		||||
                styles: this.conditionalStyles,
 | 
			
		||||
                staticStyle: this.staticStyle,
 | 
			
		||||
                selectedConditionId: this.selectedConditionId
 | 
			
		||||
            };
 | 
			
		||||
            if (defaultConditionId) {
 | 
			
		||||
                objectStyle.defaultConditionId = defaultConditionId;
 | 
			
		||||
            }
 | 
			
		||||
            if (this.conditionSetDomainObject) {
 | 
			
		||||
                objectStyle.conditionSetIdentifier = this.conditionSetDomainObject.identifier;
 | 
			
		||||
            }
 | 
			
		||||
            let domainObjectStyles =  (domainObject.configuration && domainObject.configuration.objectStyles) || {};
 | 
			
		||||
 | 
			
		||||
            if (items) {
 | 
			
		||||
                items.forEach(item => {
 | 
			
		||||
                    let itemStaticStyle = {};
 | 
			
		||||
                    let itemConditionalStyle = { styles: []};
 | 
			
		||||
                    if (!this.conditionSetDomainObject) {
 | 
			
		||||
                        if (domainObjectStyles[item.id] && domainObjectStyles[item.id].staticStyle) {
 | 
			
		||||
                            itemStaticStyle = domainObjectStyles[item.id].staticStyle.style;
 | 
			
		||||
                        }
 | 
			
		||||
                        if (item.applicableStyles[property]) {
 | 
			
		||||
                            itemStaticStyle[property] = this.staticStyle.style[property];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (Object.keys(itemStaticStyle).length <= 0) {
 | 
			
		||||
                            itemStaticStyle = undefined;
 | 
			
		||||
                        }
 | 
			
		||||
                        domainObjectStyles[item.id] = { staticStyle: { style: itemStaticStyle } };
 | 
			
		||||
                    } else {
 | 
			
		||||
                        objectStyle.styles.forEach((conditionalStyle, index) => {
 | 
			
		||||
                            let style = {};
 | 
			
		||||
                            Object.keys(item.applicableStyles).concat(['isStyleInvisible']).forEach(key => {
 | 
			
		||||
                                style[key] = conditionalStyle.style[key];
 | 
			
		||||
                            });
 | 
			
		||||
                            itemConditionalStyle.styles.push({
 | 
			
		||||
                                ...conditionalStyle,
 | 
			
		||||
                                style
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        domainObjectStyles[item.id] = {
 | 
			
		||||
                            ...domainObjectStyles[item.id],
 | 
			
		||||
                            ...objectStyle,
 | 
			
		||||
                            ...itemConditionalStyle
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            } else {
 | 
			
		||||
                domainObjectStyles = {
 | 
			
		||||
                    ...domainObjectStyles,
 | 
			
		||||
                    ...objectStyle
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return domainObjectStyles;
 | 
			
		||||
        },
 | 
			
		||||
        applySelectedConditionStyle(conditionId) {
 | 
			
		||||
            this.selectedConditionId = conditionId;
 | 
			
		||||
            this.getAndPersistStyles();
 | 
			
		||||
        },
 | 
			
		||||
        persist(domainObject, style) {
 | 
			
		||||
            this.openmct.objects.mutate(domainObject, 'configuration.objectStyles', style);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
@@ -20,25 +20,21 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
import { createOpenMct } from "testTools";
 | 
			
		||||
import { createOpenMct } from "testUtils";
 | 
			
		||||
import ConditionPlugin from "./plugin";
 | 
			
		||||
 | 
			
		||||
let openmct = createOpenMct();
 | 
			
		||||
openmct.install(new ConditionPlugin());
 | 
			
		||||
 | 
			
		||||
let conditionSetDefinition;
 | 
			
		||||
let mockConditionSetDomainObject;
 | 
			
		||||
let element;
 | 
			
		||||
let child;
 | 
			
		||||
 | 
			
		||||
describe('the plugin', function () {
 | 
			
		||||
    let conditionSetDefinition;
 | 
			
		||||
    let mockConditionSetDomainObject;
 | 
			
		||||
    let element;
 | 
			
		||||
    let child;
 | 
			
		||||
    let openmct;
 | 
			
		||||
 | 
			
		||||
    beforeAll((done) => {
 | 
			
		||||
        openmct = createOpenMct();
 | 
			
		||||
        openmct.install(new ConditionPlugin());
 | 
			
		||||
 | 
			
		||||
        conditionSetDefinition = openmct.types.get('conditionSet').definition;
 | 
			
		||||
        const appHolder = document.createElement('div');
 | 
			
		||||
        appHolder.style.width = '640px';
 | 
			
		||||
        appHolder.style.height = '480px';
 | 
			
		||||
 | 
			
		||||
        element = document.createElement('div');
 | 
			
		||||
        child = document.createElement('div');
 | 
			
		||||
@@ -55,7 +51,7 @@ describe('the plugin', function () {
 | 
			
		||||
        conditionSetDefinition.initialize(mockConditionSetDomainObject);
 | 
			
		||||
 | 
			
		||||
        openmct.on('start', done);
 | 
			
		||||
        openmct.start(appHolder);
 | 
			
		||||
        openmct.startHeadless();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    let mockConditionSetObject = {
 | 
			
		||||
 
 | 
			
		||||
@@ -20,8 +20,6 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
const convertToNumbers = (input) => {
 | 
			
		||||
    let numberInputs = [];
 | 
			
		||||
    input.forEach(inputValue => numberInputs.push(Number(inputValue)));
 | 
			
		||||
@@ -257,7 +255,7 @@ export const OPERATIONS = [
 | 
			
		||||
            const lhsValue = input[0] !== undefined ? input[0].toString() : '';
 | 
			
		||||
            if (input[1]) {
 | 
			
		||||
                const values = input[1].split(',');
 | 
			
		||||
                return values.find((value) => lhsValue === _.trim(value.toString()));
 | 
			
		||||
                return values.find((value) => lhsValue === value.toString().trim());
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        },
 | 
			
		||||
@@ -274,7 +272,7 @@ export const OPERATIONS = [
 | 
			
		||||
            const lhsValue = input[0] !== undefined ? input[0].toString() : '';
 | 
			
		||||
            if (input[1]) {
 | 
			
		||||
                const values = input[1].split(',');
 | 
			
		||||
                const found = values.find((value) => lhsValue === _.trim(value.toString()));
 | 
			
		||||
                const found = values.find((value) => lhsValue === value.toString().trim());
 | 
			
		||||
                return !found;
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,8 @@
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
import isEmpty from 'lodash/isEmpty';
 | 
			
		||||
 | 
			
		||||
const NONE_VALUE = '__no_value';
 | 
			
		||||
 | 
			
		||||
const styleProps = {
 | 
			
		||||
@@ -122,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;
 | 
			
		||||
@@ -154,7 +169,7 @@ export const getApplicableStylesForItem = (domainObject, item) => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getStylesWithoutNoneValue = (style) => {
 | 
			
		||||
    if (_.isEmpty(style) || !style) {
 | 
			
		||||
    if (isEmpty(style) || !style) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    let styleObj = {};
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,6 @@
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import uuid from 'uuid';
 | 
			
		||||
 | 
			
		||||
import SubobjectView from './SubobjectView.vue'
 | 
			
		||||
import TelemetryView from './TelemetryView.vue'
 | 
			
		||||
import BoxView from './BoxView.vue'
 | 
			
		||||
@@ -76,6 +75,7 @@ import TextView from './TextView.vue'
 | 
			
		||||
import LineView from './LineView.vue'
 | 
			
		||||
import ImageView from './ImageView.vue'
 | 
			
		||||
import EditMarquee from './EditMarquee.vue'
 | 
			
		||||
import _ from 'lodash'
 | 
			
		||||
 | 
			
		||||
const ITEM_TYPE_VIEW_MAP = {
 | 
			
		||||
    'subobject-view': SubobjectView,
 | 
			
		||||
@@ -512,7 +512,7 @@ export default {
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        updateTelemetryFormat(item, format) {
 | 
			
		||||
            let index = _.findIndex(this.layoutItems, item);
 | 
			
		||||
            let index = this.layoutItems.findIndex(item);
 | 
			
		||||
            item.format = format;
 | 
			
		||||
            this.mutate(`configuration.items[${index}]`, item);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import LayoutDrag from './../LayoutDrag'
 | 
			
		||||
import _ from 'lodash'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    inject: ['openmct'],
 | 
			
		||||
 
 | 
			
		||||
@@ -62,6 +62,7 @@
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
import conditionalStylesMixin from "../mixins/objectStyles-mixin";
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
const START_HANDLE_QUADRANTS = {
 | 
			
		||||
    1: 'c-frame-edit__handle--sw',
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
 | 
			
		||||
import Layout from './components/DisplayLayout.vue'
 | 
			
		||||
import Vue from 'vue'
 | 
			
		||||
import objectUtils from '../../api/objects/object-utils.js'
 | 
			
		||||
import objectUtils from 'objectUtils'
 | 
			
		||||
import DisplayLayoutType from './DisplayLayoutType.js'
 | 
			
		||||
import DisplayLayoutToolbar from './DisplayLayoutToolbar.js'
 | 
			
		||||
import AlphaNumericFormatViewProvider from './AlphanumericFormatViewProvider.js'
 | 
			
		||||
 
 | 
			
		||||
@@ -62,6 +62,7 @@
 | 
			
		||||
<script>
 | 
			
		||||
import FilterField from './FilterField.vue';
 | 
			
		||||
import ToggleSwitch from '../../../ui/components/ToggleSwitch.vue';
 | 
			
		||||
import isEmpty from 'lodash/isEmpty';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    inject: ['openmct'],
 | 
			
		||||
@@ -102,7 +103,7 @@ export default {
 | 
			
		||||
        hasActiveFilters() {
 | 
			
		||||
            // Should be true when the user has entered any filter values.
 | 
			
		||||
            return Object.values(this.persistedFilters).some(comparator => {
 | 
			
		||||
                return (typeof(comparator) === 'object' && !_.isEmpty(comparator));
 | 
			
		||||
                return (typeof(comparator) === 'object' && !isEmpty(comparator));
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,8 @@
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import FilterObject from './FilterObject.vue';
 | 
			
		||||
import GlobalFilters from './GlobalFilters.vue'
 | 
			
		||||
import GlobalFilters from './GlobalFilters.vue';
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
const FILTER_VIEW_TITLE = 'Filters applied';
 | 
			
		||||
const FILTER_VIEW_TITLE_MIXED = 'Mixed filters applied';
 | 
			
		||||
 
 | 
			
		||||
@@ -64,6 +64,7 @@
 | 
			
		||||
<script>
 | 
			
		||||
import compositionLoader from './composition-loader';
 | 
			
		||||
import ListItem from './ListItem.vue';
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    components: {ListItem},
 | 
			
		||||
 
 | 
			
		||||
@@ -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 = _.sortedIndex(this.imageHistory, datum, this.timeFormat.format.bind(this.timeFormat));
 | 
			
		||||
            const index = _.sortedIndexBy(this.imageHistory, datum, this.timeFormat.format.bind(this.timeFormat));
 | 
			
		||||
            this.imageHistory.splice(index, 0, datum);
 | 
			
		||||
 | 
			
		||||
            if(updateValues) {
 | 
			
		||||
                this.updateValues(datum);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        updateValues(datum) {
 | 
			
		||||
            if (this.isPaused) {
 | 
			
		||||
 
 | 
			
		||||
@@ -169,11 +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();
 | 
			
		||||
 | 
			
		||||
            window.location.href = link;
 | 
			
		||||
 | 
			
		||||
            this.openmct.time.stopClock();
 | 
			
		||||
            let message = '';
 | 
			
		||||
            if (isTimeBoundChanged) {
 | 
			
		||||
                this.openmct.time.bounds({
 | 
			
		||||
@@ -187,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());
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
@@ -152,7 +152,7 @@ function (
 | 
			
		||||
    MCTChartController.prototype.destroy = function () {
 | 
			
		||||
        this.isDestroyed = true;
 | 
			
		||||
        this.stopListening();
 | 
			
		||||
        _.invoke(this.lines, 'destroy');
 | 
			
		||||
        this.lines.forEach(line => line.destroy());
 | 
			
		||||
        DrawLoader.releaseDrawAPI(this.drawAPI);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ define([
 | 
			
		||||
        this.initialize(options);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _.extend(Collection.prototype, EventEmitter.prototype);
 | 
			
		||||
    Object.assign(Collection.prototype, EventEmitter.prototype);
 | 
			
		||||
    eventHelpers.extend(Collection.prototype);
 | 
			
		||||
 | 
			
		||||
    Collection.extend = extend;
 | 
			
		||||
@@ -105,12 +105,7 @@ define([
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Collection.prototype.indexOf = function (model) {
 | 
			
		||||
        return _.findIndex(
 | 
			
		||||
            this.models,
 | 
			
		||||
            function (m) {
 | 
			
		||||
                return m === model;
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
        return this.models.findIndex(m => m === model);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Collection.prototype.remove = function (model) {
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,7 @@ define([
 | 
			
		||||
        this.initialize(options);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _.extend(Model.prototype, EventEmitter.prototype);
 | 
			
		||||
    Object.assign(Model.prototype, EventEmitter.prototype);
 | 
			
		||||
    eventHelpers.extend(Model.prototype);
 | 
			
		||||
 | 
			
		||||
    Model.extend = extend;
 | 
			
		||||
 
 | 
			
		||||
@@ -146,7 +146,7 @@ define([
 | 
			
		||||
                strategy = 'minmax';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            options = _.extend({}, { size: 1000, strategy, filters: this.filters }, options || {});
 | 
			
		||||
            options = Object.assign({}, { size: 1000, strategy, filters: this.filters }, options || {});
 | 
			
		||||
 | 
			
		||||
            if (!this.unsubscribe) {
 | 
			
		||||
                this.unsubscribe = this.openmct
 | 
			
		||||
@@ -160,6 +160,7 @@ define([
 | 
			
		||||
                    );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* eslint-disable you-dont-need-lodash-underscore/concat */
 | 
			
		||||
            return this.openmct
 | 
			
		||||
                .telemetry
 | 
			
		||||
                .request(this.domainObject, options)
 | 
			
		||||
@@ -171,6 +172,7 @@ define([
 | 
			
		||||
                        .value();
 | 
			
		||||
                    this.reset(newPoints);
 | 
			
		||||
                }.bind(this));
 | 
			
		||||
            /* eslint-enable you-dont-need-lodash-underscore/concat */
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * Update x formatter on x change.
 | 
			
		||||
@@ -270,7 +272,7 @@ define([
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        sortedIndex: function (point) {
 | 
			
		||||
            return _.sortedIndex(this.data, point, this.getXVal);
 | 
			
		||||
            return _.sortedIndexBy(this.data, point, this.getXVal);
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * Update min/max stats for the series.
 | 
			
		||||
@@ -322,7 +324,15 @@ define([
 | 
			
		||||
         *                  a point to the end without dupe checking.
 | 
			
		||||
         */
 | 
			
		||||
        add: function (point, appendOnly) {
 | 
			
		||||
            var insertIndex = this.data.length;
 | 
			
		||||
            var insertIndex = this.data.length,
 | 
			
		||||
                currentYVal = this.getYVal(point),
 | 
			
		||||
                lastYVal = this.getYVal(this.data[insertIndex - 1]);
 | 
			
		||||
 | 
			
		||||
            if (this.isValueInvalid(currentYVal) && this.isValueInvalid(lastYVal)) {
 | 
			
		||||
                console.warn('[Plot] Invalid Y Values detected');
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!appendOnly) {
 | 
			
		||||
                insertIndex = this.sortedIndex(point);
 | 
			
		||||
                if (this.getXVal(this.data[insertIndex]) === this.getXVal(point)) {
 | 
			
		||||
@@ -332,11 +342,21 @@ define([
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.updateStats(point);
 | 
			
		||||
            point.mctLimitState = this.evaluate(point);
 | 
			
		||||
            this.data.splice(insertIndex, 0, point);
 | 
			
		||||
            this.emit('add', point, insertIndex, this);
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        isValueInvalid: function (val) {
 | 
			
		||||
            return Number.isNaN(val) || val === undefined;
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Remove a point from the data array and notify listeners.
 | 
			
		||||
         * @private
 | 
			
		||||
 
 | 
			
		||||
@@ -101,11 +101,11 @@ define([
 | 
			
		||||
            var plotObject = this.plot.get('domainObject');
 | 
			
		||||
            if (plotObject.type === 'telemetry.plot.overlay') {
 | 
			
		||||
 | 
			
		||||
                var persistedIndex = _.findIndex(plotObject.configuration.series, function (s) {
 | 
			
		||||
                var persistedIndex = plotObject.configuration.series.findIndex(s => {
 | 
			
		||||
                    return _.isEqual(identifier, s.identifier);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                var configIndex = _.findIndex(this.models, function (m) {
 | 
			
		||||
                var configIndex = this.models.findIndex(m => {
 | 
			
		||||
                    return _.isEqual(m.domainObject.identifier, identifier);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -182,21 +182,6 @@ define([
 | 
			
		||||
            this.set('format', yFormat.format.bind(yFormat));
 | 
			
		||||
            this.set('values', yMetadata.values);
 | 
			
		||||
            if (!label) {
 | 
			
		||||
                var labelUnits = series.map(function (s) {
 | 
			
		||||
                    return s.metadata.value(s.get('yKey')).units;
 | 
			
		||||
                }).reduce(function (a, b) {
 | 
			
		||||
                    if (a === undefined) {
 | 
			
		||||
                        return b;
 | 
			
		||||
                    }
 | 
			
		||||
                    if (a === b) {
 | 
			
		||||
                        return a;
 | 
			
		||||
                    }
 | 
			
		||||
                    return '';
 | 
			
		||||
                }, undefined);
 | 
			
		||||
                if (labelUnits) {
 | 
			
		||||
                    this.set('label', labelUnits);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                var labelName = series.map(function (s) {
 | 
			
		||||
                    return s.metadata.value(s.get('yKey')).name;
 | 
			
		||||
                }).reduce(function (a, b) {
 | 
			
		||||
@@ -208,7 +193,28 @@ define([
 | 
			
		||||
                    }
 | 
			
		||||
                    return '';
 | 
			
		||||
                }, undefined);
 | 
			
		||||
                this.set('label', labelName);
 | 
			
		||||
 | 
			
		||||
                if (labelName) {
 | 
			
		||||
                    this.set('label', labelName);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var labelUnits = series.map(function (s) {
 | 
			
		||||
                    return s.metadata.value(s.get('yKey')).units;
 | 
			
		||||
                }).reduce(function (a, b) {
 | 
			
		||||
                    if (a === undefined) {
 | 
			
		||||
                        return b;
 | 
			
		||||
                    }
 | 
			
		||||
                    if (a === b) {
 | 
			
		||||
                        return a;
 | 
			
		||||
                    }
 | 
			
		||||
                    return '';
 | 
			
		||||
                }, undefined);
 | 
			
		||||
 | 
			
		||||
                if (labelUnits) {
 | 
			
		||||
                    this.set('label', labelUnits);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        defaults: function (options) {
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,7 @@ define([
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _.extend(Draw2D.prototype, EventEmitter.prototype);
 | 
			
		||||
    Object.assign(Draw2D.prototype, EventEmitter.prototype);
 | 
			
		||||
    eventHelpers.extend(Draw2D.prototype);
 | 
			
		||||
 | 
			
		||||
    // Convert from logical to physical x coordinates
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@ define([
 | 
			
		||||
        this.listenTo(this.canvas, "webglcontextlost", this.onContextLost, this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _.extend(DrawWebGL.prototype, EventEmitter.prototype);
 | 
			
		||||
    Object.assign(DrawWebGL.prototype, EventEmitter.prototype);
 | 
			
		||||
    eventHelpers.extend(DrawWebGL.prototype);
 | 
			
		||||
 | 
			
		||||
    DrawWebGL.prototype.onContextLost = function (event) {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@
 | 
			
		||||
define([
 | 
			
		||||
    '../configuration/configStore',
 | 
			
		||||
    '../lib/eventHelpers',
 | 
			
		||||
    '../../../../api/objects/object-utils',
 | 
			
		||||
    'objectUtils',
 | 
			
		||||
    'lodash'
 | 
			
		||||
], function (
 | 
			
		||||
    configStore,
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@ define([
 | 
			
		||||
    function dynamicPathForKey(key) {
 | 
			
		||||
        return function (object, model) {
 | 
			
		||||
            var modelIdentifier = model.get('identifier');
 | 
			
		||||
            var index = _.findIndex(object.configuration.series, function (s) {
 | 
			
		||||
            var index = object.configuration.series.findIndex(s => {
 | 
			
		||||
                return _.isEqual(s.identifier, modelIdentifier);
 | 
			
		||||
            });
 | 
			
		||||
            return 'configuration.series[' + index + '].' + key;
 | 
			
		||||
 
 | 
			
		||||
@@ -73,10 +73,10 @@ define([
 | 
			
		||||
                    if (range.max === '' || range.max === null || typeof range.max === 'undefined') {
 | 
			
		||||
                        return 'Must specify Maximum';
 | 
			
		||||
                    }
 | 
			
		||||
                    if (_.isNaN(Number(range.min))) {
 | 
			
		||||
                    if (Number.isNaN(Number(range.min))) {
 | 
			
		||||
                        return 'Minimum must be a number.';
 | 
			
		||||
                    }
 | 
			
		||||
                    if (_.isNaN(Number(range.max))) {
 | 
			
		||||
                    if (Number.isNaN(Number(range.max))) {
 | 
			
		||||
                        return 'Maximum must be a number.';
 | 
			
		||||
                    }
 | 
			
		||||
                    if (Number(range.min) > Number(range.max)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -325,7 +325,7 @@ define([
 | 
			
		||||
        } else {
 | 
			
		||||
            // A history entry is created by startMarquee, need to remove
 | 
			
		||||
            // if marquee zoom doesn't occur.
 | 
			
		||||
            this.back();
 | 
			
		||||
            this.plotHistory.pop();
 | 
			
		||||
        }
 | 
			
		||||
        this.$scope.rectangles = [];
 | 
			
		||||
        this.marquee = undefined;
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,7 @@ define([
 | 
			
		||||
                if (childObj) {
 | 
			
		||||
                    var index = telemetryObjects.indexOf(childObj);
 | 
			
		||||
                    telemetryObjects.splice(index, 1);
 | 
			
		||||
                    $scope.$broadcast('plot:tickWidth', _.max(tickWidthMap));
 | 
			
		||||
                    $scope.$broadcast('plot:tickWidth', Math.max(...Object.values(tickWidthMap)));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
define([
 | 
			
		||||
    '../../api/objects/object-utils'
 | 
			
		||||
    'objectUtils'
 | 
			
		||||
], function (
 | 
			
		||||
    objectUtils
 | 
			
		||||
) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
define ([
 | 
			
		||||
    './ConditionEvaluator',
 | 
			
		||||
    '../../../api/objects/object-utils',
 | 
			
		||||
    'objectUtils',
 | 
			
		||||
    'EventEmitter',
 | 
			
		||||
    'zepto',
 | 
			
		||||
    'lodash'
 | 
			
		||||
@@ -9,7 +9,8 @@ define ([
 | 
			
		||||
    objectUtils,
 | 
			
		||||
    EventEmitter,
 | 
			
		||||
    $,
 | 
			
		||||
    _
 | 
			
		||||
    _,
 | 
			
		||||
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ define([
 | 
			
		||||
    './TestDataManager',
 | 
			
		||||
    './WidgetDnD',
 | 
			
		||||
    './eventHelpers',
 | 
			
		||||
    '../../../api/objects/object-utils',
 | 
			
		||||
    'objectUtils',
 | 
			
		||||
    'lodash',
 | 
			
		||||
    'zepto'
 | 
			
		||||
], function (
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
define([
 | 
			
		||||
    './Select',
 | 
			
		||||
    '../../../../api/objects/object-utils'
 | 
			
		||||
    'objectUtils'
 | 
			
		||||
], function (
 | 
			
		||||
    Select,
 | 
			
		||||
    objectUtils
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './SummaryWidgetEvaluator',
 | 
			
		||||
    '../../../../api/objects/object-utils'
 | 
			
		||||
    'objectUtils'
 | 
			
		||||
], function (
 | 
			
		||||
    SummaryWidgetEvaluator,
 | 
			
		||||
    objectUtils
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@
 | 
			
		||||
define([
 | 
			
		||||
    './SummaryWidgetRule',
 | 
			
		||||
    '../eventHelpers',
 | 
			
		||||
    '../../../../api/objects/object-utils',
 | 
			
		||||
    'objectUtils',
 | 
			
		||||
    'lodash'
 | 
			
		||||
], function (
 | 
			
		||||
    SummaryWidgetRule,
 | 
			
		||||
@@ -80,10 +80,12 @@ define([
 | 
			
		||||
                    }
 | 
			
		||||
                }.bind(this);
 | 
			
		||||
 | 
			
		||||
                /* eslint-disable you-dont-need-lodash-underscore/map */
 | 
			
		||||
                unsubscribes = _.map(
 | 
			
		||||
                    realtimeStates,
 | 
			
		||||
                    this.subscribeToObjectState.bind(this, updateCallback)
 | 
			
		||||
                );
 | 
			
		||||
                /* eslint-enable you-dont-need-lodash-underscore/map */
 | 
			
		||||
            }.bind(this));
 | 
			
		||||
 | 
			
		||||
        return function () {
 | 
			
		||||
@@ -151,11 +153,13 @@ define([
 | 
			
		||||
    SummaryWidgetEvaluator.prototype.getBaseStateClone = function () {
 | 
			
		||||
        return this.load()
 | 
			
		||||
            .then(function () {
 | 
			
		||||
                /* eslint-disable you-dont-need-lodash-underscore/values */
 | 
			
		||||
                return _(this.baseState)
 | 
			
		||||
                    .values()
 | 
			
		||||
                    .map(_.clone)
 | 
			
		||||
                    .indexBy('id')
 | 
			
		||||
                    .keyBy('id')
 | 
			
		||||
                    .value();
 | 
			
		||||
                /* eslint-enable you-dont-need-lodash-underscore/values */
 | 
			
		||||
            }.bind(this));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -182,7 +186,7 @@ define([
 | 
			
		||||
     * @private.
 | 
			
		||||
     */
 | 
			
		||||
    SummaryWidgetEvaluator.prototype.updateObjectStateFromLAD = function (options, objectState) {
 | 
			
		||||
        options = _.extend({}, options, {
 | 
			
		||||
        options = Object.assign({}, options, {
 | 
			
		||||
            strategy: 'latest',
 | 
			
		||||
            size: 1
 | 
			
		||||
        });
 | 
			
		||||
@@ -255,10 +259,12 @@ define([
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* eslint-disable you-dont-need-lodash-underscore/map */
 | 
			
		||||
        var latestTimestamp = _(state)
 | 
			
		||||
            .map('timestamps')
 | 
			
		||||
            .sortBy(timestampKey)
 | 
			
		||||
            .last();
 | 
			
		||||
        /* eslint-enable you-dont-need-lodash-underscore/map */
 | 
			
		||||
 | 
			
		||||
        if (!latestTimestamp) {
 | 
			
		||||
            latestTimestamp = {};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
define([
 | 
			
		||||
    '../SummaryWidget',
 | 
			
		||||
    './SummaryWidgetView',
 | 
			
		||||
    '../../../../api/objects/object-utils'
 | 
			
		||||
    'objectUtils'
 | 
			
		||||
], function (
 | 
			
		||||
    SummaryWidgetEditView,
 | 
			
		||||
    SummaryWidgetView,
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
/*jshint latedef: nofunc */
 | 
			
		||||
/*global console */
 | 
			
		||||
define([
 | 
			
		||||
    '../../../api/objects/object-utils',
 | 
			
		||||
    'objectUtils',
 | 
			
		||||
    './TelemetryAverager'
 | 
			
		||||
], function (objectUtils, TelemetryAverager) {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    '../../api/objects/object-utils',
 | 
			
		||||
    'objectUtils',
 | 
			
		||||
    './components/table-configuration.vue',
 | 
			
		||||
    './TelemetryTableConfiguration',
 | 
			
		||||
    'vue'
 | 
			
		||||
 
 | 
			
		||||
@@ -100,7 +100,7 @@ define([
 | 
			
		||||
 | 
			
		||||
        hasColumnWithKey(columnKey) {
 | 
			
		||||
            return _.flatten(Object.values(this.columns))
 | 
			
		||||
                .findIndex(column => column.getKey() === columnKey) !== -1;
 | 
			
		||||
                .some(column => column.getKey() === columnKey);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        getColumns() {
 | 
			
		||||
@@ -109,9 +109,10 @@ define([
 | 
			
		||||
 | 
			
		||||
        getAllHeaders() {
 | 
			
		||||
            let flattenedColumns = _.flatten(Object.values(this.columns));
 | 
			
		||||
            /* eslint-disable you-dont-need-lodash-underscore/uniq */
 | 
			
		||||
            let headers = _.uniq(flattenedColumns, false, column => column.getKey())
 | 
			
		||||
                .reduce(fromColumnsToHeadersMap, {});
 | 
			
		||||
 | 
			
		||||
            /* eslint-enable you-dont-need-lodash-underscore/uniq */
 | 
			
		||||
            function fromColumnsToHeadersMap(headersMap, column) {
 | 
			
		||||
                headersMap[column.getKey()] = column.getTitle();
 | 
			
		||||
                return headersMap;
 | 
			
		||||
 
 | 
			
		||||
@@ -93,7 +93,7 @@ define(
 | 
			
		||||
                    // same time stamp
 | 
			
		||||
                    let potentialDupes = this.rows.slice(startIx, endIx + 1);
 | 
			
		||||
                    // Search potential dupes for exact dupe
 | 
			
		||||
                    isDuplicate = _.findIndex(potentialDupes, _.isEqual.bind(undefined, row)) > -1;
 | 
			
		||||
                    isDuplicate = potentialDupes.some(_.isEqual.bind(undefined, row));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!isDuplicate) {
 | 
			
		||||
@@ -120,7 +120,7 @@ define(
 | 
			
		||||
                const firstValue = this.getValueForSortColumn(this.rows[0]);
 | 
			
		||||
                const lastValue = this.getValueForSortColumn(this.rows[this.rows.length - 1]);
 | 
			
		||||
 | 
			
		||||
                lodashFunction = lodashFunction || _.sortedIndex;
 | 
			
		||||
                lodashFunction = lodashFunction || _.sortedIndexBy;
 | 
			
		||||
 | 
			
		||||
                if (this.sortOptions.direction === 'asc') {
 | 
			
		||||
                    if (testRowValue > lastValue) {
 | 
			
		||||
@@ -201,7 +201,7 @@ define(
 | 
			
		||||
            sortBy(sortOptions) {
 | 
			
		||||
                if (arguments.length > 0) {
 | 
			
		||||
                    this.sortOptions = sortOptions;
 | 
			
		||||
                    this.rows = _.sortByOrder(this.rows, (row) => row.getParsedValue(sortOptions.key) , sortOptions.direction);
 | 
			
		||||
                    this.rows = _.orderBy(this.rows, (row) => row.getParsedValue(sortOptions.key) , sortOptions.direction);
 | 
			
		||||
                    this.emit('sort');
 | 
			
		||||
                }
 | 
			
		||||
                // Return duplicate to avoid direct modification of underlying object
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,8 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
const FILTER_INDICATOR_LABEL = 'Filters:';
 | 
			
		||||
const FILTER_INDICATOR_LABEL_MIXED = 'Mixed Filters:';
 | 
			
		||||
const FILTER_INDICATOR_TITLE = 'Data filters are being applied to this view.';
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -24,34 +24,39 @@ import Vue from 'vue';
 | 
			
		||||
import {
 | 
			
		||||
    createOpenMct,
 | 
			
		||||
    createMouseEvent
 | 
			
		||||
} from 'testTools';
 | 
			
		||||
 | 
			
		||||
let openmct;
 | 
			
		||||
let tablePlugin;
 | 
			
		||||
let element;
 | 
			
		||||
let child;
 | 
			
		||||
} from 'testUtils';
 | 
			
		||||
 | 
			
		||||
describe("the plugin", () => {
 | 
			
		||||
    beforeEach((done) => {
 | 
			
		||||
        const appHolder = document.createElement('div');
 | 
			
		||||
        appHolder.style.width = '640px';
 | 
			
		||||
        appHolder.style.height = '480px';
 | 
			
		||||
    let openmct;
 | 
			
		||||
    let tablePlugin;
 | 
			
		||||
    let element;
 | 
			
		||||
    let child;
 | 
			
		||||
 | 
			
		||||
    beforeEach((done) => {
 | 
			
		||||
        openmct = createOpenMct();
 | 
			
		||||
 | 
			
		||||
        // Table Plugin is actually installed by default, but because installing it
 | 
			
		||||
        // again is harmless it is left here as an examplar for non-default plugins.
 | 
			
		||||
        tablePlugin = new TablePlugin();
 | 
			
		||||
        openmct.install(tablePlugin);
 | 
			
		||||
 | 
			
		||||
        element = document.createElement('div');
 | 
			
		||||
        child = document.createElement('div');
 | 
			
		||||
        element.appendChild(child);
 | 
			
		||||
 | 
			
		||||
        tablePlugin = new TablePlugin();
 | 
			
		||||
        openmct.install(tablePlugin);
 | 
			
		||||
 | 
			
		||||
        spyOn(openmct.telemetry, 'request').and.returnValue(Promise.resolve([]));
 | 
			
		||||
 | 
			
		||||
        openmct.on('start', done);
 | 
			
		||||
        openmct.start(appHolder);
 | 
			
		||||
        openmct.startHeadless();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe("defines a table object", function () {
 | 
			
		||||
        it("that is creatable", () => {
 | 
			
		||||
            let tableType = openmct.types.get('table');
 | 
			
		||||
            expect(tableType.definition.creatable).toBe(true);
 | 
			
		||||
        });
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    it("provides a table view for objects with telemetry", () => {
 | 
			
		||||
        const testTelemetryObject = {
 | 
			
		||||
            id:"test-object",
 | 
			
		||||
 
 | 
			
		||||
@@ -114,25 +114,6 @@ mct-plot {
 | 
			
		||||
    .plot-wrapper-axis-and-display-area {
 | 
			
		||||
        position: relative;
 | 
			
		||||
        flex: 1 1 auto;
 | 
			
		||||
 | 
			
		||||
        .l-state-indicators {
 | 
			
		||||
            color: $colorPausedBg;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            display: block;
 | 
			
		||||
            font-size: 1.5em;
 | 
			
		||||
            pointer-events: none;
 | 
			
		||||
            top: $interiorMarginSm;
 | 
			
		||||
            left: $interiorMarginSm;
 | 
			
		||||
            z-index: 2;
 | 
			
		||||
 | 
			
		||||
            > * + * {
 | 
			
		||||
                margin-left: $interiorMarginSm;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .t-alert-unsynced {
 | 
			
		||||
                display: none;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .gl-plot-wrapper-display-area-and-x-axis {
 | 
			
		||||
@@ -294,6 +275,25 @@ mct-plot {
 | 
			
		||||
            right: $m;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .l-state-indicators {
 | 
			
		||||
        color: $colorPausedBg;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        display: block;
 | 
			
		||||
        font-size: 1.5em;
 | 
			
		||||
        pointer-events: none;
 | 
			
		||||
        top: $interiorMarginSm;
 | 
			
		||||
        left: $interiorMargin;
 | 
			
		||||
        z-index: 2;
 | 
			
		||||
 | 
			
		||||
        > * + * {
 | 
			
		||||
            margin-left: $interiorMarginSm;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .t-alert-unsynced {
 | 
			
		||||
            display: none;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.gl-plot-display-area,
 | 
			
		||||
 
 | 
			
		||||
@@ -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/>'
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user