mirror of
https://github.com/nasa/openmct.git
synced 2025-06-30 04:33:03 +00:00
Compare commits
118 Commits
notebook-p
...
context-me
Author | SHA1 | Date | |
---|---|---|---|
8493b481dd | |||
28723b59b7 | |||
9fa7de0b77 | |||
54bfc84ada | |||
6137700c82 | |||
91a1b3f31d | |||
357b25a76b | |||
bab53ad9bd | |||
d0d4579f13 | |||
02b537580c | |||
7073b0717f | |||
d6bb1b2a12 | |||
c256696790 | |||
d5480e7524 | |||
ab463e93fe | |||
8363c65312 | |||
04598b6cf1 | |||
43628ad9d6 | |||
67bea86bc8 | |||
4eb4cbfffc | |||
eda01abcbc | |||
2fa29124bf | |||
694b8f4666 | |||
33faeafa98 | |||
a40ff07353 | |||
41dc9c794d | |||
f1faf3965d | |||
da2ecbbcad | |||
32c892fe98 | |||
bbb271a678 | |||
fec1438806 | |||
28f19ec310 | |||
f934454c25 | |||
eb49ffae02 | |||
5751012872 | |||
aa041e04cf | |||
24e7ea143a | |||
79d5d9c4d0 | |||
b5bfdc4418 | |||
59730c60ec | |||
4a87a5d847 | |||
421c09ec2c | |||
0679b246b8 | |||
83f9c6c528 | |||
a5f3ba6259 | |||
a70facf0c8 | |||
447fe94325 | |||
8e2b666766 | |||
dcbfbdbb89 | |||
4c76bf34ab | |||
81b7a9d3e0 | |||
dc573c479c | |||
23303c910e | |||
3282934cf6 | |||
c157fab081 | |||
7c07b66cc9 | |||
7a906ccf5c | |||
ff7debfb81 | |||
92ba103f45 | |||
2c2d8d6b56 | |||
cfadb9f4fd | |||
396817b2d1 | |||
96eb6d6b74 | |||
cb5d47f66f | |||
ea90d02d66 | |||
95f73d8eb8 | |||
a37c686993 | |||
f12166097c | |||
d103a22fa0 | |||
04a60cfcbb | |||
8d723960f4 | |||
6d3cd2c699 | |||
87bf94fe0a | |||
af93823b6f | |||
4a39ddf425 | |||
83c273b976 | |||
7dd81beb03 | |||
1842d3923c | |||
26838635b6 | |||
11f2c35bb2 | |||
766f48c1ba | |||
da7b93f9b3 | |||
99c095a69f | |||
f885e83505 | |||
928bc4c68a | |||
d5539c7ae4 | |||
c86a104fb6 | |||
46fedc1a30 | |||
3b6ef9b44b | |||
c68edd9b7d | |||
11574b7c40 | |||
abc2cd2413 | |||
5d74882646 | |||
9fe7f230e6 | |||
de4c5b3729 | |||
2a7901914a | |||
73b0fc6f79 | |||
ddef16795c | |||
d188b9a056 | |||
f510f3edd0 | |||
e05b0bb562 | |||
713c5e9fb7 | |||
17bca04560 | |||
e0c5bca47d | |||
cdc7c1af64 | |||
3158baa998 | |||
698508fde4 | |||
68a96989e1 | |||
46a6a43234 | |||
d41fc27b55 | |||
24bb96cc90 | |||
483ee173d6 | |||
8f81a45b9b | |||
666459be87 | |||
d3fe2a6811 | |||
97b37edce4 | |||
dd70bb470f | |||
072bf361de |
@ -20,8 +20,8 @@ jobs:
|
|||||||
paths:
|
paths:
|
||||||
- node_modules
|
- node_modules
|
||||||
- run:
|
- run:
|
||||||
name: npm run test
|
name: npm run test:coverage
|
||||||
command: npm run test
|
command: npm run test:coverage
|
||||||
- run:
|
- run:
|
||||||
name: npm run lint
|
name: npm run lint
|
||||||
command: npm run lint
|
command: npm run lint
|
||||||
|
64
.eslintrc.js
64
.eslintrc.js
@ -1,3 +1,4 @@
|
|||||||
|
const LEGACY_FILES = ["platform/**", "example/**"];
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
@ -10,7 +11,8 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
"extends": [
|
"extends": [
|
||||||
"eslint:recommended",
|
"eslint:recommended",
|
||||||
"plugin:vue/recommended"
|
"plugin:vue/recommended",
|
||||||
|
"plugin:you-dont-need-lodash-underscore/compatible"
|
||||||
],
|
],
|
||||||
"parser": "vue-eslint-parser",
|
"parser": "vue-eslint-parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
@ -22,6 +24,9 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"you-dont-need-lodash-underscore/omit": "off",
|
||||||
|
"you-dont-need-lodash-underscore/throttle": "off",
|
||||||
|
"you-dont-need-lodash-underscore/flatten": "off",
|
||||||
"no-bitwise": "error",
|
"no-bitwise": "error",
|
||||||
"curly": "error",
|
"curly": "error",
|
||||||
"eqeqeq": "error",
|
"eqeqeq": "error",
|
||||||
@ -66,6 +71,56 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
"dot-notation": "error",
|
"dot-notation": "error",
|
||||||
"indent": ["error", 4],
|
"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": [
|
"vue/html-indent": [
|
||||||
"error",
|
"error",
|
||||||
4,
|
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:
|
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.
|
* `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`: 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.
|
* `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.
|
* `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
|
##### The Time Conductor and Telemetry
|
||||||
|
158
CONTRIBUTING.md
158
CONTRIBUTING.md
@ -103,7 +103,7 @@ the name chosen could not be mistaken for a topic or master branch.
|
|||||||
### Merging
|
### Merging
|
||||||
|
|
||||||
When development is complete on an issue, the first step toward merging it
|
When development is complete on an issue, the first step toward merging it
|
||||||
back into the master branch is to file a Pull Request. The contributions
|
back into the master branch is to file a Pull Request (PR). The contributions
|
||||||
should meet code, test, and commit message standards as described below,
|
should meet code, test, and commit message standards as described below,
|
||||||
and the pull request should include a completed author checklist, also
|
and the pull request should include a completed author checklist, also
|
||||||
as described below. Pull requests may be assigned to specific team
|
as described below. Pull requests may be assigned to specific team
|
||||||
@ -114,6 +114,15 @@ request. When the reviewer is satisfied, they should add a comment to
|
|||||||
the pull request containing the reviewer checklist (from below) and complete
|
the pull request containing the reviewer checklist (from below) and complete
|
||||||
the merge back to the master branch.
|
the merge back to the master branch.
|
||||||
|
|
||||||
|
Additionally:
|
||||||
|
* Every pull request must link to the issue that it addresses. Eg. “Addresses #1234” or “Closes #1234”. This is the responsibility of the pull request’s __author__. If no issue exists, create one.
|
||||||
|
* Every __author__ must include testing instructions. These instructions should identify the areas of code affected, and some minimal test steps. If addressing a bug, reproduction steps should be included, if they were not included in the original issue. If reproduction steps were included on the original issue, and are sufficient, refer to them.
|
||||||
|
* A pull request that closes an issue should say so in the description. Including the text “Closes #1234” will cause the linked issue to be automatically closed when the pull request is merged. This is the responsibility of the pull 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
|
## Standards
|
||||||
|
|
||||||
Contributions to Open MCT are expected to meet the following standards.
|
Contributions to Open MCT are expected to meet the following standards.
|
||||||
@ -122,89 +131,96 @@ changes.
|
|||||||
|
|
||||||
### Code Standards
|
### Code Standards
|
||||||
|
|
||||||
JavaScript sources in Open MCT must satisfy JSLint under its default
|
JavaScript sources in Open MCT must satisfy the ESLint rules defined in
|
||||||
settings. This is verified by the command line build.
|
this repository. This is verified by the command line build.
|
||||||
|
|
||||||
#### Code Guidelines
|
#### Code Guidelines
|
||||||
|
|
||||||
JavaScript sources in Open MCT should:
|
The following guidelines are provided for anyone contributing source code to the Open MCT project:
|
||||||
|
|
||||||
* Use four spaces for indentation. Tabs should not be used.
|
1. Write clean code. Here’s a good summary - https://github.com/ryanmcdermott/clean-code-javascript.
|
||||||
* Include JSDoc for any exposed API (e.g. public methods, constructors).
|
1. Include JSDoc for any exposed API (e.g. public methods, classes).
|
||||||
* Include non-JSDoc comments as-needed for explaining private variables,
|
1. Include non-JSDoc comments as-needed for explaining private variables,
|
||||||
methods, or algorithms when they are non-obvious.
|
methods, or algorithms when they are non-obvious. Otherwise code
|
||||||
* Define one public class per script, expressed as a constructor function
|
should be self-documenting.
|
||||||
returned from an AMD-style module.
|
1. Classes and Vue components should use camel case, first letter capitalized
|
||||||
* Follow “Java-like” naming conventions. These includes:
|
|
||||||
* Classes should use camel case, first letter capitalized
|
|
||||||
(e.g. SomeClassName).
|
(e.g. SomeClassName).
|
||||||
* Methods, variables, fields, and function names should use camel case,
|
1. Methods, variables, fields, events, and function names should use camelCase,
|
||||||
first letter lower-case (e.g. someVariableName).
|
first letter lower-case (e.g. someVariableName).
|
||||||
* Constants (variables or fields which are meant to be declared and
|
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
|
initialized statically, and never changed) should use only capital
|
||||||
letters, with underscores between words (e.g. SOME_CONSTANT).
|
letters, with underscores between words (e.g. SOME_CONSTANT). They should always be declared as `const`s
|
||||||
* File names should be the name of the exported class, plus a .js extension
|
1. File names should be the name of the exported class, plus a .js extension
|
||||||
(e.g. SomeClassName.js).
|
(e.g. SomeClassName.js).
|
||||||
* Avoid anonymous functions, except when functions are short (a few lines)
|
1. Avoid anonymous functions, except when functions are short (one or two lines)
|
||||||
and/or their inclusion makes sense within the flow of the code
|
and their inclusion makes sense within the flow of the code
|
||||||
(e.g. as arguments to a forEach call).
|
(e.g. as arguments to a forEach call). Anonymous functions should always be arrow functions.
|
||||||
* Avoid deep nesting (especially of functions), except where necessary
|
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).
|
(e.g. due to closure scope).
|
||||||
* End with a single new-line character.
|
1. End with a single new-line character.
|
||||||
* Expose public methods by declaring them on the class's prototype.
|
1. Always use ES6 `Class`es and inheritence rather than the pre-ES6 prototypal
|
||||||
* Within a given function's scope, do not mix declarations and imperative
|
pattern.
|
||||||
|
1. Within a given function's scope, do not mix declarations and imperative
|
||||||
code, and present these in the following order:
|
code, and present these in the following order:
|
||||||
* First, variable declarations and initialization.
|
* First, variable declarations and initialization.
|
||||||
* Second, function declarations.
|
* Secondly, imperative statements.
|
||||||
* Third, imperative statements.
|
* Finally, the returned value. Functions should only have a single return statement.
|
||||||
* Finally, the returned value.
|
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,
|
Deviations from Open MCT code style guidelines require two-party agreement,
|
||||||
typically from the author of the change and its reviewer.
|
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
|
### Test Standards
|
||||||
|
|
||||||
Automated testing shall occur whenever changes are merged into the main
|
Automated testing shall occur whenever changes are merged into the main
|
||||||
@ -292,6 +308,7 @@ checklist).
|
|||||||
2. Unit tests included and/or updated with changes?
|
2. Unit tests included and/or updated with changes?
|
||||||
3. Command line build passes?
|
3. Command line build passes?
|
||||||
4. Changes have been smoke-tested?
|
4. Changes have been smoke-tested?
|
||||||
|
5. Testing instructions included?
|
||||||
|
|
||||||
### Reviewer Checklist
|
### Reviewer Checklist
|
||||||
|
|
||||||
@ -299,3 +316,4 @@ checklist).
|
|||||||
2. Appropriate unit tests included?
|
2. Appropriate unit tests included?
|
||||||
3. Code style and in-line documentation are appropriate?
|
3. Code style and in-line documentation are appropriate?
|
||||||
4. Commit messages meet standards?
|
4. Commit messages meet standards?
|
||||||
|
5. Has associated issue been labelled `unverified`? (only applicable if this PR closes the issue)
|
||||||
|
@ -50,7 +50,8 @@ define([
|
|||||||
values: [
|
values: [
|
||||||
{
|
{
|
||||||
key: "name",
|
key: "name",
|
||||||
name: "Name"
|
name: "Name",
|
||||||
|
format: "string"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "utc",
|
key: "utc",
|
||||||
@ -99,7 +100,7 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
|
GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
|
||||||
return _.extend(
|
return Object.assign(
|
||||||
{},
|
{},
|
||||||
domainObject.telemetry,
|
domainObject.telemetry,
|
||||||
METADATA_BY_TYPE[domainObject.type]
|
METADATA_BY_TYPE[domainObject.type]
|
||||||
|
@ -52,6 +52,7 @@ define([
|
|||||||
return {
|
return {
|
||||||
name: name,
|
name: name,
|
||||||
utc: Math.floor(timestamp / 5000) * 5000,
|
utc: Math.floor(timestamp / 5000) * 5000,
|
||||||
|
local: Math.floor(timestamp / 5000) * 5000,
|
||||||
url: IMAGE_SAMPLES[Math.floor(timestamp / 5000) % IMAGE_SAMPLES.length]
|
url: IMAGE_SAMPLES[Math.floor(timestamp / 5000) % IMAGE_SAMPLES.length]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -78,7 +79,7 @@ define([
|
|||||||
},
|
},
|
||||||
request: function (domainObject, options) {
|
request: function (domainObject, options) {
|
||||||
var start = options.start;
|
var start = options.start;
|
||||||
var end = options.end;
|
var end = Math.min(options.end, Date.now());
|
||||||
var data = [];
|
var data = [];
|
||||||
while (start <= end && data.length < 5000) {
|
while (start <= end && data.length < 5000) {
|
||||||
data.push(pointForTimestamp(start, domainObject.name));
|
data.push(pointForTimestamp(start, domainObject.name));
|
||||||
@ -118,6 +119,14 @@ define([
|
|||||||
name: 'Time',
|
name: 'Time',
|
||||||
key: 'utc',
|
key: 'utc',
|
||||||
format: 'utc',
|
format: 'utc',
|
||||||
|
hints: {
|
||||||
|
domain: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Local Time',
|
||||||
|
key: 'local',
|
||||||
|
format: 'local-format',
|
||||||
hints: {
|
hints: {
|
||||||
domain: 1
|
domain: 1
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="example">{{ msg }}</div>
|
<div class="example">{{ msg }}</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
data () {
|
data() {
|
||||||
return {
|
return {
|
||||||
msg: 'Hello world!'
|
msg: 'Hello world!'
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
Open MCT, Copyright (c) 2014-2017, United States Government
|
Open MCT, Copyright (c) 2014-2020, United States Government
|
||||||
as represented by the Administrator of the National Aeronautics and Space
|
as represented by the Administrator of the National Aeronautics and Space
|
||||||
Administration. All rights reserved.
|
Administration. All rights reserved.
|
||||||
|
|
||||||
@ -43,9 +43,9 @@
|
|||||||
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
|
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
openmct.install(openmct.plugins.LocalStorage());
|
||||||
openmct.install(openmct.plugins.Espresso());
|
openmct.install(openmct.plugins.Espresso());
|
||||||
openmct.install(openmct.plugins.MyItems());
|
openmct.install(openmct.plugins.MyItems());
|
||||||
openmct.install(openmct.plugins.LocalStorage());
|
|
||||||
openmct.install(openmct.plugins.Generator());
|
openmct.install(openmct.plugins.Generator());
|
||||||
openmct.install(openmct.plugins.ExampleImagery());
|
openmct.install(openmct.plugins.ExampleImagery());
|
||||||
openmct.install(openmct.plugins.UTCTimeSystem());
|
openmct.install(openmct.plugins.UTCTimeSystem());
|
||||||
|
@ -24,16 +24,27 @@
|
|||||||
|
|
||||||
const devMode = process.env.NODE_ENV !== 'production';
|
const devMode = process.env.NODE_ENV !== 'production';
|
||||||
const browsers = [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'ChromeHeadless'];
|
const browsers = [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'ChromeHeadless'];
|
||||||
|
const coverageEnabled = process.env.COVERAGE === 'true';
|
||||||
|
const reporters = ['progress', 'html'];
|
||||||
|
|
||||||
|
if (coverageEnabled) {
|
||||||
|
reporters.push('coverage-istanbul');
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = (config) => {
|
module.exports = (config) => {
|
||||||
const webpackConfig = require('./webpack.config.js');
|
const webpackConfig = require('./webpack.config.js');
|
||||||
delete webpackConfig.output;
|
delete webpackConfig.output;
|
||||||
|
|
||||||
if (!devMode) {
|
if (!devMode || coverageEnabled) {
|
||||||
webpackConfig.module.rules.push({
|
webpackConfig.module.rules.push({
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
exclude: /node_modules|example/,
|
exclude: /node_modules|example|lib|dist/,
|
||||||
use: 'istanbul-instrumenter-loader'
|
use: {
|
||||||
|
loader: 'istanbul-instrumenter-loader',
|
||||||
|
options: {
|
||||||
|
esModules: true
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,11 +56,7 @@ module.exports = (config) => {
|
|||||||
'src/**/*Spec.js'
|
'src/**/*Spec.js'
|
||||||
],
|
],
|
||||||
port: 9876,
|
port: 9876,
|
||||||
reporters: [
|
reporters: reporters,
|
||||||
'progress',
|
|
||||||
'coverage',
|
|
||||||
'html'
|
|
||||||
],
|
|
||||||
browsers: browsers,
|
browsers: browsers,
|
||||||
customLaunchers: {
|
customLaunchers: {
|
||||||
ChromeDebugging: {
|
ChromeDebugging: {
|
||||||
@ -61,27 +68,27 @@ module.exports = (config) => {
|
|||||||
colors: true,
|
colors: true,
|
||||||
logLevel: config.LOG_INFO,
|
logLevel: config.LOG_INFO,
|
||||||
autoWatch: true,
|
autoWatch: true,
|
||||||
coverageReporter: {
|
|
||||||
dir: process.env.CIRCLE_ARTIFACTS ?
|
|
||||||
process.env.CIRCLE_ARTIFACTS + '/coverage' :
|
|
||||||
"dist/reports/coverage",
|
|
||||||
check: {
|
|
||||||
global: {
|
|
||||||
lines: 80,
|
|
||||||
excludes: ['src/plugins/plot/**/*.js']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// HTML test reporting.
|
// HTML test reporting.
|
||||||
htmlReporter: {
|
htmlReporter: {
|
||||||
outputDir: "dist/reports/tests",
|
outputDir: "dist/reports/tests",
|
||||||
preserveDescribeNesting: true,
|
preserveDescribeNesting: true,
|
||||||
foldAll: false
|
foldAll: false
|
||||||
},
|
},
|
||||||
|
coverageIstanbulReporter: {
|
||||||
|
fixWebpackSourcePaths: true,
|
||||||
|
dir: process.env.CIRCLE_ARTIFACTS ?
|
||||||
|
process.env.CIRCLE_ARTIFACTS + '/coverage' :
|
||||||
|
"dist/reports/coverage",
|
||||||
|
reports: ['html', 'lcovonly', 'text-summary'],
|
||||||
|
thresholds: {
|
||||||
|
global: {
|
||||||
|
lines: 62
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
preprocessors: {
|
preprocessors: {
|
||||||
// add webpack as preprocessor
|
'platform/**/*Spec.js': ['webpack', 'sourcemap'],
|
||||||
'platform/**/*Spec.js': [ 'webpack', 'sourcemap' ],
|
'src/**/*Spec.js': ['webpack', 'sourcemap']
|
||||||
'src/**/*Spec.js': [ 'webpack', 'sourcemap' ]
|
|
||||||
},
|
},
|
||||||
webpack: webpackConfig,
|
webpack: webpackConfig,
|
||||||
webpackMiddleware: {
|
webpackMiddleware: {
|
||||||
|
19
package.json
19
package.json
@ -4,8 +4,7 @@
|
|||||||
"description": "The Open MCT core platform",
|
"description": "The Open MCT core platform",
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"acorn": "6.2.0",
|
"angular": "1.7.9",
|
||||||
"angular": "1.4.14",
|
|
||||||
"angular-route": "1.4.14",
|
"angular-route": "1.4.14",
|
||||||
"babel-eslint": "8.2.6",
|
"babel-eslint": "8.2.6",
|
||||||
"comma-separated-values": "^3.6.4",
|
"comma-separated-values": "^3.6.4",
|
||||||
@ -25,6 +24,7 @@
|
|||||||
"d3-time-format": "2.1.x",
|
"d3-time-format": "2.1.x",
|
||||||
"eslint": "5.2.0",
|
"eslint": "5.2.0",
|
||||||
"eslint-plugin-vue": "^6.0.0",
|
"eslint-plugin-vue": "^6.0.0",
|
||||||
|
"eslint-plugin-you-dont-need-lodash-underscore": "^6.10.0",
|
||||||
"eventemitter3": "^1.2.0",
|
"eventemitter3": "^1.2.0",
|
||||||
"exports-loader": "^0.7.0",
|
"exports-loader": "^0.7.0",
|
||||||
"express": "^4.13.1",
|
"express": "^4.13.1",
|
||||||
@ -43,19 +43,20 @@
|
|||||||
"karma-chrome-launcher": "^2.2.0",
|
"karma-chrome-launcher": "^2.2.0",
|
||||||
"karma-cli": "^1.0.1",
|
"karma-cli": "^1.0.1",
|
||||||
"karma-coverage": "^1.1.2",
|
"karma-coverage": "^1.1.2",
|
||||||
|
"karma-coverage-istanbul-reporter": "^2.1.1",
|
||||||
"karma-html-reporter": "^0.2.7",
|
"karma-html-reporter": "^0.2.7",
|
||||||
"karma-jasmine": "^1.1.2",
|
"karma-jasmine": "^1.1.2",
|
||||||
"karma-sourcemap-loader": "^0.3.7",
|
"karma-sourcemap-loader": "^0.3.7",
|
||||||
"karma-webpack": "^3.0.0",
|
"karma-webpack": "^3.0.0",
|
||||||
"location-bar": "^3.0.1",
|
"location-bar": "^3.0.1",
|
||||||
"lodash": "^3.10.1",
|
"lodash": "^4.17.12",
|
||||||
"markdown-toc": "^0.11.7",
|
"markdown-toc": "^0.11.7",
|
||||||
"marked": "^0.3.5",
|
"marked": "^0.3.5",
|
||||||
"mini-css-extract-plugin": "^0.4.1",
|
"mini-css-extract-plugin": "^0.4.1",
|
||||||
"minimist": "^1.1.1",
|
"minimist": "^1.1.1",
|
||||||
"moment": "^2.11.1",
|
"moment": "2.25.3",
|
||||||
"moment-duration-format": "^2.2.2",
|
"moment-duration-format": "^2.2.2",
|
||||||
"moment-timezone": "^0.5.21",
|
"moment-timezone": "0.5.28",
|
||||||
"node-bourbon": "^4.2.3",
|
"node-bourbon": "^4.2.3",
|
||||||
"node-sass": "^4.9.2",
|
"node-sass": "^4.9.2",
|
||||||
"painterro": "^0.2.65",
|
"painterro": "^0.2.65",
|
||||||
@ -76,14 +77,16 @@
|
|||||||
"zepto": "^1.2.0"
|
"zepto": "^1.2.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"clean": "rm -rf ./dist",
|
||||||
"start": "node app.js",
|
"start": "node app.js",
|
||||||
"lint": "eslint platform example src/**/*.{js,vue} openmct.js",
|
"lint": "eslint platform example src --ext .js,.vue openmct.js",
|
||||||
"lint:fix": "eslint platform example src/**/*.{js,vue} openmct.js --fix",
|
"lint:fix": "eslint platform example src --ext .js,.vue openmct.js --fix",
|
||||||
"build:prod": "cross-env NODE_ENV=production webpack",
|
"build:prod": "cross-env NODE_ENV=production webpack",
|
||||||
"build:dev": "webpack",
|
"build:dev": "webpack",
|
||||||
"build:watch": "webpack --watch",
|
"build:watch": "webpack --watch",
|
||||||
"test": "karma start --single-run",
|
"test": "karma start --single-run",
|
||||||
"test-debug": "cross-env NODE_ENV=debug karma start --no-single-run",
|
"test:debug": "cross-env NODE_ENV=debug karma start --no-single-run",
|
||||||
|
"test:coverage": "./scripts/test-coverage.sh",
|
||||||
"test:watch": "karma start --no-single-run",
|
"test:watch": "karma start --no-single-run",
|
||||||
"verify": "concurrently 'npm:test' 'npm:lint'",
|
"verify": "concurrently 'npm:test' 'npm:lint'",
|
||||||
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",
|
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",
|
||||||
|
@ -6,6 +6,12 @@
|
|||||||
ng-show="ngModel.dialog.messages.length > 1 ||
|
ng-show="ngModel.dialog.messages.length > 1 ||
|
||||||
ngModel.dialog.messages.length == 0">s</span>
|
ngModel.dialog.messages.length == 0">s</span>
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
ng-if="ngModel.dialog.topBarButton"
|
||||||
|
class="c-button c-button--major"
|
||||||
|
ng-click="ngModel.topBarButton.onClick">
|
||||||
|
{{ ngModel.topBarButton.label }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-messages c-overlay__messages">
|
<div class="w-messages c-overlay__messages">
|
||||||
<mct-include
|
<mct-include
|
||||||
@ -16,7 +22,7 @@
|
|||||||
<button ng-repeat="dialogAction in ngModel.dialog.actions"
|
<button ng-repeat="dialogAction in ngModel.dialog.actions"
|
||||||
class="c-button c-button--major"
|
class="c-button c-button--major"
|
||||||
ng-click="dialogAction.action()">
|
ng-click="dialogAction.action()">
|
||||||
{{dialogAction.label}}
|
{{ dialogAction.label }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define(
|
define(
|
||||||
['../../../../../src/api/objects/object-utils'],
|
['objectUtils'],
|
||||||
function (objectUtils) {
|
function (objectUtils) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,44 +21,15 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
"./src/NotificationIndicatorController",
|
"./src/NotificationService"
|
||||||
"./src/NotificationIndicator",
|
|
||||||
"./src/NotificationService",
|
|
||||||
"./res/notification-indicator.html"
|
|
||||||
], function (
|
], function (
|
||||||
NotificationIndicatorController,
|
NotificationService
|
||||||
NotificationIndicator,
|
|
||||||
NotificationService,
|
|
||||||
notificationIndicatorTemplate
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name:"platform/commonUI/notification",
|
name:"platform/commonUI/notification",
|
||||||
definition: {
|
definition: {
|
||||||
"extensions": {
|
"extensions": {
|
||||||
"templates": [
|
|
||||||
{
|
|
||||||
"key": "notificationIndicatorTemplate",
|
|
||||||
"template": notificationIndicatorTemplate
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"controllers": [
|
|
||||||
{
|
|
||||||
"key": "NotificationIndicatorController",
|
|
||||||
"implementation": NotificationIndicatorController,
|
|
||||||
"depends": [
|
|
||||||
"$scope",
|
|
||||||
"openmct",
|
|
||||||
"dialogService"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"indicators": [
|
|
||||||
{
|
|
||||||
"implementation": NotificationIndicator,
|
|
||||||
"priority": "fallback"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"services": [
|
"services": [
|
||||||
{
|
{
|
||||||
"key": "notificationService",
|
"key": "notificationService",
|
||||||
|
@ -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
|
* @namespace platform/containment
|
||||||
*/
|
*/
|
||||||
define(
|
define(
|
||||||
['../../../src/api/objects/object-utils'],
|
['objectUtils'],
|
||||||
function (objectUtils) {
|
function (objectUtils) {
|
||||||
|
|
||||||
function PersistableCompositionPolicy(openmct) {
|
function PersistableCompositionPolicy(openmct) {
|
||||||
|
@ -81,7 +81,7 @@ define(
|
|||||||
baseContext = context || {};
|
baseContext = context || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
var actionContext = _.extend({}, baseContext);
|
var actionContext = Object.assign({}, baseContext);
|
||||||
actionContext.domainObject = this.domainObject;
|
actionContext.domainObject = this.domainObject;
|
||||||
|
|
||||||
return this.actionService.getActions(actionContext);
|
return this.actionService.getActions(actionContext);
|
||||||
|
@ -87,6 +87,11 @@ define([
|
|||||||
bootstrapper
|
bootstrapper
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Override of angular1.6 ! hashPrefix
|
||||||
|
app.config(['$locationProvider', function ($locationProvider) {
|
||||||
|
$locationProvider.hashPrefix('');
|
||||||
|
}]);
|
||||||
|
|
||||||
// Apply logging levels; this must be done now, before the
|
// Apply logging levels; this must be done now, before the
|
||||||
// first log statement.
|
// first log statement.
|
||||||
new LogLevel(logLevel).configure(app, $log);
|
new LogLevel(logLevel).configure(app, $log);
|
||||||
|
@ -121,7 +121,7 @@ define(['lodash'], function (_) {
|
|||||||
*/
|
*/
|
||||||
ExportAsJSONAction.prototype.rewriteLink = function (child, parent) {
|
ExportAsJSONAction.prototype.rewriteLink = function (child, parent) {
|
||||||
this.externalIdentifiers.push(this.getId(child));
|
this.externalIdentifiers.push(this.getId(child));
|
||||||
var index = _.findIndex(parent.composition, function (id) {
|
var index = parent.composition.findIndex(id => {
|
||||||
return _.isEqual(child.identifier, id);
|
return _.isEqual(child.identifier, id);
|
||||||
});
|
});
|
||||||
var copyOfChild = this.copyObject(child);
|
var copyOfChild = this.copyObject(child);
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
define(['zepto', '../../../../src/api/objects/object-utils.js'], function ($, objectUtils) {
|
define(['zepto', 'objectUtils'], function ($, objectUtils) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ImportAsJSONAction is available from context menus and allows a user
|
* The ImportAsJSONAction is available from context menus and allows a user
|
||||||
|
@ -71,7 +71,7 @@ define([
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "ELASTIC_PATH",
|
"key": "ELASTIC_PATH",
|
||||||
"value": "mct/domain_object",
|
"value": "mct/_doc",
|
||||||
"priority": "fallback"
|
"priority": "fallback"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -32,9 +32,9 @@ define(
|
|||||||
// JSLint doesn't like underscore-prefixed properties,
|
// JSLint doesn't like underscore-prefixed properties,
|
||||||
// so hide them here.
|
// so hide them here.
|
||||||
var SRC = "_source",
|
var SRC = "_source",
|
||||||
REV = "_version",
|
CONFLICT = 409,
|
||||||
ID = "_id",
|
SEQ_NO = "_seq_no",
|
||||||
CONFLICT = 409;
|
PRIMARY_TERM = "_primary_term";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ElasticPersistenceProvider reads and writes JSON documents
|
* The ElasticPersistenceProvider reads and writes JSON documents
|
||||||
@ -104,7 +104,8 @@ define(
|
|||||||
// Get a domain object model out of ElasticSearch's response
|
// Get a domain object model out of ElasticSearch's response
|
||||||
ElasticPersistenceProvider.prototype.getModel = function (response) {
|
ElasticPersistenceProvider.prototype.getModel = function (response) {
|
||||||
if (response && response[SRC]) {
|
if (response && response[SRC]) {
|
||||||
this.revs[response[ID]] = response[REV];
|
this.revs[response[SEQ_NO]] = response[SEQ_NO];
|
||||||
|
this.revs[response[PRIMARY_TERM]] = response[PRIMARY_TERM];
|
||||||
return response[SRC];
|
return response[SRC];
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -116,7 +117,8 @@ define(
|
|||||||
// indicate that the request failed.
|
// indicate that the request failed.
|
||||||
ElasticPersistenceProvider.prototype.checkResponse = function (response, key) {
|
ElasticPersistenceProvider.prototype.checkResponse = function (response, key) {
|
||||||
if (response && !response.error) {
|
if (response && !response.error) {
|
||||||
this.revs[key] = response[REV];
|
this.revs[SEQ_NO] = response[SEQ_NO];
|
||||||
|
this.revs[PRIMARY_TERM] = response[PRIMARY_TERM];
|
||||||
return response;
|
return response;
|
||||||
} else {
|
} else {
|
||||||
return this.handleError(response, key);
|
return this.handleError(response, key);
|
||||||
@ -147,7 +149,7 @@ define(
|
|||||||
function checkUpdate(response) {
|
function checkUpdate(response) {
|
||||||
return self.checkResponse(response, key);
|
return self.checkResponse(response, key);
|
||||||
}
|
}
|
||||||
return this.put(key, value, { version: this.revs[key] })
|
return this.put(key, value)
|
||||||
.then(checkUpdate);
|
.then(checkUpdate);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ define(
|
|||||||
it("allows object creation", function () {
|
it("allows object creation", function () {
|
||||||
var model = { someKey: "some value" };
|
var model = { someKey: "some value" };
|
||||||
mockHttp.and.returnValue(mockPromise({
|
mockHttp.and.returnValue(mockPromise({
|
||||||
data: { "_id": "abc", "_version": 1 }
|
data: { "_id": "abc", "_seq_no": 1, "_primary_term": 1 }
|
||||||
}));
|
}));
|
||||||
provider.createObject("testSpace", "abc", model).then(capture);
|
provider.createObject("testSpace", "abc", model).then(capture);
|
||||||
expect(mockHttp).toHaveBeenCalledWith({
|
expect(mockHttp).toHaveBeenCalledWith({
|
||||||
@ -100,7 +100,7 @@ define(
|
|||||||
it("allows object models to be read back", function () {
|
it("allows object models to be read back", function () {
|
||||||
var model = { someKey: "some value" };
|
var model = { someKey: "some value" };
|
||||||
mockHttp.and.returnValue(mockPromise({
|
mockHttp.and.returnValue(mockPromise({
|
||||||
data: { "_id": "abc", "_version": 1, "_source": model }
|
data: { "_id": "abc", "_seq_no": 1, "_primary_term": 1, "_source": model }
|
||||||
}));
|
}));
|
||||||
provider.readObject("testSpace", "abc").then(capture);
|
provider.readObject("testSpace", "abc").then(capture);
|
||||||
expect(mockHttp).toHaveBeenCalledWith({
|
expect(mockHttp).toHaveBeenCalledWith({
|
||||||
@ -117,19 +117,19 @@ define(
|
|||||||
|
|
||||||
// First do a read to populate rev tags...
|
// First do a read to populate rev tags...
|
||||||
mockHttp.and.returnValue(mockPromise({
|
mockHttp.and.returnValue(mockPromise({
|
||||||
data: { "_id": "abc", "_version": 42, "_source": {} }
|
data: { "_id": "abc", "_source": {} }
|
||||||
}));
|
}));
|
||||||
provider.readObject("testSpace", "abc");
|
provider.readObject("testSpace", "abc");
|
||||||
|
|
||||||
// Now perform an update
|
// Now perform an update
|
||||||
mockHttp.and.returnValue(mockPromise({
|
mockHttp.and.returnValue(mockPromise({
|
||||||
data: { "_id": "abc", "_version": 43, "_source": {} }
|
data: { "_id": "abc", "_seq_no": 1, "_source": {} }
|
||||||
}));
|
}));
|
||||||
provider.updateObject("testSpace", "abc", model).then(capture);
|
provider.updateObject("testSpace", "abc", model).then(capture);
|
||||||
expect(mockHttp).toHaveBeenCalledWith({
|
expect(mockHttp).toHaveBeenCalledWith({
|
||||||
url: "/test/db/abc",
|
url: "/test/db/abc",
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
params: { version: 42 },
|
params: undefined,
|
||||||
data: model
|
data: model
|
||||||
});
|
});
|
||||||
expect(capture.calls.mostRecent().args[0]).toBeTruthy();
|
expect(capture.calls.mostRecent().args[0]).toBeTruthy();
|
||||||
@ -138,13 +138,13 @@ define(
|
|||||||
it("allows object deletion", function () {
|
it("allows object deletion", function () {
|
||||||
// First do a read to populate rev tags...
|
// First do a read to populate rev tags...
|
||||||
mockHttp.and.returnValue(mockPromise({
|
mockHttp.and.returnValue(mockPromise({
|
||||||
data: { "_id": "abc", "_version": 42, "_source": {} }
|
data: { "_id": "abc", "_source": {} }
|
||||||
}));
|
}));
|
||||||
provider.readObject("testSpace", "abc");
|
provider.readObject("testSpace", "abc");
|
||||||
|
|
||||||
// Now perform an update
|
// Now perform an update
|
||||||
mockHttp.and.returnValue(mockPromise({
|
mockHttp.and.returnValue(mockPromise({
|
||||||
data: { "_id": "abc", "_version": 42, "_source": {} }
|
data: { "_id": "abc", "_source": {} }
|
||||||
}));
|
}));
|
||||||
provider.deleteObject("testSpace", "abc", {}).then(capture);
|
provider.deleteObject("testSpace", "abc", {}).then(capture);
|
||||||
expect(mockHttp).toHaveBeenCalledWith({
|
expect(mockHttp).toHaveBeenCalledWith({
|
||||||
@ -167,13 +167,13 @@ define(
|
|||||||
expect(capture).toHaveBeenCalledWith(undefined);
|
expect(capture).toHaveBeenCalledWith(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("handles rejection due to version", function () {
|
it("handles rejection due to _seq_no", function () {
|
||||||
var model = { someKey: "some value" },
|
var model = { someKey: "some value" },
|
||||||
mockErrorCallback = jasmine.createSpy('error');
|
mockErrorCallback = jasmine.createSpy('error');
|
||||||
|
|
||||||
// First do a read to populate rev tags...
|
// First do a read to populate rev tags...
|
||||||
mockHttp.and.returnValue(mockPromise({
|
mockHttp.and.returnValue(mockPromise({
|
||||||
data: { "_id": "abc", "_version": 42, "_source": {} }
|
data: { "_id": "abc", "_seq_no": 1, "_source": {} }
|
||||||
}));
|
}));
|
||||||
provider.readObject("testSpace", "abc");
|
provider.readObject("testSpace", "abc");
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ define(
|
|||||||
|
|
||||||
// First do a read to populate rev tags...
|
// First do a read to populate rev tags...
|
||||||
mockHttp.and.returnValue(mockPromise({
|
mockHttp.and.returnValue(mockPromise({
|
||||||
data: { "_id": "abc", "_version": 42, "_source": {} }
|
data: { "_id": "abc", "_seq_no": 1, "_source": {} }
|
||||||
}));
|
}));
|
||||||
provider.readObject("testSpace", "abc");
|
provider.readObject("testSpace", "abc");
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
* Module defining GenericSearchProvider. Created by shale on 07/16/2015.
|
* Module defining GenericSearchProvider. Created by shale on 07/16/2015.
|
||||||
*/
|
*/
|
||||||
define([
|
define([
|
||||||
'../../../../src/api/objects/object-utils',
|
'objectUtils',
|
||||||
'lodash'
|
'lodash'
|
||||||
], function (
|
], function (
|
||||||
objectUtils,
|
objectUtils,
|
||||||
@ -191,7 +191,7 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
var domainObject = objectUtils.toNewFormat(model, id);
|
var domainObject = objectUtils.toNewFormat(model, id);
|
||||||
var composition = _.find(this.openmct.composition.registry, function (p) {
|
var composition = this.openmct.composition.registry.find(p => {
|
||||||
return p.appliesTo(domainObject);
|
return p.appliesTo(domainObject);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
'../../../src/api/objects/object-utils',
|
'objectUtils',
|
||||||
'lodash'
|
'lodash'
|
||||||
],
|
],
|
||||||
function (
|
function (
|
||||||
@ -235,7 +235,7 @@ define(
|
|||||||
var defaultRange = metadata.valuesForHints(['range'])[0];
|
var defaultRange = metadata.valuesForHints(['range'])[0];
|
||||||
defaultRange = defaultRange ? defaultRange.key : undefined;
|
defaultRange = defaultRange ? defaultRange.key : undefined;
|
||||||
|
|
||||||
var sourceMap = _.indexBy(metadata.values(), 'key');
|
var sourceMap = _.keyBy(metadata.values(), 'key');
|
||||||
|
|
||||||
var isLegacyProvider = telemetryAPI.findRequestProvider(domainObject) ===
|
var isLegacyProvider = telemetryAPI.findRequestProvider(domainObject) ===
|
||||||
telemetryAPI.legacyProvider;
|
telemetryAPI.legacyProvider;
|
||||||
@ -300,7 +300,7 @@ define(
|
|||||||
var defaultRange = metadata.valuesForHints(['range'])[0];
|
var defaultRange = metadata.valuesForHints(['range'])[0];
|
||||||
defaultRange = defaultRange ? defaultRange.key : undefined;
|
defaultRange = defaultRange ? defaultRange.key : undefined;
|
||||||
|
|
||||||
var sourceMap = _.indexBy(metadata.values(), 'key');
|
var sourceMap = _.keyBy(metadata.values(), 'key');
|
||||||
|
|
||||||
var isLegacyProvider = telemetryAPI.findSubscriptionProvider(domainObject) ===
|
var isLegacyProvider = telemetryAPI.findSubscriptionProvider(domainObject) ===
|
||||||
telemetryAPI.legacyProvider;
|
telemetryAPI.legacyProvider;
|
||||||
|
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"
|
||||||
|
]
|
||||||
|
}
|
2
scripts/test-coverage.sh
Executable file
2
scripts/test-coverage.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
export NODE_OPTIONS=--max_old_space_size=4096
|
||||||
|
cross-env COVERAGE=true karma start --single-run
|
20
src/MCT.js
20
src/MCT.js
@ -28,7 +28,7 @@ define([
|
|||||||
'./api/api',
|
'./api/api',
|
||||||
'./api/overlays/OverlayAPI',
|
'./api/overlays/OverlayAPI',
|
||||||
'./selection/Selection',
|
'./selection/Selection',
|
||||||
'./api/objects/object-utils',
|
'objectUtils',
|
||||||
'./plugins/plugins',
|
'./plugins/plugins',
|
||||||
'./adapter/indicators/legacy-indicators-plugin',
|
'./adapter/indicators/legacy-indicators-plugin',
|
||||||
'./plugins/buildInfo/plugin',
|
'./plugins/buildInfo/plugin',
|
||||||
@ -240,7 +240,7 @@ define([
|
|||||||
|
|
||||||
this.overlays = new OverlayAPI.default();
|
this.overlays = new OverlayAPI.default();
|
||||||
|
|
||||||
this.contextMenu = new api.ContextMenuRegistry();
|
this.menus = new api.MenuAPI(this);
|
||||||
|
|
||||||
this.router = new ApplicationRouter();
|
this.router = new ApplicationRouter();
|
||||||
|
|
||||||
@ -249,7 +249,7 @@ define([
|
|||||||
this.legacyRegistry = new BundleRegistry();
|
this.legacyRegistry = new BundleRegistry();
|
||||||
installDefaultBundles(this.legacyRegistry);
|
installDefaultBundles(this.legacyRegistry);
|
||||||
|
|
||||||
// Plugin's that are installed by default
|
// Plugins that are installed by default
|
||||||
|
|
||||||
this.install(this.plugins.Plot());
|
this.install(this.plugins.Plot());
|
||||||
this.install(this.plugins.TelemetryTable());
|
this.install(this.plugins.TelemetryTable());
|
||||||
@ -266,6 +266,7 @@ define([
|
|||||||
this.install(this.plugins.WebPage());
|
this.install(this.plugins.WebPage());
|
||||||
this.install(this.plugins.Condition());
|
this.install(this.plugins.Condition());
|
||||||
this.install(this.plugins.ConditionWidget());
|
this.install(this.plugins.ConditionWidget());
|
||||||
|
this.install(this.plugins.NotificationIndicator());
|
||||||
}
|
}
|
||||||
|
|
||||||
MCT.prototype = Object.create(EventEmitter.prototype);
|
MCT.prototype = Object.create(EventEmitter.prototype);
|
||||||
@ -350,17 +351,13 @@ define([
|
|||||||
* @param {HTMLElement} [domElement] the DOM element in which to run
|
* @param {HTMLElement} [domElement] the DOM element in which to run
|
||||||
* MCT; if undefined, MCT will be run in the body of the document
|
* MCT; if undefined, MCT will be run in the body of the document
|
||||||
*/
|
*/
|
||||||
MCT.prototype.start = function (domElement) {
|
MCT.prototype.start = function (domElement = document.body, isHeadlessMode = false) {
|
||||||
if (!this.plugins.DisplayLayout._installed) {
|
if (!this.plugins.DisplayLayout._installed) {
|
||||||
this.install(this.plugins.DisplayLayout({
|
this.install(this.plugins.DisplayLayout({
|
||||||
showAsView: ['summary-widget']
|
showAsView: ['summary-widget']
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!domElement) {
|
|
||||||
domElement = document.body;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.element = domElement;
|
this.element = domElement;
|
||||||
|
|
||||||
this.legacyExtension('runs', {
|
this.legacyExtension('runs', {
|
||||||
@ -400,6 +397,7 @@ define([
|
|||||||
// something has depended upon objectService. Cool, right?
|
// something has depended upon objectService. Cool, right?
|
||||||
this.$injector.get('objectService');
|
this.$injector.get('objectService');
|
||||||
|
|
||||||
|
if (!isHeadlessMode) {
|
||||||
var appLayout = new Vue({
|
var appLayout = new Vue({
|
||||||
components: {
|
components: {
|
||||||
'Layout': Layout.default
|
'Layout': Layout.default
|
||||||
@ -413,11 +411,17 @@ define([
|
|||||||
|
|
||||||
this.layout = appLayout.$refs.layout;
|
this.layout = appLayout.$refs.layout;
|
||||||
Browse(this);
|
Browse(this);
|
||||||
|
}
|
||||||
this.router.start();
|
this.router.start();
|
||||||
this.emit('start');
|
this.emit('start');
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MCT.prototype.startHeadless = function () {
|
||||||
|
let unreachableNode = document.createElement('div');
|
||||||
|
return this.start(unreachableNode, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Install a plugin in MCT.
|
* Install a plugin in MCT.
|
||||||
*
|
*
|
||||||
|
@ -21,11 +21,11 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'./MCT',
|
|
||||||
'./plugins/plugins',
|
'./plugins/plugins',
|
||||||
'legacyRegistry'
|
'legacyRegistry',
|
||||||
], function (MCT, plugins, legacyRegistry) {
|
'testUtils'
|
||||||
xdescribe("MCT", function () {
|
], function (plugins, legacyRegistry, testUtils) {
|
||||||
|
describe("MCT", function () {
|
||||||
var openmct;
|
var openmct;
|
||||||
var mockPlugin;
|
var mockPlugin;
|
||||||
var mockPlugin2;
|
var mockPlugin2;
|
||||||
@ -38,7 +38,7 @@ define([
|
|||||||
mockListener = jasmine.createSpy('listener');
|
mockListener = jasmine.createSpy('listener');
|
||||||
oldBundles = legacyRegistry.list();
|
oldBundles = legacyRegistry.list();
|
||||||
|
|
||||||
openmct = new MCT();
|
openmct = testUtils.createOpenMct();
|
||||||
|
|
||||||
openmct.install(mockPlugin);
|
openmct.install(mockPlugin);
|
||||||
openmct.install(mockPlugin2);
|
openmct.install(mockPlugin2);
|
||||||
@ -63,8 +63,11 @@ define([
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("start", function () {
|
describe("start", function () {
|
||||||
beforeEach(function () {
|
let appHolder;
|
||||||
openmct.start();
|
beforeEach(function (done) {
|
||||||
|
appHolder = document.createElement("div");
|
||||||
|
openmct.on('start', done);
|
||||||
|
openmct.start(appHolder);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("calls plugins for configuration", function () {
|
it("calls plugins for configuration", function () {
|
||||||
@ -75,25 +78,51 @@ define([
|
|||||||
it("emits a start event", function () {
|
it("emits a start event", function () {
|
||||||
expect(mockListener).toHaveBeenCalled();
|
expect(mockListener).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Renders the application into the provided container element", function () {
|
||||||
|
let openMctShellElements = appHolder.querySelectorAll('div.l-shell');
|
||||||
|
expect(openMctShellElements.length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("startHeadless", function () {
|
||||||
|
beforeEach(function (done) {
|
||||||
|
openmct.on('start', done);
|
||||||
|
openmct.startHeadless();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls plugins for configuration", function () {
|
||||||
|
expect(mockPlugin).toHaveBeenCalledWith(openmct);
|
||||||
|
expect(mockPlugin2).toHaveBeenCalledWith(openmct);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("emits a start event", function () {
|
||||||
|
expect(mockListener).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Does not render Open MCT", function () {
|
||||||
|
let openMctShellElements = document.body.querySelectorAll('div.l-shell');
|
||||||
|
expect(openMctShellElements.length).toBe(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("setAssetPath", function () {
|
describe("setAssetPath", function () {
|
||||||
var testAssetPath;
|
var testAssetPath;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
testAssetPath = "some/path";
|
|
||||||
openmct.legacyExtension = jasmine.createSpy('legacyExtension');
|
openmct.legacyExtension = jasmine.createSpy('legacyExtension');
|
||||||
openmct.setAssetPath(testAssetPath);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("internally configures the path for assets", function () {
|
it("configures the path for assets", function () {
|
||||||
expect(openmct.legacyExtension).toHaveBeenCalledWith(
|
testAssetPath = "some/path/";
|
||||||
'constants',
|
openmct.setAssetPath(testAssetPath);
|
||||||
{
|
expect(openmct.getAssetPath()).toBe(testAssetPath);
|
||||||
key: "ASSETS_PATH",
|
});
|
||||||
value: testAssetPath
|
|
||||||
}
|
it("adds a trailing /", function () {
|
||||||
);
|
testAssetPath = "some/path";
|
||||||
|
openmct.setAssetPath(testAssetPath);
|
||||||
|
expect(openmct.getAssetPath()).toBe(testAssetPath + "/");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'../../api/objects/object-utils'
|
'objectUtils'
|
||||||
], function (objectUtils) {
|
], function (objectUtils) {
|
||||||
function ActionDialogDecorator(mct, actionService) {
|
function ActionDialogDecorator(mct, actionService) {
|
||||||
this.mct = mct;
|
this.mct = mct;
|
||||||
|
@ -33,5 +33,5 @@ export default function LegacyActionAdapter(openmct, legacyActions) {
|
|||||||
|
|
||||||
legacyActions.filter(contextualCategoryOnly)
|
legacyActions.filter(contextualCategoryOnly)
|
||||||
.map(LegacyAction => new LegacyContextMenuAction(openmct, LegacyAction))
|
.map(LegacyAction => new LegacyContextMenuAction(openmct, LegacyAction))
|
||||||
.forEach(openmct.contextMenu.registerAction);
|
.forEach(openmct.menus.registerObjectAction);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define(['../../api/objects/object-utils'], function (objectUtils) {
|
define(['objectUtils'], function (objectUtils) {
|
||||||
function AdapterCapability(domainObject) {
|
function AdapterCapability(domainObject) {
|
||||||
this.domainObject = domainObject;
|
this.domainObject = domainObject;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
* Module defining AlternateCompositionCapability. Created by vwoeltje on 11/7/14.
|
* Module defining AlternateCompositionCapability. Created by vwoeltje on 11/7/14.
|
||||||
*/
|
*/
|
||||||
define([
|
define([
|
||||||
'../../api/objects/object-utils',
|
'objectUtils',
|
||||||
'../../../platform/core/src/capabilities/ContextualDomainObject'
|
'../../../platform/core/src/capabilities/ContextualDomainObject'
|
||||||
], function (objectUtils, ContextualDomainObject) {
|
], function (objectUtils, ContextualDomainObject) {
|
||||||
function AlternateCompositionCapability($injector, domainObject) {
|
function AlternateCompositionCapability($injector, domainObject) {
|
||||||
|
@ -31,6 +31,7 @@ define([
|
|||||||
var capability = viewConstructor(domainObject);
|
var capability = viewConstructor(domainObject);
|
||||||
var oldInvoke = capability.invoke.bind(capability);
|
var oldInvoke = capability.invoke.bind(capability);
|
||||||
|
|
||||||
|
/* eslint-disable you-dont-need-lodash-underscore/map */
|
||||||
capability.invoke = function () {
|
capability.invoke = function () {
|
||||||
var availableViews = oldInvoke();
|
var availableViews = oldInvoke();
|
||||||
var newDomainObject = capability
|
var newDomainObject = capability
|
||||||
@ -52,6 +53,8 @@ define([
|
|||||||
.map('view')
|
.map('view')
|
||||||
.value();
|
.value();
|
||||||
};
|
};
|
||||||
|
/* eslint-enable you-dont-need-lodash-underscore/map */
|
||||||
|
|
||||||
return capability;
|
return capability;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
define([
|
define([
|
||||||
'../capabilities/AlternateCompositionCapability',
|
'../capabilities/AlternateCompositionCapability',
|
||||||
'../../api/objects/object-utils'
|
'objectUtils'
|
||||||
], function (
|
], function (
|
||||||
AlternateCompositionCapability,
|
AlternateCompositionCapability,
|
||||||
objectUtils
|
objectUtils
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'../../api/objects/object-utils'
|
'objectUtils'
|
||||||
], function (
|
], function (
|
||||||
utils
|
utils
|
||||||
) {
|
) {
|
||||||
|
@ -78,7 +78,7 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
TimeSettingsURLHandler.prototype.parseQueryParams = function () {
|
TimeSettingsURLHandler.prototype.parseQueryParams = function () {
|
||||||
var searchParams = _.pick(this.$location.search(), _.values(SEARCH));
|
var searchParams = _.pick(this.$location.search(), Object.values(SEARCH));
|
||||||
var parsedParams = {
|
var parsedParams = {
|
||||||
clock: searchParams[SEARCH.MODE],
|
clock: searchParams[SEARCH.MODE],
|
||||||
timeSystem: searchParams[SEARCH.TIME_SYSTEM]
|
timeSystem: searchParams[SEARCH.TIME_SYSTEM]
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'../../api/objects/object-utils'
|
'objectUtils'
|
||||||
], function (
|
], function (
|
||||||
utils
|
utils
|
||||||
) {
|
) {
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'../../api/objects/object-utils'
|
'objectUtils'
|
||||||
], function (
|
], function (
|
||||||
objectUtils
|
objectUtils
|
||||||
) {
|
) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
define([
|
define([
|
||||||
'./LegacyViewProvider',
|
'./LegacyViewProvider',
|
||||||
'./TypeInspectorViewProvider',
|
'./TypeInspectorViewProvider',
|
||||||
'../../api/objects/object-utils'
|
'objectUtils'
|
||||||
], function (
|
], function (
|
||||||
LegacyViewProvider,
|
LegacyViewProvider,
|
||||||
TypeInspectorViewProvider,
|
TypeInspectorViewProvider,
|
||||||
|
@ -28,8 +28,8 @@ define([
|
|||||||
'./telemetry/TelemetryAPI',
|
'./telemetry/TelemetryAPI',
|
||||||
'./indicators/IndicatorAPI',
|
'./indicators/IndicatorAPI',
|
||||||
'./notifications/NotificationAPI',
|
'./notifications/NotificationAPI',
|
||||||
'./contextMenu/ContextMenuAPI',
|
'./Editor',
|
||||||
'./Editor'
|
'./menu/MenuAPI'
|
||||||
|
|
||||||
], function (
|
], function (
|
||||||
TimeAPI,
|
TimeAPI,
|
||||||
@ -39,8 +39,8 @@ define([
|
|||||||
TelemetryAPI,
|
TelemetryAPI,
|
||||||
IndicatorAPI,
|
IndicatorAPI,
|
||||||
NotificationAPI,
|
NotificationAPI,
|
||||||
ContextMenuAPI,
|
EditorAPI,
|
||||||
EditorAPI
|
MenuAPI
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
TimeAPI: TimeAPI,
|
TimeAPI: TimeAPI,
|
||||||
@ -51,6 +51,6 @@ define([
|
|||||||
IndicatorAPI: IndicatorAPI,
|
IndicatorAPI: IndicatorAPI,
|
||||||
NotificationAPI: NotificationAPI.default,
|
NotificationAPI: NotificationAPI.default,
|
||||||
EditorAPI: EditorAPI,
|
EditorAPI: EditorAPI,
|
||||||
ContextMenuRegistry: ContextMenuAPI.default
|
MenuAPI: MenuAPI.default
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -70,7 +70,7 @@ define([
|
|||||||
* @memberof module:openmct.CompositionAPI#
|
* @memberof module:openmct.CompositionAPI#
|
||||||
*/
|
*/
|
||||||
CompositionAPI.prototype.get = function (domainObject) {
|
CompositionAPI.prototype.get = function (domainObject) {
|
||||||
var provider = _.find(this.registry, function (p) {
|
var provider = this.registry.find(p => {
|
||||||
return p.appliesTo(domainObject);
|
return p.appliesTo(domainObject);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ define([
|
|||||||
throw new Error('Event not supported by composition: ' + event);
|
throw new Error('Event not supported by composition: ' + event);
|
||||||
}
|
}
|
||||||
|
|
||||||
var index = _.findIndex(this.listeners[event], function (l) {
|
var index = this.listeners[event].findIndex(l => {
|
||||||
return l.callback === callback && l.context === context;
|
return l.callback === callback && l.context === context;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
define([
|
define([
|
||||||
'lodash',
|
'lodash',
|
||||||
'../objects/object-utils'
|
'objectUtils'
|
||||||
], function (
|
], function (
|
||||||
_,
|
_,
|
||||||
objectUtils
|
objectUtils
|
||||||
@ -143,7 +143,7 @@ define([
|
|||||||
var keyString = objectUtils.makeKeyString(domainObject.identifier);
|
var keyString = objectUtils.makeKeyString(domainObject.identifier);
|
||||||
var objectListeners = this.listeningTo[keyString];
|
var objectListeners = this.listeningTo[keyString];
|
||||||
|
|
||||||
var index = _.findIndex(objectListeners[event], function (l) {
|
var index = objectListeners[event].findIndex(l => {
|
||||||
return l.callback === callback && l.context === context;
|
return l.callback === callback && l.context === context;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -196,8 +196,8 @@ define([
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
DefaultCompositionProvider.prototype.includes = function (parent, childId) {
|
DefaultCompositionProvider.prototype.includes = function (parent, childId) {
|
||||||
return parent.composition.findIndex(composee =>
|
return parent.composition.some(composee =>
|
||||||
this.publicAPI.objects.areIdsEqual(composee, childId)) !== -1;
|
this.publicAPI.objects.areIdsEqual(composee, childId));
|
||||||
};
|
};
|
||||||
|
|
||||||
DefaultCompositionProvider.prototype.reorder = function (domainObject, oldIndex, newIndex) {
|
DefaultCompositionProvider.prototype.reorder = function (domainObject, oldIndex, newIndex) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -20,29 +20,32 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import ContextMenuComponent from './ContextMenu.vue';
|
import Menu from './menu.js';
|
||||||
import Vue from 'vue';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ContextMenuAPI allows the addition of new context menu actions, and for the context menu to be launched from
|
* The MenuAPI allows the addition of new context menu actions, and for the context menu to be launched from
|
||||||
* custom HTML elements.
|
* custom HTML elements.
|
||||||
* @interface ContextMenuAPI
|
* @interface MenuAPI
|
||||||
* @memberof module:openmct
|
* @memberof module:openmct
|
||||||
*/
|
*/
|
||||||
class ContextMenuAPI {
|
|
||||||
constructor() {
|
|
||||||
this._allActions = [];
|
|
||||||
this._activeContextMenu = undefined;
|
|
||||||
|
|
||||||
this._hideActiveContextMenu = this._hideActiveContextMenu.bind(this);
|
class MenuAPI {
|
||||||
this.registerAction = this.registerAction.bind(this);
|
constructor(openmct) {
|
||||||
|
this.openmct = openmct;
|
||||||
|
this._allObjectActions = [];
|
||||||
|
|
||||||
|
this.showMenu = this.showMenu.bind(this);
|
||||||
|
this.registerObjectAction = this.registerObjectAction.bind(this);
|
||||||
|
this._clearMenuComponent = this._clearMenuComponent.bind(this);
|
||||||
|
this._applicableObjectActions = this._applicableObjectActions.bind(this);
|
||||||
|
this._showObjectMenu = this._showObjectMenu.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines an item to be added to context menus. Allows specification of text, appearance, and behavior when
|
* Defines an item to be added to context menus. Allows specification of text, appearance, and behavior when
|
||||||
* selected. Applicabilioty can be restricted by specification of an `appliesTo` function.
|
* selected. Applicabilioty can be restricted by specification of an `appliesTo` function.
|
||||||
*
|
*
|
||||||
* @interface ContextMenuAction
|
* @interface ObjectAction
|
||||||
* @memberof module:openmct
|
* @memberof module:openmct
|
||||||
* @property {string} name the human-readable name of this view
|
* @property {string} name the human-readable name of this view
|
||||||
* @property {string} description a longer-form description (typically
|
* @property {string} description a longer-form description (typically
|
||||||
@ -68,17 +71,32 @@ class ContextMenuAPI {
|
|||||||
/**
|
/**
|
||||||
* @param {ContextMenuAction} actionDefinition
|
* @param {ContextMenuAction} actionDefinition
|
||||||
*/
|
*/
|
||||||
registerAction(actionDefinition) {
|
registerObjectAction(actionDefinition) {
|
||||||
this._allActions.push(actionDefinition);
|
this._allObjectActions.push(actionDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
showMenu(x, y, actions) {
|
||||||
* @private
|
if (this.menuComponent) {
|
||||||
*/
|
this.menuComponent.dismiss();
|
||||||
_showContextMenuForObjectPath(objectPath, x, y, actionsToBeIncluded) {
|
}
|
||||||
|
|
||||||
let applicableActions = this._allActions.filter((action) => {
|
let options = {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
actions
|
||||||
|
}
|
||||||
|
|
||||||
|
this.menuComponent = new Menu(options);
|
||||||
|
this.menuComponent.on('destroy', this._clearMenuComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
_clearMenuComponent() {
|
||||||
|
this.menuComponent = undefined;
|
||||||
|
delete this.menuComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
_applicableObjectActions(objectPath, actionsToBeIncluded) {
|
||||||
|
let applicableActions = this._allObjectActions.filter((action) => {
|
||||||
if (actionsToBeIncluded) {
|
if (actionsToBeIncluded) {
|
||||||
if (action.appliesTo === undefined && actionsToBeIncluded.includes(action.key)) {
|
if (action.appliesTo === undefined && actionsToBeIncluded.includes(action.key)) {
|
||||||
return true;
|
return true;
|
||||||
@ -92,66 +110,19 @@ class ContextMenuAPI {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this._activeContextMenu) {
|
applicableActions.forEach(action => {
|
||||||
this._hideActiveContextMenu();
|
action.callBack = () => {
|
||||||
}
|
return action.invoke(objectPath);
|
||||||
|
};
|
||||||
this._activeContextMenu = this._createContextMenuForObject(objectPath, applicableActions);
|
|
||||||
this._activeContextMenu.$mount();
|
|
||||||
document.body.appendChild(this._activeContextMenu.$el);
|
|
||||||
|
|
||||||
let position = this._calculatePopupPosition(x, y, this._activeContextMenu.$el);
|
|
||||||
this._activeContextMenu.$el.style.left = `${position.x}px`;
|
|
||||||
this._activeContextMenu.$el.style.top = `${position.y}px`;
|
|
||||||
|
|
||||||
document.addEventListener('click', this._hideActiveContextMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_calculatePopupPosition(eventPosX, eventPosY, menuElement) {
|
|
||||||
let menuDimensions = menuElement.getBoundingClientRect();
|
|
||||||
let overflowX = (eventPosX + menuDimensions.width) - document.body.clientWidth;
|
|
||||||
let overflowY = (eventPosY + menuDimensions.height) - document.body.clientHeight;
|
|
||||||
|
|
||||||
if (overflowX > 0) {
|
|
||||||
eventPosX = eventPosX - overflowX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overflowY > 0) {
|
|
||||||
eventPosY = eventPosY - overflowY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
x: eventPosX,
|
|
||||||
y: eventPosY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_hideActiveContextMenu() {
|
|
||||||
document.removeEventListener('click', this._hideActiveContextMenu);
|
|
||||||
document.body.removeChild(this._activeContextMenu.$el);
|
|
||||||
this._activeContextMenu.$destroy();
|
|
||||||
this._activeContextMenu = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_createContextMenuForObject(objectPath, actions) {
|
|
||||||
return new Vue({
|
|
||||||
components: {
|
|
||||||
ContextMenu: ContextMenuComponent
|
|
||||||
},
|
|
||||||
provide: {
|
|
||||||
actions: actions,
|
|
||||||
objectPath: objectPath
|
|
||||||
},
|
|
||||||
template: '<ContextMenu></ContextMenu>'
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return applicableActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
_showObjectMenu(objectPath, x, y, actionsToBeIncluded) {
|
||||||
|
let applicableActions = this._applicableObjectActions(objectPath, actionsToBeIncluded);
|
||||||
|
|
||||||
|
this.showMenu(x, y, applicableActions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default ContextMenuAPI;
|
export default MenuAPI;
|
@ -6,7 +6,7 @@
|
|||||||
:key="action.name"
|
:key="action.name"
|
||||||
:class="action.cssClass"
|
:class="action.cssClass"
|
||||||
:title="action.description"
|
:title="action.description"
|
||||||
@click="action.invoke(objectPath)"
|
@click="action.callBack"
|
||||||
>
|
>
|
||||||
{{ action.name }}
|
{{ action.name }}
|
||||||
</li>
|
</li>
|
||||||
@ -19,6 +19,6 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
inject: ['actions', 'objectPath']
|
inject: ['actions']
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
94
src/api/menu/menu.js
Normal file
94
src/api/menu/menu.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
import EventEmitter from 'EventEmitter';
|
||||||
|
import MenuComponent from './components/Menu.vue';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
class Menu extends EventEmitter {
|
||||||
|
constructor(options) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.options = options;
|
||||||
|
|
||||||
|
this.component = new Vue({
|
||||||
|
provide: {
|
||||||
|
actions: options.actions
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
MenuComponent
|
||||||
|
},
|
||||||
|
template: '<menu-component />'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options.onDestroy) {
|
||||||
|
this.once('destroy', options.onDestroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dismiss = this.dismiss.bind(this);
|
||||||
|
this.show = this.show.bind(this);
|
||||||
|
|
||||||
|
this.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
dismiss() {
|
||||||
|
this.emit('destroy');
|
||||||
|
document.body.removeChild(this.component.$el);
|
||||||
|
document.removeEventListener('click', this.dismiss);
|
||||||
|
this.component.$destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
this.component.$mount();
|
||||||
|
document.body.appendChild(this.component.$el);
|
||||||
|
|
||||||
|
let position = this._calculatePopupPosition(this.options.x, this.options.y, this.component.$el);
|
||||||
|
|
||||||
|
this.component.$el.style.left = `${position.x}px`;
|
||||||
|
this.component.$el.style.top = `${position.y}px`;
|
||||||
|
|
||||||
|
document.addEventListener('click', this.dismiss);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_calculatePopupPosition(eventPosX, eventPosY, menuElement) {
|
||||||
|
let menuDimensions = menuElement.getBoundingClientRect();
|
||||||
|
let overflowX = (eventPosX + menuDimensions.width) - document.body.clientWidth;
|
||||||
|
let overflowY = (eventPosY + menuDimensions.height) - document.body.clientHeight;
|
||||||
|
|
||||||
|
if (overflowX > 0) {
|
||||||
|
eventPosX = eventPosX - overflowX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overflowY > 0) {
|
||||||
|
eventPosY = eventPosY - overflowY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: eventPosX,
|
||||||
|
y: eventPosY
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Menu;
|
@ -128,6 +128,11 @@ export default class NotificationAPI extends EventEmitter {
|
|||||||
return this._notify(notificationModel);
|
return this._notify(notificationModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dismissAllNotifications() {
|
||||||
|
this.notifications = [];
|
||||||
|
this.emit('dismiss-all');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minimize a notification. The notification will still be available
|
* Minimize a notification. The notification will still be available
|
||||||
* from the notification list. Typically notifications with a
|
* from the notification list. Typically notifications with a
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'./object-utils.js',
|
'objectUtils',
|
||||||
'lodash'
|
'lodash'
|
||||||
], function (
|
], function (
|
||||||
utils,
|
utils,
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
define([
|
define([
|
||||||
'lodash',
|
'lodash',
|
||||||
'./object-utils',
|
'objectUtils',
|
||||||
'./MutableObject',
|
'./MutableObject',
|
||||||
'./RootRegistry',
|
'./RootRegistry',
|
||||||
'./RootObjectProvider',
|
'./RootObjectProvider',
|
||||||
|
@ -43,7 +43,7 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
RootRegistry.prototype.addRoot = function (key) {
|
RootRegistry.prototype.addRoot = function (key) {
|
||||||
if (isKey(key) || (_.isArray(key) && _.every(key, isKey))) {
|
if (isKey(key) || (Array.isArray(key) && key.every(isKey))) {
|
||||||
this.providers.push(function () {
|
this.providers.push(function () {
|
||||||
return key;
|
return key;
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
define([
|
define([
|
||||||
'../object-utils'
|
'objectUtils'
|
||||||
], function (
|
], function (
|
||||||
objectUtils
|
objectUtils
|
||||||
) {
|
) {
|
||||||
|
@ -22,6 +22,7 @@ class OverlayAPI {
|
|||||||
this.dismissLastOverlay();
|
this.dismissLastOverlay();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,6 +129,7 @@ class OverlayAPI {
|
|||||||
|
|
||||||
return progressDialog;
|
return progressDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default OverlayAPI;
|
export default OverlayAPI;
|
||||||
|
@ -85,9 +85,9 @@ define([
|
|||||||
value: +e.value
|
value: +e.value
|
||||||
};
|
};
|
||||||
}), 'e.value');
|
}), 'e.value');
|
||||||
valueMetadata.values = _.pluck(valueMetadata.enumerations, 'value');
|
valueMetadata.values = valueMetadata.enumerations.map(e => e.value);
|
||||||
valueMetadata.max = _.max(valueMetadata.values);
|
valueMetadata.max = Math.max(valueMetadata.values);
|
||||||
valueMetadata.min = _.min(valueMetadata.values);
|
valueMetadata.min = Math.min(valueMetadata.values);
|
||||||
}
|
}
|
||||||
|
|
||||||
valueMetadatas.push(valueMetadata);
|
valueMetadatas.push(valueMetadata);
|
||||||
@ -103,7 +103,7 @@ define([
|
|||||||
var metadata = domainObject.telemetry || {};
|
var metadata = domainObject.telemetry || {};
|
||||||
if (this.typeHasTelemetry(domainObject)) {
|
if (this.typeHasTelemetry(domainObject)) {
|
||||||
var typeMetadata = this.typeService.getType(domainObject.type).typeDef.telemetry;
|
var typeMetadata = this.typeService.getType(domainObject.type).typeDef.telemetry;
|
||||||
_.extend(metadata, typeMetadata);
|
Object.assign(metadata, typeMetadata);
|
||||||
if (!metadata.values) {
|
if (!metadata.values) {
|
||||||
metadata.values = valueMetadatasFromOldFormat(metadata);
|
metadata.values = valueMetadatasFromOldFormat(metadata);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ define([
|
|||||||
'./TelemetryMetadataManager',
|
'./TelemetryMetadataManager',
|
||||||
'./TelemetryValueFormatter',
|
'./TelemetryValueFormatter',
|
||||||
'./DefaultMetadataProvider',
|
'./DefaultMetadataProvider',
|
||||||
'../objects/object-utils',
|
'objectUtils',
|
||||||
'lodash'
|
'lodash'
|
||||||
], function (
|
], function (
|
||||||
TelemetryMetadataManager,
|
TelemetryMetadataManager,
|
||||||
@ -370,7 +370,7 @@ define([
|
|||||||
TelemetryAPI.prototype.commonValuesForHints = function (metadatas, hints) {
|
TelemetryAPI.prototype.commonValuesForHints = function (metadatas, hints) {
|
||||||
var options = metadatas.map(function (metadata) {
|
var options = metadatas.map(function (metadata) {
|
||||||
var values = metadata.valuesForHints(hints);
|
var values = metadata.valuesForHints(hints);
|
||||||
return _.indexBy(values, 'key');
|
return _.keyBy(values, 'key');
|
||||||
}).reduce(function (a, b) {
|
}).reduce(function (a, b) {
|
||||||
var results = {};
|
var results = {};
|
||||||
Object.keys(a).forEach(function (key) {
|
Object.keys(a).forEach(function (key) {
|
||||||
@ -383,7 +383,7 @@ define([
|
|||||||
var sortKeys = hints.map(function (h) {
|
var sortKeys = hints.map(function (h) {
|
||||||
return 'hints.' + h;
|
return 'hints.' + h;
|
||||||
});
|
});
|
||||||
return _.sortByAll(options, sortKeys);
|
return _.sortBy(options, sortKeys);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,13 +57,13 @@ define([
|
|||||||
|
|
||||||
if (valueMetadata.format === 'enum') {
|
if (valueMetadata.format === 'enum') {
|
||||||
if (!valueMetadata.values) {
|
if (!valueMetadata.values) {
|
||||||
valueMetadata.values = _.pluck(valueMetadata.enumerations, 'value');
|
valueMetadata.values = valueMetadata.enumerations.map(e => e.value);
|
||||||
}
|
}
|
||||||
if (!valueMetadata.hasOwnProperty('max')) {
|
if (!valueMetadata.hasOwnProperty('max')) {
|
||||||
valueMetadata.max = _.max(valueMetadata.values) + 1;
|
valueMetadata.max = Math.max(valueMetadata.values) + 1;
|
||||||
}
|
}
|
||||||
if (!valueMetadata.hasOwnProperty('min')) {
|
if (!valueMetadata.hasOwnProperty('min')) {
|
||||||
valueMetadata.min = _.min(valueMetadata.values) - 1;
|
valueMetadata.min = Math.min(valueMetadata.values) - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ define([
|
|||||||
return metadata.hints[hint];
|
return metadata.hints[hint];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return _.sortByAll(matchingMetadata, ...iteratees);
|
return _.sortBy(matchingMetadata, ...iteratees);
|
||||||
};
|
};
|
||||||
|
|
||||||
TelemetryMetadataManager.prototype.getFilterableValues = function () {
|
TelemetryMetadataManager.prototype.getFilterableValues = function () {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -24,10 +24,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<tr @contextmenu.prevent="showContextMenu">
|
<tr @contextmenu.prevent="showContextMenu">
|
||||||
<td>{{ name }}</td>
|
<td>{{ name }}</td>
|
||||||
<td>{{ timestamp }}</td>
|
<td>{{ formattedTimestamp }}</td>
|
||||||
<td :class="valueClass">
|
<td :class="valueClass">{{ value }}</td>
|
||||||
{{ value }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -52,16 +50,22 @@ export default {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
name: this.domainObject.name,
|
name: this.domainObject.name,
|
||||||
timestamp: '---',
|
timestamp: undefined,
|
||||||
value: '---',
|
value: '---',
|
||||||
valueClass: '',
|
valueClass: '',
|
||||||
currentObjectPath
|
currentObjectPath
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
formattedTimestamp() {
|
||||||
|
return this.timestamp !== undefined ? this.formats[this.timestampKey].format(this.timestamp) : '---';
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
||||||
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
|
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
|
||||||
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||||
|
this.bounds = this.openmct.time.bounds();
|
||||||
|
|
||||||
this.limitEvaluator = this.openmct
|
this.limitEvaluator = this.openmct
|
||||||
.telemetry
|
.telemetry
|
||||||
@ -76,6 +80,7 @@ export default {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.openmct.time.on('timeSystem', this.updateTimeSystem);
|
this.openmct.time.on('timeSystem', this.updateTimeSystem);
|
||||||
|
this.openmct.time.on('bounds', this.updateBounds);
|
||||||
|
|
||||||
this.timestampKey = this.openmct.time.timeSystem().key;
|
this.timestampKey = this.openmct.time.timeSystem().key;
|
||||||
|
|
||||||
@ -89,46 +94,66 @@ export default {
|
|||||||
.telemetry
|
.telemetry
|
||||||
.subscribe(this.domainObject, this.updateValues);
|
.subscribe(this.domainObject, this.updateValues);
|
||||||
|
|
||||||
this.openmct
|
this.requestHistory();
|
||||||
.telemetry
|
|
||||||
.request(this.domainObject, {strategy: 'latest'})
|
|
||||||
.then((array) => this.updateValues(array[array.length - 1]));
|
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.stopWatchingMutation();
|
this.stopWatchingMutation();
|
||||||
this.unsubscribe();
|
this.unsubscribe();
|
||||||
this.openmct.off('timeSystem', this.updateTimeSystem);
|
this.openmct.time.off('timeSystem', this.updateTimeSystem);
|
||||||
|
this.openmct.time.off('bounds', this.updateBounds);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateValues(datum) {
|
updateValues(datum) {
|
||||||
this.timestamp = this.formats[this.timestampKey].format(datum);
|
let newTimestamp = this.formats[this.timestampKey].parse(datum),
|
||||||
|
limit;
|
||||||
|
|
||||||
|
if(this.shouldUpdate(newTimestamp)) {
|
||||||
|
this.timestamp = this.formats[this.timestampKey].parse(datum);
|
||||||
this.value = this.formats[this.valueKey].format(datum);
|
this.value = this.formats[this.valueKey].format(datum);
|
||||||
|
limit = this.limitEvaluator.evaluate(datum, this.valueMetadata);
|
||||||
var limit = this.limitEvaluator.evaluate(datum, this.valueMetadata);
|
|
||||||
|
|
||||||
if (limit) {
|
if (limit) {
|
||||||
this.valueClass = limit.cssClass;
|
this.valueClass = limit.cssClass;
|
||||||
} else {
|
} else {
|
||||||
this.valueClass = '';
|
this.valueClass = '';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
shouldUpdate(newTimestamp) {
|
||||||
|
return (this.timestamp === undefined) ||
|
||||||
|
(this.inBounds(newTimestamp) &&
|
||||||
|
newTimestamp > this.timestamp);
|
||||||
|
},
|
||||||
|
requestHistory() {
|
||||||
|
this.openmct
|
||||||
|
.telemetry
|
||||||
|
.request(this.domainObject, {
|
||||||
|
start: this.bounds.start,
|
||||||
|
end: this.bounds.end,
|
||||||
|
size: 1,
|
||||||
|
strategy: 'latest'
|
||||||
|
})
|
||||||
|
.then((array) => this.updateValues(array[array.length - 1]));
|
||||||
},
|
},
|
||||||
updateName(name) {
|
updateName(name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
},
|
},
|
||||||
|
updateBounds(bounds, isTick) {
|
||||||
|
this.bounds = bounds;
|
||||||
|
if(!isTick) {
|
||||||
|
this.requestHistory();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
inBounds(timestamp) {
|
||||||
|
return timestamp >= this.bounds.start && timestamp <= this.bounds.end;
|
||||||
|
},
|
||||||
updateTimeSystem(timeSystem) {
|
updateTimeSystem(timeSystem) {
|
||||||
this.value = '---';
|
this.value = '---';
|
||||||
this.timestamp = '---';
|
this.timestamp = '---';
|
||||||
this.valueClass = '';
|
this.valueClass = '';
|
||||||
this.timestampKey = timeSystem.key;
|
this.timestampKey = timeSystem.key;
|
||||||
|
|
||||||
this.openmct
|
|
||||||
.telemetry
|
|
||||||
.request(this.domainObject, {strategy: 'latest'})
|
|
||||||
.then((array) => this.updateValues(array[array.length - 1]));
|
|
||||||
|
|
||||||
},
|
},
|
||||||
showContextMenu(event) {
|
showContextMenu(event) {
|
||||||
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
|
this.openmct.menus._showObjectMenu(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ export default {
|
|||||||
this.items.push(item);
|
this.items.push(item);
|
||||||
},
|
},
|
||||||
removeItem(identifier) {
|
removeItem(identifier) {
|
||||||
let index = _.findIndex(this.items, (item) => this.openmct.objects.makeKeyString(identifier) === item.key);
|
let index = this.items.findIndex(item => this.openmct.objects.makeKeyString(identifier) === item.key);
|
||||||
|
|
||||||
this.items.splice(index, 1);
|
this.items.splice(index, 1);
|
||||||
},
|
},
|
||||||
|
@ -102,7 +102,7 @@ export default {
|
|||||||
this.compositions.push({composition, addCallback, removeCallback});
|
this.compositions.push({composition, addCallback, removeCallback});
|
||||||
},
|
},
|
||||||
removePrimary(identifier) {
|
removePrimary(identifier) {
|
||||||
let index = _.findIndex(this.primaryTelemetryObjects, (primary) => this.openmct.objects.makeKeyString(identifier) === primary.key),
|
let index = this.primaryTelemetryObjects.findIndex(primary => this.openmct.objects.makeKeyString(identifier) === primary.key),
|
||||||
primary = this.primaryTelemetryObjects[index];
|
primary = this.primaryTelemetryObjects[index];
|
||||||
|
|
||||||
this.$set(this.secondaryTelemetryObjects, primary.key, undefined);
|
this.$set(this.secondaryTelemetryObjects, primary.key, undefined);
|
||||||
@ -130,7 +130,7 @@ export default {
|
|||||||
removeSecondary(primary) {
|
removeSecondary(primary) {
|
||||||
return (identifier) => {
|
return (identifier) => {
|
||||||
let array = this.secondaryTelemetryObjects[primary.key],
|
let array = this.secondaryTelemetryObjects[primary.key],
|
||||||
index = _.findIndex(array, (secondary) => this.openmct.objects.makeKeyString(identifier) === secondary.key);
|
index = array.findIndex(secondary => this.openmct.objects.makeKeyString(identifier) === secondary.key);
|
||||||
|
|
||||||
array.splice(index, 1);
|
array.splice(index, 1);
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ define([
|
|||||||
|
|
||||||
openmct.indicators.add(indicator);
|
openmct.indicators.add(indicator);
|
||||||
|
|
||||||
openmct.contextMenu.registerAction(new ClearDataAction.default(openmct, appliesToObjects));
|
openmct.menus.registerObjectAction(new ClearDataAction.default(openmct, appliesToObjects));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
import EventEmitter from 'EventEmitter';
|
import EventEmitter from 'EventEmitter';
|
||||||
import uuid from 'uuid';
|
import uuid from 'uuid';
|
||||||
import TelemetryCriterion from "./criterion/TelemetryCriterion";
|
import TelemetryCriterion from "./criterion/TelemetryCriterion";
|
||||||
import { TRIGGER } from "./utils/constants";
|
import { evaluateResults } from './utils/evaluator';
|
||||||
import {computeCondition, computeConditionByLimit} from "./utils/evaluator";
|
import { getLatestTimestamp } from './utils/time';
|
||||||
import AllTelemetryCriterion from "./criterion/AllTelemetryCriterion";
|
import AllTelemetryCriterion from "./criterion/AllTelemetryCriterion";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -56,29 +56,42 @@ export default class ConditionClass extends EventEmitter {
|
|||||||
this.conditionManager = conditionManager;
|
this.conditionManager = conditionManager;
|
||||||
this.id = conditionConfiguration.id;
|
this.id = conditionConfiguration.id;
|
||||||
this.criteria = [];
|
this.criteria = [];
|
||||||
this.criteriaResults = {};
|
|
||||||
this.result = undefined;
|
this.result = undefined;
|
||||||
this.latestTimestamp = {};
|
this.timeSystems = this.openmct.time.getAllTimeSystems();
|
||||||
|
|
||||||
if (conditionConfiguration.configuration.criteria) {
|
if (conditionConfiguration.configuration.criteria) {
|
||||||
this.createCriteria(conditionConfiguration.configuration.criteria);
|
this.createCriteria(conditionConfiguration.configuration.criteria);
|
||||||
}
|
}
|
||||||
this.trigger = conditionConfiguration.configuration.trigger;
|
this.trigger = conditionConfiguration.configuration.trigger;
|
||||||
this.conditionManager.on('broadcastTelemetry', this.handleBroadcastTelemetry, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleBroadcastTelemetry(datum) {
|
getResult(datum) {
|
||||||
if (!datum || !datum.id) {
|
if (!datum || !datum.id) {
|
||||||
console.log('no data received');
|
console.log('no data received');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.isTelemetryUsed(datum.id)) {
|
||||||
|
|
||||||
this.criteria.forEach(criterion => {
|
this.criteria.forEach(criterion => {
|
||||||
if (criterion.telemetry && (criterion.telemetry === 'all' || criterion.telemetry === 'any')) {
|
if (this.isAnyOrAllTelemetry(criterion)) {
|
||||||
criterion.handleSubscription(datum, this.conditionManager.telemetryObjects);
|
criterion.getResult(datum, this.conditionManager.telemetryObjects);
|
||||||
} else {
|
} else {
|
||||||
criterion.emit(`subscription:${datum.id}`, datum);
|
criterion.getResult(datum);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.result = evaluateResults(this.criteria.map(criterion => criterion.result), this.trigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isAnyOrAllTelemetry(criterion) {
|
||||||
|
return (criterion.telemetry && (criterion.telemetry === 'all' || criterion.telemetry === 'any'));
|
||||||
|
}
|
||||||
|
|
||||||
|
isTelemetryUsed(id) {
|
||||||
|
return this.criteria.some(criterion => {
|
||||||
|
return this.isAnyOrAllTelemetry(criterion) || criterion.telemetryObjectIdAsString === id;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
update(conditionConfiguration) {
|
update(conditionConfiguration) {
|
||||||
@ -89,7 +102,6 @@ export default class ConditionClass extends EventEmitter {
|
|||||||
updateTrigger(trigger) {
|
updateTrigger(trigger) {
|
||||||
if (this.trigger !== trigger) {
|
if (this.trigger !== trigger) {
|
||||||
this.trigger = trigger;
|
this.trigger = trigger;
|
||||||
this.handleConditionUpdated();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +145,6 @@ export default class ConditionClass extends EventEmitter {
|
|||||||
criterion = new TelemetryCriterion(criterionConfigurationWithId, this.openmct);
|
criterion = new TelemetryCriterion(criterionConfigurationWithId, this.openmct);
|
||||||
}
|
}
|
||||||
criterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
criterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
||||||
criterion.on('criterionResultUpdated', (obj) => this.handleCriterionResult(obj));
|
|
||||||
if (!this.criteria) {
|
if (!this.criteria) {
|
||||||
this.criteria = [];
|
this.criteria = [];
|
||||||
}
|
}
|
||||||
@ -162,22 +173,11 @@ export default class ConditionClass extends EventEmitter {
|
|||||||
const newCriterionConfiguration = this.generateCriterion(criterionConfiguration);
|
const newCriterionConfiguration = this.generateCriterion(criterionConfiguration);
|
||||||
let newCriterion = new TelemetryCriterion(newCriterionConfiguration, this.openmct);
|
let newCriterion = new TelemetryCriterion(newCriterionConfiguration, this.openmct);
|
||||||
newCriterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
newCriterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
||||||
newCriterion.on('criterionResultUpdated', (obj) => this.handleCriterionResult(obj));
|
|
||||||
|
|
||||||
let criterion = found.item;
|
let criterion = found.item;
|
||||||
criterion.unsubscribe();
|
criterion.unsubscribe();
|
||||||
criterion.off('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
criterion.off('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
||||||
criterion.off('criterionResultUpdated', (obj) => this.handleCriterionResult(obj));
|
|
||||||
this.criteria.splice(found.index, 1, newCriterion);
|
this.criteria.splice(found.index, 1, newCriterion);
|
||||||
if (this.criteriaResults[criterion.id] !== undefined) {
|
|
||||||
delete this.criteriaResults[criterion.id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
removeCriterion(id) {
|
|
||||||
if (this.destroyCriterion(id)) {
|
|
||||||
this.handleConditionUpdated();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,15 +185,12 @@ export default class ConditionClass extends EventEmitter {
|
|||||||
let found = this.findCriterion(id);
|
let found = this.findCriterion(id);
|
||||||
if (found) {
|
if (found) {
|
||||||
let criterion = found.item;
|
let criterion = found.item;
|
||||||
criterion.destroy();
|
criterion.off('criterionUpdated', (obj) => {
|
||||||
// TODO this is passing the wrong args
|
this.handleCriterionUpdated(obj);
|
||||||
criterion.off('criterionUpdated', (result) => {
|
|
||||||
this.handleCriterionUpdated(id, result);
|
|
||||||
});
|
});
|
||||||
|
criterion.destroy();
|
||||||
this.criteria.splice(found.index, 1);
|
this.criteria.splice(found.index, 1);
|
||||||
if (this.criteriaResults[criterion.id] !== undefined) {
|
|
||||||
delete this.criteriaResults[criterion.id];
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -203,59 +200,40 @@ export default class ConditionClass extends EventEmitter {
|
|||||||
let found = this.findCriterion(criterion.id);
|
let found = this.findCriterion(criterion.id);
|
||||||
if (found) {
|
if (found) {
|
||||||
this.criteria[found.index] = criterion.data;
|
this.criteria[found.index] = criterion.data;
|
||||||
// TODO nothing is listening to this
|
|
||||||
this.emitEvent('conditionUpdated', {
|
|
||||||
trigger: this.trigger,
|
|
||||||
criteria: this.criteria
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCriteriaResults(eventData) {
|
|
||||||
const id = eventData.id;
|
|
||||||
|
|
||||||
if (this.findCriterion(id)) {
|
|
||||||
// The !! here is important to convert undefined to false otherwise the criteriaResults won't get deleted when the criteria is destroyed
|
|
||||||
this.criteriaResults[id] = !!eventData.data.result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCriterionResult(eventData) {
|
|
||||||
this.updateCriteriaResults(eventData);
|
|
||||||
this.handleConditionUpdated(eventData.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
requestLADConditionResult() {
|
requestLADConditionResult() {
|
||||||
const criteriaResults = this.criteria
|
let latestTimestamp;
|
||||||
.map(criterion => criterion.requestLAD({telemetryObjects: this.conditionManager.telemetryObjects}));
|
let criteriaResults = {};
|
||||||
|
const criteriaRequests = this.criteria
|
||||||
|
.map(criterion => criterion.requestLAD(this.conditionManager.telemetryObjects));
|
||||||
|
|
||||||
return Promise.all(criteriaResults)
|
return Promise.all(criteriaRequests)
|
||||||
.then(results => {
|
.then(results => {
|
||||||
results.forEach(result => {
|
results.forEach(resultObj => {
|
||||||
this.updateCriteriaResults(result);
|
const { id, data, data: { result } } = resultObj;
|
||||||
this.latestTimestamp = this.getLatestTimestamp(this.latestTimestamp, result.data)
|
if (this.findCriterion(id)) {
|
||||||
|
criteriaResults[id] = !!result;
|
||||||
|
}
|
||||||
|
latestTimestamp = getLatestTimestamp(
|
||||||
|
latestTimestamp,
|
||||||
|
data,
|
||||||
|
this.timeSystems,
|
||||||
|
this.openmct.time.timeSystem()
|
||||||
|
);
|
||||||
});
|
});
|
||||||
this.evaluate();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
data: Object.assign({}, this.latestTimestamp, { result: this.result })
|
data: Object.assign(
|
||||||
}
|
{},
|
||||||
|
latestTimestamp,
|
||||||
|
{ result: evaluateResults(Object.values(criteriaResults), this.trigger) }
|
||||||
|
)
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getTelemetrySubscriptions() {
|
|
||||||
return this.criteria.map(criterion => criterion.telemetryObjectIdAsString);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleConditionUpdated(datum) {
|
|
||||||
// trigger an updated event so that consumers can react accordingly
|
|
||||||
this.evaluate();
|
|
||||||
this.emitEvent('conditionResultUpdated',
|
|
||||||
Object.assign({}, datum, { result: this.result })
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getCriteria() {
|
getCriteria() {
|
||||||
return this.criteria;
|
return this.criteria;
|
||||||
}
|
}
|
||||||
@ -269,41 +247,7 @@ export default class ConditionClass extends EventEmitter {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
evaluate() {
|
|
||||||
if (this.trigger && this.trigger === TRIGGER.XOR) {
|
|
||||||
this.result = computeConditionByLimit(this.criteriaResults, 1);
|
|
||||||
} else if (this.trigger && this.trigger === TRIGGER.NOT) {
|
|
||||||
this.result = computeConditionByLimit(this.criteriaResults, 0);
|
|
||||||
} else {
|
|
||||||
this.result = computeCondition(this.criteriaResults, this.trigger === TRIGGER.ALL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getLatestTimestamp(current, compare) {
|
|
||||||
const timestamp = Object.assign({}, current);
|
|
||||||
|
|
||||||
this.openmct.time.getAllTimeSystems().forEach(timeSystem => {
|
|
||||||
if (!timestamp[timeSystem.key]
|
|
||||||
|| compare[timeSystem.key] > timestamp[timeSystem.key]
|
|
||||||
) {
|
|
||||||
timestamp[timeSystem.key] = compare[timeSystem.key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
emitEvent(eventName, data) {
|
|
||||||
this.emit(eventName, {
|
|
||||||
id: this.id,
|
|
||||||
data: data
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
this.conditionManager.off('broadcastTelemetry', this.handleBroadcastTelemetry, this);
|
|
||||||
if (typeof this.stopObservingForChanges === 'function') {
|
|
||||||
this.stopObservingForChanges();
|
|
||||||
}
|
|
||||||
this.destroyCriteria();
|
this.destroyCriteria();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import Condition from "./Condition";
|
import Condition from "./Condition";
|
||||||
|
import { getLatestTimestamp } from './utils/time';
|
||||||
import uuid from "uuid";
|
import uuid from "uuid";
|
||||||
import EventEmitter from 'EventEmitter';
|
import EventEmitter from 'EventEmitter';
|
||||||
|
|
||||||
@ -29,8 +30,7 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
super();
|
super();
|
||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
this.conditionSetDomainObject = conditionSetDomainObject;
|
this.conditionSetDomainObject = conditionSetDomainObject;
|
||||||
this.timeAPI = this.openmct.time;
|
this.timeSystems = this.openmct.time.getAllTimeSystems();
|
||||||
this.latestTimestamp = {};
|
|
||||||
this.composition = this.openmct.composition.get(conditionSetDomainObject);
|
this.composition = this.openmct.composition.get(conditionSetDomainObject);
|
||||||
this.composition.on('add', this.subscribeToTelemetry, this);
|
this.composition.on('add', this.subscribeToTelemetry, this);
|
||||||
this.composition.on('remove', this.unsubscribeFromTelemetry, this);
|
this.composition.on('remove', this.unsubscribeFromTelemetry, this);
|
||||||
@ -55,7 +55,7 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
this.telemetryObjects[id] = Object.assign({}, endpoint, {telemetryMetaData: this.openmct.telemetry.getMetadata(endpoint).valueMetadatas});
|
this.telemetryObjects[id] = Object.assign({}, endpoint, {telemetryMetaData: this.openmct.telemetry.getMetadata(endpoint).valueMetadatas});
|
||||||
this.subscriptions[id] = this.openmct.telemetry.subscribe(
|
this.subscriptions[id] = this.openmct.telemetry.subscribe(
|
||||||
endpoint,
|
endpoint,
|
||||||
this.broadcastTelemetry.bind(this, id)
|
this.telemetryReceived.bind(this, endpoint)
|
||||||
);
|
);
|
||||||
this.updateConditionTelemetry();
|
this.updateConditionTelemetry();
|
||||||
}
|
}
|
||||||
@ -70,10 +70,10 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
this.subscriptions[id]();
|
this.subscriptions[id]();
|
||||||
delete this.subscriptions[id];
|
delete this.subscriptions[id];
|
||||||
delete this.telemetryObjects[id];
|
delete this.telemetryObjects[id];
|
||||||
|
this.removeConditionTelemetry();
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize() {
|
initialize() {
|
||||||
this.conditionResults = {};
|
|
||||||
this.conditionClassCollection = [];
|
this.conditionClassCollection = [];
|
||||||
if (this.conditionSetDomainObject.configuration.conditionCollection.length) {
|
if (this.conditionSetDomainObject.configuration.conditionCollection.length) {
|
||||||
this.conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
|
this.conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
|
||||||
@ -86,6 +86,30 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
this.conditionClassCollection.forEach((condition) => condition.updateTelemetry());
|
this.conditionClassCollection.forEach((condition) => condition.updateTelemetry());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeConditionTelemetry() {
|
||||||
|
let conditionsChanged = false;
|
||||||
|
this.conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration) => {
|
||||||
|
conditionConfiguration.configuration.criteria.forEach((criterion, index) => {
|
||||||
|
const isAnyAllTelemetry = criterion.telemetry && (criterion.telemetry === 'any' || criterion.telemetry === 'all');
|
||||||
|
if (!isAnyAllTelemetry) {
|
||||||
|
const found = Object.values(this.telemetryObjects).find((telemetryObject) => {
|
||||||
|
return this.openmct.objects.areIdsEqual(telemetryObject.identifier, criterion.telemetry);
|
||||||
|
});
|
||||||
|
if (!found) {
|
||||||
|
criterion.telemetry = '';
|
||||||
|
criterion.metadata = '';
|
||||||
|
criterion.input = [];
|
||||||
|
criterion.operation = '';
|
||||||
|
conditionsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (conditionsChanged) {
|
||||||
|
this.persistConditions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateCondition(conditionConfiguration, index) {
|
updateCondition(conditionConfiguration, index) {
|
||||||
let condition = this.conditionClassCollection[index];
|
let condition = this.conditionClassCollection[index];
|
||||||
condition.update(conditionConfiguration);
|
condition.update(conditionConfiguration);
|
||||||
@ -95,7 +119,6 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
|
|
||||||
initCondition(conditionConfiguration, index) {
|
initCondition(conditionConfiguration, index) {
|
||||||
let condition = new Condition(conditionConfiguration, this.openmct, this);
|
let condition = new Condition(conditionConfiguration, this.openmct, this);
|
||||||
condition.on('conditionResultUpdated', this.handleConditionResult.bind(this));
|
|
||||||
if (index !== undefined) {
|
if (index !== undefined) {
|
||||||
this.conditionClassCollection.splice(index + 1, 0, condition);
|
this.conditionClassCollection.splice(index + 1, 0, condition);
|
||||||
} else {
|
} else {
|
||||||
@ -159,22 +182,16 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
|
|
||||||
removeCondition(index) {
|
removeCondition(index) {
|
||||||
let condition = this.conditionClassCollection[index];
|
let condition = this.conditionClassCollection[index];
|
||||||
condition.destroyCriteria();
|
condition.destroy();
|
||||||
condition.off('conditionResultUpdated', this.handleConditionResult.bind(this));
|
|
||||||
this.conditionClassCollection.splice(index, 1);
|
this.conditionClassCollection.splice(index, 1);
|
||||||
this.conditionSetDomainObject.configuration.conditionCollection.splice(index, 1);
|
this.conditionSetDomainObject.configuration.conditionCollection.splice(index, 1);
|
||||||
if (this.conditionResults[condition.id] !== undefined) {
|
|
||||||
delete this.conditionResults[condition.id];
|
|
||||||
}
|
|
||||||
this.persistConditions();
|
this.persistConditions();
|
||||||
this.handleConditionResult();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
findConditionById(id) {
|
findConditionById(id) {
|
||||||
return this.conditionClassCollection.find(conditionClass => conditionClass.id === id);
|
return this.conditionClassCollection.find(conditionClass => conditionClass.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
//this.$set(this.conditionClassCollection, reorderEvent.newIndex, oldConditions[reorderEvent.oldIndex]);
|
|
||||||
reorderConditions(reorderPlan) {
|
reorderConditions(reorderPlan) {
|
||||||
let oldConditions = Array.from(this.conditionSetDomainObject.configuration.conditionCollection);
|
let oldConditions = Array.from(this.conditionSetDomainObject.configuration.conditionCollection);
|
||||||
let newCollection = [];
|
let newCollection = [];
|
||||||
@ -191,7 +208,23 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
let currentCondition = conditionCollection[conditionCollection.length-1];
|
let currentCondition = conditionCollection[conditionCollection.length-1];
|
||||||
|
|
||||||
for (let i = 0; i < conditionCollection.length - 1; i++) {
|
for (let i = 0; i < conditionCollection.length - 1; i++) {
|
||||||
if (this.conditionResults[conditionCollection[i].id]) {
|
const condition = this.findConditionById(conditionCollection[i].id)
|
||||||
|
if (condition.result) {
|
||||||
|
//first condition to be true wins
|
||||||
|
currentCondition = conditionCollection[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentConditionLAD(conditionResults) {
|
||||||
|
const conditionCollection = this.conditionSetDomainObject.configuration.conditionCollection;
|
||||||
|
let currentCondition = conditionCollection[conditionCollection.length-1];
|
||||||
|
|
||||||
|
for (let i = 0; i < conditionCollection.length - 1; i++) {
|
||||||
|
if (conditionResults[conditionCollection[i].id]) {
|
||||||
//first condition to be true wins
|
//first condition to be true wins
|
||||||
currentCondition = conditionCollection[i];
|
currentCondition = conditionCollection[i];
|
||||||
break;
|
break;
|
||||||
@ -200,24 +233,79 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
return currentCondition;
|
return currentCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateConditionResults(resultObj) {
|
requestLADConditionSetOutput() {
|
||||||
if (!resultObj) {
|
if (!this.conditionClassCollection.length) {
|
||||||
|
return Promise.resolve([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.compositionLoad.then(() => {
|
||||||
|
let latestTimestamp;
|
||||||
|
let conditionResults = {};
|
||||||
|
const conditionRequests = this.conditionClassCollection
|
||||||
|
.map(condition => condition.requestLADConditionResult());
|
||||||
|
|
||||||
|
return Promise.all(conditionRequests)
|
||||||
|
.then((results) => {
|
||||||
|
results.forEach(resultObj => {
|
||||||
|
const { id, data, data: { result } } = resultObj;
|
||||||
|
if (this.findConditionById(id)) {
|
||||||
|
conditionResults[id] = !!result;
|
||||||
|
}
|
||||||
|
latestTimestamp = getLatestTimestamp(
|
||||||
|
latestTimestamp,
|
||||||
|
data,
|
||||||
|
this.timeSystems,
|
||||||
|
this.openmct.time.timeSystem()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!Object.values(latestTimestamp).some(timeSystem => timeSystem)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentCondition = this.getCurrentConditionLAD(conditionResults);
|
||||||
|
const currentOutput = Object.assign(
|
||||||
|
{
|
||||||
|
output: currentCondition.configuration.output,
|
||||||
|
id: this.conditionSetDomainObject.identifier,
|
||||||
|
conditionId: currentCondition.id
|
||||||
|
},
|
||||||
|
latestTimestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
return [currentOutput];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
isTelemetryUsed(endpoint) {
|
||||||
|
const id = this.openmct.objects.makeKeyString(endpoint.identifier);
|
||||||
|
|
||||||
|
for(const condition of this.conditionClassCollection) {
|
||||||
|
if (condition.isTelemetryUsed(id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
telemetryReceived(endpoint, datum) {
|
||||||
|
if (!this.isTelemetryUsed(endpoint)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = resultObj.id;
|
const normalizedDatum = this.createNormalizedDatum(datum, endpoint);
|
||||||
|
const timeSystemKey = this.openmct.time.timeSystem().key;
|
||||||
|
let timestamp = {};
|
||||||
|
timestamp[timeSystemKey] = normalizedDatum[timeSystemKey];
|
||||||
|
|
||||||
if (this.findConditionById(id)) {
|
this.conditionClassCollection.forEach(condition => {
|
||||||
this.conditionResults[id] = resultObj.data.result;
|
condition.getResult(normalizedDatum);
|
||||||
}
|
});
|
||||||
|
|
||||||
this.updateTimestamp(resultObj.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleConditionResult(resultObj) {
|
|
||||||
// update conditions results and then calculate the current condition
|
|
||||||
this.updateConditionResults(resultObj);
|
|
||||||
const currentCondition = this.getCurrentCondition();
|
const currentCondition = this.getCurrentCondition();
|
||||||
|
|
||||||
this.emit('conditionSetResultUpdated',
|
this.emit('conditionSetResultUpdated',
|
||||||
Object.assign(
|
Object.assign(
|
||||||
{
|
{
|
||||||
@ -225,51 +313,11 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
id: this.conditionSetDomainObject.identifier,
|
id: this.conditionSetDomainObject.identifier,
|
||||||
conditionId: currentCondition.id
|
conditionId: currentCondition.id
|
||||||
},
|
},
|
||||||
this.latestTimestamp
|
timestamp
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTimestamp(timestamp) {
|
|
||||||
this.timeAPI.getAllTimeSystems().forEach(timeSystem => {
|
|
||||||
if (!this.latestTimestamp[timeSystem.key]
|
|
||||||
|| timestamp[timeSystem.key] > this.latestTimestamp[timeSystem.key]
|
|
||||||
) {
|
|
||||||
this.latestTimestamp[timeSystem.key] = timestamp[timeSystem.key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
requestLADConditionSetOutput() {
|
|
||||||
if (!this.conditionClassCollection.length) {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.compositionLoad.then(() => {
|
|
||||||
const ladConditionResults = this.conditionClassCollection
|
|
||||||
.map(condition => condition.requestLADConditionResult());
|
|
||||||
|
|
||||||
return Promise.all(ladConditionResults)
|
|
||||||
.then((results) => {
|
|
||||||
results.forEach(resultObj => { this.updateConditionResults(resultObj); });
|
|
||||||
const currentCondition = this.getCurrentCondition();
|
|
||||||
|
|
||||||
return Object.assign(
|
|
||||||
{
|
|
||||||
output: currentCondition.configuration.output,
|
|
||||||
id: this.conditionSetDomainObject.identifier,
|
|
||||||
conditionId: currentCondition.id
|
|
||||||
},
|
|
||||||
this.latestTimestamp
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
broadcastTelemetry(id, datum) {
|
|
||||||
this.emit(`broadcastTelemetry`, Object.assign({}, this.createNormalizedDatum(datum, id), {id: id}));
|
|
||||||
}
|
|
||||||
|
|
||||||
getTestData(metadatum) {
|
getTestData(metadatum) {
|
||||||
let data = undefined;
|
let data = undefined;
|
||||||
if (this.testData.applied) {
|
if (this.testData.applied) {
|
||||||
@ -281,13 +329,20 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
createNormalizedDatum(telemetryDatum, id) {
|
createNormalizedDatum(telemetryDatum, endpoint) {
|
||||||
return Object.values(this.telemetryObjects[id].telemetryMetaData).reduce((normalizedDatum, metadatum) => {
|
const id = this.openmct.objects.makeKeyString(endpoint.identifier);
|
||||||
|
const metadata = this.openmct.telemetry.getMetadata(endpoint).valueMetadatas;
|
||||||
|
|
||||||
|
const normalizedDatum = Object.values(metadata).reduce((datum, metadatum) => {
|
||||||
const testValue = this.getTestData(metadatum);
|
const testValue = this.getTestData(metadatum);
|
||||||
const formatter = this.openmct.telemetry.getValueFormatter(metadatum);
|
const formatter = this.openmct.telemetry.getValueFormatter(metadatum);
|
||||||
normalizedDatum[metadatum.key] = testValue !== undefined ? formatter.parse(testValue) : formatter.parse(telemetryDatum[metadatum.source]);
|
datum[metadatum.key] = testValue !== undefined ? formatter.parse(testValue) : formatter.parse(telemetryDatum[metadatum.source]);
|
||||||
return normalizedDatum;
|
return datum;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
normalizedDatum.id = id;
|
||||||
|
|
||||||
|
return normalizedDatum;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTestData(testData) {
|
updateTestData(testData) {
|
||||||
@ -303,14 +358,13 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
this.composition.off('add', this.subscribeToTelemetry, this);
|
this.composition.off('add', this.subscribeToTelemetry, this);
|
||||||
this.composition.off('remove', this.unsubscribeFromTelemetry, this);
|
this.composition.off('remove', this.unsubscribeFromTelemetry, this);
|
||||||
Object.values(this.subscriptions).forEach(unsubscribe => unsubscribe());
|
Object.values(this.subscriptions).forEach(unsubscribe => unsubscribe());
|
||||||
this.subscriptions = undefined;
|
delete this.subscriptions;
|
||||||
|
|
||||||
if(this.stopObservingForChanges) {
|
if(this.stopObservingForChanges) {
|
||||||
this.stopObservingForChanges();
|
this.stopObservingForChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.conditionClassCollection.forEach((condition) => {
|
this.conditionClassCollection.forEach((condition) => {
|
||||||
condition.off('conditionResultUpdated', this.handleConditionResult);
|
|
||||||
condition.destroy();
|
condition.destroy();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ describe('ConditionManager', () => {
|
|||||||
};
|
};
|
||||||
let mockComposition;
|
let mockComposition;
|
||||||
let loader;
|
let loader;
|
||||||
|
let mockTimeSystems;
|
||||||
|
|
||||||
function mockAngularComponents() {
|
function mockAngularComponents() {
|
||||||
let mockInjector = jasmine.createSpyObj('$injector', ['get']);
|
let mockInjector = jasmine.createSpyObj('$injector', ['get']);
|
||||||
@ -111,10 +112,16 @@ describe('ConditionManager', () => {
|
|||||||
openmct.objects.observe.and.returnValue(function () {});
|
openmct.objects.observe.and.returnValue(function () {});
|
||||||
openmct.objects.mutate.and.returnValue(function () {});
|
openmct.objects.mutate.and.returnValue(function () {});
|
||||||
|
|
||||||
|
mockTimeSystems = {
|
||||||
|
key: 'utc'
|
||||||
|
};
|
||||||
|
openmct.time = jasmine.createSpyObj('time', ['getAllTimeSystems']);
|
||||||
|
openmct.time.getAllTimeSystems.and.returnValue([mockTimeSystems]);
|
||||||
|
|
||||||
conditionMgr = new ConditionManager(conditionSetDomainObject, openmct);
|
conditionMgr = new ConditionManager(conditionSetDomainObject, openmct);
|
||||||
|
|
||||||
conditionMgr.on('conditionSetResultUpdated', mockListener);
|
conditionMgr.on('conditionSetResultUpdated', mockListener);
|
||||||
conditionMgr.on('broadcastTelemetry', mockListener);
|
conditionMgr.on('telemetryReceived', mockListener);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates a conditionCollection with a default condition', function () {
|
it('creates a conditionCollection with a default condition', function () {
|
||||||
|
@ -54,13 +54,22 @@ export default class ConditionSetMetadataProvider {
|
|||||||
return {
|
return {
|
||||||
values: this.getDomains().concat([
|
values: this.getDomains().concat([
|
||||||
{
|
{
|
||||||
name: 'Output',
|
key: "state",
|
||||||
key: 'output',
|
source: "output",
|
||||||
format: 'enum',
|
name: "State",
|
||||||
|
format: "enum",
|
||||||
enumerations: enumerations,
|
enumerations: enumerations,
|
||||||
hints: {
|
hints: {
|
||||||
range: 1
|
range: 1
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "output",
|
||||||
|
name: "Value",
|
||||||
|
format: "string",
|
||||||
|
hints: {
|
||||||
|
range: 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
};
|
};
|
||||||
|
@ -45,7 +45,7 @@ export default class ConditionSetTelemetryProvider {
|
|||||||
|
|
||||||
return conditionManager.requestLADConditionSetOutput()
|
return conditionManager.requestLADConditionSetOutput()
|
||||||
.then(latestOutput => {
|
.then(latestOutput => {
|
||||||
return latestOutput ? [latestOutput] : [];
|
return latestOutput;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,12 +25,12 @@ import {TRIGGER} from "./utils/constants";
|
|||||||
import TelemetryCriterion from "./criterion/TelemetryCriterion";
|
import TelemetryCriterion from "./criterion/TelemetryCriterion";
|
||||||
|
|
||||||
let openmct = {},
|
let openmct = {},
|
||||||
mockListener,
|
|
||||||
testConditionDefinition,
|
testConditionDefinition,
|
||||||
testTelemetryObject,
|
testTelemetryObject,
|
||||||
conditionObj,
|
conditionObj,
|
||||||
conditionManager,
|
conditionManager,
|
||||||
mockBroadcastTelemetry;
|
mockTelemetryReceived,
|
||||||
|
mockTimeSystems;
|
||||||
|
|
||||||
describe("The condition", function () {
|
describe("The condition", function () {
|
||||||
|
|
||||||
@ -38,27 +38,33 @@ describe("The condition", function () {
|
|||||||
conditionManager = jasmine.createSpyObj('conditionManager',
|
conditionManager = jasmine.createSpyObj('conditionManager',
|
||||||
['on']
|
['on']
|
||||||
);
|
);
|
||||||
mockBroadcastTelemetry = jasmine.createSpy('listener');
|
mockTelemetryReceived = jasmine.createSpy('listener');
|
||||||
conditionManager.on('broadcastTelemetry', mockBroadcastTelemetry);
|
conditionManager.on('telemetryReceived', mockTelemetryReceived);
|
||||||
|
|
||||||
mockListener = jasmine.createSpy('listener');
|
|
||||||
testTelemetryObject = {
|
testTelemetryObject = {
|
||||||
identifier:{ namespace: "", key: "test-object"},
|
identifier:{ namespace: "", key: "test-object"},
|
||||||
type: "test-object",
|
type: "test-object",
|
||||||
name: "Test Object",
|
name: "Test Object",
|
||||||
telemetry: {
|
telemetry: {
|
||||||
values: [{
|
values: [{
|
||||||
key: "some-key",
|
key: "value",
|
||||||
name: "Some attribute",
|
name: "Value",
|
||||||
|
hints: {
|
||||||
|
range: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "utc",
|
||||||
|
name: "Time",
|
||||||
|
format: "utc",
|
||||||
hints: {
|
hints: {
|
||||||
domain: 1
|
domain: 1
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "some-other-key",
|
key: "testSource",
|
||||||
name: "Another attribute",
|
source: "value",
|
||||||
hints: {
|
name: "Test",
|
||||||
range: 1
|
format: "string"
|
||||||
}
|
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -74,6 +80,12 @@ describe("The condition", function () {
|
|||||||
openmct.telemetry.subscribe.and.returnValue(function () {});
|
openmct.telemetry.subscribe.and.returnValue(function () {});
|
||||||
openmct.telemetry.getMetadata.and.returnValue(testTelemetryObject.telemetry.values);
|
openmct.telemetry.getMetadata.and.returnValue(testTelemetryObject.telemetry.values);
|
||||||
|
|
||||||
|
mockTimeSystems = {
|
||||||
|
key: 'utc'
|
||||||
|
};
|
||||||
|
openmct.time = jasmine.createSpyObj('time', ['getAllTimeSystems']);
|
||||||
|
openmct.time.getAllTimeSystems.and.returnValue([mockTimeSystems]);
|
||||||
|
|
||||||
testConditionDefinition = {
|
testConditionDefinition = {
|
||||||
id: '123-456',
|
id: '123-456',
|
||||||
configuration: {
|
configuration: {
|
||||||
@ -97,8 +109,6 @@ describe("The condition", function () {
|
|||||||
openmct,
|
openmct,
|
||||||
conditionManager
|
conditionManager
|
||||||
);
|
);
|
||||||
|
|
||||||
conditionObj.on('conditionUpdated', mockListener);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("generates criteria with the correct properties", function () {
|
it("generates criteria with the correct properties", function () {
|
||||||
@ -133,4 +143,38 @@ describe("The condition", function () {
|
|||||||
expect(result).toBeTrue();
|
expect(result).toBeTrue();
|
||||||
expect(conditionObj.criteria.length).toEqual(0);
|
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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -23,10 +23,14 @@
|
|||||||
import EventEmitter from 'EventEmitter';
|
import EventEmitter from 'EventEmitter';
|
||||||
|
|
||||||
export default class StyleRuleManager extends EventEmitter {
|
export default class StyleRuleManager extends EventEmitter {
|
||||||
constructor(styleConfiguration, openmct, callback) {
|
constructor(styleConfiguration, openmct, callback, suppressSubscriptionOnEdit) {
|
||||||
super();
|
super();
|
||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
if (suppressSubscriptionOnEdit) {
|
||||||
|
this.openmct.editor.on('isEditing', this.toggleSubscription.bind(this));
|
||||||
|
this.isEditing = this.openmct.editor.editing;
|
||||||
|
}
|
||||||
if (styleConfiguration) {
|
if (styleConfiguration) {
|
||||||
this.initialize(styleConfiguration);
|
this.initialize(styleConfiguration);
|
||||||
if (styleConfiguration.conditionSetIdentifier) {
|
if (styleConfiguration.conditionSetIdentifier) {
|
||||||
@ -37,9 +41,25 @@ export default class StyleRuleManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleSubscription(isEditing) {
|
||||||
|
this.isEditing = isEditing;
|
||||||
|
if (this.isEditing) {
|
||||||
|
if (this.stopProvidingTelemetry) {
|
||||||
|
this.stopProvidingTelemetry();
|
||||||
|
}
|
||||||
|
if (this.conditionSetIdentifier) {
|
||||||
|
this.applySelectedConditionStyle();
|
||||||
|
}
|
||||||
|
} else if (this.conditionSetIdentifier) {
|
||||||
|
this.subscribeToConditionSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
initialize(styleConfiguration) {
|
initialize(styleConfiguration) {
|
||||||
this.conditionSetIdentifier = styleConfiguration.conditionSetIdentifier;
|
this.conditionSetIdentifier = styleConfiguration.conditionSetIdentifier;
|
||||||
this.staticStyle = styleConfiguration.staticStyle;
|
this.staticStyle = styleConfiguration.staticStyle;
|
||||||
|
this.selectedConditionId = styleConfiguration.selectedConditionId;
|
||||||
|
this.defaultConditionId = styleConfiguration.defaultConditionId;
|
||||||
this.updateConditionStylesMap(styleConfiguration.styles || []);
|
this.updateConditionStylesMap(styleConfiguration.styles || []);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +74,7 @@ export default class StyleRuleManager extends EventEmitter {
|
|||||||
this.handleConditionSetResultUpdated(output[0]);
|
this.handleConditionSetResultUpdated(output[0]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.stopProvidingTelemetry = this.openmct.telemetry.subscribe(conditionSetDomainObject, output => this.handleConditionSetResultUpdated(output));
|
this.stopProvidingTelemetry = this.openmct.telemetry.subscribe(conditionSetDomainObject, this.handleConditionSetResultUpdated.bind(this));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,12 +86,16 @@ export default class StyleRuleManager extends EventEmitter {
|
|||||||
let isNewConditionSet = !this.conditionSetIdentifier ||
|
let isNewConditionSet = !this.conditionSetIdentifier ||
|
||||||
!this.openmct.objects.areIdsEqual(this.conditionSetIdentifier, styleConfiguration.conditionSetIdentifier);
|
!this.openmct.objects.areIdsEqual(this.conditionSetIdentifier, styleConfiguration.conditionSetIdentifier);
|
||||||
this.initialize(styleConfiguration);
|
this.initialize(styleConfiguration);
|
||||||
|
if (this.isEditing) {
|
||||||
|
this.applySelectedConditionStyle();
|
||||||
|
} else {
|
||||||
//Only resubscribe if the conditionSet has changed.
|
//Only resubscribe if the conditionSet has changed.
|
||||||
if (isNewConditionSet) {
|
if (isNewConditionSet) {
|
||||||
this.subscribeToConditionSet();
|
this.subscribeToConditionSet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateConditionStylesMap(conditionStyles) {
|
updateConditionStylesMap(conditionStyles) {
|
||||||
let conditionStyleMap = {};
|
let conditionStyleMap = {};
|
||||||
@ -103,13 +127,23 @@ export default class StyleRuleManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySelectedConditionStyle() {
|
||||||
|
const conditionId = this.selectedConditionId || this.defaultConditionId;
|
||||||
|
if (!conditionId) {
|
||||||
|
this.applyStaticStyle();
|
||||||
|
} else if (this.conditionalStyleMap[conditionId]) {
|
||||||
|
this.currentStyle = this.conditionalStyleMap[conditionId];
|
||||||
|
this.updateDomainObjectStyle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
applyStaticStyle() {
|
applyStaticStyle() {
|
||||||
if (this.staticStyle) {
|
if (this.staticStyle) {
|
||||||
this.currentStyle = this.staticStyle.style;
|
this.currentStyle = this.staticStyle.style;
|
||||||
} else {
|
} else {
|
||||||
if (this.currentStyle) {
|
if (this.currentStyle) {
|
||||||
Object.keys(this.currentStyle).forEach(key => {
|
Object.keys(this.currentStyle).forEach(key => {
|
||||||
this.currentStyle[key] = 'transparent';
|
this.currentStyle[key] = '__no_value';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,18 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="isEditing"
|
<div class="c-condition-h"
|
||||||
class="c-condition c-condition--edit js-condition-drag-wrapper"
|
:class="{ 'is-drag-target': draggingOver }"
|
||||||
|
@dragover.prevent
|
||||||
|
@drop.prevent="dropCondition($event, conditionIndex)"
|
||||||
|
@dragenter="dragEnter($event, conditionIndex)"
|
||||||
|
@dragleave="dragLeave($event, conditionIndex)"
|
||||||
>
|
>
|
||||||
|
<div class="c-condition-h__drop-target"></div>
|
||||||
|
<div v-if="isEditing"
|
||||||
|
:class="{'is-current': condition.id === currentConditionId}"
|
||||||
|
class="c-condition c-condition--edit"
|
||||||
|
>
|
||||||
<!-- Edit view -->
|
<!-- Edit view -->
|
||||||
<div class="c-condition__header">
|
<div class="c-condition__header">
|
||||||
<span class="c-condition__drag-grippy c-grippy c-grippy--vertical-drag"
|
<span class="c-condition__drag-grippy c-grippy c-grippy--vertical-drag"
|
||||||
@ -31,8 +40,7 @@
|
|||||||
:class="[{ 'is-enabled': !condition.isDefault }, { 'hide-nice': condition.isDefault }]"
|
:class="[{ 'is-enabled': !condition.isDefault }, { 'hide-nice': condition.isDefault }]"
|
||||||
:draggable="!condition.isDefault"
|
:draggable="!condition.isDefault"
|
||||||
@dragstart="dragStart"
|
@dragstart="dragStart"
|
||||||
@dragstop="dragStop"
|
@dragend="dragEnd"
|
||||||
@dragover.stop
|
|
||||||
></span>
|
></span>
|
||||||
|
|
||||||
<span class="c-condition__disclosure c-disclosure-triangle c-tree__item__view-control is-enabled"
|
<span class="c-condition__disclosure c-disclosure-triangle c-tree__item__view-control is-enabled"
|
||||||
@ -75,7 +83,7 @@
|
|||||||
<input v-model="condition.configuration.name"
|
<input v-model="condition.configuration.name"
|
||||||
class="t-condition-input__name"
|
class="t-condition-input__name"
|
||||||
type="text"
|
type="text"
|
||||||
@blur="persist"
|
@change="persist"
|
||||||
>
|
>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@ -98,7 +106,7 @@
|
|||||||
v-model="condition.configuration.output"
|
v-model="condition.configuration.output"
|
||||||
class="t-condition-name-input"
|
class="t-condition-name-input"
|
||||||
type="text"
|
type="text"
|
||||||
@blur="persist"
|
@change="persist"
|
||||||
>
|
>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
@ -157,10 +165,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else
|
<div v-else
|
||||||
class="c-condition c-condition--browse"
|
class="c-condition c-condition--browse"
|
||||||
>
|
:class="{'is-current': condition.id === currentConditionId}"
|
||||||
|
>
|
||||||
<!-- Browse view -->
|
<!-- Browse view -->
|
||||||
<div class="c-condition__header">
|
<div class="c-condition__header">
|
||||||
<span class="c-condition__name">
|
<span class="c-condition__name">
|
||||||
@ -175,6 +184,7 @@
|
|||||||
:condition="condition"
|
:condition="condition"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -191,6 +201,10 @@ export default {
|
|||||||
ConditionDescription
|
ConditionDescription
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
currentConditionId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
condition: {
|
condition: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
@ -207,6 +221,14 @@ export default {
|
|||||||
type: Array,
|
type: Array,
|
||||||
required: true,
|
required: true,
|
||||||
default: () => []
|
default: () => []
|
||||||
|
},
|
||||||
|
isDragging: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
moveIndex: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -217,8 +239,8 @@ export default {
|
|||||||
selectedOutputSelection: '',
|
selectedOutputSelection: '',
|
||||||
outputOptions: ['false', 'true', 'string'],
|
outputOptions: ['false', 'true', 'string'],
|
||||||
criterionIndex: 0,
|
criterionIndex: 0,
|
||||||
selectedTelemetryName: '',
|
draggingOver: false,
|
||||||
selectedFieldName: ''
|
isDefault: this.condition.isDefault
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -286,11 +308,39 @@ export default {
|
|||||||
dragStart(e) {
|
dragStart(e) {
|
||||||
e.dataTransfer.setData('dragging', e.target); // required for FF to initiate drag
|
e.dataTransfer.setData('dragging', e.target); // required for FF to initiate drag
|
||||||
e.dataTransfer.effectAllowed = "copyMove";
|
e.dataTransfer.effectAllowed = "copyMove";
|
||||||
e.dataTransfer.setDragImage(e.target.closest('.js-condition-drag-wrapper'), 0, 0);
|
e.dataTransfer.setDragImage(e.target.closest('.c-condition-h'), 0, 0);
|
||||||
this.$emit('setMoveIndex', this.conditionIndex);
|
this.$emit('setMoveIndex', this.conditionIndex);
|
||||||
},
|
},
|
||||||
dragStop(e) {
|
dragEnd(event) {
|
||||||
e.dataTransfer.clearData();
|
this.dragStarted = false;
|
||||||
|
event.dataTransfer.clearData();
|
||||||
|
this.$emit('dragComplete');
|
||||||
|
},
|
||||||
|
dropCondition(event, targetIndex) {
|
||||||
|
if (!this.isDragging) { return }
|
||||||
|
if (targetIndex > this.moveIndex) { targetIndex-- } // for 'downward' move
|
||||||
|
if (this.isValidTarget(targetIndex)) {
|
||||||
|
this.dragElement = undefined;
|
||||||
|
this.draggingOver = false;
|
||||||
|
this.$emit('dropCondition', targetIndex);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dragEnter(event, targetIndex) {
|
||||||
|
if (!this.isDragging) { return }
|
||||||
|
if (targetIndex > this.moveIndex) { targetIndex-- } // for 'downward' move
|
||||||
|
if (this.isValidTarget(targetIndex)) {
|
||||||
|
this.dragElement = event.target.parentElement;
|
||||||
|
this.draggingOver = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dragLeave(event) {
|
||||||
|
if (event.target.parentElement === this.dragElement) {
|
||||||
|
this.draggingOver = false;
|
||||||
|
this.dragElement = undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isValidTarget(targetIndex) {
|
||||||
|
return this.moveIndex !== targetIndex;
|
||||||
},
|
},
|
||||||
destroy() {
|
destroy() {
|
||||||
},
|
},
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section id="conditionCollection"
|
<section id="conditionCollection"
|
||||||
class="c-cs__conditions"
|
|
||||||
:class="{ 'is-expanded': expanded }"
|
:class="{ 'is-expanded': expanded }"
|
||||||
>
|
>
|
||||||
<div class="c-cs__header c-section__header">
|
<div class="c-cs__header c-section__header">
|
||||||
@ -53,30 +52,27 @@
|
|||||||
<span class="c-cs-button__label">Add Condition</span>
|
<span class="c-cs-button__label">Add Condition</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="c-cs__conditions-h">
|
<div class="c-cs__conditions-h"
|
||||||
<div v-for="(condition, index) in conditionCollection"
|
:class="{ 'is-active-dragging': isDragging }"
|
||||||
:key="condition.id"
|
|
||||||
class="c-condition-h"
|
|
||||||
>
|
>
|
||||||
<div v-if="isEditing"
|
<Condition v-for="(condition, index) in conditionCollection"
|
||||||
class="c-c__drag-ghost"
|
:key="condition.id"
|
||||||
@drop.prevent="dropCondition"
|
:condition="condition"
|
||||||
@dragenter="dragEnter"
|
:current-condition-id="currentConditionId"
|
||||||
@dragleave="dragLeave"
|
|
||||||
@dragover.prevent
|
|
||||||
></div>
|
|
||||||
<Condition :condition="condition"
|
|
||||||
:condition-index="index"
|
:condition-index="index"
|
||||||
:telemetry="telemetryObjs"
|
:telemetry="telemetryObjs"
|
||||||
:is-editing="isEditing"
|
:is-editing="isEditing"
|
||||||
|
:move-index="moveIndex"
|
||||||
|
:is-dragging="isDragging"
|
||||||
@updateCondition="updateCondition"
|
@updateCondition="updateCondition"
|
||||||
@removeCondition="removeCondition"
|
@removeCondition="removeCondition"
|
||||||
@cloneCondition="cloneCondition"
|
@cloneCondition="cloneCondition"
|
||||||
@setMoveIndex="setMoveIndex"
|
@setMoveIndex="setMoveIndex"
|
||||||
|
@dragComplete="dragComplete"
|
||||||
|
@dropCondition="dropCondition"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -109,9 +105,11 @@ export default {
|
|||||||
conditionResults: {},
|
conditionResults: {},
|
||||||
conditions: [],
|
conditions: [],
|
||||||
telemetryObjs: [],
|
telemetryObjs: [],
|
||||||
moveIndex: Number,
|
moveIndex: undefined,
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
defaultOutput: undefined
|
defaultOutput: undefined,
|
||||||
|
dragCounter: 0,
|
||||||
|
currentConditionId: ''
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -149,6 +147,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleConditionSetResultUpdated(data) {
|
handleConditionSetResultUpdated(data) {
|
||||||
|
this.currentConditionId = data.conditionId;
|
||||||
this.$emit('conditionSetResultUpdated', data)
|
this.$emit('conditionSetResultUpdated', data)
|
||||||
},
|
},
|
||||||
observeForChanges() {
|
observeForChanges() {
|
||||||
@ -166,9 +165,7 @@ export default {
|
|||||||
this.moveIndex = index;
|
this.moveIndex = index;
|
||||||
this.isDragging = true;
|
this.isDragging = true;
|
||||||
},
|
},
|
||||||
dropCondition(e) {
|
dropCondition(targetIndex) {
|
||||||
let targetIndex = Array.from(document.querySelectorAll('.c-c__drag-ghost')).indexOf(e.target);
|
|
||||||
if (targetIndex > this.moveIndex) { targetIndex-- } // for 'downward' move
|
|
||||||
const oldIndexArr = Object.keys(this.conditionCollection);
|
const oldIndexArr = Object.keys(this.conditionCollection);
|
||||||
const move = function (arr, old_index, new_index) {
|
const move = function (arr, old_index, new_index) {
|
||||||
while (old_index < 0) {
|
while (old_index < 0) {
|
||||||
@ -194,26 +191,16 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.reorder(reorderPlan);
|
this.reorder(reorderPlan);
|
||||||
|
},
|
||||||
e.target.classList.remove("dragging");
|
dragComplete() {
|
||||||
this.isDragging = false;
|
this.isDragging = false;
|
||||||
},
|
},
|
||||||
dragEnter(e) {
|
|
||||||
if (!this.isDragging) { return }
|
|
||||||
let targetIndex = Array.from(document.querySelectorAll('.c-c__drag-ghost')).indexOf(e.target);
|
|
||||||
if (targetIndex > this.moveIndex) { targetIndex-- } // for 'downward' move
|
|
||||||
if (this.moveIndex === targetIndex) { return }
|
|
||||||
e.target.classList.add("dragging");
|
|
||||||
},
|
|
||||||
dragLeave(e) {
|
|
||||||
e.target.classList.remove("dragging");
|
|
||||||
},
|
|
||||||
addTelemetryObject(domainObject) {
|
addTelemetryObject(domainObject) {
|
||||||
this.telemetryObjs.push(domainObject);
|
this.telemetryObjs.push(domainObject);
|
||||||
this.$emit('telemetryUpdated', this.telemetryObjs);
|
this.$emit('telemetryUpdated', this.telemetryObjs);
|
||||||
},
|
},
|
||||||
removeTelemetryObject(identifier) {
|
removeTelemetryObject(identifier) {
|
||||||
let index = _.findIndex(this.telemetryObjs, (obj) => {
|
let index = this.telemetryObjs.findIndex(obj => {
|
||||||
let objId = this.openmct.objects.makeKeyString(obj.identifier);
|
let objId = this.openmct.objects.makeKeyString(obj.identifier);
|
||||||
let id = this.openmct.objects.makeKeyString(identifier);
|
let id = this.openmct.objects.makeKeyString(identifier);
|
||||||
return objId === id;
|
return objId === id;
|
||||||
|
@ -23,30 +23,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="c-cs">
|
<div class="c-cs">
|
||||||
<section class="c-cs__current-output c-section">
|
<section class="c-cs__current-output c-section">
|
||||||
<div class="c-cs__header c-section__header">
|
|
||||||
<span class="c-cs__header-label c-section__label">Current Output</span>
|
|
||||||
</div>
|
|
||||||
<div class="c-cs__content c-cs__current-output-value">
|
<div class="c-cs__content c-cs__current-output-value">
|
||||||
|
<span class="c-cs__current-output-value__label">Current Output</span>
|
||||||
|
<span class="c-cs__current-output-value__value">
|
||||||
<template v-if="currentConditionOutput">
|
<template v-if="currentConditionOutput">
|
||||||
{{ currentConditionOutput }}
|
{{ currentConditionOutput }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ defaultConditionOutput }}
|
{{ defaultConditionOutput }}
|
||||||
</template>
|
</template>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<TestData :is-editing="isEditing"
|
<div class="c-cs__test-data-and-conditions-w">
|
||||||
|
<TestData class="c-cs__test-data"
|
||||||
|
:is-editing="isEditing"
|
||||||
:test-data="testData"
|
:test-data="testData"
|
||||||
:telemetry="telemetryObjs"
|
:telemetry="telemetryObjs"
|
||||||
@updateTestData="updateTestData"
|
@updateTestData="updateTestData"
|
||||||
/>
|
/>
|
||||||
<ConditionCollection
|
<ConditionCollection class="c-cs__conditions"
|
||||||
:is-editing="isEditing"
|
:is-editing="isEditing"
|
||||||
:test-data="testData"
|
:test-data="testData"
|
||||||
@conditionSetResultUpdated="updateCurrentOutput"
|
@conditionSetResultUpdated="updateCurrentOutput"
|
||||||
@updateDefaultOutput="updateDefaultOutput"
|
@updateDefaultOutput="updateDefaultOutput"
|
||||||
@telemetryUpdated="updateTelemetry"
|
@telemetryUpdated="updateTelemetry"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
0
src/plugins/condition/components/CurrentOutput.vue
Normal file
0
src/plugins/condition/components/CurrentOutput.vue
Normal file
@ -23,7 +23,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<section v-show="isEditing"
|
<section v-show="isEditing"
|
||||||
id="test-data"
|
id="test-data"
|
||||||
class="c-cs__test-data"
|
|
||||||
:class="{ 'is-expanded': expanded }"
|
:class="{ 'is-expanded': expanded }"
|
||||||
>
|
>
|
||||||
<div class="c-cs__header c-section__header">
|
<div class="c-cs__header c-section__header">
|
||||||
@ -37,7 +36,7 @@
|
|||||||
<div v-if="expanded"
|
<div v-if="expanded"
|
||||||
class="c-cs__content"
|
class="c-cs__content"
|
||||||
>
|
>
|
||||||
<div class="c-cdef__controls"
|
<div class="c-cs__test-data__controls c-cdef__controls"
|
||||||
:disabled="!telemetry.length"
|
:disabled="!telemetry.length"
|
||||||
>
|
>
|
||||||
<label class="c-toggle-switch">
|
<label class="c-toggle-switch">
|
||||||
@ -96,7 +95,7 @@
|
|||||||
>
|
>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<div class="c-test-datum__buttons">
|
<div class="c-cs-test__buttons">
|
||||||
<button class="c-click-icon c-test-data__duplicate-button icon-duplicate"
|
<button class="c-click-icon c-test-data__duplicate-button icon-duplicate"
|
||||||
title="Duplicate this test datum"
|
title="Duplicate this test datum"
|
||||||
@click="addTestInput(testInput)"
|
@click="addTestInput(testInput)"
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
.c-cs {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&__content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex: 0 1 auto;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
> * {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
overflow: hidden;
|
|
||||||
+ * {
|
|
||||||
margin-top: $interiorMarginSm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.c-button {
|
|
||||||
align-self: start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-editing & {
|
|
||||||
// Add some space to kick away from blue editing border indication
|
|
||||||
padding: $interiorMargin;
|
|
||||||
}
|
|
||||||
|
|
||||||
section {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__conditions-h {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
overflow: auto;
|
|
||||||
padding-right: $interiorMarginSm;
|
|
||||||
|
|
||||||
> * + * {
|
|
||||||
margin-top: $interiorMarginSm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__conditions {
|
|
||||||
> * + * {
|
|
||||||
margin-top: $interiorMarginSm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.hint {
|
|
||||||
padding: $interiorMarginSm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/************************** SPECIFIC ITEMS */
|
|
||||||
&__current-output-value {
|
|
||||||
font-size: 1.25em;
|
|
||||||
padding: $interiorMargin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************** TEST DATA */
|
|
||||||
.c-cs-tests {
|
|
||||||
flex: 0 1 auto;
|
|
||||||
overflow: auto;
|
|
||||||
padding-right: $interiorMarginSm;
|
|
||||||
|
|
||||||
> * + * {
|
|
||||||
margin-top: $interiorMarginSm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.c-cs-test {
|
|
||||||
> * {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
+ * {
|
|
||||||
margin-left: $interiorMargin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__controls {
|
|
||||||
display: flex;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
|
|
||||||
> * + * {
|
|
||||||
margin-left: $interiorMargin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,133 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
.c-condition,
|
|
||||||
.c-test-datum {
|
|
||||||
@include discreteItem();
|
|
||||||
display: flex;
|
|
||||||
padding: $interiorMargin;
|
|
||||||
|
|
||||||
&--edit {
|
|
||||||
line-height: 160%; // For layout when inputs wrap, like in criteria
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.c-condition {
|
|
||||||
flex-direction: column;
|
|
||||||
min-width: 400px;
|
|
||||||
|
|
||||||
> * + * {
|
|
||||||
margin-top: $interiorMarginSm;
|
|
||||||
}
|
|
||||||
&--browse {
|
|
||||||
.c-condition__summary {
|
|
||||||
border-top: 1px solid $colorInteriorBorder;
|
|
||||||
padding-top: $interiorMargin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************** HEADER */
|
|
||||||
&__header {
|
|
||||||
$h: 22px;
|
|
||||||
display: flex;
|
|
||||||
align-items: start;
|
|
||||||
align-content: stretch;
|
|
||||||
overflow: hidden;
|
|
||||||
min-height: $h;
|
|
||||||
line-height: $h;
|
|
||||||
|
|
||||||
> * {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
+ * {
|
|
||||||
margin-left: $interiorMarginSm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__drag-grippy {
|
|
||||||
transform: translateY(50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__name {
|
|
||||||
font-weight: bold;
|
|
||||||
align-self: baseline; // Fixes bold line-height offset problem
|
|
||||||
}
|
|
||||||
|
|
||||||
&__output,
|
|
||||||
&__summary {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************** CONDITION DEFINITION, EDITING */
|
|
||||||
.c-cdef {
|
|
||||||
display: grid;
|
|
||||||
grid-row-gap: $interiorMarginSm;
|
|
||||||
grid-column-gap: $interiorMargin;
|
|
||||||
grid-auto-columns: min-content 1fr max-content;
|
|
||||||
align-items: start;
|
|
||||||
min-width: 150px;
|
|
||||||
margin-left: 29px;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&__criteria,
|
|
||||||
&__match-and-criteria {
|
|
||||||
display: contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__label {
|
|
||||||
grid-column: 1;
|
|
||||||
text-align: right;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__separator {
|
|
||||||
grid-column: 1 / span 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__controls {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
align-items: flex-start;
|
|
||||||
grid-column: 2;
|
|
||||||
|
|
||||||
> * > * {
|
|
||||||
margin-right: $interiorMarginSm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__buttons {
|
|
||||||
grid-column: 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.c-c__drag-ghost {
|
|
||||||
width: 100%;
|
|
||||||
min-height: $interiorMarginSm;
|
|
||||||
|
|
||||||
&.dragging {
|
|
||||||
min-height: 5em;
|
|
||||||
background-color: lightblue;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
318
src/plugins/condition/components/conditionals.scss
Normal file
318
src/plugins/condition/components/conditionals.scss
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
/***************************** DRAGGING */
|
||||||
|
.is-active-dragging {
|
||||||
|
.c-condition-h__drop-target {
|
||||||
|
height: 3px;
|
||||||
|
margin-bottom: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-condition-h {
|
||||||
|
&__drop-target {
|
||||||
|
border-radius: $controlCr;
|
||||||
|
height: 0;
|
||||||
|
min-height: 0;
|
||||||
|
transition: background-color, height;
|
||||||
|
transition-duration: 150ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-drag-target {
|
||||||
|
.c-condition > * {
|
||||||
|
pointer-events: none; // Keeps the JS drop handler from being intercepted by internal elements
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-condition-h__drop-target {
|
||||||
|
background-color: rgba($colorKey, 0.7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-cs {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
/************************** CONDITION SET LAYOUT */
|
||||||
|
&__current-output {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__test-data-and-conditions-w {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__test-data,
|
||||||
|
&__conditions {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__test-data {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
max-height: 50%;
|
||||||
|
|
||||||
|
&.is-expanded {
|
||||||
|
margin-bottom: $interiorMargin * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__conditions {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
|
||||||
|
> * + * {
|
||||||
|
margin-top: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
+ * {
|
||||||
|
margin-top: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-button {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-editing & {
|
||||||
|
// Add some space to kick away from blue editing border indication
|
||||||
|
padding: $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__conditions-h {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: auto;
|
||||||
|
padding-right: $interiorMarginSm;
|
||||||
|
|
||||||
|
> * + * {
|
||||||
|
margin-top: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
padding: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************** SPECIFIC ITEMS */
|
||||||
|
&__current-output-value {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: baseline;
|
||||||
|
padding: 0 $interiorMargin $interiorMarginLg $interiorMargin;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
padding: $interiorMargin 0; // Must do this to align label and value
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
color: $colorInspectorSectionHeaderFg;
|
||||||
|
opacity: 0.9;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__value {
|
||||||
|
$p: $interiorMargin * 3;
|
||||||
|
font-size: 1.25em;
|
||||||
|
margin-left: $interiorMargin;
|
||||||
|
padding-left: $p;
|
||||||
|
padding-right: $p;
|
||||||
|
background: rgba(black, 0.2);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************** CONDITIONS AND TEST DATUM ELEMENTS */
|
||||||
|
.c-condition,
|
||||||
|
.c-test-datum {
|
||||||
|
@include discreteItem();
|
||||||
|
display: flex;
|
||||||
|
padding: $interiorMargin;
|
||||||
|
line-height: 170%; // Aligns text with controls like selects
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-cdef,
|
||||||
|
.c-cs-test {
|
||||||
|
&__controls {
|
||||||
|
display: flex;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
> * > * {
|
||||||
|
margin-right: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__buttons {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-condition {
|
||||||
|
border: 1px solid transparent;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 400px;
|
||||||
|
|
||||||
|
> * + * {
|
||||||
|
margin-top: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
&--browse {
|
||||||
|
.c-condition__summary {
|
||||||
|
border-top: 1px solid $colorInteriorBorder;
|
||||||
|
padding-top: $interiorMargin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************** HEADER */
|
||||||
|
&__header {
|
||||||
|
$h: 22px;
|
||||||
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
|
align-content: stretch;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: $h;
|
||||||
|
line-height: $h;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
+ * {
|
||||||
|
margin-left: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__drag-grippy {
|
||||||
|
transform: translateY(50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
font-weight: bold;
|
||||||
|
align-self: baseline; // Fixes bold line-height offset problem
|
||||||
|
}
|
||||||
|
|
||||||
|
&__output,
|
||||||
|
&__summary {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-current {
|
||||||
|
$c: $colorBodyFg;
|
||||||
|
border-color: rgba($c, 0.2);
|
||||||
|
background: rgba($c, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************** CONDITION DEFINITION, EDITING */
|
||||||
|
.c-cdef {
|
||||||
|
display: grid;
|
||||||
|
grid-row-gap: $interiorMarginSm;
|
||||||
|
grid-column-gap: $interiorMargin;
|
||||||
|
grid-auto-columns: min-content 1fr max-content;
|
||||||
|
align-items: start;
|
||||||
|
min-width: 150px;
|
||||||
|
margin-left: 29px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&__criteria,
|
||||||
|
&__match-and-criteria {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
grid-column: 1;
|
||||||
|
text-align: right;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__separator {
|
||||||
|
grid-column: 1 / span 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__controls {
|
||||||
|
align-items: flex-start;
|
||||||
|
grid-column: 2;
|
||||||
|
|
||||||
|
> * > * {
|
||||||
|
margin-right: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__buttons {
|
||||||
|
grid-column: 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-c__drag-ghost {
|
||||||
|
width: 100%;
|
||||||
|
min-height: $interiorMarginSm;
|
||||||
|
|
||||||
|
&.dragging {
|
||||||
|
min-height: 5em;
|
||||||
|
background-color: lightblue;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************** TEST DATA */
|
||||||
|
.c-cs__test-data {
|
||||||
|
&__controls {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-cs-tests {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
overflow: auto;
|
||||||
|
padding-right: $interiorMarginSm;
|
||||||
|
|
||||||
|
> * + * {
|
||||||
|
margin-top: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-cs-test {
|
||||||
|
> * + * {
|
||||||
|
margin-left: $interiorMargin;
|
||||||
|
}
|
||||||
|
}
|
@ -79,6 +79,8 @@
|
|||||||
<div v-for="(conditionStyle, index) in conditionalStyles"
|
<div v-for="(conditionStyle, index) in conditionalStyles"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="c-inspect-styles__condition"
|
class="c-inspect-styles__condition"
|
||||||
|
:class="{'is-current': conditionStyle.conditionId === selectedConditionId}"
|
||||||
|
@click="applySelectedConditionStyle(conditionStyle.conditionId)"
|
||||||
>
|
>
|
||||||
<condition-error :show-label="true"
|
<condition-error :show-label="true"
|
||||||
:condition="getCondition(conditionStyle.conditionId)"
|
:condition="getCondition(conditionStyle.conditionId)"
|
||||||
@ -105,6 +107,8 @@ import ConditionDescription from "@/plugins/condition/components/ConditionDescri
|
|||||||
import ConditionError from "@/plugins/condition/components/ConditionError.vue";
|
import ConditionError from "@/plugins/condition/components/ConditionError.vue";
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import PreviewAction from "@/ui/preview/PreviewAction.js";
|
import PreviewAction from "@/ui/preview/PreviewAction.js";
|
||||||
|
import {getApplicableStylesForItem} from "@/plugins/condition/utils/styleUtils";
|
||||||
|
import isEmpty from 'lodash/isEmpty';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ConditionalStylesView',
|
name: 'ConditionalStylesView',
|
||||||
@ -115,24 +119,8 @@ export default {
|
|||||||
},
|
},
|
||||||
inject: [
|
inject: [
|
||||||
'openmct',
|
'openmct',
|
||||||
'domainObject'
|
'selection'
|
||||||
],
|
],
|
||||||
props: {
|
|
||||||
itemId: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
initialStyles: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
canHide: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
conditionalStyles: [],
|
conditionalStyles: [],
|
||||||
@ -141,13 +129,16 @@ export default {
|
|||||||
isEditing: this.openmct.editor.isEditing(),
|
isEditing: this.openmct.editor.isEditing(),
|
||||||
conditions: undefined,
|
conditions: undefined,
|
||||||
conditionsLoaded: false,
|
conditionsLoaded: false,
|
||||||
navigateToPath: ''
|
navigateToPath: '',
|
||||||
|
selectedConditionId: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.openmct.editor.off('isEditing', this.setEditState);
|
this.removeListeners();
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.itemId = '';
|
||||||
|
this.getDomainObjectFromSelection();
|
||||||
this.previewAction = new PreviewAction(this.openmct);
|
this.previewAction = new PreviewAction(this.openmct);
|
||||||
if (this.domainObject.configuration && this.domainObject.configuration.objectStyles) {
|
if (this.domainObject.configuration && this.domainObject.configuration.objectStyles) {
|
||||||
let objectStyles = this.itemId ? this.domainObject.configuration.objectStyles[this.itemId] : this.domainObject.configuration.objectStyles;
|
let objectStyles = this.itemId ? this.domainObject.configuration.objectStyles[this.itemId] : this.domainObject.configuration.objectStyles;
|
||||||
@ -162,6 +153,52 @@ export default {
|
|||||||
this.openmct.editor.on('isEditing', this.setEditState);
|
this.openmct.editor.on('isEditing', this.setEditState);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
isItemType(type, item) {
|
||||||
|
return item && (item.type === type);
|
||||||
|
},
|
||||||
|
getDomainObjectFromSelection() {
|
||||||
|
let layoutItem;
|
||||||
|
let domainObject;
|
||||||
|
|
||||||
|
if (this.selection[0].length > 1) {
|
||||||
|
//If there are more than 1 items in the this.selection[0] list, the first one could either be a sub domain object OR a layout drawing control.
|
||||||
|
//The second item in the this.selection[0] list is the container object (usually a layout)
|
||||||
|
layoutItem = this.selection[0][0].context.layoutItem;
|
||||||
|
const item = this.selection[0][0].context.item;
|
||||||
|
this.canHide = true;
|
||||||
|
if (item &&
|
||||||
|
(!layoutItem || (this.isItemType('subobject-view', layoutItem)))) {
|
||||||
|
domainObject = item;
|
||||||
|
} else {
|
||||||
|
domainObject = this.selection[0][1].context.item;
|
||||||
|
if (layoutItem) {
|
||||||
|
this.itemId = layoutItem.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
domainObject = this.selection[0][0].context.item;
|
||||||
|
}
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
this.initialStyles = getApplicableStylesForItem(domainObject, layoutItem);
|
||||||
|
this.$nextTick(() => {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
removeListeners() {
|
||||||
|
if (this.stopObserving) {
|
||||||
|
this.stopObserving();
|
||||||
|
}
|
||||||
|
if (this.stopObservingItems) {
|
||||||
|
this.stopObservingItems();
|
||||||
|
}
|
||||||
|
if (this.stopProvidingTelemetry) {
|
||||||
|
this.stopProvidingTelemetry();
|
||||||
|
}
|
||||||
|
},
|
||||||
initialize(conditionSetDomainObject) {
|
initialize(conditionSetDomainObject) {
|
||||||
//If there are new conditions in the conditionSet we need to set those styles to default
|
//If there are new conditions in the conditionSet we need to set those styles to default
|
||||||
this.conditionSetDomainObject = conditionSetDomainObject;
|
this.conditionSetDomainObject = conditionSetDomainObject;
|
||||||
@ -170,6 +207,13 @@ export default {
|
|||||||
},
|
},
|
||||||
setEditState(isEditing) {
|
setEditState(isEditing) {
|
||||||
this.isEditing = isEditing;
|
this.isEditing = isEditing;
|
||||||
|
if (this.isEditing) {
|
||||||
|
if (this.stopProvidingTelemetry) {
|
||||||
|
this.stopProvidingTelemetry();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.subscribeToConditionSet();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
addConditionSet() {
|
addConditionSet() {
|
||||||
let conditionSetDomainObject;
|
let conditionSetDomainObject;
|
||||||
@ -240,23 +284,64 @@ export default {
|
|||||||
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
|
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
|
||||||
if (this.itemId) {
|
if (this.itemId) {
|
||||||
domainObjectStyles[this.itemId].conditionSetIdentifier = undefined;
|
domainObjectStyles[this.itemId].conditionSetIdentifier = undefined;
|
||||||
|
domainObjectStyles[this.itemId].selectedConditionId = undefined;
|
||||||
|
domainObjectStyles[this.itemId].defaultConditionId = undefined;
|
||||||
delete domainObjectStyles[this.itemId].conditionSetIdentifier;
|
delete domainObjectStyles[this.itemId].conditionSetIdentifier;
|
||||||
domainObjectStyles[this.itemId].styles = undefined;
|
domainObjectStyles[this.itemId].styles = undefined;
|
||||||
delete domainObjectStyles[this.itemId].styles;
|
delete domainObjectStyles[this.itemId].styles;
|
||||||
if (_.isEmpty(domainObjectStyles[this.itemId])) {
|
if (isEmpty(domainObjectStyles[this.itemId])) {
|
||||||
delete domainObjectStyles[this.itemId];
|
delete domainObjectStyles[this.itemId];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
domainObjectStyles.conditionSetIdentifier = undefined;
|
domainObjectStyles.conditionSetIdentifier = undefined;
|
||||||
|
domainObjectStyles.selectedConditionId = undefined;
|
||||||
|
domainObjectStyles.defaultConditionId = undefined;
|
||||||
delete domainObjectStyles.conditionSetIdentifier;
|
delete domainObjectStyles.conditionSetIdentifier;
|
||||||
domainObjectStyles.styles = undefined;
|
domainObjectStyles.styles = undefined;
|
||||||
delete domainObjectStyles.styles;
|
delete domainObjectStyles.styles;
|
||||||
}
|
}
|
||||||
if (_.isEmpty(domainObjectStyles)) {
|
if (isEmpty(domainObjectStyles)) {
|
||||||
domainObjectStyles = undefined;
|
domainObjectStyles = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.persist(domainObjectStyles);
|
this.persist(domainObjectStyles);
|
||||||
|
if (this.stopProvidingTelemetry) {
|
||||||
|
this.stopProvidingTelemetry();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateDomainObjectItemStyles(newItems) {
|
||||||
|
//check that all items that have been styles still exist. Otherwise delete those styles
|
||||||
|
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
|
||||||
|
let itemsToRemove = [];
|
||||||
|
let keys = Object.keys(domainObjectStyles);
|
||||||
|
//TODO: Need an easier way to find which properties are itemIds
|
||||||
|
keys.forEach((key) => {
|
||||||
|
const keyIsItemId = (key !== 'styles') &&
|
||||||
|
(key !== 'staticStyle') &&
|
||||||
|
(key !== 'defaultConditionId') &&
|
||||||
|
(key !== 'selectedConditionId') &&
|
||||||
|
(key !== 'conditionSetIdentifier');
|
||||||
|
if (keyIsItemId) {
|
||||||
|
if (!(newItems.find(item => item.id === key))) {
|
||||||
|
itemsToRemove.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (itemsToRemove.length) {
|
||||||
|
this.removeItemStyles(itemsToRemove, domainObjectStyles);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeItemStyles(itemIds, domainObjectStyles) {
|
||||||
|
itemIds.forEach(itemId => {
|
||||||
|
if (domainObjectStyles[itemId]) {
|
||||||
|
domainObjectStyles[itemId] = undefined;
|
||||||
|
delete domainObjectStyles[this.itemId];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (isEmpty(domainObjectStyles)) {
|
||||||
|
domainObjectStyles = undefined;
|
||||||
|
}
|
||||||
|
this.persist(domainObjectStyles);
|
||||||
},
|
},
|
||||||
initializeConditionalStyles() {
|
initializeConditionalStyles() {
|
||||||
if (!this.conditions) {
|
if (!this.conditions) {
|
||||||
@ -264,6 +349,9 @@ export default {
|
|||||||
}
|
}
|
||||||
let conditionalStyles = [];
|
let conditionalStyles = [];
|
||||||
this.conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
|
this.conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
|
||||||
|
if (conditionConfiguration.isDefault) {
|
||||||
|
this.selectedConditionId = conditionConfiguration.id;
|
||||||
|
}
|
||||||
this.conditions[conditionConfiguration.id] = conditionConfiguration;
|
this.conditions[conditionConfiguration.id] = conditionConfiguration;
|
||||||
let foundStyle = this.findStyleByConditionId(conditionConfiguration.id);
|
let foundStyle = this.findStyleByConditionId(conditionConfiguration.id);
|
||||||
if (foundStyle) {
|
if (foundStyle) {
|
||||||
@ -279,13 +367,39 @@ export default {
|
|||||||
//we're doing this so that we remove styles for any conditions that have been removed from the condition set
|
//we're doing this so that we remove styles for any conditions that have been removed from the condition set
|
||||||
this.conditionalStyles = conditionalStyles;
|
this.conditionalStyles = conditionalStyles;
|
||||||
this.conditionsLoaded = true;
|
this.conditionsLoaded = true;
|
||||||
this.persist(this.getDomainObjectConditionalStyle());
|
this.persist(this.getDomainObjectConditionalStyle(this.selectedConditionId));
|
||||||
|
if (!this.isEditing) {
|
||||||
|
this.subscribeToConditionSet();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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 : '';
|
||||||
},
|
},
|
||||||
initializeStaticStyle(objectStyles) {
|
initializeStaticStyle(objectStyles) {
|
||||||
let staticStyle = objectStyles && objectStyles.staticStyle;
|
let staticStyle = objectStyles && objectStyles.staticStyle;
|
||||||
this.staticStyle = staticStyle || {
|
if (staticStyle) {
|
||||||
|
this.staticStyle = {
|
||||||
|
style: Object.assign({}, this.initialStyles, staticStyle.style)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.staticStyle = {
|
||||||
style: Object.assign({}, this.initialStyles)
|
style: Object.assign({}, this.initialStyles)
|
||||||
};
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
findStyleByConditionId(id) {
|
findStyleByConditionId(id) {
|
||||||
return this.conditionalStyles.find(conditionalStyle => conditionalStyle.conditionId === id);
|
return this.conditionalStyles.find(conditionalStyle => conditionalStyle.conditionId === id);
|
||||||
@ -298,14 +412,19 @@ export default {
|
|||||||
let found = this.findStyleByConditionId(conditionStyle.conditionId);
|
let found = this.findStyleByConditionId(conditionStyle.conditionId);
|
||||||
if (found) {
|
if (found) {
|
||||||
found.style = conditionStyle.style;
|
found.style = conditionStyle.style;
|
||||||
|
this.selectedConditionId = found.conditionId;
|
||||||
this.persist(this.getDomainObjectConditionalStyle());
|
this.persist(this.getDomainObjectConditionalStyle());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getDomainObjectConditionalStyle() {
|
getDomainObjectConditionalStyle(defaultConditionId) {
|
||||||
let objectStyle = {
|
let objectStyle = {
|
||||||
styles: this.conditionalStyles,
|
styles: this.conditionalStyles,
|
||||||
staticStyle: this.staticStyle
|
staticStyle: this.staticStyle,
|
||||||
|
selectedConditionId: this.selectedConditionId
|
||||||
};
|
};
|
||||||
|
if (defaultConditionId) {
|
||||||
|
objectStyle.defaultConditionId = defaultConditionId;
|
||||||
|
}
|
||||||
if (this.conditionSetDomainObject) {
|
if (this.conditionSetDomainObject) {
|
||||||
objectStyle.conditionSetIdentifier = this.conditionSetDomainObject.identifier;
|
objectStyle.conditionSetIdentifier = this.conditionSetDomainObject.identifier;
|
||||||
}
|
}
|
||||||
@ -327,6 +446,10 @@ export default {
|
|||||||
getCondition(id) {
|
getCondition(id) {
|
||||||
return this.conditions ? this.conditions[id] : {};
|
return this.conditions ? this.conditions[id] : {};
|
||||||
},
|
},
|
||||||
|
applySelectedConditionStyle(conditionId) {
|
||||||
|
this.selectedConditionId = conditionId;
|
||||||
|
this.persist(this.getDomainObjectConditionalStyle());
|
||||||
|
},
|
||||||
persist(style) {
|
persist(style) {
|
||||||
this.openmct.objects.mutate(this.domainObject, 'configuration.objectStyles', style);
|
this.openmct.objects.mutate(this.domainObject, 'configuration.objectStyles', style);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,270 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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 class="c-inspect-styles__header">
|
||||||
|
Object Style
|
||||||
|
</div>
|
||||||
|
<div class="c-inspect-styles__content">
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
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',
|
||||||
|
components: {
|
||||||
|
StyleEditor
|
||||||
|
},
|
||||||
|
inject: [
|
||||||
|
'openmct',
|
||||||
|
'selection'
|
||||||
|
],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
staticStyle: undefined,
|
||||||
|
isEditing: this.openmct.editor.isEditing(),
|
||||||
|
mixedStyles: [],
|
||||||
|
isStaticAndConditionalStyles: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.removeListeners();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.items = [];
|
||||||
|
this.previewAction = new PreviewAction(this.openmct);
|
||||||
|
this.getObjectsAndItemsFromSelection();
|
||||||
|
this.initializeStaticStyle();
|
||||||
|
this.openmct.editor.on('isEditing', this.setEditState);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
isItemType(type, item) {
|
||||||
|
return item && (item.type === type);
|
||||||
|
},
|
||||||
|
hasConditionalStyles(domainObject, id) {
|
||||||
|
return getConditionalStyleForItem(domainObject, id) !== undefined;
|
||||||
|
},
|
||||||
|
getObjectsAndItemsFromSelection() {
|
||||||
|
let domainObject;
|
||||||
|
let subObjects = [];
|
||||||
|
|
||||||
|
//multiple selection
|
||||||
|
let itemInitialStyles = [];
|
||||||
|
let itemStyle;
|
||||||
|
this.selection.forEach((selectionItem) => {
|
||||||
|
const item = selectionItem[0].context.item;
|
||||||
|
const layoutItem = selectionItem[0].context.layoutItem;
|
||||||
|
if (item && this.isItemType('subobject-view', layoutItem)) {
|
||||||
|
subObjects.push(item);
|
||||||
|
itemStyle = getApplicableStylesForItem(item);
|
||||||
|
if (!this.isStaticAndConditionalStyles) {
|
||||||
|
this.isStaticAndConditionalStyles = this.hasConditionalStyles(item);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
domainObject = selectionItem[1].context.item;
|
||||||
|
itemStyle = getApplicableStylesForItem(domainObject, layoutItem || item);
|
||||||
|
this.items.push({
|
||||||
|
id: layoutItem.id,
|
||||||
|
applicableStyles: itemStyle
|
||||||
|
});
|
||||||
|
if (!this.isStaticAndConditionalStyles) {
|
||||||
|
this.isStaticAndConditionalStyles = this.hasConditionalStyles(domainObject, layoutItem.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itemInitialStyles.push(itemStyle);
|
||||||
|
});
|
||||||
|
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) {
|
||||||
|
//check that all items that have been styles still exist. Otherwise delete those styles
|
||||||
|
let keys = Object.keys(this.domainObject.configuration.objectStyles || {});
|
||||||
|
keys.forEach((key) => {
|
||||||
|
if ((key !== 'styles') &&
|
||||||
|
(key !== 'staticStyle') &&
|
||||||
|
(key !== 'conditionSetIdentifier')) {
|
||||||
|
if (!(newItems.find(item => item.id === key))) {
|
||||||
|
this.removeItemStyles(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
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, '*', function (newObject) {
|
||||||
|
this.domainObjectsById[id] = JSON.parse(JSON.stringify(newObject));
|
||||||
|
}.bind(this));
|
||||||
|
this.unObserveObjects.push(unobserveObject);
|
||||||
|
},
|
||||||
|
removeListeners() {
|
||||||
|
if (this.stopObserving) {
|
||||||
|
this.stopObserving();
|
||||||
|
}
|
||||||
|
if (this.stopObservingItems) {
|
||||||
|
this.stopObservingItems();
|
||||||
|
}
|
||||||
|
if (this.unObserveObjects) {
|
||||||
|
this.unObserveObjects.forEach((unObserveObject) => {
|
||||||
|
unObserveObject();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.unObserveObjects = [];
|
||||||
|
},
|
||||||
|
removeItemStyles(itemId) {
|
||||||
|
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
|
||||||
|
if (itemId && domainObjectStyles[itemId]) {
|
||||||
|
domainObjectStyles[itemId] = undefined;
|
||||||
|
delete domainObjectStyles[this.itemId];
|
||||||
|
|
||||||
|
if (isEmpty(domainObjectStyles)) {
|
||||||
|
domainObjectStyles = undefined;
|
||||||
|
}
|
||||||
|
this.persist(this.domainObject, domainObjectStyles);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeConditionalStyles(domainObjectStyles, itemId) {
|
||||||
|
if (itemId) {
|
||||||
|
domainObjectStyles[itemId].conditionSetIdentifier = undefined;
|
||||||
|
delete domainObjectStyles[itemId].conditionSetIdentifier;
|
||||||
|
domainObjectStyles[itemId].styles = undefined;
|
||||||
|
delete domainObjectStyles[itemId].styles;
|
||||||
|
} else {
|
||||||
|
domainObjectStyles.conditionSetIdentifier = undefined;
|
||||||
|
delete domainObjectStyles.conditionSetIdentifier;
|
||||||
|
domainObjectStyles.styles = undefined;
|
||||||
|
delete domainObjectStyles.styles;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setEditState(isEditing) {
|
||||||
|
this.isEditing = isEditing;
|
||||||
|
},
|
||||||
|
initializeStaticStyle() {
|
||||||
|
this.staticStyle = {
|
||||||
|
style: Object.assign({}, this.initialStyles)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
updateStaticStyle(staticStyle, property) {
|
||||||
|
//update the static style for each of the layoutItems as well as each sub object item
|
||||||
|
this.staticStyle = staticStyle;
|
||||||
|
this.persist(this.domainObject, this.getDomainObjectStyle(this.domainObject, property, this.items));
|
||||||
|
if (this.domainObjectsById) {
|
||||||
|
const keys = Object.keys(this.domainObjectsById);
|
||||||
|
keys.forEach(key => {
|
||||||
|
let domainObject = this.domainObjectsById[key];
|
||||||
|
this.persist(domainObject, this.getDomainObjectStyle(domainObject, property));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.isStaticAndConditionalStyles = false;
|
||||||
|
let foundIndex = this.mixedStyles.indexOf(property);
|
||||||
|
if (foundIndex > -1) {
|
||||||
|
this.mixedStyles.splice(foundIndex, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getDomainObjectStyle(domainObject, property, items) {
|
||||||
|
let domainObjectStyles = (domainObject.configuration && domainObject.configuration.objectStyles) || {};
|
||||||
|
|
||||||
|
if (items) {
|
||||||
|
items.forEach(item => {
|
||||||
|
let itemStaticStyle = {};
|
||||||
|
if (domainObjectStyles[item.id] && domainObjectStyles[item.id].staticStyle) {
|
||||||
|
itemStaticStyle = domainObjectStyles[item.id].staticStyle.style;
|
||||||
|
}
|
||||||
|
Object.keys(item.applicableStyles).forEach(key => {
|
||||||
|
if (property === key) {
|
||||||
|
itemStaticStyle[key] = this.staticStyle.style[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (this.isStaticAndConditionalStyles) {
|
||||||
|
this.removeConditionalStyles(domainObjectStyles, item.id);
|
||||||
|
}
|
||||||
|
if (isEmpty(itemStaticStyle)) {
|
||||||
|
itemStaticStyle = undefined;
|
||||||
|
domainObjectStyles[item.id] = undefined;
|
||||||
|
} else {
|
||||||
|
domainObjectStyles[item.id] = Object.assign({}, { staticStyle: { style: itemStaticStyle } });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (!domainObjectStyles.staticStyle) {
|
||||||
|
domainObjectStyles.staticStyle = {
|
||||||
|
style: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.isStaticAndConditionalStyles) {
|
||||||
|
this.removeConditionalStyles(domainObjectStyles);
|
||||||
|
}
|
||||||
|
domainObjectStyles.staticStyle.style[property] = this.staticStyle.style[property];
|
||||||
|
}
|
||||||
|
|
||||||
|
return domainObjectStyles;
|
||||||
|
},
|
||||||
|
|
||||||
|
persist(domainObject, style) {
|
||||||
|
this.openmct.objects.mutate(domainObject, 'configuration.objectStyles', style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -22,38 +22,41 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="c-style">
|
<div class="c-style">
|
||||||
<span class="c-style-thumb"
|
<span :class="[
|
||||||
:class="{ 'is-style-invisible': styleItem.style.isStyleInvisible }"
|
{ 'is-style-invisible': styleItem.style.isStyleInvisible },
|
||||||
:style="[styleItem.style.imageUrl ? { backgroundImage:'url(' + styleItem.style.imageUrl + ')'} : styleItem.style ]"
|
{ 'c-style-thumb--mixed': mixedStyles.indexOf('backgroundColor') > -1 }
|
||||||
|
]"
|
||||||
|
:style="[styleItem.style.imageUrl ? { backgroundImage:'url(' + styleItem.style.imageUrl + ')'} : itemStyle ]"
|
||||||
|
class="c-style-thumb"
|
||||||
>
|
>
|
||||||
<span class="c-style-thumb__text"
|
<span class="c-style-thumb__text"
|
||||||
:class="{ 'hide-nice': !styleItem.style.color }"
|
:class="{ 'hide-nice': !hasProperty(styleItem.style.color) }"
|
||||||
>
|
>
|
||||||
ABC
|
ABC
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="c-toolbar">
|
<span class="c-toolbar">
|
||||||
<toolbar-color-picker v-if="styleItem.style.border"
|
<toolbar-color-picker v-if="hasProperty(styleItem.style.border)"
|
||||||
class="c-style__toolbar-button--border-color u-menu-to--center"
|
class="c-style__toolbar-button--border-color u-menu-to--center"
|
||||||
:options="borderColorOption"
|
:options="borderColorOption"
|
||||||
@change="updateStyleValue"
|
@change="updateStyleValue"
|
||||||
/>
|
/>
|
||||||
<toolbar-color-picker v-if="styleItem.style.backgroundColor"
|
<toolbar-color-picker v-if="hasProperty(styleItem.style.backgroundColor)"
|
||||||
class="c-style__toolbar-button--background-color u-menu-to--center"
|
class="c-style__toolbar-button--background-color u-menu-to--center"
|
||||||
:options="backgroundColorOption"
|
:options="backgroundColorOption"
|
||||||
@change="updateStyleValue"
|
@change="updateStyleValue"
|
||||||
/>
|
/>
|
||||||
<toolbar-color-picker v-if="styleItem.style.color"
|
<toolbar-color-picker v-if="hasProperty(styleItem.style.color)"
|
||||||
class="c-style__toolbar-button--color u-menu-to--center"
|
class="c-style__toolbar-button--color u-menu-to--center"
|
||||||
:options="colorOption"
|
:options="colorOption"
|
||||||
@change="updateStyleValue"
|
@change="updateStyleValue"
|
||||||
/>
|
/>
|
||||||
<toolbar-button v-if="styleItem.style.imageUrl !== undefined"
|
<toolbar-button v-if="hasProperty(styleItem.style.imageUrl)"
|
||||||
class="c-style__toolbar-button--image-url"
|
class="c-style__toolbar-button--image-url"
|
||||||
:options="imageUrlOption"
|
:options="imageUrlOption"
|
||||||
@change="updateStyleValue"
|
@change="updateStyleValue"
|
||||||
/>
|
/>
|
||||||
<toolbar-toggle-button v-if="styleItem.style.isStyleInvisible !== undefined"
|
<toolbar-toggle-button v-if="hasProperty(styleItem.style.isStyleInvisible)"
|
||||||
class="c-style__toolbar-button--toggle-visible"
|
class="c-style__toolbar-button--toggle-visible"
|
||||||
:options="isStyleInvisibleOption"
|
:options="isStyleInvisibleOption"
|
||||||
@change="updateStyleValue"
|
@change="updateStyleValue"
|
||||||
@ -68,6 +71,7 @@ import ToolbarColorPicker from "@/ui/toolbar/components/toolbar-color-picker.vue
|
|||||||
import ToolbarButton from "@/ui/toolbar/components/toolbar-button.vue";
|
import ToolbarButton from "@/ui/toolbar/components/toolbar-button.vue";
|
||||||
import ToolbarToggleButton from "@/ui/toolbar/components/toolbar-toggle-button.vue";
|
import ToolbarToggleButton from "@/ui/toolbar/components/toolbar-toggle-button.vue";
|
||||||
import {STYLE_CONSTANTS} from "@/plugins/condition/utils/constants";
|
import {STYLE_CONSTANTS} from "@/plugins/condition/utils/constants";
|
||||||
|
import {getStylesWithoutNoneValue} from "@/plugins/condition/utils/styleUtils";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'StyleEditor',
|
name: 'StyleEditor',
|
||||||
@ -83,37 +87,52 @@ export default {
|
|||||||
isEditing: {
|
isEditing: {
|
||||||
type: Boolean
|
type: Boolean
|
||||||
},
|
},
|
||||||
|
mixedStyles: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
styleItem: {
|
styleItem: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
itemStyle() {
|
||||||
|
return getStylesWithoutNoneValue(this.styleItem.style);
|
||||||
|
},
|
||||||
borderColorOption() {
|
borderColorOption() {
|
||||||
|
let value = this.styleItem.style.border.replace('1px solid ', '');
|
||||||
return {
|
return {
|
||||||
icon: 'icon-line-horz',
|
icon: 'icon-line-horz',
|
||||||
title: STYLE_CONSTANTS.borderColorTitle,
|
title: STYLE_CONSTANTS.borderColorTitle,
|
||||||
value: this.styleItem.style.border.replace('1px solid ', ''),
|
value: this.normalizeValueForSwatch(value),
|
||||||
property: 'border',
|
property: 'border',
|
||||||
isEditing: this.isEditing
|
isEditing: this.isEditing,
|
||||||
|
nonSpecific: this.mixedStyles.indexOf('border') > -1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
backgroundColorOption() {
|
backgroundColorOption() {
|
||||||
|
let value = this.styleItem.style.backgroundColor;
|
||||||
return {
|
return {
|
||||||
icon: 'icon-paint-bucket',
|
icon: 'icon-paint-bucket',
|
||||||
title: STYLE_CONSTANTS.backgroundColorTitle,
|
title: STYLE_CONSTANTS.backgroundColorTitle,
|
||||||
value: this.styleItem.style.backgroundColor,
|
value: this.normalizeValueForSwatch(value),
|
||||||
property: 'backgroundColor',
|
property: 'backgroundColor',
|
||||||
isEditing: this.isEditing
|
isEditing: this.isEditing,
|
||||||
|
nonSpecific: this.mixedStyles.indexOf('backgroundColor') > -1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colorOption() {
|
colorOption() {
|
||||||
|
let value = this.styleItem.style.color;
|
||||||
return {
|
return {
|
||||||
icon: 'icon-font',
|
icon: 'icon-font',
|
||||||
title: STYLE_CONSTANTS.textColorTitle,
|
title: STYLE_CONSTANTS.textColorTitle,
|
||||||
value: this.styleItem.style.color,
|
value: this.normalizeValueForSwatch(value),
|
||||||
property: 'color',
|
property: 'color',
|
||||||
isEditing: this.isEditing
|
isEditing: this.isEditing,
|
||||||
|
nonSpecific: this.mixedStyles.indexOf('color') > -1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
imageUrlOption() {
|
imageUrlOption() {
|
||||||
@ -138,7 +157,8 @@ export default {
|
|||||||
property: 'imageUrl',
|
property: 'imageUrl',
|
||||||
formKeys: ['url'],
|
formKeys: ['url'],
|
||||||
value: {url: this.styleItem.style.imageUrl},
|
value: {url: this.styleItem.style.imageUrl},
|
||||||
isEditing: this.isEditing
|
isEditing: this.isEditing,
|
||||||
|
nonSpecific: this.mixedStyles.indexOf('imageUrl') > -1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isStyleInvisibleOption() {
|
isStyleInvisibleOption() {
|
||||||
@ -163,7 +183,23 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
hasProperty(property) {
|
||||||
|
return property !== undefined;
|
||||||
|
},
|
||||||
|
normalizeValueForSwatch(value) {
|
||||||
|
if (value && value.indexOf('__no_value') > -1) {
|
||||||
|
return value.replace('__no_value', 'transparent');
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
normalizeValueForStyle(value) {
|
||||||
|
if (value && value === 'transparent') {
|
||||||
|
return '__no_value';
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
updateStyleValue(value, item) {
|
updateStyleValue(value, item) {
|
||||||
|
value = this.normalizeValueForStyle(value);
|
||||||
if (item.property === 'border') {
|
if (item.property === 'border') {
|
||||||
value = '1px solid ' + value;
|
value = '1px solid ' + value;
|
||||||
}
|
}
|
||||||
@ -172,7 +208,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.styleItem.style[item.property] = value;
|
this.styleItem.style[item.property] = value;
|
||||||
}
|
}
|
||||||
this.$emit('persist', this.styleItem);
|
this.$emit('persist', this.styleItem, item.property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
601
src/plugins/condition/components/inspector/StylesView.vue
Normal file
601
src/plugins/condition/components/inspector/StylesView.vue
Normal file
@ -0,0 +1,601 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="c-inspector__styles c-inspect-styles">
|
||||||
|
<div v-if="isStaticAndConditionalStyles"
|
||||||
|
class="c-inspect-styles__mixed-static-and-conditional u-alert u-alert--block u-alert--with-icon"
|
||||||
|
>
|
||||||
|
Your selection includes one or more items that use Conditional Styling. Applying a static style below will replace any Conditional Styling with the new choice.
|
||||||
|
</div>
|
||||||
|
<template v-if="!conditionSetDomainObject">
|
||||||
|
<div class="c-inspect-styles__header">
|
||||||
|
Object Style
|
||||||
|
</div>
|
||||||
|
<div class="c-inspect-styles__content">
|
||||||
|
<div v-if="staticStyle"
|
||||||
|
class="c-inspect-styles__style"
|
||||||
|
>
|
||||||
|
<style-editor class="c-inspect-styles__editor"
|
||||||
|
:style-item="staticStyle"
|
||||||
|
:is-editing="isEditing"
|
||||||
|
:mixed-styles="mixedStyles"
|
||||||
|
@persist="updateStaticStyle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
id="addConditionSet"
|
||||||
|
class="c-button c-button--major c-toggle-styling-button labeled"
|
||||||
|
@click="addConditionSet"
|
||||||
|
>
|
||||||
|
<span class="c-cs-button__label">Use Conditional Styling...</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="c-inspect-styles__header">
|
||||||
|
Conditional Object Styles
|
||||||
|
</div>
|
||||||
|
<div class="c-inspect-styles__content c-inspect-styles__condition-set">
|
||||||
|
<a v-if="conditionSetDomainObject"
|
||||||
|
class="c-object-label icon-conditional"
|
||||||
|
:href="navigateToPath"
|
||||||
|
@click="navigateOrPreview"
|
||||||
|
>
|
||||||
|
<span class="c-object-label__name">{{ conditionSetDomainObject.name }}</span>
|
||||||
|
</a>
|
||||||
|
<template v-if="isEditing">
|
||||||
|
<button
|
||||||
|
id="changeConditionSet"
|
||||||
|
class="c-button labeled"
|
||||||
|
@click="addConditionSet"
|
||||||
|
>
|
||||||
|
<span class="c-button__label">Change...</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="c-click-icon icon-x"
|
||||||
|
title="Remove conditional styles"
|
||||||
|
@click="removeConditionSet"
|
||||||
|
></button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="conditionsLoaded"
|
||||||
|
class="c-inspect-styles__conditions"
|
||||||
|
>
|
||||||
|
<div v-for="(conditionStyle, index) in conditionalStyles"
|
||||||
|
:key="index"
|
||||||
|
class="c-inspect-styles__condition"
|
||||||
|
:class="{'is-current': conditionStyle.conditionId === selectedConditionId}"
|
||||||
|
@click="applySelectedConditionStyle(conditionStyle.conditionId)"
|
||||||
|
>
|
||||||
|
<condition-error :show-label="true"
|
||||||
|
:condition="getCondition(conditionStyle.conditionId)"
|
||||||
|
/>
|
||||||
|
<condition-description :show-label="true"
|
||||||
|
:condition="getCondition(conditionStyle.conditionId)"
|
||||||
|
/>
|
||||||
|
<style-editor class="c-inspect-styles__editor"
|
||||||
|
:style-item="conditionStyle"
|
||||||
|
:is-editing="isEditing"
|
||||||
|
@persist="updateConditionalStyle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import StyleEditor from "./StyleEditor.vue";
|
||||||
|
import PreviewAction from "@/ui/preview/PreviewAction.js";
|
||||||
|
import { getApplicableStylesForItem, getConsolidatedStyleValues, getConditionSetIdentifierForItem } from "@/plugins/condition/utils/styleUtils";
|
||||||
|
import ConditionSetSelectorDialog from "@/plugins/condition/components/inspector/ConditionSetSelectorDialog.vue";
|
||||||
|
import ConditionError from "@/plugins/condition/components/ConditionError.vue";
|
||||||
|
import ConditionDescription from "@/plugins/condition/components/ConditionDescription.vue";
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'StylesView',
|
||||||
|
components: {
|
||||||
|
StyleEditor,
|
||||||
|
ConditionError,
|
||||||
|
ConditionDescription
|
||||||
|
},
|
||||||
|
inject: [
|
||||||
|
'openmct',
|
||||||
|
'selection'
|
||||||
|
],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
staticStyle: undefined,
|
||||||
|
isEditing: this.openmct.editor.isEditing(),
|
||||||
|
mixedStyles: [],
|
||||||
|
isStaticAndConditionalStyles: false,
|
||||||
|
conditionalStyles: [],
|
||||||
|
conditionSetDomainObject: undefined,
|
||||||
|
conditions: undefined,
|
||||||
|
conditionsLoaded: false,
|
||||||
|
navigateToPath: '',
|
||||||
|
selectedConditionId: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.removeListeners();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.items = [];
|
||||||
|
this.previewAction = new PreviewAction(this.openmct);
|
||||||
|
this.isMultipleSelection = this.selection.length > 1;
|
||||||
|
this.getObjectsAndItemsFromSelection();
|
||||||
|
if (!this.isMultipleSelection) {
|
||||||
|
let objectStyles = this.getObjectStyles();
|
||||||
|
this.initializeStaticStyle(objectStyles);
|
||||||
|
if (objectStyles && objectStyles.conditionSetIdentifier) {
|
||||||
|
this.openmct.objects.get(objectStyles.conditionSetIdentifier).then(this.initialize);
|
||||||
|
this.conditionalStyles = objectStyles.styles;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.initializeStaticStyle();
|
||||||
|
}
|
||||||
|
this.openmct.editor.on('isEditing', this.setEditState);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getObjectStyles() {
|
||||||
|
let objectStyles;
|
||||||
|
if (this.domainObjectsById) {
|
||||||
|
const domainObject = Object.values(this.domainObjectsById)[0];
|
||||||
|
if (domainObject.configuration && domainObject.configuration.objectStyles) {
|
||||||
|
objectStyles = domainObject.configuration.objectStyles;
|
||||||
|
}
|
||||||
|
} else if (this.items.length) {
|
||||||
|
const itemId = this.items[0].id;
|
||||||
|
if (this.domainObject.configuration && this.domainObject.configuration.objectStyles && this.domainObject.configuration.objectStyles[itemId]) {
|
||||||
|
objectStyles = this.domainObject.configuration.objectStyles[itemId];
|
||||||
|
}
|
||||||
|
} else if (this.domainObject.configuration && this.domainObject.configuration.objectStyles) {
|
||||||
|
objectStyles = this.domainObject.configuration.objectStyles;
|
||||||
|
}
|
||||||
|
return objectStyles;
|
||||||
|
},
|
||||||
|
setEditState(isEditing) {
|
||||||
|
this.isEditing = isEditing;
|
||||||
|
if (this.isEditing) {
|
||||||
|
if (this.stopProvidingTelemetry) {
|
||||||
|
this.stopProvidingTelemetry();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.subscribeToConditionSet();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enableConditionSetNav() {
|
||||||
|
this.openmct.objects.getOriginalPath(this.conditionSetDomainObject.identifier).then(
|
||||||
|
(objectPath) => {
|
||||||
|
this.objectPath = objectPath;
|
||||||
|
this.navigateToPath = '#/browse/' + this.objectPath
|
||||||
|
.map(o => o && this.openmct.objects.makeKeyString(o.identifier))
|
||||||
|
.reverse()
|
||||||
|
.join('/');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
navigateOrPreview(event) {
|
||||||
|
// If editing, display condition set in Preview overlay; otherwise nav to it while browsing
|
||||||
|
if (this.openmct.editor.isEditing()) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.previewAction.invoke(this.objectPath);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isItemType(type, item) {
|
||||||
|
return item && (item.type === type);
|
||||||
|
},
|
||||||
|
hasConditionalStyle(domainObject, layoutItem) {
|
||||||
|
const id = layoutItem ? layoutItem.id : undefined;
|
||||||
|
return getConditionSetIdentifierForItem(domainObject, id) !== undefined;
|
||||||
|
},
|
||||||
|
getObjectsAndItemsFromSelection() {
|
||||||
|
let domainObject;
|
||||||
|
let subObjects = [];
|
||||||
|
let itemsWithConditionalStyles = 0;
|
||||||
|
|
||||||
|
//multiple selection
|
||||||
|
let itemInitialStyles = [];
|
||||||
|
let itemStyle;
|
||||||
|
this.selection.forEach((selectionItem) => {
|
||||||
|
const item = selectionItem[0].context.item;
|
||||||
|
const layoutItem = selectionItem[0].context.layoutItem;
|
||||||
|
const isChildItem = selectionItem.length > 1;
|
||||||
|
if (!isChildItem) {
|
||||||
|
domainObject = item;
|
||||||
|
itemStyle = getApplicableStylesForItem(item);
|
||||||
|
if (this.hasConditionalStyle(item)) {
|
||||||
|
itemsWithConditionalStyles += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.canHide = true;
|
||||||
|
domainObject = selectionItem[1].context.item;
|
||||||
|
if (item && !layoutItem || this.isItemType('subobject-view', layoutItem)) {
|
||||||
|
subObjects.push(item);
|
||||||
|
itemStyle = getApplicableStylesForItem(item);
|
||||||
|
if (this.hasConditionalStyle(item)) {
|
||||||
|
itemsWithConditionalStyles += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
itemStyle = getApplicableStylesForItem(domainObject, layoutItem || item);
|
||||||
|
this.items.push({
|
||||||
|
id: layoutItem.id,
|
||||||
|
applicableStyles: itemStyle
|
||||||
|
});
|
||||||
|
if (this.hasConditionalStyle(item, layoutItem)) {
|
||||||
|
itemsWithConditionalStyles += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itemInitialStyles.push(itemStyle);
|
||||||
|
});
|
||||||
|
this.isStaticAndConditionalStyles = this.isMultipleSelection && itemsWithConditionalStyles;
|
||||||
|
const {styles, mixedStyles} = getConsolidatedStyleValues(itemInitialStyles);
|
||||||
|
this.initialStyles = styles;
|
||||||
|
this.mixedStyles = mixedStyles;
|
||||||
|
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
this.removeListeners();
|
||||||
|
if (this.domainObject) {
|
||||||
|
this.stopObserving = this.openmct.objects.observe(this.domainObject, '*', newDomainObject => this.domainObject = newDomainObject);
|
||||||
|
this.stopObservingItems = this.openmct.objects.observe(this.domainObject, 'configuration.items', this.updateDomainObjectItemStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
subObjects.forEach(this.registerListener);
|
||||||
|
},
|
||||||
|
updateDomainObjectItemStyles(newItems) {
|
||||||
|
let keys = Object.keys(this.domainObject.configuration.objectStyles || {});
|
||||||
|
keys.forEach((key) => {
|
||||||
|
if (this.isKeyItemId(key)) {
|
||||||
|
if (!(newItems.find(item => item.id === key))) {
|
||||||
|
this.removeItemStyles(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
isKeyItemId(key) {
|
||||||
|
return (key !== 'styles') &&
|
||||||
|
(key !== 'staticStyle') &&
|
||||||
|
(key !== 'defaultConditionId') &&
|
||||||
|
(key !== 'selectedConditionId') &&
|
||||||
|
(key !== 'conditionSetIdentifier');
|
||||||
|
},
|
||||||
|
registerListener(domainObject) {
|
||||||
|
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||||
|
|
||||||
|
if (!this.domainObjectsById) {
|
||||||
|
this.domainObjectsById = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.domainObjectsById[id]) {
|
||||||
|
this.domainObjectsById[id] = domainObject;
|
||||||
|
this.observeObject(domainObject, id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
observeObject(domainObject, id) {
|
||||||
|
let unobserveObject = this.openmct.objects.observe(domainObject, '*', (newObject) => {
|
||||||
|
this.domainObjectsById[id] = JSON.parse(JSON.stringify(newObject));
|
||||||
|
});
|
||||||
|
this.unObserveObjects.push(unobserveObject);
|
||||||
|
},
|
||||||
|
removeListeners() {
|
||||||
|
if (this.stopObserving) {
|
||||||
|
this.stopObserving();
|
||||||
|
}
|
||||||
|
if (this.stopObservingItems) {
|
||||||
|
this.stopObservingItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.stopProvidingTelemetry) {
|
||||||
|
this.stopProvidingTelemetry();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.unObserveObjects) {
|
||||||
|
this.unObserveObjects.forEach((unObserveObject) => {
|
||||||
|
unObserveObject();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.unObserveObjects = [];
|
||||||
|
},
|
||||||
|
subscribeToConditionSet() {
|
||||||
|
if (this.stopProvidingTelemetry) {
|
||||||
|
this.stopProvidingTelemetry();
|
||||||
|
}
|
||||||
|
if (this.conditionSetDomainObject) {
|
||||||
|
this.openmct.telemetry.request(this.conditionSetDomainObject)
|
||||||
|
.then(output => {
|
||||||
|
if (output && output.length) {
|
||||||
|
this.handleConditionSetResultUpdated(output[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.stopProvidingTelemetry = this.openmct.telemetry.subscribe(this.conditionSetDomainObject, this.handleConditionSetResultUpdated.bind(this));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleConditionSetResultUpdated(resultData) {
|
||||||
|
this.selectedConditionId = resultData ? resultData.conditionId : '';
|
||||||
|
},
|
||||||
|
initialize(conditionSetDomainObject) {
|
||||||
|
//If there are new conditions in the conditionSet we need to set those styles to default
|
||||||
|
this.conditionSetDomainObject = conditionSetDomainObject;
|
||||||
|
this.enableConditionSetNav();
|
||||||
|
this.initializeConditionalStyles();
|
||||||
|
},
|
||||||
|
initializeConditionalStyles() {
|
||||||
|
if (!this.conditions) {
|
||||||
|
this.conditions = {};
|
||||||
|
}
|
||||||
|
let conditionalStyles = [];
|
||||||
|
this.conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
|
||||||
|
if (conditionConfiguration.isDefault) {
|
||||||
|
this.selectedConditionId = conditionConfiguration.id;
|
||||||
|
}
|
||||||
|
this.conditions[conditionConfiguration.id] = conditionConfiguration;
|
||||||
|
let foundStyle = this.findStyleByConditionId(conditionConfiguration.id);
|
||||||
|
if (foundStyle) {
|
||||||
|
foundStyle.style = Object.assign((this.canHide ? { isStyleInvisible: '' } : {}), this.initialStyles, foundStyle.style);
|
||||||
|
conditionalStyles.push(foundStyle);
|
||||||
|
} else {
|
||||||
|
conditionalStyles.splice(index, 0, {
|
||||||
|
conditionId: conditionConfiguration.id,
|
||||||
|
style: Object.assign((this.canHide ? { isStyleInvisible: '' } : {}), this.initialStyles)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//we're doing this so that we remove styles for any conditions that have been removed from the condition set
|
||||||
|
this.conditionalStyles = conditionalStyles;
|
||||||
|
this.conditionsLoaded = true;
|
||||||
|
this.getAndPersistStyles(null, this.selectedConditionId);
|
||||||
|
if (!this.isEditing) {
|
||||||
|
this.subscribeToConditionSet();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//TODO: Double check how this works for single styles
|
||||||
|
initializeStaticStyle(objectStyles) {
|
||||||
|
let staticStyle = objectStyles && objectStyles.staticStyle;
|
||||||
|
if (staticStyle) {
|
||||||
|
this.staticStyle = {
|
||||||
|
style: Object.assign({}, this.initialStyles, staticStyle.style)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.staticStyle = {
|
||||||
|
style: Object.assign({}, this.initialStyles)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeItemStyles(itemId) {
|
||||||
|
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
|
||||||
|
if (itemId && domainObjectStyles[itemId]) {
|
||||||
|
delete domainObjectStyles[itemId];
|
||||||
|
|
||||||
|
if (Object.keys(domainObjectStyles).length <= 0) {
|
||||||
|
domainObjectStyles = undefined;
|
||||||
|
}
|
||||||
|
this.persist(this.domainObject, domainObjectStyles);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
findStyleByConditionId(id) {
|
||||||
|
return this.conditionalStyles.find(conditionalStyle => conditionalStyle.conditionId === id);
|
||||||
|
},
|
||||||
|
getCondition(id) {
|
||||||
|
return this.conditions ? this.conditions[id] : {};
|
||||||
|
},
|
||||||
|
addConditionSet() {
|
||||||
|
let conditionSetDomainObject;
|
||||||
|
const handleItemSelection = (item) => {
|
||||||
|
if (item) {
|
||||||
|
conditionSetDomainObject = item;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const dismissDialog = (overlay, initialize) => {
|
||||||
|
overlay.dismiss();
|
||||||
|
if (initialize && conditionSetDomainObject) {
|
||||||
|
this.conditionSetDomainObject = conditionSetDomainObject;
|
||||||
|
this.conditionalStyles = [];
|
||||||
|
this.initializeConditionalStyles();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let vm = new Vue({
|
||||||
|
provide: {
|
||||||
|
openmct: this.openmct
|
||||||
|
},
|
||||||
|
components: {ConditionSetSelectorDialog},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
handleItemSelection
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: '<condition-set-selector-dialog @conditionSetSelected="handleItemSelection"></condition-set-selector-dialog>'
|
||||||
|
}).$mount();
|
||||||
|
|
||||||
|
let overlay = this.openmct.overlays.overlay({
|
||||||
|
element: vm.$el,
|
||||||
|
size: 'small',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
label: 'OK',
|
||||||
|
emphasis: 'true',
|
||||||
|
callback: () => dismissDialog(overlay, true)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cancel',
|
||||||
|
callback: () => dismissDialog(overlay, false)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
onDestroy: () => vm.$destroy()
|
||||||
|
});
|
||||||
|
},
|
||||||
|
removeConditionSet() {
|
||||||
|
this.conditionSetDomainObject = undefined;
|
||||||
|
this.conditionalStyles = [];
|
||||||
|
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
|
||||||
|
if (this.domainObjectsById) {
|
||||||
|
const domainObjects = Object.values(this.domainObjectsById);
|
||||||
|
domainObjects.forEach(domainObject => {
|
||||||
|
let objectStyles = (domainObject.configuration && domainObject.configuration.objectStyles) || {};
|
||||||
|
this.removeConditionalStyles(objectStyles);
|
||||||
|
if (objectStyles && Object.keys(objectStyles).length <= 0) {
|
||||||
|
objectStyles = undefined;
|
||||||
|
}
|
||||||
|
this.persist(domainObject, objectStyles);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.items.length) {
|
||||||
|
this.items.forEach((item) => {
|
||||||
|
const itemId = item.id;
|
||||||
|
this.removeConditionalStyles(domainObjectStyles, itemId);
|
||||||
|
if (domainObjectStyles[itemId] && Object.keys(domainObjectStyles[itemId]).length <= 0) {
|
||||||
|
delete domainObjectStyles[itemId];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.removeConditionalStyles(domainObjectStyles);
|
||||||
|
}
|
||||||
|
if (domainObjectStyles && Object.keys(domainObjectStyles).length <= 0) {
|
||||||
|
domainObjectStyles = undefined;
|
||||||
|
}
|
||||||
|
this.persist(this.domainObject, domainObjectStyles);
|
||||||
|
|
||||||
|
if (this.stopProvidingTelemetry) {
|
||||||
|
this.stopProvidingTelemetry();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeConditionalStyles(domainObjectStyles, itemId) {
|
||||||
|
if (itemId && domainObjectStyles[itemId]) {
|
||||||
|
domainObjectStyles[itemId].conditionSetIdentifier = undefined;
|
||||||
|
delete domainObjectStyles[itemId].conditionSetIdentifier;
|
||||||
|
domainObjectStyles[itemId].selectedConditionId = undefined;
|
||||||
|
domainObjectStyles[itemId].defaultConditionId = undefined;
|
||||||
|
domainObjectStyles[itemId].styles = undefined;
|
||||||
|
delete domainObjectStyles[itemId].styles;
|
||||||
|
} else {
|
||||||
|
domainObjectStyles.conditionSetIdentifier = undefined;
|
||||||
|
delete domainObjectStyles.conditionSetIdentifier;
|
||||||
|
domainObjectStyles.selectedConditionId = undefined;
|
||||||
|
domainObjectStyles.defaultConditionId = undefined;
|
||||||
|
domainObjectStyles.styles = undefined;
|
||||||
|
delete domainObjectStyles.styles;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateStaticStyle(staticStyle, property) {
|
||||||
|
//update the static style for each of the layoutItems as well as each sub object item
|
||||||
|
this.staticStyle = staticStyle;
|
||||||
|
this.removeConditionSet();
|
||||||
|
this.getAndPersistStyles(property);
|
||||||
|
},
|
||||||
|
updateConditionalStyle(conditionStyle, property) {
|
||||||
|
let foundStyle = this.findStyleByConditionId(conditionStyle.conditionId);
|
||||||
|
if (foundStyle) {
|
||||||
|
foundStyle.style = conditionStyle.style;
|
||||||
|
this.selectedConditionId = foundStyle.conditionId;
|
||||||
|
this.getAndPersistStyles(property);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getAndPersistStyles(property, defaultConditionId) {
|
||||||
|
this.persist(this.domainObject, this.getDomainObjectStyle(this.domainObject, property, this.items, defaultConditionId));
|
||||||
|
if (this.domainObjectsById) {
|
||||||
|
const domainObjects = Object.values(this.domainObjectsById);
|
||||||
|
domainObjects.forEach(domainObject => {
|
||||||
|
this.persist(domainObject, this.getDomainObjectStyle(domainObject, property, null, defaultConditionId));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!this.items.length && !this.domainObjectsById) {
|
||||||
|
this.persist(this.domainObject, this.getDomainObjectStyle(this.domainObject, property, null, defaultConditionId));
|
||||||
|
}
|
||||||
|
this.isStaticAndConditionalStyles = false;
|
||||||
|
if (property) {
|
||||||
|
let foundIndex = this.mixedStyles.indexOf(property);
|
||||||
|
if (foundIndex > -1) {
|
||||||
|
this.mixedStyles.splice(foundIndex, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getDomainObjectStyle(domainObject, property, items, defaultConditionId) {
|
||||||
|
let objectStyle = {
|
||||||
|
styles: this.conditionalStyles,
|
||||||
|
staticStyle: this.staticStyle,
|
||||||
|
selectedConditionId: this.selectedConditionId
|
||||||
|
};
|
||||||
|
if (defaultConditionId) {
|
||||||
|
objectStyle.defaultConditionId = defaultConditionId;
|
||||||
|
}
|
||||||
|
if (this.conditionSetDomainObject) {
|
||||||
|
objectStyle.conditionSetIdentifier = this.conditionSetDomainObject.identifier;
|
||||||
|
}
|
||||||
|
let domainObjectStyles = (domainObject.configuration && domainObject.configuration.objectStyles) || {};
|
||||||
|
|
||||||
|
if (items) {
|
||||||
|
items.forEach(item => {
|
||||||
|
let itemStaticStyle = {};
|
||||||
|
let itemConditionalStyle = { styles: []};
|
||||||
|
if (!this.conditionSetDomainObject) {
|
||||||
|
if (domainObjectStyles[item.id] && domainObjectStyles[item.id].staticStyle) {
|
||||||
|
itemStaticStyle = Object.assign({}, domainObjectStyles[item.id].staticStyle.style);
|
||||||
|
}
|
||||||
|
if (item.applicableStyles[property] !== undefined) {
|
||||||
|
itemStaticStyle[property] = this.staticStyle.style[property];
|
||||||
|
}
|
||||||
|
if (Object.keys(itemStaticStyle).length <= 0) {
|
||||||
|
itemStaticStyle = undefined;
|
||||||
|
}
|
||||||
|
domainObjectStyles[item.id] = { staticStyle: { style: itemStaticStyle } };
|
||||||
|
} else {
|
||||||
|
objectStyle.styles.forEach((conditionalStyle, index) => {
|
||||||
|
let style = {};
|
||||||
|
Object.keys(item.applicableStyles).concat(['isStyleInvisible']).forEach(key => {
|
||||||
|
style[key] = conditionalStyle.style[key];
|
||||||
|
});
|
||||||
|
itemConditionalStyle.styles.push({
|
||||||
|
...conditionalStyle,
|
||||||
|
style
|
||||||
|
});
|
||||||
|
});
|
||||||
|
domainObjectStyles[item.id] = {
|
||||||
|
...domainObjectStyles[item.id],
|
||||||
|
...objectStyle,
|
||||||
|
...itemConditionalStyle
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
domainObjectStyles = {
|
||||||
|
...domainObjectStyles,
|
||||||
|
...objectStyle
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return domainObjectStyles;
|
||||||
|
},
|
||||||
|
applySelectedConditionStyle(conditionId) {
|
||||||
|
this.selectedConditionId = conditionId;
|
||||||
|
this.getAndPersistStyles();
|
||||||
|
},
|
||||||
|
persist(domainObject, style) {
|
||||||
|
this.openmct.objects.mutate(domainObject, 'configuration.objectStyles', style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -60,6 +60,31 @@
|
|||||||
|
|
||||||
&__condition {
|
&__condition {
|
||||||
@include discreteItem();
|
@include discreteItem();
|
||||||
|
border: 1px solid transparent;
|
||||||
|
pointer-events: none; // Prevent selecting when the object isn't being edited
|
||||||
|
|
||||||
|
&.is-current {
|
||||||
|
$c: $colorBodyFg;
|
||||||
|
border-color: rgba($c, 0.2);
|
||||||
|
background: rgba($c, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-editing & {
|
||||||
|
cursor: pointer;
|
||||||
|
pointer-events: initial;
|
||||||
|
transition: $transOut;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba($colorBodyFg, 0.1);
|
||||||
|
transition: $transIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-current {
|
||||||
|
$c: $editUIColorBg;
|
||||||
|
border-color: $c;
|
||||||
|
background: rgba($c, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-style {
|
.c-style {
|
||||||
|
@ -20,11 +20,11 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import EventEmitter from 'EventEmitter';
|
import TelemetryCriterion from './TelemetryCriterion';
|
||||||
import {OPERATIONS} from '../utils/operations';
|
import { evaluateResults } from "../utils/evaluator";
|
||||||
import {computeCondition} from "@/plugins/condition/utils/evaluator";
|
import { getLatestTimestamp } from '../utils/time';
|
||||||
|
|
||||||
export default class TelemetryCriterion extends EventEmitter {
|
export default class AllTelemetryCriterion extends TelemetryCriterion {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribes/Unsubscribes to telemetry and emits the result
|
* Subscribes/Unsubscribes to telemetry and emits the result
|
||||||
@ -34,23 +34,35 @@ export default class TelemetryCriterion extends EventEmitter {
|
|||||||
* @param openmct
|
* @param openmct
|
||||||
*/
|
*/
|
||||||
constructor(telemetryDomainObjectDefinition, openmct) {
|
constructor(telemetryDomainObjectDefinition, openmct) {
|
||||||
super();
|
super(telemetryDomainObjectDefinition, openmct);
|
||||||
|
}
|
||||||
|
|
||||||
this.openmct = openmct;
|
initialize() {
|
||||||
this.objectAPI = this.openmct.objects;
|
this.telemetryObjects = { ...this.telemetryDomainObjectDefinition.telemetryObjects };
|
||||||
this.telemetryAPI = this.openmct.telemetry;
|
|
||||||
this.timeAPI = this.openmct.time;
|
|
||||||
this.id = telemetryDomainObjectDefinition.id;
|
|
||||||
this.telemetry = telemetryDomainObjectDefinition.telemetry;
|
|
||||||
this.operation = telemetryDomainObjectDefinition.operation;
|
|
||||||
this.telemetryObjects = Object.assign({}, telemetryDomainObjectDefinition.telemetryObjects);
|
|
||||||
this.input = telemetryDomainObjectDefinition.input;
|
|
||||||
this.metadata = telemetryDomainObjectDefinition.metadata;
|
|
||||||
this.telemetryDataCache = {};
|
this.telemetryDataCache = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isValid() {
|
||||||
|
return (this.telemetry === 'any' || this.telemetry === 'all') && this.metadata && this.operation;
|
||||||
|
}
|
||||||
|
|
||||||
updateTelemetry(telemetryObjects) {
|
updateTelemetry(telemetryObjects) {
|
||||||
this.telemetryObjects = Object.assign({}, telemetryObjects);
|
this.telemetryObjects = { ...telemetryObjects };
|
||||||
|
this.removeTelemetryDataCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
removeTelemetryDataCache() {
|
||||||
|
const telemetryCacheIds = Object.keys(this.telemetryDataCache);
|
||||||
|
Object.values(this.telemetryObjects).forEach(telemetryObject => {
|
||||||
|
const id = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||||
|
const foundIndex = telemetryCacheIds.indexOf(id);
|
||||||
|
if (foundIndex > -1) {
|
||||||
|
telemetryCacheIds.splice(foundIndex, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
telemetryCacheIds.forEach(id => {
|
||||||
|
delete (this.telemetryDataCache[id]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
formatData(data, telemetryObjects) {
|
formatData(data, telemetryObjects) {
|
||||||
@ -68,105 +80,87 @@ export default class TelemetryCriterion extends EventEmitter {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const datum = {
|
const datum = {
|
||||||
result: computeCondition(this.telemetryDataCache, this.telemetry === 'all')
|
result: evaluateResults(Object.values(this.telemetryDataCache), this.telemetry)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
// TODO check back to see if we should format times here
|
this.openmct.time.getAllTimeSystems().forEach(timeSystem => {
|
||||||
this.timeAPI.getAllTimeSystems().forEach(timeSystem => {
|
|
||||||
datum[timeSystem.key] = data[timeSystem.key]
|
datum[timeSystem.key] = data[timeSystem.key]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return datum;
|
return datum;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubscription(data, telemetryObjects) {
|
getResult(data, telemetryObjects) {
|
||||||
if(this.isValid()) {
|
const validatedData = this.isValid() ? data : {};
|
||||||
this.emitEvent('criterionResultUpdated', this.formatData(data, telemetryObjects));
|
|
||||||
} else {
|
if (validatedData) {
|
||||||
this.emitEvent('criterionResultUpdated', this.formatData({}, telemetryObjects));
|
this.telemetryDataCache[validatedData.id] = this.computeResult(validatedData);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
findOperation(operation) {
|
Object.values(telemetryObjects).forEach(telemetryObject => {
|
||||||
for (let i=0; i < OPERATIONS.length; i++) {
|
const id = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||||
if (operation === OPERATIONS[i].name) {
|
if (this.telemetryDataCache[id] === undefined) {
|
||||||
return OPERATIONS[i].operation;
|
this.telemetryDataCache[id] = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
computeResult(data) {
|
|
||||||
let result = false;
|
|
||||||
if (data) {
|
|
||||||
let comparator = this.findOperation(this.operation);
|
|
||||||
let params = [];
|
|
||||||
params.push(data[this.metadata]);
|
|
||||||
if (this.input instanceof Array && this.input.length) {
|
|
||||||
this.input.forEach(input => params.push(input));
|
|
||||||
}
|
|
||||||
if (typeof comparator === 'function') {
|
|
||||||
result = comparator(params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
emitEvent(eventName, data) {
|
|
||||||
this.emit(eventName, {
|
|
||||||
id: this.id,
|
|
||||||
data: data
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.result = evaluateResults(Object.values(this.telemetryDataCache), this.telemetry);
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid() {
|
requestLAD(telemetryObjects) {
|
||||||
return (this.telemetry === 'any' || this.telemetry === 'all') && this.metadata && this.operation;
|
const options = {
|
||||||
}
|
|
||||||
|
|
||||||
requestLAD(options) {
|
|
||||||
options = Object.assign({},
|
|
||||||
options,
|
|
||||||
{
|
|
||||||
strategy: 'latest',
|
strategy: 'latest',
|
||||||
size: 1
|
size: 1
|
||||||
}
|
};
|
||||||
);
|
|
||||||
|
|
||||||
if (!this.isValid()) {
|
if (!this.isValid()) {
|
||||||
return this.formatData({}, options.telemetryObjects);
|
return this.formatData({}, telemetryObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
let keys = Object.keys(Object.assign({}, options.telemetryObjects));
|
let keys = Object.keys(Object.assign({}, telemetryObjects));
|
||||||
const telemetryRequests = keys
|
const telemetryRequests = keys
|
||||||
.map(key => this.telemetryAPI.request(
|
.map(key => this.openmct.telemetry.request(
|
||||||
options.telemetryObjects[key],
|
telemetryObjects[key],
|
||||||
options
|
options
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let telemetryDataCache = {};
|
||||||
return Promise.all(telemetryRequests)
|
return Promise.all(telemetryRequests)
|
||||||
.then(telemetryRequestsResults => {
|
.then(telemetryRequestsResults => {
|
||||||
let latestDatum;
|
let latestTimestamp;
|
||||||
|
const timeSystems = this.openmct.time.getAllTimeSystems();
|
||||||
|
const timeSystem = this.openmct.time.timeSystem();
|
||||||
|
|
||||||
telemetryRequestsResults.forEach((results, index) => {
|
telemetryRequestsResults.forEach((results, index) => {
|
||||||
latestDatum = results.length ? results[results.length - 1] : {};
|
const latestDatum = results.length ? results[results.length - 1] : {};
|
||||||
if (index < telemetryRequestsResults.length-1) {
|
const datumId = keys[index];
|
||||||
if (latestDatum) {
|
const normalizedDatum = this.createNormalizedDatum(latestDatum, telemetryObjects[datumId]);
|
||||||
this.telemetryDataCache[latestDatum.id] = this.computeResult(latestDatum);
|
|
||||||
}
|
telemetryDataCache[datumId] = this.computeResult(normalizedDatum);
|
||||||
}
|
|
||||||
|
latestTimestamp = getLatestTimestamp(
|
||||||
|
latestTimestamp,
|
||||||
|
normalizedDatum,
|
||||||
|
timeSystems,
|
||||||
|
timeSystem
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const datum = {
|
||||||
|
result: evaluateResults(Object.values(telemetryDataCache), this.telemetry),
|
||||||
|
...latestTimestamp
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
data: this.formatData(latestDatum, options.telemetryObjects)
|
data: datum
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
this.emitEvent('criterionRemoved');
|
|
||||||
delete this.telemetryObjects;
|
delete this.telemetryObjects;
|
||||||
delete this.telemetryDataCache;
|
delete this.telemetryDataCache;
|
||||||
delete this.telemetryObjectIdAsString;
|
|
||||||
delete this.telemetryObject;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import EventEmitter from 'EventEmitter';
|
import EventEmitter from 'EventEmitter';
|
||||||
import {OPERATIONS} from '../utils/operations';
|
import { OPERATIONS } from '../utils/operations';
|
||||||
|
|
||||||
export default class TelemetryCriterion extends EventEmitter {
|
export default class TelemetryCriterion extends EventEmitter {
|
||||||
|
|
||||||
@ -36,44 +36,89 @@ export default class TelemetryCriterion extends EventEmitter {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
this.objectAPI = this.openmct.objects;
|
this.telemetryDomainObjectDefinition = telemetryDomainObjectDefinition;
|
||||||
this.telemetryAPI = this.openmct.telemetry;
|
|
||||||
this.timeAPI = this.openmct.time;
|
|
||||||
this.id = telemetryDomainObjectDefinition.id;
|
this.id = telemetryDomainObjectDefinition.id;
|
||||||
this.telemetry = telemetryDomainObjectDefinition.telemetry;
|
this.telemetry = telemetryDomainObjectDefinition.telemetry;
|
||||||
this.operation = telemetryDomainObjectDefinition.operation;
|
this.operation = telemetryDomainObjectDefinition.operation;
|
||||||
this.input = telemetryDomainObjectDefinition.input;
|
this.input = telemetryDomainObjectDefinition.input;
|
||||||
this.metadata = telemetryDomainObjectDefinition.metadata;
|
this.metadata = telemetryDomainObjectDefinition.metadata;
|
||||||
this.telemetryObject = telemetryDomainObjectDefinition.telemetryObject;
|
this.result = undefined;
|
||||||
this.telemetryObjectIdAsString = this.objectAPI.makeKeyString(telemetryDomainObjectDefinition.telemetry);
|
|
||||||
this.on(`subscription:${this.telemetryObjectIdAsString}`, this.handleSubscription);
|
this.initialize();
|
||||||
this.emitEvent('criterionUpdated', this);
|
this.emitEvent('criterionUpdated', this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
this.telemetryObject = this.telemetryDomainObjectDefinition.telemetryObject;
|
||||||
|
this.telemetryObjectIdAsString = this.openmct.objects.makeKeyString(this.telemetryDomainObjectDefinition.telemetry);
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid() {
|
||||||
|
return this.telemetryObject && this.metadata && this.operation;
|
||||||
|
}
|
||||||
|
|
||||||
updateTelemetry(telemetryObjects) {
|
updateTelemetry(telemetryObjects) {
|
||||||
this.telemetryObject = telemetryObjects[this.telemetryObjectIdAsString];
|
this.telemetryObject = telemetryObjects[this.telemetryObjectIdAsString];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createNormalizedDatum(telemetryDatum, endpoint) {
|
||||||
|
const id = this.openmct.objects.makeKeyString(endpoint.identifier);
|
||||||
|
const metadata = this.openmct.telemetry.getMetadata(endpoint).valueMetadatas;
|
||||||
|
|
||||||
|
const normalizedDatum = Object.values(metadata).reduce((datum, metadatum) => {
|
||||||
|
const formatter = this.openmct.telemetry.getValueFormatter(metadatum);
|
||||||
|
datum[metadatum.key] = formatter.parse(telemetryDatum[metadatum.source]);
|
||||||
|
return datum;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
normalizedDatum.id = id;
|
||||||
|
|
||||||
|
return normalizedDatum;
|
||||||
|
}
|
||||||
|
|
||||||
formatData(data) {
|
formatData(data) {
|
||||||
const datum = {
|
const datum = {
|
||||||
result: this.computeResult(data)
|
result: this.computeResult(data)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
// TODO check back to see if we should format times here
|
this.openmct.time.getAllTimeSystems().forEach(timeSystem => {
|
||||||
this.timeAPI.getAllTimeSystems().forEach(timeSystem => {
|
|
||||||
datum[timeSystem.key] = data[timeSystem.key]
|
datum[timeSystem.key] = data[timeSystem.key]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return datum;
|
return datum;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubscription(data) {
|
getResult(data) {
|
||||||
if(this.isValid()) {
|
const validatedData = this.isValid() ? data : {};
|
||||||
this.emitEvent('criterionResultUpdated', this.formatData(data));
|
this.result = this.computeResult(validatedData);
|
||||||
} else {
|
|
||||||
this.emitEvent('criterionResultUpdated', this.formatData({}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requestLAD() {
|
||||||
|
const options = {
|
||||||
|
strategy: 'latest',
|
||||||
|
size: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!this.isValid()) {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
data: this.formatData({})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.openmct.telemetry.request(
|
||||||
|
this.telemetryObject,
|
||||||
|
options
|
||||||
|
).then(results => {
|
||||||
|
const latestDatum = results.length ? results[results.length - 1] : {};
|
||||||
|
const normalizedDatum = this.createNormalizedDatum(latestDatum, this.telemetryObject);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
data: this.formatData(normalizedDatum)
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
findOperation(operation) {
|
findOperation(operation) {
|
||||||
@ -95,7 +140,7 @@ export default class TelemetryCriterion extends EventEmitter {
|
|||||||
this.input.forEach(input => params.push(input));
|
this.input.forEach(input => params.push(input));
|
||||||
}
|
}
|
||||||
if (typeof comparator === 'function') {
|
if (typeof comparator === 'function') {
|
||||||
result = comparator(params);
|
result = !!comparator(params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -108,42 +153,9 @@ export default class TelemetryCriterion extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid() {
|
|
||||||
return this.telemetryObject && this.metadata && this.operation;
|
|
||||||
}
|
|
||||||
|
|
||||||
requestLAD(options) {
|
|
||||||
options = Object.assign({},
|
|
||||||
options,
|
|
||||||
{
|
|
||||||
strategy: 'latest',
|
|
||||||
size: 1
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!this.isValid()) {
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
data: this.formatData({})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.telemetryAPI.request(
|
|
||||||
this.telemetryObject,
|
|
||||||
options
|
|
||||||
).then(results => {
|
|
||||||
const latestDatum = results.length ? results[results.length - 1] : {};
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
data: this.formatData(latestDatum)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
this.off(`subscription:${this.telemetryObjectIdAsString}`, this.handleSubscription);
|
|
||||||
this.emitEvent('criterionRemoved');
|
|
||||||
delete this.telemetryObjectIdAsString;
|
|
||||||
delete this.telemetryObject;
|
delete this.telemetryObject;
|
||||||
|
delete this.telemetryObjectIdAsString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ describe("The telemetry criterion", function () {
|
|||||||
key: "testSource",
|
key: "testSource",
|
||||||
source: "value",
|
source: "value",
|
||||||
name: "Test",
|
name: "Test",
|
||||||
format: "enum"
|
format: "string"
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -80,8 +80,9 @@ describe("The telemetry criterion", function () {
|
|||||||
testCriterionDefinition = {
|
testCriterionDefinition = {
|
||||||
id: 'test-criterion-id',
|
id: 'test-criterion-id',
|
||||||
telemetry: openmct.objects.makeKeyString(testTelemetryObject.identifier),
|
telemetry: openmct.objects.makeKeyString(testTelemetryObject.identifier),
|
||||||
operation: 'lessThan',
|
operation: 'textContains',
|
||||||
metadata: 'sin',
|
metadata: 'value',
|
||||||
|
input: ['Hell'],
|
||||||
telemetryObject: testTelemetryObject
|
telemetryObject: testTelemetryObject
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -100,12 +101,21 @@ describe("The telemetry criterion", function () {
|
|||||||
expect(telemetryCriterion.telemetryObjectIdAsString).toEqual(testTelemetryObject.identifier.key);
|
expect(telemetryCriterion.telemetryObjectIdAsString).toEqual(testTelemetryObject.identifier.key);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("updates and emits event on new data from telemetry providers", function () {
|
it("returns a result on new data from relevant telemetry providers", function () {
|
||||||
spyOn(telemetryCriterion, 'emitEvent').and.callThrough();
|
telemetryCriterion.getResult({
|
||||||
telemetryCriterion.handleSubscription({
|
|
||||||
value: 'Hello',
|
value: 'Hello',
|
||||||
utc: 'Hi'
|
utc: 'Hi',
|
||||||
|
id: testTelemetryObject.identifier.key
|
||||||
});
|
});
|
||||||
expect(telemetryCriterion.emitEvent).toHaveBeenCalled();
|
expect(telemetryCriterion.result).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// it("does not return a result on new data from irrelavant telemetry providers", function () {
|
||||||
|
// telemetryCriterion.getResult({
|
||||||
|
// value: 'Hello',
|
||||||
|
// utc: 'Hi',
|
||||||
|
// id: '1234'
|
||||||
|
// });
|
||||||
|
// expect(telemetryCriterion.result).toBeFalse();
|
||||||
|
// });
|
||||||
});
|
});
|
||||||
|
@ -20,25 +20,24 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import { createOpenMct } from "testTools";
|
import { createOpenMct } from "testUtils";
|
||||||
import ConditionPlugin from "./plugin";
|
import ConditionPlugin from "./plugin";
|
||||||
|
import StylesView from "./components/inspector/StylesView.vue";
|
||||||
let openmct = createOpenMct();
|
import Vue from 'vue';
|
||||||
openmct.install(new ConditionPlugin());
|
import {getApplicableStylesForItem} from "./utils/styleUtils";
|
||||||
|
|
||||||
let conditionSetDefinition;
|
|
||||||
let mockConditionSetDomainObject;
|
|
||||||
let element;
|
|
||||||
let child;
|
|
||||||
|
|
||||||
describe('the plugin', function () {
|
describe('the plugin', function () {
|
||||||
|
let conditionSetDefinition;
|
||||||
|
let mockConditionSetDomainObject;
|
||||||
|
let element;
|
||||||
|
let child;
|
||||||
|
let openmct;
|
||||||
|
|
||||||
beforeAll((done) => {
|
beforeEach((done) => {
|
||||||
|
openmct = createOpenMct();
|
||||||
|
openmct.install(new ConditionPlugin());
|
||||||
|
|
||||||
conditionSetDefinition = openmct.types.get('conditionSet').definition;
|
conditionSetDefinition = openmct.types.get('conditionSet').definition;
|
||||||
const appHolder = document.createElement('div');
|
|
||||||
appHolder.style.width = '640px';
|
|
||||||
appHolder.style.height = '480px';
|
|
||||||
|
|
||||||
element = document.createElement('div');
|
element = document.createElement('div');
|
||||||
child = document.createElement('div');
|
child = document.createElement('div');
|
||||||
@ -55,7 +54,7 @@ describe('the plugin', function () {
|
|||||||
conditionSetDefinition.initialize(mockConditionSetDomainObject);
|
conditionSetDefinition.initialize(mockConditionSetDomainObject);
|
||||||
|
|
||||||
openmct.on('start', done);
|
openmct.on('start', done);
|
||||||
openmct.start(appHolder);
|
openmct.startHeadless();
|
||||||
});
|
});
|
||||||
|
|
||||||
let mockConditionSetObject = {
|
let mockConditionSetObject = {
|
||||||
@ -94,4 +93,259 @@ describe('the plugin', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('the condition set usage for multiple display layout items', () => {
|
||||||
|
let displayLayoutItem;
|
||||||
|
let lineLayoutItem;
|
||||||
|
let boxLayoutItem;
|
||||||
|
let selection;
|
||||||
|
let component;
|
||||||
|
let styleViewComponentObject;
|
||||||
|
const conditionSetDomainObject = {
|
||||||
|
"configuration":{
|
||||||
|
"conditionTestData":[
|
||||||
|
{
|
||||||
|
"telemetry":"",
|
||||||
|
"metadata":"",
|
||||||
|
"input":""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"conditionCollection":[
|
||||||
|
{
|
||||||
|
"id":"39584410-cbf9-499e-96dc-76f27e69885d",
|
||||||
|
"configuration":{
|
||||||
|
"name":"Unnamed Condition",
|
||||||
|
"output":"Sine > 0",
|
||||||
|
"trigger":"all",
|
||||||
|
"criteria":[
|
||||||
|
{
|
||||||
|
"id":"85fbb2f7-7595-42bd-9767-a932266c5225",
|
||||||
|
"telemetry":{
|
||||||
|
"namespace":"",
|
||||||
|
"key":"be0ba97f-b510-4f40-a18d-4ff121d5ea1a"
|
||||||
|
},
|
||||||
|
"operation":"greaterThan",
|
||||||
|
"input":[
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
"metadata":"sin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":"35400132-63b0-425c-ac30-8197df7d5862",
|
||||||
|
"telemetry":"any",
|
||||||
|
"operation":"enumValueIs",
|
||||||
|
"input":[
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
"metadata":"state"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"summary":"Match if all criteria are met: Sine Wave Generator Sine > 0 and any telemetry State is OFF "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isDefault":true,
|
||||||
|
"id":"2532d90a-e0d6-4935-b546-3123522da2de",
|
||||||
|
"configuration":{
|
||||||
|
"name":"Default",
|
||||||
|
"output":"Default",
|
||||||
|
"trigger":"all",
|
||||||
|
"criteria":[
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"summary":""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"composition":[
|
||||||
|
{
|
||||||
|
"namespace":"",
|
||||||
|
"key":"be0ba97f-b510-4f40-a18d-4ff121d5ea1a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"namespace":"",
|
||||||
|
"key":"077ffa67-e78f-4e99-80e0-522ac33a3888"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"telemetry":{
|
||||||
|
},
|
||||||
|
"name":"Condition Set",
|
||||||
|
"type":"conditionSet",
|
||||||
|
"identifier":{
|
||||||
|
"namespace":"",
|
||||||
|
"key":"863012c1-f6ca-4ab0-aed7-fd43d5e4cd12"
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
const staticStyle = {
|
||||||
|
"style":{
|
||||||
|
"backgroundColor":"#717171",
|
||||||
|
"border":"1px solid #00ffff"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const conditionalStyle = {
|
||||||
|
"conditionId":"39584410-cbf9-499e-96dc-76f27e69885d",
|
||||||
|
"style":{
|
||||||
|
"isStyleInvisible":"",
|
||||||
|
"backgroundColor":"#717171",
|
||||||
|
"border":"1px solid #ffff00"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
displayLayoutItem = {
|
||||||
|
"composition":[
|
||||||
|
],
|
||||||
|
"configuration":{
|
||||||
|
"items":[
|
||||||
|
{
|
||||||
|
"fill":"#717171",
|
||||||
|
"stroke":"",
|
||||||
|
"x":1,
|
||||||
|
"y":1,
|
||||||
|
"width":10,
|
||||||
|
"height":5,
|
||||||
|
"type":"box-view",
|
||||||
|
"id":"89b88746-d325-487b-aec4-11b79afff9e8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x":18,
|
||||||
|
"y":9,
|
||||||
|
"x2":23,
|
||||||
|
"y2":4,
|
||||||
|
"stroke":"#717171",
|
||||||
|
"type":"line-view",
|
||||||
|
"id":"57d49a28-7863-43bd-9593-6570758916f0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"layoutGrid":[
|
||||||
|
10,
|
||||||
|
10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name":"Display Layout",
|
||||||
|
"type":"layout",
|
||||||
|
"identifier":{
|
||||||
|
"namespace":"",
|
||||||
|
"key":"c5e636c1-6771-4c9c-b933-8665cab189b3"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
lineLayoutItem = {
|
||||||
|
"x":18,
|
||||||
|
"y":9,
|
||||||
|
"x2":23,
|
||||||
|
"y2":4,
|
||||||
|
"stroke":"#717171",
|
||||||
|
"type":"line-view",
|
||||||
|
"id":"57d49a28-7863-43bd-9593-6570758916f0"
|
||||||
|
};
|
||||||
|
boxLayoutItem = {
|
||||||
|
"fill": "#717171",
|
||||||
|
"stroke": "",
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"width": 10,
|
||||||
|
"height": 5,
|
||||||
|
"type": "box-view",
|
||||||
|
"id": "89b88746-d325-487b-aec4-11b79afff9e8"
|
||||||
|
};
|
||||||
|
selection = [
|
||||||
|
[{
|
||||||
|
context: {
|
||||||
|
"layoutItem": lineLayoutItem,
|
||||||
|
"index":1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
context: {
|
||||||
|
"item": displayLayoutItem,
|
||||||
|
"supportsMultiSelect":true
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
[{
|
||||||
|
context: {
|
||||||
|
"layoutItem": boxLayoutItem,
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
context: {
|
||||||
|
item: displayLayoutItem,
|
||||||
|
"supportsMultiSelect":true
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
];
|
||||||
|
let viewContainer = document.createElement('div');
|
||||||
|
child.append(viewContainer);
|
||||||
|
component = new Vue({
|
||||||
|
provide: {
|
||||||
|
openmct: openmct,
|
||||||
|
selection: selection
|
||||||
|
},
|
||||||
|
el: viewContainer,
|
||||||
|
components: {
|
||||||
|
StylesView
|
||||||
|
},
|
||||||
|
template: '<styles-view/>'
|
||||||
|
});
|
||||||
|
return Vue.nextTick().then(() => {
|
||||||
|
styleViewComponentObject = component.$root.$children[0];
|
||||||
|
styleViewComponentObject.setEditState(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('initializes the items in the view', () => {
|
||||||
|
expect(styleViewComponentObject.items.length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('initializes conditional styles', () => {
|
||||||
|
styleViewComponentObject.conditionSetDomainObject = conditionSetDomainObject;
|
||||||
|
styleViewComponentObject.conditionalStyles = [];
|
||||||
|
styleViewComponentObject.initializeConditionalStyles();
|
||||||
|
expect(styleViewComponentObject.conditionalStyles.length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('updates applicable conditional styles', () => {
|
||||||
|
styleViewComponentObject.conditionSetDomainObject = conditionSetDomainObject;
|
||||||
|
styleViewComponentObject.conditionalStyles = [];
|
||||||
|
styleViewComponentObject.initializeConditionalStyles();
|
||||||
|
expect(styleViewComponentObject.conditionalStyles.length).toBe(2);
|
||||||
|
styleViewComponentObject.updateConditionalStyle(conditionalStyle, 'border');
|
||||||
|
return Vue.nextTick().then(() => {
|
||||||
|
expect(styleViewComponentObject.domainObject.configuration.objectStyles).toBeDefined();
|
||||||
|
[boxLayoutItem, lineLayoutItem].forEach((item) => {
|
||||||
|
const itemStyles = styleViewComponentObject.domainObject.configuration.objectStyles[item.id].styles;
|
||||||
|
expect(itemStyles.length).toBe(2);
|
||||||
|
const foundStyle = itemStyles.find((style) => {
|
||||||
|
return style.conditionId === conditionalStyle.conditionId;
|
||||||
|
});
|
||||||
|
expect(foundStyle).toBeDefined();
|
||||||
|
const applicableStyles = getApplicableStylesForItem(styleViewComponentObject.domainObject, item);
|
||||||
|
const applicableStylesKeys = Object.keys(applicableStyles).concat(['isStyleInvisible']);
|
||||||
|
Object.keys(foundStyle.style).forEach((key) => {
|
||||||
|
expect(applicableStylesKeys.indexOf(key)).toBeGreaterThan(-1);
|
||||||
|
expect(foundStyle.style[key]).toEqual(conditionalStyle.style[key]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('updates applicable static styles', () => {
|
||||||
|
styleViewComponentObject.updateStaticStyle(staticStyle, 'border');
|
||||||
|
return Vue.nextTick().then(() => {
|
||||||
|
expect(styleViewComponentObject.domainObject.configuration.objectStyles).toBeDefined();
|
||||||
|
[boxLayoutItem, lineLayoutItem].forEach((item) => {
|
||||||
|
const itemStyle = styleViewComponentObject.domainObject.configuration.objectStyles[item.id].staticStyle;
|
||||||
|
expect(itemStyle).toBeDefined();
|
||||||
|
const applicableStyles = getApplicableStylesForItem(styleViewComponentObject.domainObject, item);
|
||||||
|
const applicableStylesKeys = Object.keys(applicableStyles).concat(['isStyleInvisible']);
|
||||||
|
Object.keys(itemStyle.style).forEach((key) => {
|
||||||
|
expect(applicableStylesKeys.indexOf(key)).toBeGreaterThan(-1);
|
||||||
|
expect(itemStyle.style[key]).toEqual(staticStyle.style[key]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -19,36 +19,50 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
import { TRIGGER } from "./constants";
|
||||||
|
|
||||||
export const computeCondition = (resultMap, allMustBeTrue) => {
|
export const evaluateResults = (results, trigger) => {
|
||||||
let result = false;
|
if (trigger && trigger === TRIGGER.XOR) {
|
||||||
for (let key in resultMap) {
|
return matchExact(results, 1);
|
||||||
if (resultMap.hasOwnProperty(key)) {
|
} else if (trigger && trigger === TRIGGER.NOT) {
|
||||||
result = resultMap[key];
|
return matchExact(results, 0);
|
||||||
if (allMustBeTrue && !result) {
|
} else if (trigger && trigger === TRIGGER.ALL) {
|
||||||
//If we want all conditions to be true, then even one negative result should break.
|
return matchAll(results);
|
||||||
break;
|
} else {
|
||||||
} else if (!allMustBeTrue && result) {
|
return matchAny(results);
|
||||||
//If we want at least one condition to be true, then even one positive result should break.
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Returns true only if limit number of results are satisfied
|
function matchAll(results) {
|
||||||
export const computeConditionByLimit = (resultMap, limit) => {
|
for (const result of results) {
|
||||||
let trueCount = 0;
|
if (!result) {
|
||||||
for (let key in resultMap) {
|
return false;
|
||||||
if (resultMap.hasOwnProperty(key)) {
|
|
||||||
if (resultMap[key]) {
|
|
||||||
trueCount++;
|
|
||||||
}
|
|
||||||
if (trueCount > limit) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchAny(results) {
|
||||||
|
for (const result of results) {
|
||||||
|
if (result) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return trueCount === limit;
|
}
|
||||||
};
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchExact(results, target) {
|
||||||
|
let matches = 0;
|
||||||
|
for (const result of results) {
|
||||||
|
if (result) {
|
||||||
|
matches++;
|
||||||
|
}
|
||||||
|
if (matches > target) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches === target;
|
||||||
|
}
|
||||||
|
@ -20,47 +20,185 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import { computeConditionByLimit } from "./evaluator";
|
import { evaluateResults } from './evaluator';
|
||||||
|
import { TRIGGER } from './constants';
|
||||||
|
|
||||||
describe('evaluate results based on trigger', function () {
|
describe('evaluate results', () => {
|
||||||
|
// const allTrue = [true, true, true, true, true];
|
||||||
|
// const oneTrue = [false, false, false, false, true];
|
||||||
|
// const multipleTrue = [false, true, false, true, false];
|
||||||
|
// const noneTrue = [false, false, false, false, false];
|
||||||
|
// const allTrueWithUndefined = [true, true, true, undefined, true];
|
||||||
|
// const oneTrueWithUndefined = [undefined, undefined, undefined, undefined, true];
|
||||||
|
// const multipleTrueWithUndefined = [true, undefined, true, undefined, true];
|
||||||
|
// const allUndefined = [undefined, undefined, undefined, undefined, undefined];
|
||||||
|
// const singleTrue = [true];
|
||||||
|
// const singleFalse = [false];
|
||||||
|
// const singleUndefined = [undefined];
|
||||||
|
// const empty = [];
|
||||||
|
|
||||||
it('should evaluate to true if trigger is NOT', () => {
|
const tests = [
|
||||||
const results = {
|
{
|
||||||
result: false,
|
name: 'allTrue',
|
||||||
result1: false,
|
values: [true, true, true, true, true],
|
||||||
result2: false
|
any: true,
|
||||||
};
|
all: true,
|
||||||
const result = computeConditionByLimit(results, 0);
|
not: false,
|
||||||
expect(result).toBeTrue();
|
xor: false
|
||||||
|
}, {
|
||||||
|
name: 'oneTrue',
|
||||||
|
values: [false, false, false, false, true],
|
||||||
|
any: true,
|
||||||
|
all: false,
|
||||||
|
not: false,
|
||||||
|
xor: true
|
||||||
|
}, {
|
||||||
|
name: 'multipleTrue',
|
||||||
|
values: [false, true, false, true, false],
|
||||||
|
any: true,
|
||||||
|
all: false,
|
||||||
|
not: false,
|
||||||
|
xor: false
|
||||||
|
}, {
|
||||||
|
name: 'noneTrue',
|
||||||
|
values: [false, false, false, false, false],
|
||||||
|
any: false,
|
||||||
|
all: false,
|
||||||
|
not: true,
|
||||||
|
xor: false
|
||||||
|
}, {
|
||||||
|
name: 'allTrueWithUndefined',
|
||||||
|
values: [true, true, true, undefined, true],
|
||||||
|
any: true,
|
||||||
|
all: false,
|
||||||
|
not: false,
|
||||||
|
xor: false
|
||||||
|
}, {
|
||||||
|
name: 'oneTrueWithUndefined',
|
||||||
|
values: [undefined, undefined, undefined, undefined, true],
|
||||||
|
any: true,
|
||||||
|
all: false,
|
||||||
|
not: false,
|
||||||
|
xor: true
|
||||||
|
}, {
|
||||||
|
name: 'multipleTrueWithUndefined',
|
||||||
|
values: [true, undefined, true, undefined, true],
|
||||||
|
any: true,
|
||||||
|
all: false,
|
||||||
|
not: false,
|
||||||
|
xor: false
|
||||||
|
}, {
|
||||||
|
name: 'allUndefined',
|
||||||
|
values: [undefined, undefined, undefined, undefined, undefined],
|
||||||
|
any: false,
|
||||||
|
all: false,
|
||||||
|
not: true,
|
||||||
|
xor: false
|
||||||
|
}, {
|
||||||
|
name: 'singleTrue',
|
||||||
|
values: [true],
|
||||||
|
any: true,
|
||||||
|
all: true,
|
||||||
|
not: false,
|
||||||
|
xor: true
|
||||||
|
}, {
|
||||||
|
name: 'singleFalse',
|
||||||
|
values: [false],
|
||||||
|
any: false,
|
||||||
|
all: false,
|
||||||
|
not: true,
|
||||||
|
xor: false
|
||||||
|
}, {
|
||||||
|
name: 'singleUndefined',
|
||||||
|
values: [undefined],
|
||||||
|
any: false,
|
||||||
|
all: false,
|
||||||
|
not: true,
|
||||||
|
xor: false
|
||||||
|
}
|
||||||
|
// , {
|
||||||
|
// name: 'empty',
|
||||||
|
// values: [],
|
||||||
|
// any: false,
|
||||||
|
// all: false,
|
||||||
|
// not: true,
|
||||||
|
// xor: false
|
||||||
|
// }
|
||||||
|
];
|
||||||
|
|
||||||
|
describe(`based on trigger ${TRIGGER.ANY}`, () => {
|
||||||
|
it('should evaluate to expected result', () => {
|
||||||
|
tests.forEach(test => {
|
||||||
|
const result = evaluateResults(test.values, TRIGGER.ANY);
|
||||||
|
expect(result).toEqual(test[TRIGGER.ANY])
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should evaluate to false if trigger is NOT', () => {
|
describe(`based on trigger ${TRIGGER.ALL}`, () => {
|
||||||
const results = {
|
it('should evaluate to expected result', () => {
|
||||||
result: true,
|
tests.forEach(test => {
|
||||||
result1: false,
|
const result = evaluateResults(test.values, TRIGGER.ALL);
|
||||||
result2: false
|
expect(result).toEqual(test[TRIGGER.ALL])
|
||||||
};
|
});
|
||||||
const result = computeConditionByLimit(results, 0);
|
});
|
||||||
expect(result).toBeFalse();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should evaluate to true if trigger is XOR', () => {
|
describe(`based on trigger ${TRIGGER.NOT}`, () => {
|
||||||
const results = {
|
it('should evaluate to expected result', () => {
|
||||||
result: false,
|
tests.forEach(test => {
|
||||||
result1: true,
|
const result = evaluateResults(test.values, TRIGGER.NOT);
|
||||||
result2: false
|
expect(result).toEqual(test[TRIGGER.NOT])
|
||||||
};
|
});
|
||||||
const result = computeConditionByLimit(results, 1);
|
});
|
||||||
expect(result).toBeTrue();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should evaluate to false if trigger is XOR', () => {
|
describe(`based on trigger ${TRIGGER.XOR}`, () => {
|
||||||
const results = {
|
it('should evaluate to expected result', () => {
|
||||||
result: false,
|
tests.forEach(test => {
|
||||||
result1: true,
|
const result = evaluateResults(test.values, TRIGGER.XOR);
|
||||||
result2: true
|
expect(result).toEqual(test[TRIGGER.XOR])
|
||||||
};
|
|
||||||
const result = computeConditionByLimit(results, 1);
|
|
||||||
expect(result).toBeFalse();
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// it('should evaluate to true if trigger is NOT', () => {
|
||||||
|
// const results = {
|
||||||
|
// result: false,
|
||||||
|
// result1: false,
|
||||||
|
// result2: false
|
||||||
|
// };
|
||||||
|
// const result = computeConditionByLimit(results, 0);
|
||||||
|
// expect(result).toBeTrue();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('should evaluate to false if trigger is NOT', () => {
|
||||||
|
// const results = {
|
||||||
|
// result: true,
|
||||||
|
// result1: false,
|
||||||
|
// result2: false
|
||||||
|
// };
|
||||||
|
// const result = computeConditionByLimit(results, 0);
|
||||||
|
// expect(result).toBeFalse();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('should evaluate to true if trigger is XOR', () => {
|
||||||
|
// const results = {
|
||||||
|
// result: false,
|
||||||
|
// result1: true,
|
||||||
|
// result2: false
|
||||||
|
// };
|
||||||
|
// const result = computeConditionByLimit(results, 1);
|
||||||
|
// expect(result).toBeTrue();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('should evaluate to false if trigger is XOR', () => {
|
||||||
|
// const results = {
|
||||||
|
// result: false,
|
||||||
|
// result1: true,
|
||||||
|
// result2: true
|
||||||
|
// };
|
||||||
|
// const result = computeConditionByLimit(results, 1);
|
||||||
|
// expect(result).toBeFalse();
|
||||||
|
// });
|
||||||
});
|
});
|
||||||
|
@ -20,7 +20,21 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import _ from 'lodash';
|
const convertToNumbers = (input) => {
|
||||||
|
let numberInputs = [];
|
||||||
|
input.forEach(inputValue => numberInputs.push(Number(inputValue)));
|
||||||
|
return numberInputs;
|
||||||
|
};
|
||||||
|
|
||||||
|
const convertToStrings = (input) => {
|
||||||
|
let stringInputs = [];
|
||||||
|
input.forEach(inputValue => stringInputs.push(inputValue !== undefined ? inputValue.toString() : ''));
|
||||||
|
return stringInputs;
|
||||||
|
};
|
||||||
|
|
||||||
|
const joinValues = (values, length) => {
|
||||||
|
return values.slice(0, length).join(', ');
|
||||||
|
};
|
||||||
|
|
||||||
export const OPERATIONS = [
|
export const OPERATIONS = [
|
||||||
{
|
{
|
||||||
@ -32,7 +46,7 @@ export const OPERATIONS = [
|
|||||||
appliesTo: ['number'],
|
appliesTo: ['number'],
|
||||||
inputCount: 1,
|
inputCount: 1,
|
||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' is ' + values.join(', ');
|
return ' is ' + joinValues(values, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -44,7 +58,7 @@ export const OPERATIONS = [
|
|||||||
appliesTo: ['number'],
|
appliesTo: ['number'],
|
||||||
inputCount: 1,
|
inputCount: 1,
|
||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' is not ' + values.join(', ');
|
return ' is not ' + joinValues(values, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -56,7 +70,7 @@ export const OPERATIONS = [
|
|||||||
appliesTo: ['number'],
|
appliesTo: ['number'],
|
||||||
inputCount: 1,
|
inputCount: 1,
|
||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' > ' + values.join(', ');
|
return ' > ' + joinValues(values, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -68,7 +82,7 @@ export const OPERATIONS = [
|
|||||||
appliesTo: ['number'],
|
appliesTo: ['number'],
|
||||||
inputCount: 1,
|
inputCount: 1,
|
||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' < ' + values.join(', ');
|
return ' < ' + joinValues(values, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -80,7 +94,7 @@ export const OPERATIONS = [
|
|||||||
appliesTo: ['number'],
|
appliesTo: ['number'],
|
||||||
inputCount: 1,
|
inputCount: 1,
|
||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' >= ' + values.join(', ');
|
return ' >= ' + joinValues(values, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -92,14 +106,13 @@ export const OPERATIONS = [
|
|||||||
appliesTo: ['number'],
|
appliesTo: ['number'],
|
||||||
inputCount: 1,
|
inputCount: 1,
|
||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' <= ' + values.join(', ');
|
return ' <= ' + joinValues(values, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'between',
|
name: 'between',
|
||||||
operation: function (input) {
|
operation: function (input) {
|
||||||
let numberInputs = [];
|
let numberInputs = convertToNumbers(input);
|
||||||
input.forEach(inputValue => numberInputs.push(Number(inputValue)));
|
|
||||||
let larger = Math.max(...numberInputs.slice(1,3));
|
let larger = Math.max(...numberInputs.slice(1,3));
|
||||||
let smaller = Math.min(...numberInputs.slice(1,3));
|
let smaller = Math.min(...numberInputs.slice(1,3));
|
||||||
return (numberInputs[0] > smaller) && (numberInputs[0] < larger);
|
return (numberInputs[0] > smaller) && (numberInputs[0] < larger);
|
||||||
@ -114,8 +127,7 @@ export const OPERATIONS = [
|
|||||||
{
|
{
|
||||||
name: 'notBetween',
|
name: 'notBetween',
|
||||||
operation: function (input) {
|
operation: function (input) {
|
||||||
let numberInputs = [];
|
let numberInputs = convertToNumbers(input);
|
||||||
input.forEach(inputValue => numberInputs.push(Number(inputValue)));
|
|
||||||
let larger = Math.max(...numberInputs.slice(1,3));
|
let larger = Math.max(...numberInputs.slice(1,3));
|
||||||
let smaller = Math.min(...numberInputs.slice(1,3));
|
let smaller = Math.min(...numberInputs.slice(1,3));
|
||||||
return (numberInputs[0] < smaller) || (numberInputs[0] > larger);
|
return (numberInputs[0] < smaller) || (numberInputs[0] > larger);
|
||||||
@ -136,7 +148,7 @@ export const OPERATIONS = [
|
|||||||
appliesTo: ['string'],
|
appliesTo: ['string'],
|
||||||
inputCount: 1,
|
inputCount: 1,
|
||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' contains ' + values.join(', ');
|
return ' contains ' + joinValues(values, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -148,7 +160,7 @@ export const OPERATIONS = [
|
|||||||
appliesTo: ['string'],
|
appliesTo: ['string'],
|
||||||
inputCount: 1,
|
inputCount: 1,
|
||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' does not contain ' + values.join(', ');
|
return ' does not contain ' + joinValues(values, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -160,7 +172,7 @@ export const OPERATIONS = [
|
|||||||
appliesTo: ['string'],
|
appliesTo: ['string'],
|
||||||
inputCount: 1,
|
inputCount: 1,
|
||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' starts with ' + values.join(', ');
|
return ' starts with ' + joinValues(values, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -172,7 +184,7 @@ export const OPERATIONS = [
|
|||||||
appliesTo: ['string'],
|
appliesTo: ['string'],
|
||||||
inputCount: 1,
|
inputCount: 1,
|
||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' ends with ' + values.join(', ');
|
return ' ends with ' + joinValues(values, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -184,7 +196,7 @@ export const OPERATIONS = [
|
|||||||
appliesTo: ['string'],
|
appliesTo: ['string'],
|
||||||
inputCount: 1,
|
inputCount: 1,
|
||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' is exactly ' + values.join(', ');
|
return ' is exactly ' + joinValues(values, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -214,33 +226,36 @@ export const OPERATIONS = [
|
|||||||
{
|
{
|
||||||
name: 'enumValueIs',
|
name: 'enumValueIs',
|
||||||
operation: function (input) {
|
operation: function (input) {
|
||||||
return input[0] === input[1];
|
let stringInputs = convertToStrings(input);
|
||||||
|
return stringInputs[0] === stringInputs[1];
|
||||||
},
|
},
|
||||||
text: 'is',
|
text: 'is',
|
||||||
appliesTo: ['enum'],
|
appliesTo: ['enum'],
|
||||||
inputCount: 1,
|
inputCount: 1,
|
||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' is ' + values.join(', ');
|
return ' is ' + joinValues(values, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'enumValueIsNot',
|
name: 'enumValueIsNot',
|
||||||
operation: function (input) {
|
operation: function (input) {
|
||||||
return input[0] !== input[1];
|
let stringInputs = convertToStrings(input);
|
||||||
|
return stringInputs[0] !== stringInputs[1];
|
||||||
},
|
},
|
||||||
text: 'is not',
|
text: 'is not',
|
||||||
appliesTo: ['enum'],
|
appliesTo: ['enum'],
|
||||||
inputCount: 1,
|
inputCount: 1,
|
||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' is not ' + values.join(', ');
|
return ' is not ' + joinValues(values, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'valueIs',
|
name: 'valueIs',
|
||||||
operation: function (input) {
|
operation: function (input) {
|
||||||
|
const lhsValue = input[0] !== undefined ? input[0].toString() : '';
|
||||||
if (input[1]) {
|
if (input[1]) {
|
||||||
const values = input[1].split(',');
|
const values = input[1].split(',');
|
||||||
return values.find((value) => input[0].toString() === _.trim(value.toString()));
|
return values.find((value) => lhsValue === value.toString().trim());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
@ -254,9 +269,10 @@ export const OPERATIONS = [
|
|||||||
{
|
{
|
||||||
name: 'valueIsNot',
|
name: 'valueIsNot',
|
||||||
operation: function (input) {
|
operation: function (input) {
|
||||||
|
const lhsValue = input[0] !== undefined ? input[0].toString() : '';
|
||||||
if (input[1]) {
|
if (input[1]) {
|
||||||
const values = input[1].split(',');
|
const values = input[1].split(',');
|
||||||
const found = values.find((value) => input[0].toString() === _.trim(value.toString()));
|
const found = values.find((value) => lhsValue === value.toString().trim());
|
||||||
return !found;
|
return !found;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -25,8 +25,10 @@ let isOneOfOperation = OPERATIONS.find((operation) => operation.name === 'valueI
|
|||||||
let isNotOneOfOperation = OPERATIONS.find((operation) => operation.name === 'valueIsNot');
|
let isNotOneOfOperation = OPERATIONS.find((operation) => operation.name === 'valueIsNot');
|
||||||
let isBetween = OPERATIONS.find((operation) => operation.name === 'between');
|
let isBetween = OPERATIONS.find((operation) => operation.name === 'between');
|
||||||
let isNotBetween = OPERATIONS.find((operation) => operation.name === 'notBetween');
|
let isNotBetween = OPERATIONS.find((operation) => operation.name === 'notBetween');
|
||||||
|
let enumIsOperation = OPERATIONS.find((operation) => operation.name === 'enumValueIs');
|
||||||
|
let enumIsNotOperation = OPERATIONS.find((operation) => operation.name === 'enumValueIsNot');
|
||||||
|
|
||||||
describe('Is one of and is not one of operations', function () {
|
describe('operations', function () {
|
||||||
|
|
||||||
it('should evaluate isOneOf to true for number inputs', () => {
|
it('should evaluate isOneOf to true for number inputs', () => {
|
||||||
const inputs = [45, "5,6,45,8"];
|
const inputs = [45, "5,6,45,8"];
|
||||||
@ -87,4 +89,54 @@ describe('Is one of and is not one of operations', function () {
|
|||||||
const inputs = ["45", "30", "50"];
|
const inputs = ["45", "30", "50"];
|
||||||
expect(!!isNotBetween.operation(inputs)).toBeFalse();
|
expect(!!isNotBetween.operation(inputs)).toBeFalse();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should evaluate enumValueIs to true for number inputs', () => {
|
||||||
|
const inputs = [1, "1"];
|
||||||
|
expect(!!enumIsOperation.operation(inputs)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate enumValueIs to true for string inputs', () => {
|
||||||
|
const inputs = ["45", "45"];
|
||||||
|
expect(!!enumIsOperation.operation(inputs)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate enumValueIsNot to true for number inputs', () => {
|
||||||
|
const inputs = [45, "46"];
|
||||||
|
expect(!!enumIsNotOperation.operation(inputs)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate enumValueIsNot to true for string inputs', () => {
|
||||||
|
const inputs = ["45", "46"];
|
||||||
|
expect(!!enumIsNotOperation.operation(inputs)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate enumValueIs to false for number inputs', () => {
|
||||||
|
const inputs = [1, "2"];
|
||||||
|
expect(!!enumIsOperation.operation(inputs)).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate enumValueIs to false for string inputs', () => {
|
||||||
|
const inputs = ["45", "46"];
|
||||||
|
expect(!!enumIsOperation.operation(inputs)).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate enumValueIsNot to false for number inputs', () => {
|
||||||
|
const inputs = [45, "45"];
|
||||||
|
expect(!!enumIsNotOperation.operation(inputs)).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate enumValueIsNot to false for string inputs', () => {
|
||||||
|
const inputs = ["45", "45"];
|
||||||
|
expect(!!enumIsNotOperation.operation(inputs)).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate enumValueIs to false for undefined input', () => {
|
||||||
|
const inputs = [undefined, "45"];
|
||||||
|
expect(!!enumIsOperation.operation(inputs)).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate enumValueIsNot to true for undefined input', () => {
|
||||||
|
const inputs = [undefined, "45"];
|
||||||
|
expect(!!enumIsNotOperation.operation(inputs)).toBeTrue();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -19,27 +19,169 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
import isEmpty from 'lodash/isEmpty';
|
||||||
|
|
||||||
export const getStyleProp = (key, defaultValue) => {
|
const NONE_VALUE = '__no_value';
|
||||||
let styleProp = undefined;
|
|
||||||
switch(key) {
|
const styleProps = {
|
||||||
case 'fill': styleProp = {
|
backgroundColor: {
|
||||||
backgroundColor: defaultValue || 'transparent'
|
svgProperty: 'fill',
|
||||||
};
|
noneValue: NONE_VALUE,
|
||||||
break;
|
applicableForType: type => {
|
||||||
case 'stroke': styleProp = {
|
return !type ? true : (type === 'text-view' ||
|
||||||
border: '1px solid ' + (defaultValue || 'transparent')
|
type === 'telemetry-view' ||
|
||||||
};
|
type === 'box-view' ||
|
||||||
break;
|
type === 'subobject-view');
|
||||||
case 'color': styleProp = {
|
}
|
||||||
color: defaultValue || 'transparent'
|
},
|
||||||
};
|
border: {
|
||||||
break;
|
svgProperty: 'stroke',
|
||||||
case 'url': styleProp = {
|
noneValue: NONE_VALUE,
|
||||||
imageUrl: defaultValue || 'transparent'
|
applicableForType: type => {
|
||||||
};
|
return !type ? true : (type === 'text-view' ||
|
||||||
break;
|
type === 'telemetry-view' ||
|
||||||
|
type === 'box-view' ||
|
||||||
|
type === 'image-view' ||
|
||||||
|
type === 'line-view'||
|
||||||
|
type === 'subobject-view');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
svgProperty: 'color',
|
||||||
|
noneValue: NONE_VALUE,
|
||||||
|
applicableForType: type => {
|
||||||
|
return !type ? true : (type === 'text-view' ||
|
||||||
|
type === 'telemetry-view'||
|
||||||
|
type === 'subobject-view');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
imageUrl: {
|
||||||
|
svgProperty: 'url',
|
||||||
|
noneValue: '',
|
||||||
|
applicableForType: type => {
|
||||||
|
return !type ? false : type === 'image-view';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
return styleProp;
|
|
||||||
|
const aggregateStyleValues = (accumulator, currentStyle) => {
|
||||||
|
const styleKeys = Object.keys(currentStyle);
|
||||||
|
const properties = Object.keys(styleProps);
|
||||||
|
properties.forEach((property) => {
|
||||||
|
if (!accumulator[property]) {
|
||||||
|
accumulator[property] = [];
|
||||||
|
}
|
||||||
|
const found = styleKeys.find(key => key === property);
|
||||||
|
if (found) {
|
||||||
|
accumulator[property].push(currentStyle[found]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return accumulator;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns a union of styles used by multiple items.
|
||||||
|
// Styles that are common to all items but don't have the same value are added to the mixedStyles list
|
||||||
|
export const getConsolidatedStyleValues = (multipleItemStyles) => {
|
||||||
|
let aggregatedStyleValues = multipleItemStyles.reduce(aggregateStyleValues, {});
|
||||||
|
|
||||||
|
let styleValues = {};
|
||||||
|
let mixedStyles = [];
|
||||||
|
const properties = Object.keys(styleProps);
|
||||||
|
properties.forEach((property) => {
|
||||||
|
const values = aggregatedStyleValues[property];
|
||||||
|
if (values.length) {
|
||||||
|
if (values.every(value => value === values[0])) {
|
||||||
|
styleValues[property] = values[0];
|
||||||
|
} else {
|
||||||
|
styleValues[property] = '';
|
||||||
|
mixedStyles.push(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
styles: styleValues,
|
||||||
|
mixedStyles
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStaticStyleForItem = (domainObject, id) => {
|
||||||
|
let domainObjectStyles = domainObject && domainObject.configuration && domainObject.configuration.objectStyles;
|
||||||
|
if (domainObjectStyles) {
|
||||||
|
if (id) {
|
||||||
|
if(domainObjectStyles[id] && domainObjectStyles[id].staticStyle) {
|
||||||
|
return domainObjectStyles[id].staticStyle.style;
|
||||||
|
}
|
||||||
|
} else if (domainObjectStyles.staticStyle) {
|
||||||
|
return domainObjectStyles.staticStyle.style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getConditionalStyleForItem = (domainObject, id) => {
|
||||||
|
let domainObjectStyles = domainObject && domainObject.configuration && domainObject.configuration.objectStyles;
|
||||||
|
if (domainObjectStyles) {
|
||||||
|
if (id) {
|
||||||
|
if (domainObjectStyles[id] && domainObjectStyles[id].conditionSetIdentifier) {
|
||||||
|
return domainObjectStyles[id].styles;
|
||||||
|
}
|
||||||
|
} 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;
|
||||||
|
const id = item && item.id;
|
||||||
|
let style = {};
|
||||||
|
|
||||||
|
let staticStyle = getStaticStyleForItem(domainObject, id);
|
||||||
|
|
||||||
|
const properties = Object.keys(styleProps);
|
||||||
|
properties.forEach(property => {
|
||||||
|
const styleProp = styleProps[property];
|
||||||
|
if (styleProp.applicableForType(type)) {
|
||||||
|
let defaultValue;
|
||||||
|
if (staticStyle) {
|
||||||
|
defaultValue = staticStyle[property];
|
||||||
|
} else if (item) {
|
||||||
|
defaultValue = item[styleProp.svgProperty];
|
||||||
|
}
|
||||||
|
style[property] = defaultValue === undefined ? styleProp.noneValue : defaultValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return style;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getStylesWithoutNoneValue = (style) => {
|
||||||
|
if (isEmpty(style) || !style) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let styleObj = {};
|
||||||
|
const keys = Object.keys(style);
|
||||||
|
keys.forEach(key => {
|
||||||
|
if ((typeof style[key] === 'string')) {
|
||||||
|
if (style[key].indexOf('__no_value') > -1) {
|
||||||
|
style[key] = '';
|
||||||
|
} else {
|
||||||
|
styleObj[key] = style[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return styleObj;
|
||||||
};
|
};
|
||||||
|
52
src/plugins/condition/utils/time.js
Normal file
52
src/plugins/condition/utils/time.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
export const getLatestTimestamp = (
|
||||||
|
currentTimestamp,
|
||||||
|
compareTimestamp,
|
||||||
|
timeSystems,
|
||||||
|
currentTimeSystem
|
||||||
|
) => {
|
||||||
|
let latest = { ...currentTimestamp };
|
||||||
|
const compare = { ...compareTimestamp };
|
||||||
|
const key = currentTimeSystem.key;
|
||||||
|
|
||||||
|
if (!latest || !latest[key]) {
|
||||||
|
latest = updateLatestTimeStamp(compare, timeSystems)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compare[key] > latest[key]) {
|
||||||
|
latest = updateLatestTimeStamp(compare, timeSystems)
|
||||||
|
}
|
||||||
|
|
||||||
|
return latest;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLatestTimeStamp(timestamp, timeSystems) {
|
||||||
|
let latest = {};
|
||||||
|
|
||||||
|
timeSystems.forEach(timeSystem => {
|
||||||
|
latest[timeSystem.key] = timestamp[timeSystem.key];
|
||||||
|
});
|
||||||
|
|
||||||
|
return latest;
|
||||||
|
}
|
@ -21,13 +21,14 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<a class="c-condition-widget"
|
<component :is="urlDefined ? 'a' : 'span'"
|
||||||
:href="internalDomainObject.url"
|
class="c-condition-widget"
|
||||||
|
:href="urlDefined ? internalDomainObject.url : null"
|
||||||
>
|
>
|
||||||
<div class="c-condition-widget__label">
|
<div class="c-condition-widget__label">
|
||||||
{{ internalDomainObject.label }}
|
{{ internalDomainObject.label }}
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -38,6 +39,11 @@ export default {
|
|||||||
internalDomainObject: this.domainObject
|
internalDomainObject: this.domainObject
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
urlDefined() {
|
||||||
|
return this.internalDomainObject.url && this.internalDomainObject.url.length > 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.unlisten = this.openmct.objects.observe(this.internalDomainObject, '*', this.updateInternalDomainObject);
|
this.unlisten = this.openmct.objects.observe(this.internalDomainObject, '*', this.updateInternalDomainObject);
|
||||||
},
|
},
|
||||||
|
@ -28,10 +28,12 @@
|
|||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: $interiorMarginLg $interiorMarginLg * 2;
|
padding: $interiorMarginLg $interiorMarginLg * 2;
|
||||||
cursor: inherit !important;
|
}
|
||||||
&[href] {
|
|
||||||
|
a.c-condition-widget {
|
||||||
|
// Widget is conditionally made into a <a> when URL property has been defined
|
||||||
cursor: pointer !important;
|
cursor: pointer !important;
|
||||||
}
|
pointer-events: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make Condition Widget expand when in a hidden frame Layout context
|
// Make Condition Widget expand when in a hidden frame Layout context
|
||||||
|
@ -43,7 +43,7 @@ export default {
|
|||||||
makeDefinition() {
|
makeDefinition() {
|
||||||
return {
|
return {
|
||||||
fill: '#717171',
|
fill: '#717171',
|
||||||
stroke: 'transparent',
|
stroke: '',
|
||||||
x: 1,
|
x: 1,
|
||||||
y: 1,
|
y: 1,
|
||||||
width: 10,
|
width: 10,
|
||||||
@ -74,13 +74,14 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
style() {
|
style() {
|
||||||
return Object.assign({
|
if (this.itemStyle) {
|
||||||
|
return this.itemStyle;
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
backgroundColor: this.item.fill,
|
backgroundColor: this.item.fill,
|
||||||
border: '1px solid ' + this.item.stroke
|
border: this.item.stroke ? '1px solid ' + this.item.stroke : ''
|
||||||
}, this.itemStyle);
|
};
|
||||||
},
|
}
|
||||||
styleClass() {
|
|
||||||
return this.itemStyle && this.itemStyle.isStyleInvisible;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -68,7 +68,6 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import uuid from 'uuid';
|
import uuid from 'uuid';
|
||||||
|
|
||||||
import SubobjectView from './SubobjectView.vue'
|
import SubobjectView from './SubobjectView.vue'
|
||||||
import TelemetryView from './TelemetryView.vue'
|
import TelemetryView from './TelemetryView.vue'
|
||||||
import BoxView from './BoxView.vue'
|
import BoxView from './BoxView.vue'
|
||||||
@ -76,6 +75,7 @@ import TextView from './TextView.vue'
|
|||||||
import LineView from './LineView.vue'
|
import LineView from './LineView.vue'
|
||||||
import ImageView from './ImageView.vue'
|
import ImageView from './ImageView.vue'
|
||||||
import EditMarquee from './EditMarquee.vue'
|
import EditMarquee from './EditMarquee.vue'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
const ITEM_TYPE_VIEW_MAP = {
|
const ITEM_TYPE_VIEW_MAP = {
|
||||||
'subobject-view': SubobjectView,
|
'subobject-view': SubobjectView,
|
||||||
@ -512,7 +512,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateTelemetryFormat(item, format) {
|
updateTelemetryFormat(item, format) {
|
||||||
let index = _.findIndex(this.layoutItems, item);
|
let index = this.layoutItems.findIndex(item);
|
||||||
item.format = format;
|
item.format = format;
|
||||||
this.mutate(`configuration.items[${index}]`, item);
|
this.mutate(`configuration.items[${index}]`, item);
|
||||||
}
|
}
|
||||||
|
@ -74,13 +74,18 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
style() {
|
style() {
|
||||||
|
let backgroundImage = 'url(' + this.item.url + ')';
|
||||||
|
let border = '1px solid ' + this.item.stroke;
|
||||||
|
if (this.itemStyle) {
|
||||||
|
if (this.itemStyle.imageUrl !== undefined) {
|
||||||
|
backgroundImage = 'url(' + this.itemStyle.imageUrl + ')';
|
||||||
|
}
|
||||||
|
border = this.itemStyle.border;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
backgroundImage: this.itemStyle ? ('url(' + this.itemStyle.imageUrl + ')') : 'url(' + this.item.url + ')',
|
backgroundImage,
|
||||||
border: (this.itemStyle && this.itemStyle.border) ? this.itemStyle.border : ('1px solid ' + this.item.stroke)
|
border
|
||||||
};
|
};
|
||||||
},
|
|
||||||
styleClass() {
|
|
||||||
return this.itemStyle && this.itemStyle.isStyleInvisible;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import LayoutDrag from './../LayoutDrag'
|
import LayoutDrag from './../LayoutDrag'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
<script>
|
<script>
|
||||||
|
|
||||||
import conditionalStylesMixin from "../mixins/objectStyles-mixin";
|
import conditionalStylesMixin from "../mixins/objectStyles-mixin";
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
const START_HANDLE_QUADRANTS = {
|
const START_HANDLE_QUADRANTS = {
|
||||||
1: 'c-frame-edit__handle--sw',
|
1: 'c-frame-edit__handle--sw',
|
||||||
@ -127,8 +128,11 @@ export default {
|
|||||||
return {x, y, x2, y2};
|
return {x, y, x2, y2};
|
||||||
},
|
},
|
||||||
stroke() {
|
stroke() {
|
||||||
if (this.itemStyle && this.itemStyle.border) {
|
if (this.itemStyle) {
|
||||||
|
if (this.itemStyle.border) {
|
||||||
return this.itemStyle.border.replace('1px solid ', '');
|
return this.itemStyle.border.replace('1px solid ', '');
|
||||||
|
}
|
||||||
|
return '';
|
||||||
} else {
|
} else {
|
||||||
return this.item.stroke;
|
return this.item.stroke;
|
||||||
}
|
}
|
||||||
@ -146,9 +150,6 @@ export default {
|
|||||||
height: `${height}px`
|
height: `${height}px`
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
styleClass() {
|
|
||||||
return this.itemStyle && this.itemStyle.isStyleInvisible;
|
|
||||||
},
|
|
||||||
startHandleClass() {
|
startHandleClass() {
|
||||||
return START_HANDLE_QUADRANTS[this.vectorQuadrant];
|
return START_HANDLE_QUADRANTS[this.vectorQuadrant];
|
||||||
},
|
},
|
||||||
|
@ -30,14 +30,13 @@
|
|||||||
<div
|
<div
|
||||||
v-if="domainObject"
|
v-if="domainObject"
|
||||||
class="c-telemetry-view"
|
class="c-telemetry-view"
|
||||||
|
:class="styleClass"
|
||||||
:style="styleObject"
|
:style="styleObject"
|
||||||
@contextmenu.prevent="showContextMenu"
|
@contextmenu.prevent="showContextMenu"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="showLabel"
|
v-if="showLabel"
|
||||||
class="c-telemetry-view__label"
|
class="c-telemetry-view__label"
|
||||||
:class="[styleClass]"
|
|
||||||
:style="objectStyle"
|
|
||||||
>
|
>
|
||||||
<div class="c-telemetry-view__label-text">
|
<div class="c-telemetry-view__label-text">
|
||||||
{{ domainObject.name }}
|
{{ domainObject.name }}
|
||||||
@ -48,8 +47,7 @@
|
|||||||
v-if="showValue"
|
v-if="showValue"
|
||||||
:title="fieldName"
|
:title="fieldName"
|
||||||
class="c-telemetry-view__value"
|
class="c-telemetry-view__value"
|
||||||
:class="[telemetryClass, !telemetryClass && styleClass]"
|
:class="[telemetryClass]"
|
||||||
:style="!telemetryClass && objectStyle"
|
|
||||||
>
|
>
|
||||||
<div class="c-telemetry-view__value-text">
|
<div class="c-telemetry-view__value-text">
|
||||||
{{ telemetryValue }}
|
{{ telemetryValue }}
|
||||||
@ -62,7 +60,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import LayoutFrame from './LayoutFrame.vue'
|
import LayoutFrame from './LayoutFrame.vue'
|
||||||
import printj from 'printj'
|
import printj from 'printj'
|
||||||
import StyleRuleManager from "../../condition/StyleRuleManager";
|
import conditionalStylesMixin from "../mixins/objectStyles-mixin";
|
||||||
|
|
||||||
const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5],
|
const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5],
|
||||||
DEFAULT_POSITION = [1, 1],
|
DEFAULT_POSITION = [1, 1],
|
||||||
@ -81,8 +79,8 @@ export default {
|
|||||||
height: DEFAULT_TELEMETRY_DIMENSIONS[1],
|
height: DEFAULT_TELEMETRY_DIMENSIONS[1],
|
||||||
displayMode: 'all',
|
displayMode: 'all',
|
||||||
value: metadata.getDefaultDisplayValue(),
|
value: metadata.getDefaultDisplayValue(),
|
||||||
stroke: "transparent",
|
stroke: "",
|
||||||
fill: "transparent",
|
fill: "",
|
||||||
color: "",
|
color: "",
|
||||||
size: "13px"
|
size: "13px"
|
||||||
};
|
};
|
||||||
@ -91,6 +89,7 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
LayoutFrame
|
LayoutFrame
|
||||||
},
|
},
|
||||||
|
mixins: [conditionalStylesMixin],
|
||||||
props: {
|
props: {
|
||||||
item: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -113,8 +112,7 @@ export default {
|
|||||||
datum: undefined,
|
datum: undefined,
|
||||||
formats: undefined,
|
formats: undefined,
|
||||||
domainObject: undefined,
|
domainObject: undefined,
|
||||||
currentObjectPath: undefined,
|
currentObjectPath: undefined
|
||||||
objectStyle: ''
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -127,15 +125,10 @@ export default {
|
|||||||
return displayMode === 'all' || displayMode === 'value';
|
return displayMode === 'all' || displayMode === 'value';
|
||||||
},
|
},
|
||||||
styleObject() {
|
styleObject() {
|
||||||
return {
|
return Object.assign({}, {
|
||||||
backgroundColor: this.item.fill,
|
|
||||||
borderColor: this.item.stroke,
|
|
||||||
color: this.item.color,
|
|
||||||
fontSize: this.item.size
|
fontSize: this.item.size
|
||||||
}
|
}, this.itemStyle);
|
||||||
},
|
|
||||||
styleClass() {
|
|
||||||
return this.objectStyle && this.objectStyle.isStyleInvisible;
|
|
||||||
},
|
},
|
||||||
fieldName() {
|
fieldName() {
|
||||||
return this.valueMetadata && this.valueMetadata.name;
|
return this.valueMetadata && this.valueMetadata.name;
|
||||||
@ -190,15 +183,6 @@ export default {
|
|||||||
this.removeSelectable();
|
this.removeSelectable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.unlistenStyles) {
|
|
||||||
this.unlistenStyles();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.styleRuleManager) {
|
|
||||||
this.styleRuleManager.destroy();
|
|
||||||
delete this.styleRuleManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.openmct.time.off("bounds", this.refreshData);
|
this.openmct.time.off("bounds", this.refreshData);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -241,7 +225,6 @@ export default {
|
|||||||
},
|
},
|
||||||
setObject(domainObject) {
|
setObject(domainObject) {
|
||||||
this.domainObject = domainObject;
|
this.domainObject = domainObject;
|
||||||
this.initObjectStyles();
|
|
||||||
this.keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
|
this.keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||||
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
||||||
this.limitEvaluator = this.openmct.telemetry.limitEvaluator(this.domainObject);
|
this.limitEvaluator = this.openmct.telemetry.limitEvaluator(this.domainObject);
|
||||||
@ -265,31 +248,7 @@ export default {
|
|||||||
this.$emit('formatChanged', this.item, format);
|
this.$emit('formatChanged', this.item, format);
|
||||||
},
|
},
|
||||||
showContextMenu(event) {
|
showContextMenu(event) {
|
||||||
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
|
this.openmct.menus._showObjectMenu(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
|
||||||
},
|
|
||||||
initObjectStyles() {
|
|
||||||
if (this.domainObject.configuration) {
|
|
||||||
this.styleRuleManager = new StyleRuleManager(this.domainObject.configuration.objectStyles, this.openmct, this.updateStyle.bind(this));
|
|
||||||
|
|
||||||
if (this.unlistenStyles) {
|
|
||||||
this.unlistenStyles();
|
|
||||||
}
|
|
||||||
this.unlistenStyles = this.openmct.objects.observe(this.domainObject, 'configuration.objectStyles', (newObjectStyle) => {
|
|
||||||
//Updating object styles in the inspector view will trigger this so that the changes are reflected immediately
|
|
||||||
this.styleRuleManager.updateObjectStyleConfig(newObjectStyle);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
updateStyle(styleObj) {
|
|
||||||
let keys = Object.keys(styleObj);
|
|
||||||
keys.forEach(key => {
|
|
||||||
if ((typeof styleObj[key] === 'string') && (styleObj[key].indexOf('transparent') > -1)) {
|
|
||||||
if (styleObj[key]) {
|
|
||||||
styleObj[key] = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.objectStyle = styleObj;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
:class="[styleClass]"
|
:class="[styleClass]"
|
||||||
:style="style"
|
:style="style"
|
||||||
>
|
>
|
||||||
{{ item.text }}
|
<div class="c-text-view__text">{{ item.text }}</div>
|
||||||
</div>
|
</div>
|
||||||
</layout-frame>
|
</layout-frame>
|
||||||
</template>
|
</template>
|
||||||
@ -44,8 +44,8 @@ import conditionalStylesMixin from "../mixins/objectStyles-mixin";
|
|||||||
export default {
|
export default {
|
||||||
makeDefinition(openmct, gridSize, element) {
|
makeDefinition(openmct, gridSize, element) {
|
||||||
return {
|
return {
|
||||||
fill: 'transparent',
|
fill: '',
|
||||||
stroke: 'transparent',
|
stroke: '',
|
||||||
size: '13px',
|
size: '13px',
|
||||||
color: '',
|
color: '',
|
||||||
x: 1,
|
x: 1,
|
||||||
@ -80,14 +80,8 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
style() {
|
style() {
|
||||||
return Object.assign({
|
return Object.assign({
|
||||||
backgroundColor: this.item.fill,
|
|
||||||
border: '1px solid ' + this.item.stroke,
|
|
||||||
color: this.item.color,
|
|
||||||
fontSize: this.item.size
|
fontSize: this.item.size
|
||||||
}, this.itemStyle);
|
}, this.itemStyle);
|
||||||
},
|
|
||||||
styleClass() {
|
|
||||||
return this.itemStyle && this.itemStyle.isStyleInvisible;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user