Compare commits

...

167 Commits

Author SHA1 Message Date
4c672e074e Merge branch 'mct4463' of github.com:nasa/openmct into mct4463 2021-11-17 14:32:28 -06:00
3319322bc6 Merge github.com:nasa/openmct into mct4463 2021-11-17 14:31:53 -06:00
f5943512da Added line break 2021-11-17 14:31:19 -06:00
c57d659cb5 Merge branch 'master' into mct4463 2021-11-17 13:19:16 -06:00
4a9af38491 Whitespace 2021-11-17 10:44:05 -06:00
c0c35d6e8c Adjusted name of sort method 2021-11-17 10:41:56 -06:00
25b3431131 saving the object if it was missing (#4471) 2021-11-16 17:34:11 -08:00
c8723da098 Transaction fix (#4421)
* When transaction is active, objects.get should search in dirty object first.

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-11-15 14:20:02 -08:00
933ce7aa3c [#4378] Ensure navigated object check works correctly when path is modified (#4433)
* [#4378] Emit event when router path is set. Handle the event when creating an object

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-11-15 15:35:59 -06:00
8ef3869325 Notebook Objects cannot be created with CouchDB enabled (#4425)
* added null check
* added test coverage for exception that caused bug

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-11-15 14:55:04 -06:00
53f5fdabe5 Mct4207 (#4366)
* MCT 4207
* fix lint

Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
2021-11-15 11:25:57 -08:00
d10561fc7f Fix security policy typo, and duplicate security issue template entries (#4447)
* Tiny typo
* Remove duped security issue entries
2021-11-10 15:38:13 -08:00
566469e691 [Task] Update our top level security policy (#4429)
* Create SECURITY.md

* Remove unused template

* Add security template to our issue chooser

* Add new issue type for maintenance

* eslint changes

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-11-10 13:33:22 -08:00
6d4a324fca [Timer] Re-implement Timer object in Vue.js (#4311)
* Re-implemented timer and clock and installed as a plugin
* Clock indicator is installed as configuration to clock plugin
* Uses moment

Co-authored-by: Andrew Henry <akhenry@gmail.com>
Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov>
2021-11-09 14:41:42 -08:00
b8fabb7e73 [MyItems Plugin] Migrate/remove legacy MyItems code into new plugin (#4107)
* removed legacy my items, created my items plugin, moved relevant code to new plugin
* added object api method for checking if a domainObject is a missing object

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-11-05 11:17:49 -07:00
1680c3cc1b example imagery refactor to have configurable image urls and IMAGE_DELAY (#4024)
*Imagery refactor to have configurable image urls and IMAGE_DELAY.
2021-11-05 10:54:12 -07:00
61dd85c704 Sort MyItems alphabetically when building the tree #1717 (#4376)
* Sort MyItems alphabetically when building the tree

* Fixed brace indentation

* Modified tree-item to accept is-new prop for initial highlighting

* Adjusted sort function and properly sort children before splicing treetItems

* Mods for #1717
- Refined color and timing, color is now theme-compliant;
- Added new theme color constants;
- Smoke tested in Espresso and Snow themes;

Co-authored-by: Andrew Henry <akhenry@gmail.com>
Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com>
2021-11-04 13:35:10 -07:00
980777691a [CI] Add npm audit to the nightly (#4431) 2021-11-04 06:53:55 -07:00
a50c1704e5 [CI] Firefox needs to be defined as FirefoxHeadless (#4415)
* [ci] Firefox needs to be defined as FirefoxHeadless

* Update job names and comments

* Fix circleCI config yaml
2021-11-01 13:21:08 -07:00
98080784a3 [CI] Update dependabot regex to use ruby rules (#4411)
Need to use ruby regex matching. Added more dependencies to monitor.
2021-11-01 10:19:57 -07:00
bf7b672957 [CI] Disable html unit test reporting to increase CI Speed (#4416)
* [CI] Disable html unit test reporting to increase CI Speed

* remove package

* Remove istanbul html reports

* clean up errors

* Update README.md
2021-11-01 09:02:32 -07:00
5dadf6f6fc Prep version for sprint 1.8.1 (#4405) 2021-10-29 18:47:03 -05:00
555db60bf7 1.8.0 merge into master (#4404) 2021-10-29 15:43:11 -07:00
1972ca9ea7 Run Codecov in informational mode (#4409) 2021-10-29 15:09:33 -07:00
1e11bbc2ad Add codecov.io and make general CircleCI Improvements (#4375) 2021-10-29 09:52:47 -07:00
c4a87ae5d7 Dependabot for linting and GHA (#4397)
* Dependabot for linting and GHA

* Update dependabot.yml

* Real-time updates were removed from dependabot beta

* label GHA bumps

* Ignore yaml changes on security scans
2021-10-29 09:22:02 -07:00
4e325fb165 [Tabs] Fix "Eager Load Tabs" option (#4371)
* If eager load is checked, tabs are pre-fetched and kept alive.
* If eager load is not checked, tabs are not pre-fetched, and are not kept alive
2021-10-28 19:09:44 -07:00
e59e4efdf0 Inspect PRs (#4395) 2021-10-28 12:57:48 -07:00
f17fda53a0 Save the object before adding it to the parent so that transaction committing works properly (#4388) 2021-10-28 09:35:53 -07:00
f2dbe6d816 Setting snapshot version for 1.8.0 (#4379) 2021-10-26 15:04:06 -07:00
510d3bd333 1.7.8 master (#4373)
* Notebook conflict auto retry 1.7.7 (#4230)
* Use timeFormatter.parse to get the timestamp of imagery since the source could be something other than key (#4238)
* If there is a pending create request for an id, queue a duplicate request. (#4243)
* [Telemetry Tables] Handling Request Loading (#4245)

* Fix file selection on pressing enter key (#4246)

* starting loading as false, since that makes sense (#4247)

* Hide independent time conductor mode if only 1 mode option is available. (#4250)

* Fix bargraph color selection (#4253)

* snapshot clicked while in edit mode should open in preview mode #4115 (#4257)

* Fix missing object handling in several vues (#4259)

* Flexible Layouts display Condition Sets as their editing/browsing interface (#4179)

* Flexible Layouts display Condition Sets as their editing/browsing interface #4141

* [Telemetry Table] Progress bar tests (#4249)

* Remove alert styling and hide pause button if in Fixed Time mode. (#4263)

* [Table/Collection Fixes] Clearing correctly, no mutating options, no duplicate requests (#4261)

* Condition sets only persist if actively editing (#4262)

* Imagery views should follow time context (#4264)

* Equal stacked plot y widths for all it's sub-plots (#4267)

* Fix Bar Graph related CSS (#4270)

* Bar graph review comment fixes (#4232)

* Mct4196 - Fixes Conditional Styling not being applied when editing a Condition Widget (#4255)

* Fix plot zoom when child of time strip (#4272)

* Resume plot if no pan, zoom, or drag action is taken (#4138) (#4256)

* [Telemetry Collection] No duplicate requests on load (#4274)

* doing the easy thing first (#4278)

* Bargraph time metadata should consider 'source' (#4289)

* Show clicked image in large view (#4280)

* added icon for inspector (#4275)

* Bar graph style nullcheck (#4291)

* Stacked plots need to align the Y axis  (#4286)

* Duplicate Request Fixes (#4295)

* Add braintree sanitize url lib and sanitize form urls (#4296)

* Mct4177 fix for telemetry endpoints with '.' in the key (#4308)

* Remove additional request to load plots when mounted. (#4314)

* Fix plots dup requests (#4324)

* Merging 1.7.8 into master.

Co-authored-by: Andrew Henry <akhenry@gmail.com>
Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov>
Co-authored-by: Khalid Adil <khalidadil29@gmail.com>
Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com>
Co-authored-by: Scott Bell <scott@traclabs.com>
Co-authored-by: Michael Rogers <michael@mhrogers.com>
2021-10-26 13:35:23 -07:00
a908eb1d65 Mct4170 - Give indicators priorities (#4322)
* added priority api with an enum for sane priority defaults
openmct.priority.LOW: -1000. Should always run last.
openmct.priority.DEFAULT: 0. This is the default unless you specify something else.
openmct.priority.HIGH: 1000. Should always run first.

* allow indicators to be sorted by priority
2021-10-25 14:24:03 -07:00
c0bda64927 Mct4337 - CouchDB installation instructions (#4340)
* added rough first draft on installing and configuring couchdb

* second draft of couchdb manual

* made explict the roles to delete

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-10-25 14:07:27 -07:00
d0c5731287 Implement transactions in Object API and retire legacy transactions #4089 (#4195)
* Implement transactions in Object API and retire legacy transactions #4089
* Added `objectAPI.refresh`

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-10-25 13:13:17 -07:00
5eaf222f88 Test time conductor history 4287 (#4321)
Added some extra test for the new implementation of Time Conductor History on PR 4287
* Refractor on testing and Time Conductor
* Update duration.js
Refractor on getPreciseDuration()
2021-10-22 12:21:28 -07:00
0249ab4df5 [StackedPlots] Destroy programmatically created component instances (#4345) 2021-10-22 10:54:46 -07:00
4f8cba160d Router test fix (#3973)
* removed DEPRECATION warnings
* test fixes
* added spec reporter to debug failing tests  and fixed couple specs
* disabled failFast to see all failing tests
* disabled fail test and  change timeoutInterval to 5000
* removed unused debounce import

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-10-21 16:55:34 -07:00
c269e089da Condition Widgets multiple fixes (#4335) 2021-10-21 10:16:41 -07:00
4873f40614 Add clarity to PR Template (#4336)
* Add clarity to PR Template

* one more time

* Update PULL_REQUEST_TEMPLATE.md
2021-10-20 13:13:41 -07:00
10bb9173ec enable lint on circle ci (#4312)
* enable lint on circle ci

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-10-18 15:17:17 -05:00
ea8c9c7cc8 The Object API should propagate out fresh model to any observers when .get() is called #4305 (#4325) 2021-10-18 13:01:41 -07:00
4c9c084eec #4197 - make time conductor history more readable (#4287) 2021-10-13 17:02:47 -07:00
b64ee10812 Fix #4299 (#4300) 2021-10-13 16:42:45 -07:00
ee1ecf43db Fix leftover lint errors/warnings (#4316) 2021-10-13 16:15:23 -07:00
4d8db8eb7c Update Conductor.vue (#4150)
* checking for NaN on pan

Lint resolved

Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
2021-10-12 14:04:58 -07:00
1b13965200 Fix #3981 (#4302)
* Fix #3981
- Mods to markup and CSS for better approach to overflowing and min-heights;
- WIP!

* Fix #3981
- Refinements to min-height approach;
- CSS cleanups;

Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
2021-10-07 14:50:54 -05:00
38db8f7fe5 Fix #4090 (#4298)
- HTML/CSS mods to remove button holding element that was blocking clicks,
instead position buttons independently;
- Disabled style now handled better in `show-on-hover` class;
- Removed overly-specific size and positioning defs from cArrowButtonBase mixin;
2021-10-07 10:41:39 -07:00
4ba8f893a6 authors should think about backwards compatibility (#4223)
* authors should think about backwards compatibility

* Add reviewer check for breaking changes
2021-09-23 10:45:07 -05:00
c4b9be18f1 Support for Bar Graphs (#4221)
* Adds new types for Bar Graphs (#4168)
* Adds new spectral test data

Co-authored-by: Scott Bell <scott@traclabs.com>
Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com>
Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-09-18 13:00:16 -07:00
eabdf6cd04 Independent time conductor (#3988)
* Independent time API implementation
* Independent time conductor in plan view

Co-authored-by: charlesh88 <charles.f.hacskaylo@nasa.gov>
Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-09-18 09:53:35 -07:00
e56c673005 [Telemetry Collections] Add process method to historical request options (for yield requests) (#4201)
* added processor generator to request options in the telemetry API. Allows progressive yielding of request results.

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-09-17 19:50:53 -05:00
dad9f12a5c Imagery view for time strip (#4114)
* Imagery view for time strip

Co-authored-by: charlesh88 <charles.f.hacskaylo@nasa.gov>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
2021-09-17 20:05:40 -04:00
aa5edb0b83 Flexible inspector properties (#4109)
* inspector properties can be passed in through context
* defaults to the currently hard-coded details (title, type, modified or created)
2021-09-17 16:20:22 -07:00
b315803180 Add linear progress bar to tables (#4204)
* Add linear progress bar to tables
- Stubbed in markup;
- Better CSS anim for clarity;

* Indeterminate progress bar for telemetry tables
- Significant refinements to use ProgressBar.vue component;
- Stubbed in temp computed property for `progressLoad`;
- Better animation approach for indeterminate progress;
- Refined markup and CSS for `c-progress-bar`;

* Indeterminate progress bar for telemetry tables
- Refinements for determinate progress as shown in notification banners;
- Refined look of progress bar for clarity;
- Vue component now uses progressPerc === undefined instead of 'unknown';
- Animation tweaked;

* Changed progress-bar v-if test
- Per PR change suggestion, replace `v-if=progressLoad.progressPerc !== 100`
to `v-if=loading`;
2021-09-17 15:53:00 -07:00
b27317631b Add new glyphs for Bar Chart and Map views (#4219)
- New glyph and background classes for `icon-bar-chart` and
`bg-icon-bar-chart`;
- New glyph and background classes for `icon-map` and
`bg-icon-map`;
2021-09-17 13:11:09 -07:00
953a9daafb Fixes resizing handler error - adds null check (#4218) 2021-09-16 16:10:48 -07:00
63f9cd449f Refactor Angular Clock and Clock Indicator as plugin (#4106)
* clock and clock indicator installed as a plugin
* { enableIndicator: true } to install indicator
* Vue for views
2021-09-15 11:01:40 -07:00
54220f547b WIP (#4213)
Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-09-14 20:18:33 -04:00
93d967c2b3 Snapshot notice link not navigating as expected #4194 (#4199)
Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
2021-09-14 15:17:31 -07:00
1226459c6f View Large overlay doesn't allow taking Snapshots (#4091)
* Added NotebookMenuSwitcher in preview header
* Use preview component inside viewLargeAction
* Added autoHide flag to overlay API that allows developers to specify whether an overlay should remain visible if other overlays are subsequently triggered (eg. the snapshot overlay)
* When in edit mode, disable navigation link to notebook entry.

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-09-13 19:36:14 -05:00
d7c9c9cb98 Snapshot images should use the namespace of the notebook they are being saved to or LocalStorage (#4020)
* Snapshot images should use the namespace of the notebook they are being saved to, or LocalStorage #4007

Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
2021-09-13 13:44:38 -07:00
2131ef2397 Clear data for objects clears data for all objects
Clear data for objects clears data for all objects #4065
2021-09-10 11:30:54 -07:00
48c22369a1 Fixed memory leak in import-export plugin (#4061) 2021-09-02 15:45:11 -07:00
6506077f4d refactor panes (#4125)
* remove router listeners
* remove some hard-coding
2021-09-02 14:11:05 -07:00
b1b4266ff3 Add automated security scanning to our repo (#4166) 2021-08-30 15:44:25 -07:00
42b0148f93 Add new icon for aggregate telemetry (#4163) 2021-08-30 11:19:47 -07:00
9461ad8edd Add new Ellipse drawing object in Display Layouts (#4153)
* Add new ellipse drawing object to Display Layouts
- Fix test and linting issues;

Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
2021-08-30 13:29:05 -04:00
40055ba955 Prepare for sprint 1.7.8 (#4156) 2021-08-27 04:55:30 -07:00
9cb85ad176 1.7.7 merge into master (#4155)
* Merge 1.7.7 sprint branch into master

Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov>
Co-authored-by: Khalid Adil <khalidadil29@gmail.com>
2021-08-27 04:44:23 -07:00
f2b2953a5d [Display Layout] Right click on item acts as sticky move (#4126)
* Added a left click filter to the mousedown events
* Moved ternary logic out of the template
* Move defauts into function params
2021-08-23 16:15:57 -07:00
62de310686 fix: typo spelling grammar (#4095)
* fix: typo spelling grammar
2021-08-23 15:43:58 -07:00
4b9ff67e49 [Notebook] Create Snapshot directly from any frame in a layout #3300 (#4099) 2021-08-23 14:03:49 -07:00
d5e32ec494 [Telemetry Collection] Fixes: abort requests, naming, bindings, errors, time system handling (#4128)
* naming signal correctly for aborint
* updating api call for requesting telemetry collections

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-08-19 17:21:35 -07:00
38880ba3d1 Update job names to be more explicit (#4137)
It's still not clear which jobs pass/fail on tests. This change will update the name of the job which is run to be more explicit that it only pass/fails on the build step
2021-08-19 13:25:07 -07:00
a99ce7733c changed from window resize event, to element ResizeObserver for more accurate tracking of tree size (#4132) 2021-08-18 16:38:48 -07:00
9f48764210 Add Nightly CI Job to Circle to identify flake on master (#4032)
* Nightly job
* Unique job names
2021-08-18 13:16:15 -07:00
a1aaa0dd41 Refractor (#3836)
* Refractor
* Update AgentService.js
* Update ExportAsJSONActionSpec.js
2021-08-18 11:57:47 -07:00
bee15e98c8 Added .npmrc to silence log messages < WARN (#3649)
* Added .npmrc to silence log messages < WARN
2021-08-18 09:31:53 -07:00
092bbe547d Prepare for sprint 1.7.7 (#4127) 2021-08-18 11:56:12 -04:00
6cbe05317c 3788 - Re-implement DeviceClassifier in vanilla JS (#3837)
* Changed AgentService to Agent and exposed in utils
* removed MCTDevice
2021-08-17 10:21:50 -07:00
3b92fcdf6c Prevent extra loading of plots data (#4120) 2021-08-17 09:51:53 -07:00
6dde54bd25 Fix plots performance (#4092)
* Fix no mutating props violation for Browsebar and StyleEditor
* Separate plot series data from the configuration (like it should be!)
2021-08-16 14:21:09 -07:00
359e7377ac Notebook Snapshot menu is only updating section and page names for the editor's view #3982 (#4002)
* if default section/page is missing then clear default notebook and hide option from dropdown.

* handle edge case when section is null/undefined.

* refactored notebook localstorage data + fixed some edge cases when default section/page gets deleted.

Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
2021-08-12 13:29:01 -07:00
9f4190f781 [Linting] Fix linting errors (#4082) 2021-08-11 15:11:17 -07:00
f3fc991a74 [Telemetry Collections] Add Telemetry Collection Functionality to Telemetry API (#3689)
Adds telemetry collections to the telemetry API

Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-08-10 10:36:33 -07:00
2564e75fc9 [Notebook] Example Imagery doesn't capture images #2942 (#2943)
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-08-10 10:26:51 -07:00
f42fe78acf 1.7.6 master merge (#4097)
* remove can edit from hyperlink (#4076)

* Add check for stop observing before calling it (#4080)

* Set the yKey value on the series when it's changed (#4083)

* [Imagery] Click on image to get a large view #3582 (#4085)

fixed issue where large imagery view opens only once.

Co-authored-by: Henry Hsu <hhsu0219@gmail.com>
Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov>
2021-08-10 07:00:13 -07:00
fe928a1386 [Imagery] Click on image to get a large view #3582 (#4077)
fixed issue where large imagery view opens only once.
2021-08-04 12:57:48 -07:00
b329ed6ed5 Couch object provider performance improvement using SharedWorker (#3993)
* Use the window SharedWorker instead of the WorkerService
* Use relative asset path for Shared Workers
* Remove beforeunload listener on destroy
2021-07-30 15:23:02 -07:00
9b7a0d7e4c Reimplement hyperlink vue (#4062)
* added vue hyperlink plugin
* remove angular code. update target attribute
* Polishing on form styles
- Remove `display: flex` from `.l-shell__main-container` and
`.c-so-view__object-view` CSS - IMPORTANT: NEEDS REGRESSION TESTING!
- Improvements to `.c-hyperlink` CSS;
- Markup cleanups and simplification;
- Remove duped CSS in object-frame.scss, probably result of prior bad
past merge;
* Fixes for object-frame and preview.scss
* Refinement to make hyperlink button have same display behavior as
Condition Widget;
* refactor layout template. update tests
* remove legacy hyperlink
* Updating firefox launcher

Co-authored-by: Henry Hsu <henry.hsu@nasa.gov>
Co-authored-by: charlesh88 <charles.f.hacskaylo@nasa.gov>
2021-07-30 13:49:31 -07:00
5c15e53abb Mct4039 (#4057)
Re-implements ImageExportService as ES6 class instead of Angular managed service.

Co-authored-by: John Hill <jchill2.spam@gmail.com>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-07-29 22:05:18 -07:00
f58b3881f2 Not everything fits into the two types of issue (#4064)
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-07-29 17:17:51 -07:00
071a13b219 [Imagery] Click on image to get a large view (#3770)
* [Imagery] Click on image to get a large view #3582
* Created new viewLargeAction.
* Changes in view registry to add parent element property inside view object.
* Separate class for views and added missing changes for LadTableSet.
* Renamed callBack to onItemClicked.

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-07-29 09:19:07 -07:00
ca66898e51 [Plugin] Remote Clock based off Telemetry (#3998)
* Remote-clock plugin
* Added a default clock class that can be extended by other classes
* Updated local clock to use the parent default clock class
* added a period check to make sure its been a certain amount of time before emitting
Co-authored-by: John Hill <jchill2.spam@gmail.com>
2021-07-28 16:46:08 -07:00
94c7b2343a Add Enhancement request template (#4063)
* Add Enhancement request template

* Link to github discussions

* Update config.yml
2021-07-27 15:02:30 -07:00
c397c336ab [Telemetry Tables] Observe for changes in table configuration (#4053) 2021-07-27 14:08:44 -07:00
eea23f2caf Fix typo in template (#4059) 2021-07-27 11:05:02 -07:00
6665641c02 Update issue templates (#4058)
Add a bug report directly to the project
2021-07-27 10:38:24 -07:00
c3ebf52dd2 Prepare for sprint 1.7.6 (#4052) 2021-07-26 14:04:26 -07:00
f8f2e7da9b Remove deprecated timeline bundle (#4048) 2021-07-23 13:51:32 -07:00
240f58b2d0 [Telemetry API] wrap limits function return in promise if needed (#4044) 2021-07-20 07:25:43 -07:00
7d3baee7b5 URL Params to hide tree and inspector (#3951)
* Add checks and hide panes accordingly, toggle hide params when toggling panes, add params on change event
* add tests

Co-authored-by: Henry Hsu <henry.hsu@nasa.gov>
Co-authored-by: John Hill <jchill2.spam@gmail.com>
2021-07-19 10:01:05 -07:00
1f5cb7ca42 Prevent default on click events for conductor delta buttons (#4022)
* Prevent default on click events for conductor delta buttons
2021-07-15 14:46:53 -07:00
4a7ebe326c Plot view policy fix (#3995)
* deny plot view for non-numeric telemetry

* revert plot type for backwards compatibility
2021-07-14 18:12:26 -07:00
10da314a4a Add resize event and disable pointer events on iframes on trigger of resize (#4016) 2021-07-14 17:32:45 -07:00
b3ceccd7fb temporarily skip test on chrome (#4021) 2021-07-14 15:58:44 -07:00
1bde4c9a0c Update all unit test packages, set node engine rules, new circleci workflow, pin to stable (#3957)
* Update all unit test packages, set node engine rules, new circleci workflow

Co-authored-by: unlikelyzero <jchill2@gmail.com>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-07-14 09:26:38 -07:00
4b85360446 1.7.4 stable master (#4015) 2021-07-13 13:59:37 -07:00
41b860a547 Fixes for Imagery Snapshotting #3963 (#4001)
* refactored compass structure and code.
* resize image wrapper
* center image properly
* Refactor imagery compass rose as SVG
* Suppress prev/next image arrows from Snapshot

Co-authored-by: Nikhil Mandlik <nikhil.k.mandlik@nasa.gov>
2021-07-09 18:03:11 -07:00
254b3db966 added mock values to compass for example imagery. (#3999) 2021-07-09 15:13:54 -07:00
cbb3f32d1e 1.7.4 into master (#3985)
catching any errors from a user canceling from dialog (#3968)
Fix navigation errors (#3970)
Only add listeners to observables on creation
Do not double destroy mutable objects
Disallow pause and play in time strip view for plots. (#3972)
Update version

Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-06-29 09:40:30 -07:00
e3bf72e77f New time conductor popups should be closed by hitting ESC key (#3978) 2021-06-29 09:03:58 -07:00
0b63b782cf Image thumbs autoscroll resumption functionality (#3892)
* add logs for testing

* check autoScroll value

* Add auto scroll button at thumbnails

* add auto scroll button functionality

* turn on auto scroll whenever scroll bar is not at the right end

* check if scroll right when the page load

* update scroll to right condition

* remove resetScroll method, refactor scrollToRight and some cleaning

* check initial status

* remove logs

* Styling for imagery thumbs 'autoscroll resume' button

- Refined look and feel of the approach;
- CSS classes now assigned at the wrapper level;
- Markup changed to allow wrapping of scroll area and button;
- TODO: prevent a drag resize of the main view area from forcing
autoscroll to pause;

* Add tests for auto scroll

* add resize observer for thumb wrapper

* reset scroll bar position when window is resized

* Revert "upgrade to webpack5 (#3871)" (#3907) (#3908)

This reverts commit e1e0eeac56.

Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov>

* Check for getlimits api (#3910)

* add debounce and resizing observer to thumbwrapper

* handling resizing window and auto scroll

* 1.clean up comments and logs 2.make variable names more descriptive 3.add scroll to right for play button

* fix eslint formate issue

* update class name in test

* fix eslint format error

* remove a couple variables that were created but not used.

Co-authored-by: Henry Hsu <henry.hsu@nasa.gov>
Co-authored-by: Henry Hsu <hhsu0219@gmail.com>
Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov>
Co-authored-by: Jamie Vigliotta <jamie.j.vigliotta@nasa.gov>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-06-29 07:52:27 -07:00
da39fd0c70 Overlay fixes and improvements (#3901)
* Overlay-related fixes
- Prevent navigation when a folder's grid or list view is displayed in
an overlay;

* Overlay-related fixes
- Get rid of theme-based special overlay coloring that was making the
overlay hard to use;
- Add margin to `l-overlay-large` to make it clearer that user is in an
overlay when interacting with that view;
- Refinements to colors and layout in About screens;
2021-06-28 14:35:35 -07:00
96dd581a67 Timestrip plan Inspection (#3863)
* Stub in static HTML for Timestrip Activity Inspection
- Added static markup with placeholder values and display logic;
- Refined approach for Links;
* Refactor duration formatting
* Display activity name when it's available
* Don't use indices for keys
* Don't show properties with no labels
2021-06-28 10:04:54 -07:00
2a1e322230 adding link to discussions in readme to encourage users to showcase their use of Open MCT (#3933)
Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
2021-06-22 09:34:36 -07:00
300b98bd54 Disallow pan, zoom and pause/play controls in time strip view (#3936)
* Disallow pan and zoom when in time strip view

* Disable plot controls in time strip view
2021-06-22 09:25:12 -07:00
c946609d13 Added LGTM code quality badge (#3960)
We score an A, we should flaunt it! (We should also aim for A+).
2021-06-22 09:10:08 -07:00
7ca559fbe4 [Styles] add unit tests (#3557)
* unit tests for inspector styles feature
* add mock capability for local storage

Co-authored-by: Deep Tailor <deep.j.tailor@nasa.gov>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-06-22 06:50:49 -07:00
71392915c1 Mct3834 (#3962)
* remove redundant code

Co-authored-by: Henry Hsu <henry.hsu@nasa.gov>
2021-06-21 17:23:42 -07:00
2889e88a97 Styling for plot limits (#3917)
* Styling for plot limits and colors
* Updates to limit provider and css
* Change limits related CSS "*--upper" and "*--lower" to "*--upr" and
"*--lwr" for better parity with legacy naming;
* Refactor limit class to util
* Use new classes for sine wave generator for red-low and yellow-high
* Added modifier classes for right and below-aligned labels;
* Prevent label overlap of limits as much as possible
* Add border colors to limit labels for better visual ties to their lines
* Add documentation for limit level specification API change

Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-06-21 16:22:28 -07:00
d56d176aac Issue #3834 Reimplement New Tab action in vanilla JS (#3876)
* [Reimplement] create new action plugin for issue #3834

Co-authored-by mariuszr mariusz.rosinski@gmail.com
Co-authored-by: Henry Hsu <henryhsu@henrys-air.lan>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-06-21 16:11:31 -07:00
925518c83f [Notebooks] Don't save images on the object (#3792)
* Create and store image data into new domain object of type 'notebookSnapshotImage'
* Reduced thumbnail size to 30px
* Image migration script for old notebooks.
* Saves thumbnail image on notebook instead of new object.
2021-06-21 15:42:33 -07:00
fa5aceb7b3 Bind method to 'this' so that its listeners are correctly unbound on destroy (#3948)
* Bind method to 'this' so that its listener can work correctly
* Bind this for toggling subscriptions as well
2021-06-21 10:44:59 -07:00
6755ef4641 Support for remote mutation of Notebooks with Couch DB (#3887)
* Update notebook automatically when modified by another user
* Don't persist selected and default page and section IDs on notebook object
* Fixing object synchronization bugs
* Adding unit tests
* Synchronize notebooks AND plans
* Removed observeEnabled flag

Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
2021-06-21 10:25:17 -07:00
333e8b5583 [Testing] Resolve all promises (#3829)
* all promises in test specs should be returned

Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-06-18 16:06:15 -07:00
9d8a8b36d2 Move duplicate fixes (#3947)
* Changed text of form labels;
* Corrected case of "Location" in Duplicate action;
* changed from objects.mutate to objects.save for duplicate action name change
* handling cancel of move

Co-authored-by: charlesh88 <charles.f.hacskaylo@nasa.gov>
2021-06-17 14:04:47 -07:00
b484a4a959 Initial LighthouseCI Commit (#3906)
* Initial LighthouseCI Commit

Co-authored-by: unlikelyzero <jchill2@gmail.com>
Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
2021-06-16 11:37:37 -07:00
64e7c62d98 [Style] check if there is an element to style before applying style (#3950)
* check if there is an element to style

* add mmgis (external plugin) type to style exclusion list

* revert b919cf9 to be fixed properly

* reduce code
2021-06-15 16:03:23 -07:00
6483fe2402 Prepare master for Sprint 1.7.4 (#3925) 2021-06-07 11:37:49 -07:00
a123889d6a Pre release for Sprint 1.7.3 (#3924)
* Revert "upgrade to webpack5 (#3871)" (#3907) (#3908)
* [Navigation Tree] Fix composition on closed folders and scrolling for items NOT in tree (#3920)
* Update package.json version and version documentation to include tags for npmjs

Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov>
Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
2021-06-07 11:25:58 -07:00
a40867d544 Revert "upgrade to webpack5 (#3871)" (#3907)
This reverts commit e1e0eeac56.
2021-06-02 07:04:40 -07:00
dbed9262c0 Tree revert refactor (#3886)
* Reverts object tree to expand/collapse tree model
* Retains expanded/collapsed state 
* Adds collapse all feature
2021-06-01 15:47:21 -07:00
43ac66233e [Issue] remove FollowTimerAction, followIndicator and tests (#3855)
Co-authored-by: Henry Hsu <henryhsu@Henrys-MacBook-Air.local>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-05-28 16:06:09 -07:00
04e85c176a Update templates (#3904) 2021-05-28 14:55:36 -07:00
8274c23129 Plots limit lines (#3882) 2021-05-28 14:51:29 -07:00
5fafde5f23 Updates to recognize issue template config (#3902)
* issue template config

* Update PR Template

Co-authored-by: unlikelyzero <jchill2@gmail.com>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-05-28 14:16:56 -07:00
80a6e7f719 Fix erroneously checked in dev code (#3897)
Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
2021-05-28 13:22:11 -07:00
2c13aeecce Make legend configuration properties reactive (#3889)
Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov>
2021-05-28 13:13:57 -07:00
ac015c3e45 Updates to the sprint cycle and end of sprint release process (#3878)
* Updates to the sprint cycle and end of sprint release process

* Adds reviewer checklist item for labelling an issue as a bug

* Update Cycle doc with test process changes.

* Update static.md references, add Issue templates

* Updated criticality definition

Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
Co-authored-by: John Hill <jchill2.spam@gmail.com>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-05-28 12:24:14 -07:00
ae1a4bcc6a A change in the parent container's size for plots re-requests telemetry (#3890)
* Use resize obeserver to detect a change in the parent container's size for plots and re-request telemetry
2021-05-28 11:44:56 -07:00
e1e0eeac56 upgrade to webpack5 (#3871)
Upgrade to webpack 5
Changes dependencies to work with webpack 5 as well.
2021-05-27 15:16:03 -07:00
c90dfb2a1f Fix the browser back button in Open MCT (#3526)
Fixes Open MCT back button.

Co-authored-by: Joshi <simplyrender@gmail.com>
2021-05-26 17:00:36 -07:00
1dfa5e5b8c Prepare snapshot for sprint 1.7.3 (#3877)
Co-authored-by: John Hill <jchill2.spam@gmail.com>
2021-05-24 10:54:51 -07:00
99896b72ea Small typo (#3838)
Looks like there is a small typo: `this this object`.

Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
2021-05-21 15:57:53 -07:00
979ba77c8e Normalize "OK" to uppercase in all dialogs; (#3850)
Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
2021-05-21 15:38:29 -07:00
aebb5df611 Check that mutation happens only if model has changed (#3751)
* When a mutation is requested, the LegacyObjectAPIInterceptor triggers a second mutatation request - ensure that the model for this 2nd request has some diff from the current model before saving the object.

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-05-20 10:01:14 -07:00
605eeff9d7 Plots - remove legacy code (#3814)
* Remove Lecacy plot code
* Adds tests for plots inspector
* Set range max and min to undefined instead of 0
2021-05-20 09:08:50 -07:00
a83ee1f90f Allow context click on Imagery to invoke browser-level Save As... (#3857)
- `pointer-events: none` added to `c-compass` wrapper (which was
blocking the image from catching mouse events), and
`pointer-events: all` added to `c-direction-rose` element;
- Unit tested locally in main view and both types of layouts;
- Fixed indention spacing in file;
2021-05-18 14:42:18 -07:00
fe899cbcc8 New Time Conductor time input for real-time (#3409)
* Time Conductor Real Time input popup

Co-authored-by: Jamie Vigliotta <jamie.j.vigliotta@nasa.gov>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-05-12 11:54:10 -07:00
633bac2ed5 Sync time conductor with plots time range (#3843)
* Adds play and pause functionality for plots (not for legacy plots)

* Add time conductor sync gesture to actions. Also fix status css.

Co-authored-by: charlesh88 <charles.f.hacskaylo@nasa.gov>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-05-12 10:57:54 -07:00
dacec48aec Update condition sets in fixed timespan mode if the datum's timestamp is valid (#3852) 2021-05-11 19:25:56 -07:00
3ca133c782 Pass objectPath as property to LAD rows (#3870)
Includes some code cleanup
2021-05-11 18:58:17 -07:00
12416b8079 Dynamic sizing for compass rose based on image size (#3826)
* Dynamic sizing for compass rose based on image size

- Compass rose now sizes and positions proportionally to the containing
image, with min and max sizes;
- Refactored computed `compassDimensionsStyle` as
`sizedImageDimensions` for reusability;
- Tweaked sizing of compass ordinals text and North arrow for better
legibility;
- Minor tweaks to element positioning and opacity for better legibility;
- TODO: add unit tests;

* Fix linting and code style

- Fixed lint errors;
- Better variable names;

* Address comments from PR #3826 review:

- Renamed `compassRoseSizing` to `compassRoseSizingClasses` and fixed
function logic;
- Fixed line breaks for code style;
2021-05-11 12:07:44 -07:00
9920e67c83 Regex search tables (#2956)
Support regex searches in table columns

Co-authored-by: charlesh88 <charlesh88@gmail.com>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-05-05 17:50:14 -07:00
0e80a5b8a0 [NIRVSS] Encode imagery metadata into image file names (#3759)
* [NIRVSS] Encode imagery metadata into image file names

* added image name metadata to example.imagery plugin.

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-05-05 17:24:31 -07:00
05f9202fe4 Return promise correctly for get calls (#3862) 2021-05-05 15:23:49 -07:00
0da35a44b0 Plots inspector using Vue (#3781) 2021-05-03 12:33:19 -07:00
2305cd2e49 Check if an object is mutable before destroying the mutable (#3825) 2021-04-22 15:33:08 -07:00
b30b6bc94e [Conductor] Add durations to history (#3820)
* added durations to conductor history

* removing commented out moment import

* removing unneccary const

* little change

* reusing code

* addressing pr comments, change 24 hours to one day :) and some formatting issues

* better formatting and deduping

* name change

Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
2021-04-22 06:38:20 -07:00
564f254652 Implement Couch Search and Request Batching (#3798)
* Implemented search in couch provider

* Promises, not await

* Batch requests

* Only batch if > 1

* Remove legacy Couch adapter

* Cleaned up couch request batching code

* Added test cases

* Code cleanup

* Changes to new and legacy objects API to remove redundant persists due to mutation of modified and persisted timestamps

* Cleaned up couch unit tests

Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
2021-04-22 06:29:28 -07:00
9fa71244ea [#3789] Destroy mutable objects only if needed (#3799)
* [#3789] Don't observe objects if they are already mutable objects. Add some null checks.
* Don't destroy mutable in Selection.js if it wasn't created in that context.
* Remove * listeners and add null checks
* Don't delete _observers and _globalEventEmitters on $destroy. Pop all items off the _observers list for a mutable domain object.

Co-authored-by: Andrew Henry <akhenry@gmail.com>
2021-04-20 16:47:36 -07:00
8157cdc7e9 Fix importing from JSON file where some property values are null (#3813) 2021-04-20 15:50:29 -07:00
721bdd737a [VIPEROMCT-41] When new telemetry data arrives, don't evaluate criteria that are defined for a different telemtry endpoint. (#3797) 2021-04-20 14:51:44 -07:00
1b57999059 [TextHighlight] Fixed, "not updating when text string changes" (#3796)
Co-authored-by: David Tsay <3614296+davetsay@users.noreply.github.com>
2021-04-09 12:38:59 -07:00
b7460cef41 Update master to snapshot version of next sprint (#3786) 2021-04-08 12:55:17 -07:00
46f7f6dd04 [Notebook] Fixing pages with no entries breaking search (#3791)
* also added result count to search results
2021-04-06 17:17:38 -07:00
569 changed files with 24137 additions and 21867 deletions

View File

@ -1,36 +1,113 @@
version: 2
jobs:
build:
version: 2.1
executors:
linux:
docker:
- image: circleci/node:13-browsers
environment:
CHROME_BIN: "/usr/bin/google-chrome"
- image: cimg/base:stable
orbs:
node: circleci/node@4.5.1
browser-tools: circleci/browser-tools@1.1.3
jobs:
npm-audit:
executor: linux
steps:
- checkout
- run:
name: Update npm
command: 'sudo npm install -g npm@latest'
- restore_cache:
key: dependency-cache-{{ checksum "package.json" }}
- run:
name: Installing dependencies (npm install)
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package.json" }}
paths:
- node_modules
- run:
name: npm run test:coverage
command: npm run test:coverage
- run:
name: npm run lint
command: npm run lint
- store_artifacts:
path: dist
prefix: dist
workflows:
version: 2
- checkout
- node/install:
install-npm: true
node-version: lts/fermium
- run: npm install
- run: npm audit --audit-level=low
test:
parameters:
node-version:
type: string
browser:
type: string
executor: linux
steps:
- checkout
- restore_cache:
key: deps-{{ .Branch }}--<< parameters.node-version >>--{{ checksum "package.json" }}
- node/install:
install-npm: false
node-version: << parameters.node-version >>
- run: npm install
- when:
condition:
equal: [ "FirefoxESR", <<parameters.browser>> ]
steps:
- browser-tools/install-firefox:
version: "91.2.0esr" #https://archive.mozilla.org/pub/firefox/releases/
- when:
condition:
equal: [ "FirefoxHeadless", <<parameters.browser>> ]
steps:
- browser-tools/install-firefox
- when:
condition:
equal: [ "ChromeHeadless", <<parameters.browser>> ]
steps:
- browser-tools/install-chrome:
replace-existing: false
- save_cache:
key: deps-{{ .Branch }}--<< parameters.node-version >>--{{ checksum "package.json" }}
paths:
- ~/.npm
- ~/.cache
- node_modules
- when:
condition:
equal: [ "", <<parameters.browser>> ] #Only run linting when browsers are not running to save time
steps:
- run: npm run lint
- when:
condition: << parameters.browser >> #Truthy evaluation to only run when browser is specified
steps:
- run: npm run test:coverage -- --browsers=<<parameters.browser>>
- store_test_results:
path: dist/reports/tests/
- store_artifacts:
path: dist/reports/
workflows:
matrix-tests:
jobs:
- build
- test:
post-steps:
- run:
command:
curl -Os https://uploader.codecov.io/latest/linux/codecov;chmod +x codecov;./codecov
name: node10-chrome
node-version: lts/dubnium
browser: ChromeHeadless
- test:
name: node12-build-lint
node-version: lts/erbium
browser: "" #Skip unit tests
- test:
name: node14-build-lint
node-version: lts/fermium
browser: "" #Skip unit tests
nightly:
jobs:
- test:
name: node10-chrome-nightly
node-version: lts/dubnium
browser: ChromeHeadless
- test:
name: node12-firefoxESR-nightly
node-version: lts/erbium
browser: FirefoxESR
- test:
name: node14-firefox-nightly
node-version: lts/fermium
browser: FirefoxHeadless
- npm-audit
triggers:
- schedule:
cron: "0 0 * * *"
filters:
branches:
only:
- master

44
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,44 @@
---
name: Bug report
about: File a Bug !
title: ''
labels: type:bug
assignees: ''
---
<!--- Focus on user impact in the title. Use the Summary Field to -->
<!--- describe the problem technically. -->
#### Summary
<!--- A description of the issue encountered. When possible, a description -->
<!--- of the impact of the issue. What use case does it impede?-->
#### Expected vs Current Behavior
<!--- Tell us what should have happened -->
#### Impact Check List
<!--- Please select from the following options -->
- [ ] Data loss or misrepresented data?
- [ ] Regression? Did this used to work or has it always been broken?
- [ ] Is there a workaround available?
- [ ] Does this impact a critical component?
- [ ] Is this just a visual bug?
#### Steps to Reproduce
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->
1.
2.
3.
4.
#### Environment
* Open MCT Version: <!--- date of build, version, or SHA -->
* Deployment Type: <!--- npm dev? VIPER Dev? openmct-yamcs? -->
* OS:
* Browser:
#### Additional Information
<!--- Include any screenshots, gifs, or logs which will expedite triage -->

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: Discussions
url: https://github.com/nasa/openmct/discussions
about: Have a question about the project?

View File

@ -0,0 +1,20 @@
---
name: Enhancement request
about: Suggest an enhancement or new improvement for this project
title: ''
labels: type:enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -0,0 +1,11 @@
---
name: Maintenance
about: Add, update or remove documentation, tests, or dependencies.
title: ''
labels: type:maintenance
assignees: ''
---
#### Summary
<!--- Generally describe the purpose of the change. -->

13
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,13 @@
### All Submissions:
* [ ] Have you followed the guidelines in our [Contributing document](https://github.com/nasa/openmct/blob/master/CONTRIBUTING.md)?
* [ ] Have you checked to ensure there aren't other open [Pull Requests](https://github.com/nasa/openmct/pulls) for the same update/change?
* [ ] Is this change backwards compatible? For example, developers won't need to change how they are calling the API or how they've extended core plugins such as Tables or Plots.
### Author Checklist
* [ ] Changes address original issue?
* [ ] Unit tests included and/or updated with changes?
* [ ] Command line build passes?
* [ ] Has this been smoke tested?
* [ ] Testing instructions included in associated issue?

23
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,23 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 2
labels:
- "type:maintenance"
- "dependencies"
allow:
- dependency-name: "eslint*"
- dependency-name: "karma*"
- dependency-name: "jasmine*"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
labels:
- "type:maintenance"
- "dependencies"

41
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
paths-ignore:
- '**/*Spec.js'
- '**/*.md'
- '**/*.txt'
- '**/*.yml'
- '**/*.yaml'
schedule:
- cron: '28 21 * * 3'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: javascript
- name: Autobuild
uses: github/codeql-action/autobuild@v1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

20
.github/workflows/lighthouse.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: lighthouse
on:
workflow_dispatch:
inputs:
version:
description: 'Which branch do you want to test?' # Limited to branch for now
required: false
default: 'master'
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.version }}
- uses: actions/setup-node@v2
with:
node-version: '14'
- run: npm install && npm install -g @lhci/cli #Don't want to include this in our deps
- run: lhci autorun

6
.gitignore vendored
View File

@ -40,4 +40,10 @@ npm-debug.log
# karma reports
report.*.json
# Lighthouse reports
.lighthouseci
package-lock.json
#codecov artifacts
codecov

1
.npmrc Normal file
View File

@ -0,0 +1 @@
loglevel=warn

19
API.md
View File

@ -423,13 +423,14 @@ 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 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:
* `domain`: Values with a `domain` hint will be used for the x-axis of a plot, and tables will render columns for these values first.
* `range`: Values with a `range` hint will be used as the y-axis on a plot, and tables will render columns for these values after the `domain` values.
* `image`: Indicates that the value may be interpreted as the URL to an image file, in which case appropriate views will be made available.
* `imageDownloadName`: Indicates that the value may be interpreted as the name of the image file.
##### The Time Conductor and Telemetry
@ -594,9 +595,17 @@ section.
#### Limit Evaluators **draft**
Limit evaluators allow a telemetry integrator to define how limits should be
applied to telemetry from a given domain object. For an example of a limit
evaluator, take a look at `examples/generator/SinewaveLimitProvider.js`.
Limit evaluators allow a telemetry integrator to define which limits exist for a
telemetry endpoint and how limits should be applied to telemetry from a given domain object.
A limit evaluator can implement the `evalute` method which is used to define how limits
should be applied to telemetry and the `getLimits` method which is used to specify
what the limit values are for different limit levels.
Limit levels can be mapped to one of 5 colors for visualization:
`purple`, `red`, `orange`, `yellow` and `cyan`.
For an example of a limit evaluator, take a look at `examples/generator/SinewaveLimitProvider.js`.
### Telemetry Consumer APIs **draft**
@ -987,7 +996,7 @@ reveal additional information when the mouse cursor is hovered over it.
A common use case for indicators is to convey the state of some external system such as a
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
returning a 2xx status code. The URL Status Indicator is made available as a default plugin. See
the [documentation](./src/plugins/URLIndicatorPlugin) for details on how to install and configure the
URL Status Indicator.

View File

@ -10,7 +10,7 @@ accept changes from external contributors.
The short version:
1. Write your contribution.
1. Write your contribution or describe your idea in the form of an [GitHub issue](https://github.com/nasa/openmct/issues/new/choose) or [Starting a GitHub Discussion](https://github.com/nasa/openmct/discussions)
2. Make sure your contribution meets code, test, and commit message
standards as described below.
3. Submit a pull request from a topic branch back to `master`. Include a check
@ -18,6 +18,7 @@ The short version:
for review.)
4. Respond to any discussion. When the reviewer decides it's ready, they
will merge back `master` and fill out their own check list.
5. If you are a first-time contributor, please see [this discussion](https://github.com/nasa/openmct/discussions/3821) for further information.
## Contribution Process
@ -115,7 +116,7 @@ the pull request containing the reviewer checklist (from below) and complete
the merge back to the master branch.
Additionally:
* Every pull request must link to the issue that it addresses. Eg. “Addresses #1234” or “Closes #1234”. This is the responsibility of the pull requests __author__. If no issue exists, create one.
* Every pull request must link to the issue that it addresses. Eg. “Addresses #1234” or “Closes #1234”. This is the responsibility of the pull requests __author__. If no issue exists, [create one](https://github.com/nasa/openmct/issues/new/choose).
* Every __author__ must include testing instructions. These instructions should identify the areas of code affected, and some minimal test steps. If addressing a bug, reproduction steps should be included, if they were not included in the original issue. If reproduction steps were included on the original issue, and are sufficient, refer to them.
* A pull request that closes an issue should say so in the description. Including the text “Closes #1234” will cause the linked issue to be automatically closed when the pull request is merged. This is the responsibility of the pull requests __author__.
* When a pull request is merged, and the corresponding issue closed, the __reviewer__ must add the tag “unverified” to the original issue. This will indicate that although the issue is closed, it has not been tested yet.
@ -296,23 +297,12 @@ these standards.
Issues are tracked at https://github.com/nasa/openmct/issues.
Issues should include:
* A short description of the issue encountered.
* A longer-form description of the issue encountered. When possible, steps to
reproduce the issue.
* When possible, a description of the impact of the issue. What use case does
it impede?
* An assessment of the severity of the issue.
Issue severity is categorized as follows (in ascending order):
* _Trivial_: Minimal impact on the usefulness and functionality of the
software; a "nice-to-have."
* _(Unspecified)_: Major loss of functionality or impairment of use.
* _Critical_: Large-scale loss of functionality or impairment of use,
such that remaining utility becomes marginal.
* _Blocker_: Harmful or otherwise unacceptable behavior. Must fix.
* _Trivial_: Minimal impact on the usefulness and functionality of the software; a "nice-to-have." Visual impact without functional impact,
* _Medium_: Some impairment of use, but simple workarounds exist
* _Critical_: Significant loss of functionality or impairment of use. Display of telemetry data is not affected though.
* _Blocker_: Major functionality is impaired or lost, threatening mission success. Display of telemetry data is impaired or blocked by the bug, which could lead to loss of situational awareness.
## Check Lists
@ -322,16 +312,20 @@ checklist).
### Author Checklist
1. Changes address original issue?
2. Unit tests included and/or updated with changes?
3. Command line build passes?
4. Changes have been smoke-tested?
5. Testing instructions included?
[Within PR Template](.github/PULL_REQUEST_TEMPLATE.md)
### Reviewer Checklist
1. Changes appear to address issue?
2. Appropriate unit tests included?
3. Code style and in-line documentation are appropriate?
4. Commit messages meet standards?
5. Has associated issue been labelled `unverified`? (only applicable if this PR closes the issue)
* [ ] Changes appear to address issue?
* [ ] Changes appear not to be breaking changes?
* [ ] Appropriate unit tests included?
* [ ] Code style and in-line documentation are appropriate?
* [ ] Commit messages meet standards?
* [ ] Has associated issue been labelled `unverified`? (only applicable if this PR closes the issue)
* [ ] Has associated issue been labelled `bug`? (only applicable if this PR is for a bug fix)
* [ ] List of Acceptance Tests Performed.
Write out a small list of tests performed with just enough detail for another developer on the team
to execute.
i.e. ```When Clicking on Add button, new `object` appears in dropdown.```

View File

@ -1,9 +1,11 @@
# Open MCT [![license](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0)
# Open MCT [![license](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0) [![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/nasa/openmct.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/nasa/openmct/context:javascript) [![codecov](https://codecov.io/gh/nasa/openmct/branch/master/graph/badge.svg?token=7DQIipp3ej)](https://codecov.io/gh/nasa/openmct)
Open MCT (Open Mission Control Technologies) is a next-generation mission control framework for visualization of data on desktop and mobile devices. It is developed at NASA's Ames Research Center, and is being used by NASA for data analysis of spacecraft missions, as well as planning and operation of experimental rover systems. As a generalizable and open source framework, Open MCT could be used as the basis for building applications for planning, operation, and analysis of any systems producing telemetry data.
Please visit our [Official Site](https://nasa.github.io/openmct/) and [Getting Started Guide](https://nasa.github.io/openmct/getting-started/)
Once you've created something amazing with Open MCT, showcase your work in our GitHub Discussions [Show and Tell](https://github.com/nasa/openmct/discussions/categories/show-and-tell) section. We love seeing unique and wonderful implementations of Open MCT!
## See Open MCT in Action
Try Open MCT now with our [live demo](https://openmct-demo.herokuapp.com/).
@ -44,7 +46,7 @@ The clearest examples for developing Open MCT plugins are in the
our documentation.
We want Open MCT to be as easy to use, install, run, and develop for as
possible, and your feedback will help us get there! Feedback can be provided via [GitHub issues](https://github.com/nasa/openmct/issues), or by emailing us at [arc-dl-openmct@mail.nasa.gov](mailto:arc-dl-openmct@mail.nasa.gov).
possible, and your feedback will help us get there! Feedback can be provided via [GitHub issues](https://github.com/nasa/openmct/issues/new/choose), [Starting a GitHub Discussion](https://github.com/nasa/openmct/discussions), or by emailing us at [arc-dl-openmct@mail.nasa.gov](mailto:arc-dl-openmct@mail.nasa.gov).
## Building Applications With Open MCT
@ -83,6 +85,8 @@ naming convention is otherwise the same.)
When `npm test` is run, test results will be written as HTML to
`dist/reports/tests/`. Code coverage information is written to `dist/reports/coverage`.
Code Coverage Reports are available from [codecov.io](https://app.codecov.io/gh/nasa/openmct/)
# Glossary
Certain terms are used throughout Open MCT with consistent meanings

31
SECURITY.md Normal file
View File

@ -0,0 +1,31 @@
# Security Policy
The Open MCT team secures our code base using a combination of code review, dependency review, and periodic security reviews. Static analysis performed during automated verification additionally safeguards against common coding errors which may result in vulnerabilities.
### Reporting a Vulnerability
For general defects, please for a [Bug Report](https://github.com/nasa/openmct/issues/new/choose)
To report a vulnerability for Open MCT please send a detailed report to [arc-dl-openmct](mailto:arc-dl-openmct@mail.nasa.gov).
See our [top-level security policy](https://github.com/nasa/openmct/security/policy) for additional information.
### CodeQL and LGTM
The [CodeQL GitHub Actions workflow](https://github.com/nasa/openmct/blob/master/.github/workflows/codeql-analysis.yml) is available to the public. To review the results, fork the repository and run the CodeQL workflow.
CodeQL is run for every pull-request in GitHub Actions.
The project is also monitored by [LGTM](https://lgtm.com/projects/g/nasa/openmct/) and is available to public.
### ESLint
Static analysis is run for every push on the master branch and every pull request on all branches in Github Actions.
For more information about ESLint, visit https://eslint.org/.
### General Support
For additional support, please open a [Github Discussion](https://github.com/nasa/openmct/discussions).
If you wish to report a cybersecurity incident or concern, please contact the NASA Security Operations Center either by phone at 1-877-627-2732 or via email address soc@nasa.gov.

27
codecov.yml Normal file
View File

@ -0,0 +1,27 @@
codecov:
require_ci_to_pass: false #This setting will update the bot regardless of whether or not tests pass
coverage:
status:
project:
default:
informational: true
patch:
default:
informational: true
precision: 2
round: down
range: "66...100"
parsers:
gcov:
branch_detection:
conditional: true
loop: true
method: false
macro: false
comment:
layout: "reach,diff,flags,files,footer"
behavior: default
require_changes: false

View File

@ -423,7 +423,7 @@ which can help with this, however.
instead of separate approaches for static and substitutable
dependencies.
* Removes need to understand Angular's DI mechanism.
* Improves useability of documentation (`typeService` is an
* Improves usability of documentation (`typeService` is an
instance of `CompositeService` and implements `TypeService`
so you can easily traverse links in the JSDoc.)
* Can be used more easily from Web Workers, allowing services

View File

@ -25,7 +25,7 @@
## Legacy Documentation
As we transition to a new API, the following documentation for the old API
(which is supported during the transtion) may be useful as well:
(which is supported during the transition) may be useful as well:
* The [Architecture Overview](architecture/) describes the concepts used
throughout Open MCT, and gives a high level overview of the platform's design.

View File

@ -73,11 +73,11 @@ acceptance testing (e.g. by resolving any blockers found); any
resources not needed for this effort should be used to begin work
for the subsequent sprint.
| Week | Mon | Tue | Wed | Thu | Fri |
|:-----:|:-------------------------:|:------:|:---:|:----------------------------:|:-----------:|
| __1__ | Sprint plan | Tag-up | | | |
| __2__ | | Tag-up | | | Code freeze |
| __3__ | Per-sprint testing | Triage | | _Per-sprint testing*_ | Ship |
| Week | Mon | Tue | Wed | Thu | Fri |
|:-----:|:-------------------------:|:------:|:---:|:----------------------------:|:-------------------------------------:|
| __1__ | Sprint plan | Tag-up | | | |
| __2__ | | Tag-up | | | Code freeze and sprint branch |
| __3__ | Per-sprint testing | Triage | | _Per-sprint testing*_ | Ship and merge sprint branch to master|
&ast; If necessary.
@ -105,14 +105,20 @@ emphasis on testing.
that team may begin work for that sprint during the
third week, since testing and blocker resolution is unlikely
to require all available resources.
* Testing success criteria identified per issue (where necessary). This could be in the form of acceptance tests on the issue or detailing performance tests, for example.
* __Tag-up.__ Check in and status update among development team.
May amend plan for sprint as-needed.
* __Code freeze.__ Any new work from this sprint
(features, bug fixes, enhancements) must be integrated by the
end of the second week of the sprint. After code freeze
(and until the end of the sprint) the only changes that should be
merged into the master branch should directly address issues
needed to pass acceptance testing.
end of the second week of the sprint. After code freeze, a sprint
branch will be created (and until the end of the sprint) the only
changes that should be merged into the sprint branch should
directly address issues needed to pass acceptance testing.
During this time, any other feature development will continue to
be merged into the master branch for the next sprint.
* __Sprint branch merge to master.__ After acceptance testing, the sprint branch
will be merged back to the master branch. Any code conflicts that
arise will be resolved by the team.
* [__Per-release Testing.__](testing/plan.md#per-release-testing)
Structured testing with predefined
success criteria. No release should ship without passing
@ -126,8 +132,8 @@ emphasis on testing.
* [__Testathon.__](testing/plan.md#user-testing)
Multi-user testing, involving as many users as
is feasible, plus development team. Open-ended; should verify
completed work from this sprint, test exploratorily for
regressions, et cetera.
completed work from this sprint using the sprint branch, test
exploratorily for regressions, et cetera.
* [__Long-Duration Test.__](testing/plan.md#long-duration-testing) A
test to verify that the software remains
stable after running for longer durations. May include some
@ -143,7 +149,7 @@ emphasis on testing.
Subset of Pre-release Testing
which should be performed before shipping at the end of any
sprint. Time is allocated for a second round of
Pre-release Testing if the first round is not passed.
Pre-release Testing if the first round is not passed. Smoke tests collected from issues/PRs
* __Triage.__ Team reviews issues from acceptance testing and uses
success criteria to determine whether or not they should block
release, then formulates a plan to address these issues before

View File

@ -19,7 +19,7 @@ Testing for Open MCT includes:
Manual, non-rigorous testing of the software and/or specific features
of interest. Verifies that the software runs and that basic functionality
is present.
is present. The outcome of Smoke Testing should be a simplified list of Acceptance Tests which could be executed by another team member with sufficient context.
### Unit Testing
@ -49,7 +49,7 @@ User testing will focus on the following activities:
* General "trying to break things."
During user testing, users will
[report issues](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
[report issues](https://github.com/nasa/openmct/issues/new/choose)
as they are encountered.
Desired outcomes of user testing are:
@ -71,7 +71,7 @@ usage. After twenty-four hours, the software is evaluated for:
at the start of the test? Is it as responsive?
Any defects or unexpected behavior identified during testing should be
[reported as issues](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
[reported as issues](https://github.com/nasa/openmct/issues/new/choose)
and reviewed for severity.
## Test Performance

View File

@ -92,8 +92,8 @@ should update (or delegate the task of updating) Open MCT version
numbers by the following process:
1. Update version number in `package.json`
1. Create a new branch off the `master` branch.
2. Remove `-SNAPSHOT` suffix from the version in `package.json`.
1. Checkout branch created for the last sprint that has been successfully tested.
2. Remove a `-SNAPSHOT` suffix from the version in `package.json`.
3. Verify that resulting version number meets semantic versioning
requirements relative to previous stable version. Increment the
version number if necessary.
@ -131,7 +131,8 @@ numbers by the following process:
3. In `package.json` change package to be public (private: false)
4. Test the package before publishing by doing `npm publish --dry-run`
if necessary.
5. Publish the package to the npmjs registry (e.g. `npm publish --access public`)
5. Publish the package to the npmjs registry (e.g. `npm publish --access public`)
NOTE: Use the `--tag unstable` flag to the npm publishj if this is a prerelease.
6. Confirm the package has been published (e.g. `https://www.npmjs.com/package/openmct`)
5. Update snapshot status in `package.json`
1. Create a new branch off the `master` branch.

View File

@ -28,6 +28,15 @@ define([
domain: 2
}
},
{
key: "cos",
name: "Cosine",
unit: "deg",
formatString: '%0.2f',
hints: {
domain: 3
}
},
// Need to enable "LocalTimeSystem" plugin to make use of this
// {
// key: "local",

View File

@ -26,14 +26,26 @@ define([
) {
var RED = {
var PURPLE = {
sin: 2.2,
cos: 2.2
},
RED = {
sin: 0.9,
cos: 0.9
},
ORANGE = {
sin: 0.7,
cos: 0.7
},
YELLOW = {
sin: 0.5,
cos: 0.5
},
CYAN = {
sin: 0.45,
cos: 0.45
},
LIMITS = {
rh: {
cssClass: "is-limit--upr is-limit--red",
@ -93,5 +105,70 @@ define([
};
};
SinewaveLimitProvider.prototype.getLimits = function (domainObject) {
return {
limits: function () {
return Promise.resolve({
WATCH: {
low: {
color: "cyan",
sin: -CYAN.sin,
cos: -CYAN.cos
},
high: {
color: "cyan",
...CYAN
}
},
WARNING: {
low: {
color: "yellow",
sin: -YELLOW.sin,
cos: -YELLOW.cos
},
high: {
color: "yellow",
...YELLOW
}
},
DISTRESS: {
low: {
color: "orange",
sin: -ORANGE.sin,
cos: -ORANGE.cos
},
high: {
color: "orange",
...ORANGE
}
},
CRITICAL: {
low: {
color: "red",
sin: -RED.sin,
cos: -RED.cos
},
high: {
color: "red",
...RED
}
},
SEVERE: {
low: {
color: "purple",
sin: -PURPLE.sin,
cos: -PURPLE.cos
},
high: {
color: "purple",
...PURPLE
}
}
});
}
};
};
return SinewaveLimitProvider;
});

View File

@ -63,7 +63,7 @@ define([
StateGeneratorProvider.prototype.request = function (domainObject, options) {
var start = options.start;
var end = options.end;
var end = Math.min(Date.now(), options.end); // no future values
var duration = domainObject.telemetry.duration * 1000;
if (options.strategy === 'latest' || options.size === 1) {
start = end;

View File

@ -54,23 +54,38 @@
var start = Date.now();
var step = 1000 / data.dataRateInHz;
var nextStep = start - (start % step) + step;
let work;
if (data.spectra) {
work = function (now) {
while (nextStep < now) {
const messageCopy = Object.create(message);
message.data.start = nextStep - (60 * 1000);
message.data.end = nextStep;
onRequest(messageCopy);
nextStep += step;
}
function work(now) {
while (nextStep < now) {
self.postMessage({
id: message.id,
data: {
name: data.name,
utc: nextStep,
yesterday: nextStep - 60 * 60 * 24 * 1000,
sin: sin(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness),
cos: cos(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness)
}
});
nextStep += step;
}
return nextStep;
};
} else {
work = function (now) {
while (nextStep < now) {
self.postMessage({
id: message.id,
data: {
name: data.name,
utc: nextStep,
yesterday: nextStep - 60 * 60 * 24 * 1000,
sin: sin(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness),
wavelength: wavelength(start, nextStep),
cos: cos(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness)
}
});
nextStep += step;
}
return nextStep;
return nextStep;
};
}
subscriptions[message.id] = work;
@ -111,13 +126,21 @@
utc: nextStep,
yesterday: nextStep - 60 * 60 * 24 * 1000,
sin: sin(nextStep, period, amplitude, offset, phase, randomness),
wavelength: wavelength(start, nextStep),
cos: cos(nextStep, period, amplitude, offset, phase, randomness)
});
}
self.postMessage({
id: message.id,
data: data
data: request.spectra ? {
wavelength: data.map((item) => {
return item.wavelength;
}),
cos: data.map((item) => {
return item.cos;
})
} : data
});
}
@ -131,6 +154,10 @@
* Math.sin(phase + (timestamp / period / 1000 * Math.PI * 2)) + (amplitude * Math.random() * randomness) + offset;
}
function wavelength(start, nextStep) {
return (nextStep - start) / 10;
}
function sendError(error, message) {
self.postMessage({
error: error.name + ': ' + error.message,

View File

@ -20,136 +20,219 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
const DEFAULT_IMAGE_SAMPLES = [
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18731.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18732.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18733.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18734.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18735.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18736.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18737.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18738.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18739.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18740.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18741.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18742.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18743.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18744.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18745.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18746.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18747.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18748.jpg"
];
const DEFAULT_IMAGE_LOAD_DELAY_IN_MILISECONDS = 20000;
const MIN_IMAGE_LOAD_DELAY_IN_MILISECONDS = 5000;
], function (
let openmctInstance;
) {
function ImageryPlugin() {
const IMAGE_SAMPLES = [
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18731.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18732.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18733.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18734.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18735.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18736.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18737.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18738.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18739.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18740.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18741.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18742.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18743.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18744.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18745.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18746.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18747.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18748.jpg"
];
const IMAGE_DELAY = 20000;
function pointForTimestamp(timestamp, name) {
return {
name: name,
utc: Math.floor(timestamp / IMAGE_DELAY) * IMAGE_DELAY,
local: Math.floor(timestamp / IMAGE_DELAY) * IMAGE_DELAY,
url: IMAGE_SAMPLES[Math.floor(timestamp / IMAGE_DELAY) % IMAGE_SAMPLES.length]
};
}
var realtimeProvider = {
supportsSubscribe: function (domainObject) {
return domainObject.type === 'example.imagery';
},
subscribe: function (domainObject, callback) {
var interval = setInterval(function () {
callback(pointForTimestamp(Date.now(), domainObject.name));
}, IMAGE_DELAY);
return function () {
clearInterval(interval);
export default function () {
return function install(openmct) {
openmctInstance = openmct;
openmct.types.addType('example.imagery', {
key: 'example.imagery',
name: 'Example Imagery',
cssClass: 'icon-image',
description: 'For development use. Creates example imagery '
+ 'data that mimics a live imagery stream.',
creatable: true,
initialize: (object) => {
object.configuration = {
imageLocation: '',
imageLoadDelayInMilliSeconds: DEFAULT_IMAGE_LOAD_DELAY_IN_MILISECONDS,
imageSamples: []
};
}
};
var historicalProvider = {
supportsRequest: function (domainObject, options) {
return domainObject.type === 'example.imagery'
&& options.strategy !== 'latest';
},
request: function (domainObject, options) {
var start = options.start;
var end = Math.min(options.end, Date.now());
var data = [];
while (start <= end && data.length < IMAGE_DELAY) {
data.push(pointForTimestamp(start, domainObject.name));
start += IMAGE_DELAY;
}
return Promise.resolve(data);
}
};
var ladProvider = {
supportsRequest: function (domainObject, options) {
return domainObject.type === 'example.imagery'
&& options.strategy === 'latest';
},
request: function (domainObject, options) {
return Promise.resolve([pointForTimestamp(Date.now(), domainObject.name)]);
}
};
return function install(openmct) {
openmct.types.addType('example.imagery', {
key: 'example.imagery',
name: 'Example Imagery',
cssClass: 'icon-image',
description: 'For development use. Creates example imagery '
+ 'data that mimics a live imagery stream.',
creatable: true,
initialize: function (object) {
object.telemetry = {
values: [
{
name: 'Name',
key: 'name'
},
{
name: 'Time',
key: 'utc',
format: 'utc',
hints: {
domain: 2
}
},
{
name: 'Local Time',
key: 'local',
format: 'local-format',
hints: {
domain: 1
}
},
{
name: 'Image',
key: 'url',
format: 'image',
hints: {
image: 1
}
object.telemetry = {
values: [
{
name: 'Name',
key: 'name'
},
{
name: 'Time',
key: 'utc',
format: 'utc',
hints: {
domain: 2
}
]
};
},
{
name: 'Local Time',
key: 'local',
format: 'local-format',
hints: {
domain: 1
}
},
{
name: 'Image',
key: 'url',
format: 'image',
hints: {
image: 1
}
},
{
name: 'Image Download Name',
key: 'imageDownloadName',
format: 'imageDownloadName',
hints: {
imageDownloadName: 1
}
}
]
};
},
form: [
{
key: 'imageLocation',
name: 'Images url list (comma separated)',
control: 'textarea',
cssClass: 'l-inline',
property: [
"configuration",
"imageLocation"
]
},
{
key: 'imageLoadDelayInMilliSeconds',
name: 'Image load delay (milliseconds)',
control: 'numberfield',
required: true,
cssClass: 'l-inline',
property: [
"configuration",
"imageLoadDelayInMilliSeconds"
]
}
});
]
});
openmct.telemetry.addProvider(realtimeProvider);
openmct.telemetry.addProvider(historicalProvider);
openmct.telemetry.addProvider(ladProvider);
};
openmct.telemetry.addProvider(getRealtimeProvider());
openmct.telemetry.addProvider(getHistoricalProvider());
openmct.telemetry.addProvider(getLadProvider());
};
}
function getCompassValues(min, max) {
return min + Math.random() * (max - min);
}
function getImageSamples(configuration) {
let imageSamples = DEFAULT_IMAGE_SAMPLES;
if (configuration.imageLocation && configuration.imageLocation.length) {
imageSamples = getImageUrlListFromConfig(configuration);
}
return ImageryPlugin;
});
return imageSamples;
}
function getImageUrlListFromConfig(configuration) {
return configuration.imageLocation.split(',');
}
function getImageLoadDelay(domainObject) {
const imageLoadDelay = domainObject.configuration.imageLoadDelayInMilliSeconds;
if (!imageLoadDelay) {
openmctInstance.objects.mutate(domainObject, 'configuration.imageLoadDelayInMilliSeconds', DEFAULT_IMAGE_LOAD_DELAY_IN_MILISECONDS);
return DEFAULT_IMAGE_LOAD_DELAY_IN_MILISECONDS;
}
if (imageLoadDelay < MIN_IMAGE_LOAD_DELAY_IN_MILISECONDS) {
openmctInstance.objects.mutate(domainObject, 'configuration.imageLoadDelayInMilliSeconds', MIN_IMAGE_LOAD_DELAY_IN_MILISECONDS);
return MIN_IMAGE_LOAD_DELAY_IN_MILISECONDS;
}
return imageLoadDelay;
}
function getRealtimeProvider() {
return {
supportsSubscribe: domainObject => domainObject.type === 'example.imagery',
subscribe: (domainObject, callback) => {
const delay = getImageLoadDelay(domainObject);
const interval = setInterval(() => {
callback(pointForTimestamp(Date.now(), domainObject.name, getImageSamples(domainObject.configuration), delay));
}, delay);
return () => {
clearInterval(interval);
};
}
};
}
function getHistoricalProvider() {
return {
supportsRequest: (domainObject, options) => {
return domainObject.type === 'example.imagery'
&& options.strategy !== 'latest';
},
request: (domainObject, options) => {
const delay = getImageLoadDelay(domainObject);
let start = options.start;
const end = Math.min(options.end, Date.now());
const data = [];
while (start <= end && data.length < delay) {
data.push(pointForTimestamp(start, domainObject.name, getImageSamples(domainObject.configuration), delay));
start += delay;
}
return Promise.resolve(data);
}
};
}
function getLadProvider() {
return {
supportsRequest: (domainObject, options) => {
return domainObject.type === 'example.imagery'
&& options.strategy === 'latest';
},
request: (domainObject, options) => {
const delay = getImageLoadDelay(domainObject);
return Promise.resolve([pointForTimestamp(Date.now(), domainObject.name, delay)]);
}
};
}
function pointForTimestamp(timestamp, name, imageSamples, delay) {
const url = imageSamples[Math.floor(timestamp / delay) % imageSamples.length];
const urlItems = url.split('/');
const imageDownloadName = `example.imagery.${urlItems[urlItems.length - 1]}`;
return {
name,
utc: Math.floor(timestamp / delay) * delay,
local: Math.floor(timestamp / delay) * delay,
url,
sunOrientation: getCompassValues(0, 360),
cameraPan: getCompassValues(0, 360),
heading: getCompassValues(0, 360),
imageDownloadName
};
}

View File

@ -1,4 +1,4 @@
import Vue from 'Vue';
import Vue from 'vue';
import HelloWorld from './HelloWorld.vue';
function SimpleVuePlugin() {

View File

@ -152,7 +152,7 @@
<h2>How to Use Glyphs</h2>
<div class="cols cols1-1">
<div class="col">
<p>The easiest way to use a glyph is to include its CSS class in an element. The CSS adds a psuedo <code>:before</code> HTML element to whatever element it's attached to that makes proper use of the symbols font.</p>
<p>The easiest way to use a glyph is to include its CSS class in an element. The CSS adds a pseudo <code>:before</code> HTML element to whatever element it's attached to that makes proper use of the symbols font.</p>
<p>Alternately, you can use the <code>.ui-symbol</code> class in an object that contains encoded HTML entities. This method is only recommended if you cannot use the aforementioned CSS class approach.</p>
</div>
<mct-example><a class="s-button icon-gear" title="Settings"></a>

View File

@ -82,13 +82,14 @@
);
openmct.install(openmct.plugins.LocalStorage());
openmct.install(openmct.plugins.Espresso());
openmct.install(openmct.plugins.MyItems());
openmct.install(openmct.plugins.Generator());
openmct.install(openmct.plugins.ExampleImagery());
openmct.install(openmct.plugins.PlanLayout());
openmct.install(openmct.plugins.Timeline());
openmct.install(openmct.plugins.PlotVue());
openmct.install(openmct.plugins.Hyperlink());
openmct.install(openmct.plugins.UTCTimeSystem());
openmct.install(openmct.plugins.AutoflowView({
type: "telemetry.panel"
@ -195,6 +196,8 @@
['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked'],
{indicator: true}
));
openmct.install(openmct.plugins.Clock({ enableClockIndicator: true }));
openmct.install(openmct.plugins.Timer());
openmct.start();
</script>
</html>

View File

@ -23,9 +23,9 @@
/*global module,process*/
const devMode = process.env.NODE_ENV !== 'production';
const browsers = [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'FirefoxHeadless'];
const browsers = [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'ChromeHeadless'];
const coverageEnabled = process.env.COVERAGE === 'true';
const reporters = ['progress', 'html'];
const reporters = ['spec', 'junit'];
if (coverageEnabled) {
reporters.push('coverage-istanbul');
@ -59,7 +59,8 @@ module.exports = (config) => {
browsers: browsers,
client: {
jasmine: {
random: false
random: false,
timeoutInterval: 5000
}
},
customLaunchers: {
@ -67,29 +68,47 @@ module.exports = (config) => {
base: 'Chrome',
flags: ['--remote-debugging-port=9222'],
debug: true
},
FirefoxESR: {
base: 'FirefoxHeadless',
name: 'FirefoxESR'
}
},
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
// HTML test reporting.
htmlReporter: {
// htmlReporter: {
// outputDir: "dist/reports/tests",
// preserveDescribeNesting: true,
// foldAll: false
// },
junitReporter: {
outputDir: "dist/reports/tests",
preserveDescribeNesting: true,
foldAll: false
outputFile: "test-results.xml",
useBrowserName: false
},
coverageIstanbulReporter: {
fixWebpackSourcePaths: true,
dir: process.env.CIRCLE_ARTIFACTS ?
process.env.CIRCLE_ARTIFACTS + '/coverage' :
"dist/reports/coverage",
reports: ['html', 'lcovonly', 'text-summary'],
dir: process.env.CIRCLE_ARTIFACTS
? process.env.CIRCLE_ARTIFACTS + '/coverage'
: "dist/reports/coverage",
reports: ['lcovonly', 'text-summary'],
thresholds: {
global: {
lines: 66
}
}
},
specReporter: {
maxLogLines: 5,
suppressErrorSummary: true,
suppressFailed: false,
suppressPassed: false,
suppressSkipped: true,
showSpecTiming: true,
failFast: false
},
preprocessors: {
'indexTest.js': ['webpack', 'sourcemap']
},

96
lighthouserc.yml Normal file
View File

@ -0,0 +1,96 @@
---
ci:
collect:
urls:
- http://localhost/
numberOfRuns: 5
settings:
onlyCategories:
- performance
- best-practices
upload:
target: temporary-public-storage
assert:
preset: lighthouse:recommended
assertions:
### Applicable assertions
bootup-time:
- warn
- minScore: 0.88 #Original value was calculated at 0.88
dom-size:
- error
- maxNumericValue: 200 #Original value was calculated at 188
first-contentful-paint:
- error
- minScore: 0.07 #Original value was calculated at 0.08
mainthread-work-breakdown:
- warn
- minScore: 0.8 #Original value was calculated at 0.8
unused-javascript:
- warn
- maxLength: 1
- error
- maxNumericValue: 2000 #Original value was calculated at 1855
unused-css-rules: warn
installable-manifest: warn
service-worker: warn
### Disabled seo, accessibility, and pwa assertions, below
categories:seo: 'off'
categories:accessibility: 'off'
categories:pwa: 'off'
accesskeys: 'off'
apple-touch-icon: 'off'
aria-allowed-attr: 'off'
aria-command-name: 'off'
aria-hidden-body: 'off'
aria-hidden-focus: 'off'
aria-input-field-name: 'off'
aria-meter-name: 'off'
aria-progressbar-name: 'off'
aria-required-attr: 'off'
aria-required-children: 'off'
aria-required-parent: 'off'
aria-roles: 'off'
aria-toggle-field-name: 'off'
aria-tooltip-name: 'off'
aria-treeitem-name: 'off'
aria-valid-attr: 'off'
aria-valid-attr-value: 'off'
button-name: 'off'
bypass: 'off'
canonical: 'off'
color-contrast: 'off'
content-width: 'off'
crawlable-anchors: 'off'
csp-xss: 'off'
font-display: 'off'
font-size: 'off'
maskable-icon: 'off'
heading-order: 'off'
hreflang: 'off'
html-has-lang: 'off'
html-lang-valid: 'off'
http-status-code: 'off'
image-alt: 'off'
input-image-alt: 'off'
is-crawlable: 'off'
label: 'off'
link-name: 'off'
link-text: 'off'
list: 'off'
listitem: 'off'
meta-description: 'off'
meta-refresh: 'off'
meta-viewport: 'off'
object-alt: 'off'
plugins: 'off'
robots-txt: 'off'
splash-screen: 'off'
tabindex: 'off'
tap-targets: 'off'
td-headers-attr: 'off'
th-has-data-cells: 'off'
themed-omnibox: 'off'
valid-lang: 'off'
video-caption: 'off'
viewport: 'off'

View File

@ -1,9 +1,9 @@
{
"name": "openmct",
"version": "1.6.3-SNAPSHOT",
"version": "1.8.1-SNAPSHOT",
"description": "The Open MCT core platform",
"dependencies": {},
"devDependencies": {
"@braintree/sanitize-url": "^5.0.2",
"angular": ">=1.8.0",
"angular-route": "1.4.14",
"babel-eslint": "10.0.3",
@ -12,16 +12,9 @@
"copy-webpack-plugin": "^4.5.2",
"cross-env": "^6.0.3",
"css-loader": "^1.0.0",
"d3-array": "1.2.x",
"d3-axis": "1.0.x",
"d3-collection": "1.0.x",
"d3-color": "1.0.x",
"d3-format": "1.2.x",
"d3-interpolate": "1.1.x",
"d3-scale": "1.0.x",
"d3-selection": "1.3.x",
"d3-time": "1.0.x",
"d3-time-format": "2.1.x",
"eslint": "7.0.0",
"eslint-plugin-vue": "^7.5.0",
"eslint-plugin-you-dont-need-lodash-underscore": "^6.10.0",
@ -34,20 +27,21 @@
"git-rev-sync": "^1.4.0",
"glob": ">= 3.0.0",
"html-loader": "^0.5.5",
"html2canvas": "^1.0.0-alpha.12",
"html2canvas": "^1.0.0-rc.7",
"imports-loader": "^0.8.0",
"istanbul-instrumenter-loader": "^3.0.1",
"jasmine-core": "^3.1.0",
"jasmine-core": "^3.7.1",
"jsdoc": "^3.3.2",
"karma": "5.1.1",
"karma": "6.3.4",
"karma-chrome-launcher": "3.1.0",
"karma-firefox-launcher": "1.3.0",
"karma-cli": "2.0.0",
"karma-coverage": "2.0.3",
"karma-coverage-istanbul-reporter": "3.0.3",
"karma-html-reporter": "0.2.7",
"karma-jasmine": "3.3.1",
"karma-sourcemap-loader": "0.3.7",
"karma-firefox-launcher": "2.1.1",
"karma-jasmine": "4.0.1",
"karma-junit-reporter": "2.0.1",
"karma-sourcemap-loader": "0.3.8",
"karma-spec-reporter": "0.0.32",
"karma-webpack": "4.0.2",
"location-bar": "^3.0.1",
"lodash": "^4.17.12",
@ -60,7 +54,9 @@
"moment-timezone": "0.5.28",
"node-bourbon": "^4.2.3",
"node-sass": "^4.14.1",
"painterro": "^1.0.35",
"painterro": "^1.2.56",
"plotly.js-basic-dist": "^2.5.0",
"plotly.js-gl2d-dist": "^2.5.0",
"printj": "^1.2.1",
"raw-loader": "^0.5.1",
"request": "^2.69.0",
@ -69,6 +65,7 @@
"uuid": "^3.3.3",
"v8-compile-cache": "^1.1.0",
"vue": "2.5.6",
"vue-eslint-parser": "7.11.0",
"vue-loader": "^15.2.6",
"vue-template-compiler": "2.5.6",
"webpack": "^4.16.2",
@ -78,7 +75,8 @@
"zepto": "^1.2.0"
},
"scripts": {
"clean": "rm -rf ./dist",
"clean": "rm -rf ./dist /node_modules; rm package-lock.json",
"clean-test-lint": "npm run clean; npm install ; npm run test; npm run lint",
"start": "node app.js",
"lint": "eslint platform example src --ext .js,.vue openmct.js",
"lint:fix": "eslint platform example src --ext .js,.vue openmct.js --fix",
@ -88,6 +86,7 @@
"test": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run",
"test:debug": "cross-env NODE_ENV=debug karma start --no-single-run",
"test:coverage": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" COVERAGE=true karma start --single-run",
"test:coverage:firefox": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run --browsers=FirefoxHeadless",
"test:watch": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --no-single-run",
"verify": "concurrently 'npm:test' 'npm:lint'",
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",
@ -99,6 +98,9 @@
"type": "git",
"url": "https://github.com/nasa/openmct.git"
},
"engines": {
"node": ">=10.10.2 <16.0.0"
},
"author": "",
"license": "Apache-2.0",
"private": true

View File

@ -24,7 +24,6 @@ define([
"./src/navigation/NavigationService",
"./src/navigation/NavigateAction",
"./src/navigation/OrphanNavigationHandler",
"./src/windowing/NewTabAction",
"./res/templates/browse.html",
"./res/templates/browse-object.html",
"./res/templates/browse/object-header.html",
@ -37,7 +36,6 @@ define([
NavigationService,
NavigateAction,
OrphanNavigationHandler,
NewTabAction,
browseTemplate,
browseObjectTemplate,
objectHeaderTemplate,
@ -128,23 +126,6 @@ define([
"depends": [
"navigationService"
]
},
{
"key": "window",
"name": "Open In New Tab",
"implementation": NewTabAction,
"description": "Open in a new browser tab",
"category": [
"view-control",
"contextual"
],
"depends": [
"urlService",
"$window"
],
"group": "windowing",
"priority": 10,
"cssClass": "icon-new-window"
}
],
"runs": [

View File

@ -64,7 +64,7 @@ define(
*
* @param {DomainObject} domainObject the domain object to navigate to
* @param {Boolean} force if true, force navigation to occur.
* @returns {Boolean} true if navigation occured, otherwise false.
* @returns {Boolean} true if navigation occurred, otherwise false.
*/
NavigationService.prototype.setNavigation = function (domainObject, force) {
if (force) {

View File

@ -1,58 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
/**
* Module defining NewTabAction (Originally NewWindowAction). Created by vwoeltje on 11/18/14.
*/
define(
[],
function () {
/**
* The new tab action allows a domain object to be opened
* into a new browser tab.
* @memberof platform/commonUI/browse
* @constructor
* @implements {Action}
*/
function NewTabAction(urlService, $window, context) {
context = context || {};
this.urlService = urlService;
this.open = function () {
arguments[0] += "&hideTree=true&hideInspector=true";
$window.open.apply($window, arguments);
};
// Choose the object to be opened into a new tab
this.domainObject = context.selectedObject || context.domainObject;
}
NewTabAction.prototype.perform = function () {
this.open(
this.urlService.urlForNewTab("browse", this.domainObject),
"_blank"
);
};
return NewTabAction;
}
);

View File

@ -1,75 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/windowing/NewTabAction"],
function (NewTabAction) {
describe("The new tab action", function () {
var actionSelected,
actionCurrent,
mockWindow,
mockContextCurrent,
mockContextSelected,
mockUrlService;
beforeEach(function () {
mockWindow = jasmine.createSpyObj("$window", ["open", "location"]);
// Context if the current object is selected
// For example, when the top right new tab
// button is clicked, the user is using the
// current domainObject
mockContextCurrent = jasmine.createSpyObj("context", ["domainObject"]);
// Context if the selected object is selected
// For example, when an object in the left
// tree is opened in a new tab using the
// context menu
mockContextSelected = jasmine.createSpyObj("context", ["selectedObject",
"domainObject"]);
// Mocks the urlService used to make the new tab's url from a
// domainObject and mode
mockUrlService = jasmine.createSpyObj("urlService", ["urlForNewTab"]);
// Action done using the current context or mockContextCurrent
actionCurrent = new NewTabAction(mockUrlService, mockWindow,
mockContextCurrent);
// Action done using the selected context or mockContextSelected
actionSelected = new NewTabAction(mockUrlService, mockWindow,
mockContextSelected);
});
it("new tab with current url is opened", function () {
actionCurrent.perform();
});
it("new tab with a selected url is opened", function () {
actionSelected.perform();
});
});
}
);

View File

@ -34,9 +34,6 @@ define([
"./src/policies/EditPersistableObjectsPolicy",
"./src/representers/EditRepresenter",
"./src/capabilities/EditorCapability",
"./src/capabilities/TransactionCapabilityDecorator",
"./src/services/TransactionManager",
"./src/services/TransactionService",
"./src/creation/CreateMenuController",
"./src/creation/LocatorController",
"./src/creation/CreationPolicy",
@ -63,9 +60,6 @@ define([
EditPersistableObjectsPolicy,
EditRepresenter,
EditorCapability,
TransactionCapabilityDecorator,
TransactionManager,
TransactionService,
CreateMenuController,
LocatorController,
CreationPolicy,
@ -263,26 +257,6 @@ define([
}
],
"components": [
{
"type": "decorator",
"provides": "capabilityService",
"implementation": TransactionCapabilityDecorator,
"depends": [
"$q",
"transactionManager"
],
"priority": "fallback"
},
{
"type": "provider",
"provides": "transactionService",
"implementation": TransactionService,
"depends": [
"$q",
"$log",
"cacheService"
]
},
{
"key": "CreateActionProvider",
"provides": "actionService",
@ -320,7 +294,6 @@ define([
"description": "Provides transactional editing capabilities",
"implementation": EditorCapability,
"depends": [
"transactionService",
"openmct"
]
}
@ -331,15 +304,6 @@ define([
"template": locatorTemplate
}
],
"services": [
{
"key": "transactionManager",
"implementation": TransactionManager,
"depends": [
"transactionService"
]
}
],
"runs": [
{
depends: [

View File

@ -96,8 +96,7 @@ function (
SaveAsAction.prototype.save = function () {
var self = this,
domainObject = this.domainObject,
dialog = new SaveInProgressDialog(this.dialogService),
toUndirty = [];
dialog = new SaveInProgressDialog(this.dialogService);
function doWizardSave(parent) {
var wizard = self.createWizard(parent);
@ -132,11 +131,14 @@ function (
return fetchObject(object.getModel().location);
}
function saveObject(parent) {
return self.openmct.editor.save().then(() => {
// Force mutation for search indexing
return parent;
});
function saveObject(object) {
//persist the object, which adds it to the transaction and then call editor.save
return object.getCapability("persistence").persist()
.then(() => {
return self.openmct.editor.save().then(() => {
return object;
});
});
}
function addSavedObjectToParent(parent) {
@ -150,17 +152,6 @@ function (
});
}
function undirty(object) {
return object.getCapability('persistence').refresh();
}
function undirtyOriginals(object) {
return Promise.all(toUndirty.map(undirty))
.then(() => {
return object;
});
}
function indexForSearch(addedObject) {
addedObject.useCapability('mutation', (model) => {
return model;
@ -187,10 +178,9 @@ function (
return getParent(domainObject)
.then(doWizardSave)
.then(showBlockingDialog)
.then(getParent)
.then(saveObject)
.then(getParent)
.then(addSavedObjectToParent)
.then(undirtyOriginals)
.then((addedObject) => {
return fetchObject(addedObject.getId());
})

View File

@ -30,34 +30,17 @@ define(
* Once initiated, any persist operations will be queued pending a
* subsequent call to [.save()](@link #save) or [.finish()](@link
* #finish).
* @param transactionService
* @param domainObject
* @constructor
*/
function EditorCapability(
transactionService,
openmct,
domainObject
) {
this.transactionService = transactionService;
this.openmct = openmct;
this.domainObject = domainObject;
}
/**
* Initiate an editing session. This will start a transaction during
* which any persist operations will be deferred until either save()
* or finish() are called.
*/
EditorCapability.prototype.edit = function () {
console.warn('DEPRECATED: cannot edit via edit capability, use openmct.editor instead.');
if (!this.openmct.editor.isEditing()) {
this.openmct.editor.edit();
this.domainObject.getCapability('status').set('editing', true);
}
};
/**
* Determines whether this object, or any of its ancestors are
* currently being edited.
@ -76,38 +59,6 @@ define(
return this.openmct.editor.isEditing();
};
/**
* Save any unsaved changes from this editing session. This will
* end the current transaction and continue with a new one.
* @returns {*}
*/
EditorCapability.prototype.save = function () {
console.warn('DEPRECATED: cannot save via edit capability, use openmct.editor instead.');
return Promise.resolve();
};
EditorCapability.prototype.invoke = EditorCapability.prototype.edit;
/**
* Finish the current editing session. This will discard any pending
* persist operations
* @returns {*}
*/
EditorCapability.prototype.finish = function () {
console.warn('DEPRECATED: cannot finish via edit capability, use openmct.editor instead.');
return Promise.resolve();
};
/**
* @returns {boolean} true if there have been any domain model
* modifications since the last persist, false otherwise.
*/
EditorCapability.prototype.dirty = function () {
return this.transactionService.size() > 0;
};
return EditorCapability;
}
);

View File

@ -1,75 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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(
['./TransactionalPersistenceCapability'],
function (TransactionalPersistenceCapability) {
/**
* Wraps the [PersistenceCapability]{@link PersistenceCapability} with
* transactional capabilities.
* @param $q
* @param transactionService
* @param capabilityService
* @see TransactionalPersistenceCapability
* @constructor
*/
function TransactionCapabilityDecorator(
$q,
transactionService,
capabilityService
) {
this.capabilityService = capabilityService;
this.transactionService = transactionService;
this.$q = $q;
}
/**
* Decorate PersistenceCapability to queue persistence calls when a
* transaction is in progress.
*/
TransactionCapabilityDecorator.prototype.getCapabilities = function () {
var self = this,
capabilities = this.capabilityService.getCapabilities
.apply(this.capabilityService, arguments),
persistenceCapability = capabilities.persistence;
capabilities.persistence = function (domainObject) {
var original =
(typeof persistenceCapability === 'function')
? persistenceCapability(domainObject)
: persistenceCapability;
return new TransactionalPersistenceCapability(
self.$q,
self.transactionService,
original,
domainObject
);
};
return capabilities;
};
return TransactionCapabilityDecorator;
}
);

View File

@ -1,91 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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 () {
/**
* Wraps persistence capability to enable transactions. Transactions
* will cause persist calls not to be invoked immediately, but
* rather queued until [EditorCapability.save()]{@link EditorCapability#save}
* or [EditorCapability.cancel()]{@link EditorCapability#cancel} are
* called.
* @memberof platform/commonUI/edit/capabilities
* @param $q
* @param transactionManager
* @param persistenceCapability
* @param domainObject
* @constructor
*/
function TransactionalPersistenceCapability(
$q,
transactionManager,
persistenceCapability,
domainObject
) {
this.transactionManager = transactionManager;
this.persistenceCapability = persistenceCapability;
this.domainObject = domainObject;
this.$q = $q;
}
/**
* The wrapped persist function. If a transaction is active, persist
* will be queued until the transaction is committed or cancelled.
* @returns {*}
*/
TransactionalPersistenceCapability.prototype.persist = function () {
var wrappedPersistence = this.persistenceCapability;
if (this.transactionManager.isActive()) {
this.transactionManager.addToTransaction(
this.domainObject.getId(),
wrappedPersistence.persist.bind(wrappedPersistence),
wrappedPersistence.refresh.bind(wrappedPersistence)
);
//Need to return a promise from this function
return this.$q.when(true);
} else {
return this.persistenceCapability.persist();
}
};
TransactionalPersistenceCapability.prototype.refresh = function () {
this.transactionManager
.clearTransactionsFor(this.domainObject.getId());
return this.persistenceCapability.refresh();
};
TransactionalPersistenceCapability.prototype.getSpace = function () {
return this.persistenceCapability.getSpace();
};
TransactionalPersistenceCapability.prototype.persisted = function () {
return this.persistenceCapability.persisted();
};
return TransactionalPersistenceCapability;
}
);

View File

@ -86,11 +86,20 @@ define(
})
.join('/');
window.location.href = url;
function editObject() {
const path = objectPath.slice(-1).map(obj => {
const objNew = obj.getCapability('adapter').invoke();
if (isFirstViewEditable(object.useCapability('adapter'), objectPath)) {
openmct.editor.edit();
return objNew;
});
if (isFirstViewEditable(object.useCapability('adapter'), path)) {
openmct.editor.edit();
}
}
openmct.router.once('afterNavigation', editObject);
openmct.router.navigate(url);
}
newModel.type = this.type.getKey();

View File

@ -1,99 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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 () {
/**
* A Transaction represents a set of changes that are intended to
* be kept or discarded as a unit.
* @param $log Angular's `$log` service, for logging messages
* @constructor
* @memberof platform/commonUI/edit/services
*/
function Transaction($log) {
this.$log = $log;
this.callbacks = [];
}
/**
* Add a change to the current transaction, as expressed by functions
* to either keep or discard the change.
* @param {Function} commit called when the transaction is committed
* @param {Function} cancel called when the transaction is cancelled
* @returns {Function) a function which may be called to remove this
* pair of callbacks from the transaction
*/
Transaction.prototype.add = function (commit, cancel) {
var callback = {
commit: commit,
cancel: cancel
};
this.callbacks.push(callback);
return function () {
this.callbacks = this.callbacks.filter(function (c) {
return c !== callback;
});
}.bind(this);
};
/**
* Get the number of changes in the current transaction.
* @returns {number} the size of the current transaction
*/
Transaction.prototype.size = function () {
return this.callbacks.length;
};
/**
* Keep all changes associated with this transaction.
* @method {platform/commonUI/edit/services.Transaction#commit}
* @returns {Promise} a promise which will resolve when all callbacks
* have been handled.
*/
/**
* Discard all changes associated with this transaction.
* @method {platform/commonUI/edit/services.Transaction#cancel}
* @returns {Promise} a promise which will resolve when all callbacks
* have been handled.
*/
['commit', 'cancel'].forEach(function (method) {
Transaction.prototype[method] = function () {
var promises = [];
var callback;
while (this.callbacks.length > 0) {
callback = this.callbacks.shift();
try {
promises.push(callback[method]());
} catch (e) {
this.$log
.error("Error trying to " + method + " transaction.");
}
}
return Promise.all(promises);
};
});
return Transaction;
});

View File

@ -1,119 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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 () {
/**
* Manages transactions to support the TransactionalPersistenceCapability.
* This assumes that all commit/cancel callbacks for a given domain
* object are equivalent, and only need to be added once to any active
* transaction. Violating this assumption may cause unexpected behavior.
* @constructor
* @memberof platform/commonUI/edit
*/
function TransactionManager(transactionService) {
this.transactionService = transactionService;
this.clearTransactionFns = {};
}
/**
* Check if a transaction is currently active.
* @returns {boolean} true if there is a transaction active
*/
TransactionManager.prototype.isActive = function () {
return this.transactionService.isActive();
};
/**
* Check if callbacks associated with this domain object have already
* been added to the active transaction.
* @private
* @param {string} id the identifier of the domain object to check
* @returns {boolean} true if callbacks have been added
*/
TransactionManager.prototype.isScheduled = function (id) {
return Boolean(this.clearTransactionFns[id]);
};
/**
* Add callbacks associated with this domain object to the active
* transaction. Both callbacks are expected to return promises that
* resolve when their associated behavior is complete.
*
* If callbacks associated with this domain object have already been
* added to the active transaction, this call will be ignored.
*
* @param {string} id the identifier of the associated domain object
* @param {Function} onCommit behavior to invoke when committing transaction
* @param {Function} onCancel behavior to invoke when cancelling transaction
*/
TransactionManager.prototype.addToTransaction = function (
id,
onCommit,
onCancel
) {
var release = this.releaseClearFn.bind(this, id);
function chain(promiseFn, nextFn) {
return function () {
return promiseFn().then(nextFn);
};
}
/**
* Clear any existing persistence calls for object with given ID. This ensures only the most recent persistence
* call is executed. This should prevent stale objects being persisted and overwriting fresh ones.
*/
if (this.isScheduled(id)) {
this.clearTransactionsFor(id);
}
this.clearTransactionFns[id] =
this.transactionService.addToTransaction(
chain(onCommit, release),
chain(onCancel, release)
);
};
/**
* Remove any callbacks associated with this domain object from the
* active transaction.
* @param {string} id the identifier for the domain object
*/
TransactionManager.prototype.clearTransactionsFor = function (id) {
if (this.isScheduled(id)) {
this.clearTransactionFns[id]();
this.releaseClearFn(id);
}
};
/**
* Release the cached "remove from transaction" function that has been
* stored in association with this domain object.
* @param {string} id the identifier for the domain object
* @private
*/
TransactionManager.prototype.releaseClearFn = function (id) {
delete this.clearTransactionFns[id];
};
return TransactionManager;
});

View File

@ -1,138 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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(
['./Transaction', './NestedTransaction'],
function (Transaction, NestedTransaction) {
/**
* Implements an application-wide transaction state. Once a
* transaction is started, calls to
* [PersistenceCapability.persist()]{@link PersistenceCapability#persist}
* will be deferred until a subsequent call to
* [TransactionService.commit]{@link TransactionService#commit} is made.
*
* @memberof platform/commonUI/edit/services
* @param $q
* @constructor
*/
function TransactionService($q, $log, cacheService) {
this.$q = $q;
this.$log = $log;
this.cacheService = cacheService;
this.transactions = [];
}
/**
* Starts a transaction. While a transaction is active all calls to
* [PersistenceCapability.persist](@link PersistenceCapability#persist)
* will be queued until [commit]{@link #commit} or [cancel]{@link
* #cancel} are called
*/
TransactionService.prototype.startTransaction = function () {
var transaction = this.isActive()
? new NestedTransaction(this.transactions[0])
: new Transaction(this.$log);
this.transactions.push(transaction);
};
/**
* @returns {boolean} If true, indicates that a transaction is in progress
*/
TransactionService.prototype.isActive = function () {
return this.transactions.length > 0;
};
/**
* Adds provided functions to a queue to be called on
* [.commit()]{@link #commit} or
* [.cancel()]{@link #commit}
* @param onCommit A function to call on commit
* @param onCancel A function to call on cancel
*/
TransactionService.prototype.addToTransaction = function (onCommit, onCancel) {
if (this.isActive()) {
return this.activeTransaction().add(onCommit, onCancel);
} else {
//Log error because this is a programming error if it occurs.
this.$log.error("No transaction in progress");
}
};
/**
* Get the transaction at the top of the stack.
* @private
*/
TransactionService.prototype.activeTransaction = function () {
return this.transactions[this.transactions.length - 1];
};
/**
* All persist calls deferred since the beginning of the transaction
* will be committed. If this is the last transaction, clears the
* cache.
*
* @returns {Promise} resolved when all persist operations have
* completed. Will reject if any commit operations fail
*/
TransactionService.prototype.commit = function () {
var transaction = this.transactions.pop();
if (!transaction) {
return Promise.reject();
}
if (!this.isActive()) {
return transaction.commit()
.then(function (r) {
this.cacheService.flush();
return r;
}.bind(this));
}
return transaction.commit();
};
/**
* Cancel the current transaction, replacing any dirty objects from
* persistence. Not a true rollback, as it cannot be used to undo any
* persist calls that were successful in the event one of a batch of
* persists failing.
*
* @returns {*}
*/
TransactionService.prototype.cancel = function () {
var transaction = this.transactions.pop();
return transaction ? transaction.cancel() : Promise.reject();
};
/**
* Get the size (the number of commit/cancel callbacks) of
* the active transaction.
* @returns {number} size of the active transaction
*/
TransactionService.prototype.size = function () {
return this.isActive() ? this.activeTransaction().size() : 0;
};
return TransactionService;
});

View File

@ -1,192 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/capabilities/EditorCapability"],
function (EditorCapability) {
xdescribe("The editor capability", function () {
var mockDomainObject,
capabilities,
mockParentObject,
mockTransactionService,
mockStatusCapability,
mockParentStatus,
mockContextCapability,
capability;
function fastPromise(val) {
return {
then: function (callback) {
return callback(val);
}
};
}
beforeEach(function () {
mockDomainObject = jasmine.createSpyObj(
"domainObject",
["getId", "getModel", "hasCapability", "getCapability", "useCapability"]
);
mockParentObject = jasmine.createSpyObj(
"domainObject",
["getId", "getModel", "hasCapability", "getCapability", "useCapability"]
);
mockTransactionService = jasmine.createSpyObj(
"transactionService",
[
"startTransaction",
"size",
"commit",
"cancel"
]
);
mockTransactionService.commit.and.returnValue(fastPromise());
mockTransactionService.cancel.and.returnValue(fastPromise());
mockTransactionService.isActive = jasmine.createSpy('isActive');
mockStatusCapability = jasmine.createSpyObj(
"statusCapability",
["get", "set"]
);
mockParentStatus = jasmine.createSpyObj(
"statusCapability",
["get", "set"]
);
mockContextCapability = jasmine.createSpyObj(
"contextCapability",
["getParent"]
);
mockContextCapability.getParent.and.returnValue(mockParentObject);
capabilities = {
context: mockContextCapability,
status: mockStatusCapability
};
mockDomainObject.hasCapability.and.callFake(function (name) {
return capabilities[name] !== undefined;
});
mockDomainObject.getCapability.and.callFake(function (name) {
return capabilities[name];
});
mockParentObject.getCapability.and.returnValue(mockParentStatus);
mockParentObject.hasCapability.and.returnValue(false);
capability = new EditorCapability(
mockTransactionService,
mockDomainObject
);
});
it("starts a transaction when edit is invoked", function () {
capability.edit();
expect(mockTransactionService.startTransaction).toHaveBeenCalled();
});
it("sets editing status on object", function () {
capability.edit();
expect(mockStatusCapability.set).toHaveBeenCalledWith("editing", true);
});
it("uses editing status to determine editing context root", function () {
capability.edit();
mockStatusCapability.get.and.returnValue(false);
expect(capability.isEditContextRoot()).toBe(false);
mockStatusCapability.get.and.returnValue(true);
expect(capability.isEditContextRoot()).toBe(true);
});
it("inEditingContext returns true if parent object is being"
+ " edited", function () {
mockStatusCapability.get.and.returnValue(false);
mockParentStatus.get.and.returnValue(false);
expect(capability.inEditContext()).toBe(false);
mockParentStatus.get.and.returnValue(true);
expect(capability.inEditContext()).toBe(true);
});
describe("save", function () {
beforeEach(function () {
capability.edit();
capability.save();
});
it("commits the transaction", function () {
expect(mockTransactionService.commit).toHaveBeenCalled();
});
it("begins a new transaction", function () {
expect(mockTransactionService.startTransaction).toHaveBeenCalled();
});
});
describe("finish", function () {
beforeEach(function () {
mockTransactionService.isActive.and.returnValue(true);
capability.edit();
capability.finish();
});
it("cancels the transaction", function () {
expect(mockTransactionService.cancel).toHaveBeenCalled();
});
it("resets the edit state", function () {
expect(mockStatusCapability.set).toHaveBeenCalledWith('editing', false);
});
});
describe("finish", function () {
beforeEach(function () {
mockTransactionService.isActive.and.returnValue(false);
capability.edit();
});
it("does not cancel transaction when transaction is not active", function () {
capability.finish();
expect(mockTransactionService.cancel).not.toHaveBeenCalled();
});
it("returns a promise", function () {
expect(capability.finish() instanceof Promise).toBe(true);
});
});
describe("dirty", function () {
var model = {};
beforeEach(function () {
mockDomainObject.getModel.and.returnValue(model);
capability.edit();
capability.finish();
});
it("returns true if the object has been modified since it"
+ " was last persisted", function () {
mockTransactionService.size.and.returnValue(0);
expect(capability.dirty()).toBe(false);
mockTransactionService.size.and.returnValue(1);
expect(capability.dirty()).toBe(true);
});
});
});
}
);

View File

@ -1,54 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/capabilities/TransactionalPersistenceCapability",
"../../src/capabilities/TransactionCapabilityDecorator"
],
function (TransactionalPersistenceCapability, TransactionCapabilityDecorator) {
describe("The transaction capability decorator", function () {
var mockQ,
mockTransactionService,
mockCapabilityService,
provider;
beforeEach(function () {
mockQ = {};
mockTransactionService = {};
mockCapabilityService = jasmine.createSpyObj("capabilityService", ["getCapabilities"]);
mockCapabilityService.getCapabilities.and.returnValue({
persistence: function () {}
});
provider = new TransactionCapabilityDecorator(mockQ, mockTransactionService, mockCapabilityService);
});
it("decorates the persistence capability", function () {
var capabilities = provider.getCapabilities();
expect(capabilities.persistence({}) instanceof TransactionalPersistenceCapability).toBe(true);
});
});
}
);

View File

@ -1,111 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/capabilities/TransactionalPersistenceCapability"
],
function (TransactionalPersistenceCapability) {
function fastPromise(val) {
return {
then: function (callback) {
return callback(val);
}
};
}
describe("The transactional persistence decorator", function () {
var mockQ,
mockTransactionManager,
mockPersistence,
mockDomainObject,
testId,
capability;
beforeEach(function () {
testId = "test-id";
mockQ = jasmine.createSpyObj("$q", ["when"]);
mockQ.when.and.callFake(function (val) {
return fastPromise(val);
});
mockTransactionManager = jasmine.createSpyObj(
"transactionService",
["isActive", "addToTransaction", "clearTransactionsFor"]
);
mockPersistence = jasmine.createSpyObj(
"persistenceCapability",
["persist", "refresh", "getSpace"]
);
mockPersistence.persist.and.returnValue(fastPromise());
mockPersistence.refresh.and.returnValue(fastPromise());
mockDomainObject = jasmine.createSpyObj(
"domainObject",
["getModel", "getId"]
);
mockDomainObject.getModel.and.returnValue({persisted: 1});
mockDomainObject.getId.and.returnValue(testId);
capability = new TransactionalPersistenceCapability(
mockQ,
mockTransactionManager,
mockPersistence,
mockDomainObject
);
});
it("if no transaction is active, passes through to persistence"
+ " provider", function () {
mockTransactionManager.isActive.and.returnValue(false);
capability.persist();
expect(mockPersistence.persist).toHaveBeenCalled();
});
it("if transaction is active, persist and cancel calls are"
+ " queued", function () {
mockTransactionManager.isActive.and.returnValue(true);
capability.persist();
expect(mockTransactionManager.addToTransaction).toHaveBeenCalled();
mockTransactionManager.addToTransaction.calls.mostRecent().args[1]();
expect(mockPersistence.persist).toHaveBeenCalled();
mockTransactionManager.addToTransaction.calls.mostRecent().args[2]();
expect(mockPersistence.refresh).toHaveBeenCalled();
});
it("wraps getSpace", function () {
mockPersistence.getSpace.and.returnValue('foo');
expect(capability.getSpace()).toEqual('foo');
});
it("clears transactions and delegates refresh calls", function () {
capability.refresh();
expect(mockTransactionManager.clearTransactionsFor)
.toHaveBeenCalledWith(testId);
expect(mockPersistence.refresh)
.toHaveBeenCalled();
});
});
}
);

View File

@ -1,75 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/services/NestedTransaction"], function (NestedTransaction) {
var TRANSACTION_METHODS = ['add', 'commit', 'cancel', 'size'];
describe("A NestedTransaction", function () {
var mockTransaction,
nestedTransaction;
beforeEach(function () {
mockTransaction =
jasmine.createSpyObj('transaction', TRANSACTION_METHODS);
nestedTransaction = new NestedTransaction(mockTransaction);
});
it("exposes a Transaction's interface", function () {
TRANSACTION_METHODS.forEach(function (method) {
expect(nestedTransaction[method])
.toEqual(jasmine.any(Function));
});
});
describe("when callbacks are added", function () {
var mockCommit,
mockCancel;
beforeEach(function () {
mockCommit = jasmine.createSpy('commit');
mockCancel = jasmine.createSpy('cancel');
nestedTransaction.add(mockCommit, mockCancel);
});
it("does not interact with its parent transaction", function () {
TRANSACTION_METHODS.forEach(function (method) {
expect(mockTransaction[method])
.not.toHaveBeenCalled();
});
});
describe("and the transaction is committed", function () {
beforeEach(function () {
nestedTransaction.commit();
});
it("adds to its parent transaction", function () {
expect(mockTransaction.add).toHaveBeenCalledWith(
jasmine.any(Function),
jasmine.any(Function)
);
});
});
});
});
});

View File

@ -1,141 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/services/TransactionManager"],
function (TransactionManager) {
describe("TransactionManager", function () {
var mockTransactionService,
testId,
mockOnCommit,
mockOnCancel,
mockRemoves,
mockPromise,
manager;
beforeEach(function () {
mockRemoves = [];
mockTransactionService = jasmine.createSpyObj(
"transactionService",
["addToTransaction", "isActive"]
);
mockOnCommit = jasmine.createSpy('commit');
mockOnCancel = jasmine.createSpy('cancel');
testId = 'test-id';
mockPromise = jasmine.createSpyObj('promise', ['then']);
mockOnCommit.and.returnValue(mockPromise);
mockOnCancel.and.returnValue(mockPromise);
mockTransactionService.addToTransaction.and.callFake(function () {
var mockRemove =
jasmine.createSpy('remove-' + mockRemoves.length);
mockRemoves.push(mockRemove);
return mockRemove;
});
manager = new TransactionManager(mockTransactionService);
});
it("delegates isActive calls", function () {
[false, true].forEach(function (state) {
mockTransactionService.isActive.and.returnValue(state);
expect(manager.isActive()).toBe(state);
});
});
describe("when addToTransaction is called", function () {
beforeEach(function () {
manager.addToTransaction(
testId,
mockOnCommit,
mockOnCancel
);
});
it("adds callbacks to the active transaction", function () {
expect(mockTransactionService.addToTransaction)
.toHaveBeenCalledWith(
jasmine.any(Function),
jasmine.any(Function)
);
});
it("invokes passed-in callbacks from its own callbacks", function () {
expect(mockOnCommit).not.toHaveBeenCalled();
mockTransactionService.addToTransaction
.calls.mostRecent().args[0]();
expect(mockOnCommit).toHaveBeenCalled();
expect(mockOnCancel).not.toHaveBeenCalled();
mockTransactionService.addToTransaction
.calls.mostRecent().args[1]();
expect(mockOnCancel).toHaveBeenCalled();
});
describe("Adds callbacks to transaction", function () {
beforeEach(function () {
spyOn(manager, 'clearTransactionsFor');
manager.clearTransactionsFor.and.callThrough();
});
it("and clears pending calls if same object", function () {
manager.addToTransaction(
testId,
jasmine.createSpy(),
jasmine.createSpy()
);
expect(manager.clearTransactionsFor).toHaveBeenCalledWith(testId);
});
it("and does not clear pending calls if different object", function () {
manager.addToTransaction(
'other-id',
jasmine.createSpy(),
jasmine.createSpy()
);
expect(manager.clearTransactionsFor).not.toHaveBeenCalled();
});
afterEach(function () {
expect(mockTransactionService.addToTransaction.calls.count()).toEqual(2);
});
});
it("does not remove callbacks from the transaction", function () {
expect(mockRemoves[0]).not.toHaveBeenCalled();
});
describe("and clearTransactionsFor is subsequently called", function () {
beforeEach(function () {
manager.clearTransactionsFor(testId);
});
it("removes callbacks from the transaction", function () {
expect(mockRemoves[0]).toHaveBeenCalled();
});
});
});
});
}
);

View File

@ -1,139 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/services/TransactionService"],
function (TransactionService) {
describe("The Transaction Service", function () {
var mockQ,
mockLog,
mockCacheService,
transactionService;
function fastPromise(val) {
return {
then: function (callback) {
return fastPromise(callback(val));
}
};
}
beforeEach(function () {
mockQ = jasmine.createSpyObj("$q", ["all"]);
mockCacheService = jasmine.createSpyObj("cacheService", ["flush"]);
mockQ.all.and.returnValue(fastPromise());
mockLog = jasmine.createSpyObj("$log", ["error"]);
transactionService = new TransactionService(mockQ, mockLog, mockCacheService);
});
it("isActive returns true if a transaction is in progress", function () {
expect(transactionService.isActive()).toBe(false);
transactionService.startTransaction();
expect(transactionService.isActive()).toBe(true);
});
it("addToTransaction queues onCommit and onCancel functions", function () {
var onCommit = jasmine.createSpy('onCommit'),
onCancel = jasmine.createSpy('onCancel');
transactionService.startTransaction();
transactionService.addToTransaction(onCommit, onCancel);
expect(transactionService.size()).toBe(1);
});
it("size function returns size of commit and cancel queues", function () {
var onCommit = jasmine.createSpy('onCommit'),
onCancel = jasmine.createSpy('onCancel');
transactionService.startTransaction();
transactionService.addToTransaction(onCommit, onCancel);
transactionService.addToTransaction(onCommit, onCancel);
transactionService.addToTransaction(onCommit, onCancel);
expect(transactionService.size()).toBe(3);
});
describe("commit", function () {
var onCommits;
beforeEach(function () {
onCommits = [0, 1, 2].map(function (val) {
return jasmine.createSpy("onCommit" + val);
});
transactionService.startTransaction();
onCommits.forEach(transactionService.addToTransaction.bind(transactionService));
});
it("commit calls all queued commit functions", function () {
expect(transactionService.size()).toBe(3);
return transactionService.commit().then(() => {
onCommits.forEach(function (spy) {
expect(spy).toHaveBeenCalled();
});
});
});
it("commit resets active state and clears queues", function () {
return transactionService.commit().then(() => {
expect(transactionService.isActive()).toBe(false);
expect(transactionService.size()).toBe(0);
expect(transactionService.size()).toBe(0);
});
});
});
describe("cancel", function () {
var onCancels;
beforeEach(function () {
onCancels = [0, 1, 2].map(function (val) {
return jasmine.createSpy("onCancel" + val);
});
transactionService.startTransaction();
onCancels.forEach(function (onCancel) {
transactionService.addToTransaction(undefined, onCancel);
});
});
it("cancel calls all queued cancel functions", function () {
expect(transactionService.size()).toBe(3);
transactionService.cancel();
onCancels.forEach(function (spy) {
expect(spy).toHaveBeenCalled();
});
});
it("cancel resets active state and clears queues", function () {
transactionService.cancel();
expect(transactionService.isActive()).toBe(false);
expect(transactionService.size()).toBe(0);
});
});
});
}
);

View File

@ -1,109 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/services/Transaction"],
function (Transaction) {
describe("A Transaction", function () {
var mockLog,
transaction;
beforeEach(function () {
mockLog = jasmine.createSpyObj(
'$log',
['warn', 'info', 'error', 'debug']
);
transaction = new Transaction(mockLog);
});
it("initially has a size of zero", function () {
expect(transaction.size()).toEqual(0);
});
describe("when callbacks are added", function () {
var mockCommit,
mockCancel,
remove;
beforeEach(function () {
mockCommit = jasmine.createSpy('commit');
mockCancel = jasmine.createSpy('cancel');
remove = transaction.add(mockCommit, mockCancel);
});
it("reports a new size", function () {
expect(transaction.size()).toEqual(1);
});
it("returns a function to remove those callbacks", function () {
expect(remove).toEqual(jasmine.any(Function));
remove();
expect(transaction.size()).toEqual(0);
});
describe("and the transaction is committed", function () {
beforeEach(function () {
transaction.commit();
});
it("triggers the commit callback", function () {
expect(mockCommit).toHaveBeenCalled();
});
it("does not trigger the cancel callback", function () {
expect(mockCancel).not.toHaveBeenCalled();
});
});
describe("and the transaction is cancelled", function () {
beforeEach(function () {
transaction.cancel();
});
it("triggers the cancel callback", function () {
expect(mockCancel).toHaveBeenCalled();
});
it("does not trigger the commit callback", function () {
expect(mockCommit).not.toHaveBeenCalled();
});
});
describe("and an exception is encountered during commit", function () {
beforeEach(function () {
mockCommit.and.callFake(function () {
throw new Error("test error");
});
transaction.commit();
});
it("logs an error", function () {
expect(mockLog.error).toHaveBeenCalled();
});
});
});
});
}
);

View File

@ -25,15 +25,14 @@ define([
], function (
moment
) {
var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss.SSS",
DATE_FORMATS = [
DATE_FORMAT,
DATE_FORMAT + "Z",
"YYYY-MM-DD HH:mm:ss",
"YYYY-MM-DD HH:mm",
"YYYY-MM-DD"
];
const DATE_FORMAT = "YYYY-MM-DD HH:mm:ss.SSS";
const DATE_FORMATS = [
DATE_FORMAT,
DATE_FORMAT + "Z",
"YYYY-MM-DD HH:mm:ss",
"YYYY-MM-DD HH:mm",
"YYYY-MM-DD"
];
/**
* @typedef Scale
@ -53,15 +52,27 @@ define([
this.key = "utc";
}
/**
* @param {string} formatString
* @returns the value of formatString if the value is a string type and exists in the DATE_FORMATS array; otherwise the DATE_FORMAT value.
*/
function validateFormatString(formatString) {
return typeof formatString === 'string' && DATE_FORMATS.includes(formatString) ? formatString : DATE_FORMAT;
}
/**
* @param {number} value The value to format.
* @returns {string} the formatted date(s). If multiple values were requested, then an array of
* @param {string} formatString The string format to format. Default "YYYY-MM-DD HH:mm:ss.SSS" + "Z"
* @returns {string} the formatted date(s) according to the proper parameter of formatString or the default value of "YYYY-MM-DD HH:mm:ss.SSS" + "Z".
* If multiple values were requested, then an array of
* formatted values will be returned. Where a value could not be formatted, `undefined` will be returned at its position
* in the array.
*/
UTCTimeFormat.prototype.format = function (value) {
UTCTimeFormat.prototype.format = function (value, formatString) {
if (value !== undefined) {
return moment.utc(value).format(DATE_FORMAT) + "Z";
const format = validateFormatString(formatString);
return moment.utc(value).format(format) + (formatString ? '' : 'Z');
} else {
return value;
}

View File

@ -21,28 +21,14 @@
*****************************************************************************/
define([
"./src/MCTDevice",
"./src/AgentService",
"./src/DeviceClassifier"
"./src/AgentService"
], function (
MCTDevice,
AgentService,
DeviceClassifier
AgentService
) {
return {
name: "platform/commonUI/mobile",
definition: {
"extensions": {
"directives": [
{
"key": "mctDevice",
"implementation": MCTDevice,
"depends": [
"agentService"
]
}
],
"services": [
{
"key": "agentService",
@ -51,15 +37,6 @@ define([
"$window"
]
}
],
"runs": [
{
"implementation": DeviceClassifier,
"depends": [
"agentService",
"$document"
]
}
]
}
}

View File

@ -20,122 +20,12 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
/**
* Provides features which support variant behavior on mobile devices.
*
* @namespace platform/commonUI/mobile
*/
define(
[],
function () {
define(["../../../../src/utils/agent/Agent.js"], function (Agent) {
function AngularAgentServiceWrapper(window) {
const AS = Agent.default;
/**
* The query service handles calls for browser and userAgent
* info using a comparison between the userAgent and key
* device names
* @constructor
* @param $window Angular-injected instance of the window
* @memberof platform/commonUI/mobile
*/
function AgentService($window) {
var userAgent = $window.navigator.userAgent,
matches = userAgent.match(/iPad|iPhone|Android/i) || [];
this.userAgent = userAgent;
this.mobileName = matches[0];
this.$window = $window;
this.touchEnabled = ($window.ontouchstart !== undefined);
}
/**
* Check if the user is on a mobile device.
* @returns {boolean} true on mobile
*/
AgentService.prototype.isMobile = function () {
return Boolean(this.mobileName);
};
/**
* Check if the user is on a phone-sized mobile device.
* @returns {boolean} true on a phone
*/
AgentService.prototype.isPhone = function () {
if (this.isMobile()) {
if (this.isAndroidTablet()) {
return false;
} else if (this.mobileName === 'iPad') {
return false;
} else {
return true;
}
} else {
return false;
}
};
/**
* Check if the user is on a tablet sized android device
* @returns {boolean} true on an android tablet
*/
AgentService.prototype.isAndroidTablet = function () {
if (this.mobileName === 'Android') {
if (this.isPortrait() && window.innerWidth >= 768) {
return true;
} else if (this.isLandscape() && window.innerHeight >= 768) {
return true;
}
} else {
return false;
}
};
/**
* Check if the user is on a tablet-sized mobile device.
* @returns {boolean} true on a tablet
*/
AgentService.prototype.isTablet = function () {
return (this.isMobile() && !this.isPhone() && this.mobileName !== 'Android') || (this.isMobile() && this.isAndroidTablet());
};
/**
* Check if the user's device is in a portrait-style
* orientation (display width is narrower than display height.)
* @returns {boolean} true in portrait mode
*/
AgentService.prototype.isPortrait = function () {
return this.$window.innerWidth < this.$window.innerHeight;
};
/**
* Check if the user's device is in a landscape-style
* orientation (display width is greater than display height.)
* @returns {boolean} true in landscape mode
*/
AgentService.prototype.isLandscape = function () {
return !this.isPortrait();
};
/**
* Check if the user's device supports a touch interface.
* @returns {boolean} true if touch is supported
*/
AgentService.prototype.isTouch = function () {
return this.touchEnabled;
};
/**
* Check if the user agent matches a certain named device,
* as indicated by checking for a case-insensitive substring
* match.
* @param {string} name the name to check for
* @returns {boolean} true if the user agent includes that name
*/
AgentService.prototype.isBrowser = function (name) {
name = name.toLowerCase();
return this.userAgent.toLowerCase().indexOf(name) !== -1;
};
return AgentService;
return new AS(window);
}
);
return AngularAgentServiceWrapper;
});

View File

@ -0,0 +1,96 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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 AgentService from "./AgentService";
const TEST_USER_AGENTS = {
DESKTOP:
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36",
IPAD:
"Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53",
IPHONE:
"Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53"
};
describe("The AgentService", function () {
let testWindow;
let agentService;
beforeEach(function () {
testWindow = {
innerWidth: 640,
innerHeight: 480,
navigator: {
userAgent: TEST_USER_AGENTS.DESKTOP
}
};
});
it("recognizes desktop devices as non-mobile", function () {
testWindow.navigator.userAgent = TEST_USER_AGENTS.DESKTOP;
agentService = new AgentService(testWindow);
expect(agentService.isMobile()).toBeFalsy();
expect(agentService.isPhone()).toBeFalsy();
expect(agentService.isTablet()).toBeFalsy();
});
it("detects iPhones", function () {
testWindow.navigator.userAgent = TEST_USER_AGENTS.IPHONE;
agentService = new AgentService(testWindow);
expect(agentService.isMobile()).toBeTruthy();
expect(agentService.isPhone()).toBeTruthy();
expect(agentService.isTablet()).toBeFalsy();
});
it("detects iPads", function () {
testWindow.navigator.userAgent = TEST_USER_AGENTS.IPAD;
agentService = new AgentService(testWindow);
expect(agentService.isMobile()).toBeTruthy();
expect(agentService.isPhone()).toBeFalsy();
expect(agentService.isTablet()).toBeTruthy();
});
it("detects display orientation", function () {
agentService = new AgentService(testWindow);
testWindow.innerWidth = 1024;
testWindow.innerHeight = 400;
expect(agentService.isPortrait()).toBeFalsy();
expect(agentService.isLandscape()).toBeTruthy();
testWindow.innerWidth = 400;
testWindow.innerHeight = 1024;
expect(agentService.isPortrait()).toBeTruthy();
expect(agentService.isLandscape()).toBeFalsy();
});
it("detects touch support", function () {
testWindow.ontouchstart = null;
expect(new AgentService(testWindow).isTouch()).toBe(true);
delete testWindow.ontouchstart;
expect(new AgentService(testWindow).isTouch()).toBe(false);
});
it("allows for checking browser type", function () {
testWindow.navigator.userAgent = "Chromezilla Safarifox";
agentService = new AgentService(testWindow);
expect(agentService.isBrowser("Chrome")).toBe(true);
expect(agentService.isBrowser("Firefox")).toBe(false);
});
});

View File

@ -1,72 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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(
['./DeviceMatchers'],
function (DeviceMatchers) {
/**
* Runs at application startup and adds a subset of the following
* CSS classes to the body of the document, depending on device
* attributes:
*
* * `mobile`: Phones or tablets.
* * `phone`: Phones specifically.
* * `tablet`: Tablets specifically.
* * `desktop`: Non-mobile devices.
* * `portrait`: Devices in a portrait-style orientation.
* * `landscape`: Devices in a landscape-style orientation.
* * `touch`: Device supports touch events.
*
* @param {platform/commonUI/mobile.AgentService} agentService
* the service used to examine the user agent
* @param $document Angular's jqLite-wrapped document element
* @constructor
*/
function MobileClassifier(agentService, $document) {
var body = $document.find('body');
Object.keys(DeviceMatchers).forEach(function (key, index, array) {
if (DeviceMatchers[key](agentService)) {
body.addClass(key);
}
});
if (agentService.isMobile()) {
var mediaQuery = window.matchMedia('(orientation: landscape)');
mediaQuery.addListener(function (event) {
if (event.matches) {
body.removeClass('portrait');
body.addClass('landscape');
} else {
body.removeClass('landscape');
body.addClass('portrait');
}
});
}
}
return MobileClassifier;
}
);

View File

@ -1,58 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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 () {
/**
* An object containing key-value pairs, where keys are symbolic of
* device attributes, and values are functions that take the
* `agentService` as inputs and return boolean values indicating
* whether or not the current device has these attributes.
*
* For internal use by the mobile support bundle.
*
* @memberof platform/commonUI/mobile
* @private
*/
return {
mobile: function (agentService) {
return agentService.isMobile();
},
phone: function (agentService) {
return agentService.isPhone();
},
tablet: function (agentService) {
return agentService.isTablet();
},
desktop: function (agentService) {
return !agentService.isMobile();
},
portrait: function (agentService) {
return agentService.isPortrait();
},
landscape: function (agentService) {
return agentService.isLandscape();
},
touch: function (agentService) {
return agentService.isTouch();
}
};
});

View File

@ -1,88 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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(
['./DeviceMatchers'],
function (DeviceMatchers) {
/**
* The `mct-device` directive, when applied as an attribute,
* only includes the element when the device being used matches
* a set of characteristics required.
*
* Required characteristics are given as space-separated strings
* as the value to this attribute, e.g.:
*
* <span mct-device="mobile portrait">Hello world!</span>
*
* ...will only show Hello world! when viewed on a mobile device
* in the portrait orientation.
*
* Valid device characteristics to detect are:
*
* * `mobile`: Phones or tablets.
* * `phone`: Phones specifically.
* * `tablet`: Tablets specifically.
* * `desktop`: Non-mobile devices.
* * `portrait`: Devices in a portrait-style orientation.
* * `landscape`: Devices in a landscape-style orientation.
* * `touch`: Device supports touch events.
*
* @param {AgentService} agentService used to detect device type
* based on information about the user agent
*/
function MCTDevice(agentService) {
function deviceMatches(tokens) {
tokens = tokens || "";
return tokens.split(" ").every(function (token) {
var fn = DeviceMatchers[token];
return fn && fn(agentService);
});
}
function link(scope, element, attrs, ctrl, transclude) {
if (deviceMatches(attrs.mctDevice)) {
transclude(function (clone) {
element.replaceWith(clone);
});
}
}
return {
link: link,
// We are transcluding the whole element (like ng-if)
transclude: 'element',
// 1 more than ng-if
priority: 601,
// Also terminal, since element will be transcluded
terminal: true,
// Only apply as an attribute
restrict: "A"
};
}
return MCTDevice;
}
);

View File

@ -1,99 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/AgentService"],
function (AgentService) {
var TEST_USER_AGENTS = {
DESKTOP: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36",
IPAD: "Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53",
IPHONE: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53"
};
describe("The AgentService", function () {
var testWindow, agentService;
beforeEach(function () {
testWindow = {
innerWidth: 640,
innerHeight: 480,
navigator: {
userAgent: TEST_USER_AGENTS.DESKTOP
}
};
});
it("recognizes desktop devices as non-mobile", function () {
testWindow.navigator.userAgent = TEST_USER_AGENTS.DESKTOP;
agentService = new AgentService(testWindow);
expect(agentService.isMobile()).toBeFalsy();
expect(agentService.isPhone()).toBeFalsy();
expect(agentService.isTablet()).toBeFalsy();
});
it("detects iPhones", function () {
testWindow.navigator.userAgent = TEST_USER_AGENTS.IPHONE;
agentService = new AgentService(testWindow);
expect(agentService.isMobile()).toBeTruthy();
expect(agentService.isPhone()).toBeTruthy();
expect(agentService.isTablet()).toBeFalsy();
});
it("detects iPads", function () {
testWindow.navigator.userAgent = TEST_USER_AGENTS.IPAD;
agentService = new AgentService(testWindow);
expect(agentService.isMobile()).toBeTruthy();
expect(agentService.isPhone()).toBeFalsy();
expect(agentService.isTablet()).toBeTruthy();
});
it("detects display orientation", function () {
agentService = new AgentService(testWindow);
testWindow.innerWidth = 1024;
testWindow.innerHeight = 400;
expect(agentService.isPortrait()).toBeFalsy();
expect(agentService.isLandscape()).toBeTruthy();
testWindow.innerWidth = 400;
testWindow.innerHeight = 1024;
expect(agentService.isPortrait()).toBeTruthy();
expect(agentService.isLandscape()).toBeFalsy();
});
it("detects touch support", function () {
testWindow.ontouchstart = null;
expect(new AgentService(testWindow).isTouch())
.toBe(true);
delete testWindow.ontouchstart;
expect(new AgentService(testWindow).isTouch())
.toBe(false);
});
it("allows for checking browser type", function () {
testWindow.navigator.userAgent = "Chromezilla Safarifox";
agentService = new AgentService(testWindow);
expect(agentService.isBrowser("Chrome")).toBe(true);
expect(agentService.isBrowser("Firefox")).toBe(false);
});
});
}
);

View File

@ -1,109 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/DeviceClassifier", "../src/DeviceMatchers"],
function (DeviceClassifier, DeviceMatchers) {
var AGENT_SERVICE_METHODS = [
'isMobile',
'isPhone',
'isTablet',
'isPortrait',
'isLandscape',
'isTouch'
],
TEST_PERMUTATIONS = [
['isMobile', 'isPhone', 'isTouch', 'isPortrait'],
['isMobile', 'isPhone', 'isTouch', 'isLandscape'],
['isMobile', 'isTablet', 'isTouch', 'isPortrait'],
['isMobile', 'isTablet', 'isTouch', 'isLandscape'],
['isTouch'],
[]
];
describe("DeviceClassifier", function () {
var mockAgentService,
mockDocument,
mockBody;
beforeEach(function () {
mockAgentService = jasmine.createSpyObj(
'agentService',
AGENT_SERVICE_METHODS
);
mockDocument = jasmine.createSpyObj(
'$document',
['find']
);
mockBody = jasmine.createSpyObj(
'body',
['addClass']
);
mockDocument.find.and.callFake(function (sel) {
return sel === 'body' && mockBody;
});
AGENT_SERVICE_METHODS.forEach(function (m) {
mockAgentService[m].and.returnValue(false);
});
});
TEST_PERMUTATIONS.forEach(function (trueMethods) {
var summary = trueMethods.length === 0
? "device has no detected characteristics"
: "device " + (trueMethods.join(", "));
describe("when " + summary, function () {
var classifier; // eslint-disable-line
beforeEach(function () {
trueMethods.forEach(function (m) {
mockAgentService[m].and.returnValue(true);
});
classifier = new DeviceClassifier(
mockAgentService,
mockDocument
);
});
it("adds classes for matching, detected characteristics", function () {
Object.keys(DeviceMatchers).filter(function (m) {
return DeviceMatchers[m](mockAgentService);
}).forEach(function (key) {
expect(mockBody.addClass)
.toHaveBeenCalledWith(key);
});
});
it("does not add classes for non-matching characteristics", function () {
Object.keys(DeviceMatchers).filter(function (m) {
return !DeviceMatchers[m](mockAgentService);
}).forEach(function (key) {
expect(mockBody.addClass)
.not.toHaveBeenCalledWith(key);
});
});
});
});
});
}
);

View File

@ -1,78 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/DeviceMatchers"],
function (DeviceMatchers) {
describe("DeviceMatchers", function () {
var mockAgentService;
beforeEach(function () {
mockAgentService = jasmine.createSpyObj(
'agentService',
[
'isMobile',
'isPhone',
'isTablet',
'isPortrait',
'isLandscape',
'isTouch'
]
);
});
it("detects when a device is a desktop device", function () {
mockAgentService.isMobile.and.returnValue(false);
expect(DeviceMatchers.desktop(mockAgentService))
.toBe(true);
mockAgentService.isMobile.and.returnValue(true);
expect(DeviceMatchers.desktop(mockAgentService))
.toBe(false);
});
function method(deviceType) {
return "is" + deviceType[0].toUpperCase() + deviceType.slice(1);
}
[
"mobile",
"phone",
"tablet",
"landscape",
"portrait",
"landscape",
"touch"
].forEach(function (deviceType) {
it("detects when a device is a " + deviceType + " device", function () {
mockAgentService[method(deviceType)].and.returnValue(true);
expect(DeviceMatchers[deviceType](mockAgentService))
.toBe(true);
mockAgentService[method(deviceType)].and.returnValue(false);
expect(DeviceMatchers[deviceType](mockAgentService))
.toBe(false);
});
});
});
}
);

View File

@ -1,168 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/MCTDevice'],
function (MCTDevice) {
var JQLITE_METHODS = ['replaceWith'];
describe("The mct-device directive", function () {
var mockAgentService,
mockTransclude,
mockElement,
mockClone,
testAttrs,
directive;
function link() {
directive.link(null, mockElement, testAttrs, null, mockTransclude);
}
beforeEach(function () {
mockAgentService = jasmine.createSpyObj(
"agentService",
["isMobile", "isPhone", "isTablet", "isPortrait", "isLandscape"]
);
mockTransclude = jasmine.createSpy("$transclude");
mockElement = jasmine.createSpyObj(name, JQLITE_METHODS);
mockClone = jasmine.createSpyObj(name, JQLITE_METHODS);
mockTransclude.and.callFake(function (fn) {
fn(mockClone);
});
// Look desktop-like by default
mockAgentService.isLandscape.and.returnValue(true);
testAttrs = {};
directive = new MCTDevice(mockAgentService);
});
function expectInclusion() {
expect(mockElement.replaceWith)
.toHaveBeenCalledWith(mockClone);
}
function expectExclusion() {
expect(mockElement.replaceWith).not.toHaveBeenCalled();
}
it("is applicable at the attribute level", function () {
expect(directive.restrict).toEqual("A");
});
it("transcludes at the element level", function () {
expect(directive.transclude).toEqual('element');
});
it("has a greater priority number than ng-if", function () {
expect(directive.priority > 600).toBeTruthy();
});
it("restricts element inclusion for mobile devices", function () {
testAttrs.mctDevice = "mobile";
link();
expectExclusion();
mockAgentService.isMobile.and.returnValue(true);
link();
expectInclusion();
});
it("restricts element inclusion for tablet devices", function () {
testAttrs.mctDevice = "tablet";
mockAgentService.isMobile.and.returnValue(true);
link();
expectExclusion();
mockAgentService.isTablet.and.returnValue(true);
link();
expectInclusion();
});
it("restricts element inclusion for phone devices", function () {
testAttrs.mctDevice = "phone";
mockAgentService.isMobile.and.returnValue(true);
link();
expectExclusion();
mockAgentService.isPhone.and.returnValue(true);
link();
expectInclusion();
});
it("restricts element inclusion for desktop devices", function () {
testAttrs.mctDevice = "desktop";
mockAgentService.isMobile.and.returnValue(true);
link();
expectExclusion();
mockAgentService.isMobile.and.returnValue(false);
link();
expectInclusion();
});
it("restricts element inclusion for portrait orientation", function () {
testAttrs.mctDevice = "portrait";
link();
expectExclusion();
mockAgentService.isPortrait.and.returnValue(true);
link();
expectInclusion();
});
it("restricts element inclusion for landscape orientation", function () {
testAttrs.mctDevice = "landscape";
mockAgentService.isLandscape.and.returnValue(false);
mockAgentService.isPortrait.and.returnValue(true);
link();
expectExclusion();
mockAgentService.isLandscape.and.returnValue(true);
link();
expectInclusion();
});
it("allows multiple device characteristics to be requested", function () {
// Won't try to test every permutation here, just
// make sure the multi-characteristic feature has support.
testAttrs.mctDevice = "portrait mobile";
link();
// Neither portrait nor mobile, not called
expectExclusion();
mockAgentService.isPortrait.and.returnValue(true);
link();
// Was portrait, but not mobile, so no
expectExclusion();
mockAgentService.isMobile.and.returnValue(true);
link();
expectInclusion();
});
});
}
);

View File

@ -28,7 +28,6 @@ define([
"./src/models/ModelCacheService",
"./src/models/PersistedModelProvider",
"./src/models/CachingModelDecorator",
"./src/models/MissingModelDecorator",
"./src/types/TypeProvider",
"./src/actions/ActionProvider",
"./src/actions/ActionAggregator",
@ -45,7 +44,6 @@ define([
"./src/capabilities/MutationCapability",
"./src/capabilities/DelegationCapability",
"./src/capabilities/InstantiationCapability",
"./src/runs/TransactingMutationListener",
"./src/services/Now",
"./src/services/Throttle",
"./src/services/Topic",
@ -58,7 +56,6 @@ define([
ModelCacheService,
PersistedModelProvider,
CachingModelDecorator,
MissingModelDecorator,
TypeProvider,
ActionProvider,
ActionAggregator,
@ -75,7 +72,6 @@ define([
MutationCapability,
DelegationCapability,
InstantiationCapability,
TransactingMutationListener,
Now,
Throttle,
Topic,
@ -150,12 +146,6 @@ define([
"cacheService"
]
},
{
"provides": "modelService",
"type": "decorator",
"priority": "fallback",
"implementation": MissingModelDecorator
},
{
"provides": "typeService",
"type": "provider",
@ -363,12 +353,6 @@ define([
]
}
],
"runs": [
{
"implementation": TransactingMutationListener,
"depends": ["topic", "transactionService", "cacheService"]
}
],
"constants": [
{
"key": "PERSISTENCE_SPACE",
@ -379,7 +363,7 @@ define([
{
"name": "Math.uuid.js",
"version": "1.4.7",
"description": "Unique identifer generation (code adapted.)",
"description": "Unique identifier generation (code adapted.)",
"author": "Robert Kieffer",
"website": "https://github.com/broofa/node-uuid",
"copyright": "Copyright (c) 2010-2012 Robert Kieffer",

View File

@ -141,11 +141,17 @@ define(
if (mutationResult !== false) {
// Copy values if result was a different object
// (either our clone or some other new thing)
if (model !== result) {
let modelHasChanged = _.isEqual(model, result) === false;
if (modelHasChanged) {
copyValues(model, result);
}
model.modified = useTimestamp ? timestamp : now();
if (modelHasChanged
|| (useTimestamp !== undefined)
|| (model.modified === undefined)) {
model.modified = useTimestamp ? timestamp : now();
}
notifyListeners(model);
}

View File

@ -1,55 +0,0 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web 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 Web 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 () {
/**
* Listens for mutation on domain objects and triggers persistence when
* it occurs.
* @param {Topic} topic the `topic` service; used to listen for mutation
* @memberof platform/core
*/
function TransactingMutationListener(
topic,
transactionService,
cacheService
) {
function hasChanged(domainObject) {
var model = domainObject.getModel();
return model.persisted === undefined || model.modified > model.persisted;
}
var mutationTopic = topic('mutation');
mutationTopic.listen(function (domainObject) {
var persistence = domainObject.getCapability('persistence');
cacheService.put(domainObject.getId(), domainObject.getModel());
if (hasChanged(domainObject)) {
persistence.persist();
}
});
}
return TransactingMutationListener;
});

View File

@ -1,86 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/models/MissingModelDecorator"],
function (MissingModelDecorator) {
describe("The missing model decorator", function () {
var mockModelService,
testModels,
decorator;
function asPromise(value) {
return (value || {}).then ? value : {
then: function (callback) {
return asPromise(callback(value));
}
};
}
beforeEach(function () {
mockModelService = jasmine.createSpyObj(
"modelService",
["getModels"]
);
testModels = {
testId: { someKey: "some value" }
};
mockModelService.getModels.and.returnValue(asPromise(testModels));
decorator = new MissingModelDecorator(mockModelService);
});
it("delegates to the wrapped model service", function () {
decorator.getModels(['a', 'b', 'c']);
expect(mockModelService.getModels)
.toHaveBeenCalledWith(['a', 'b', 'c']);
});
it("provides models for any IDs which are missing", function () {
var models;
decorator.getModels(['testId', 'otherId'])
.then(function (m) {
models = m;
});
expect(models.otherId).toBeDefined();
});
it("does not overwrite existing models", function () {
var models;
decorator.getModels(['testId', 'otherId'])
.then(function (m) {
models = m;
});
expect(models.testId).toEqual({ someKey: "some value" });
});
it("does not modify the wrapped service's response", function () {
decorator.getModels(['testId', 'otherId']);
expect(testModels.otherId).toBeUndefined();
});
});
}
);

View File

@ -1,112 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/runs/TransactingMutationListener"],
function (TransactingMutationListener) {
describe("TransactingMutationListener", function () {
var mockTopic,
mockMutationTopic,
mockCacheService,
mockTransactionService,
mockDomainObject,
mockModel,
mockPersistence;
beforeEach(function () {
mockTopic = jasmine.createSpy('topic');
mockMutationTopic =
jasmine.createSpyObj('mutation', ['listen']);
mockCacheService =
jasmine.createSpyObj('cacheService', [
'put'
]);
mockTransactionService =
jasmine.createSpyObj('transactionService', [
'isActive',
'startTransaction',
'commit'
]);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getId', 'getCapability', 'getModel']
);
mockPersistence = jasmine.createSpyObj(
'persistence',
['persist', 'refresh', 'persisted']
);
mockTopic.and.callFake(function (t) {
expect(t).toBe('mutation');
return mockMutationTopic;
});
mockDomainObject.getId.and.returnValue('mockId');
mockDomainObject.getCapability.and.callFake(function (c) {
expect(c).toBe('persistence');
return mockPersistence;
});
mockModel = {};
mockDomainObject.getModel.and.returnValue(mockModel);
mockPersistence.persisted.and.returnValue(true);
return new TransactingMutationListener(
mockTopic,
mockTransactionService,
mockCacheService
);
});
it("listens for mutation", function () {
expect(mockMutationTopic.listen)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("calls persist if the model has changed", function () {
mockModel.persisted = Date.now();
//Mark the model dirty by setting the mutated date later than the last persisted date.
mockModel.modified = mockModel.persisted + 1;
mockMutationTopic.listen.calls.mostRecent()
.args[0](mockDomainObject);
expect(mockPersistence.persist).toHaveBeenCalled();
});
it("does not call persist if the model has not changed", function () {
mockModel.persisted = Date.now();
mockModel.modified = mockModel.persisted;
mockMutationTopic.listen.calls.mostRecent()
.args[0](mockDomainObject);
expect(mockPersistence.persist).not.toHaveBeenCalled();
});
});
}
);

View File

@ -1,321 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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([
"moment-timezone",
"./src/indicators/ClockIndicator",
"./src/indicators/FollowIndicator",
"./src/services/TickerService",
"./src/services/TimerService",
"./src/controllers/ClockController",
"./src/controllers/TimerController",
"./src/controllers/RefreshingController",
"./src/actions/FollowTimerAction",
"./src/actions/StartTimerAction",
"./src/actions/RestartTimerAction",
"./src/actions/StopTimerAction",
"./src/actions/PauseTimerAction",
"./res/templates/clock.html",
"./res/templates/timer.html"
], function (
MomentTimezone,
ClockIndicator,
FollowIndicator,
TickerService,
TimerService,
ClockController,
TimerController,
RefreshingController,
FollowTimerAction,
StartTimerAction,
RestartTimerAction,
StopTimerAction,
PauseTimerAction,
clockTemplate,
timerTemplate
) {
return {
name: "platform/features/clock",
definition: {
"name": "Clocks/Timers",
"descriptions": "Domain objects for displaying current & relative times.",
"configuration": {
"paths": {
"moment-duration-format": "moment-duration-format"
},
"shim": {
"moment-duration-format": {
"deps": [
"moment"
]
}
}
},
"extensions": {
"constants": [
{
"key": "CLOCK_INDICATOR_FORMAT",
"value": "YYYY/MM/DD HH:mm:ss"
}
],
"indicators": [
{
"implementation": ClockIndicator,
"depends": [
"tickerService",
"CLOCK_INDICATOR_FORMAT"
],
"priority": "preferred"
}
],
"services": [
{
"key": "tickerService",
"implementation": TickerService,
"depends": [
"$timeout",
"now"
]
},
{
"key": "timerService",
"implementation": TimerService,
"depends": ["openmct"]
}
],
"controllers": [
{
"key": "ClockController",
"implementation": ClockController,
"depends": [
"$scope",
"tickerService"
]
},
{
"key": "TimerController",
"implementation": TimerController,
"depends": [
"$scope",
"$window",
"now"
]
},
{
"key": "RefreshingController",
"implementation": RefreshingController,
"depends": [
"$scope",
"tickerService"
]
}
],
"views": [
{
"key": "clock",
"type": "clock",
"editable": false,
"template": clockTemplate
},
{
"key": "timer",
"type": "timer",
"editable": false,
"template": timerTemplate
}
],
"actions": [
{
"key": "timer.follow",
"implementation": FollowTimerAction,
"depends": ["timerService"],
"category": "contextual",
"name": "Follow Timer",
"cssClass": "icon-clock",
"priority": "optional"
},
{
"key": "timer.start",
"implementation": StartTimerAction,
"depends": [
"now"
],
"category": "contextual",
"name": "Start",
"cssClass": "icon-play",
"priority": "preferred"
},
{
"key": "timer.pause",
"implementation": PauseTimerAction,
"depends": [
"now"
],
"category": "contextual",
"name": "Pause",
"cssClass": "icon-pause",
"priority": "preferred"
},
{
"key": "timer.restart",
"implementation": RestartTimerAction,
"depends": [
"now"
],
"category": "contextual",
"name": "Restart at 0",
"cssClass": "icon-refresh",
"priority": "preferred"
},
{
"key": "timer.stop",
"implementation": StopTimerAction,
"depends": [
"now"
],
"category": "contextual",
"name": "Stop",
"cssClass": "icon-box",
"priority": "preferred"
}
],
"types": [
{
"key": "clock",
"name": "Clock",
"cssClass": "icon-clock",
"description": "A UTC-based clock that supports a variety of display formats. Clocks can be added to Display Layouts.",
"priority": 101,
"features": [
"creation"
],
"properties": [
{
"key": "clockFormat",
"name": "Display Format",
"control": "composite",
"items": [
{
"control": "select",
"options": [
{
"value": "YYYY/MM/DD hh:mm:ss",
"name": "YYYY/MM/DD hh:mm:ss"
},
{
"value": "YYYY/DDD hh:mm:ss",
"name": "YYYY/DDD hh:mm:ss"
},
{
"value": "hh:mm:ss",
"name": "hh:mm:ss"
}
],
"cssClass": "l-inline"
},
{
"control": "select",
"options": [
{
"value": "clock12",
"name": "12hr"
},
{
"value": "clock24",
"name": "24hr"
}
],
"cssClass": "l-inline"
}
]
},
{
"key": "timezone",
"name": "Timezone",
"control": "autocomplete",
"options": MomentTimezone.tz.names()
}
],
"model": {
"clockFormat": [
"YYYY/MM/DD hh:mm:ss",
"clock12"
],
"timezone": "UTC"
}
},
{
"key": "timer",
"name": "Timer",
"cssClass": "icon-timer",
"description": "A timer that counts up or down to a datetime. Timers can be started, stopped and reset whenever needed, and support a variety of display formats. Each Timer displays the same value to all users. Timers can be added to Display Layouts.",
"priority": 100,
"features": [
"creation"
],
"properties": [
{
"key": "timestamp",
"control": "datetime",
"name": "Target"
},
{
"key": "timerFormat",
"control": "select",
"name": "Display Format",
"options": [
{
"value": "long",
"name": "DDD hh:mm:ss"
},
{
"value": "short",
"name": "hh:mm:ss"
}
]
}
],
"model": {
"timerFormat": "DDD hh:mm:ss"
}
}
],
"runs": [{
"implementation": FollowIndicator,
"depends": ["openmct", "timerService"]
}],
"licenses": [
{
"name": "moment-duration-format",
"version": "1.3.0",
"author": "John Madhavan-Reese",
"description": "Duration parsing/formatting",
"website": "https://github.com/jsmreese/moment-duration-format",
"copyright": "Copyright 2014 John Madhavan-Reese",
"license": "license-mit",
"link": "https://github.com/jsmreese/moment-duration-format/blob/master/LICENSE"
}
]
}
}
};
});

View File

@ -1,32 +0,0 @@
<!--
Open MCT, Copyright (c) 2009-2016, 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.
-->
<div class="c-clock l-time-display u-style-receiver js-style-receiver" ng-controller="ClockController as clock">
<div class="c-clock__timezone">
{{clock.zone()}}
</div>
<div class="c-clock__value">
{{clock.text()}}
</div>
<div class="c-clock__ampm">
{{clock.ampm()}}
</div>
</div>

View File

@ -1,37 +0,0 @@
<!--
Open MCT, Copyright (c) 2009-2016, 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.
-->
<div class="c-timer u-style-receiver js-style-receiver is-{{timer.timerState}}" ng-controller="TimerController as timer">
<div class="c-timer__controls">
<button ng-click="timer.clickStopButton()"
ng-hide="timer.timerState == 'stopped'"
title="Reset"
class="c-timer__ctrl-reset c-icon-button c-icon-button--major icon-reset"></button>
<button ng-click="timer.clickButton()"
title="{{timer.buttonText()}}"
class="c-timer__ctrl-pause-play c-icon-button c-icon-button--major {{timer.buttonCssClass()}}"></button>
</div>
<div class="c-timer__direction {{timer.signClass()}}"
ng-hide="!timer.signClass()"></div>
<div class="c-timer__value">{{timer.text() || "--:--:--"}}
</div>
<span class="c-timer__ng-controller u-contents" ng-controller="RefreshingController"></span>
</div>

View File

@ -1,56 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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 () {
/**
* Designates a specific timer for following. Timelines, for example,
* use the actively followed timer to display a time-of-interest line
* and interpret time conductor bounds in the Timeline's relative
* time frame.
*
* @implements {Action}
* @memberof platform/features/clock
* @constructor
* @param {ActionContext} context the context for this action
*/
function FollowTimerAction(timerService, context) {
var domainObject =
context.domainObject
&& context.domainObject.useCapability('adapter');
this.perform =
timerService.setTimer.bind(timerService, domainObject);
}
FollowTimerAction.appliesTo = function (context) {
var model =
(context.domainObject && context.domainObject.getModel())
|| {};
return model.type === 'timer';
};
return FollowTimerAction;
}
);

View File

@ -1,70 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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 () {
/**
* Implements the "Pause" action for timers.
*
* Sets the reference pausedTime in a timer to the current
* time, such that it stops counting up.
*
* @implements {Action}
* @memberof platform/features/clock
* @constructor
* @param {Function} now a function which returns the current
* time (typically wrapping `Date.now`)
* @param {ActionContext} context the context for this action
*/
function PauseTimerAction(now, context) {
this.domainObject = context.domainObject;
this.now = now;
}
PauseTimerAction.appliesTo = function (context) {
var model =
(context.domainObject && context.domainObject.getModel())
|| {};
// We show this variant for timers which have
// a target time, or is in a playing state.
return model.type === 'timer'
&& model.timerState === 'started';
};
PauseTimerAction.prototype.perform = function () {
var domainObject = this.domainObject,
now = this.now;
function updateModel(model) {
model.timerState = 'paused';
model.pausedTime = now();
}
return domainObject.useCapability('mutation', updateModel);
};
return PauseTimerAction;
}
);

View File

@ -1,70 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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 () {
/**
* Implements the "Restart at 0" action.
*
* Behaves the same as (and delegates functionality to)
* the "Start" action.
*
* @implements {Action}
* @memberof platform/features/clock
* @constructor
* @param {Function} now a function which returns the current
* time (typically wrapping `Date.now`)
* @param {ActionContext} context the context for this action
*/
function RestartTimerAction(now, context) {
this.domainObject = context.domainObject;
this.now = now;
}
RestartTimerAction.appliesTo = function (context) {
var model =
(context.domainObject && context.domainObject.getModel())
|| {};
// We show this variant for timers which already have a target time.
return model.type === 'timer'
&& model.timerState !== 'stopped';
};
RestartTimerAction.prototype.perform = function () {
var domainObject = this.domainObject,
now = this.now;
function updateModel(model) {
model.timestamp = now();
model.timerState = 'started';
model.pausedTime = undefined;
}
return domainObject.useCapability('mutation', updateModel);
};
return RestartTimerAction;
}
);

View File

@ -1,78 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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 () {
/**
* Implements the "Start" action for timers.
*
* Sets the reference timestamp in a timer to the current
* time, such that it begins counting up.
*
* @implements {Action}
* @memberof platform/features/clock
* @constructor
* @param {Function} now a function which returns the current
* time (typically wrapping `Date.now`)
* @param {ActionContext} context the context for this action
*/
function StartTimerAction(now, context) {
this.domainObject = context.domainObject;
this.now = now;
}
StartTimerAction.appliesTo = function (context) {
var model =
(context.domainObject && context.domainObject.getModel())
|| {};
// We show this variant for timers which do not yet have
// a target time.
return model.type === 'timer'
&& model.timerState !== 'started';
};
StartTimerAction.prototype.perform = function () {
var domainObject = this.domainObject,
now = this.now;
function updateModel(model) {
//if we are resuming
if (model.pausedTime) {
var timeShift = now() - model.pausedTime;
model.timestamp = model.timestamp + timeShift;
} else {
model.timestamp = now();
}
model.timerState = 'started';
model.pausedTime = undefined;
}
return domainObject.useCapability('mutation', updateModel);
};
return StartTimerAction;
}
);

View File

@ -1,70 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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 () {
/**
* Implements the "Stop" action for timers.
*
* Sets the reference timestamp in a timer undefined,
* such that it is reset and makes no movements.
*
* @implements {Action}
* @memberof platform/features/clock
* @constructor
* @param {Function} now a function which returns the current
* time (typically wrapping `Date.now`)
* @param {ActionContext} context the context for this action
*/
function StopTimerAction(now, context) {
this.domainObject = context.domainObject;
this.now = now;
}
StopTimerAction.appliesTo = function (context) {
var model =
(context.domainObject && context.domainObject.getModel())
|| {};
// We show this variant for timers which do not yet have
// a target time.
return model.type === 'timer'
&& model.timerState !== 'stopped';
};
StopTimerAction.prototype.perform = function () {
var domainObject = this.domainObject;
function updateModel(model) {
model.timestamp = undefined;
model.timerState = 'stopped';
model.pausedTime = undefined;
}
return domainObject.useCapability('mutation', updateModel);
};
return StopTimerAction;
}
);

View File

@ -1,110 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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([
'moment',
'moment-timezone'
],
function (
moment,
momentTimezone
) {
/**
* Controller for views of a Clock domain object.
*
* @constructor
* @memberof platform/features/clock
* @param {angular.Scope} $scope the Angular scope
* @param {platform/features/clock.TickerService} tickerService
* a service used to align behavior with clock ticks
*/
function ClockController($scope, tickerService) {
var lastTimestamp,
unlisten,
timeFormat,
zoneName,
self = this;
function update() {
var m = zoneName
? moment.utc(lastTimestamp).tz(zoneName) : moment.utc(lastTimestamp);
self.zoneAbbr = m.zoneAbbr();
self.textValue = timeFormat && m.format(timeFormat);
self.ampmValue = m.format("A"); // Just the AM or PM part
}
function tick(timestamp) {
lastTimestamp = timestamp;
update();
}
function updateModel(model) {
var baseFormat;
if (model !== undefined) {
baseFormat = model.clockFormat[0];
self.use24 = model.clockFormat[1] === 'clock24';
timeFormat = self.use24
? baseFormat.replace('hh', "HH") : baseFormat;
// If wrong timezone is provided, the UTC will be used
zoneName = momentTimezone.tz.names().includes(model.timezone)
? model.timezone : "UTC";
update();
}
}
// Pull in the model (clockFormat and timezone) from the domain object model
$scope.$watch('model', updateModel);
// Listen for clock ticks ... and stop listening on destroy
unlisten = tickerService.listen(tick);
$scope.$on('$destroy', unlisten);
}
/**
* Get the clock's time zone, as displayable text.
* @returns {string}
*/
ClockController.prototype.zone = function () {
return this.zoneAbbr;
};
/**
* Get the current time, as displayable text.
* @returns {string}
*/
ClockController.prototype.text = function () {
return this.textValue;
};
/**
* Get the text to display to qualify a time as AM or PM.
* @returns {string}
*/
ClockController.prototype.ampm = function () {
return this.use24 ? '' : this.ampmValue;
};
return ClockController;
}
);

View File

@ -1,55 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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 () {
/**
* Continually refreshes the represented domain object.
*
* This is a short-term workaround to assure Timer views stay
* up-to-date; should be replaced by a global auto-refresh.
*
* @constructor
* @memberof platform/features/clock
* @param {angular.Scope} $scope the Angular scope
* @param {platform/features/clock.TickerService} tickerService
* a service used to align behavior with clock ticks
*/
function RefreshingController($scope, tickerService) {
var unlisten;
function triggerRefresh() {
var persistence = $scope.domainObject
&& $scope.domainObject.getCapability('persistence');
return persistence && persistence.refresh();
}
unlisten = tickerService.listen(triggerRefresh);
$scope.$on('$destroy', unlisten);
}
return RefreshingController;
}
);

View File

@ -1,239 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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(
['./TimerFormatter'],
function (TimerFormatter) {
var FORMATTER = new TimerFormatter();
/**
* Controller for views of a Timer domain object.
*
* @constructor
* @memberof platform/features/clock
* @param {angular.Scope} $scope the Angular scope
* @param $window Angular-provided window object
* @param {Function} now a function which returns the current
* time (typically wrapping `Date.now`)
*/
function TimerController($scope, $window, now) {
var formatter,
active = true,
relativeTimestamp,
lastTimestamp,
relativeTimerState,
self = this;
function update() {
var timeDelta = lastTimestamp - relativeTimestamp;
if (formatter && !isNaN(timeDelta)) {
self.textValue = formatter(timeDelta);
self.signValue = timeDelta < 0 ? "-"
: timeDelta >= 1000 ? "+" : "";
self.signCssClass = timeDelta < 0 ? "icon-minus"
: timeDelta >= 1000 ? "icon-plus" : "";
} else {
self.textValue = "";
self.signValue = "";
self.signCssClass = "";
}
}
function updateFormat(key) {
formatter = FORMATTER[key] || FORMATTER.long;
}
function updateTimestamp(timestamp) {
relativeTimestamp = timestamp;
}
function updateTimerState(timerState) {
self.timerState = relativeTimerState = timerState;
}
function updateActions(actionCapability, actionKey) {
self.relevantAction = actionCapability
&& actionCapability.getActions(actionKey)[0];
self.stopAction = relativeTimerState !== 'stopped'
? actionCapability && actionCapability.getActions('timer.stop')[0] : undefined;
}
function isPaused() {
return relativeTimerState === 'paused';
}
function handleLegacyTimer(model) {
if (model.timerState === undefined) {
model.timerState = model.timestamp === undefined
? 'stopped' : 'started';
}
}
function updateObject(domainObject) {
var model = domainObject.getModel();
handleLegacyTimer(model);
var timestamp = model.timestamp,
formatKey = model.timerFormat,
timerState = model.timerState,
actionCapability = domainObject.getCapability('action'),
actionKey = (timerState !== 'started')
? 'timer.start' : 'timer.pause';
updateFormat(formatKey);
updateTimestamp(timestamp);
updateTimerState(timerState);
updateActions(actionCapability, actionKey);
//if paused on startup show last known position
if (isPaused() && !lastTimestamp) {
lastTimestamp = model.pausedTime;
}
update();
}
function handleObjectChange(domainObject) {
if (domainObject) {
updateObject(domainObject);
}
}
function handleModification() {
handleObjectChange($scope.domainObject);
}
function tick() {
var lastSign = self.signValue,
lastText = self.textValue;
if (!isPaused()) {
lastTimestamp = now();
update();
}
if (relativeTimerState === undefined) {
handleModification();
}
// We're running in an animation frame, not in a digest cycle.
// We need to trigger a digest cycle if our displayable data
// changes.
if (lastSign !== self.signValue || lastText !== self.textValue) {
$scope.$apply();
}
if (active) {
$window.requestAnimationFrame(tick);
}
}
$window.requestAnimationFrame(tick);
// Pull in the timer format from the domain object model
$scope.$watch('domainObject', handleObjectChange);
$scope.$watch('model.modified', handleModification);
// When the scope is destroyed, stop requesting anim. frames
$scope.$on('$destroy', function () {
active = false;
});
this.$scope = $scope;
this.signValue = '';
this.textValue = '';
this.updateObject = updateObject;
}
/**
* Get the CSS class to display the right icon
* for the start/pause button.
* @returns {string} cssclass to display
*/
TimerController.prototype.buttonCssClass = function () {
return this.relevantAction
? this.relevantAction.getMetadata().cssClass : "";
};
/**
* Get the text to show for the start/pause button
* (e.g. in a tooltip)
* @returns {string} name of the action
*/
TimerController.prototype.buttonText = function () {
return this.relevantAction
? this.relevantAction.getMetadata().name : "";
};
/**
* Perform the action associated with the start/pause button.
*/
TimerController.prototype.clickButton = function () {
if (this.relevantAction) {
this.relevantAction.perform();
this.updateObject(this.$scope.domainObject);
}
};
/**
* Perform the action associated with the stop button.
*/
TimerController.prototype.clickStopButton = function () {
if (this.stopAction) {
this.stopAction.perform();
this.updateObject(this.$scope.domainObject);
}
};
/**
* Get the sign (+ or -) of the current timer value, as
* displayable text.
* @returns {string} sign of the current timer value
*/
TimerController.prototype.sign = function () {
return this.signValue;
};
/**
* Get the sign (+ or -) of the current timer value, as
* a CSS class.
* @returns {string} sign of the current timer value
*/
TimerController.prototype.signClass = function () {
return this.signCssClass;
};
/**
* Get the text to display for the current timer value.
* @returns {string} current timer value
*/
TimerController.prototype.text = function () {
return this.textValue;
};
return TimerController;
}
);

View File

@ -1,73 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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(
['moment', 'moment-duration-format'],
function (moment) {
var SHORT_FORMAT = "HH:mm:ss",
LONG_FORMAT = "d[D] HH:mm:ss";
/**
* Provides formatting functions for Timers.
*
* Display formats for timers are a little different from what
* moment.js provides, so we have custom logic here. This specifically
* supports `TimerController`.
*
* @constructor
* @memberof platform/features/clock
*/
function TimerFormatter() {
}
// Round this timestamp down to the second boundary
// (e.g. 1124ms goes down to 1000ms, -2400ms goes down to -3000ms)
function toWholeSeconds(duration) {
return Math.abs(Math.floor(duration / 1000) * 1000);
}
/**
* Format a duration for display, using the short form.
* (e.g. 03:33:11)
* @param {number} duration the duration, in milliseconds
* @param {boolean} sign true if positive
*/
TimerFormatter.prototype.short = function (duration) {
return moment.duration(toWholeSeconds(duration), 'ms')
.format(SHORT_FORMAT, { trim: false });
};
/**
* Format a duration for display, using the long form.
* (e.g. 0d 03:33:11)
* @param {number} duration the duration, in milliseconds
* @param {boolean} sign true if positive
*/
TimerFormatter.prototype.long = function (duration) {
return moment.duration(toWholeSeconds(duration), 'ms')
.format(LONG_FORMAT, { trim: false });
};
return TimerFormatter;
}
);

View File

@ -1,65 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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(
['moment'],
function (moment) {
/**
* Indicator that displays the current UTC time in the status area.
* @implements {Indicator}
* @memberof platform/features/clock
* @param {platform/features/clock.TickerService} tickerService
* a service used to align behavior with clock ticks
* @param {string} indicatorFormat format string for timestamps
* shown in this indicator
*/
function ClockIndicator(tickerService, indicatorFormat) {
var self = this;
this.text = "";
tickerService.listen(function (timestamp) {
self.text = moment.utc(timestamp)
.format(indicatorFormat) + " UTC";
});
}
ClockIndicator.prototype.getGlyphClass = function () {
return "";
};
ClockIndicator.prototype.getCssClass = function () {
return "t-indicator-clock icon-clock no-minify c-indicator--not-clickable";
};
ClockIndicator.prototype.getText = function () {
return this.text;
};
ClockIndicator.prototype.getDescription = function () {
return "";
};
return ClockIndicator;
}
);

View File

@ -1,51 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-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 () {
/**
* Indicator that displays the active timer, as well as its
* current state.
* @memberof platform/features/clock
*/
return function installFollowIndicator(openmct, timerService) {
var indicator = openmct.indicators.simpleIndicator();
var timer = timerService.getTimer();
setIndicatorStatus(timer);
function setIndicatorStatus(newTimer) {
if (newTimer !== undefined) {
indicator.iconClass('icon-timer');
indicator.statusClass('s-status-on');
indicator.text('Following timer ' + newTimer.name);
} else {
indicator.iconClass('icon-timer');
indicator.statusClass('s-status-disabled');
indicator.text('No timer being followed');
}
}
timerService.on('change', setIndicatorStatus);
openmct.indicators.add(indicator);
};
});

View File

@ -1,87 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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 () {
/**
* Calls functions every second, as close to the actual second
* tick as is feasible.
* @constructor
* @memberof platform/features/clock
* @param $timeout Angular's $timeout
* @param {Function} now function to provide the current time in ms
*/
function TickerService($timeout, now) {
var self = this;
function tick() {
var timestamp = now(),
millis = timestamp % 1000;
// Only update callbacks if a second has actually passed.
if (timestamp >= self.last + 1000) {
self.callbacks.forEach(function (callback) {
callback(timestamp);
});
self.last = timestamp - millis;
}
// Try to update at exactly the next second
$timeout(tick, 1000 - millis, true);
}
tick();
this.callbacks = [];
this.last = now() - 1000;
}
/**
* Listen for clock ticks. The provided callback will
* be invoked with the current timestamp (in milliseconds
* since Jan 1 1970) at regular intervals, as near to the
* second boundary as possible.
*
* @param {Function} callback callback to invoke
* @returns {Function} a function to unregister this listener
*/
TickerService.prototype.listen = function (callback) {
var self = this;
self.callbacks.push(callback);
// Provide immediate feedback
callback(this.last);
// Provide a deregistration function
return function () {
self.callbacks = self.callbacks.filter(function (cb) {
return cb !== callback;
});
};
};
return TickerService;
}
);

View File

@ -1,113 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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(['EventEmitter'], function (EventEmitter) {
/**
* Tracks the currently-followed Timer object. Used by
* timelines et al to synchronize to a particular timer.
*
* The TimerService emits `change` events when the active timer
* is changed.
*/
function TimerService(openmct) {
EventEmitter.apply(this);
this.time = openmct.time;
this.objects = openmct.objects;
}
TimerService.prototype = Object.create(EventEmitter.prototype);
/**
* Set (or clear, if `timer` is undefined) the currently active timer.
* @param {DomainObject} timer the new active timer
* @emits change
*/
TimerService.prototype.setTimer = function (timer) {
this.timer = timer;
this.emit('change', timer);
if (this.stopObserving) {
this.stopObserving();
delete this.stopObserving;
}
if (timer) {
this.stopObserving =
this.objects.observe(timer, '*', this.setTimer.bind(this));
}
};
/**
* Get the currently active timer.
* @return {DomainObject} the active timer
* @emits change
*/
TimerService.prototype.getTimer = function () {
return this.timer;
};
/**
* Check if there is a currently active timer.
* @return {boolean} true if there is a timer
*/
TimerService.prototype.hasTimer = function () {
return Boolean(this.timer);
};
/**
* Convert the provided timestamp to milliseconds relative to
* the active timer.
* @return {number} milliseconds since timer start
*/
TimerService.prototype.convert = function (timestamp) {
var clock = this.time.clock();
var canConvert = this.hasTimer()
&& Boolean(clock)
&& this.timer.timerState !== 'stopped';
if (!canConvert) {
return undefined;
}
var now = clock.currentValue();
var delta = this.timer.timerState === 'paused'
? now - this.timer.pausedTime : 0;
var epoch = this.timer.timestamp;
return timestamp - epoch - delta;
};
/**
* Get the value of the active clock, adjusted to be relative to the active
* timer. If there is no clock or no active timer, this will return
* `undefined`.
* @return {number} milliseconds since the start of the active timer
*/
TimerService.prototype.now = function () {
var clock = this.time.clock();
return clock && this.convert(clock.currentValue());
};
return TimerService;
});

View File

@ -1,89 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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/actions/FollowTimerAction"
], function (FollowTimerAction) {
var TIMER_SERVICE_METHODS =
['setTimer', 'getTimer', 'clearTimer', 'on', 'off'];
describe("The Follow Timer action", function () {
var testContext;
var testModel;
var testAdaptedObject;
beforeEach(function () {
testModel = {};
testContext = {
domainObject: jasmine.createSpyObj('domainObject', [
'getModel',
'useCapability'
])
};
testAdaptedObject = { foo: 'bar' };
testContext.domainObject.getModel.and.returnValue(testModel);
testContext.domainObject.useCapability.and.callFake(function (c) {
return c === 'adapter' && testAdaptedObject;
});
});
it("is applicable to timers", function () {
testModel.type = "timer";
expect(FollowTimerAction.appliesTo(testContext)).toBe(true);
});
it("is inapplicable to non-timers", function () {
testModel.type = "folder";
expect(FollowTimerAction.appliesTo(testContext)).toBe(false);
});
describe("when instantiated", function () {
var mockTimerService;
var action;
beforeEach(function () {
mockTimerService = jasmine.createSpyObj(
'timerService',
TIMER_SERVICE_METHODS
);
action = new FollowTimerAction(mockTimerService, testContext);
});
it("does not interact with the timer service", function () {
TIMER_SERVICE_METHODS.forEach(function (method) {
expect(mockTimerService[method]).not.toHaveBeenCalled();
});
});
describe("and performed", function () {
beforeEach(function () {
action.perform();
});
it("sets the active timer", function () {
expect(mockTimerService.setTimer)
.toHaveBeenCalledWith(testAdaptedObject);
});
});
});
});
});

View File

@ -1,106 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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/actions/PauseTimerAction"],
function (PauseTimerAction) {
describe("A timer's Pause action", function () {
var mockNow,
mockDomainObject,
testModel,
testContext,
action;
function asPromise(value) {
return (value || {}).then ? value : {
then: function (callback) {
return asPromise(callback(value));
}
};
}
function testState(type, timerState, timestamp, expected) {
testModel.type = type;
testModel.timerState = timerState;
testModel.timestamp = timestamp;
if (expected) {
expect(PauseTimerAction.appliesTo(testContext)).toBeTruthy();
} else {
expect(PauseTimerAction.appliesTo(testContext)).toBeFalsy();
}
}
beforeEach(function () {
mockNow = jasmine.createSpy('now');
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getCapability', 'useCapability', 'getModel']
);
mockDomainObject.useCapability.and.callFake(function (c, v) {
if (c === 'mutation') {
testModel = v(testModel) || testModel;
return asPromise(true);
}
});
mockDomainObject.getModel.and.callFake(function () {
return testModel;
});
testModel = {};
testContext = {domainObject: mockDomainObject};
action = new PauseTimerAction(mockNow, testContext);
});
it("updates the model with a timerState", function () {
testModel.timerState = 'started';
action.perform();
expect(testModel.timerState).toEqual('paused');
});
it("updates the model with a pausedTime", function () {
testModel.pausedTime = undefined;
mockNow.and.returnValue(12000);
action.perform();
expect(testModel.pausedTime).toEqual(12000);
});
it("applies only to timers in a playing state", function () {
//in a stopped state
testState('timer', 'stopped', undefined, false);
//in a paused state
testState('timer', 'paused', 12000, false);
//in a playing state
testState('timer', 'started', 12000, true);
//not a timer
testState('clock', 'started', 12000, false);
});
});
}
);

View File

@ -1,112 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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/actions/RestartTimerAction"],
function (RestartTimerAction) {
describe("A timer's restart action", function () {
var mockNow,
mockDomainObject,
testModel,
testContext,
action;
function asPromise(value) {
return (value || {}).then ? value : {
then: function (callback) {
return asPromise(callback(value));
}
};
}
function testState(type, timerState, timestamp, expected) {
testModel.type = type;
testModel.timerState = timerState;
testModel.timestamp = timestamp;
if (expected) {
expect(RestartTimerAction.appliesTo(testContext)).toBeTruthy();
} else {
expect(RestartTimerAction.appliesTo(testContext)).toBeFalsy();
}
}
beforeEach(function () {
mockNow = jasmine.createSpy('now');
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getCapability', 'useCapability', 'getModel']
);
mockDomainObject.useCapability.and.callFake(function (c, v) {
if (c === 'mutation') {
testModel = v(testModel) || testModel;
return asPromise(true);
}
});
mockDomainObject.getModel.and.callFake(function () {
return testModel;
});
testModel = {};
testContext = { domainObject: mockDomainObject };
action = new RestartTimerAction(mockNow, testContext);
});
it("updates the model with a timestamp", function () {
testModel.pausedTime = 12000;
mockNow.and.returnValue(12000);
action.perform();
expect(testModel.timestamp).toEqual(12000);
});
it("updates the model with a pausedTime", function () {
testModel.pausedTime = 12000;
action.perform();
expect(testModel.pausedTime).toEqual(undefined);
});
it("updates the model with a timerState", function () {
testModel.timerState = 'stopped';
action.perform();
expect(testModel.timerState).toEqual('started');
});
it("applies only to timers in a non-stopped state", function () {
//in a stopped state
testState('timer', 'stopped', undefined, false);
//in a paused state
testState('timer', 'paused', 12000, true);
//in a playing state
testState('timer', 'started', 12000, true);
//not a timer
testState('clock', 'paused', 12000, false);
});
});
}
);

View File

@ -1,111 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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/actions/StartTimerAction"],
function (StartTimerAction) {
describe("A timer's start action", function () {
var mockNow,
mockDomainObject,
testModel,
testContext,
action;
function asPromise(value) {
return (value || {}).then ? value : {
then: function (callback) {
return asPromise(callback(value));
}
};
}
function testState(type, timerState, timestamp, expected) {
testModel.type = type;
testModel.timerState = timerState;
testModel.timestamp = timestamp;
if (expected) {
expect(StartTimerAction.appliesTo(testContext)).toBeTruthy();
} else {
expect(StartTimerAction.appliesTo(testContext)).toBeFalsy();
}
}
beforeEach(function () {
mockNow = jasmine.createSpy('now');
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getCapability', 'useCapability', 'getModel']
);
mockDomainObject.useCapability.and.callFake(function (c, v) {
if (c === 'mutation') {
testModel = v(testModel) || testModel;
return asPromise(true);
}
});
mockDomainObject.getModel.and.callFake(function () {
return testModel;
});
testModel = {};
testContext = {domainObject: mockDomainObject};
action = new StartTimerAction(mockNow, testContext);
});
it("updates the model with a timestamp", function () {
mockNow.and.returnValue(12000);
action.perform();
expect(testModel.timestamp).toEqual(12000);
});
it("updates the model with a pausedTime", function () {
testModel.pausedTime = 12000;
action.perform();
expect(testModel.pausedTime).toEqual(undefined);
});
it("updates the model with a timerState", function () {
testModel.timerState = undefined;
action.perform();
expect(testModel.timerState).toEqual('started');
});
it("applies only to timers not in a playing state", function () {
//in a stopped state
testState('timer', 'stopped', undefined, true);
//in a paused state
testState('timer', 'paused', 12000, true);
//in a playing state
testState('timer', 'started', 12000, false);
//not a timer
testState('clock', 'paused', 12000, false);
});
});
}
);

View File

@ -1,111 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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/actions/StopTimerAction"],
function (StopTimerAction) {
describe("A timer's stop action", function () {
var mockNow,
mockDomainObject,
testModel,
testContext,
action;
function asPromise(value) {
return (value || {}).then ? value : {
then: function (callback) {
return asPromise(callback(value));
}
};
}
function testState(type, timerState, timestamp, expected) {
testModel.type = type;
testModel.timerState = timerState;
testModel.timestamp = timestamp;
if (expected) {
expect(StopTimerAction.appliesTo(testContext)).toBeTruthy();
} else {
expect(StopTimerAction.appliesTo(testContext)).toBeFalsy();
}
}
beforeEach(function () {
mockNow = jasmine.createSpy('now');
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getCapability', 'useCapability', 'getModel']
);
mockDomainObject.useCapability.and.callFake(function (c, v) {
if (c === 'mutation') {
testModel = v(testModel) || testModel;
return asPromise(true);
}
});
mockDomainObject.getModel.and.callFake(function () {
return testModel;
});
testModel = {};
testContext = {domainObject: mockDomainObject};
action = new StopTimerAction(mockNow, testContext);
});
it("updates the model with a timestamp", function () {
mockNow.and.returnValue(12000);
action.perform();
expect(testModel.timestamp).toEqual(undefined);
});
it("updates the model with a pausedTime", function () {
testModel.pausedTime = 12000;
action.perform();
expect(testModel.pausedTime).toEqual(undefined);
});
it("updates the model with a timerState", function () {
testModel.timerState = 'started';
action.perform();
expect(testModel.timerState).toEqual('stopped');
});
it("applies only to timers in a non-stopped state", function () {
//in a stopped state
testState('timer', 'stopped', undefined, false);
//in a paused state
testState('timer', 'paused', 12000, true);
//in a playing state
testState('timer', 'started', 12000, true);
//not a timer
testState('clock', 'paused', 12000, false);
});
});
}
);

View File

@ -1,107 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-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. 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/controllers/ClockController"],
function (ClockController) {
// Wed, 03 Jun 2015 17:56:14 GMT
var TEST_TIMESTAMP = 1433354174000;
describe("A clock view's controller", function () {
var mockScope,
mockTicker,
mockUnticker,
controller;
beforeEach(function () {
mockScope = jasmine.createSpyObj('$scope', ['$watch', '$on']);
mockTicker = jasmine.createSpyObj('ticker', ['listen']);
mockUnticker = jasmine.createSpy('unticker');
mockTicker.listen.and.returnValue(mockUnticker);
controller = new ClockController(mockScope, mockTicker);
});
it("watches for model (clockFormat and timezone) from the domain object model", function () {
expect(mockScope.$watch).toHaveBeenCalledWith(
"model",
jasmine.any(Function)
);
});
it("subscribes to clock ticks", function () {
expect(mockTicker.listen)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("unsubscribes to ticks when destroyed", function () {
// Make sure $destroy is being listened for...
expect(mockScope.$on.calls.mostRecent().args[0]).toEqual('$destroy');
expect(mockUnticker).not.toHaveBeenCalled();
// ...and makes sure that its listener unsubscribes from ticker
mockScope.$on.calls.mostRecent().args[1]();
expect(mockUnticker).toHaveBeenCalled();
});
it("formats using the format string from the model", function () {
mockTicker.listen.calls.mostRecent().args[0](TEST_TIMESTAMP);
mockScope.$watch.calls.mostRecent().args[1]({
"clockFormat": [
"YYYY-DDD hh:mm:ss",
"clock24"
],
"timezone": "Canada/Eastern"
});
expect(controller.zone()).toEqual("EDT");
expect(controller.text()).toEqual("2015-154 13:56:14");
expect(controller.ampm()).toEqual("");
});
it("formats 12-hour time", function () {
mockTicker.listen.calls.mostRecent().args[0](TEST_TIMESTAMP);
mockScope.$watch.calls.mostRecent().args[1]({
"clockFormat": [
"YYYY-DDD hh:mm:ss",
"clock12"
],
"timezone": ""
});
expect(controller.zone()).toEqual("UTC");
expect(controller.text()).toEqual("2015-154 05:56:14");
expect(controller.ampm()).toEqual("PM");
});
it("does not throw exceptions when model is undefined", function () {
mockTicker.listen.calls.mostRecent().args[0](TEST_TIMESTAMP);
expect(function () {
mockScope.$watch.calls.mostRecent().args[1](undefined);
}).not.toThrow();
});
});
}
);

View File

@ -1,80 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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/controllers/RefreshingController"],
function (RefreshingController) {
describe("The refreshing controller", function () {
var mockScope,
mockTicker,
mockUnticker,
controller;
beforeEach(function () {
mockScope = jasmine.createSpyObj('$scope', ['$on']);
mockTicker = jasmine.createSpyObj('ticker', ['listen']);
mockUnticker = jasmine.createSpy('unticker');
mockTicker.listen.and.returnValue(mockUnticker);
controller = new RefreshingController(mockScope, mockTicker);
});
it("refreshes the represented object on every tick", function () {
var mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getCapability']
),
mockPersistence = jasmine.createSpyObj(
'persistence',
['persist', 'refresh']
);
mockDomainObject.getCapability.and.callFake(function (c) {
return (c === 'persistence') && mockPersistence;
});
mockScope.domainObject = mockDomainObject;
mockTicker.listen.calls.mostRecent().args[0](12321);
expect(mockPersistence.refresh).toHaveBeenCalled();
expect(mockPersistence.persist).not.toHaveBeenCalled();
});
it("subscribes to clock ticks", function () {
expect(mockTicker.listen)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("unsubscribes to ticks when destroyed", function () {
// Make sure $destroy is being listened for...
expect(mockScope.$on.calls.mostRecent().args[0]).toEqual('$destroy');
expect(mockUnticker).not.toHaveBeenCalled();
// ...and makes sure that its listener unsubscribes from ticker
mockScope.$on.calls.mostRecent().args[1]();
expect(mockUnticker).toHaveBeenCalled();
});
});
}
);

View File

@ -1,227 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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/controllers/TimerController"],
function (TimerController) {
// Wed, 03 Jun 2015 17:56:14 GMT
var TEST_TIMESTAMP = 1433354174000;
describe("A timer view's controller", function () {
var mockScope,
mockWindow,
mockNow,
mockDomainObject,
mockActionCapability,
mockStart,
mockPause,
mockStop,
testModel,
controller;
function invokeWatch(expr, value) {
mockScope.$watch.calls.all().forEach(function (call) {
if (call.args[0] === expr) {
call.args[1](value);
}
});
}
beforeEach(function () {
mockScope = jasmine.createSpyObj(
'$scope',
['$watch', '$on', '$apply']
);
mockWindow = jasmine.createSpyObj(
'$window',
['requestAnimationFrame']
);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getCapability', 'useCapability', 'getModel']
);
mockActionCapability = jasmine.createSpyObj(
'action',
['getActions']
);
mockStart = jasmine.createSpyObj(
'start',
['getMetadata', 'perform']
);
mockPause = jasmine.createSpyObj(
'paused',
['getMetadata', 'perform']
);
mockStop = jasmine.createSpyObj(
'stopped',
['getMetadata', 'perform']
);
mockNow = jasmine.createSpy('now');
mockDomainObject.getCapability.and.callFake(function (c) {
return (c === 'action') && mockActionCapability;
});
mockDomainObject.getModel.and.callFake(function () {
return testModel;
});
mockActionCapability.getActions.and.callFake(function (k) {
return [{
'timer.start': mockStart,
'timer.pause': mockPause,
'timer.stop': mockStop
}[k]];
});
mockStart.getMetadata.and.returnValue({
cssClass: "icon-play",
name: "Start"
});
mockPause.getMetadata.and.returnValue({
cssClass: "icon-pause",
name: "Pause"
});
mockStop.getMetadata.and.returnValue({
cssClass: "icon-box",
name: "Stop"
});
mockScope.domainObject = mockDomainObject;
testModel = {};
controller = new TimerController(mockScope, mockWindow, mockNow);
});
it("watches for the domain object in view", function () {
expect(mockScope.$watch).toHaveBeenCalledWith(
"domainObject",
jasmine.any(Function)
);
});
it("watches for domain object modifications", function () {
expect(mockScope.$watch).toHaveBeenCalledWith(
"model.modified",
jasmine.any(Function)
);
});
it("updates on a timer", function () {
expect(mockWindow.requestAnimationFrame)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("displays nothing when there is no target", function () {
// Notify that domain object is available via scope
invokeWatch('domainObject', mockDomainObject);
mockNow.and.returnValue(TEST_TIMESTAMP);
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
expect(controller.sign()).toEqual("");
expect(controller.signClass()).toEqual("");
expect(controller.text()).toEqual("");
});
it("formats time to display relative to target", function () {
testModel.timestamp = TEST_TIMESTAMP;
testModel.timerFormat = 'long';
// Notify that domain object is available via scope
invokeWatch('domainObject', mockDomainObject);
mockNow.and.returnValue(TEST_TIMESTAMP + 121000);
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
expect(controller.sign()).toEqual("+");
expect(controller.signClass()).toEqual("icon-plus");
expect(controller.text()).toEqual("0D 00:02:01");
mockNow.and.returnValue(TEST_TIMESTAMP - 121000);
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
expect(controller.sign()).toEqual("-");
expect(controller.signClass()).toEqual("icon-minus");
expect(controller.text()).toEqual("0D 00:02:01");
mockNow.and.returnValue(TEST_TIMESTAMP);
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
expect(controller.sign()).toEqual("");
expect(controller.signClass()).toEqual("");
expect(controller.text()).toEqual("0D 00:00:00");
});
it("shows cssClass & name for the applicable start/pause action", function () {
invokeWatch('domainObject', mockDomainObject);
expect(controller.buttonCssClass()).toEqual("icon-play");
expect(controller.buttonText()).toEqual("Start");
testModel.timestamp = 12321;
testModel.timerState = 'started';
invokeWatch('model.modified', 1);
expect(controller.buttonCssClass()).toEqual("icon-pause");
expect(controller.buttonText()).toEqual("Pause");
});
it("performs correct start/pause/stop action on click", function () {
//test start
invokeWatch('domainObject', mockDomainObject);
expect(mockStart.perform).not.toHaveBeenCalled();
controller.clickButton();
expect(mockStart.perform).toHaveBeenCalled();
//test pause
testModel.timestamp = 12321;
testModel.timerState = 'started';
invokeWatch('model.modified', 1);
expect(mockPause.perform).not.toHaveBeenCalled();
controller.clickButton();
expect(mockPause.perform).toHaveBeenCalled();
//test stop
expect(mockStop.perform).not.toHaveBeenCalled();
controller.clickStopButton();
expect(mockStop.perform).toHaveBeenCalled();
});
it("stops requesting animation frames when destroyed", function () {
var initialCount = mockWindow.requestAnimationFrame.calls.count();
// First, check that normally new frames keep getting requested
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
expect(mockWindow.requestAnimationFrame.calls.count())
.toEqual(initialCount + 1);
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
expect(mockWindow.requestAnimationFrame.calls.count())
.toEqual(initialCount + 2);
// Now, verify that it stops after $destroy
expect(mockScope.$on.calls.mostRecent().args[0])
.toEqual('$destroy');
mockScope.$on.calls.mostRecent().args[1]();
// Frames should no longer get requested
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
expect(mockWindow.requestAnimationFrame.calls.count())
.toEqual(initialCount + 2);
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
expect(mockWindow.requestAnimationFrame.calls.count())
.toEqual(initialCount + 2);
});
});
}
);

View File

@ -1,111 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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/controllers/TimerFormatter"],
function (TimerFormatter) {
var MS_IN_SEC = 1000,
MS_IN_MIN = MS_IN_SEC * 60,
MS_IN_HR = MS_IN_MIN * 60,
MS_IN_DAY = MS_IN_HR * 24;
describe("The timer value formatter", function () {
var formatter = new TimerFormatter();
function sum(a, b) {
return a + b;
}
function toDuration(days, hours, mins, secs) {
return [
days * MS_IN_DAY,
hours * MS_IN_HR,
mins * MS_IN_MIN,
secs * MS_IN_SEC
].reduce(sum, 0);
}
it("formats short-form values (no days)", function () {
expect(formatter.short(toDuration(0, 123, 2, 3) + 123))
.toEqual("123:02:03");
});
it("formats negative short-form values (no days)", function () {
expect(formatter.short(-toDuration(0, 123, 2, 3) + 123))
.toEqual("123:02:03");
});
it("formats long-form values (with days)", function () {
expect(formatter.long(toDuration(0, 123, 2, 3) + 123))
.toEqual("5D 03:02:03");
});
it("formats negative long-form values (no days)", function () {
expect(formatter.long(-toDuration(0, 123, 2, 3) + 123))
.toEqual("5D 03:02:03");
});
it("rounds seconds down for positive durations", function () {
expect(formatter.short(MS_IN_SEC + 600))
.toEqual("00:00:01");
});
it("rounds seconds up for negative durations", function () {
expect(formatter.short(-MS_IN_SEC - 600))
.toEqual("00:00:02");
});
it("short-formats correctly around negative time borders", function () {
expect(formatter.short(-1)).toEqual("00:00:01");
expect(formatter.short(-1000)).toEqual("00:00:01");
expect(formatter.short(-1001)).toEqual("00:00:02");
expect(formatter.short(-2000)).toEqual("00:00:02");
expect(formatter.short(-59001)).toEqual("00:01:00");
expect(formatter.short(-60000)).toEqual("00:01:00");
expect(formatter.short(-MS_IN_HR + 999)).toEqual("01:00:00");
expect(formatter.short(-MS_IN_HR)).toEqual("01:00:00");
});
it("differentiates between values around zero", function () {
// These are more than 1000 ms apart so should not appear
// as the same second
expect(formatter.short(-999))
.not.toEqual(formatter.short(999));
});
it("handles negative days", function () {
expect(formatter.long(-10 * MS_IN_DAY))
.toEqual("10D 00:00:00");
expect(formatter.long(-10 * MS_IN_DAY + 100))
.toEqual("10D 00:00:00");
expect(formatter.long(-10 * MS_IN_DAY + 999))
.toEqual("10D 00:00:00");
expect(formatter.short(-10 * MS_IN_DAY + 100))
.toEqual("240:00:00");
});
});
}
);

View File

@ -1,58 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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/indicators/ClockIndicator"],
function (ClockIndicator) {
// Wed, 03 Jun 2015 17:56:14 GMT
var TEST_TIMESTAMP = 1433354174000,
TEST_FORMAT = "YYYY-DDD HH:mm:ss";
describe("The clock indicator", function () {
var mockTicker,
mockUnticker,
indicator;
beforeEach(function () {
mockTicker = jasmine.createSpyObj('ticker', ['listen']);
mockUnticker = jasmine.createSpy('unticker');
mockTicker.listen.and.returnValue(mockUnticker);
indicator = new ClockIndicator(mockTicker, TEST_FORMAT);
});
it("displays the current time", function () {
mockTicker.listen.calls.mostRecent().args[0](TEST_TIMESTAMP);
expect(indicator.getText()).toEqual("2015-154 17:56:14 UTC");
});
it("implements the Indicator interface", function () {
expect(indicator.getCssClass()).toEqual(jasmine.any(String));
expect(indicator.getText()).toEqual(jasmine.any(String));
expect(indicator.getDescription()).toEqual(jasmine.any(String));
});
});
}
);

View File

@ -1,96 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-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/indicators/FollowIndicator",
"../../src/services/TimerService",
"../../../../../src/MCT",
'zepto'
], function (
FollowIndicator,
TimerService,
MCT,
$
) {
xdescribe("The timer-following indicator", function () {
var timerService;
var openmct;
beforeEach(function () {
openmct = new MCT();
timerService = new TimerService(openmct);
spyOn(openmct.indicators, "add");
});
it("adds an indicator when installed", function () {
FollowIndicator(openmct, timerService);
expect(openmct.indicators.add).toHaveBeenCalled();
});
it("indicates that no timer is being followed", function () {
FollowIndicator(openmct, timerService);
var simpleIndicator = openmct.indicators.add.calls.mostRecent().args[0];
var element = simpleIndicator.element;
var text = $('.indicator-text', element).text().trim();
expect(text).toEqual('No timer being followed');
});
describe("when a timer is set", function () {
var testObject;
var simpleIndicator;
beforeEach(function () {
testObject = {
identifier: {
namespace: 'namespace',
key: 'key'
},
name: "some timer!"
};
timerService.setTimer(testObject);
FollowIndicator(openmct, timerService);
simpleIndicator = openmct.indicators.add.calls.mostRecent().args[0];
});
it("displays the timer's name", function () {
var element = simpleIndicator.element;
var text = $('.indicator-text', element).text().trim();
expect(text).toEqual('Following timer ' + testObject.name);
});
it("displays the timer's name when it changes", function () {
var secondTimer = {
identifier: {
namespace: 'namespace',
key: 'key2'
},
name: "Some other timer"
};
var element = simpleIndicator.element;
timerService.setTimer(secondTimer);
var text = $('.indicator-text', element).text().trim();
expect(text).toEqual('Following timer ' + secondTimer.name);
});
});
});
});

View File

@ -1,62 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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/services/TickerService"],
function (TickerService) {
var TEST_TIMESTAMP = 1433354174000;
describe("The ticker service", function () {
var mockTimeout,
mockNow,
mockCallback,
tickerService;
beforeEach(function () {
mockTimeout = jasmine.createSpy('$timeout');
mockNow = jasmine.createSpy('now');
mockCallback = jasmine.createSpy('callback');
mockNow.and.returnValue(TEST_TIMESTAMP);
tickerService = new TickerService(mockTimeout, mockNow);
});
it("notifies listeners of clock ticks", function () {
tickerService.listen(mockCallback);
mockNow.and.returnValue(TEST_TIMESTAMP + 12321);
mockTimeout.calls.mostRecent().args[0]();
expect(mockCallback)
.toHaveBeenCalledWith(TEST_TIMESTAMP + 12321);
});
it("allows listeners to unregister", function () {
tickerService.listen(mockCallback)(); // Unregister immediately
mockNow.and.returnValue(TEST_TIMESTAMP + 12321);
mockTimeout.calls.mostRecent().args[0]();
expect(mockCallback).not
.toHaveBeenCalledWith(TEST_TIMESTAMP + 12321);
});
});
}
);

View File

@ -1,77 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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/services/TimerService'
], function (TimerService) {
describe("TimerService", function () {
var callback;
var mockmct;
var timerService;
beforeEach(function () {
callback = jasmine.createSpy('callback');
mockmct = {
time: { clock: jasmine.createSpy('clock') },
objects: { observe: jasmine.createSpy('observe') }
};
timerService = new TimerService(mockmct);
timerService.on('change', callback);
});
it("initially emits no change events", function () {
expect(callback).not.toHaveBeenCalled();
});
it("reports no current timer", function () {
expect(timerService.getTimer()).toBeUndefined();
});
describe("setTimer", function () {
var testTimer;
beforeEach(function () {
testTimer = { name: "I am some timer; you are nobody." };
timerService.setTimer(testTimer);
});
it("emits a change event", function () {
expect(callback).toHaveBeenCalled();
});
it("reports the current timer", function () {
expect(timerService.getTimer()).toBe(testTimer);
});
it("observes changes to an object", function () {
var newTimer = { name: "I am another timer." };
expect(mockmct.objects.observe).toHaveBeenCalledWith(
testTimer,
'*',
jasmine.any(Function)
);
mockmct.objects.observe.calls.mostRecent().args[2](newTimer);
expect(timerService.getTimer()).toBe(newTimer);
});
});
});
});

View File

@ -1,120 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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/HyperlinkController',
'./res/templates/hyperlink.html'
], function (
HyperlinkController,
hyperlinkTemplate
) {
return {
name: "platform/features/hyperlink",
definition: {
"name": "Hyperlink",
"description": "Insert a hyperlink to reference a link",
"extensions": {
"types": [
{
"key": "hyperlink",
"name": "Hyperlink",
"cssClass": "icon-chain-links",
"description": "A hyperlink to redirect to a different link",
"features": ["creation"],
"properties": [
{
"key": "url",
"name": "URL",
"control": "textfield",
"required": true,
"cssClass": "l-input-lg"
},
{
"key": "displayText",
"name": "Text to Display",
"control": "textfield",
"required": true,
"cssClass": "l-input-lg"
},
{
"key": "displayFormat",
"name": "Display Format",
"control": "select",
"options": [
{
"name": "Link",
"value": "link"
},
{
"value": "button",
"name": "Button"
}
],
"cssClass": "l-inline"
},
{
"key": "openNewTab",
"name": "Tab to Open Hyperlink",
"control": "select",
"options": [
{
"name": "Open in this tab",
"value": "thisTab"
},
{
"value": "newTab",
"name": "Open in a new tab"
}
],
"cssClass": "l-inline"
}
],
"model": {
"displayFormat": "link",
"openNewTab": "thisTab",
"removeTitle": true
}
}
],
"views": [
{
"key": "hyperlink",
"type": "hyperlink",
"name": "Hyperlink Display",
"template": hyperlinkTemplate,
"editable": false
}
],
"controllers": [
{
"key": "HyperlinkController",
"implementation": HyperlinkController,
"depends": ["$scope"]
}
]
}
}
};
});

View File

@ -1,61 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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 adds the Hyperlink object type, which can be used to add hyperlinks as a domain Object type
and into display Layouts as either a button or link that can be chosen to open in either the same tab or
create a new tab to open the link in
* @namespace platform/features/hyperlink
*/
define(
[],
function () {
function HyperlinkController($scope) {
this.$scope = $scope;
}
/**Function to analyze the location in which to open the hyperlink
@returns true if the hyperlink is chosen to open in a different tab, false if the same tab
**/
HyperlinkController.prototype.openNewTab = function () {
if (this.$scope.domainObject.getModel().openNewTab === "thisTab") {
return false;
} else {
return true;
}
};
/**Function to specify the format in which the hyperlink should be created
@returns true if the hyperlink is chosen to be created as a button, false if a link
**/
HyperlinkController.prototype.isButton = function () {
if (this.$scope.domainObject.getModel().displayFormat === "link") {
return false;
}
return true;
};
return HyperlinkController;
}
);

View File

@ -1,89 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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/HyperlinkController"],
function (HyperlinkController) {
describe("The controller for hyperlinks", function () {
var domainObject,
controller,
scope;
beforeEach(function () {
scope = jasmine.createSpyObj(
"$scope",
["domainObject"]
);
domainObject = jasmine.createSpyObj(
"domainObject",
["getModel"]
);
scope.domainObject = domainObject;
controller = new HyperlinkController(scope);
});
it("knows when it should open a new tab", function () {
scope.domainObject.getModel.and.returnValue({
"displayFormat": "link",
"openNewTab": "newTab",
"showTitle": false
}
);
controller = new HyperlinkController(scope);
expect(controller.openNewTab())
.toBe(true);
});
it("knows when it is a button", function () {
scope.domainObject.getModel.and.returnValue({
"displayFormat": "button",
"openNewTab": "thisTab",
"showTitle": false
}
);
controller = new HyperlinkController(scope);
expect(controller.isButton())
.toEqual(true);
});
it("knows when it should open in the same tab", function () {
scope.domainObject.getModel.and.returnValue({
"displayFormat": "link",
"openNewTab": "thisTab",
"showTitle": false
}
);
controller = new HyperlinkController(scope);
expect(controller.openNewTab())
.toBe(false);
});
it("knows when it is a link", function () {
scope.domainObject.getModel.and.returnValue({
"displayFormat": "link",
"openNewTab": "thisTab",
"showTitle": false
}
);
controller = new HyperlinkController(scope);
expect(controller.openNewTab())
.toBe(false);
});
});
}
);

Some files were not shown because too many files have changed in this diff Show More