Compare commits

...

141 Commits

Author SHA1 Message Date
Joel McKinnon
08656a6674 persist output string selection 2020-01-16 15:29:07 -08:00
Joel McKinnon
642499d519 added string output field 2020-01-16 09:56:17 -08:00
Joel McKinnon
fa0a54eee7 css fixes and add any/all control 2020-01-16 09:13:43 -08:00
Joel McKinnon
82f175f6c7 fixed style issues and added default select labels 2020-01-15 17:59:51 -08:00
Joshi
9fd720777b Merge branch 'conditionSet-view' of https://github.com/nasa/openmct into conditionSet-with-classes 2020-01-15 11:28:18 -08:00
Joshi
4c68c725b1 Adding telemetry options to ConditionEdit 2020-01-15 10:51:45 -08:00
Joel McKinnon
06a5207c6d deriving current output from current (blue) condition output and persisting 2020-01-14 17:07:32 -08:00
Joel McKinnon
78b885c508 using current condition output for current output label 2020-01-14 13:44:19 -08:00
Joshi
a18a3b6099 Adds telemetry objects on composition add 2020-01-14 13:32:13 -08:00
Joshi
81b8a76f1b (WIP) Fixes cyclic error while saving conditionCollection 2020-01-14 10:57:00 -08:00
Joshi
31736fa194 Merge branch 'conditionSet-view' of https://github.com/nasa/openmct into conditionSet-with-classes 2020-01-14 10:27:10 -08:00
Joshi
33632ef1dc (WIP) conditionSets using ConditionClasses 2020-01-14 09:52:12 -08:00
Joel McKinnon
94305ed82c persist data changes on update 2020-01-14 09:29:00 -08:00
Joel McKinnon
c8abc45e25 add default condition only when none present 2020-01-14 08:38:12 -08:00
Joshi
cd25459ac9 Merge branch 'conditionSet-telemetry' of https://github.com/nasa/openmct into conditionSet-view 2020-01-13 22:53:45 -08:00
Joshi
aaf1eb8059 Merge branch 'condition-class' of https://github.com/nasa/openmct into conditionSet-view 2020-01-13 22:52:51 -08:00
Joshi
8ca202d0a9 Merge branch 'topic-conditionals' of https://github.com/nasa/openmct into condition-class 2020-01-13 22:48:08 -08:00
Joshi
d2f7904118 Merge branch 'topic-conditionals' of https://github.com/nasa/openmct into conditionSet-telemetry 2020-01-13 22:47:52 -08:00
Joel McKinnon
2d059fb856 Merge pull request #2610 from nasa/telemetry-criterion
Adds telemetry criterion class and related tests
2020-01-13 16:07:32 -08:00
Joshi
8bbd7898bb Updates conditionSet composition policy to allow only telemetry since we're no longer using composition for condition domain objects 2020-01-13 14:59:45 -08:00
Nikhil Mandlik
ea6f8c9a50 small fixes 2020-01-13 14:45:00 -08:00
Joshi
d152440436 Fixes careless mistake - undefined object. 2020-01-13 14:12:05 -08:00
Joshi
1ffe76a525 Fixes linting issue. 2020-01-13 14:09:59 -08:00
Joshi
a6825f530c Fixes failing test. 2020-01-13 14:05:43 -08:00
Joshi
7cf6dc386f Removes use of createOpenMCT and uses mock object for openmct instead. 2020-01-13 13:58:25 -08:00
Joshi
5d8252bb07 Adds tests for condition class 2020-01-13 13:55:54 -08:00
Joel McKinnon
e1e1e0fb2f temp 2020-01-13 13:52:26 -08:00
Joel McKinnon
4f7345563f temp 2020-01-13 13:40:43 -08:00
Joel McKinnon
68a2b9f3a8 added Default name 2020-01-10 16:45:20 -08:00
Joel McKinnon
d79402c568 name property WIP 2020-01-10 15:58:16 -08:00
Joel McKinnon
d0e8f650be remove condition with persistance 2020-01-10 12:59:43 -08:00
Joel McKinnon
d819c6efe2 add condition button working with persistance 2020-01-10 12:22:05 -08:00
Joshi
91c877f234 Adds tests for Condition class 2020-01-10 10:43:55 -08:00
Joshi
55a674ba7b Merge branch 'topic-conditionals' of https://github.com/nasa/openmct into condition-class 2020-01-09 06:46:27 -08:00
Joshi
36055b7c04 Changes name of emitted event 2020-01-09 06:44:19 -08:00
Joshi
fe3cc661d3 Fixes tests. 2020-01-08 12:20:17 -08:00
Joshi
eb7efae1cc Persist condition to conditionSet. Remove extra condition unshift in addCondition method. 2020-01-07 11:56:24 -08:00
Joshi
63f8fb54d4 conditions added to conditioncollection 2020-01-07 11:42:31 -08:00
Joshi
097fa2e655 condition collection add to composition 2020-01-07 08:44:30 -08:00
Joshi
3d0b4d51c2 Merge branch 'topic-conditionals' of https://github.com/nasa/openmct into telemetry-criterion 2020-01-06 13:10:58 -08:00
Joel McKinnon
37650487f7 Merge pull request #2608 from nasa/conditionSet-view-provider
Condition set view provider
2020-01-06 13:10:00 -08:00
Joel McKinnon
6ccc0b4fbf added TODO comments 2020-01-06 12:04:19 -08:00
Joel McKinnon
79fe95372d fix lint errors 2020-01-06 10:44:09 -08:00
Joel McKinnon
6adb190d0e Merge branch 'conditionSet-view' of https://github.com/nasa/openmct into conditionSet-view-provider 2020-01-06 10:36:25 -08:00
Joel McKinnon
c094e6c6f4 change icon 2020-01-06 10:35:10 -08:00
Joshi
8c796b4e57 Allows adding new conditions and associated criteria.
Stub for evaluating conditions.
2020-01-06 10:09:47 -08:00
Joel McKinnon
c08e9a89ff add condition 2020-01-06 09:48:11 -08:00
Joshi
cc8ba18ccc Fixes condition plugin tests 2020-01-03 11:27:06 -08:00
Joel McKinnon
57c671a42e combined tests in one pluginSpec file 2020-01-03 09:13:17 -08:00
Joel McKinnon
1ee6ecf3ae removed conditionSet folder and fixed lint errors 2020-01-03 08:39:13 -08:00
Joel McKinnon
5f80b3773b restructured folders 2020-01-02 15:19:57 -08:00
Joel McKinnon
8452455050 WIP: all condition set UI elements in place - started condition form elements 2020-01-02 12:59:32 -08:00
Joel McKinnon
e5d8f60cdb WIP: all condition set UI elements in place except condition form elements 2019-12-31 11:33:33 -08:00
Joel McKinnon
de466000a0 WIP: styling for conditionSet and condition 2019-12-30 18:26:59 -08:00
Joel McKinnon
49664c011c component styling and expand funcitonality 2019-12-27 18:17:56 -08:00
Joel McKinnon
cf34d6b127 added domainObject bakc into provider 2019-12-27 14:23:04 -08:00
Joel McKinnon
e52f6ce099 WIP: styling components 2019-12-27 14:19:39 -08:00
Joel McKinnon
1ecdc4c487 addressed review comment 2019-12-27 13:22:05 -08:00
Joel McKinnon
d38e2c49cb WIP: current output styling 2019-12-27 13:20:21 -08:00
Joshi
f8464fa76f Adds telemetry criterion class and related tests 2019-12-27 12:57:30 -08:00
Joel McKinnon
308ae2cb2e added CurrentOutput and TestData components 2019-12-26 16:07:55 -08:00
Joel McKinnon
88219659fb renamed Conditions component to ConditionSet 2019-12-26 13:40:58 -08:00
Joel McKinnon
c34c2df061 remove fdescribe 2019-12-26 12:36:58 -08:00
Joel McKinnon
99c7bd4c10 added conditions and condition components 2019-12-26 12:25:30 -08:00
Joel McKinnon
f93d5a6fbf skeletal html mockup 2019-12-26 08:25:58 -08:00
Joel McKinnon
cd116667be change to inject domainObject 2019-12-23 14:32:57 -08:00
Joel McKinnon
2f2de3952d addressed review comments 2019-12-23 12:14:35 -08:00
Joel McKinnon
45e56798c5 removed fit 2019-12-23 11:24:25 -08:00
Joel McKinnon
0664d480e6 conditionSet provider with tests 2019-12-23 11:19:56 -08:00
Joel McKinnon
283599ddf5 Merge branch 'topic-conditionals' of https://github.com/nasa/openmct into conditionSet-view-provider 2019-12-20 09:56:26 -08:00
Joel McKinnon
09e3ceefa0 Merge pull request #2600 from nasa/condition-set-policy
Adds ConditionSet composition policy. Allows conditions to be added to conditionSets
2019-12-20 08:51:37 -08:00
Joshi
87f76ebfe4 Addresses comments. 2019-12-19 21:20:38 -08:00
Joshi
55a195b841 Adds ConditionSet composition policy. Allows conditions to be added to conditionSets 2019-12-19 12:33:11 -08:00
Joel McKinnon
c7946fd7b3 refactor conditionSet pluginSpec 2019-12-19 11:14:55 -08:00
Joel McKinnon
5d3ba3199c Merge remote-tracking branch 'origin/topic-conditionals' into conditionSet-view-provider 2019-12-19 09:07:44 -08:00
Joel McKinnon
f0d10306fc completing merge 2019-12-19 09:06:19 -08:00
Joel McKinnon
161943b5b8 Merge pull request #2598 from nasa/condition-type
Adds new condition type and plugin. Also adds tests
2019-12-18 15:56:20 -08:00
Shefali Joshi
e545043a26 Merge branch 'topic-conditionals' into condition-type 2019-12-18 15:52:46 -08:00
Shefali Joshi
40fb58b5b7 Merge pull request #2597 from nasa/conditionSet-object-type
Condition set object type
2019-12-18 15:50:42 -08:00
Joshi
1f9d4708b3 Adds copyright 2019-12-18 13:19:21 -08:00
Joshi
162809e081 [#2570] adds new condition type and plugin. Also adds tests 2019-12-18 13:13:54 -08:00
Joel McKinnon
482c871ac2 removed fdescribe 2019-12-18 13:10:29 -08:00
Joel McKinnon
f0b3311630 fixed merge conflicts 2019-12-18 13:01:28 -08:00
Joel McKinnon
656d6d6c3f addressed review comments 2019-12-18 12:48:05 -08:00
Joel McKinnon
ea45f0f4aa WIP 2019-12-18 12:16:25 -08:00
Joel McKinnon
6a25cb0a58 renaming 2019-12-18 11:50:10 -08:00
Joel McKinnon
4a1901420d removed fdescribe 2019-12-18 11:44:40 -08:00
Joel McKinnon
ad64f00608 WIP renaming 2019-12-18 11:43:20 -08:00
Joel McKinnon
65aea29cb9 renamed conditionCollection to conditionSet and made all filenames and references consistent 2019-12-18 11:23:37 -08:00
Joel McKinnon
7981424e9a WIP: - preparing to rename branch 2019-12-18 11:08:21 -08:00
Joel McKinnon
10c4340475 completed tests for condition collection object 2019-12-17 13:24:34 -08:00
Joel McKinnon
0a95db1a51 fixed missing commas 2019-12-17 08:15:15 -08:00
Joel McKinnon
ace77dce65 WIP 2019-12-17 08:10:35 -08:00
Joel McKinnon
c1d58bb25f fixed another minor merge conflict 2019-12-16 16:55:26 -08:00
Joel McKinnon
fbcafe0f62 mfixed merge conflicts 2019-12-16 16:50:57 -08:00
Joel McKinnon
9a9d9222a9 Merge branch 'master' into condition-object-type 2019-12-16 14:52:48 -08:00
Joel McKinnon
221e5b4f6c Added tests for ConditionPlugin 2019-12-16 14:42:19 -08:00
Joshi
5df74aee68 [test-framework] Adds basic test for condition plugin 2019-12-16 11:06:19 -08:00
Nikhil
3b195e9c7d Example imagery vue (#2525)
* WIP: imagery vue refactor

* cleaup

* show orange border when paused.

* resize image and thumbs wrappers.

* scrollToBottom fixed.

* fixed lint errors

* use multipane vue component for resize + cleanup + style adjustments.

* added min-height to image pane and thumbs-layout pane.

* remove old plugin and using es6 const.

* using ES6 imports.

* clean up + formatting changes.

* updated as per review comments.

* extracted styles from vue component.

* fixed lint errors.

* updated as per review comments + cleanup.
2019-12-13 15:36:01 -08:00
Joel McKinnon
17838d8040 WIP: setting up test framework for conditionals 2019-12-12 14:36:24 -08:00
Andrew Henry
2248c2da08 Removed styleguide 2019-12-11 16:21:51 -08:00
Andrew Henry
532c0e98db Merges TCR with master 2019-12-11 16:09:15 -08:00
Andrew Henry
ef3bae1312 Merge branch 'topic-core-refactor' into tcr-master 2019-12-11 15:56:24 -08:00
Andrew Henry
98c9cc92b8 Merge branch 'topic-core-refactor' into tcr-master 2019-12-11 14:52:11 -08:00
Andrew Henry
ecd8372efa Fixed merged conflict 2019-12-11 14:40:53 -08:00
Andrew Henry
76fc0b01fa Updated version number (#2574) 2019-12-11 14:22:51 -08:00
Joel McKinnon
f82ca91a61 changed node mules path 2019-12-06 15:13:03 -08:00
Andrew Henry
f86b8cce16 Merge branch 'topic-core-refactor' into tcr-master 2019-12-06 14:37:18 -08:00
Joel McKinnon
b06c234b59 import path for vue component 2019-12-06 13:02:23 -08:00
Joel McKinnon
31a7ebd4f1 basic skeleton for conditions code 2019-12-06 12:05:36 -08:00
Andrew Henry
c83e44ff1c Merged from master 2019-12-06 09:45:21 -08:00
Shefali Joshi
419285c396 Issue #2540 Removes old tutorial and links to the new openMCT tutorial (#2550) 2019-11-27 16:06:43 -08:00
Javier Revillas
3f6f893e29 [Startup] Stop using -h for aliasing --host (#2544)
This solves #2543 and includes documentation for the --host flag in the
help dialog.
2019-11-19 15:06:41 -08:00
Andrew Henry
14e8c7a401 Removed references to the "new API". (#2529)
It just causes confusion. There was also an out of date link that ironically pointed to the old API.
2019-11-04 13:53:47 -08:00
Andrew Henry
3dee6db5e2 Locked painterro version to 0.2.65. Fixes #2447 (#2448) 2019-08-21 13:53:00 -07:00
Andrew Henry
98c8e19d93 Only persist latest mutated model. (#2295)
* Only persist latest mutated model. Fixes #2277

* Updated tests

* Fixed style issues
2019-02-22 13:45:44 -08:00
Pete Richards
a8ba3b3fdb Merge pull request #2228 from MarvinJWendt/grammar-fix
Grammar fixes in API.md
2018-12-11 20:07:01 -08:00
Aayush Arora (angularboy)
1b31a472a5 URL validation Removed (#2219)
* Removed Regex from Hypelink Bundle
2018-11-27 08:26:06 -08:00
Pete Richards
e5fe8fd975 Save As clears transaction while undirtying (#1471)
* mutation listener adds via transaction manager

Update the TransactingMutationListener to add items to a transaction
using the transactionManager so that they can be properly removed
from the transaction at a later date.

Prevents showing error dialogs during successful save, and also
prevents persisting duplicate objects.

Fixes #1468
2018-11-26 09:23:42 -08:00
MarvinJWendt
b36d1ca2bc Grammar fixes
Sources:
to experiment: https://en.oxforddictionaries.com/definition/experiment
2018-11-24 02:43:25 +01:00
Andrew Henry
e9730ced9e Should say License instead of Licenses (#2222) 2018-11-13 19:01:09 -05:00
Pete Richards
ff2f79b087 Update copyright and update filename so github detects it (#2220) 2018-11-13 15:42:56 -08:00
Pete Richards
76e163473a [Plot] Remove x-axis tick ellipses (#2212)
Remove ellipses from x-axis ticks and reversal of tick text.  This
allows PNG export to export ticks correctly instead of reversed.

Fixes #2177
2018-11-08 12:24:26 -08:00
Charles Hacskaylo
6fdc24ab21 Added larger hit area to allow better access to buttons (#2148)
Fixes #2147
2018-11-08 10:46:31 -08:00
Pete Richards
cb93124ee1 [readme] fix email address (#2210)
* fix email address

Update email address to match website, fix #2202

* update display address
2018-11-07 10:43:03 -08:00
Pete Richards
4bda4080d2 Consistent composition order (#2209)
* ensure composition loads in specified order

* Remove Modern JS to match current style guide
2018-11-07 10:07:57 -08:00
Pete Richards
e710cafb2c Mutate correct path for plot range (#2208)
Mutate correct path on object for axis range.  Fixes #2182.
2018-11-07 10:02:41 -08:00
Andrew Henry
e9643ad07f Added brief readmes for all plugins. (#2184) 2018-10-03 18:55:27 -07:00
Pete Richards
ca16892237 [cleanup] remove npm lodash (#2155)
remove npm lodash and unused scripts directory.  Removes usage of
lodash 3.10 in node files.
2018-08-31 12:04:16 -07:00
Pete Richards
a2b0d350d8 Merge pull request #2151 from nasa/update-d3-deps
Updated d3 dependency paths
2018-08-27 13:17:19 -07:00
Andrew Henry
534bdbae50 Updated d3 dependency paths 2018-08-27 10:19:39 -07:00
Andrew Henry
831873e7de Updated README to remove misleading references to instabilities in API. (#2150) 2018-08-21 10:38:12 -07:00
Pete Richards
622d246fdd Merge pull request #2129 from nasa/fixed-position-2125
[Fixed Position] Cannot add on objects when creating Fixed Position for the first time
2018-08-10 10:58:05 -07:00
Pete Richards
4a1ca9f299 Remove stray characters 2018-08-10 10:10:15 -07:00
Pete Richards
4e1de2678c Merge pull request #2134 from nasa/tables-2132
Change table row layout to use flex fixes #2132
2018-08-10 10:07:34 -07:00
Deep Tailor
33a4792531 do not show warning dialog when user moves an object from one location to another (#2142)
* dont show error dialog when user moves an object from one location to another

* add test for not showing blocking message on remove action

Fixes #2141
2018-08-10 10:06:40 -07:00
Pete Richards
37dd4856a6 Merge pull request #2145 from nasa/import-export-links
Fixes Import / Export to work correctly with links and contained objects.
2018-08-10 10:05:28 -07:00
Andrew Henry
6a9cf3389d Fixes #2144. Identifiers for objects and links now exported as identifier objects.
Use keystring as map key on import. Also removed redundant step to re-add imported objects to parent composition.
2018-08-10 07:09:59 -07:00
charlesh88
2da2395473 Change table row layout to use flex
Fixes #2132
- flex styles applied;
- CSS reorganized for better DRY;
- Set height on <tr> so that <td>'s won't collapse when
all cells of a row have empty values. This can occur when columns are
hidden in a Telemetry Table.
2018-07-27 18:04:06 -07:00
Deep Tailor
00ecd27bb3 fixes #2130
fix lingering event listener that was caused by function (setSelection) being stored in two different locations, causing pointer mis match
2018-07-26 12:21:10 -07:00
Deep Tailor
0fa4486dcf force a click on the fixed position element after initialize to initialise Fixed Position controller on the selection API 2018-07-25 16:31:31 -07:00
89 changed files with 2718 additions and 5415 deletions

67
API.md
View File

@@ -52,7 +52,6 @@
- [The URL Status Indicator](#the-url-status-indicator)
- [Creating a Simple Indicator](#creating-a-simple-indicator)
- [Custom Indicators](#custom-indicators)
- [Included Plugins](#included-plugins)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@@ -424,7 +423,7 @@ attribute | type | flags | notes
###### Value Hints
Each telemetry value description has an object defining hints. Keys in this this object represent the hint itself, and the value represents the weight of that hint. A lower weight means the hint has a higher priority. For example, multiple values could be hinted for use as the y axis of a plot (raw, engineering), but the highest priority would be the default choice. Likewise, a table will use hints to determine the default order of columns.
Each telemetry value description has an object defining hints. Keys in this this object represent the hint itself, and the value represents the weight of that hint. A lower weight means the hint has a higher priority. For example, multiple values could be hinted for use as the y-axis of a plot (raw, engineering), but the highest priority would be the default choice. Likewise, a table will use hints to determine the default order of columns.
Known hints:
@@ -506,7 +505,7 @@ example:
}
```
This strategy says "I want the lastest data point in this time range". A provider which recognizes this request should return only one value-- the latest-- in the requested time range. Depending on your back-end implementation, performing these queries in bulk can be a large performance increase. These are generally issued by views that are only capable of displaying a single value and only need to show the latest value.
This strategy says "I want the latest data point in this time range". A provider which recognizes this request should return only one value-- the latest-- in the requested time range. Depending on your back-end implementation, performing these queries in bulk can be a large performance increase. These are generally issued by views that are only capable of displaying a single value and only need to show the latest value.
##### `minmax` request strategy
@@ -601,7 +600,7 @@ evaluator, take a look at `examples/generator/SinewaveLimitProvider.js`.
### Telemetry Consumer APIs **draft**
The APIs for requesting telemetry from Open MCT -- e.g. for use in custom views -- are currently in draft state and are being revised. If you'd like to experiement with them before they are finalized, please contact the team via the contact-us link on our website.
The APIs for requesting telemetry from Open MCT -- e.g. for use in custom views -- are currently in draft state and are being revised. If you'd like to experiment with them before they are finalized, please contact the team via the contact-us link on our website.
## Time API
@@ -989,7 +988,7 @@ A common use case for indicators is to convey the state of some external system
persistence backend or HTTP server. So long as this system is accessible via HTTP request,
Open MCT provides a general purpose indicator to show whether the server is available and
returing a 2xx status code. The URL Status Indicator is made available as a default plugin. See
[Included Plugins](#included-plugins) below for details on how to install and configure the
the [documentation](./src/plugins/URLIndicatorPlugin) for details on how to install and configure the
URL Status Indicator.
### Creating a Simple Indicator
@@ -1028,7 +1027,7 @@ different colors to indicate status.
### Custom Indicators
A completely custom indicator can be added by simple providing a DOM element to place alongside other indicators.
A completely custom indicator can be added by simply providing a DOM element to place alongside other indicators.
``` javascript
var domNode = document.createElement('div');
@@ -1041,59 +1040,3 @@ A completely custom indicator can be added by simple providing a DOM element to
element: domNode
});
```
## Included Plugins
Open MCT is packaged along with a few general-purpose plugins:
* `openmct.plugins.Conductor` provides a user interface for working with time
within the application. If activated, configuration must be provided. This is
detailed in the section on [Time Conductor Configuration](#time-conductor-configuration).
* `openmct.plugins.CouchDB` is an adapter for using CouchDB for persistence
of user-created objects. This is a constructor that takes the URL for the
CouchDB database as a parameter, e.g.
```javascript
openmct.install(openmct.plugins.CouchDB('http://localhost:5984/openmct'))
```
* `openmct.plugins.Elasticsearch` is an adapter for using Elasticsearch for
persistence of user-created objects. This is a
constructor that takes the URL for the Elasticsearch instance as a
parameter. eg.
```javascript
openmct.install(openmct.plugins.CouchDB('http://localhost:9200'))
```
* `openmct.plugins.Espresso` and `openmct.plugins.Snow` are two different
themes (dark and light) available for Open MCT. Note that at least one
of these themes must be installed for Open MCT to appear correctly.
* `openmct.plugins.URLIndicator` adds an indicator which shows the
availability of a URL with the following options:
- `url` : URL to indicate the status of
- `iconClass`: Icon to show in the status bar, defaults to `icon-database`, [list of all icons](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home?view=items)
- `interval`: Interval between checking the connection, defaults to `10000`
- `label` Name showing up as text in the status bar, defaults to url
```javascript
openmct.install(openmct.plugins.URLIndicator({
url: 'http://localhost:8080',
iconClass: 'check',
interval: 10000,
label: 'Localhost'
})
);
```
* `openmct.plugins.LocalStorage` provides persistence of user-created
objects in browser-local storage. This is particularly useful in
development environments.
* `openmct.plugins.MyItems` adds a top-level folder named "My Items"
when the application is first started, providing a place for a
user to store created items.
* `openmct.plugins.UTCTimeSystem` provides a default time system for Open MCT.
Generally, you will want to either install these plugins, or install
different plugins that provide persistence and an initial folder
hierarchy.
eg.
```javascript
openmct.install(openmct.plugins.LocalStorage());
openmct.install(openmct.plugins.MyItems());
```

7
LICENSE.md Normal file
View File

@@ -0,0 +1,7 @@
# Open MCT License
Open MCT, Copyright (c) 2014-2019, 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.

View File

@@ -1,691 +0,0 @@
# Open MCT Licenses
Open MCT, Copyright (c) 2014-2017, 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 as follows.
## Software Components Licenses
This software includes components released under the following licenses:
---
### SuperSocket
#### Info
* Link: https://supersocket.codeplex.com/
* Version: 0.9.0.2
* Author: Kerry Jiang
* Description: Supports SuperWebSocket
#### License
Copyright 2012 Kerry Jiang (kerry-jiang@hotmail.com)
SuperSocket 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.
---
### SuperWebSocket
#### Info
* Link: https://superswebocket.codeplex.com/
* Version: 0.9.0.2
* Author: Kerry Jiang
* Description: WebSocket implementation for client-server communication
#### License
Copyright 2010-2013 Kerry Jiang (kerry-jiang@hotmail.com)
SuperWebSocket 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.
---
### log4net
#### Info
* Link: http://logging.apache.org/log4net/
* Version: 1.2.13
* Author: Apache Software Foundation
* Description: Logging.
#### License
Copyright © 2004-2015 Apache Software Foundation.
log4net 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.
---
### Blanket.js
#### Info
* Link: http://blanketjs.org/
* Version: 1.1.5
* Author: Alex Seville
* Description: Code coverage measurement and reporting
#### License
Copyright (c) 2013 Alex Seville
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### Jasmine
#### Info
* Link: http://jasmine.github.io/
* Version: 1.3.1
* Author: Pivotal Labs
* Description: Unit testing
#### License
Copyright (c) 2008-2011 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### RequireJS
#### Info
* Link: http://requirejs.org/
* Version: 2.1.22
* Author: The Dojo Foundation
* Description: Script loader
#### License
Copyright (c) 2010-2015, The Dojo Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### requirejs-text
#### Info
* Link: https://github.com/requirejs/text
* Version: 2.0.14
* Author: The Dojo Foundation
* Description: Text loading plugin for RequireJS
#### License
Copyright (c) 2010-2014, The Dojo Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---
### AngularJS
#### Info
* Link: http://angularjs.org/
* Version: 1.4.4
* Author: Google
* Description: Client-side web application framework
#### License
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### Angular-Route
#### Info
* Link: http://angularjs.org/
* Version: 1.4.4
* Author: Google
* Description: Client-side view routing
#### License
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### ES6-Promise
#### Info
* Link: https://github.com/jakearchibald/es6-promise
* Version: 3.0.2
* Authors: Yehuda Katz, Tom Dale, Stefan Penner and contributors
* Description: Promise polyfill for pre-ECMAScript 6 browsers
#### License
Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### screenfull.js
#### Info
* Link: https://github.com/sindresorhus/screenfull.js/
* Version: 3.0.0
* Author: Sindre Sorhus
* Description: Wrapper for cross-browser usage of fullscreen API
#### License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### Math.uuid.js
#### Info
* Link: https://github.com/broofa/node-uuid
* Version: 1.4.7
* Author: Robert Kieffer
* Description: Unique identifer generation.
#### License
Copyright (c) 2010-2012 Robert Kieffer
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### Normalize.css
#### Info
* Link: https://github.com/necolas/normalize.css
* Version: 1.1.2
* Authors: Nicolas Gallagher, Jonathan Neal
* Description: Browser style normalization
#### License
Copyright (c) Nicolas Gallagher and Jonathan Neal
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### Moment.js
#### Info
* Link: http://momentjs.com
* Version: 2.11.1
* Authors: Tim Wood, Iskren Chernev, Moment.js contributors
* Description: Time/date parsing/formatting
#### License
Copyright (c) 2011-2014 Tim Wood, Iskren Chernev, Moment.js contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### moment-duration-format
#### Info
* Link: https://github.com/jsmreese/moment-duration-format
* Version: 1.3.0
* Authors: John Madhavan-Reese
* Description: Duration parsing/formatting
#### License
Copyright 2014 John Madhavan-Reese
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### CSV.js
#### Info
* Link: https://github.com/knrz/CSV.js
* Version: 3.6.4
* Authors: Kash Nouroozi
* Description: Encoder for CSV (comma separated values) export
#### License
Copyright (c) 2014 Kash Nouroozi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
### FileSaver.js
#### Info
* Link: https://github.com/eligrey/FileSaver.js/
* Version: 0.0.2
* Authors: Eli Grey
* Description: File download initiator (for file exports)
#### License
Copyright © 2015 Eli Grey.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### Zepto
#### Info
* Link: http://zeptojs.com/
* Version: 1.1.6
* Authors: Thomas Fuchs
* Description: DOM manipulation
#### License
Copyright (c) 2010-2016 Thomas Fuchs
http://zeptojs.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### Json.NET
#### Info
* Link: http://www.newtonsoft.com/json
* Version: 6.0.8
* Author: Newtonsoft
* Description: JSON serialization/deserialization
#### License
Copyright (c) 2007 James Newton-King
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### Nancy
#### Info
* Link: http://nancyfx.org
* Version: 0.23.2
* Author: Andreas Håkansson, Steven Robbins and contributors
* Description: Embedded web server
#### License
Copyright © 2010 Andreas Håkansson, Steven Robbins and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### Nancy.Hosting.Self
#### Info
* Link: http://nancyfx.org
* Version: 0.23.2
* Author: Andreas Håkansson, Steven Robbins and contributors
* Description: Embedded web server
#### License
Copyright © 2010 Andreas Håkansson, Steven Robbins and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### Almond
* Link: https://github.com/requirejs/almond
* Version: 0.3.3
* Author: jQuery Foundation
* Description: Lightweight RequireJS replacement for builds
#### License
Copyright jQuery Foundation and other contributors, https://jquery.org/
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history
available at https://github.com/requirejs/almond
The following license applies to all parts of this software except as
documented below:
====
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====
Copyright and related rights for sample code are waived via CC0. Sample
code is defined as all source code displayed within the prose of the
documentation.
CC0: http://creativecommons.org/publicdomain/zero/1.0/
====
Files located in the node_modules directory, and certain utilities used
to build or test the software in the test and dist directories, are
externally maintained libraries used by this software which have their own
licenses; we recommend you read them, as their terms may differ from the
terms above.
### Lodash
* Link: https://lodash.com
* Version: 3.10.1
* Author: Dojo Foundation
* Description: Utility functions
#### License
Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
Based on Underscore.js, copyright 2009-2015 Jeremy Ashkenas,
DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
### EventEmitter3
* Link: https://github.com/primus/eventemitter3
* Version: 1.2.0
* Author: Arnout Kazemier
* Description: Event-driven programming support
#### License
The MIT License (MIT)
Copyright (c) 2014 Arnout Kazemier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

2
app.js
View File

@@ -16,7 +16,7 @@ const request = require('request');
// Defaults
options.port = options.port || options.p || 8080;
options.host = options.host || options.h || 'localhost';
options.host = options.host || 'localhost';
options.directory = options.directory || options.D || '.';
// Show command line options

View File

@@ -0,0 +1,80 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for All files</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="prettify.css" />
<link rel="stylesheet" href="base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
/
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Statements</span>
<span class='fraction'>0/0</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Branches</span>
<span class='fraction'>0/0</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Functions</span>
<span class='fraction'>0/0</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Lines</span>
<span class='fraction'>0/0</span>
</div>
</div>
</div>
<div class='status-line high'></div>
<div class="pad1">
<table class="coverage-summary">
<thead>
<tr>
<th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
<th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
<th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
<th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
<th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
<th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
<th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div><div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Wed Dec 11 2019 13:15:10 GMT-0800 (Pacific Standard Time)
</div>
</div>
<script src="prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="sorter.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

View File

@@ -0,0 +1,158 @@
var addSorting = (function () {
"use strict";
var cols,
currentSort = {
index: 0,
desc: false
};
// returns the summary table element
function getTable() { return document.querySelector('.coverage-summary'); }
// returns the thead element of the summary table
function getTableHeader() { return getTable().querySelector('thead tr'); }
// returns the tbody element of the summary table
function getTableBody() { return getTable().querySelector('tbody'); }
// returns the th element for nth column
function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; }
// loads all columns
function loadColumns() {
var colNodes = getTableHeader().querySelectorAll('th'),
colNode,
cols = [],
col,
i;
for (i = 0; i < colNodes.length; i += 1) {
colNode = colNodes[i];
col = {
key: colNode.getAttribute('data-col'),
sortable: !colNode.getAttribute('data-nosort'),
type: colNode.getAttribute('data-type') || 'string'
};
cols.push(col);
if (col.sortable) {
col.defaultDescSort = col.type === 'number';
colNode.innerHTML = colNode.innerHTML + '<span class="sorter"></span>';
}
}
return cols;
}
// attaches a data attribute to every tr element with an object
// of data values keyed by column name
function loadRowData(tableRow) {
var tableCols = tableRow.querySelectorAll('td'),
colNode,
col,
data = {},
i,
val;
for (i = 0; i < tableCols.length; i += 1) {
colNode = tableCols[i];
col = cols[i];
val = colNode.getAttribute('data-value');
if (col.type === 'number') {
val = Number(val);
}
data[col.key] = val;
}
return data;
}
// loads all row data
function loadData() {
var rows = getTableBody().querySelectorAll('tr'),
i;
for (i = 0; i < rows.length; i += 1) {
rows[i].data = loadRowData(rows[i]);
}
}
// sorts the table using the data for the ith column
function sortByIndex(index, desc) {
var key = cols[index].key,
sorter = function (a, b) {
a = a.data[key];
b = b.data[key];
return a < b ? -1 : a > b ? 1 : 0;
},
finalSorter = sorter,
tableBody = document.querySelector('.coverage-summary tbody'),
rowNodes = tableBody.querySelectorAll('tr'),
rows = [],
i;
if (desc) {
finalSorter = function (a, b) {
return -1 * sorter(a, b);
};
}
for (i = 0; i < rowNodes.length; i += 1) {
rows.push(rowNodes[i]);
tableBody.removeChild(rowNodes[i]);
}
rows.sort(finalSorter);
for (i = 0; i < rows.length; i += 1) {
tableBody.appendChild(rows[i]);
}
}
// removes sort indicators for current column being sorted
function removeSortIndicators() {
var col = getNthColumn(currentSort.index),
cls = col.className;
cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
col.className = cls;
}
// adds sort indicators for current column being sorted
function addSortIndicators() {
getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted';
}
// adds event listeners for all sorter widgets
function enableUI() {
var i,
el,
ithSorter = function ithSorter(i) {
var col = cols[i];
return function () {
var desc = col.defaultDescSort;
if (currentSort.index === i) {
desc = !currentSort.desc;
}
sortByIndex(i, desc);
removeSortIndicators();
currentSort.index = i;
currentSort.desc = desc;
addSortIndicators();
};
};
for (i =0 ; i < cols.length; i += 1) {
if (cols[i].sortable) {
// add the click event handler on the th so users
// dont have to click on those tiny arrows
el = getNthColumn(i).querySelector('.sorter').parentElement;
if (el.addEventListener) {
el.addEventListener('click', ithSorter(i));
} else {
el.attachEvent('onclick', ithSorter(i));
}
}
}
}
// adds sorting functionality to the UI
return function () {
if (!getTable()) {
return;
}
cols = loadColumns();
loadData(cols);
addSortIndicators();
enableUI();
};
})();
window.addEventListener('load', addSorting);

View File

@@ -33,5 +33,5 @@ As we transition to a new API, the following documentation for the old API
* The [Developer's Guide](guide/) goes into more detail about how to use the
platform and the functionality that it provides.
* The [Tutorials](tutorials/) give examples of extending the platform to add
* The [Tutorials](https://github.com/nasa/openmct-tutorial) give examples of extending the platform to add
functionality, and integrate with data sources.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -38,13 +38,12 @@
const THIRTY_MINUTES = 30 * 60 * 1000;
[
'example/eventGenerator',
'example/styleguide'
'example/eventGenerator'
].forEach(
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
);
openmct.install(openmct.plugins.Espresso());
openmct.install(openmct.plugins.Snow());
openmct.install(openmct.plugins.MyItems());
openmct.install(openmct.plugins.LocalStorage());
openmct.install(openmct.plugins.Generator());

View File

@@ -1,6 +1,6 @@
{
"name": "openmct",
"version": "1.0.0-beta",
"version": "1.0.0-snapshot",
"description": "The Open MCT core platform",
"dependencies": {},
"devDependencies": {
@@ -64,6 +64,7 @@
"request": "^2.69.0",
"split": "^1.0.0",
"style-loader": "^1.0.1",
"uuid": "^3.3.3",
"v8-compile-cache": "^1.1.0",
"vue": "2.5.6",
"vue-loader": "^15.2.6",

View File

@@ -102,14 +102,14 @@ define(
* @returns {Action[]} an array of matching actions
* @memberof platform/core.ActionCapability#
*/
ActionCapability.prototype.perform = function (context) {
ActionCapability.prototype.perform = function (context, flag) {
// Alias to getActions(context)[0].perform, with a
// check for empty arrays.
var actions = this.getActions(context);
return this.$q.when(
(actions && actions.length > 0) ?
actions[0].perform() :
actions[0].perform(flag) :
undefined
);
};

View File

@@ -91,7 +91,7 @@ define(
.then(function () {
return object
.getCapability('action')
.perform('remove');
.perform('remove', true);
});
};

View File

@@ -227,10 +227,11 @@ define(
locationPromise.resolve();
});
it("removes object from parent", function () {
it("removes object from parent without user warning dialog", function () {
expect(actionCapability.perform)
.toHaveBeenCalledWith('remove');
.toHaveBeenCalledWith('remove', true);
});
});
});
@@ -247,9 +248,9 @@ define(
.toHaveBeenCalled();
});
it("removes object from parent", function () {
it("removes object from parent without user warning dialog", function () {
expect(actionCapability.perform)
.toHaveBeenCalledWith('remove');
.toHaveBeenCalledWith('remove', true);
});
});

View File

@@ -1,86 +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/policies/ImageryViewPolicy",
"./src/controllers/ImageryController",
"./src/directives/MCTBackgroundImage",
"./res/templates/imagery.html"
], function (
ImageryViewPolicy,
ImageryController,
MCTBackgroundImage,
imageryTemplate
) {
return {
name:"platform/features/imagery",
definition: {
"name": "Plot view for telemetry",
"extensions": {
"views": [
{
"name": "Imagery",
"key": "imagery",
"cssClass": "icon-image",
"template": imageryTemplate,
"priority": "preferred",
"needs": [
"telemetry"
],
"editable": false
}
],
"policies": [
{
"category": "view",
"implementation": ImageryViewPolicy,
"depends": [
"openmct"
]
}
],
"controllers": [
{
"key": "ImageryController",
"implementation": ImageryController,
"depends": [
"$scope",
"$window",
"$element",
"openmct"
]
}
],
"directives": [
{
"key": "mctBackgroundImage",
"implementation": MCTBackgroundImage,
"depends": [
"$document"
]
}
]
}
}
};
});

View File

@@ -1,58 +0,0 @@
<div class="t-imagery c-imagery" ng-controller="ImageryController as imagery">
<mct-split-pane class='abs' anchor="bottom" alias="imagery">
<div class="split-pane-component has-local-controls l-image-main-wrapper l-flex-col">
<div class="h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover l-flex-row c-imagery__lc">
<span class="holder flex-elem grows c-imagery__lc__sliders">
<input class="icon-brightness" type="range"
min="0"
max="500"
ng-model="filters.brightness" />
<input class="icon-contrast" type="range"
min="0"
max="500"
ng-model="filters.contrast" />
</span>
<span class="holder flex-elem t-reset-btn-holder c-imagery__lc__reset-btn">
<a class="s-icon-button icon-reset t-btn-reset"
ng-click="filters = { brightness: 100, contrast: 100 }"></a>
</span>
</div>
<div class="l-image-main s-image-main flex-elem grows"
ng-class="{ paused: imagery.paused(), stale:false }">
<div class="image-main"
mct-background-image="imagery.getImageUrl()"
filters="filters">
</div>
</div>
<div class="l-image-main-controlbar flex-elem l-flex-row">
<div class="l-datetime-w flex-elem grows">
<a class="c-button show-thumbs sm hidden icon-thumbs-strip"
ng-click="showThumbsBubble = (showThumbsBubble) ? false:true"></a>
<span class="l-time">{{imagery.getTime()}}</span>
</div>
<div class="h-local-controls flex-elem">
<a class="c-button icon-pause pause-play"
ng-click="imagery.paused(!imagery.paused())"
ng-class="{ 'is-paused': imagery.paused() }"></a>
<a href=""
class="s-button l-mag s-mag vsm icon-reset"
ng-click="clipped = false"
ng-show="clipped === true"
title="Not all of image is visible; click to reset."></a>
</div>
</div>
</div>
<mct-splitter></mct-splitter>
<div class="split-pane-component l-image-thumbs-wrapper">
<div class="l-image-thumb-item" ng-class="{selected: image.selected}" ng-repeat="image in imageHistory track by $index"
ng-click="imagery.setSelectedImage(image)" ng-init="imagery.scrollToBottom()">
<img class="l-thumb"
ng-src={{imagery.getImageUrl(image)}}>
<div class="l-time">{{imagery.getTime(image)}}</div>
</div>
</div>
</mct-split-pane>
</div>

View File

@@ -1,284 +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.
*****************************************************************************/
/**
* This bundle implements views of image telemetry.
* @namespace platform/features/imagery
*/
define(
[
'zepto',
'lodash'
],
function ($, _) {
/**
* Controller for the "Imagery" view of a domain object which
* provides image telemetry.
* @constructor
* @memberof platform/features/imagery
*/
function ImageryController($scope, $window, element, openmct) {
this.$scope = $scope;
this.$window = $window;
this.openmct = openmct;
this.date = "";
this.time = "";
this.zone = "";
this.imageUrl = "";
this.requestCount = 0;
this.scrollable = $(".l-image-thumbs-wrapper");
this.autoScroll = openmct.time.clock() ? true : false;
this.$scope.imageHistory = [];
this.$scope.filters = {
brightness: 100,
contrast: 100
};
this.subscribe = this.subscribe.bind(this);
this.stopListening = this.stopListening.bind(this);
this.updateValues = this.updateValues.bind(this);
this.updateHistory = this.updateHistory.bind(this);
this.onBoundsChange = this.onBoundsChange.bind(this);
this.onScroll = this.onScroll.bind(this);
this.setSelectedImage = this.setSelectedImage.bind(this);
this.subscribe(this.$scope.domainObject);
this.$scope.$on('$destroy', this.stopListening);
this.openmct.time.on('bounds', this.onBoundsChange);
this.scrollable.on('scroll', this.onScroll);
}
ImageryController.prototype.subscribe = function (domainObject) {
this.date = "";
this.imageUrl = "";
this.openmct.objects.get(domainObject.getId())
.then(function (object) {
this.domainObject = object;
var metadata = this.openmct
.telemetry
.getMetadata(this.domainObject);
this.timeKey = this.openmct.time.timeSystem().key;
this.timeFormat = this.openmct
.telemetry
.getValueFormatter(metadata.value(this.timeKey));
this.imageFormat = this.openmct
.telemetry
.getValueFormatter(metadata.valuesForHints(['image'])[0]);
this.unsubscribe = this.openmct.telemetry
.subscribe(this.domainObject, function (datum) {
this.updateHistory(datum);
this.updateValues(datum);
}.bind(this));
this.requestHistory(this.openmct.time.bounds());
}.bind(this));
};
ImageryController.prototype.requestHistory = function (bounds) {
this.requestCount++;
this.$scope.imageHistory = [];
var requestId = this.requestCount;
this.openmct.telemetry
.request(this.domainObject, bounds)
.then(function (values) {
if (this.requestCount > requestId) {
return Promise.resolve('Stale request');
}
values.forEach(function (datum) {
this.updateHistory(datum);
}, this);
this.updateValues(values[values.length - 1]);
}.bind(this));
};
ImageryController.prototype.stopListening = function () {
this.openmct.time.off('bounds', this.onBoundsChange);
this.scrollable.off('scroll', this.onScroll);
if (this.unsubscribe) {
this.unsubscribe();
delete this.unsubscribe;
}
};
/**
* Responds to bound change event be requesting new
* historical data if the bound change was manual.
* @private
* @param {object} [newBounds] new bounds object
* @param {boolean} [tick] true when change is automatic
*/
ImageryController.prototype.onBoundsChange = function (newBounds, tick) {
if (this.domainObject && !tick) {
this.requestHistory(newBounds);
}
};
/**
* Updates displayable values to match those of the most
* recently received datum.
* @param {object} [datum] the datum
* @private
*/
ImageryController.prototype.updateValues = function (datum) {
if (this.isPaused) {
this.nextDatum = datum;
return;
}
this.time = this.timeFormat.format(datum);
this.imageUrl = this.imageFormat.format(datum);
};
/**
* Appends given imagery datum to running history.
* @private
* @param {object} [datum] target telemetry datum
* @returns {boolean} falsy when a duplicate datum is given
*/
ImageryController.prototype.updateHistory = function (datum) {
if (!this.datumMatchesMostRecent(datum)) {
var index = _.sortedIndex(this.$scope.imageHistory, datum, this.timeFormat.format.bind(this.timeFormat));
this.$scope.imageHistory.splice(index, 0, datum);
return true;
} else {
return false;
}
};
/**
* Checks to see if the given datum is the same as the most recent in history.
* @private
* @param {object} [datum] target telemetry datum
* @returns {boolean} true if datum is most recent in history, false otherwise
*/
ImageryController.prototype.datumMatchesMostRecent = function (datum) {
if (this.$scope.imageHistory.length !== 0) {
var datumTime = this.timeFormat.format(datum);
var datumURL = this.imageFormat.format(datum);
var lastHistoryTime = this.timeFormat.format(this.$scope.imageHistory.slice(-1)[0]);
var lastHistoryURL = this.imageFormat.format(this.$scope.imageHistory.slice(-1)[0]);
return datumTime === lastHistoryTime && datumURL === lastHistoryURL;
}
return false;
};
ImageryController.prototype.onScroll = function (event) {
this.$window.requestAnimationFrame(function () {
var thumbnailWrapperHeight = this.scrollable[0].offsetHeight;
var thumbnailWrapperWidth = this.scrollable[0].offsetWidth;
if (this.scrollable[0].scrollLeft <
(this.scrollable[0].scrollWidth - this.scrollable[0].clientWidth) - (thumbnailWrapperWidth) ||
this.scrollable[0].scrollTop <
(this.scrollable[0].scrollHeight - this.scrollable[0].clientHeight) - (thumbnailWrapperHeight)) {
this.autoScroll = false;
} else {
this.autoScroll = true;
}
}.bind(this));
};
/**
* Force history imagery div to scroll to bottom.
*/
ImageryController.prototype.scrollToBottom = function () {
if (this.autoScroll) {
this.scrollable[0].scrollTop = this.scrollable[0].scrollHeight;
}
};
/**
* Get the time portion (hours, minutes, seconds) of the
* timestamp associated with the incoming image telemetry
* if no parameter is given, or of a provided datum.
* @param {object} [datum] target telemetry datum
* @returns {string} the time
*/
ImageryController.prototype.getTime = function (datum) {
return datum ?
this.timeFormat.format(datum) :
this.time;
};
/**
* Get the URL of the most recent image telemetry if no
* parameter is given, or of a provided datum.
* @param {object} [datum] target telemetry datum
* @returns {string} URL for telemetry image
*/
ImageryController.prototype.getImageUrl = function (datum) {
return datum ?
this.imageFormat.format(datum) :
this.imageUrl;
};
/**
* Getter-setter for paused state of the view (true means
* paused, false means not.)
* @param {boolean} [state] the state to set
* @returns {boolean} the current state
*/
ImageryController.prototype.paused = function (state) {
if (arguments.length > 0 && state !== this.isPaused) {
this.unselectAllImages();
this.isPaused = state;
if (this.nextDatum) {
this.updateValues(this.nextDatum);
delete this.nextDatum;
} else {
this.updateValues(this.$scope.imageHistory[this.$scope.imageHistory.length - 1]);
}
this.autoScroll = true;
}
return this.isPaused;
};
/**
* Set the selected image on the state for the large imagery div to use.
* @param {object} [image] the image object to get url from.
*/
ImageryController.prototype.setSelectedImage = function (image) {
this.imageUrl = this.getImageUrl(image);
this.time = this.getTime(image);
this.paused(true);
this.unselectAllImages();
image.selected = true;
};
/**
* Loop through the history imagery data to set all images to unselected.
*/
ImageryController.prototype.unselectAllImages = function () {
for (var i = 0; i < this.$scope.imageHistory.length; i++) {
this.$scope.imageHistory[i].selected = false;
}
};
return ImageryController;
}
);

View File

@@ -1,110 +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 () {
/**
* Defines the `mct-background-image` directive.
*
* Used as an attribute, this will set the `background-image`
* property to the URL given in its value, but only after that
* image has loaded; this avoids "flashing" as images change.
*
* If the value of `mct-background-image`is falsy, no image
* will be displayed (immediately.)
*
* Optionally, a `filters` attribute may be specified as an
* object with `brightness` and/or `contrast` properties,
* whose values are percentages. A value of 100 will make
* no changes to the image's brightness or contrast.
*
* @constructor
* @memberof platform/features/imagery
*/
function MCTBackgroundImage($document) {
function link(scope, element) {
// General strategy here:
// - Keep count of how many images have been requested; this
// counter will be used as an internal identifier or sorts
// for each image that loads.
// - As the src attribute changes, begin loading those images.
// - When images do load, update the background-image property
// of the element, but only if a more recently
// requested image has not already been loaded.
// The order in which URLs are passed in and the order
// in which images are actually loaded may be different, so
// some strategy like this is necessary to ensure that images
// do not display out-of-order.
var requested = 0, loaded = 0;
function updateFilters(filters) {
var styleValue = filters ?
Object.keys(filters).map(function (k) {
return k + "(" + filters[k] + "%)";
}).join(' ') :
"";
element.css('filter', styleValue);
element.css('webkitFilter', styleValue);
}
function nextImage(url) {
var myCounter = requested,
image;
function useImage() {
if (loaded <= myCounter) {
loaded = myCounter;
element.css('background-image', "url('" + url + "')");
}
}
if (!url) {
loaded = myCounter;
element.css('background-image', 'none');
} else {
image = $document[0].createElement('img');
image.src = url;
image.onload = useImage;
}
requested += 1;
}
scope.$watch('mctBackgroundImage', nextImage);
scope.$watchCollection('filters', updateFilters);
}
return {
restrict: "A",
scope: {
mctBackgroundImage: "=",
filters: "="
},
link: link
};
}
return MCTBackgroundImage;
}
);

View File

@@ -1,59 +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/api/objects/object-utils'
], function (
objectUtils
) {
/**
* Policy preventing the Imagery view from being made available for
* domain objects which do not have associated image telemetry.
* @implements {Policy.<View, DomainObject>}
* @constructor
*/
function ImageryViewPolicy(openmct) {
this.openmct = openmct;
}
ImageryViewPolicy.prototype.hasImageTelemetry = function (domainObject) {
var newDO = objectUtils.toNewFormat(
domainObject.getModel(),
domainObject.getId()
);
var metadata = this.openmct.telemetry.getMetadata(newDO);
var values = metadata.valuesForHints(['image']);
return values.length >= 1;
};
ImageryViewPolicy.prototype.allow = function (view, domainObject) {
if (view.key === 'imagery' || view.key === 'historical-imagery') {
return this.hasImageTelemetry(domainObject);
}
return true;
};
return ImageryViewPolicy;
});

View File

@@ -1,271 +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(
[
"zepto",
"../../src/controllers/ImageryController"
],
function ($, ImageryController) {
var MOCK_ELEMENT_TEMPLATE =
'<div class="l-image-thumbs-wrapper"></div>';
xdescribe("The Imagery controller", function () {
var $scope,
openmct,
oldDomainObject,
newDomainObject,
unsubscribe,
metadata,
prefix,
controller,
requestPromise,
mockWindow,
mockElement;
beforeEach(function () {
$scope = jasmine.createSpyObj('$scope', ['$on', '$watch']);
oldDomainObject = jasmine.createSpyObj(
'domainObject',
['getId']
);
newDomainObject = { name: 'foo' };
oldDomainObject.getId.and.returnValue('testID');
openmct = {
objects: jasmine.createSpyObj('objectAPI', [
'get'
]),
time: jasmine.createSpyObj('timeAPI', [
'timeSystem',
'clock',
'on',
'off',
'bounds'
]),
telemetry: jasmine.createSpyObj('telemetryAPI', [
'subscribe',
'request',
'getValueFormatter',
'getMetadata'
])
};
metadata = jasmine.createSpyObj('metadata', [
'value',
'valuesForHints'
]);
metadata.value.and.returnValue("timestamp");
metadata.valuesForHints.and.returnValue(["value"]);
prefix = "formatted ";
unsubscribe = jasmine.createSpy('unsubscribe');
openmct.telemetry.subscribe.and.returnValue(unsubscribe);
openmct.time.timeSystem.and.returnValue({
key: 'testKey'
});
$scope.domainObject = oldDomainObject;
openmct.objects.get.and.returnValue(Promise.resolve(newDomainObject));
openmct.telemetry.getMetadata.and.returnValue(metadata);
openmct.telemetry.getValueFormatter.and.callFake(function (property) {
var formatter =
jasmine.createSpyObj("formatter-" + property, ['format']);
var isTime = (property === "timestamp");
formatter.format.and.callFake(function (datum) {
return (isTime ? prefix : "") + datum[property];
});
return formatter;
});
requestPromise = new Promise(function (resolve) {
setTimeout(function () {
resolve([{
timestamp: 1434600258123,
value: 'some/url'
}]);
}, 10);
});
openmct.telemetry.request.and.returnValue(requestPromise);
mockElement = $(MOCK_ELEMENT_TEMPLATE);
mockWindow = jasmine.createSpyObj('$window', ['requestAnimationFrame']);
mockWindow.requestAnimationFrame.and.callFake(function (f) {
return f();
});
controller = new ImageryController(
$scope,
mockWindow,
mockElement,
openmct
);
});
describe("when loaded", function () {
var callback,
boundsListener,
bounds;
beforeEach(function () {
return requestPromise.then(function () {
openmct.time.on.calls.all().forEach(function (call) {
if (call.args[0] === "bounds") {
boundsListener = call.args[1];
}
});
callback =
openmct.telemetry.subscribe.calls.mostRecent().args[1];
});
});
it("requests history", function () {
expect(openmct.telemetry.request).toHaveBeenCalledWith(
newDomainObject, bounds
);
expect(controller.getTime()).toEqual(prefix + 1434600258123);
expect(controller.getImageUrl()).toEqual('some/url');
});
it("exposes the latest telemetry values", function () {
callback({
timestamp: 1434600259456,
value: "some/other/url"
});
expect(controller.getTime()).toEqual(prefix + 1434600259456);
expect(controller.getImageUrl()).toEqual("some/other/url");
});
it("allows updates to be paused and unpaused", function () {
var newTimestamp = 1434600259456,
newUrl = "some/other/url",
initialTimestamp = controller.getTime(),
initialUrl = controller.getImageUrl();
expect(initialTimestamp).not.toBe(prefix + newTimestamp);
expect(initialUrl).not.toBe(newUrl);
expect(controller.paused()).toBeFalsy();
controller.paused(true);
expect(controller.paused()).toBeTruthy();
callback({ timestamp: newTimestamp, value: newUrl });
expect(controller.getTime()).toEqual(initialTimestamp);
expect(controller.getImageUrl()).toEqual(initialUrl);
controller.paused(false);
expect(controller.paused()).toBeFalsy();
expect(controller.getTime()).toEqual(prefix + newTimestamp);
expect(controller.getImageUrl()).toEqual(newUrl);
});
it("forwards large image view to latest image in history on un-pause", function () {
$scope.imageHistory = [
{ utc: 1434600258122, url: 'some/url1', selected: false},
{ utc: 1434600258123, url: 'some/url2', selected: false}
];
controller.paused(true);
controller.paused(false);
expect(controller.getImageUrl()).toEqual(controller.getImageUrl($scope.imageHistory[1]));
});
it("subscribes to telemetry", function () {
expect(openmct.telemetry.subscribe).toHaveBeenCalledWith(
newDomainObject,
jasmine.any(Function)
);
});
it("requests telemetry", function () {
expect(openmct.telemetry.request).toHaveBeenCalledWith(
newDomainObject,
bounds
);
});
it("unsubscribes and unlistens when scope is destroyed", function () {
expect(unsubscribe).not.toHaveBeenCalled();
$scope.$on.calls.all().forEach(function (call) {
if (call.args[0] === '$destroy') {
call.args[1]();
}
});
expect(unsubscribe).toHaveBeenCalled();
expect(openmct.time.off)
.toHaveBeenCalledWith('bounds', jasmine.any(Function));
});
it("listens for bounds event and responds to tick and manual change", function () {
var mockBounds = {start: 1434600000000, end: 1434600500000};
expect(openmct.time.on).toHaveBeenCalled();
openmct.telemetry.request.calls.reset();
boundsListener(mockBounds, true);
expect(openmct.telemetry.request).not.toHaveBeenCalled();
boundsListener(mockBounds, false);
expect(openmct.telemetry.request).toHaveBeenCalledWith(newDomainObject, mockBounds);
});
it ("doesnt append duplicate datum", function () {
var mockDatum = {value: 'image/url', timestamp: 1434700000000};
var mockDatum2 = {value: 'image/url', timestamp: 1434700000000};
var mockDatum3 = {value: 'image/url', url: 'someval', timestamp: 1434700000000};
expect(controller.updateHistory(mockDatum)).toBe(true);
expect(controller.updateHistory(mockDatum)).toBe(false);
expect(controller.updateHistory(mockDatum)).toBe(false);
expect(controller.updateHistory(mockDatum2)).toBe(false);
expect(controller.updateHistory(mockDatum3)).toBe(false);
});
describe("when user clicks on imagery thumbnail", function () {
var mockDatum = { utc: 1434600258123, url: 'some/url', selected: false};
it("pauses and adds selected class to imagery thumbnail", function () {
controller.setSelectedImage(mockDatum);
expect(controller.paused()).toBeTruthy();
expect(mockDatum.selected).toBeTruthy();
});
it("unselects previously selected image", function () {
$scope.imageHistory = [{ utc: 1434600258123, url: 'some/url', selected: true}];
controller.unselectAllImages();
expect($scope.imageHistory[0].selected).toBeFalsy();
});
it("updates larger image url and time", function () {
controller.setSelectedImage(mockDatum);
expect(controller.getImageUrl()).toEqual(controller.getImageUrl(mockDatum));
expect(controller.getTime()).toEqual(controller.timeFormat.format(mockDatum.utc));
});
});
});
it("initially shows an empty string for date/time", function () {
expect(controller.getTime()).toEqual("");
expect(controller.getImageUrl()).toEqual("");
});
});
}
);

View File

@@ -1,126 +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/directives/MCTBackgroundImage"],
function (MCTBackgroundImage) {
describe("The mct-background-image directive", function () {
var mockDocument,
mockScope,
mockElement,
testImage,
directive;
beforeEach(function () {
mockDocument = [
jasmine.createSpyObj('document', ['createElement'])
];
mockScope = jasmine.createSpyObj('scope', [
'$watch',
'$watchCollection'
]);
mockElement = jasmine.createSpyObj('element', ['css']);
testImage = {};
mockDocument[0].createElement.and.returnValue(testImage);
directive = new MCTBackgroundImage(mockDocument);
});
it("is applicable as an attribute", function () {
expect(directive.restrict).toEqual("A");
});
it("two-way-binds its own value", function () {
expect(directive.scope.mctBackgroundImage).toEqual("=");
});
describe("once linked", function () {
beforeEach(function () {
directive.link(mockScope, mockElement, {});
});
it("watches for changes to the URL", function () {
expect(mockScope.$watch).toHaveBeenCalledWith(
'mctBackgroundImage',
jasmine.any(Function)
);
});
it("updates images in-order, even when they load out-of-order", function () {
var firstOnload;
mockScope.$watch.calls.mostRecent().args[1]("some/url/0");
firstOnload = testImage.onload;
mockScope.$watch.calls.mostRecent().args[1]("some/url/1");
// Resolve in a different order
testImage.onload();
firstOnload();
// Should still have taken the more recent value
expect(mockElement.css.calls.mostRecent().args).toEqual([
"background-image",
"url('some/url/1')"
]);
});
it("clears the background image when undefined is passed in", function () {
mockScope.$watch.calls.mostRecent().args[1]("some/url/0");
testImage.onload();
mockScope.$watch.calls.mostRecent().args[1](undefined);
expect(mockElement.css.calls.mostRecent().args).toEqual([
"background-image",
"none"
]);
});
it("updates filters on change", function () {
var filters = { brightness: 123, contrast: 21 };
mockScope.$watchCollection.calls.all().forEach(function (call) {
if (call.args[0] === 'filters') {
call.args[1](filters);
}
});
expect(mockElement.css).toHaveBeenCalledWith(
'filter',
'brightness(123%) contrast(21%)'
);
});
it("clears filters when none are present", function () {
mockScope.$watchCollection.calls.all().forEach(function (call) {
if (call.args[0] === 'filters') {
call.args[1](undefined);
}
});
expect(mockElement.css)
.toHaveBeenCalledWith('filter', '');
});
});
});
}
);

View File

@@ -1,84 +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/policies/ImageryViewPolicy"],
function (ImageryViewPolicy) {
describe("Imagery view policy", function () {
var testView,
openmct,
mockDomainObject,
mockTelemetry,
mockMetadata,
policy;
beforeEach(function () {
testView = { key: "imagery" };
mockMetadata = jasmine.createSpyObj('metadata', [
"valuesForHints"
]);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getId', 'getModel', 'getCapability']
);
mockTelemetry = jasmine.createSpyObj(
'telemetry',
['getMetadata']
);
mockDomainObject.getCapability.and.callFake(function (c) {
return c === 'telemetry' ? mockTelemetry : undefined;
});
mockDomainObject.getId.and.returnValue("some-id");
mockDomainObject.getModel.and.returnValue({ name: "foo" });
mockTelemetry.getMetadata.and.returnValue(mockMetadata);
mockMetadata.valuesForHints.and.returnValue(["bar"]);
openmct = { telemetry: mockTelemetry };
policy = new ImageryViewPolicy(openmct);
});
it("checks for hints indicating image telemetry", function () {
policy.allow(testView, mockDomainObject);
expect(mockMetadata.valuesForHints)
.toHaveBeenCalledWith(["image"]);
});
it("allows the imagery view for domain objects with image telemetry", function () {
expect(policy.allow(testView, mockDomainObject)).toBeTruthy();
});
it("disallows the imagery view for domain objects without image telemetry", function () {
mockMetadata.valuesForHints.and.returnValue([]);
expect(policy.allow(testView, mockDomainObject)).toBeFalsy();
});
it("allows other views", function () {
testView.key = "somethingElse";
expect(policy.allow(testView, mockDomainObject)).toBeTruthy();
});
});
}
);

View File

@@ -0,0 +1,8 @@
# My Items plugin
Defines top-level folder named "My Items" to store user-created items. Enabled by default, this can be disabled in a
read-only deployment with no user-editable objects.
## Installation
```js
openmct.install(openmct.plugins.MyItems());
```

View File

@@ -0,0 +1,14 @@
# Import / Export Plugin
The Import/Export plugin allows objects to be exported as JSON files. This allows for sharing of objects between users
who are not using a shared persistence store. It also allows object trees to be backed up. Additionally, object trees
exported using this tool can then be exposed as read-only static root trees using the
[Static Root Plugin](../../src/plugins/staticRootPlugin/README.md).
Upon installation it will add two new context menu actions to allow import and export of objects. Initiating the Export
action on an object will produce a JSON file that includes the object and all of its composed children. Selecting Import
on an object will allow the user to import a previously exported object tree as a child of the selected object.
## Installation
```js
openmct.install(openmct.plugins.ImportExport())
```

View File

@@ -133,7 +133,7 @@ define(['lodash'], function (_) {
copyOfChild.location = parentId;
parent.composition[index] = copyOfChild.identifier;
this.tree[newIdString] = copyOfChild;
this.tree[parentId].composition[index] = newIdString;
this.tree[parentId].composition[index] = copyOfChild.identifier;
return copyOfChild;
};

View File

@@ -136,6 +136,10 @@ define(['zepto', '../../../../src/api/objects/object-utils.js'], function ($, ob
return tree;
};
ImportAsJSONAction.prototype.getKeyString = function (identifier) {
return this.openmct.objects.makeKeyString(identifier);
};
/**
* Rewrites all instances of a given id in the tree with a newly generated
* replacement to prevent collision.

View File

@@ -47,7 +47,12 @@ define(
uniqueId = 0;
newObjects = [];
openmct = {
$injector: jasmine.createSpyObj('$injector', ['get'])
$injector: jasmine.createSpyObj('$injector', ['get']),
objects: {
makeKeyString: function (identifier) {
return identifier.key;
}
}
};
mockInstantiate = jasmine.createSpy('instantiate').and.callFake(
function (model, id) {
@@ -153,7 +158,7 @@ define(
body: JSON.stringify({
"openmct": {
"infiniteParent": {
"composition": ["infinteChild"],
"composition": [{key: "infinteChild", namespace: ""}],
"name": "1",
"type": "folder",
"modified": 1503598129176,
@@ -161,7 +166,7 @@ define(
"persisted": 1503598129176
},
"infinteChild": {
"composition": ["infiniteParent"],
"composition": [{key: "infinteParent", namespace: ""}],
"name": "2",
"type": "folder",
"modified": 1503598132428,

View File

@@ -1,2 +1,8 @@
This bundle implements a connection to an external CouchDB persistence
store in Open MCT.
# Couch DB Persistence Plugin
An adapter for using CouchDB for persistence of user-created objects. The plugin installation function takes the URL
for the CouchDB database as a parameter.
## Installation
```js
openmct.install(openmct.plugins.CouchDB('http://localhost:5984/openmct'))
```

View File

@@ -1,2 +1,8 @@
This bundle implements a connection to an external ElasticSearch persistence
store in Open MCT.
# Elasticsearch Persistence Provider
An adapter for using Elastic for persistence of user-created objects. The installation function takes the URL for an
Elasticsearch server as a parameter.
## Installation
```js
openmct.install(openmct.plugins.Elasticsearch('http://localhost:9200'))
```

View File

@@ -0,0 +1,9 @@
# Local Storage Plugin
Provides persistence of user-created objects in browser Local Storage. Objects persisted in this way will only be
available from the browser and machine on which they were persisted. For shared persistence, consider the
[Elasticsearch](../elastic/) and [CouchDB](../couch/) persistence plugins.
## Installation
```js
openmct.install(openmct.plugins.LocalStorage());
```

View File

@@ -1,49 +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.
*****************************************************************************/
// Converts all templateUrl references in bundle.js files to
// plain template references, loading said templates with the
// RequireJS text plugin.
var glob = require('glob'),
fs = require('fs');
function migrate(file) {
var sourceCode = fs.readFileSync(file, 'utf8'),
lines = sourceCode.split('\n')
.filter(function (line) {
return !(/^\W*['"]use strict['"];\W*$/.test(line));
})
.filter(function (line) {
return line.indexOf("/*global") !== 0;
});
fs.writeFileSync(file, lines.join('\n'));
}
glob('@(src|platform)/**/*.js', {}, function (err, files) {
if (err) {
console.log(err);
return;
}
files.forEach(migrate);
});

View File

@@ -1,106 +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.
*****************************************************************************/
// Converts all templateUrl references in bundle.js files to
// plain template references, loading said templates with the
// RequireJS text plugin.
var glob = require('glob'),
fs = require('fs'),
path = require('path'),
_ = require('lodash');
function toTemplateName(templateUrl) {
var parts = templateUrl.split('/');
return _.camelCase(parts[parts.length - 1].replace(".html", "")) +
"Template";
}
function getTemplateUrl(sourceLine) {
return _.trim(sourceLine.split(":")[1], "\", ");
}
function hasTemplateUrl(sourceLine) {
return sourceLine.indexOf("templateUrl") !== -1;
}
function findTemplateURLs(sourceCode) {
return sourceCode.split('\n')
.map(_.trim)
.filter(hasTemplateUrl)
.map(getTemplateUrl);
}
function injectRequireArgument(sourceCode, templateUrls) {
var lines = sourceCode.split('\n'),
index;
templateUrls = _.uniq(templateUrls);
// Add arguments for source paths...
index = lines.map(_.trim).indexOf("'legacyRegistry'");
lines = lines.slice(0, index).concat(templateUrls.map(function (url) {
return " \"text!./res/" + url + "\",";
}).concat(lines.slice(index)));
/// ...and for arguments
index = lines.map(_.trim).indexOf("legacyRegistry");
lines = lines.slice(0, index).concat(templateUrls.map(function (url) {
return " " + toTemplateName(url) + ",";
}).concat(lines.slice(index)));
return lines.join('\n');
}
function rewriteUrl(sourceLine) {
return [
sourceLine.substring(0, sourceLine.indexOf(sourceLine.trim())),
"\"template\": " + toTemplateName(getTemplateUrl(sourceLine)),
_.endsWith(sourceLine, ",") ? "," : ""
].join('');
}
function rewriteLine(sourceLine) {
return hasTemplateUrl(sourceLine) ?
rewriteUrl(sourceLine.replace("templateUrl", "template")) :
sourceLine;
}
function rewriteTemplateUrls(sourceCode) {
return sourceCode.split('\n').map(rewriteLine).join('\n');
}
function migrate(file) {
var sourceCode = fs.readFileSync(file, 'utf8');
fs.writeFileSync(file, rewriteTemplateUrls(
injectRequireArgument(sourceCode, findTemplateURLs(sourceCode))
), 'utf8');
}
glob('platform/**/bundle.js', {}, function (err, files) {
if (err) {
console.log(err);
return;
}
files.forEach(migrate);
});

View File

@@ -1,72 +0,0 @@
// Temporary utility script to rewrite bundle.json
// files as bundle.js files.
var glob = require('glob'),
fs = require('fs'),
path = require('path'),
_ = require('lodash'),
template = _.template(
fs.readFileSync(path.resolve(__dirname, 'rebundle-template.txt'), 'utf8')
);
function indent(str, depth) {
return _.trimLeft(str.split('\n').map(function (line) {
return _.repeat(' ', depth || 1) + line;
}).filter(function (line) {
return line.trim().length > 0;
}).join('\n'));
}
function findImpls(bundleContents) {
return _(bundleContents.extensions || {})
.map()
.flatten()
.pluck('implementation')
.filter()
.uniq()
.value();
}
function toIdentifier(impl) {
var parts = impl.replace(".js", "").split('/');
return parts[parts.length - 1];
}
function toPath(impl) {
return "\"./src/" + impl.replace(".js", "") + "\"";
}
function replaceImpls(bundleText) {
var rx = /"implementation": "([^"]*)"/;
return bundleText.split('\n').map(function (line) {
var m = line.match(rx);
return m !== null ?
line.replace(rx, '"implementation": ' + toIdentifier(m[1])) :
line;
}).join('\n');
}
function rebundle(file) {
var plainJson = fs.readFileSync(file, 'utf8'),
bundleContents = JSON.parse(plainJson),
impls = findImpls(bundleContents),
bundleName = file.replace("/bundle.json", ""),
outputFile = file.replace(".json", ".js"),
contents = template({
bundleName: bundleName,
implPaths: indent(impls.map(toPath).concat([""]).join(",\n")),
implNames: indent(impls.map(toIdentifier).concat([""]).join(",\n")),
bundleContents: indent(replaceImpls(JSON.stringify(bundleContents, null, 4)))
});
fs.writeFileSync(outputFile, contents, 'utf8');
}
glob('**/bundle.json', {}, function (err, files) {
if (err) {
console.log(err);
return;
}
files.forEach(rebundle);
});

View File

@@ -1,5 +1,5 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* Open MCT, Copyright (c) 2014-2019, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
@@ -33,6 +33,7 @@ define([
'./adapter/indicators/legacy-indicators-plugin',
'./plugins/buildInfo/plugin',
'./ui/registries/ViewRegistry',
'./plugins/imagery/plugin',
'./ui/registries/InspectorViewRegistry',
'./ui/registries/ToolbarRegistry',
'./ui/router/ApplicationRouter',
@@ -59,6 +60,7 @@ define([
LegacyIndicatorsPlugin,
buildInfoPlugin,
ViewRegistry,
ImageryPlugin,
InspectorViewRegistry,
ToolbarRegistry,
ApplicationRouter,
@@ -257,10 +259,12 @@ define([
this.install(RemoveActionPlugin.default());
this.install(this.plugins.FolderView());
this.install(this.plugins.Tabs());
this.install(ImageryPlugin.default());
this.install(this.plugins.FlexibleLayout());
this.install(this.plugins.GoToOriginalAction());
this.install(this.plugins.ImportExport());
this.install(this.plugins.WebPage());
this.install(this.plugins.Condition());
}
MCT.prototype = Object.create(EventEmitter.prototype);

View File

@@ -0,0 +1,7 @@
# Espresso Theme
Dark theme for the Open MCT user interface.
## Installation
```js
openmct.install(openmct.plugins.Espresso());
```

View File

@@ -38,7 +38,6 @@ const DEFAULTS = [
'platform/exporters',
'platform/telemetry',
'platform/features/clock',
'platform/features/imagery',
'platform/features/hyperlink',
'platform/features/timeline',
'platform/forms',
@@ -82,7 +81,6 @@ define([
'../platform/execution/bundle',
'../platform/exporters/bundle',
'../platform/features/clock/bundle',
'../platform/features/imagery/bundle',
'../platform/features/my-items/bundle',
'../platform/features/hyperlink/bundle',
'../platform/features/static-markup/bundle',

View File

@@ -0,0 +1,21 @@
# URL Indicator
Adds an indicator which shows the availability of a URL, with success based on receipt of a 200 HTTP code. Can be used
for monitoring the availability of web services.
## Installation
```js
openmct.install(openmct.plugins.URLIndicator({
url: 'http://localhost:8080',
iconClass: 'check',
interval: 10000,
label: 'Localhost'
})
);
```
## Options
* __url__: URL to indicate the status of
* __iconClass__: Icon to show in the status bar, defaults to icon-database. See the [Style Guide](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home/glyphs?view=styleguide.glyphs) for more icon options.
* __interval__: Interval between checking the connection, defaults to 10000
* __label__: Name showing up as text in the status bar, defaults to url

View File

@@ -25,15 +25,6 @@ define([
], function (
AutoflowTabularView
) {
/**
* This plugin provides an Autoflow Tabular View for domain objects
* in Open MCT.
*
* @param {Object} options
* @param {String} [options.type] the domain object type for which
* this view should be available; if omitted, this view will
* be available for all objects
*/
return function (options) {
return function (openmct) {
var views = (openmct.mainViews || openmct.objectViews);

View File

@@ -0,0 +1,15 @@
# Autoflow View
This plugin provides the Autoflow View for domain objects in Open MCT. This view allows users to visualize the latest
values of a collection of telemetry points in a condensed list.
## Installation
``` js
openmct.install(openmct.plugins.AutoflowView({
type: "telemetry.fixed"
}));
```
## Options
* `type`: The object type to add the Autoflow View to. Currently supports a single value. If not provided, will make the
Autoflow view available for all objects (which is probably not what you want).

View File

@@ -0,0 +1,198 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2019, 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 * as EventEmitter from 'eventemitter3';
import uuid from 'uuid';
import TelemetryCriterion from "@/plugins/condition/criterion/TelemetryCriterion";
import { TRIGGER } from "@/plugins/condition/utils/constants";
/*
* conditionDefinition = {
* trigger: 'any'/'all',
* criteria: [
* {
* operation: '',
* input: '',
* metaDataKey: '',
* key: 'someTelemetryObjectKey'
* }
* ]
* }
*/
export default class ConditionClass extends EventEmitter {
constructor(conditionDefinition, openmct) {
super();
this.openmct = openmct;
this.id = this.openmct.objects.makeKeyString(conditionDefinition.identifier);
if (conditionDefinition.criteria) {
this.createCriteria(conditionDefinition.criteria);
} else {
this.criteria = [];
}
this.trigger = conditionDefinition.trigger;
this.result = null;
}
updateTrigger(conditionDefinition) {
if (this.trigger !== conditionDefinition.trigger) {
this.trigger = conditionDefinition.trigger;
this.handleConditionUpdated();
}
}
generateCriterion(criterionDefinition) {
return {
id: uuid(),
operation: criterionDefinition.operation || '',
input: criterionDefinition.input === undefined ? [] : criterionDefinition.input,
metaDataKey: criterionDefinition.metaDataKey || '',
key: criterionDefinition.key || ''
};
}
createCriteria(criterionDefinitions) {
criterionDefinitions.forEach((criterionDefinition) => {
this.addCriterion(criterionDefinition);
});
}
updateCriteria(criterionDefinitions) {
this.destroyCriteria();
this.createCriteria(criterionDefinitions);
}
/**
* adds criterion to the condition.
*/
addCriterion(criterionDefinition) {
let criterionDefinitionWithId = this.generateCriterion(criterionDefinition || null);
let criterion = new TelemetryCriterion(criterionDefinitionWithId, this.openmct);
criterion.on('criterionUpdated', (data) => {
this.handleCriterionUpdated(data);
});
if (!this.criteria) {
this.criteria = [];
}
this.criteria.push(criterion);
this.handleConditionUpdated();
return criterionDefinitionWithId.id;
}
findCriterion(id) {
let criterion;
for (let i=0, ii=this.criteria.length; i < ii; i ++) {
if (this.criteria[i].id === id) {
criterion = {
item: this.criteria[i],
index: i
}
}
}
return criterion;
}
updateCriterion(id, criterionDefinition) {
let found = this.findCriterion(id);
if (found) {
const newCriterionDefinition = this.generateCriterion(criterionDefinition);
let newCriterion = new TelemetryCriterion(newCriterionDefinition, this.openmct);
let criterion = found.item;
criterion.unsubscribe();
criterion.off('criterionUpdated', (result) => {
this.handleCriterionUpdated(id, result);
});
this.criteria.splice(found.index, 1, newCriterion);
this.handleConditionUpdated();
}
}
removeCriterion(id) {
if (this.destroyCriterion(id)) {
this.handleConditionUpdated();
}
}
destroyCriterion(id) {
let found = this.findCriterion(id);
if (found) {
let criterion = found.item;
criterion.unsubscribe();
criterion.off('criterionUpdated', (result) => {
this.handleCriterionUpdated(id, result);
});
this.criteria.splice(found.index, 1);
return true;
}
return false;
}
handleCriterionUpdated(criterion) {
// reevaluate the condition's output
// TODO: should we save the result of a criterion here or in the criterion object itself?
let found = this.findCriterion(criterion.id);
if (found) {
this.criteria[found.index] = criterion;
this.handleConditionUpdated();
}
// this.handleConditionUpdated();
}
handleConditionUpdated() {
console.log(this);
// trigger an updated event so that consumers can react accordingly
this.emitResult();
}
getCriteria() {
return this.criteria;
}
destroyCriteria() {
let success = true;
//looping through the array backwards since destroyCriterion modifies the criteria array
for (let i=this.criteria.length-1; i >= 0; i--) {
success = success && this.destroyCriterion(this.criteria[i].id);
}
return success;
}
//TODO: implement as part of the evaluator class task.
evaluate() {
if (this.trigger === TRIGGER.ANY) {
this.result = false;
} else if (this.trigger === TRIGGER.ALL) {
this.result = false;
}
}
emitResult() {
this.emit('conditionUpdated', {
id: this.id,
trigger: this.trigger,
criteria: this.criteria
});
}
}

View File

@@ -1,5 +1,5 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* Open MCT, Copyright (c) 2014-2019, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
@@ -19,16 +19,16 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define([
<%= implPaths %>
'legacyRegistry'
], function (
<%= implNames %>
legacyRegistry
) {
"use strict";
export default function ConditionSetCompositionPolicy(openmct) {
return {
allow: function (parent, child) {
let parentType = parent.type;
if (parentType === 'conditionSet' && !openmct.telemetry.isTelemetryObject(child)) {
return false;
}
legacyRegistry.register("<%= bundleName %>", <%= bundleContents %>);
});
return true;
}
}
}

View File

@@ -0,0 +1,87 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2019, 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 ConditionSetCompositionPolicy from './ConditionSetCompositionPolicy';
fdescribe('ConditionSetCompositionPolicy', () => {
let policy;
let testTelemetryObject;
let openmct = {};
let parentDomainObject;
let composition;
beforeAll(function () {
testTelemetryObject = {
identifier:{ namespace: "", key: "test-object"},
type: "test-object",
name: "Test Object",
telemetry: {
values: [{
key: "some-key",
name: "Some attribute",
hints: {
domain: 1
}
}, {
key: "some-other-key",
name: "Another attribute",
hints: {
range: 1
}
}]
}
};
openmct.objects = jasmine.createSpyObj('objects', ['get', 'makeKeyString']);
openmct.objects.get.and.returnValue(testTelemetryObject);
openmct.objects.makeKeyString.and.returnValue(testTelemetryObject.identifier.key);
openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject']);
policy = new ConditionSetCompositionPolicy(openmct);
parentDomainObject = {};
composition = {};
});
it('returns true for object types that are not conditionSets', function () {
parentDomainObject.type = 'random';
openmct.telemetry.isTelemetryObject.and.returnValue(false);
expect(policy.allow(parentDomainObject, {})).toBe(true);
});
it('returns false for object types that are not telemetry objects when parent is a conditionSet', function () {
parentDomainObject.type = 'conditionSet';
openmct.telemetry.isTelemetryObject.and.returnValue(false);
expect(policy.allow(parentDomainObject, {})).toBe(false);
});
it('returns true for object types that are telemetry objects when parent is a conditionSet', function () {
parentDomainObject.type = 'conditionSet';
openmct.telemetry.isTelemetryObject.and.returnValue(true);
expect(policy.allow(parentDomainObject, testTelemetryObject)).toBe(true);
});
it('returns true for object types that are telemetry objects when parent is not a conditionSet', function () {
parentDomainObject.type = 'random';
openmct.telemetry.isTelemetryObject.and.returnValue(true);
expect(policy.allow(parentDomainObject, testTelemetryObject)).toBe(true);
});
});

View File

@@ -0,0 +1,73 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2019, 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 ConditionSet from './components/ConditionSet.vue';
import Vue from 'vue';
export default class ConditionSetViewProvider {
constructor(openmct) {
this.openmct = openmct;
this.key = 'conditionSet.view';
this.cssClass = 'icon-summary-widget'; // TODO: replace with class for new icon
}
canView(domainObject) {
return domainObject.type === 'conditionSet';
}
canEdit(domainObject) {
return domainObject.type === 'conditionSet';
}
view(domainObject, objectPath) {
let component;
const openmct = this.openmct;
return {
show: (container, isEditing) => {
component = new Vue({
el: container,
components: {
ConditionSet
},
provide: {
openmct,
domainObject,
objectPath
},
data() {
return {
isEditing
}
},
template: '<condition-set ref="conditionSet" :isEditing="isEditing"></condition-set>'
});
},
onEditModeChange: (isEditing) => {
component.isEditing = isEditing;
},
destroy: () => {
component.$destroy();
component = undefined;
}
};
}
}

View File

@@ -0,0 +1,118 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2019, 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 Condition from "./Condition";
import {TRIGGER} from "./utils/constants";
import TelemetryCriterion from "./criterion/TelemetryCriterion";
let openmct = {},
mockListener,
testConditionDefinition,
testTelemetryObject,
conditionObj;
describe("The condition", function () {
beforeEach (() => {
mockListener = jasmine.createSpy('listener');
testTelemetryObject = {
identifier:{ namespace: "", key: "test-object"},
type: "test-object",
name: "Test Object",
telemetry: {
values: [{
key: "some-key",
name: "Some attribute",
hints: {
domain: 1
}
}, {
key: "some-other-key",
name: "Another attribute",
hints: {
range: 1
}
}]
}
};
openmct.objects = jasmine.createSpyObj('objects', ['get', 'makeKeyString']);
openmct.objects.get.and.returnValue(testTelemetryObject);
openmct.objects.makeKeyString.and.returnValue(testTelemetryObject.identifier.key);
openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject', 'subscribe']);
openmct.telemetry.isTelemetryObject.and.returnValue(true);
openmct.telemetry.subscribe.and.returnValue(function () {});
testConditionDefinition = {
trigger: TRIGGER.ANY,
criteria: [
{
operation: 'equalTo',
input: false,
metaDataKey: 'value',
key: testTelemetryObject.identifier
}
]
};
conditionObj = new Condition(
testConditionDefinition,
openmct
);
conditionObj.on('conditionUpdated', mockListener);
});
it("generates criteria with an id", function () {
const testCriterion = testConditionDefinition.criteria[0];
let criterion = conditionObj.generateCriterion(testCriterion);
expect(criterion.id).toBeDefined();
expect(criterion.operation).toEqual(testCriterion.operation);
expect(criterion.input).toEqual(testCriterion.input);
expect(criterion.metaDataKey).toEqual(testCriterion.metaDataKey);
expect(criterion.key).toEqual(testCriterion.key);
});
it("initializes with an id", function () {
expect(conditionObj.id).toBeDefined();
});
it("initializes with criteria from the condition definition", function () {
expect(conditionObj.criteria.length).toEqual(1);
let criterion = conditionObj.criteria[0];
expect(criterion instanceof TelemetryCriterion).toBeTrue();
expect(criterion.operator).toEqual(testConditionDefinition.operator);
expect(criterion.input).toEqual(testConditionDefinition.input);
expect(criterion.metaDataKey).toEqual(testConditionDefinition.metaDataKey);
expect(criterion.key).toEqual(testConditionDefinition.key);
});
it("initializes with the trigger from the condition definition", function () {
expect(conditionObj.trigger).toEqual(testConditionDefinition.trigger);
});
it("destroys all criteria for a condition", function () {
const result = conditionObj.destroyCriteria();
expect(result).toBeTrue();
expect(conditionObj.criteria.length).toEqual(0);
});
});

View File

@@ -0,0 +1,39 @@
<template>
<div id="conditionArea"
class="c-cs-ui__conditions"
:class="['widget-condition', { 'widget-condition--current': condition.isCurrent }]"
>
<div class="title-bar">
<span class="condition-name">
{{ condition.name }}
</span>
<span class="condition-output">
Output: {{ condition.output }}
</span>
</div>
<div class="condition-config">
<span class="condition-description">
{{ condition.description }}
</span>
</div>
</div>
</template>
<script>
export default {
inject: ['openmct'],
props: {
condition: {
type: Object,
required: true
}
},
data() {
return {
conditionData: {}
};
},
methods: {
}
}
</script>

View File

@@ -0,0 +1,133 @@
<template>
<section id="conditionCollection"
class="c-cs__ui_section"
>
<div class="c-cs__ui__header">
<span class="c-cs__ui__header-label">Conditions</span>
<span
class="is-enabled flex-elem"
:class="['c-cs__disclosure-triangle', { 'c-cs__disclosure-triangle--expanded': expanded }]"
@click="expanded = !expanded"
></span>
</div>
<div v-if="expanded"
class="c-cs__ui_content"
>
<div v-show="isEditing"
class="help"
>
<span>The first condition to match is the one that wins. Drag conditions to rearrange.</span>
</div>
<div class="holder add-condition-button-wrapper align-left">
<button
v-show="isEditing"
id="addCondition"
class="c-cs-button c-cs-button--major add-condition-button"
@click="addCondition"
>
<span class="c-cs-button__label">Add Condition</span>
</button>
</div>
<div class="condition-collection">
<div v-for="condition in conditionCollection"
:key="condition.identifier.key"
class="conditionArea"
>
<div v-if="isEditing">
<ConditionEdit :condition="condition" />
</div>
<div v-else>
<Condition :condition="condition" />
</div>
</div>
</div>
</div>
</section>
</template>
<script>
import Condition from '../../condition/components/Condition.vue';
import ConditionEdit from '../../condition/components/ConditionEdit.vue';
import uuid from 'uuid';
import ConditionClass from '../Condition';
export default {
inject: ['openmct', 'domainObject'],
components: {
Condition,
ConditionEdit
},
props: {
isEditing: Boolean
},
data() {
return {
expanded: true,
parentKeyString: this.openmct.objects.makeKeyString(this.domainObject.identifier),
conditionCollection: [],
conditions: []
};
},
destroyed() {
this.composition.off('add', this.addTelemetry);
},
mounted() {
this.telemetryObjs = [];
this.instantiate = this.openmct.$injector.get('instantiate');
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('add', this.addTelemetry);
this.composition.load();
this.conditionCollection = this.domainObject.configuration ? this.domainObject.configuration.conditionCollection : [];
if (!this.conditionCollection.length) {this.addCondition(null, true)}
},
methods: {
addTelemetry(telemetryDomainObject) {
this.telemetryObjs.push(telemetryDomainObject);
},
addCondition(event, isDefault) {
let conditionDO = this.getConditionDomainObject(!!isDefault);
this.conditionCollection.unshift(conditionDO);
let condition = new ConditionClass(conditionDO, this.openmct);
this.conditions.push(condition);
},
getConditionDomainObject(isDefault) {
let conditionObj = {
isDefault: isDefault,
isCurrent: true,
identifier: {
namespace: "",
key: uuid()
},
name: isDefault ? 'Default' : 'Unnamed Condition',
trigger: 'any',
criteria: isDefault ? [] : [{
operation: '',
input: '',
metaDataKey: this.openmct.telemetry.getMetadata(this.telemetryObjs[0]).values()[0].key,
key: this.telemetryObjs.length ? this.openmct.objects.makeKeyString(this.telemetryObjs[0].identifier) : null
}],
output: 'false',
summary: 'summary description'
};
let conditionDOKeyString = this.openmct.objects.makeKeyString(conditionObj.identifier);
let newDO = this.instantiate(conditionObj, conditionDOKeyString);
return newDO.useCapability('adapter');
},
updateCondition(updatedCondition) {
let index = _.findIndex(this.conditions, (condition) => condition.id === updatedCondition.id);
this.conditions[index] = updatedCondition;
},
removeCondition(identifier) {
let index = _.findIndex(this.conditionCollection, (condition) => this.openmct.objects.makeKeyString(identifier) === condition.identifier.key);
this.conditionCollection.splice(index, 1);
},
reorder(reorderPlan) {
let oldConditions = this.conditionCollection.slice();
reorderPlan.forEach((reorderEvent) => {
this.$set(this.conditionCollection, reorderEvent.newIndex, oldConditions[reorderEvent.oldIndex]);
});
}
}
}
</script>

View File

@@ -0,0 +1,233 @@
<template>
<div class="c-cs-editui__conditions"
:class="['widget-condition', { 'widget-condition--current': condition.isCurrent }]"
>
<div class="title-bar">
<span
class="c-c__menu-hamburger"
:class="{ 'is-enabled': !condition.isDefault }"
@click="expanded = !condition.expanded"
></span>
<span
class="is-enabled flex-elem"
:class="['c-c__disclosure-triangle', { 'c-c__disclosure-triangle--expanded': expanded }]"
@click="expanded = !condition.expanded"
></span>
<div class="condition-summary">
<span class="condition-name">{{ condition.name }}</span>
<span class="condition-description">{{ condition.description }}</span>
</div>
<span v-if="!condition.isDefault"
class="is-enabled c-c__duplicate"
></span>
<span v-if="!condition.isDefault"
class="is-enabled c-c__trash"
@click="removeCondition"
></span>
</div>
<div v-if="expanded"
class="condition-config-edit widget-rule-content c-sw-editui__rules-wrapper holder widget-rules-wrapper flex-elem expanded"
>
<div id="ruleArea"
class="c-sw-editui__rules widget-rules"
>
<div class="c-sw-rule">
<div class="c-sw-rule__ui l-compact-form l-widget-rule has-local-controls">
<div>
<ul class="t-widget-rule-config">
<li>
<label>Condition Name</label>
<span class="controls">
<input v-model="condition.name"
class="t-rule-name-input"
type="text"
>
</span>
</li>
<li>
<label>Output</label>
<span class="controls">
<select ref="outputSelect"
@change="getOutputBinary">
<option value="false">False</option>
<option value="true">True</option>
<option value="string">String</option>
</select>
<input v-if="stringOutputField"
ref="outputString"
class="t-rule-name-input"
type="text"
:value="condition.output"
@keyup="getOutputString"
>
</span>
</li>
</ul>
<div v-if="!condition.isDefault"
class="widget-rule-content expanded"
>
<ul class="t-widget-rule-config">
<li class="has-local-controls t-condition">
<label>Match when</label>
<span class="controls">
<select>
<option value="all">all criteria are met</option>
<option value="any">any criteria are met</option>
</select>
</span>
</li>
</ul>
<ul class="t-widget-rule-config">
<li v-if="telemetryObject && telemetryMetadata"
class="has-local-controls t-condition"
>
<label>when</label>
<span class="t-configuration">
<span class="controls">
<select class="">
<option value="">- Select Telemetry -</option>
<option :value="telemetryObject.key">{{ telemetryObject.name }}</option>
</select>
</span>
<span class="controls">
<select v-model="selectedMetaDataKey">
<option value="">- Select Field -</option>
<option v-for="option in telemetryMetadata"
:key="option.key"
:value="option.key"
>
{{ option.name }}
</option>
</select>
</span>
<span class="controls">
<select @change="getOperationKey">
<option value="">- Select Comparison -</option>
<option v-for="option in operations"
:key="option.name"
:value="option.name"
>
{{ option.text }}
</option>
</select>
<input v-if="comparisonValueField"
class="t-rule-name-input"
type="text"
@keyup="getOperationValue"
>
</span>
</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { OPERATIONS } from '../utils/operations';
export default {
inject: ['openmct', 'domainObject'],
props: {
condition: {
type: Object,
required: true
}
},
data() {
let conditionCollection = this.domainObject.configuration.conditionCollection;
return {
expanded: true,
name: this.condition.name,
description: this.condition.description,
conditionCollection,
telemetryObject: this.telemetryObject,
telemetryMetadata: this.telemetryMetadata,
operations: OPERATIONS,
selectedMetaDataKey: null,
selectedOperationKey: null,
stringOutputField: false,
comparisonValueField: false
};
},
mounted() {
if (this.condition.output !== 'false' && this.condition.output !== 'true') {
this.$refs.outputSelect.value = 'string';
this.stringOutputField = true;
}
this.updateTelemetry();
},
updated() {
this.updateCurrentCondition();
this.persist();
},
methods: {
removeCondition(ev) {
const conditionDiv = ev.target.closest('.conditionArea');
const conditionCollectionDiv = conditionDiv.closest('.condition-collection');
const index = Array.from(conditionCollectionDiv.children).indexOf(conditionDiv);
this.domainObject.configuration.conditionCollection.splice(index, 1);
},
updateTelemetry() {
if (this.hasTelemetry()) {
this.openmct.objects.get(this.condition.criteria[0].key).then((obj) => {
this.telemetryObject = obj;
this.telemetryMetadata = this.openmct.telemetry.getMetadata(this.telemetryObject).values();
this.selectedMetaDataKey = this.telemetryMetadata[0].key;
console.log('ConditionEdit', this.telemetryObject, this.telemetryMetadata);
});
} else {
this.telemetryObject = null;
}
},
hasTelemetry() {
return this.condition.criteria.length && this.condition.criteria[0].key;
},
persist(index) {
if (index) {
this.openmct.objects.mutate(this.domainObject, `configuration.conditionCollection[${index}]`, this.domainObject.configuration.conditionCollection[index]);
} else {
this.openmct.objects.mutate(this.domainObject, 'configuration.conditionCollection', this.domainObject.configuration.conditionCollection);
}
},
updateCurrentCondition() {
// TODO: replace based on telemetry
if (this.conditionCollection.length > 1) {
this.conditionCollection.forEach((condition, index) => {
index === 0 ? condition.isCurrent = true : condition.isCurrent = false
});
} else {
this.conditionCollection[0].isCurrent = true;
}
},
getOutputBinary(ev) {
if (ev.target.value !== 'string') {
this.condition.output = ev.target.value;
this.stringOutputField = false;
} else {
this.stringOutputField = true;
}
},
getOutputString(ev) {
this.condition.output = ev.target.value;
},
getOperationKey(ev) {
console.log(ev.target.value)
if (ev.target.value !== 'isUndefined' && ev.target.value !== 'isDefined') {
this.comparisonValueField = true;
} else {
this.comparisonValueField = false;
}
this.selectedOperationKey = ev.target.value;
},
getOperationValue(ev) {
this.selectedOperationKey = ev.target.value;
}
}
}
</script>

View File

@@ -0,0 +1,39 @@
<template>
<div class="c-object-view u-contents">
<div class="c-cs-edit w-condition-set">
<div class="c-sw-edit__ui holder">
<CurrentOutput :condition-collection="domainObject.conditionCollection" />
<TestData :is-editing="isEditing" />
<ConditionCollection :is-editing="isEditing"
:condition-collection="domainObject.conditionCollection"
/>
</div>
</div>
</div>
</template>
<script>
import CurrentOutput from './CurrentOutput.vue';
import TestData from './TestData.vue';
import ConditionCollection from './ConditionCollection.vue';
export default {
inject: ["openmct", "domainObject"],
components: {
CurrentOutput,
TestData,
ConditionCollection
},
props: {
isEditing: Boolean
},
data() {
let conditionCollection = this.domainObject.configuration.conditionCollection;
return {
conditionCollection
}
}
};
</script>

View File

@@ -0,0 +1,52 @@
<template>
<section id="current-output">
<div class="c-cs__ui__header">
<span class="c-cs__ui__header-label">Current Output</span>
<span
class="is-enabled flex-elem"
:class="['c-cs__disclosure-triangle', { 'c-cs__disclosure-triangle--expanded': expanded }]"
@click="expanded = !expanded"
></span>
</div>
<div v-if="expanded"
class="c-cs__ui_content"
>
<div>
<span class="current-output">{{ conditionCollection[currentConditionIndex].output }}</span>
</div>
</div>
</section>
</template>
<script>
export default {
inject: ['openmct', 'domainObject'],
props: {
isEditing: Boolean
},
data() {
let conditionCollection = this.domainObject.configuration.conditionCollection;
let currentConditionIndex = 0;
return {
expanded: true,
conditionCollection,
currentConditionIndex
}
},
mounted() {
this.currentConditionIndex = this.getCurrentConditionIndex();
},
methods: {
getCurrentConditionIndex() {
let currentConditionIndex;
this.conditionCollection.forEach((condition, index) => {
if (condition.isCurrent) {
currentConditionIndex = index;
}
});
return currentConditionIndex;
}
}
}
</script>

View File

@@ -0,0 +1,68 @@
<template>
<section v-show="isEditing"
id="test-data"
class="test-data"
>
<div class="c-cs__ui__header">
<span class="c-cs__ui__header-label">Test Data</span>
<span
class="is-enabled flex-elem"
:class="['c-cs__disclosure-triangle', { 'c-cs__disclosure-triangle--expanded': expanded }]"
@click="expanded = !expanded"
></span>
</div>
<div v-if="expanded"
class="c-cs__ui_content"
>
<label class="checkbox custom">
<input type="checkbox"
class="t-test-data-checkbox"
>
<span>Apply Test Data</span>
</label>
<div class="t-test-data-config">
<div class="c-cs-editui__conditions widget-condition">
<form>
<label>
<span>Set</span>
<select>
<option>- Select Input -</option>
</select>
</label>
<span class="is-enabled flex-elem c-cs__duplicate"></span>
<span class="is-enabled flex-elem c-cs__trash"></span>
</form>
</div>
<div class="c-cs-editui__conditions widget-condition">
<form>
<label>
<span>Set</span>
<select>
<option>- Select Input -</option>
</select>
</label>
<span class="is-enabled c-cs__duplicate"></span>
<span class="is-enabled c-cs__trash"></span>
</form>
</div>
</div>
</div>
</section>
</template>
<script>
export default {
inject: ['openmct'],
props: {
isEditing: Boolean
},
data() {
return {
expanded: true
};
},
methods: {
}
}
</script>

View File

@@ -0,0 +1,142 @@
.c-cs-edit {
padding: 0;
}
section {
padding-bottom: 5px;
}
.c-cs__ui__header {
background-color: #D0D1D3;
padding: 0.4em 0.6em;
text-transform: uppercase;
font-size: 0.8em;
font-weight: bold;
color: #7C7D80;
display: flex;
justify-content: stretch;
align-items: center;
}
.c-cs__ui__header-label {
display: inline-block;
width: 100%;
}
.c-cs__ui_content {
padding: 0.4em;
}
.c-cs__ui_content .help {
font-style: italic;
padding: 0.4em 0;
}
.current-output {
text-transform: uppercase;
font-weight: bold;
margin: 0.4em 0.6em;
}
.condition-output {
color: #999;
}
.condition-description {
color: #333;
}
.checkbox.custom {
display: flex;
align-items: center;
margin-left: 0.6em;
}
.checkbox.custom span {
display: inline-block;
margin-left: 0.6em;
}
.t-test-data-config {
margin-top: 5px;
}
.widget-condition form {
padding: 0.5em;
display: flex;
align-items: center;
justify-content: stretch;
}
.widget-condition form label {
flex-grow: 1;
margin-left: 0;
}
.widget-condition form input {
min-height: 24px;
}
.c-cs-button[class*="--major"],
.c-cs-button[class*='is-active'],
.c-cs-button--menu[class*="--major"],
.c-cs-button--menu[class*='is-active'] {
border: solid 1.5px #0B427C;
background-color: #4778A3;
padding: 0.2em 0.6em;
margin: 0.4em;
font-weight: bold;
color: #eee;
border-radius: 6px;
}
.c-cs__disclosure-triangle,
.c-cs__menu-hamburger,
.c-cs__duplicate,
.c-cs__trash {
$d: 8px;
color: $colorDisclosureCtrl;
width: $d;
visibility: hidden;
&.is-enabled {
cursor: pointer;
visibility: visible;
&:hover {
color: $colorDisclosureCtrlHov;
}
&:before {
$s: .5;
display: block;
font-family: symbolsfont;
font-size: 1rem * $s;
}
}
}
.c-cs__disclosure-triangle {
&:before {
content: $glyph-icon-arrow-right;
}
&--expanded {
&:before {
transform: rotate(90deg);
}
}
}
.c-cs__duplicate {
margin-right: 0.3em;
&:before {
content: $glyph-icon-duplicate;
}
}
.c-cs__trash {
&:before {
content: $glyph-icon-trash;
}
}

View File

@@ -0,0 +1,154 @@
.widget-condition {
background-color: #eee;
margin: 0 0 0.6em;
border-radius: 3px;
&--current {
background-color: #DEECFA;
}
}
.title-bar {
display: flex;
align-items: center;
justify-content: stretch;
padding: 0.4em 0;
}
.title-bar span {
margin-right: 0.6em;
}
.title-bar span.c-c__duplicate,
.title-bar span.c-c__trash{
margin-right: 0;
margin-left: 0.3em;
}
.widget-condition > div {
margin: 0 0.4em;
}
.condition-name {
font-weight: bold;
}
.condition-summary .condition-description {
color: #999;
}
.condition-summary {
flex-grow: 1;
}
.condition-config {
padding: 0.3em 0;
}
.widget-condition form label {
flex-grow: 1;
margin-left: 0;
}
.l-widget-rule {
padding: 0;
}
.l-compact-form ul li {
padding: 0;
}
.widget-rule-content.expanded {
margin: 0 3px;
}
.widget-rule-content.expanded ul {
border-top: solid 1px #ccc;
padding: 2px;
}
.l-compact-form ul li .controls {
display: inline-flex;
flex-grow: inherit;
padding: 2px 0;
}
.l-compact-form ul li > label {
display: block;
width: 90px;
min-width: 90px;
text-align: right;
line-height: 20px;
}
.l-compact-form ul li .controls input[type="text"],
.l-compact-form ul li .controls input[type="search"],
.l-compact-form ul li .controls input[type="number"],
.l-compact-form ul li .controls button,
.l-compact-form ul li .controls select {
min-height: 20px;
}
.condition-config-edit {
padding: 3px 0;
}
.c-c__disclosure-triangle,
.c-c__menu-hamburger,
.c-c__duplicate,
.c-c__trash {
$d: 8px;
color: $colorDisclosureCtrl;
width: $d;
visibility: hidden;
&.is-enabled {
cursor: pointer;
visibility: visible;
&:hover {
color: $colorDisclosureCtrlHov;
}
&:before {
$s: .5;
display: block;
font-family: symbolsfont;
font-size: 1rem * $s;
}
}
}
.c-c__disclosure-triangle {
&:before {
content: $glyph-icon-arrow-right;
}
&--expanded {
&:before {
transform: rotate(90deg);
}
}
}
.c-c__menu-hamburger {
&:before {
content: $glyph-icon-menu-hamburger;
}
}
.c-c__duplicate {
&:before {
content: $glyph-icon-duplicate;
}
}
.c-c__trash {
&:before {
content: $glyph-icon-trash;
}
}

View File

@@ -0,0 +1,88 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2019, 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 * as EventEmitter from 'eventemitter3';
export default class TelemetryCriterion extends EventEmitter {
constructor(telemetryDomainObjectDefinition, openmct) {
super();
this.id = telemetryDomainObjectDefinition.id;
this.subscription = null;
this.telemetryMetadata = null;
this.telemetryObjectIdAsString = null;
openmct.objects.get(openmct.objects.makeKeyString(telemetryDomainObjectDefinition.key)).then((obj) => {
if (openmct.telemetry.isTelemetryObject(obj)) {
this.telemetryObject = obj;
this.telemetryObjectIdAsString = openmct.objects.makeKeyString(this.telemetryObject.identifier);
this.telemetryMetadata = openmct.telemetry.getMetadata(this.telemetryObject.identifier);
this.emit('criterionUpdated', this);
}
});
}
handleSubscription(datum) {
//data is telemetry values, error
//how do I get data here?
this.emitResult(this.normalizeData(datum));
}
//TODO: Revisit this logic
normalizeData(datum) {
return {
[datum.key]: datum[datum.source]
}
}
emitResult(data, error) {
this.emit('criterionUpdated', {
identifier: this.id,
data: data,
error: error
});
}
/**
* Subscribes to the telemetry object and returns an unsubscribe function
*/
subscribe(openmct) {
this.subscription = openmct.telemetry.subscribe(this.telemetryObject, (datum) => {
this.handleSubscription(datum);
});
}
/**
* Calls an unsubscribe function returned by subscribe() and deletes any initialized data
*/
unsubscribe() {
//unsubscribe from telemetry source
if (typeof this.subscription === 'function') {
this.subscription();
}
delete this.subscription;
this.emit('criterion::Remove', this.telemetryObjectIdAsString);
delete this.telemetryObjectIdAsString;
delete this.telemetryObject;
delete this.telemetryMetadata;
}
}

View File

@@ -0,0 +1,112 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2019, 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 TelemetryCriterion from "./TelemetryCriterion";
let openmct = {},
mockListener,
testTelemetryObject,
telemetryCriterion;
describe("The telemetry criterion", function () {
beforeEach (() => {
testTelemetryObject = {
identifier:{ namespace: "", key: "test-object"},
type: "test-object",
name: "Test Object",
telemetry: {
values: [{
key: "some-key",
name: "Some attribute",
hints: {
domain: 1
}
}, {
key: "some-other-key",
name: "Another attribute",
hints: {
range: 1
}
}]
}
};
openmct.objects = jasmine.createSpyObj('objects', ['makeKeyString']);
// openmct.objects.get.and.returnValue(testTelemetryObject);
openmct.objects.makeKeyString.and.returnValue(testTelemetryObject.identifier.key);
openmct.telemetry = jasmine.createSpyObj('telemetry', ["subscribe"]);
// openmct.telemetry.isTelemetryObject.and.returnValue(true);
openmct.telemetry.subscribe.and.returnValue(function () {});
mockListener = jasmine.createSpy('listener');
telemetryCriterion = new TelemetryCriterion(
testTelemetryObject,
openmct
);
telemetryCriterion.on('criterionUpdated', mockListener);
});
it("initializes with a telemetry objectId as string", function () {
expect(telemetryCriterion.telemetryObjectIdAsString).toEqual(testTelemetryObject.identifier.key);
});
it("subscribes to telemetry providers", function () {
telemetryCriterion.subscribe();
expect(telemetryCriterion.subscription).toBeDefined();
});
it("normalizes telemetry data", function () {
let result = telemetryCriterion.normalizeData({
key: 'some-key',
source: 'testSource',
testSource: 'Hello'
});
expect(result).toEqual({
'some-key': 'Hello'
})
});
it("emits update event on new data from telemetry providers", function () {
spyOn(telemetryCriterion, 'emitResult').and.callThrough();
telemetryCriterion.handleSubscription({
key: 'some-key',
source: 'testSource',
testSource: 'Hello'
});
expect(telemetryCriterion.emitResult).toHaveBeenCalled();
expect(mockListener).toHaveBeenCalled();
});
it("un-subscribes from telemetry providers", function () {
telemetryCriterion.subscribe();
expect(telemetryCriterion.subscription).toBeDefined();
telemetryCriterion.unsubscribe();
expect(telemetryCriterion.subscription).toBeUndefined();
expect(telemetryCriterion.telemetryObjectIdAsString).toBeUndefined();
expect(telemetryCriterion.telemetryObject).toBeUndefined();
expect(telemetryCriterion.telemetryMetadata).toBeUndefined();
});
});

View File

@@ -0,0 +1,57 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2019, 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 ConditionSetViewProvider from './ConditionSetViewProvider.js';
import ConditionSetCompositionPolicy from "@/plugins/condition/ConditionSetCompositionPolicy";
export default function ConditionPlugin() {
return function install(openmct) {
openmct.types.addType('condition', {
name: 'Condition',
key: 'condition',
description: 'A list of criteria which will be evaluated based on a trigger',
creatable: false,
initialize: function (domainObject) {
domainObject.composition = [];
}
});
openmct.types.addType('conditionSet', {
name: 'Condition Set',
key: 'conditionSet',
description: 'A set of one or more conditions based on user-specified criteria.',
creatable: true,
cssClass: 'icon-summary-widget', // TODO: replace with class for new icon
initialize: function (domainObject) {
domainObject.configuration = {
conditionCollection: []
};
domainObject.composition = [];
}
});
openmct.composition.addPolicy(new ConditionSetCompositionPolicy(openmct).allow);
openmct.objectViews.addProvider(new ConditionSetViewProvider(openmct));
}
}

View File

@@ -0,0 +1,128 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2019, 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 { createOpenMct } from "testTools";
import ConditionPlugin from "./plugin";
let openmct = createOpenMct();
openmct.install(new ConditionPlugin());
let conditionDefinition;
let conditionSetDefinition;
let mockDomainObject;
let mockDomainObject2;
let element;
let child;
describe('the plugin', function () {
beforeAll((done) => {
conditionDefinition = openmct.types.get('condition').definition;
mockDomainObject = {
identifier: {
key: 'testConditionKey',
namespace: ''
},
type: 'condition'
};
conditionDefinition.initialize(mockDomainObject);
conditionSetDefinition = openmct.types.get('conditionSet').definition;
const appHolder = document.createElement('div');
appHolder.style.width = '640px';
appHolder.style.height = '480px';
element = document.createElement('div');
child = document.createElement('div');
element.appendChild(child);
mockDomainObject2 = {
identifier: {
key: 'testConditionSetKey',
namespace: ''
},
type: 'conditionSet'
};
conditionSetDefinition.initialize(mockDomainObject2);
openmct.on('start', done);
openmct.start(appHolder);
});
let mockConditionObject = {
name: 'Condition',
key: 'condition',
creatable: false
};
it('defines a condition object type with the correct key', () => {
expect(conditionDefinition.key).toEqual(mockConditionObject.key);
});
let mockConditionSetObject = {
name: 'Condition Set',
key: 'conditionSet',
creatable: true
};
it('defines a conditionSet object type with the correct key', () => {
expect(conditionSetDefinition.key).toEqual(mockConditionSetObject.key);
});
describe('the condition object', () => {
it('is not creatable', () => {
expect(conditionDefinition.creatable).toEqual(mockConditionObject.creatable);
});
it('initializes with an empty composition list', () => {
expect(mockDomainObject.composition instanceof Array).toBeTrue();
expect(mockDomainObject.composition.length).toEqual(0);
});
});
describe('the conditionSet object', () => {
it('is creatable', () => {
expect(conditionSetDefinition.creatable).toEqual(mockConditionSetObject.creatable);
});
it('initializes with an empty composition list', () => {
expect(mockDomainObject2.composition instanceof Array).toBeTrue();
expect(mockDomainObject2.composition.length).toEqual(0);
});
it('provides a view', () => {
const testViewObject = {
id:"test-object",
type: "conditionSet"
};
const applicableViews = openmct.objectViews.get(testViewObject);
let conditionSetView = applicableViews.find((viewProvider) => viewProvider.key === 'conditionSet.view');
expect(conditionSetView).toBeDefined();
});
});
});

View File

@@ -0,0 +1,4 @@
export const TRIGGER = {
ANY: 'any',
ALL: 'all'
};

View File

@@ -0,0 +1,7 @@
export const computeConditionForAny = (args) => {
return false;
};
export const computeConditionForAll = (args) => {
return false;
};

View File

@@ -0,0 +1,206 @@
export const OPERATIONS = [
{
name: 'equalTo',
operation: function (input) {
return input[0] === input[1];
},
text: 'is equal to',
appliesTo: ['number'],
inputCount: 1,
getDescription: function (values) {
return ' == ' + values[0];
}
},
{
name: 'notEqualTo',
operation: function (input) {
return input[0] !== input[1];
},
text: 'is not equal to',
appliesTo: ['number'],
inputCount: 1,
getDescription: function (values) {
return ' != ' + values[0];
}
},
{
name: 'greaterThan',
operation: function (input) {
return input[0] > input[1];
},
text: 'is greater than',
appliesTo: ['number'],
inputCount: 1,
getDescription: function (values) {
return ' > ' + values[0];
}
},
{
name: 'lessThan',
operation: function (input) {
return input[0] < input[1];
},
text: 'is less than',
appliesTo: ['number'],
inputCount: 1,
getDescription: function (values) {
return ' < ' + values[0];
}
},
{
name: 'greaterThanOrEq',
operation: function (input) {
return input[0] >= input[1];
},
text: 'is greater than or equal to',
appliesTo: ['number'],
inputCount: 1,
getDescription: function (values) {
return ' >= ' + values[0];
}
},
{
name: 'lessThanOrEq',
operation: function (input) {
return input[0] <= input[1];
},
text: 'is less than or equal to',
appliesTo: ['number'],
inputCount: 1,
getDescription: function (values) {
return ' <= ' + values[0];
}
},
{
name: 'between',
operation: function (input) {
return input[0] > input[1] && input[0] < input[2];
},
text: 'is between',
appliesTo: ['number'],
inputCount: 2,
getDescription: function (values) {
return ' between ' + values[0] + ' and ' + values[1];
}
},
{
name: 'notBetween',
operation: function (input) {
return input[0] < input[1] || input[0] > input[2];
},
text: 'is not between',
appliesTo: ['number'],
inputCount: 2,
getDescription: function (values) {
return ' not between ' + values[0] + ' and ' + values[1];
}
},
{
name: 'textContains',
operation: function (input) {
return input[0] && input[1] && input[0].includes(input[1]);
},
text: 'text contains',
appliesTo: ['string'],
inputCount: 1,
getDescription: function (values) {
return ' contains ' + values[0];
}
},
{
name: 'textDoesNotContain',
operation: function (input) {
return input[0] && input[1] && !input[0].includes(input[1]);
},
text: 'text does not contain',
appliesTo: ['string'],
inputCount: 1,
getDescription: function (values) {
return ' does not contain ' + values[0];
}
},
{
name: 'textStartsWith',
operation: function (input) {
return input[0].startsWith(input[1]);
},
text: 'text starts with',
appliesTo: ['string'],
inputCount: 1,
getDescription: function (values) {
return ' starts with ' + values[0];
}
},
{
name: 'textEndsWith',
operation: function (input) {
return input[0].endsWith(input[1]);
},
text: 'text ends with',
appliesTo: ['string'],
inputCount: 1,
getDescription: function (values) {
return ' ends with ' + values[0];
}
},
{
name: 'textIsExactly',
operation: function (input) {
return input[0] === input[1];
},
text: 'text is exactly',
appliesTo: ['string'],
inputCount: 1,
getDescription: function (values) {
return ' is exactly ' + values[0];
}
},
{
name: 'isUndefined',
operation: function (input) {
return typeof input[0] === 'undefined';
},
text: 'is undefined',
appliesTo: ['string', 'number', 'enum'],
inputCount: 0,
getDescription: function () {
return ' is undefined';
}
},
{
name: 'isDefined',
operation: function (input) {
return typeof input[0] !== 'undefined';
},
text: 'is defined',
appliesTo: ['string', 'number', 'enum'],
inputCount: 0,
getDescription: function () {
return ' is defined';
}
},
{
name: 'enumValueIs',
operation: function (input) {
return input[0] === input[1];
},
text: 'is',
appliesTo: ['enum'],
inputCount: 1,
getDescription: function (values) {
return ' == ' + values[0];
}
},
{
name: 'enumValueIsNot',
operation: function (input) {
return input[0] !== input[1];
},
text: 'is not',
appliesTo: ['enum'],
inputCount: 1,
getDescription: function (values) {
return ' != ' + values[0];
}
}
];

View File

@@ -0,0 +1,47 @@
import ImageryViewLayout from './components/ImageryViewLayout.vue';
import Vue from 'vue';
export default function ImageryViewProvider(openmct) {
const type = 'example.imagery';
const hasImageTelemetry = function (domainObject) {
const metadata = openmct.telemetry.getMetadata(domainObject);
if (!metadata) {
return false;
}
return metadata.valuesForHints(['image']).length > 0;
};
return {
key: type,
name: 'Imagery Layout',
cssClass: 'icon-image',
canView: function (domainObject) {
return hasImageTelemetry(domainObject);
},
view: function (domainObject) {
let component;
return {
show: function (element) {
component = new Vue({
components: {
ImageryViewLayout
},
provide: {
openmct,
domainObject
},
el: element,
template: '<imagery-view-layout ref="ImageryLayout"></imagery-view-layout>'
});
},
destroy: function () {
component.$destroy();
component = undefined;
}
};
}
}
}

View File

@@ -0,0 +1,249 @@
<template>
<multipane class="c-imagery-layout"
type="vertical"
>
<pane :style="{'min-height': `300px`}">
<div class="main-image-wrapper c-imagery has-local-controls">
<div class="h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover l-flex-row c-imagery__lc">
<span class="holder flex-elem grows c-imagery__lc__sliders">
<input v-model="filters.brightness"
class="icon-brightness"
type="range"
min="0"
max="500"
>
<input v-model="filters.contrast"
class="icon-contrast"
type="range"
min="0"
max="500"
>
</span>
<span class="holder flex-elem t-reset-btn-holder c-imagery__lc__reset-btn">
<a class="s-icon-button icon-reset t-btn-reset"
@click="filters={brightness: 100, contrast: 100}"
></a>
</span>
</div>
<div class="main-image s-image-main"
:class="{'paused unnsynced': paused(),'stale':false }"
:style="{'background-image': `url(${getImageUrl()})`,
'filter': `brightness(${filters.brightness}%) contrast(${filters.contrast}%)`}"
>
</div>
<div class="l-image-controller flex-elem l-flex-row">
<div class="l-datetime-w flex-elem grows">
<a class="c-button show-thumbs sm hidden icon-thumbs-strip"></a>
<span class="l-time">{{ getTime() }}</span>
</div>
<div class="h-local-controls flex-elem">
<a class="c-button icon-pause pause-play"
:class="{'is-paused': paused()}"
@click="paused(!paused())"
></a>
</div>
</div>
</div>
</pane>
<pane class="c-inspector__elements"
handle="before"
:style="{'min-height': `100px`}"
>
<div class="c-elements-pool">
<div ref="thumbsWrapper"
class="thumbs-layout"
@scroll="handleScroll"
>
<div v-for="(imageData, index) in imageHistory"
:key="index"
class="l-image-thumb-item"
:class="{selected: imageData.selected}"
@click="setSelectedImage(imageData)"
>
<img class="l-thumb"
:src="getImageUrl(imageData)"
>
<div class="l-time">{{ getTime(imageData) }}</div>
</div>
</div>
</div>
</pane>
</multipane>
</template>
<script>
import multipane from '@/ui/layout/multipane.vue';
import pane from '@/ui/layout/pane.vue';
import _ from 'lodash';
export default {
inject: ['openmct', 'domainObject'],
components: {
multipane,
pane
},
data() {
return {
autoScroll: true,
date: '',
filters : {
brightness: 100,
contrast: 100
},
image: {
selected: ''
},
imageFormat: '',
imageHistory: [],
imageUrl: '',
isPaused: false,
requestCount: 0,
timeFormat: ''
}
},
mounted() {
this.keystring = this.openmct.objects.makeKeyString(this.domainObject.identifier);
this.subscribe(this.domainObject);
},
updated() {
this.scrollToBottom();
},
beforeDestroy() {
this.stopListening();
},
methods: {
datumMatchesMostRecent(datum) {
if (this.imageHistory.length === 0) {
return false;
}
const datumTime = this.timeFormat.format(datum);
const datumURL = this.imageFormat.format(datum);
const lastHistoryTime = this.timeFormat.format(this.imageHistory.slice(-1)[0]);
const lastHistoryURL = this.imageFormat.format(this.imageHistory.slice(-1)[0]);
return (datumTime === lastHistoryTime) && (datumURL === lastHistoryURL);
},
getImageUrl(datum) {
return datum ?
this.imageFormat.format(datum) :
this.imageUrl;
},
getTime(datum) {
return datum ?
this.timeFormat.format(datum) :
this.time;
},
handleScroll() {
const thumbsWrapper = this.$refs.thumbsWrapper
if (!thumbsWrapper) {
return;
}
const { scrollLeft, scrollWidth, clientWidth, scrollTop, scrollHeight, clientHeight } = thumbsWrapper;
const disableScroll = (scrollWidth - scrollLeft) > 2 * clientWidth
|| (scrollHeight - scrollTop) > 2 * clientHeight;
this.autoScroll = !disableScroll;
},
paused(state) {
if (arguments.length > 0 && state !== this.isPaused) {
this.unselectAllImages();
this.isPaused = state;
if (this.nextDatum) {
this.updateValues(this.nextDatum);
delete this.nextDatum;
} else {
this.updateValues(this.imageHistory[this.imageHistory.length - 1]);
}
this.autoScroll = true;
}
return this.isPaused;
},
requestHistory(bounds) {
this.requestCount++;
this.imageHistory = [];
const requestId = this.requestCount;
this.openmct.telemetry
.request(this.domainObject, bounds)
.then((values = []) => {
if (this.requestCount > requestId) {
return Promise.resolve('Stale request');
}
values.forEach(this.updateHistory);
this.updateValues(values[values.length - 1]);
});
},
scrollToBottom() {
if (this.isPaused || !this.$refs.thumbsWrapper || !this.autoScroll) {
return;
}
const scrollHeight = this.$refs.thumbsWrapper.scrollHeight || 0;
if (!scrollHeight) {
return;
}
setTimeout(() => this.$refs.thumbsWrapper.scrollTop = scrollHeight, 0);
},
setSelectedImage(image) {
this.imageUrl = this.getImageUrl(image);
this.time = this.getTime(image);
this.paused(true);
this.unselectAllImages();
image.selected = true;
},
stopListening() {
if (this.unsubscribe) {
this.unsubscribe();
delete this.unsubscribe;
}
},
subscribe(domainObject) {
this.date = ''
this.imageUrl = '';
this.openmct.objects.get(this.keystring)
.then((object) => {
const metadata = this.openmct.telemetry.getMetadata(this.domainObject);
this.timeKey = this.openmct.time.timeSystem().key;
this.timeFormat = this.openmct.telemetry.getValueFormatter(metadata.value(this.timeKey));
this.imageFormat = this.openmct.telemetry.getValueFormatter(metadata.valuesForHints(['image'])[0]);
this.unsubscribe = this.openmct.telemetry
.subscribe(this.domainObject, (datum) => {
this.updateHistory(datum);
this.updateValues(datum);
});
this.requestHistory(this.openmct.time.bounds());
});
},
unselectAllImages() {
this.imageHistory.forEach(image => image.selected = false);
},
updateHistory(datum) {
if (this.datumMatchesMostRecent(datum)) {
return;
}
const index = _.sortedIndex(this.imageHistory, datum, this.timeFormat.format.bind(this.timeFormat));
this.imageHistory.splice(index, 0, datum);
},
updateValues(datum) {
if (this.isPaused) {
this.nextDatum = datum;
return;
}
this.time = this.timeFormat.format(datum);
this.imageUrl = this.imageFormat.format(datum);
}
}
}
</script>

View File

@@ -0,0 +1,32 @@
.c-imagery-layout {
display: flex;
flex-direction: column;
overflow: auto;
.main-image-wrapper {
display: flex;
flex-direction: column;
height: 100%;
padding-bottom: 5px;
}
.main-image {
background-position: center;
background-repeat: no-repeat;
background-size: contain;
height: 100%;
&.unnsynced{
@include sUnsynced();
}
}
.l-image-controller {
padding: 5px 0 0 0;
}
.thumbs-layout {
margin-top: 5px;
overflow: auto;
}
}

View File

@@ -0,0 +1,8 @@
import ImageryViewProvider from './ImageryViewProvider';
export default function () {
return function install(openmct) {
openmct.objectViews.addProvider(new ImageryViewProvider(openmct));
};
}

View File

@@ -0,0 +1,10 @@
# Plot Plugin
Enables plot visualization of telemetry data. This plugin adds a plot view that is available from the view switcher for
all telemetry objects. Two user createble objects are also added by this plugin, for Overlay and Stacked Plots.
Telemetry objects can be added to Overlay and Stacked Plots via drag and drop.
## Installation
``` js
openmct.install(openmct.plugins.Plot());
```

View File

@@ -225,7 +225,7 @@
left: (100 * (tick.value - min) / interval) + '%'
}"
ng-title=":: tick.fullText || tick.text">
{{:: tick.text | reverse}}
{{:: tick.text }}
</div>
</mct-ticks>

View File

@@ -46,7 +46,7 @@ define([
},
{
modelProp: 'range',
objectPath: 'form.yAxis.range',
objectPath: 'configuration.yAxis.range',
coerce: function coerceRange(range) {
if (!range) {
return {

View File

@@ -1,5 +1,5 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* Open MCT, Copyright (c) 2014-2019, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
@@ -28,6 +28,7 @@ define([
'./autoflow/AutoflowTabularPlugin',
'./timeConductor/plugin',
'../../example/imagery/plugin',
'./imagery/plugin',
'../../platform/import-export/bundle',
'./summaryWidget/plugin',
'./URLIndicatorPlugin/URLIndicatorPlugin',
@@ -46,6 +47,7 @@ define([
'./goToOriginalAction/plugin',
'./clearData/plugin',
'./webPage/plugin',
'./condition/plugin',
'./themes/espresso',
'./themes/maelstrom',
'./themes/snow'
@@ -57,6 +59,7 @@ define([
AutoflowPlugin,
TimeConductorPlugin,
ExampleImagery,
ImageryPlugin,
ImportExport,
SummaryWidget,
URLIndicatorPlugin,
@@ -75,6 +78,7 @@ define([
GoToOriginalAction,
ClearData,
WebPagePlugin,
ConditionPlugin,
Espresso,
Maelstrom,
Snow
@@ -162,6 +166,7 @@ define([
};
plugins.ExampleImagery = ExampleImagery;
plugins.ImageryPlugin = ImageryPlugin;
plugins.Plot = PlotPlugin;
plugins.TelemetryTable = TelemetryTablePlugin;
@@ -182,6 +187,7 @@ define([
plugins.Espresso = Espresso.default;
plugins.Maelstrom = Maelstrom.default;
plugins.Snow = Snow.default;
plugins.Condition = ConditionPlugin.default;
return plugins;
});

View File

@@ -0,0 +1,19 @@
# Static Root Plugin
This plugin takes an object tree as JSON and exposes it as a non-editable root level tree. This can be useful if you
have static non-editable content that you wish to expose, such as a standard set of displays that should not be edited
(but which can be copied and then modified if desired).
Any object tree in Open MCT can be exported as JSON after installing the
[Import/Export plugin](../../../platform/import-export/README.md).
## Installation
``` js
openmct.install(openmct.plugins.StaticRootPlugin('mission', 'data/static-objects.json'));
```
## Parameters
The StaticRootPlugin takes two parameters:
1. __namespace__: This should be a name that uniquely identifies this collection of objects.
2. __path__: The file that the static tree should be exposed from. This will need to be a path that is reachable by a web
browser, ie not a path on the local file system.

View File

@@ -0,0 +1,10 @@
# Summary Widget Plugin
Summary widgets can be used to provide visual indication of state based on telemetry data. They allow rules to be
defined that can then be used to change the appearance of the summary widget element based on data. For example, a
summary widget could be defined that is green when a temparature reading is between `0` and `100` centigrade, red when
it's above `100`, and orange when it's below `0`.
## Installation
```js
openmct.install(openmct.plugins.SummaryWidget());
```

View File

@@ -0,0 +1,7 @@
# Espresso Theme
A light colored theme for the Open MCT user interface.
## Installation
```js
openmct.install(openmct.plugins.Snow());
```

View File

@@ -1,5 +1,7 @@
@import "../api/overlays/components/dialog-component.scss";
@import "../api/overlays/components/overlay-component.scss";
@import "../plugins/condition/components/condition.scss";
@import "../plugins/condition/components/condition-set.scss";
@import "../plugins/displayLayout/components/box-view.scss";
@import "../plugins/displayLayout/components/display-layout.scss";
@import "../plugins/displayLayout/components/edit-marquee.scss";
@@ -14,6 +16,7 @@
@import "../plugins/folderView/components/grid-view.scss";
@import "../plugins/folderView/components/list-item.scss";
@import "../plugins/folderView/components/list-view.scss";
@import "../plugins/imagery/components/imagery-view-layout.scss";
@import "../plugins/telemetryTable/components/table-row.scss";
@import "../plugins/telemetryTable/components/telemetry-filter-indicator.scss";
@import "../plugins/tabs/components/tabs.scss";

View File

@@ -31,6 +31,7 @@ const webpackConfig = {
},
resolve: {
alias: {
"@": path.join(__dirname, "src"),
"legacyRegistry": path.join(__dirname, "src/legacyRegistry"),
"saveAs": "file-saver",
"csv": "comma-separated-values",