diff --git a/.eslintrc.js b/.eslintrc.js index 03a5b1fefe..76c78fb181 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,4 +1,4 @@ -const LEGACY_FILES = ["platform/**", "example/**"]; +const LEGACY_FILES = ["example/**"]; module.exports = { "env": { "browser": true, diff --git a/README.md b/README.md index 075408bc96..5f1ed200ac 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,22 @@ Once you've created something amazing with Open MCT, showcase your work in our G Try Open MCT now with our [live demo](https://openmct-demo.herokuapp.com/). ![Demo](https://nasa.github.io/openmct/static/res/images/Open-MCT.Browse.Layout.Mars-Weather-1.jpg) +## Open MCT v2.0.0 +Support for our legacy bundle-based API, and the libraries that it was built on (like Angular 1.x), have now been removed entirely from this repository. + +For now if you have an Open MCT application that makes use of the legacy API, [a plugin](https://github.com/nasa/openmct-legacy-plugin) is provided that bootstraps the legacy bundling mechanism and API. This plugin will not be maintained over the long term however, and the legacy support plugin will not be tested for compatibility with future versions of Open MCT. It is provided for convenience only. + +### How do I know if I am using legacy API? +You might still be using legacy API if your source code + +* Contains files named bundle.js, or bundle.json, +* Makes calls to `openmct.$injector()`, or `openmct.$angular`, +* Makes calls to `openmct.legacyRegistry`, `openmct.legacyExtension`, or `openmct.legacyBundle`. + + +### What should I do if I am using legacy API? +Please refer to [the modern Open MCT API](https://nasa.github.io/openmct/documentation/). Post any questions to the [Discussions section](https://github.com/nasa/openmct/discussions) of the Open MCT GitHub repository. + ## Building and Running Open MCT Locally Building and running Open MCT in your local dev environment is very easy. Be sure you have [Git](https://git-scm.com/downloads) and [Node.js](https://nodejs.org/) installed, then follow the directions below. Need additional information? Check out the [Getting Started](https://nasa.github.io/openmct/getting-started/) page on our website. @@ -30,11 +46,6 @@ Building and running Open MCT in your local dev environment is very easy. Be sur Open MCT is now running, and can be accessed by pointing a web browser at [http://localhost:8080/](http://localhost:8080/) -## Open MCT v1.0.0 -This represents a major overhaul of Open MCT with significant changes under the hood. We aim to maintain backward compatibility but if you do find compatibility issues, please let us know by filing an issue in this repository. If you are having major issues with v1.0.0 please check-out the v0.14.0 tag until we can resolve them for you. - -If you are migrating an application built with Open MCT as a dependency to v1.0.0 from an earlier version, please refer to [our migration guide](https://nasa.github.io/openmct/documentation/migration-guide). - ## Documentation Documentation is available on the [Open MCT website](https://nasa.github.io/openmct/documentation/). diff --git a/docs/src/architecture/framework.md b/docs/src/architecture/framework.md deleted file mode 100644 index 78adb98158..0000000000 --- a/docs/src/architecture/framework.md +++ /dev/null @@ -1,232 +0,0 @@ -# Overview - -The framework layer's most basic responsibility is allowing individual -software components to communicate. The software components it recognizes -are: - -* _Extensions_: Individual units of functionality that can be added to - or removed from Open MCT. _Extension categories_ distinguish what - type of functionality is being added/removed. -* _Bundles_: A grouping of related extensions - (named after an analogous concept from [OSGi](http://www.osgi.org/)) - that may be added or removed as a group. - -The framework layer operates by taking a set of active bundles, and -exposing extensions to one another as-needed, using -[dependency injection](https://en.wikipedia.org/wiki/Dependency_injection). -Extensions are responsible for declaring their dependencies in a -manner which the framework layer can understand. - -```nomnoml -#direction: down -[Open MCT| - [Dependency injection framework]-->[Platform bundle #1] - [Dependency injection framework]-->[Platform bundle #2] - [Dependency injection framework]-->[Plugin bundle #1] - [Dependency injection framework]-->[Plugin bundle #2] - [Platform bundle #1|[Extensions]] - [Platform bundle #2|[Extensions]] - [Plugin bundle #1|[Extensions]] - [Plugin bundle #2|[Extensions]] - [Platform bundle #1]<->[Platform bundle #2] - [Plugin bundle #1]<->[Platform bundle #2] - [Plugin bundle #1]<->[Plugin bundle #2] -] -``` - -The "dependency injection framework" in this case is -[AngularJS](https://angularjs.org/). Open MCT's framework layer -is really just a thin wrapper over Angular that recognizes the -concepts of bundles and extensions (as declared in JSON files) and -registering extensions with Angular. It additionally acts as a -mediator between Angular and [RequireJS](http://requirejs.org/), -which is used to load JavaScript sources which implement -extensions. - -```nomnoml -[Framework layer| - [AngularJS]<-[Framework Component] - [RequireJS]<-[Framework Component] - [Framework Component]1o-*[Bundles] -] -``` - -It is worth noting that _no other components_ are "aware" of the -framework component directly; Angular and Require are _used by_ the -framework components, and extensions in various bundles will have -their dependencies satisfied by Angular as a consequence of registration -activities which were performed by the framework component. - - -## Application Initialization - -The framework component initializes an Open MCT application following -a simple sequence of steps. - -```nomnoml -[ Start]->[ Load bundles.json] -[Load bundles.json]->[ Load bundle.json files] -[Load bundle.json files]->[ Resolve implementations] -[Resolve implementations]->[ Register with Angular] -[Register with Angular]->[ Bootstrap application] -[Bootstrap application]->[ End] -``` - -1. __Loading bundles.json.__ A file named `bundles.json` is loaded to determine - which bundles to load. Bundles are given in this file as relative paths - which point to bundle directories. -2. __Load bundle.json files.__ Individual bundle definitions are loaded; a - `bundle.json` file is expected in each bundle directory. -2. __Resolving implementations.__ Any scripts which provide implementations for - extensions exposed by bundles are loaded, using RequireJS. -3. __Register with Angular.__ Resolved extensions are registered with Angular, - such that they can be used by the application at run-time. This stage - includes both registration of Angular built-ins (directives, controllers, - routes, constants, and services) as well as registration of non-Angular - extensions. -4. __Bootstrap application.__ Once all extensions have been registered, - the Angular application - [is bootstrapped](https://docs.angularjs.org/guide/bootstrap). - -## Architectural Paradigm - -```nomnoml -[Extension] -[Extension]o->[Dependency #1] -[Extension]o->[Dependency #2] -[Extension]o->[Dependency #3] -``` - -Open MCT's architecture relies on a simple premise: Individual units -(extensions) only have access to the dependencies they declare that they -need, and they acquire references to these dependencies via dependency -injection. This has several desirable traits: - -* Programming to an interface is enforced. Any given dependency can be - swapped out for something which exposes an equivalent interface. This - improves flexibility against refactoring, simplifies testing, and - provides a common mechanism for extension and reconfiguration. -* The dependencies of a unit must be explicitly defined. This means that - it can be easily determined what a given unit's role is within the - larger system, in terms of what other components it will interact with. - It also helps to enforce good separation of concerns: When a set of - declared dependencies becomes long it is obvious, and this is usually - a sign that a given unit is involved in too many concerns and should - be refactored into smaller pieces. -* Individual units do not need to be aware of the framework; they need - only be aware of the interfaces to the components they specifically - use. This avoids introducing a ubiquitous dependency upon the framework - layer itself; it is plausible to modify or replace the framework - without making changes to individual software components which run upon - the framework. - -A drawback to this approach is that it makes it difficult to define -"the architecture" of Open MCT, in terms of describing the specific -units that interact at run-time. The run-time architecture is determined -by the framework as the consequence of wiring together dependencies. -As such, the specific architecture of any given application built on -Open MCT can look very different. - -Keeping that in mind, there are a few useful patterns supported by the -framework that are useful to keep in mind. - -The specific service infrastructure provided by the platform is described -in the [Platform Architecture](platform.md). - -## Extension Categories - -One of the capabilities that the framework component layers on top of -AngularJS is support for many-to-one dependencies. That is, a specific -extension may declare a dependency to _all extensions of a specific -category_, instead of being limited to declaring specific dependencies. - -```nomnoml -#direction: right -[Specific Extension] 1 o-> * [Extension of Some Category] -``` - -This is useful for introducing specific extension points to an application. -Some unit of software will depend upon all extensions of a given category -and integrate their behavior into the system in some fashion; plugin authors -can then add new extensions of that category to augment existing behaviors. - -Some developers may be familiar with the use of registries to achieve -similar characteristics. This approach is similar, except that the registry -is effectively implicit whenever a new extension category is used or -depended-upon. This has some advantages over a more straightforward -registry-based approach: - -* These many-to-one relationships are expressed as dependencies; an - extension category is registered as having dependencies on all individual - extensions of this category. This avoids ordering issues that may occur - with more conventional registries, which may be observed before all - dependencies are resolved. -* The need for service registries of specific types is removed, reducing - the number of interfaces to manage within the system. Groups of - extensions are provided as arrays. - -## Composite Services - -Composite services (registered via extension category `components`) are -a pattern supported by the framework. These allow service instances to -be built from multiple components at run-time; support for this pattern -allows additional bundles to introduce or modify behavior associated -with these services without modifying or replacing original service -instances. - -```nomnoml -#direction: down -[ FooService] -[FooDecorator #1]--:>[FooService] -[FooDecorator #n]--:>[FooService] -[FooAggregator]--:>[FooService] -[FooProvider #1]--:>[FooService] -[FooProvider #n]--:>[FooService] - -[FooDecorator #1]o->[ ...decorators...] -[...decorators...]o->[FooDecorator #n] -[FooDecorator #n]o->[FooAggregator] -[FooAggregator]o->[FooProvider #1] -[FooAggregator]o->[ ...providers...] -[FooAggregator]o->[FooProvider #n] - -[FooDecorator #1]--[ Exposed as fooService] -``` - -In this pattern, components all implement an interface which is -standardized for that service. Components additionally declare -that they belong to one of three types: - -* __Providers.__ A provider actually implements the behavior - (satisfies the contract) for that kind of service. For instance, - if a service is responsible for looking up documents by an identifier, - one provider may do so by querying a database, while another may - do so by reading a static JSON document. From the outside, either - provider would look the same (they expose the same interface) and - they could be swapped out easily. -* __Aggregator.__ An aggregator takes many providers and makes them - behave as one. Again, this implements the same interface as an - individual provider, so users of the service do not need to be - concerned about the difference between consulting many providers - and consulting one. Continuing with the example of a service that - looks up documents by identifiers, an aggregator here might consult - all providers, and return any document is found (perhaps picking one - over the other or merging documents if there are multiple matches.) -* __Decorators.__ A decorator exposes the same interface as other - components, but instead of fully implementing the behavior associated - with that kind of service, it only acts as an intermediary, delegating - the actual behavior to a different component. Decorators may transform - inputs or outputs, or initiate some side effects associated with a - service. This is useful if certain common behavior associated with a - service (caching, for instance) may be useful across many different - implementations of that same service. - -The framework will register extensions in this category such that an -aggregator will depend on all of its providers, and decorators will -depend upon on one another in a chain. The result of this compositing step -(the last decorator, if any; otherwise the aggregator, if any; -otherwise a single provider) will be exposed as a single service that -other extensions can acquire through dependency injection. Because all -components of the same type of service expose the same interface, users -of that service do not need to be aware that they are talking to an -aggregator or a provider, for instance. diff --git a/docs/src/architecture/index.md b/docs/src/architecture/index.md deleted file mode 100644 index 6f2fbcfcef..0000000000 --- a/docs/src/architecture/index.md +++ /dev/null @@ -1,76 +0,0 @@ -# Introduction - -The purpose of this document is to familiarize developers with the -overall architecture of Open MCT. - -The target audience includes: - -* _Platform maintainers_: Individuals involved in developing, - extending, and maintaining capabilities of the platform. -* _Integration developers_: Individuals tasked with integrated - Open MCT into a larger system, who need to understand - its inner workings sufficiently to complete this integration. - -As the focus of this document is on architecture, whenever possible -implementation details (such as relevant API or JSON syntax) have been -omitted. These details may be found in the developer guide. - -# Overview - -Open MCT is client software: It runs in a web browser and -provides a user interface, while communicating with various -server-side resources through browser APIs. - -```nomnoml -#direction: right -[Client|[Browser|[Open MCT]->[Browser APIs]]] -[Server|[Web services]] -[Client]<->[Server] -``` - -While Open MCT can be configured to run as a standalone client, -this is rarely very useful. Instead, it is intended to be used as a -display and interaction layer for information obtained from a -variety of back-end services. Doing so requires authoring or utilizing -adapter plugins which allow Open MCT to interact with these services. - -Typically, the pattern here is to provide a known interface that -Open MCT can utilize, and implement it such that it interacts with -whatever back-end provides the relevant information. -Examples of back-ends that can be utilized in this fashion include -databases for the persistence of user-created objects, or sources of -telemetry data. - -## Software Architecture - -The simplest overview of Open MCT is to look at it as a "layered" -architecture, where each layer more clearly specifies the behavior -of the software. - -```nomnoml -#direction: down -[Open MCT| - [Platform]<->[Application] - [Framework]->[Application] - [Framework]->[Platform] -] -``` - -These layers are: - -* [_Framework_](framework.md): The framework layer is responsible for - managing the interactions between application components. It has no - application-specific knowledge; at this layer, we have only - established an abstraction by which different software components - may communicate and/or interact. -* [_Platform_](platform.md): The platform layer defines the general look, - feel, and behavior of Open MCT. This includes user-facing components like - Browse mode and Edit mode, as well as underlying elements of the - information model and the general service infrastructure. -* _Application_: The application layer defines specific features of - an application built on Open MCT. This includes adapters to - specific back-ends, new types of things for users to create, and - new ways of visualizing objects within the system. This layer - typically consists of a mix of custom plug-ins to Open MCT, - as well as optional features (such as Plot view) included alongside - the platform. diff --git a/docs/src/architecture/platform.md b/docs/src/architecture/platform.md deleted file mode 100644 index 48ceebb9ef..0000000000 --- a/docs/src/architecture/platform.md +++ /dev/null @@ -1,726 +0,0 @@ -# Overview - -The Open MCT platform utilizes the [framework layer](framework.md) -to provide an extensible baseline for applications which includes: - -* A common user interface (and user interface paradigm) for dealing with - domain objects of various sorts. -* A variety of extension points for introducing new functionality - of various kinds within the context of the common user interface. -* A service infrastructure to support building additional components. - -## Platform Architecture - -While the framework provides a more general architectural paradigm for -building application, the platform adds more specificity by defining -additional extension types and allowing for integration with back end -components. - -The run-time architecture of an Open MCT application can be categorized -into certain high-level tiers: - -```nomnoml -[DOM]->[ AngularJS] -[AngularJS]->[Presentation Layer] -[Presentation Layer]->[Information Model] -[Presentation Layer]->[Service Infrastructure] -[Information Model]->[Service Infrastructure] -[Service Infrastructure]->[ Browser APIs] -[Browser APIs]->[Back-end] -``` - -Applications built using Open MCT may add or configure functionality -in __any of these tiers__. - -* _DOM_: The rendered HTML document, composed from HTML templates which - have been processed by AngularJS and will be updated by AngularJS - to reflect changes from the presentation layer. User interactions - are initiated from here and invoke behavior in the presentation layer. HTML  - templates are written in Angular’s template syntax; see the [Angular documentation on templates](https://docs.angularjs.org/guide/templates)​.  - These describe the page as actually seen by the user. Conceptually,  - stylesheets (controlling the look-and-feel of the rendered templates) belong  - in this grouping as well.  -* [_Presentation layer_](#presentation-layer): The presentation layer - is responsible for updating (and providing information to update) - the displayed state of the application. The presentation layer consists - primarily of _controllers_ and _directives_. The presentation layer is - concerned with inspecting the information model and preparing it for - display. -* [_Information model_](#information-model): ​Provides a common (within Open MCT  - Web) set of interfaces for dealing with “things” ­ domain objects ­ within the  - system. User-facing concerns in a Open MCT Web application are expressed as  - domain objects; examples include folders (used to organize other domain  - objects), layouts (used to build displays), or telemetry points (used as  - handles for streams of remote measurements.) These domain objects expose a  - common set of interfaces to allow reusable user interfaces to be built in the  - presentation and template tiers; the specifics of these behaviors are then  - mapped to interactions with underlying services.  -* [_Service infrastructure_](#service-infrastructure): The service - infrastructure is responsible for providing the underlying general - functionality needed to support the information model. This includes - exposing underlying sets of extensions and mediating with the - back-end. -* _Back-end_: The back-end is out of the scope of Open MCT, except - for the interfaces which are utilized by adapters participating in the - service infrastructure. Includes the underlying persistence stores, telemetry  - streams, and so forth which the Open MCT Web client is being used to interact  - with. - -## Application Start-up - -Once the -[application has been initialized](Framework.md#application-initialization) -Open MCT primarily operates in an event-driven paradigm; various -events (mouse clicks, timers firing, receiving responses to XHRs) trigger -the invocation of functions, typically in the presentation layer for -user actions or in the service infrastructure for server responses. - -The "main point of entry" into an initialized Open MCT application -is effectively the -[route](https://docs.angularjs.org/api/ngRoute/service/$route#example) -which is associated with the URL used to access Open MCT (or a -default route.) This route will be associated with a template which -will be displayed; this template will include references to directives -and controllers which will be interpreted by Angular and used to -initialize the state of the display in a manner which is backed by -both the information model and the service infrastructure. - -```nomnoml -[ Start]->[ page load] -[page load]->[ route selection] -[route selection]->[ compile, display template] -[compile, display template]->[Template] -[Template]->[ use Controllers] -[Template]->[ use Directives] -[use Controllers]->[Controllers] -[use Directives]->[Directives] -[Controllers]->[ consult information model] -[consult information model]->[ expose data] -[expose data]->[Angular] -[Angular]->[ update display] -[Directives]->[ add event listeners] -[Directives]->[ update display] -[add event listeners]->[ End] -[update display]->[ End] -``` - - -# Presentation Layer - -The presentation layer of Open MCT is responsible for providing -information to display within templates, and for handling interactions -which are initiated from templated DOM elements. AngularJS acts as -an intermediary between the web page as the user sees it, and the -presentation layer implemented as Open MCT extensions. - -```nomnoml -[Presentation Layer| - [Angular built-ins| - [routes] - [controllers] - [directives] - [templates] - ] - [Domain object representation| - [views] - [representations] - [representers] - [gestures] - ] -] -``` - -## Angular built-ins - -Several extension categories in the presentation layer map directly -to primitives from AngularJS: - -* [_Controllers_](https://docs.angularjs.org/guide/controller) provide - data to templates, and expose functionality that can be called from - templates. -* [_Directives_](https://docs.angularjs.org/guide/directive) effectively - extend HTML to provide custom behavior associated with specific - attributes and tags. -* [_Routes_](https://docs.angularjs.org/api/ngRoute/service/$route#example) - are used to associate specific URLs (including the fragment identifier) - with specific application states. (In Open MCT, these are used to - describe the mode of usage - e.g. browse or edit - as well as to - identify the object being used.) -* [_Templates_](https://docs.angularjs.org/guide/templates) are partial - HTML documents that will be rendered and kept up-to-date by AngularJS. - Open MCT introduces a custom `mct-include` directive which acts - as a wrapper around `ng-include` to allow templates to be referred - to by symbolic names. - -## Domain object representation - -The remaining extension categories in the presentation layer are specific -to displaying domain objects. - -* _Representations_ are templates that will be used to display - domain objects in specific ways (e.g. "as a tree node.") -* _Views_ are representations which are exposed to the user as options - for displaying domain objects. -* _Representers_ are extensions which modify or augment the process - of representing domain objects generally (e.g. by attaching - gestures to them.) -* _Gestures_ provide associations between specific user actions - (expressed as DOM events) and resulting behavior upon domain objects - (typically expressed as members of the `actions` extension category) - that can be reused across domain objects. For instance, `drag` and - `drop` are both gestures associated with using drag-and-drop to - modify the composition of domain objects by interacting with their - representations. - -# Information Model - -```nomnoml -#direction: right -[Information Model| - [DomainObject| - getId() : string - getModel() : object - getCapability(key : string) : Capability - hasCapability(key : string) : boolean - useCapability(key : string, args...) : * - ] - [DomainObject] 1 +- 1 [Model] - [DomainObject] 1 o- * [Capability] -] -``` - -Domain objects are the most fundamental component of Open MCT's -information model. A domain object is some distinct thing relevant to a -user's work flow, such as a telemetry channel, display, or similar. -Open MCT is a tool for viewing, browsing, manipulating, and otherwise -interacting with a graph of domain objects. - -A domain object should be conceived of as the union of the following: - -* _Identifier_: A machine-readable string that uniquely identifies the - domain object within this application instance. -* _Model_: The persistent state of the domain object. A domain object's - model is a JavaScript object that can be losslessly converted to JSON. -* _Capabilities_: Dynamic behavior associated with the domain object. - Capabilities are JavaScript objects which provide additional methods - for interacting with the domain objects which expose those capabilities. - Not all domain objects expose all capabilities. The interface exposed - by any given capability will depend on its type (as identified - by the `key` argument.) For instance, a `persistence` capability - has a different interface from a `telemetry` capability. Using - capabilities requires some prior knowledge of their interface. - -## Capabilities and Services - -```nomnoml -#direction: right -[DomainObject]o-[FooCapability] -[FooCapability]o-[FooService] -[FooService]o-[foos] -``` - -At run-time, the user is primarily concerned with interacting with -domain objects. These interactions are ultimately supported via back-end -services, but to allow customization per-object, these are often mediated -by capabilities. - -A common pattern that emerges in the Open MCT Platform is as follows: - -* A `DomainObject` has some particular behavior that will be supported - by a service. -* A `Capability` of that domain object will define that behavior, - _for that domain object_, supported by a service. -* A `Service` utilized by that capability will perform the actual behavior. -* An extension category will be utilized by that capability to determine - the set of possible behaviors. - -Concrete examples of capabilities which follow this pattern -(or a subset of this pattern) include: - -```nomnoml -#direction: right -[DomainObject]1 o- *[Capability] -[Capability]<:--[TypeCapability] -[Capability]<:--[ActionCapability] -[Capability]<:--[PersistenceCapability] -[Capability]<:--[TelemetryCapability] -[TypeCapability]o-[TypeService] -[TypeService]o-[types] -[ActionCapability]o-[ActionService] -[ActionService]o-[actions] -[PersistenceCapability]o-[PersistenceService] -[TelemetryCapability]o-[TelemetryService] -``` - -# Service Infrastructure - -Most services exposed by the Open MCT platform follow the -[composite services](Framework.md#composite-services) to permit -a higher degree of flexibility in how a service can be modified -or customized for specific applications. - -To simplify usage for plugin developers, the platform also usually -includes a provider implementation for these service type that consumes -some extension category. For instance, an `ActionService` provider is -included which depends upon extension category `actions`, and exposes -all actions declared as such to the system. As such, plugin developers -can simply implement the new actions they wish to be made available without -worrying about the details of composite services or implementing a new -`ActionService` provider; however, the ability to implement a new provider -remains useful when the expressive power of individual extensions is -insufficient. - -```nomnoml -[ Service Infrastructure | - [ObjectService]->[ModelService] - [ModelService]->[PersistenceService] - [ObjectService]->[CapabilityService] - [CapabilityService]->[capabilities] - [capabilities]->[TelemetryService] - [capabilities]->[PersistenceService] - [capabilities]->[TypeService] - [capabilities]->[ActionService] - [capabilities]->[ViewService] - [PersistenceService]->[ Document store] - [TelemetryService]->[ Telemetry source] - [ActionService]->[actions] - [ActionService]->[PolicyService] - [ViewService]->[PolicyService] - [ViewService]->[views] - [PolicyService]->[policies] - [TypeService]->[types] -] -``` - -A short summary of the roles of these services: - -* _[ObjectService](#object-service)_: Allows retrieval of domain objects by - their identifiers; in practice, often the main point of entry into the - [information model](#information-model). -* _[ModelService](#model-service)_: Provides domain object models, retrieved - by their identifier. -* _[CapabilityService](#capability-service)_: Provides capabilities, as they - apply to specific domain objects (as judged from their model.) -* _[TelemetryService](#telemetry-service)_: Provides access to historical - and real-time telemetry data. -* _[PersistenceService](#persistence-service)_: Provides the ability to - store and retrieve documents (such as domain object models.) -* _[ActionService](#action-service)_: Provides distinct user actions that - can take place within the system (typically, upon or using domain objects.) -* _[ViewService](#view-service)_: Provides views for domain objects. A view - is a user-selectable representation of a domain object (in practice, an - HTML template.) -* _[PolicyService](#policy-service)_: Handles decisions about which - behavior are allowed within certain specific contexts. -* _[TypeService](#type-service)_: Provides information to distinguish - different types of domain objects from one another within the system. - -## Object Service - -```nomnoml -#direction: right -[ ObjectService| - getObjects(ids : Array.) : Promise.> -] -[DomainObjectProvider]--:>[ObjectService] -[DomainObjectProvider]o-[ModelService] -[DomainObjectProvider]o-[CapabilityService] -``` - -As domain objects are central to Open MCT's information model, -acquiring domain objects is equally important. - -```nomnoml -#direction: right -[ Start]->[ Look up models] -[ Look up models]->[ Look up capabilities] -[ Look up capabilities]->[ Instantiate DomainObject] -[ Instantiate DomainObject]->[ End] -``` - -Open MCT includes an implementation of an `ObjectService` which -satisfies this capability by: - -* Consulting the [Model Service](#model-service) to acquire domain object - models by identifier. -* Passing these models to a [Capability Service](#capability-service) to - determine which capabilities are applicable. -* Combining these results together as [DomainObject](#information-model) - instances. - -## Model Service - -```nomnoml -#direction: down -[ ModelService| - getModels(ids : Array.) : Promise.> -] -[StaticModelProvider]--:>[ModelService] -[RootModelProvider]--:>[ModelService] -[PersistedModelProvider]--:>[ModelService] -[ModelAggregator]--:>[ModelService] -[CachingModelDecorator]--:>[ModelService] -[MissingModelDecorator]--:>[ModelService] - -[MissingModelDecorator]o-[CachingModelDecorator] -[CachingModelDecorator]o-[ModelAggregator] -[ModelAggregator]o-[StaticModelProvider] -[ModelAggregator]o-[RootModelProvider] -[ModelAggregator]o-[PersistedModelProvider] - -[PersistedModelProvider]o-[PersistenceService] -[RootModelProvider]o-[roots] -[StaticModelProvider]o-[models] -``` - -The platform's model service is responsible for providing domain object -models (effectively, JSON documents describing the persistent state -associated with domain objects.) These are retrieved by identifier. - -The platform includes multiple components of this variety: - -* `PersistedModelProvider` looks up domain object models from - a persistence store (the [`PersistenceService`](#persistence-service)); - this is how user-created and user-modified - domain object models are retrieved. -* `RootModelProvider` provides domain object models that have been - declared via the `roots` extension category. These will appear at the - top level of the tree hierarchy in the user interface. -* `StaticModelProvider` provides domain object models that have been - declared via the `models` extension category. This is useful for - allowing plugins to expose new domain objects declaratively. -* `ModelAggregator` merges together the results from multiple providers. - If multiple providers return models for the same domain object, - the most recently modified version (as determined by the `modified` - property of the model) is chosen. -* `CachingModelDecorator` caches model instances in memory. This - ensures that only a single instance of a domain object model is - present at any given time within the application, and prevent - redundant retrievals. -* `MissingModelDecorator` adds in placeholders when no providers - have returned domain object models for a specific identifier. This - allows the user to easily see that something was expected to be - present, but wasn't. - -## Capability Service - -```nomnoml -#direction: down -[ CapabilityService| - getCapabilities(model : object) : object. -] -[CoreCapabilityProvider]--:>[CapabilityService] -[QueuingPersistenceCapabilityDecorator]--:>[CapabilityService] - -[CoreCapabilityProvider]o-[capabilities] -[QueuingPersistenceCapabilityDecorator]o-[CoreCapabilityProvider] -``` - -The capability service is responsible for determining which capabilities -are applicable for a given domain object, based on its model. Primarily, -this is handled by the `CoreCapabilityProvider`, which examines -capabilities exposed via the `capabilities` extension category. - -Additionally, `platform/persistence/queue` decorates the persistence -capability specifically to batch persistence attempts among multiple -objects (this allows failures to be recognized and handled in groups.) - -## Telemetry Service - -```nomnoml -[ TelemetryService| - requestData(requests : Array.) : Promise. - subscribe(requests : Array.) : Function -]<--:[TelemetryAggregator] -``` - -The telemetry service is responsible for acquiring telemetry data. - -Notably, the platform does not include any providers for -`TelemetryService`; applications built on Open MCT will need to -implement a provider for this service if they wish to expose telemetry -data. This is usually the most important step for integrating Open MCT -into an existing telemetry system. - -Requests for telemetry data are usually initiated in the -[presentation layer](#presentation-layer) by some `Controller` referenced -from a view. The `telemetryHandler` service is most commonly used (although -one could also use an object's `telemetry` capability directly) as this -handles capability delegation, by which a domain object such as a Telemetry -Panel can declare that its `telemetry` capability should be handled by the -objects it contains. Ultimately, the request for historical data and the -new subscriptions will reach the `TelemetryService`, and, by way of the -provider(s) which are present for that `TelemetryService`, will pass the -same requests to the back-end. - -```nomnoml -[ Start]->[Controller] -[Controller]->[ declares object of interest] -[declares object of interest]->[TelemetryHandler] -[TelemetryHandler]->[ requests telemetry from capabilities] -[TelemetryHandler]->[ subscribes to telemetry using capabilities] -[requests telemetry from capabilities]->[TelemetryCapability] -[subscribes to telemetry using capabilities]->[TelemetryCapability] -[TelemetryCapability]->[ requests telemetry] -[TelemetryCapability]->[ subscribes to telemetry] -[requests telemetry]->[TelemetryService] -[subscribes to telemetry]->[TelemetryService] -[TelemetryService]->[ issues request] -[TelemetryService]->[ updates subscriptions] -[TelemetryService]->[ listens for real-time data] -[issues request]->[ Telemetry Back-end] -[updates subscriptions]->[Telemetry Back-end] -[listens for real-time data]->[Telemetry Back-end] -[Telemetry Back-end]->[ End] -``` - -The back-end, in turn, is expected to provide whatever historical -telemetry is available to satisfy the request that has been issue. - -```nomnoml -[ Start]->[ Telemetry Back-end] -[Telemetry Back-end]->[ transmits historical telemetry] -[transmits historical telemetry]->[TelemetryService] -[TelemetryService]->[ packages telemetry, fulfills requests] -[packages telemetry, fulfills requests]->[TelemetryCapability] -[TelemetryCapability]->[ unpacks telemetry per-object, fulfills request] -[unpacks telemetry per-object, fulfills request]->[TelemetryHandler] -[TelemetryHandler]->[ exposes data] -[TelemetryHandler]->[ notifies controller] -[exposes data]->[Controller] -[notifies controller]->[Controller] -[Controller]->[ prepares data for template] -[prepares data for template]->[Template] -[Template]->[ displays data] -[displays data]->[ End] -``` - -One peculiarity of this approach is that we package many responses -together at once in the `TelemetryService`, then unpack these in the -`TelemetryCapability`, then repackage these in the `TelemetryHandler`. -The rationale for this is as follows: - -* In the `TelemetryService`, we want to have the ability to combine - multiple requests into one call to the back-end, as many back-ends - will support this. It follows that we give the response as a single - object, packages in a manner that allows responses to individual - requests to be easily identified. -* In the `TelemetryCapability`, we want to provide telemetry for a - _single object_, so the telemetry data gets unpacked. This allows - for the unpacking of data to be handled in a single place, and - also permits a flexible substitution method; domain objects may have - implementations of the `telemetry` capability that do not use the - `TelemetryService` at all, while still maintaining compatibility - with any presentation layer code written to utilize this capability. - (This is true of capabilities generally.) -* In the `TelemetryHandler`, we want to group multiple responses back - together again to make it easy for the presentation layer to consume. - In this case, the grouping is different from what may have occurred - in the `TelemetryService`; this grouping is based on what is expected - to be useful _in a specific view_. The `TelemetryService` - may be receiving requests from multiple views. - -```nomnoml -[ Start]->[ Telemetry Back-end] -[Telemetry Back-end]->[ notifies client of new data] -[notifies client of new data]->[TelemetryService] -[TelemetryService]->[ relevant subscribers?] -[relevant subscribers?] yes ->[ notify subscribers] -[relevant subscribers?] no ->[ ignore] -[ignore]->[ Ignored] -[notify subscribers]->[TelemetryCapability] -[TelemetryCapability]->[ notify listener] -[notify listener]->[TelemetryHandler] -[TelemetryHandler]->[ exposes data] -[TelemetryHandler]->[ notifies controller] -[exposes data]->[Controller] -[notifies controller]->[Controller] -[Controller]->[ prepares data for template] -[prepares data for template]->[Template] -[Template]->[ displays data] -[displays data]->[ End] -``` - -The flow of real-time data is similar, and is handled by a sequence -of callbacks between the presentation layer component which is -interested in data and the telemetry service. Providers in the -telemetry service listen to the back-end for new data (via whatever -mechanism their specific back-end supports), package this data in -the same manner as historical data, and pass that to the callbacks -which are associated with relevant requests. - -## Persistence Service - -```nomnoml -#direction: right -[ PersistenceService| - listSpaces() : Promise.> - listObjects() : Promise.> - createObject(space : string, key : string, document : object) : Promise. - readObject(space : string, key : string, document : object) : Promise. - updateObject(space : string, key : string, document : object) : Promise. - deleteObject(space : string, key : string, document : object) : Promise. -] - -[ElasticPersistenceProvider]--:>[PersistenceService] -[ElasticPersistenceProvider]->[ ElasticSearch] - -[CouchPersistenceProvider]--:>[PersistenceService] -[CouchPersistenceProvider]->[ CouchDB] -``` - -Closely related to the notion of domain objects models is their -persistence. The `PersistenceService` allows these to be saved -and loaded. (Currently, this capability is only used for domain -object models, but the interface has been designed without this idea -in mind; other kinds of documents could be saved and loaded in the -same manner.) - -There is no single definitive implementation of a `PersistenceService` in -the platform. Optional adapters are provided to store and load documents -from CouchDB and ElasticSearch, respectively; plugin authors may also -write additional adapters to utilize different back end technologies. - -## Action Service - -```nomnoml -[ActionService| - getActions(context : ActionContext) : Array. -] -[ActionProvider]--:>[ActionService] -[CreateActionProvider]--:>[ActionService] -[ActionAggregator]--:>[ActionService] -[LoggingActionDecorator]--:>[ActionService] -[PolicyActionDecorator]--:>[ActionService] - -[LoggingActionDecorator]o-[PolicyActionDecorator] -[PolicyActionDecorator]o-[ActionAggregator] -[ActionAggregator]o-[ActionProvider] -[ActionAggregator]o-[CreateActionProvider] - -[ActionProvider]o-[actions] -[CreateActionProvider]o-[TypeService] -[PolicyActionDecorator]o-[PolicyService] -``` - -Actions are discrete tasks or behaviors that can be initiated by a user -upon or using a domain object. Actions may appear as menu items or -buttons in the user interface, or may be triggered by certain gestures. - -Responsibilities of platform components of the action service are as -follows: - -* `ActionProvider` exposes actions registered via extension category - `actions`, supporting simple addition of new actions. Actions are - filtered down to match action contexts based on criteria defined as - part of an action's extension definition. -* `CreateActionProvider` provides the various Create actions which - populate the Create menu. These are driven by the available types, - so do not map easily to extension category `actions`; instead, these - are generated after looking up which actions are available from the - [`TypeService`](#type-service). -* `ActionAggregator` merges together actions from multiple providers. -* `PolicyActionDecorator` enforces the `action` policy category by - filtering out actions which violate this policy, as determined by - consulting the [`PolicyService`](#policy-service). -* `LoggingActionDecorator` wraps exposed actions and writes to the - console when they are performed. - -## View Service - -```nomnoml -[ViewService| - getViews(domainObject : DomainObject) : Array. -] -[ViewProvider]--:>[ViewService] -[PolicyViewDecorator]--:>[ViewService] - -[ViewProvider]o-[views] -[PolicyViewDecorator]o-[ViewProvider] -``` - -The view service provides views that are relevant to a specified domain -object. A "view" is a user-selectable visualization of a domain object. - -The responsibilities of components of the view service are as follows: - -* `ViewProvider` exposes views registered via extension category - `views`, supporting simple addition of new views. Views are - filtered down to match domain objects based on criteria defined as - part of a view's extension definition. -* `PolicyViewDecorator` enforces the `view` policy category by - filtering out views which violate this policy, as determined by - consulting the [`PolicyService`](#policy-service). - -## Policy Service - -```nomnoml -[PolicyService| - allow(category : string, candidate : object, context : object, callback? : Function) : boolean -] -[PolicyProvider]--:>[PolicyService] -[PolicyProvider]o-[policies] -``` - -The policy service provides a general-purpose extensible decision-making -mechanism; plugins can add new extensions of category `policies` to -modify decisions of a known category. - -Often, the policy service is referenced from a decorator for another -service, to filter down the results of using that service based on some -appropriate policy category. - -The policy provider works by looking up all registered policy extensions -which are relevant to a particular _category_, then consulting each in -order to see if they allow a particular _candidate_ in a particular -_context_; the types for the `candidate` and `context` arguments will -vary depending on the `category`. Any one policy may disallow the -decision as a whole. - - -```nomnoml -[ Start]->[ is something allowed?] -[is something allowed?]->[PolicyService] -[PolicyService]->[ look up relevant policies by category] -[look up relevant policies by category]->[ consult policy #1] -[consult policy #1]->[Policy #1] -[Policy #1]->[ policy #1 allows?] -[policy #1 allows?] no ->[ decision disallowed] -[policy #1 allows?] yes ->[ consult policy #2] -[consult policy #2]->[Policy #2] -[Policy #2]->[ policy #2 allows?] -[policy #2 allows?] no ->[ decision disallowed] -[policy #2 allows?] yes ->[ consult policy #3] -[consult policy #3]->[ ...] -[...]->[ consult policy #n] -[consult policy #n]->[Policy #n] -[Policy #n]->[ policy #n allows?] -[policy #n allows?] no ->[ decision disallowed] -[policy #n allows?] yes ->[ decision allowed] -[decision disallowed]->[ Disallowed] -[decision allowed]->[ Allowed] -``` - -The policy decision is effectively an "and" operation over the individual -policy decisions: That is, all policies must agree to allow a particular -policy decision, and the first policy to disallow a decision will cause -the entire decision to be disallowed. As a consequence of this, policies -should generally be written with a default behavior of "allow", and -should only disallow the specific circumstances they are intended to -disallow. - -## Type Service - -```nomnoml -[TypeService| - listTypes() : Array. - getType(key : string) : Type -] -[TypeProvider]--:>[TypeService] -[TypeProvider]o-[types] -``` - -The type service provides metadata about the different types of domain -objects that exist within an Open MCT application. The platform -implementation reads these types in from extension category `types` -and wraps them in a JavaScript interface. diff --git a/docs/src/design/index.md b/docs/src/design/index.md deleted file mode 100644 index 7b4c3e4ebf..0000000000 --- a/docs/src/design/index.md +++ /dev/null @@ -1,3 +0,0 @@ -Design proposals: - -* [API Redesign](proposals/APIRedesign.md) \ No newline at end of file diff --git a/docs/src/design/planning/APIRefactor.md b/docs/src/design/planning/APIRefactor.md deleted file mode 100644 index ec98a115f4..0000000000 --- a/docs/src/design/planning/APIRefactor.md +++ /dev/null @@ -1,338 +0,0 @@ -# API Refactoring - -This document summarizes a path toward implementing API changes -from the [API Redesign](../proposals/APIRedesign.md) for Open MCT -v1.0.0. - -# Goals - -These plans are intended to minimize: - -* Waste; avoid allocating effort to temporary changes. -* Downtime; avoid making changes in large increments that blocks - delivery of new features for substantial periods of time. -* Risk; ensure that changes can be validated quickly, avoid putting - large effort into changes that have not been validated. - -# Plan - -```nomnoml -#comment: This diagram is in nomnoml syntax and should be rendered. -#comment: See https://github.com/nasa/openmctweb/issues/264#issuecomment-167166471 - - -[ Start]->[ Imperative bundle registration] - -[ Imperative bundle registration]->[ Build and packaging] -[ Imperative bundle registration]->[ Refactor API] - -[ Build and packaging | - [ Start]->[ Incorporate a build step] - [ Incorporate a build step | - [ Start]->[ Choose package manager] - [ Start]->[ Choose build system] - [ Choose build system]<->[ Choose package manager] - [ Choose package manager]->[ Implement] - [ Choose build system]->[ Implement] - [ Implement]->[ End] - ]->[ Separate repositories] - [ Separate repositories]->[ End] -]->[ Release candidacy] - - -[ Start]->[ Design registration API] - -[ Design registration API | - [ Start]->[ Decide on role of Angular] - [ Decide on role of Angular]->[ Design API] - [ Design API]->[ Passes review?] - [ Passes review?] no ->[ Design API] - [ Passes review?]-> yes [ End] -]->[ Refactor API] - -[ Refactor API | - [ Start]->[ Imperative extension registration] - [ Imperative extension registration]->[ Refactor individual extensions] - - [ Refactor individual extensions | - [ Start]->[ Prioritize] - [ Prioritize]->[ Sufficient value added?] - [ Sufficient value added?] no ->[ End] - [ Sufficient value added?] yes ->[ Design] - [ Design]->[ Passes review?] - [ Passes review?] no ->[ Design] - [ Passes review?]-> yes [ Implement] - [ Implement]->[ End] - ]->[ Remove legacy bundle support] - - [ Remove legacy bundle support]->[ End] -]->[ Release candidacy] - -[ Release candidacy | - [ Start]->[ Verify | - [ Start]->[ API well-documented?] - [ Start]->[ API well-tested?] - [ API well-documented?]-> no [ Write documentation] - [ API well-documented?] yes ->[ End] - [ Write documentation]->[ API well-documented?] - [ API well-tested?]-> no [ Write test cases] - [ API well-tested?]-> yes [ End] - [ Write test cases]->[ API well-tested?] - ] - [ Start]->[ Validate | - [ Start]->[ Passes review?] - [ Start]->[ Use internally] - [ Use internally]->[ Proves useful?] - [ Passes review?]-> no [ Address feedback] - [ Address feedback]->[ Passes review?] - [ Passes review?] yes -> [ End] - [ Proves useful?] yes -> [ End] - [ Proves useful?] no -> [ Fix problems] - [ Fix problems]->[ Use internally] - ] - [ Validate]->[ End] - [ Verify]->[ End] -]->[ Release] - -[ Release]->[ End] -``` - -## Step 1. Imperative bundle registration - -Register whole bundles imperatively, using their current format. - -For example, in each bundle add a `bundle.js` file: - -```js -define([ - 'mctRegistry', - 'json!bundle.json' -], function (mctRegistry, bundle) { - mctRegistry.install(bundle, "path/to/bundle"); -}); -``` - -Where `mctRegistry.install` is placeholder API that wires into the -existing bundle registration mechanisms. The main point of entry -would need to be adapted to clearly depend on these bundles -(in the require sense of a dependency), and the framework layer -would need to implement and integrate with this transitional -API. - -Benefits: - -* Achieves an API Redesign goal with minimal immediate effort. -* Conversion to an imperative syntax may be trivially automated. -* Minimal change; reuse existing bundle definitions, primarily. -* Allows early validation of switch to imperative; unforeseen - consequences of the change may be detected at this point. -* Allows implementation effort to progress in parallel with decisions - about API changes, including fundamental ones such as the role of - Angular. May act in some sense as a prototype to inform those - decisions. -* Creates a location (framework layer) where subsequent changes to - the manner in which extensions are registered may be centralized. - When there is a one-to-one correspondence between the existing - form of an extension and its post-refactor form, adapters can be - written here to defer the task of making changes ubiquitously - throughout bundles, allowing for earlier validation and - verification of those changes, and avoiding ubiquitous changes - which might require us to go dark. (Mitigates - ["greenfield paradox"](http://stepaheadsoftware.blogspot.com/2012/09/greenfield-or-refactor-legacy-code-base.html); - want to add value with new API but don't want to discard value - of tested/proven legacy codebase.) - -Detriments: - -* Requires transitional API to be implemented/supported; this is - waste. May mitigate this by time-bounding the effort put into - this step to ensure that waste is minimal. - -Note that API changes at this point do not meaningfully reflect -the desired 1.0.0 API, so no API reviews are necessary. - -## Step 2. Incorporate a build step - -After the previous step is completed, there should be a -straightforward dependency graph among AMD modules, and an -imperative (albeit transitional) API allowing for other plugins -to register themselves. This should allow for a build step to -be included in a straightforward fashion. - -Some goals for this build step: - -* Compile (and, preferably, optimize/minify) Open MCT - sources into a single `.js` file. - * It is desirable to do the same for HTML sources, but - may wish to defer this until a subsequent refactoring - step if appropriate. -* Provide non-code assets in a format that can be reused by - derivative projects in a straightforward fashion. - -Should also consider which dependency/packaging manager should -be used by dependent projects to obtain Open MCT. Approaches -include: - -1. Plain `npm`. Dependents then declare their dependency with - `npm` and utilize built sources and assets in a documented - fashion. (Note that there are - [documented challenges](http://blog.npmjs.org/post/101775448305/npm-and-front-end-packaging) - in using `npm` in this fashion.) -2. Build with `npm`, but recommend dependents install using - `bower`, as this is intended for front-end development. This may - require checking in built products, however, which - we wish to avoid (this could be solved by maintaining - a separate repository for built products.) - -In all cases, there is a related question of which build system -to use for asset generation/management and compilation/minification/etc. - -1. [`webpack`](https://webpack.github.io/) - is well-suited in principle, as it is specifically - designed for modules with non-JS dependencies. However, - there may be limitations and/or undesired behavior here - (for instance, CSS dependencies get in-lined as style tags, - removing our ability to control ordering) so it may -2. `gulp` or `grunt`. Commonplace, but both still require - non-trivial coding and/or configuration in order to produce - appropriate build artifacts. -3. [Just `npm`](http://blog.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/). - Reduces the amount of tooling being used, but may introduce - some complexity (e.g. custom scripts) to the build process, - and may reduce portability. - -## Step 3. Separate repositories - -Refactor existing applications built on Open MCT such that they -are no longer forks, but instead separate projects with a dependency -on the built artifacts from Step 2. - -Note that this is achievable already using `bower` (see `warp-bower` -branch at http://developer.nasa.gov/mct/warp for an example.) -However, changes involved in switching to an imperative API and -introducing a build process may change (and should simplify) the -approach used to utilize Open MCT as a dependency, so these -changes should be introduced first. - -## Step 4. Design registration API - -Design the registration API that will replace declarative extension -categories and extensions (including Angular built-ins and composite -services.) - -This may occur in parallel with implementation steps. - -It will be necessary -to have a decision about the role of Angular at this point; are extensions -registered via provider configuration (Angular), or directly in some -exposed registry? - -Success criteria here should be based on peer review. Scope of peer -review should be based on perceived risk/uncertainty surrounding -proposed changes, to avoid waste; may wish to limit this review to -the internal team. (The extent to which external -feedback is available is limited, but there is an inherent timeliness -to external review; need to balance this.) - -Benefits: - -* Solves the "general case" early, allowing for early validation. - -Note that in specific cases, it may be desirable to refactor some -current "extension category" in a manner that will not appear as -registries, _or_ to locate these in different -namespaces, _or_ to remove/replace certain categories entirely. -This work is deferred intentionally to allow for a solution of the -general case. - -## Step 5. Imperative extension registration - -Register individual extensions imperatively, implementing API changes -from the previous step. At this stage, _usage_ of the API may be confined -to a transitional adapter in the framework layer; bundles may continue -to utilize the transitional API for registering extensions in the -legacy format. - -An important, ongoing sub-task here will be to discover and define dependencies -among bundles. Composite services and extension categories are presently -"implicit"; after the API redesign, these will become "explicit", insofar -as some specific component will be responsible for creating any registries. -As such, "bundles" which _use_ specific registries will need to have an -enforceable dependency (e.g. require) upon those "bundles" which -_declare_ those registries. - -## Step 6. Refactor individual extensions - -Refactor individual extension categories and/or services that have -been identified as needing changes. This includes, but is not -necessarily limited to: - -* Views/Representations/Templates (refactored into "components.") -* Capabilities (refactored into "roles", potentially.) -* Telemetry (from `TelemetrySeries` to `TelemetryService`.) - -Changes should be made one category at a time (either serially -or separately in parallel) and should involve a tight cycle of: - -1. Prioritization/reprioritization; highest-value API improvements - should be done first. -2. Design. -3. Review. Refactoring individual extensions will require significant - effort (likely the most significant effort in the process) so changes - should be validated early to minimize risk/waste. -4. Implementation. These changes will not have a one-to-one relationship - with existing extensions, so changes cannot be centralized; usages - will need to be updated across all "bundles" instead of centralized - in a legacy adapter. If changes are of sufficient complexity, some - planning should be done to spread out the changes incrementally. - -By necessity, these changes may break functionality in applications -built using Open MCT. On a case-by-case basis, should consider -providing temporary "legacy support" to allow downstream updates -to occur as a separate task; the relevant trade here is between -waste/effort required to maintain legacy support, versus the -downtime which may be introduced by making these changes simultaneously -across several repositories. - - -## Step 7. Remove legacy bundle support - -Update bundles to remove any usages of legacy support for bundles -(including that used by dependent projects.) Then, remove legacy -support from Open MCT. - -## Step 8. Release candidacy - -Once API changes are complete, Open MCT should enter a release -candidacy cycle. Important things to look at here: - -* Are changes really complete? - * Are they sufficiently documented? - * Are they sufficiently tested? -* Are changes really sufficient? - * Do reviewers think they are usable? - * Does the development team find them useful in practice? This - will require calendar time to ascertain; should allocate time - for this, particularly in alignment with the sprint/release - cycle. - * Has learning curve been measurably decreased? Comparing a to-do - list tutorial to [other examples(http://todomvc.com/) could - provide an empirical basis to this. How much code is required? - How much explanation is required? How many dependencies must - be installed before initial setup? - * Does the API offer sufficient power to implement the extensions we - anticipate? - * Any open API-related issues which should block a 1.0.0 release? - -Any problems identified during release candidacy will require -subsequent design changes and planning. - -## Step 9. Release - -Once API changes have been verified and validated, proceed -with release, including: - -* Tagging as version 1.0.0 (at an appropriate time in the - sprint/release cycle.) -* Close any open issues which have been resolved (or made obsolete) - by API changes. \ No newline at end of file diff --git a/docs/src/design/proposals/APIRedesign.md b/docs/src/design/proposals/APIRedesign.md deleted file mode 100644 index 93098c3d7d..0000000000 --- a/docs/src/design/proposals/APIRedesign.md +++ /dev/null @@ -1,1282 +0,0 @@ -# Overview - -The purpose of this document is to review feedback on Open MCT's -current API and propose improvements to the API, particularly for a -1.0.0 release. - -Strategically, this is handled by: - -* Identifying broader goals. -* Documenting feedback and related background information. -* Reviewing feedback to identify trends and useful features. - * In particular, pull out "pain points" to attempt to address, - as well as positive attributes to attempt to preserve. -* Proposing a set of API changes to address these "pain points." - * This also takes into account scheduling concerns. -* Once agreed-upon, formalize this set of changes (e.g. as UML - diagrams) and plan to implement them. - -# Goals - -## Characteristics of a good API - -A good API: - -* Is easy to understand. -* Rewards doing things "the right way." -* Saves development effort. -* Is powerful enough to support a broad range of applications. -* Lends itself to good documentation. - -These characteristics can sometimes be at odds with each other, or -with other concerns. These should typically be viewed as participants -in trades. - -## Evaluating APIs - -APIs may be evaluated based on: - -* Number of interfaces. - * How many application-specific interfaces do I need to know to - solve a certain class of problems? -* Size of interfaces. - * How many methods does each interface have? -* Depth of interfaces. - * Specifically, how many methods do I need to call before the return - value is of a form that is not specific to the API? -* Clarity of interfaces. - * How much documentation or learning is required before an interface is - useful? -* Consistency of interfaces. - * How similar is one interface to an analogous interface? -* Utility of interfaces. - * How much development effort is reduced by utilizing these interfaces, - versus accomplishing the same goals with other tools? -* Power of interfaces. - * How much application functionality can I influence with the interfaces - that are available to me? - -In general, prefer to have a small number of simple, shallow, clear, -useful, powerful interfaces. - -# Developer Feedback - -## Developer Intern Feedback - -This feedback comes from interns who worked closely with -Open MCT as their primary task over the Summer of 2015. - -### Developer Intern 1 - -Worked on bug fixes in the platform and a plugin for search. - -* Initially, it was confusing that many things in files that are in - very different locations in the code base refer to each other. - * Perhaps explain more the organization strategy behind the - different main sections, like "commonUI" vs "core". -* This may be just me, but there are often long chains of related - functions calling each other, and when I had to modify the behavior, - I had a hard time remembering to look for the highest level function - in the call chain to change. I also sometimes had a hard time finding - the connections between the functions. But, that is important because - the implementation of the functions along the chain may change later. -* One very helpful thing that you could add might just be documentation - that is not in paragraph format like in the current developer guide. - I would just like a list of all the functions and members of each kind - of object there is, and descriptions of what they are and how they're - used. - * Also, the current developer guide pdf's words that are in 'code font', - rather than the normal text, are not searchable. - (Depending on the pdf viewer.) -* I do appreciate that there is some example code. -* I am still slightly confused about what "domainObject" refers to in - different situations. -* The tutorials are helpful, but only really for designing new views. - It doesn't help much with gaining understanding of how the other parts - of the application work. -* The general idea of 'telemetry' in this context is kind of confusing. - It is hard to figure out what the difference between the various ways of - dealing with telemetry are. e.g., what is the difference between just - "Telemetry" and the "Telemetry Service"? There are many - "Telemetry Things" which seem related, but in an unclear way. - -### Developer Intern 2 - -Worked on platform bug fixes and mobile support. - -* No guide for the UI and front end for the HTML/CSS part of Open MCT. - Not sure if this is applicable or needed for developers, however would - be helpful to any front end development -* Found it difficult to follow the plot controller & subplot - functions/features, such as zooming. -* If the developer guide could have for references to which files or - functions are key for gestures, browse navigation, etc it would be - helpful for future developers as a place to start looking. I found - it occasionally difficult to find which files or functions I wanted - at first. - -## Plugin Developer Feedback - -This feedback comes from developers who have worked on plugins for -Open MCT, but have not worked on the platform. - -### Plugin Developer 1 - -Used Open MCT over the course of several months (on a -less-than-half-time basis) to develop a -spectrum visualization plugin. - -* Not a lot of time to work on this, made it hard to get up the learning - curve. - * Note that this is the norm, particularly for GDS development. -* JavaScript carries its own learning curve. -* The fact that it pulls in other tools whose APIs need to be learned - also makes the learning curve harder to get up. -* Tracking down interconnected parts was a bit difficult. -* Could really use examples. -* Easy to get lost when not immersed in the style. - -### Plugin Developer 2 - -Used Open MCT over the course of several weeks (on a half-time basis) -to develop a tabular visualization plugin. - -* Pain points - * Unable to copy and paste from tutorial pdfs into code - * Wanted to verify my environment was setup properly so that I - could get the final product working in the end without having - to type everything out. Perhaps there could be something in - github that has the final completed tutorial for new users to - checkout? Or a step by step one kind of like the tutorials on - the angular js webpage? - * Typing too long without seeing results of what I was doing - * At some points in the tutorial I ended up typing for the sake - of typing without knowing what I was really typing for. - * If there were break points where we could run the incomplete - code and just see a variable dump or something even that would - be helpful to know that I am on the right track. - * Documentation on features are a bit hard to find. - * I'm not sure what I can do until I search through examples of - existing code and work my way backwards. - * Maybe you can link the features we are using in the tutorial to - their respective parts in the developer guide? Not sure if that - can be done on PDFs, so maybe a webpage instead? -* Positive Attributes - * Unable to copy and paste from tutorial pdfs into code - * I know I also listed this as a pain, but it was kind of helpful - being forced to read and type everything out. - * "Widgets" are self contained in their own directories. I don't have - to be afraid of exploding things. - * All files/config that I care about for a "widget" can be found in - the bundles.json -* Misc - * Coming from a not so strong webdev background and on top of that a - zero strong angular background I think starting off with a simple - "Hello World" webpage tutorial would have been nice. - * Start off with a bare bones bundle json with an empty controller - and static "Hello World" in the view - * Add the variable "Hello World" into the controller for the view - to display - * Add a model property to the bundle.json to take in "Hello World" - as a parameter and pass through to the controller/view - -### Open Source Contributor - - * [Failures are non-graceful when services are missing.]( - https://github.com/nasa/openmctweb/issues/79) - -## Misc. Feedback (mostly verbal) - -* Easy to add things. -* Separation of concerns is unclear (particularly: "where's the MVC?") -* Telemetry API is confusing. In particular, `TelemetrySeries` should - just be an array. - * Came out of design discussions for Limits. -* Capabilities are confusing. - -## Long-term Developer Notes - -The following notes are from original platform developer, with long -term experience using Open MCT. - -* Bundle mechanism allows for grouping related components across concerns, - and adding and removing these easily. (e.g. model and view components of - Edit mode are all grouped together in the Edit bundle.) - -## AngularJS - -Angular 2.0.0 is coming (maybe by end of 2015.) - -It will not be backwards-compatible with Angular 1.x. -The differences are significant enough that switching to -Angular 2 will require only slightly less effort than switching -to an entirely different framework. - -We can expect AngularJS 1.x to reach end-of-life reasonably soon thereafter. - -Our API is currently a superset of Angular's API, so this directly affects -our API. Specifically, API changes should be oriented towards removing -or reducing the Angular dependency. - -### Angular's Role - -Angular is Open MCT's: - -* Dependency injection framework. -* Template rendering. -* DOM interactions. -* Services library. -* Form validator. -* Routing. - -This is the problem with frameworks: They become a single point of -failure for unrelated concerns. - -### Rationale for Adopting Angular - -The rationale for adopting AngularJS as a framework is -documented in https://trunk.arc.nasa.gov/jira/browse/WTD-208. -Summary of the expected benefits: - -* Establishes design patterns that are well-documented and - understood in industry. This can be beneficial in training - new staff, and lowers the documentation burden on the local - development team. If MCT-Web were to stay with its current - architecture, significant developer-oriented documentation - and training materials would need to be produced. -* The maintainability of MCT-Web would be enhanced by using a - framework like Angular. The local team would enjoy the benefits of - maintenance performed by the sponsor, but would not incur any cost - for this. This would include future upgrades, testing, and bug fixes. -* Replaces DOM-manipulation with a declarative data-binding syntax - which automatically updates views when the model data changes. This - pattern has the potential to save the development team from - time-consuming and difficult-to-debug DOM manipulation. -* Provides data binding to backend models. -* Provides patterns for form validation. -* Establishes documented patterns for add-on modules and services. -* Supports unit tests and system tests (tests which simulate user - interactions in the browser) -* Angular software releases can be expected to be tested, which would - allow MCT-Web developers to focus on MCT-specific features, instead - of the maintenance of custom infrastructure. - -### Actual Experience with Angular - -Most of the expected benefits of Angular have been invalidated -by experience: - -* Feedback from new developers is that Angular was a hindrance to - training, not a benefit. ("One more thing to learn.") Significant - documentation remains necessary for Open MCT. -* Expected enhancements to maintainability will be effectively - invalidated by an expected Angular end-of-life. -* Data binding and automatic view updates do save development effort, - but also carry a performance penalty. This can be solved, but requires - resorting to exactly the sort of DOM manipulations we want to avoid. - In some cases this can require more total development (writing a - poorly-performing Angular version, then "optimizing" by rewriting a - non-Angular version.) -* Expected reduction of test scope will also be invalidated by an - expected end-of-life. - -Other problems: - -* Hinders integrating non-Angular components. (Need to wrap with - Angular API, e.g. as directives, which may be non-trivial.) -* Interferes with debugging by swallowing or obscuring exceptions. - -# Feedback Review - -## Problem Summary - -The following attributes of the current API are undesirable: - -- [ ] It is difficult to tell "where things are" in the code base. -- [ ] It is difficult to see how objects are passed around at run-time. -- [ ] It is difficult to trace flow of control generally. -- [ ] Multiple interfaces for related concepts (e.g. telemetry) is confusing. -- [ ] API documentation is missing or not well-formatted for use. -- [ ] High-level separation of concerns is not made clear. -- [ ] Interface depth of telemetry API is excessive (esp. `TelemetrySeries`) -- [ ] Capabilities as a concept lack clarity. -- [ ] Too many interfaces and concepts to learn. -- [ ] Exposing third-party APIs (e.g. Angular's) increases the learning curve. -- [ ] Want more examples, easier-to-use documentation. -- [ ] UI-relevant features (HTML, CSS) under-documented -- [ ] Good MVC for views of domain objects not enforced (e.g. plots) - -## Positive Features - -It is desirable to retain the following features in an API redesign: - -- [ ] Creating new features and implementing them additively is well-supported. -- [ ] Easy to add/remove features which involve multiple concerns. -- [ ] Features can be self-contained. -- [ ] Declarative syntax makes it easy to tell what's in use. - -## Requirements - -The following are considered "must-haves" of any complete API -redesign: - -- [ ] Don't require usage of Angular API. -- [ ] Don't require support for Angular API. - -# Proposals - -## RequireJS as dependency injector - -Use Require.JS for dependency injection. - -Dependencies will then be responsible for being sufficiently -mutable/extensible/customizable. This can be facilitated by -adding platform classes which can facilitate the addition -of reusable components. - -Things that we usefully acquire via dependency injection currently: - -* Services. -* Extensions (by category). -* Configuration constants. - -Services would be defined (by whatever component is responsible -for declaring it) using `define` and the explicit name of the -service. To allow for the power of composite services, the -platform would provide a `CompositeService` class that supports -this process by providing `register`, `decorate`, and `composite` -methods to register providers, decorators, and aggregators -respectively. (Note that nomenclature changes are also implied -here, to map more clearly to the Composite Pattern and to -avoid the use of the word "provider", which has ambiguity with -Angular.) - -```js -define( - "typeService", - ["CompositeService"], - function (CompositeService) { - var typeService = new CompositeService([ - "listTypes", - "getType" - ]); - - // typeService has `listTypes` and `getType` as methods; - // at this point they are stubbed (will return undefined - // or throw or similar) but this will change as - // decorators/compositors/providers are added. - - // You could build in a compositor here, or - // someone could also define one later - typeService.composite(function (typeServices) { - // ... return a TypeService - }); - - // Similarly, you could register a default implementation - // here, or from some other script. - typeService.register(function (typeService) { - // ... return a TypeService - }, { priority: 'default' }); - - return typeService; - } -); -``` - -Other code could then register additional `TypeService` -implementations (or decorators, or even compositors) by -requiring `typeService` and calling those methods; or, it -could use `typeService` directly. Priority ordering could -be utilized by adding a second "options" argument. - -For extension categories, you could simply use registries: - -```js -define( - "typeRegistry", - ["ExtensionRegistry"], - function (ExtensionRegistry) { - return new ExtensionRegistry(); - } -); -``` - -Where `ExtensionRegistry` extends `Array`, and adds a -`register` method which inserts into the array at some -appropriate point (e.g. with an options parameter that -respects priority order.) - -This makes unit testing somewhat more difficult when you -want to mock injected dependencies; there are tools out -there (e.g. [Squire](https://github.com/iammerrick/Squire.js/)) -which can help with this, however. - -### Benefits - -* Clarifies "how objects are passed around at run-time"; - answer is always "via RequireJS." -* Preserves flexibility/power provided by composite services. -* Lends itself fairly naturally to API documentation via JSDoc - (as compared to declaring things in bundles, which does not.) -* Reduces interface complexity for acquiring dependencies; - one interface for both explicit and "implicit" dependencies, - instead of separate approaches for static and substitutable - dependencies. -* Removes need to understand Angular's DI mechanism. -* 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 - to be used on background threads trivially. - -### Detriments - -* Having services which both implement the service, and - have methods for registering the service, is a little - weird; would be cleaner if these were separate. - (Mixes concerns.) -* Syntax becomes non-declarative, which may make it harder to - understand "what uses what." -* Allows for ordering problems (e.g. you start using a - service before everything has been registered.) - -## Arbitrary HTML Views - -Currently, writing new views requires writing Angular templates. -This must change if we want to reduce our dependence on Angular. - -Instead, propose that: - -* What are currently called "views" we call something different. - (Want the term view to be more like "view" in the MVC sense.) - * For example, call them "applications." -* Consolidate what are currently called "representations" and - "templates", and instead have them be "views". - -For parity with actions, a `View` would be a constructor which -takes an `ActionContext` as a parameter (with similarly-defined -properties) and exposes a method to retrieve the HTML elements -associated with it. - -The platform would then additionally expose an `AngularView` -implementation to improve compatibility with existing -representations, whose usage would something like: - -```js -define( - ["AngularView"], - function (AngularView) { - var template = "Hello world"; - return new AngularView(template); - } -); -``` - -The interface exposed by a view is TBD, but should provide at -least the following: - -* A way to get the HTML elements that are exposed by & managed - by the view. -* A `destroy` method to detach any listeners at the model level. - -Individual views are responsible for managing their resources, -e.g. listening to domain objects for mutation. To keep DRY, the -platform should include one or more view implementations that -can be used/subclassed which handle common behavior(s). - -### Benefits - -* Using Angular API for views is no longer required. -* Views become less-coupled to domain objects. Domain objects - may be present in the `ViewContext`, but this also might - just be a "view" of some totally different thing. -* Helps clarify high-level concerns in the API (a View is now - really more like a View in the MVC sense; although, not - completely, so this gets double-booked as a detriment.) -* Having a `ViewContext` that gets passed in allows views to - be more "contextually aware," which is something that has - been flagged previously as a UX desire. - -### Detriments - -* Becomes less clear how views relate to domain objects. -* Adds another interface. -* Leaves an open problem of how to distinguish views that - a user can choose (Plot, Scrolling List) from views that - are used more internally by the application (tree view.) -* Views are still not Views in the MVC sense (in practice, - the will likely be view-controller pairs.) We could call - them widgets to disambiguate this. -* Related to the above, even if we called these "widgets" - it would still fail to enforce good MVC. - -## Wrap Angular Services - -Wrap Angular's services in a custom interfaces; e.g. -replace `$http` with an `httpService` which exposes a useful -subset of `$http`'s functionality. - -### Benefits - -* Removes a ubiquitous dependency on Angular. -* Allows documentation for these features to be co-located - and consistent with other documentation. -* Facilitates replacing these with non-Angular versions - in the future. - -### Detriments - -* Increases the number of interfaces in Open MCT. (Arguably, - not really, since the same interfaces would exist if exposed - by Angular.) - -## Bundle Declarations in JavaScript - -Replace `bundle.json` files (and bundle syntax generally) with -an imperative form. There would instead be a `Bundle` interface -which scripts can implement (perhaps assisted by a platform -class.) - -The `bundles.json` file would then be replaced with a `bundles.js` -or `Bundles.js` that would look something like: - -```js -define( - [ - 'platform/core/PlatformBundle', - // ... etc ... - 'platform/features/plot/PlotBundle' - ], - function () { - return arguments; - } -); -``` - -Which could in turn be used by an initializer: - -```js -define( - ['./bundles', 'mct'], - function (bundles, mct) { - mct.initialize(bundles); - } -); -``` - -A `Bundle` would have a constructor that took some JSON object -(a `BundleContext`, lets say) and would provide methods for -application life-cycle events. Depending on other choices, -a dependency injector could be passed in at some appropriate -life-cycle call (e.g. initialize.) - -This would also allow for "composite bundles" which serve as -proxies for multiple bundles. The `BundleContext` could contain -(or later be amended to contain) filtering rules to ignore -other bundles and so forth (this has been useful for administering -Open MCT in subtly different configurations in the past.) - -### Benefits - -* Imperative; more explicit, less magic, more clear what is going on. -* Having a hierarchy of "bundles" could make it easier to navigate - (relevant groupings can be nested in a manner which is not - currently well-supported.) -* Lends itself naturally to a compilation step. -* Nudges plugin authors to "do your initialization and registration - in a specific place" instead of mixing in registration of features - with their implementations. - -### Detriments - -* Introduces another interface. -* Loses some of the convenience of having a declarative - summary of components and their dependencies. - -## Pass around a dependency injector - -:warning: Note that this is incompatible with the -[RequireJS as dependency injector](#requirejs-as-dependency-injector) -proposal. - -Via some means (such as in a registration lifecycle event as -described above) pass a dependency injector to plugins to allow -for dependencies to be registered. - -For example: - -```js -MyBundle.prototype.registration = function (architecture) { - architecture.service('typeService').register(MyTypeService); - architecture.extension('actions').register( - [ 'foo' ], - function (foo) { return new MyAction(foo); } - ); -}; -``` - -### Benefits - -* Ensures that registration occurs at an appropriate stage of - application execution, avoiding start-up problems. -* Makes registration explicit (generally easier to understand) - rather than implicit. -* Encapsulates dependency injection nicely. - -### Detriments - -* Increases number of interfaces to learn. -* Syntax likely to be awkward, since in many cases we really - want to be registering constructors. - -## Remove partial constructors - -Remove partial constructors; these are confusing. It is hard to -recognize which constructor arguments are from dependencies, and -which will be provided at run-time. Instead, it is the responsibility -of whoever is introducing a component to manage these things -separately. - -### Benefits - -* More clarity. - -### Detriments - -* Possibly results in redundant effort to manage this difference - (other APIs may need to be adjusted accordingly.) - -## Rename Views to Applications - -Rename (internally to the application, not necessarily in UI or -in user guide) what are currently called `views` to `applications`. - -### Benefits - -* Easier to understand. What is currently called a "view" is, - in the MVC sense, a view-controller pair, usually with its own - internal model for view state. Calling these "applications" - would avoid this ambiguity/inconsistency. -* Also provides an appropriate mindset for building these; - particularly, sets the expectation that you'll want to decompose - this "application" into smaller pieces. This nudges developers - in appropriate directions (in contrast to `views`, which - typically get implemented as templates with over-complicated - "controllers".) - -### Detriments - -* Developer terminology falls out of sync with what is used in - the user guide. - -## Provide Classes for Extensions - -As a general pattern, when introducing extension categories, provide -classes with a standard implementation of these interfaces that -plugin developers can `new` and register. - -For example, instead of declaring a type as: - -```json -{ - "types": [{ - "key": "sometype", - "glyph": "X", - "etc": "..." - }] -} -``` - -You would register one as: - -```js -// Assume we have gotten a reference to a type registry somehow -typeRegistry.register(new Type({ - "key": "sometype", - "glyph": "X", - "etc": "..." -})); -``` - -### Benefits - -* Easier to understand (less "magic"). -* Lends itself naturally to substitution of different implementations - of the same interface. -* Allows for run-time decisions about exactly what gets registered. - -### Detriments - -* Adds some modest boilerplate. -* Provides more opportunity to "do it wrong." - -## Normalize naming conventions - -Adopt and obey the following naming conventions for AMD modules -(and for injectable dependencies, which may end up being modules): - -* Use `UpperCamelCase` for classes. -* Use `lowerCase` names for instances. - * Use `someNoun` for object instances which implement some - interface. The noun should match the implemented interface, - when applicable. - * `useSomeVerb` for functions. -* Use `ALL_CAPS_WITH_UNDERSCORES` for other values, including - "struct-like" objects (that is, where the object conceptually - contains properties rather than methods.) - -### Benefits - -* Once familiar with the conventions, easier to understand what - individual modules are. - -### Detriments - -* A little bit inflexible. - -## Expose no third-party APIs - -As a general practice, expose no third-party APIs as part of the -platform. - -For cases where you do want to access third-party APIs directly -from other scripts, this behavior should be "opt-in" instead of -mandatory. For instance, to allow addition of Angular templates, -an Angular-support bundle could be included which provides an -`AngularView` class, a `controllerRegistry`, et cetera. Importantly, -such a bundle would need to be kept separate from the platform API, -or appropriately marked as non-platform in the API docs (an -`@experimental` tag would be nice here if we feel like extending -JSDoc.) - -### Benefits - -* Simplifies learning curve (only one API to learn.) -* Reduces Angular dependency. -* Avoids the problems of ubiquitous dependencies generally. - -### Detriments - -* Increases documentation burden. - -## Register Extensions as Instances instead of Constructors - -Register extensions as object instances instead of constructors. -This allows for API flexibility w.r.t. constructor signatures -(and avoids the need for partial constructors) and additionally -makes it easier to provide platform implementations of extensions -that can be used, subclassed, etc. - -For instance, instead of taking an `ActionContext` in its -constructor, an `Action` would be instantiated once and would -accept appropriate arguments to its methods: - -```js -function SomeAction { -} -SomeAction.prototype.canHandle = function (actionContext) { - // Check if we can handle this context -}; -SomeAction.prototype.perform = function (actionContext) { - // Perform this action, in this context -}; -``` - -### Benefits - -* Reduces scope of interfaces to understand (don't need to know - what constructor signature to provide for compatibility.) - -### Detriments - -* Requires refactoring of various types; may result in some - awkward APIs or extra factory interfaces. - -## Remove capability delegation - -The `delegation` capability has only been useful for the -`telemetry` capability, but using both together creates -some complexity to manage. In practice, these means that -telemetry views need to go through `telemetryHandler` to -get their telemetry, which in turn has an awkward API. - -This could be resolved by: - -* Removing `delegation` as a capability altogether. -* Reworking `telemetry` capability API to account for - the possibility of multiple telemetry-providing - domain objects. (Perhaps just stick `domainObject` - in as a field in each property of `TelemetryMetadata`?) -* Move the behavior currently found in `telemetryHandler` - into the `telemetry` capability itself (either the - generic version, or a version specific to telemetry - panels - probably want some distinct functionality - for each.) - -### Benefits - -* Reduces number of interfaces. -* Accounting for the possibility of multiple telemetry objects - in the `telemetry` capability API means that views using - this will be more immediately aware of this as a possibility. - -### Detriments - -* Increases complexity of `telemetry` capability's interface - (although this could probably be minimized.) - -## Nomenclature Change - -Instead of presenting Open MCT as a "framework" or -"platform", present it as an "extensible application." - -This is mostly a change for the developer guide. A -"framework" and a "platform" layer would still be useful -architecturally, but the plugin developer's mental model -for this would then be inclined toward looking at defined -extension points. The underlying extension mechanism could -still be exposed to retain the overall expressive power of -the application. - -This may subtly influence other design decisions in order -to match the "extensible application" identity. On a certain -level, this contradicts the proposal to -[rename views to applications](#rename-views-to-applications). - -### Benefits - -* May avoid incurring some of the "framework aversion" that - is common among JavaScript developers. -* More accurately describes the application. - -### Detriments - -* May also be a deterrent to developers who prefer the more - "green field" feel of developing applications on a useful - platform. - -## Capabilities as Mixins - -Change the behavior of capabilities such that they act as -mixins, adding additional methods to domain objects. -Checking if a domain object has a `persistence` capability -would instead be reduced to checking if it has a `persist` -method. - -Mixins would be applied in priority order and filtered for -applicability by policy. - -### Benefits - -* Replaces "capabilities" (which, as a concept, can be hard - to grasp) with a more familiar "mixins" concept, which has - been used more generally across many languages. -* Reduces interface depth. - -### Detriments - -* Requires checking for the interface exposed by a domain - object. Alternately, could use `instanceof`, but would - need to take care to ensure that the prototype chain of - the domain object is sufficient to do this (which may - enforce awkward or non-obvious constraints on the way these - mixins are implemented.) -* May complicate documentation; understanding the interface - of a given domain object requires visiting documentation - for various mixins. - -## Remove Applies-To Methods - -Remove all `appliesTo` static methods and replace them with -appropriate policy categories. - -### Benefits - -* Reduces sizes of interfaces. Handles filtering down sets - of extensions in a single consistent way. - -### Detriments - -* Mixes formal applicability with policy; presently, `appliesTo` - is useful for cases where a given extension cannot, even in - principle, be applied in a given context (e.g. a domain object - model is missing the properties which describe the behavior), - whereas policy is useful for cases where applicability is - being refined for business or usability reasons. Colocating - the former with the extension itself has some benefits - (exhibits better cohesion.) - * This could be mitigated in the proposed approach by locating - `appliesTo`-like policies in the same bundle as the relevant - extension. - -## Revise Telemetry API - -Revise telemetry API such that: - -* `TelemetrySeries` is replaced with arrays of JavaScript objects - with properties. -* It is no longer necessary to use `telemetryHandler` (plays well - with proposal to - [remove capability delegation](#remove-capability delegation)) -* Change `request` call to take a callback, instead of returning - a promise. This allows that callback to be invoked several - times (e.g. for progressive loading, or to reflect changes from - the time conductor.) - -Should also consider: - -* Merge `subscribe` functionality into `request`; that is, handle - real-time data as just another thing that triggers the `request` - callback. -* Add a useful API to telemetry metadata, allowing things like - formats to be retrieved directly from there. - -As a consequence of this, `request` would need to return an object -representing the active request. This would need to be able to -answer the following questions and provide the following behavior: - -* Has the request been fully filled? (For cases like progressive - loading?) -* What data has changed since the previous callback? (To support - performance optimizations in plotting; e.g. append real-time - data.) -* Stop receiving updates for this request. -* Potentially, provide utility methods for dealing with incoming - data from the request. - -Corollary to this, some revision of `TelemetryMetadata` properties -may be necessary to fully and usably describe the contents of -a telemetry series. - -### Benefits - -* Reduces interface depth. -* Reduces interface size (number of methods.) -* Supports a broader range of behaviors (e.g. progressive loading) - within the same interface. - -### Detriments - -* Merging with `subscribe` may lose the clarity/simplicity of the - current API. - -## Allow Composite Services to Fail Gracefully - -Currently, when no providers are available for a composite service -that is depended-upon, dependencies cannot be resolved and the -application fails to initialize, with errors appearing in the -developer console. - -This is acceptable behavior for truly unrecoverable missing -dependencies, but in many cases it would be preferable to allow a -given type of composite service to define some failure behavior -when no service of an appropriate type is available. - -To address this: - -* Provide an interface (preferably - [imperative](#bundle-Declarations-in-javascript)) - for declaring composite services, independent of any implementation - of an aggregator/decorator/provider. This allows the framework - layer to distinguish between unimplemented dependencies (which - could have defined failover strategies) from undefined dependencies - (which cannot.) -* Provide a default strategy for service composition that picks - the highest-priority provider, and logs an error (and fails to - satisfy) if no providers have been defined. -* Allow this aggregation strategy to be overridden, much as one - can declare aggregators currently. However, these aggregators should - get empty arrays when no providers have been registered (instead of - being ignored), at which point they can decide how to handle this - situation (graceful failure when it's possible, noisy errors when - it is not.) - -### Benefits - -* Allows for improved robustness and fault tolerance. -* Makes service declarations explicit, reducing "magic." - -### Detriments - -* Requires the inclusion of software units which define services, - instead of inferring their existence (slight increase in amount - of code that needs to be written.) -* May result in harder-to-understand errors when overridden - composition strategies do not failover well (that is, when they - do need at least implementation, but fail to check for this.) - -## Plugins as Angular Modules - -Do away with the notion of bundles entirely; use Angular modules -instead. Registering extensions or components of composite services -would then be handled by configuring a provider; reusable classes -could be exposed by the platform for these. - -Example (details are flexible, included for illustrative purposes): - -```javascript -var mctEdit = angular.module('mct-edit', ['ng', 'mct']); - -// Expose a new extension category -mctEdit.provider('actionRegistry', ExtensionCategoryProvider); - -// Expose a new extension -mctEdit.config(['actionRegistryProvider', function (arp) { - arp.register(EditPropertiesAction); -}]) - -return mctEdit; -``` - -Incompatible with proposal to -(expose no third-party APIs)[#expose-no-third-party-apis]; Angular -API would be ubiquitously exposed. - -This is a more specific variant of -(Bundle Declarations in JavaScript)[#bundle-declarations-in-javascript]. - -### Benefits - -* Removes a whole category of API (bundle definitions), reducing - learning curve associated with the software. -* Closer to Angular style, reducing disconnect between learning - Angular and learning Open MCT (reducing burden of having - to learn multiple paradigms.) -* Clarifies "what can be found where" (albeit not perfectly) - since you can look to module dependencies and follow back from there. - -### Detriments - -* Hardens dependency on Angular. -* Increases depth of understanding required of Angular. -* Increases amount of boilerplate (since a lot of this has - been short-handed by existing framework layer.) - -## Contextual Injection - -For extensions that depend on certain instance-level run-time -properties (e.g. actions or views which use objects and/or specific -capabilities of those objects), declare these features as dependencies -and expose them via dependency injection. (AngularJS does this for -`$scope` in the context of controllers, for example.) - -A sketch of an implementation for this might look like: - -```js -function ExtensionRegistry($injector, extensions, getLocals) { - this.$injector = $injector; - this.extensions = extensions; - this.getLocals = getLocals; -} -ExtensionRegistry.prototype.get = function () { - var $injector = this.$injector, - locals = this.getLocals.apply(null, arguments); - return this.extensions.filter(function (extension) { - return depsSatisfiable(extension, $injector, locals); - }).map(function (extension) { - return $injector.instantiate(extension, locals); - }); -}; - - -function ExtensionRegistryProvider(getLocals) { - this.getLocals = getLocals || function () { return {}; }; - this.extensions = []; -} -ExtensionRegistryProvider.prototype.register = function (extension) { - this.extensions.push(extension); -}; -ExtensionRegistryProvider.prototype.$get = ['$injector', function ($injector) { - return new ExtensionRegistry($injector, this.extensions, this.getLocals); -}]; -``` - -Extension registries which need to behave context-sensitively could -subclass this to describe how these contextual dependencies are satisfied -(for instance, by returning various capability properties in `getLocals`). - -Specific extensions could then declare dependencies as appropriate to the -registry they are using: - -```js -app.config(['actionRegistryProvider', function (arp) { - arp.register(['contextCapability', 'domainObject', RemoveAction]); -}]); -``` - -### Benefits - -* Allows contextual dependencies to be fulfilled in the same (or similar) - manner as global dependencies, increasing overall consistency of API. -* Clarifies dependencies of individual extensions (currently, extensions - themselves or policies generally need to imperatively describe what - dependencies will be used in order to filter down to applicable - extensions.) -* Factors out some redundant code from relevant extensions; actions, - for instance, no longer need to interpret an `ActionContext` object. - Instead, their constructors take inputs that are more relevant to - their behavior. -* Removes need for partial construction, as any arguments which would - normally be appended after partialization can instead be declared as - dependencies. Constructors in general become much less bound to the - specifics of the platform. - -### Detriments - -* Slightly increases dependency on Angular; other dependency injectors - may not offer comparable ways to specify dependencies non-globally. -* Not clear (or will take effort to make clear) which dependencies are - available for which extensions. Could be mitigated by standardizing - descriptions of context across actions and views, but that may offer - its own difficulties. -* May seem counter-intuitive coming from "vanilla" AngularJS, where - `$scope` is the only commonly-used context-sensitive dependency. - -## Add new abstractions for actions - -Originally suggested in -[this comment](https://github.com/nasa/openmctweb/pull/69#issuecomment-156199991): - -> I think there are some grey areas with actions: are they all directly -tied to user input? If so, why do they have any meaning in the back end? -Maybe we should look at different abstractions for actions: - -> * `actions` - the basic implementation of an action, essentially a - function declaration. for example, `copy` requires arguments of - `object` and a `target` to place the object in. at this level, - it is reusable in a CLI. -> * `context menu actions` - has criteria for what it applies to. - when it is visible, and defines how to get extra > input from a - user to complete that action. UI concern only. -> * `gesture-handler` - allows for mapping a `gesture` to an action, - e.g. drag and drop for link. UI Concern only. - -> We could add context menu actions for domain objects which navigate -to that object, without having to implement an action that has no real -usage on a command line / backend. - -### Benefits - -* Clearly delineates concerns (UI versus model) - -### Detriments - -* Increases number of interfaces. - -## Add gesture handlers - -See [Add new abstractions for actions](#add-new-abstractions-for-actions); -adding an intermediary between gestures and the actions that they -trigger could be useful in separating concerns, and for more easily -changing mappings in a mobile context. - -### Benefits - -* Clearly decouples UI concerns from the underlying model changes - they initiate. -* Simplifies and clarifies mobile support. - -### Detriments - -* Increases number of interfaces. - -# Decisions - -After review on Dec. 8, 2015, team consensus on these proposals is -as follows: - -Proposal | @VWoeltjen | @larkin | @akhenry | Consensus -----|:---:|:---:|:---:|:---: -RequireJS as dependency injector | :-1: | :neutral_face: :question: | [:-1:](https://github.com/nasa/openmctweb/pull/69#discussion_r44349731) | [:question:](https://github.com/nasa/openmctweb/issues/461) -Arbitrary HTML Views | :+1: | :+1: | | [:+1: 1](https://github.com/nasa/openmctweb/issues/463) -Wrap Angular Services | :-1: | [:-1:](https://github.com/nasa/openmctweb/pull/69#discussion_r43801221) | [:-1:](https://github.com/nasa/openmctweb/pull/69#discussion_r44355057) | :no_entry_sign: -Bundle Declarations in JavaScript | :+1: | :neutral_face: :question: | | [:+1:](https://github.com/nasa/openmctweb/issues/450) -Pass around a dependency injector | :-1: | :-1: | | :-1: -Remove partial constructors | :+1: | :+1: | | [:+1:](https://github.com/nasa/openmctweb/issues/462) -Rename Views to ~~Applications~~ | :+1: | :neutral_face: :question: | | [:+1: 2](https://github.com/nasa/openmctweb/issues/463) -Provide Classes for Extensions | :+1: | :+1: | | [:+1:](https://github.com/nasa/openmctweb/issues/462) -Normalize naming conventions | :+1: | :+1: | | :+1: -Expose no third-party APIs | :+1: * | [:-1:](https://github.com/nasa/openmctweb/pull/69#discussion_r43801221) | [:+1:](https://github.com/nasa/openmctweb/pull/69#discussion_r43801221) † | :+1: 3 -Register Extensions as Instances instead of Constructors | :+1: | :-1: | | [:+1:](https://github.com/nasa/openmctweb/issues/462) -Remove capability delegation | :+1: | :+1: | | [:+1:](https://github.com/nasa/openmctweb/issues/463) -Nomenclature Change | :+1: | [:+1:](https://github.com/nasa/openmctweb/issues/229#issuecomment-153453035) | | :white_check_mark: ‡ -Capabilities as Mixins | | :+1: | [:+1:](https://github.com/nasa/openmctweb/pull/69#discussion_r44355473) | [:question: 4](https://github.com/nasa/openmctweb/issues/463) -Remove Applies-To Methods | | :-1: | | :-1: -Revise Telemetry API | :+1: | :+1: | | [:+1: 5](https://github.com/nasa/openmctweb/issues/463) -Allow Composite Services to Fail Gracefully | :+1: | :-1: | | [:+1: 6](https://github.com/nasa/openmctweb/issues/463) -Plugins as Angular Modules | :+1: | :neutral_face: :question: | | [:question:](https://github.com/nasa/openmctweb/issues/461) -Contextual Injection | | :-1: | | [:question:](https://github.com/nasa/openmctweb/issues/461) -Add new abstractions for actions | [:-1:](https://github.com/nasa/openmctweb/pull/69#issuecomment-158172485) :question: | :+1: | | :-1: -Add gesture handlers | :+1: | :+1: :question: | | [:+1:](https://github.com/nasa/openmctweb/issues/463) - -* Excepting Angular APIs. Internally, continue to use code style -where classes are declared separately from their registration, such -that ubiquity of Angular dependency is minimized. - -† "I think we should limit the third party APIs we expose to -one or two, but I worry it might be counterproductive to -completely hide them." - -‡ Some ambiguity about what to call ourselves if not a platform, -but general agreement that "platform" is not a good term. -More Detail on Pete's Opinions Here: -https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign_PeteRichards.md#notes-on-current-api-proposals - -1 Needs to be designed carefully; don't want to do this with -a complicated interface, needs to be significantly simpler than wrapping -with an Angular directive would be. - -2 Agree that we need a new name, but it should not be "application" - -3 Don't want to expose (or require usage of) third-party -APIs generally. Angular may be an exception in the sense that it is an -API we presume to be present. Can use third-party APIs internally, but -don't want to support them or be tied to them. - -4 Want to have a separate spin-off discussion about -capabilities. Want to consider several alternatives here. -At minimum, though, mixins would be an improvement relative -to how these are currently handled. - -5 Agree we want to revise APIs, but this should -be a larger spin-off. - -6 Not necessarily as described, but expected to be a -property of composite services in whatever formulation they -take. Should not be default behavior. - - -[Additional proposals](APIRedesign_PeteRichards.md) considered: - -Proposal | Consensus -------|------ -Imperative component registries | [:+1:](https://github.com/nasa/openmctweb/issues/462) -Get rid of "extension category" concept. | [:+1:](https://github.com/nasa/openmctweb/issues/462) -Reduce number and depth of extension points | :+1: -Composite services should not be the default | [:question:](https://github.com/nasa/openmctweb/issues/463) -Get rid of views, representations, and templates. | [:+1: 1](https://github.com/nasa/openmctweb/issues/463) -More angular: for all services | [:question:](https://github.com/nasa/openmctweb/issues/461) -Less angular: only for views | [:question:](https://github.com/nasa/openmctweb/issues/461) -Use systemjs for module loading | [:+1: 2](https://github.com/nasa/openmctweb/issues/459) -Use gulp or grunt for standard tooling | [:+1:](https://github.com/nasa/openmctweb/issues/459) -Package openmctweb as single versioned file. | [:+1:](https://github.com/nasa/openmctweb/issues/458) -Refresh on navigation | [:+1: 3](https://github.com/nasa/openmctweb/issues/463) -Move persistence adapter to promise rejection. | [:+1:](https://github.com/nasa/openmctweb/issues/463) -Remove bulk requests from providers | [:+1: 4](https://github.com/nasa/openmctweb/issues/463) - -1 Need to agree upon details at design-time, but -basic premise is agreed-upon - want to replace -views/representations/templates with a common abstraction -(and hoist out the non-commonalities to other places as appropriate) - -2 Beneficial but not strictly necessary (may be -lower-effort alternatives); should prioritize accordingly during planning - -3 Some effort will be required to make all of the state -that needs to persist among route changes actually be persistent. -Will want to address this at design-time (will want to look at -libraries to simplify this, for instance) - -4 Maybe not all providers, but anywhere there is not a -strong case for building batching into the API we should prefer -simplicity. (Want to pay specific attention to telemetry here.) diff --git a/docs/src/design/proposals/APIRedesign_PeteRichards.md b/docs/src/design/proposals/APIRedesign_PeteRichards.md deleted file mode 100644 index 6e3a94310f..0000000000 --- a/docs/src/design/proposals/APIRedesign_PeteRichards.md +++ /dev/null @@ -1,251 +0,0 @@ - - -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - -- [Reducing interface depth (the bundle.json version)](#reducing-interface-depth-the-bundlejson-version) - - [Imperative component registries](#imperative-component-registries) - - [Get rid of "extension category" concept.](#get-rid-of-extension-category-concept) - - [Reduce number and depth of extension points](#reduce-number-and-depth-of-extension-points) - - [Composite services should not be the default](#composite-services-should-not-be-the-default) - - [Get rid of views, representations, and templates.](#get-rid-of-views-representations-and-templates) -- [Reducing interface depth (The angular discussion)](#reducing-interface-depth-the-angular-discussion) - - [More angular: for all services](#more-angular-for-all-services) - - [Less angular: only for views](#less-angular-only-for-views) -- [Standard packaging and build system](#standard-packaging-and-build-system) - - [Use systemjs for module loading](#use-systemjs-for-module-loading) - - [Use gulp or grunt for standard tooling](#use-gulp-or-grunt-for-standard-tooling) - - [Package openmctweb as single versioned file.](#package-openmctweb-as-single-versioned-file) -- [Misc Improvements](#misc-improvements) - - [Refresh on navigation](#refresh-on-navigation) - - [Move persistence adapter to promise rejection.](#move-persistence-adapter-to-promise-rejection) - - [Remove bulk requests from providers](#remove-bulk-requests-from-providers) -- [Notes on current API proposals:](#notes-on-current-api-proposals) -- [[1] Footnote: The angular debacle](#1-footnote-the-angular-debacle) - - ["Do or do not, there is no try"](#do-or-do-not-there-is-no-try) - - [A lack of commitment](#a-lack-of-commitment) - - [Commitment is good!](#commitment-is-good) - - - - -# Reducing interface depth (the bundle.json version) - -## Imperative component registries - -Transition component registries to javascript, get rid of bundle.json and bundles.json. Prescribe a method for application configuration, but allow flexibility in how application configuration is defined. - -Register components in an imperative fashion, see angularApp.factory, angularApp.controller, etc. Alternatively, implement our own application object with new registries and it's own form of registering objects. - -## Get rid of "extension category" concept. - -The concept of an "extension category" is itself an extraneous concept-- an extra layer of interface depth, an extra thing to learn before you can say "hello world". Extension points should be clearly supported and documented with whatever interfaces make sense. Developers who wish to add something that is conceptually equivalent to an extension category can do so directly, in the manner that suites their needs, without us forcing a common method on them. - -## Reduce number and depth of extension points - -Clearly specify supported extension points (e.g. persistence, model providers, telemetry providers, routes, time systems), but don't claim that the system has a clear and perfect repeatable solution for unknown extension types. New extension categories can be implemented in whatever way makes sense, without prescribing "the one and only system for managing extensions". - -The underlying problem here is we are predicting needs for extension points where none exist-- if we try and design the extension system before we know how it is used, we design the wrong thing and have to rewrite it later. - -## Composite services should not be the default - -Understanding composite services, and describing services as composite services can confuse developers. Aggregators are implemented once and forgotten, while decorators tend to be hacky, brittle solutions that are generally needed to avoid circular imports. While composite services are a useful construct, it reduces interface depth to implement them as registries + typed providers. - -You can write a provider (provides "thing x" for "inputs y") with a simple interface. A provider has two or more methods: -* a method which takes "inputs y" and returns True if it knows how to provide "thing x", false otherwise. -* one or more methods which provide "thing x" for objects of "inputs y". - -Actually checking whether a provider can respond to a request before asking it to do work allows for faster failure and clearer errors when no providers match the request. - -## Get rid of views, representations, and templates. - -Templates are an implementation detail that should be handled by module loaders. Views and representations become "components," and a new concept, "routes", is used to exposing specific views to end users. - -`components` - building blocks for views, have clear inputs and outputs, and can be coupled to other components when it makes sense. (e.g. parent-child components such as menu and menu item), but should have ZERO knowledge of our data models or telemetry apis. They should define data models that enable them to do their job well while still being easy to test. - -`routes` - a view type for a given domain object, e.g. a plot, table, display layout, etc. Can be described as "whatever shows in the main screen when you are viewing an object." Handle loading of data from a domain object and passing that data to the view components. Routes should support editing as it makes sense in their own context. - -To facilitate testing: - -* routes should be testable without having to test the actual view. -* components should be independently testable with zero knowledge of our data models or telemetry APIs. - -Component code should be organized side by side, such as: - -``` -app -|- components - |- productDetail - | |- productDetail.js - | |- productDetail.css - | |- productDetail.html - | |- productDetailSpec.js - |- productList - |- checkout - |- wishlist -``` - -Components are not always reusable, and we shouldn't be overly concerned with making them so. If components are heavily reused, they should either be moved to a platform feature (e.g. notifications, indicators), or broken off as an external dependency (e.g. publish mct-plot as mct-plot.js). - - -# Reducing interface depth (The angular discussion) - -Two options here: use more angular, use less angular. Wrapping angular methods does not reduce interface depth and must be avoided. - -The primary issue with angular is duplications of concerns-- both angular and the openmctweb platform implement the same tools side by side and it can be hard to comprehend-- it increases interface depth. For other concerns, see footnotes[1]. - -Wrapping angular methods for non-view related code is confusing to developers because of the random constraints angular places on these items-- developers ultimately have to understand both angular DI and our framework. For example, it's not possible to name the topic service "topicService" because angular expects Services to be implemented by Providers, which is different than our expectation. - -To reduce interface depth, we can replace our own provider and registry patterns with angular patterns, or we can only utilize angular view logic, and only use our own DI patterns. - -## More angular: for all services - -Increasing our commitment to angular would mean using more of the angular factories, services, etc, and less of our home grown tools. We'd implement our services and extension points as angular providers, and make them configurable via app.config. - -As an example, registering a specific type of model provider in angular would look like: - -```javascript -mct.provider('model', modelProvider() { /* implementation */}); - -mct.config(['modelProvider', function (modelProvider) { - modelProvider.providers.push(RootModelProvider); -}]); -``` - -## Less angular: only for views - -If we wish to use less angular, I would recommend discontinuing use of all angular components that are not view related-- services, factories, $http, etc, and implementing them in our own paradigm. Otherwise, we end up with layered interfaces-- one of the goals we would like to avoid. - - -# Standard packaging and build system - -Standardize the packaging and build system, and completely separate the core platform from deployments. Prescribe a starting point for deployments, but allow flexibility. - -## Use systemjs for module loading - -Allow developers to use whatever module loading system they'd like to use, while still supporting all standard cases. We should also use this system for loading assets (css, scss, html templates), which makes it easier to implement a single file deployment using standard build tooling. - -## Use gulp or grunt for standard tooling - -Using gulp or grunt as a task runner would bring us in line with standard web developer workflows and help standardize rendering, deployment, and packaging. Additional tools can be added to the workflow at low cost, simplifying the setup of developer environments. - -Gulp and grunt provide useful developer tooling such as live reload, automatic scss/less/etc compilation, and ease of extensibility for standard production build processes. They're key in decoupling code. - -## Package openmctweb as single versioned file. - -Deployments should depend on a specific version of openmctweb, but otherwise be allowed to have their own deployment and development toolsets. - -Customizations and deployments of openmctweb should not use the same build tooling as the core platform; instead they should be free to use their own build tools as they wish. (We would provide a template for an application, based on our experience with warp-for-rp and vista) - -Installation and utilization of openmctweb should be as simple as downloading the js file, including it in your own html page, and then initializing an app and running it. If a developer would prefer, they could use bower or npm to handle installation. - -Then, if we're using imperative methods for extending the application we can use the following for basic customization: - -```html - - -``` - -This packaging reduces the complexity of managing multiple deployed versions, and also allows us to provide users with incredibly simple tutorials-- they can use whatever tooling they like. For instance, a hello world tutorial may take the option of "exposing a new object in the tree". - -```javascript -var myApp = new OpenMCTWeb(); -myApp.roots.addRoot({ - id: 'myRoot', - name: 'Hello World!', -}); -myApp.routes.setDefault('myRoot'); -myApp.run(); -``` - -# Misc Improvements - -## Refresh on navigation -In cases where navigation events change the entire screen, we should be using routes and location changes to navigate between objects. We should be using href for all navigation events. - -At the same time, navigating should refresh state of every visible object. A properly configured persistence store will handle caching with standard cache headers and 304 not modified responses, which will provide good performance of object reloads, while helping us ensure that objects are always in sync between clients. - -View state (say, the expanded tree nodes) should not be tied to caching of data-- it should be something we intentionally persist and restore with each navigation. Data (such as object definitions) should be reloaded from server as necessary to restore state. - -## Move persistence adapter to promise rejection. -Simple: reject on fail, resolve on success. - -## Remove bulk requests from providers - -Aggregators can request multiple things at once, but individual providers should only have to implement handling at the level of a single request. Each provider can implement it's own internal batching, but it should support making requests at a finer level of detail. - -Excessive wrapping of code with $q.all causes additional digest cycles and decreased performance. - -For example, instead of every telemetry provider responding to a given telemetry request, aggregators should route each request to the first provider that can fulfill that request. - - -# Notes on current API proposals: - -* [RequireJS for Dependency Injection](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#requirejs-as-dependency-injector): requires other topics to be discussed first. -* [Arbitrary HTML Views](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#arbitrary-html-views): think there is a place for it, requires other topics to be discussed first. -* [Wrap Angular Services](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#wrap-angular-services): No, this is bad. -* [Bundle definitions in Javascript](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#bundle-declarations-in-javascript): Points to a solution, but ultimately requires more discussion. -* [pass around a dependency injector](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#pass-around-a-dependency-injector): No. -* [remove partial constructors](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#remove-partial-constructors): Yes, this should be superseded by another proposal though. The entire concept was a messy solution to dependency injection issues caused by declarative syntax. -* [Rename views to applications](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#rename-views-to-applications): Points to a problem that needs to be solved but I think the name is bad. -* [Provide classes for extensions](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#provide-classes-for-extensions): Yes, in specific places -* [Normalize naming conventions](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#normalize-naming-conventions): Yes. -* [Expose no third-party APIs](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#expose-no-third-party-apis): Completely disagree, points to a real problem with poor angular integration. -* [Register Extensions as Instances instead of Constructors](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#register-extensions-as-instances-instead-of-constructors): Superseded by the fact that we should not hope to implement a generic construct. -* [Remove capability delegation](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#remove-capability-delegation): Yes. -* [Nomenclature Change](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#nomenclature-change): Yes, hope to discuss the implications of this more clearly in other proposals. -* [Capabilities as mixins](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#capabilities-as-mixins): Yes. -* [Remove appliesTo methods](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#remove-applies-to-methods): No-- I think some level of this is necessary. I think a more holistic approach to policy is needed. it's a rather complicated system. -* [Revise telemetry API](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#revise-telemetry-api): If we can rough out and agree to the specifics, then Yes. Needs discussion. -* [Allow composite services to fail gracefully](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#allow-composite-services-to-fail-gracefully): No. As mentioned above, I think composite services themselves should be eliminated for a more purpose bound tool. -* [Plugins as angular modules](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#plugins-as-angular-modules): Should we decide to embrace Angular completely, I would support this. Otherwise, no. -* [Contextual Injection](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#contextual-injection): No, don't see a need. -* [Add New Abstractions for Actions](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#add-new-abstractions-for-actions): Worth a discussion. -* [Add gesture handlers](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#add-gesture-handlers): Yes if we can agree on details. We need a platform implementation that is easy to use, but we should not reinvent the wheel. - - - -# [1] Footnote: The angular debacle - -## "Do or do not, there is no try" - -A commonly voiced concern of embracing angular is the possibility of becoming dependent on a third party framework. This concern is itself detrimental-- if we're afraid of becoming dependent on a third party framework, then we will do a bad job of using the framework, and inevitably will want to stop using it. - -If we're using a framework, we need to use it fully, or not use it at all. - -## A lack of commitment - -A number of the concerns we heard from developers and interns can be attributed to the tenuous relationship between the OpenMCTWeb platform and angular. We claimed to be angular, but we weren't really angular. Instead, we are caught between our incomplete framework paradigm and the angular paradigm. In many cases we reinvented the wheel or worked around functionality that angular provides, and ended up in a more confusing state. - -## Commitment is good! - -We could just be an application that is built with angular. - -An application that is modular and extensible not because it reinvents tools for providing modularity and extensibility, but because it reuses existing tools for modularity and extensibility. - -There are benefits to buying into the angular paradigm: shift documentation burden to external project, engage a larger talent pool available both as voluntary open source contributors and as experienced developers for hire, and gain access to an ecosystem of tools that we can use to increase the speed of development. - -There are negatives too: Angular is a monolith, it has performance concerns, and an unclear future. If we can't live with it, we should look at alternatives. - diff --git a/docs/src/design/proposals/ImperativePlugins.md b/docs/src/design/proposals/ImperativePlugins.md deleted file mode 100644 index 1fbb83b1bc..0000000000 --- a/docs/src/design/proposals/ImperativePlugins.md +++ /dev/null @@ -1,164 +0,0 @@ -# Imperative Plugins - -This is a design proposal for handling -[bundle declarations in JavaScript]( -APIRedesign.md#bundle-declarations-in-javascript). - -## Developer Use Cases - -Developers will want to use bundles/plugins to (in rough order -of occurrence): - -1. Add new extension instances. -2. Use existing services -3. Add new service implementations. -4. Decorate service implementations. -5. Decorate extension instances. -6. Add new types of services. -7. Add new extension categories. - -Notably, bullets 4 and 5 above are currently handled implicitly, -which has been cited as a source of confusion. - -## Interfaces - -Two base classes may be used to satisfy these use cases: - - * The `CompositeServiceFactory` provides composite service instances. - Decorators may be added; the approach used for compositing may be - modified; and individual services may be registered to support compositing. - * The `ExtensionRegistry` allows for the simpler case where what is desired - is an array of all instances of some kind of thing within the system. - -Note that additional developer use cases may be supported by using the -more general-purpose `Registry` - -```nomnoml -[Factory. - | - - factoryFn : function (V) : T - | - + decorate(decoratorFn : function (T, V) : T, options? : RegistrationOptions) -]-:>[function (V) : T] - -[RegistrationOptions | - + priority : number or string -] - -[Registry. - | - - compositorFn : function (Array.) : V - | - + register(item : T, options? : RegistrationOptions) - + composite(compositorFn : function (Array.) : V, options? : RegistrationOptions) -]-:>[Factory.] -[Factory.]-:>[Factory.] - -[ExtensionRegistry.]-:>[Registry.>] -[Registry.>]-:>[Registry.] - -[CompositeServiceFactory.]-:>[Registry.] -[Registry.]-:>[Registry.] -``` - -## Examples - -### 1. Add new extension instances. - -```js -// Instance-style registration -mct.types.register(new mct.Type({ - key: "timeline", - name: "Timeline", - description: "A container for activities ordered in time." -}); - -// Factory-style registration -mct.actions.register(function (domainObject) { - return new RemoveAction(domainObject); -}, { priority: 200 }); -``` - -### 2. Use existing services - -```js -mct.actions.register(function (domainObject) { - var dialogService = mct.ui.dialogServiceFactory(); - return new PropertiesAction(dialogService, domainObject); -}); -``` - -### 3. Add new service implementations - -```js -// Instance-style registration -mct.persistenceServiceFactory.register(new LocalPersistenceService()); - -// Factory-style registration -mct.persistenceServiceFactory.register(function () { - var $http = angular.injector(['ng']).get('$http'); - return new LocalPersistenceService($http); -}); -``` - -### 4. Decorate service implementations - -```js -mct.modelServiceFactory.decorate(function (modelService) { - return new CachingModelDecorator(modelService); -}, { priority: 100 }); -``` - -### 5. Decorate extension instances - -```js -mct.capabilities.decorate(function (capabilities) { - return capabilities.map(decorateIfApplicable); -}); -``` - -This use case is not well-supported by these API changes. The most -common case for decoration is capabilities, which are under reconsideration; -should consider handling decoration of capabilities in a different way. - -### 6. Add new types of services - -```js -myModule.myServiceFactory = new mct.CompositeServiceFactory(); - -// In cases where a custom composition strategy is desired -myModule.myServiceFactory.composite(function (services) { - return new MyServiceCompositor(services); -}); -``` - -### 7. Add new extension categories. - -```js -myModule.hamburgers = new mct.ExtensionRegistry(); -``` - -## Evaluation - -### Benefits - -* Encourages separation of registration from declaration (individual - components are decoupled from the manner in which they are added - to the architecture.) -* Minimizes "magic." Dependencies are acquired, managed, and exposed - using plain-old-JavaScript without any dependency injector present - to obfuscate what is happening. -* Offers comparable expressive power to existing APIs; can still - extend the behavior of platform components in a variety of ways. -* Does not force or limit formalisms to use; - -### Detriments - -* Does not encourage separation of dependency acquisition from - declaration; that is, it would be quite natural using this API - to acquire references to services during the constructor call - to an extension or service. But, passing these in as constructor - arguments is preferred (to separate implementation from architecture.) -* Adds (negligible?) boilerplate relative to declarative syntax. -* Relies on factories, increasing number of interfaces to be concerned - with. \ No newline at end of file diff --git a/docs/src/design/proposals/Roles.md b/docs/src/design/proposals/Roles.md deleted file mode 100644 index 6148d47566..0000000000 --- a/docs/src/design/proposals/Roles.md +++ /dev/null @@ -1,138 +0,0 @@ -# Roles - -Roles are presented as an alternative formulation to capabilities -(dynamic behavior associated with individual domain objects.) - -Specific goals here: - -* Dependencies of individual scripts should be clear. -* Domain objects should be able to selectively exhibit a wide - variety of behaviors. - -## Developer Use Cases - -1. Checking for the existence of behavior. -2. Using behavior. -3. Augmenting existing behaviors. -4. Overriding existing behaviors. -5. Adding new behaviors. - -## Overview of Proposed Solution - -Remove `getCapability` from domain objects; add roles as external -services which can be applied to domain objects. - -## Interfaces - -```nomnoml -[Factory. - | - - factoryFn : function (V) : T - | - + decorate(decoratorFn : function (T, V) : T, options? : RegistrationOptions) -]-:>[function (V) : T] - -[RegistrationOptions | - + priority : number or string -]<:-[RoleOptions | - + validate : function (DomainObject) : boolean -] - -[Role. | - + validate(domainObject : DomainObject) : boolean - + decorate(decoratorFn : function (T, V) : T, options? : RoleOptions) -]-:>[Factory.] -[Factory.]-:>[Factory.] -``` - -## Examples - -### 1. Checking for the existence of behavior - -```js -function PlotViewPolicy(telemetryRole) { - this.telemetryRole = telemetryRole; -} -PlotViewPolicy.prototype.allow = function (view, domainObject) { - return this.telemetryRole.validate(domainObject); -}; -``` - -### 2. Using behavior - -```js -PropertiesAction.prototype.perform = function () { - var mutation = this.mutationRole(this.domainObject); - return this.showDialog.then(function (newModel) { - return mutation.mutate(function () { - return newModel; - }); - }); -}; -``` - -### 3. Augmenting existing behaviors - -```js -// Non-Angular style -mct.roles.persistenceRole.decorate(function (persistence) { - return new DecoratedPersistence(persistence); -}); - -// Angular style -myModule.decorate('persistenceRole', ['$delegate', function ($delegate) { - return new DecoratedPersistence(persistence); -}]); -``` - -### 4. Overriding existing behaviors - -```js -// Non-Angular style -mct.roles.persistenceRole.decorate(function (persistence, domainObject) { - return domainObject.getModel().type === 'someType' ? - new DifferentPersistence(domainObject) : - persistence; -}, { - validate: function (domainObject, next) { - return domainObject.getModel().type === 'someType' || next(); - } -}); -``` - -### 5. Adding new behaviors - -```js -function FooRole() { - mct.Role.apply(this, [function (domainObject) { - return new Foo(domainObject); - }]); -} - -FooRole.prototype = Object.create(mct.Role.prototype); - -FooRole.prototype.validate = function (domainObject) { - return domainObject.getModel().type === 'some-type'; -}; - -// -myModule.roles.fooRole = new FooRole(); -``` - - -## Evaluation - -### Benefits - -* Simplifies/standardizes augmentation or replacement of behavior associated - with specific domain objects. -* Minimizes number of abstractions; roles are just factories. -* Clarifies dependencies; roles used must be declared/acquired in the - same manner as services. - -### Detriments - -* Externalizes functionality which is conceptually associated with a - domain object. -* Relies on factories, increasing number of interfaces to be concerned - with. \ No newline at end of file diff --git a/docs/src/guide/index.md b/docs/src/guide/index.md deleted file mode 100644 index a74c55e016..0000000000 --- a/docs/src/guide/index.md +++ /dev/null @@ -1,2456 +0,0 @@ -# Open MCT Developer Guide -Victor Woeltjen - -[victor.woeltjen@nasa.gov](mailto:victor.woeltjen@nasa.gov) - -September 23, 2015 -Document Version 1.1 - -Date | Version | Summary of Changes | Author -------------------- | --------- | ------------------------- | --------------- -April 29, 2015 | 0 | Initial Draft | Victor Woeltjen -May 12, 2015 | 0.1 | | Victor Woeltjen -June 4, 2015 | 1.0 | Name Changes | Victor Woeltjen -October 4, 2015 | 1.1 | Conversion to MarkDown | Andrew Henry -April 5, 2016 | 1.2 | Added Mct-table directive | Andrew Henry - -# Introduction -The purpose of this guide is to familiarize software developers with the Open -MCT Web platform. - -## What is Open MCT -Open MCT is a platform for building user interface and display tools, -developed at the NASA Ames Research Center in collaboration with teams at the -Jet Propulsion Laboratory. It is written in HTML5, CSS3, and JavaScript, using -[AngularJS](http://www.angularjs.org) as a framework. Its intended use is to -create single-page web applications which integrate data and behavior from a -variety of sources and domains. - -Open MCT has been developed to support the remote operation of space -vehicles, so some of its features are specific to that task; however, it is -flexible enough to be adapted to a variety of other application domains where a -display tool oriented toward browsing, composing, and visualizing would be -useful. - -Open MCT provides: - -* A common user interface paradigm which can be applied to a variety of domains -and tasks. Open MCT is more than a widget toolkit - it provides a standard -tree-on-the-left, view-on-the-right browsing environment which you customize by -adding new browsable object types, visualizations, and back-end adapters. -* A plugin framework and an extensible API for introducing new application -features of a variety of types. -* A set of general-purpose object types and visualizations, as well as some -visualizations and infrastructure specific to telemetry display. - -## Client-Server Relationship -Open MCT is client software - it runs entirely in the user's web browser. As -such, it is largely 'server agnostic'; any web server capable of serving files -from paths is capable of providing Open MCT. - -While Open MCT can be configured to run as a standalone client, this is -rarely very useful. Instead, it is intended to be used as a display and -interaction layer for information obtained from a variety of back-end services. -Doing so requires authoring or utilizing adapter plugins which allow Open MCT -Web to interact with these services. - -Typically, the pattern here is to provide a known interface that Open MCT -can utilize, and implement it such that it interacts with whatever back-end -provides the relevant information. Examples of back-ends that can be utilized in -this fashion include databases for the persistence of user-created objects, or -sources of telemetry data. - -See the [Architecture Guide](../architecture/index.md#Overview) for information -on the client-server relationship. - -## Developing with Open MCT -Building applications with Open MCT typically means authoring and utilizing -a set of plugins which provide application-specific details about how Open MCT -Web should behave. - -### Technologies - -Open MCT sources are written in JavaScript, with a number of configuration -files written in JSON. Displayable components are written in HTML5 and CSS3. -Open MCT is built using [AngularJS](http://www.angularjs.org) from Google. A -good understanding of Angular is recommended for developers working with Open -MCT Web. - -### Forking -Open MCT does not currently have a single stand-alone artifact that can be -used as a library. Instead, the recommended approach for creating a new -application is to start by forking/branching Open MCT, and then adding new -features from there. Put another way, Open MCT's source structure is built -to serve as a template for specific applications. - -Forking in this manner should not require that you edit Open MCT's sources. -The preferred approach is to create a new directory (peer to `index.html`) for -the new application, then add new bundles (as described in the Framework -chapter) within that directory. - -To initially clone the Open MCT repository: -`git clone -b open-master` - -To create a fork to begin working on a new application using Open MCT: - - cd - git checkout open-master - git checkout -b - -As a convention used internally, applications built using Open MCT have -master branch names with an identifying prefix. For instance, if building an -application called 'Foo', the last statement above would look like: - - git checkout -b foo-master - -This convention is not enforced or understood by Open MCT in any way; it is -mentioned here as a more general recommendation. - -# Overview - -Open MCT is implemented as a framework component which manages a set of -other components. These components, called _bundles_, act as containers to group -sets of related functionality; individual units of functionality are expressed -within these bundles as _extensions_. - -Extensions declare dependencies on other extensions (either individually or -categorically), and the framework provides actual extension instances at -run-time to satisfy these declared dependency. This dependency injection -approach allows software components which have been authored separately (e.g. as -plugins) but to collaborate at run-time. - -Open MCT's framework layer is implemented on top of AngularJS's [dependency -injection mechanism](https://docs.angularjs.org/guide/di) and is modelled after -[OSGi](hhttp://www.osgi.org/) and its [Declarative Services component model](http://wiki.osgi.org/wiki/Declarative_Services). -In particular, this is where the term _bundle_ comes from. - -## Framework Overview - -The framework's role in the application is to manage connections between -bundles. All application-specific behavior is provided by individual bundles, or -as the result of their collaboration. - -The framework is described in more detail in the [Framework Overview](../architecture/framework.md#overview) of the -architecture guide. - -### Tiers -While all bundles in a running Open MCT instance are effectively peers, it -is useful to think of them as a tiered architecture, where each tier adds more -specificity to the application. -```nomnoml -#direction: down -[Plugins (Features external to OpenMCTWeb) *Bundle]->[OpenMCTWeb | -[Application (Plots, layouts, ElasticSearch wrapper) *Bundle]->[Platform (Core API, common UI, infrastructure) *Bundle] -[Platform (Core API, common UI, infrastructure) *Bundle]->[Framework (RequireJS, AngularJS, bundle loader)]] -``` - -* __Framework__ : This tier is responsible for wiring together the set of -configured components (called _bundles_) together to instantiate the running -application. It is responsible for mediating between AngularJS (in particular, -its dependency injection mechanism) and RequireJS (to load scripts at run-time.) -It additionally interprets bundle definitions (see explanation below, as well as -further detail in the Framework chapter.) At this tier, we are at our most -general: We know only that we are a plugin-based application. -* __Platform__: Components in the Platform tier describe both the general user -interface and corresponding developer-facing interfaces of Open MCT. This -tier provides the general infrastructure for applications. It is less general -than the framework tier, insofar as this tier introduces a specific user -interface paradigm, but it is still non-specific as to what useful features -will be provided. Although they can be removed or replaced easily, bundles -provided by the Platform tier generally should not be thought of as optional. -* __Application__: The application tier consists of components which utilize the -infrastructure provided by the Platform to provide functionality which will (or -could) be useful to specific applications built using Open MCT. These -include adapters to specific persistence back-ends (such as ElasticSearch or -CouchDB) as well as bundles which describe more user-facing features (such as -_Plot_ views for visualizing time series data, or _Layout_ objects for -display-building.) Bundles from this tier can be added or removed without -compromising basic application functionality, with the caveat that at least one -persistence adapter needs to be present. -* __Plugins__: Conceptually, this tier is not so different from the application -tier; it consists of bundles describing new features, back-end adapters, that -are specific to the application being built on Open MCT. It is described as -a separate tier here because it has one important distinction from the -application tier: It consists of bundles that are not included with the platform -(either authored anew for the specific application, or obtained from elsewhere.) - -Note that bundles in any tier can go off and consult back-end services. In -practice, this responsibility is handled at the Application and/or Plugin tiers; -Open MCT is built to be server-agnostic, so any back-end is considered an -application-specific detail. - -## Platform Overview - -The "tiered" architecture described in the preceding text describes a way of -thinking of and categorizing software components of a Open MCT application, -as well as the framework layer's role in mediating between these components. -Once the framework layer has wired these software components together, however, -the application's logical architecture emerges. - -An overview of the logical architecture of the platform is given in the -[Platform Architecture](../architecture/platform.md#platform-architecture) -section of the Platform guide - -### Web Services - -As mentioned in the Introduction, Open MCT is a platform single-page -applications which runs entirely in the browser. Most applications will want to -additionally interact with server-side resources, to (for example) read -telemetry data or store user-created objects. This interaction is handled by -individual bundles using APIs which are supported in browser (such as -`XMLHttpRequest`, typically wrapped by Angular's `$http`.) - -```nomnoml -#direction: right -[Web Service #1] <- [Web Browser] -[Web Service #2] <- [Web Browser] -[Web Service #3] <- [Web Browser] -[ Web Browser | - [ Open MCT | - [Plugin Bundle #1]-->[Core API] - [Core API]<--[Plugin Bundle #2] - [Platform Bundle #1]-->[Core API] - [Platform Bundle #2]-->[Core API] - [Platform Bundle #3]-->[Core API] - [Core API]<--[Platform Bundle #4] - [Core API]<--[Platform Bundle #5] - [Core API]<--[Plugin Bundle #3] - ] - [Open MCT] ->[Browser APIs] -] -``` - -This architectural approach ensures a loose coupling between applications built -using Open MCT and the backends which support them. - -### Glossary - -Certain terms are used throughout Open MCT with consistent meanings or -conventions. Other developer documentation, particularly in-line documentation, -may presume an understanding of these terms. - -* __bundle__: A bundle is a removable, reusable grouping of software elements. -The application is composed of bundles. Plug-ins are bundles. -* __capability__: A JavaScript object which exposes dynamic behavior or -non-persistent state associated with a domain object. -* __category__: A machine-readable identifier for a group that something may -belong to. -* __composition__: In the context of a domain object, this refers to the set of -other domain objects that compose or are contained by that object. A domain -object's composition is the set of domain objects that should appear immediately - beneath it in a tree hierarchy. A domain object's composition is described in -its model as an array of identifiers; its composition capability provides a -means to retrieve the actual domain object instances associated with these -identifiers asynchronously. -* __description__: When used as an object property, this refers to the human- -readable description of a thing; usually a single sentence or short paragraph. -(Most often used in the context of extensions, domain object models, or other -similar application-specific objects.) -* __domain object__: A meaningful object to the user; a distinct thing in the -work support by Open MCT. Anything that appears in the left-hand tree is a -domain object. -* __extension__: An extension is a unit of functionality exposed to the platform -in a declarative fashion by a bundle. The term 'extension category' is used to -distinguish types of extensions from specific extension instances. -* __id__: A string which uniquely identifies a domain object. -* __key__: When used as an object property, this refers to the machine-readable -identifier for a specific thing in a set of things. (Most often used in the -context of extensions or other similar application-specific object sets.) This -term is chosen to avoid attaching ambiguous meanings to 'id'. -* __model__: The persistent state associated with a domain object. A domain -object's model is a JavaScript object which can be converted to JSON without -losing information (that is, it contains no methods.) -* __name__: When used as an object property, this refers to the human-readable -name for a thing. (Most often used in the context of extensions, domain object -models, or other similar application-specific objects.) -* __navigation__: Refers to the current state of the application with respect to -the user's expressed interest in a specific domain object; e.g. when a user -clicks on a domain object in the tree, they are navigating to it, and it is -thereafter considered the navigated object (until the user makes another such -choice.) This term is used to distinguish navigation from selection, which -occurs in an editing context. -* __space__: A machine-readable name used to identify a persistence store. -Interactions with persistence with generally involve a space parameter in some -form, to distinguish multiple persistence stores from one another (for cases -where there are multiple valid persistence locations available.) -* __source__: A machine-readable name used to identify a source of telemetry -data. Similar to "space", this allows multiple telemetry sources to operate -side-by-side without conflicting. - -# Framework - -Open MCT is built on the [AngularJS framework]( http://www.angularjs.org ). A -good understanding of that framework is recommended. - -Open MCT adds an extra layer on top of AngularJS to (a) generalize its -dependency injection mechanism slightly, particularly to handle many-to-one -relationships; and (b) handle script loading. Combined, these features become a -plugin mechanism. - -This framework layer operates on two key concepts: - -* __Bundle:__ A bundle is a collection of related functionality that can be -added to the application as a group. More concretely, a bundle is a directory -containing a JSON file declaring its contents, as well as JavaScript sources, -HTML templates, and other resources used to support that functionality. (The -term bundle is borrowed from [OSGi](http://www.osgi.org/) - which has also -inspired many of the concepts used in the framework layer. A familiarity with -OSGi, particularly Declarative Services, may be useful when working with Open -MCT Web.) -* __Extension:__ An extension is an individual unit of functionality. Extensions -are collected together in bundles, and may interact with other extensions. - -The framework layer, loaded and initiated from `index.html`, is the main point -of entry for an application built on Open MCT. It is responsible for wiring -together the application at run time (much of this responsibility is actually -delegated to Angular); at a high-level, the framework does this by proceeding -through four stages: - -1. __Loading definitions:__ JSON declarations are loaded for all bundles which -will constitute the application, and wrapped in a useful API for subsequent -stages. -2. __Resolving extensions:__ Any scripts which provide implementations for -extensions exposed by bundles are loaded, using Require. -3. __Registering extensions__ Resolved extensions are registered with Angular, -such that they can be used by the application at run-time. This stage includes -both registration of Angular built-ins (directives, controllers, routes, -constants, and services) as well as registration of non-Angular extensions. -4. __Bootstrapping__ The Angular application is bootstrapped; at that point, -Angular takes over and populates the body of the page using the extensions that -have been registered. - -## Bundles - -The basic configurable unit of Open MCT is the _bundle_. This term has been -used a bit already; now we'll get to a more formal definition. - -A bundle is a directory which contains: - -* A bundle definition; a file named `bundle.json`. -* Subdirectories for sources, resources, and tests. -* Optionally, a `README.md` Markdown file describing its contents (this is not -used by Open MCT in any way, but it's a helpful convention to follow.) - -The bundle definition is the main point of entry for the bundle. The framework -looks at this to determine which components need to be loaded and how they -interact. - -A plugin in Open MCT is a bundle. The platform itself is also decomposed -into bundles, each of which provides some category of functionality. The -difference between a _bundle_ and a _plugin_ is purely a matter of the intended -use; a plugin is just a bundle that is meant to be easily added or removed. When -developing, it is typically more useful to think in terms of bundles. - -### Configuring Active Bundles - -To decide which bundles should be loaded, the framework loads a file named -`bundles.json` (peer to the `index.html` file which serves the application) to -determine which bundles should be loaded. This file should contain a single JSON -array of strings, where each is the path to a bundle. These paths should not -include bundle.json (this is implicit) or a trailing slash. - -For instance, if `bundles.json` contained: - - [ - "example/builtins", - "example/extensions" - ] - -...then the Open MCT framework would look for bundle definitions at -`example/builtins/bundle.json` and `example/extensions/bundle.json`, relative -to the path of `index.html`. No other bundles would be loaded. - -### Bundle Definition - -A bundle definition (the `bundle.json` file located within a bundle) contains a -description of the bundle itself, as well as the information exposed by the -bundle. - -This definition is expressed as a single JSON object with the following -properties (all of which are optional, falling back to reasonable defaults): - -* `key`: A machine-readable name for the bundle. (Currently used only in -logging.) -* `name`: A human-readable name for the bundle. (Also only used in logging.) -* `sources`: Names a directory in which source scripts (which will implement -extensions) are located. Defaults to 'src' -* `resources`: Names a directory in which resource files (such as HTML templates, -images, CS files, and other non-JavaScript files needed by this bundle) are -located. Defaults to 'res' -* `libraries`: Names a directory in which third-party libraries are located. -Defaults to 'lib' -* `configuration`: A bundle's configuration object, which should be formatted as -would be passed to require.config (see [RequireJS documentation](http://requirejs.org/docs/api.html ) ); -note that only paths and shim have been tested. -* `extensions`: An object containing key-value pairs, where keys are extension -categories, and values are extension definitions. See the section on Extensions -for more information. - -For example, the bundle definition for example/policy looks like: - - { - "name": "Example Policy", - "description": "Provides an example of using policies.", - "sources": "src", - "extensions": { - "policies": [ - { - "implementation": "ExamplePolicy.js", - "category": "action" - } - ] - } - } - -### Bundle Directory Structure - -In addition to the directories defined in the bundle definition, a bundle will -typically contain other directories not used at run-time. Additionally, some -useful development scripts (such as the command line build and the test suite) -expect this directory structure to be in use, and may ignore options chosen by -`bundle.json`. It is recommended that the directory structure described below be -used for new bundles. - -* `src`: Contains JavaScript sources for this bundle. May contain additional -subdirectories to organize these sources; typically, these subdirectories are -named to correspond to the extension categories they contain and/or support, but -this is only a convention. -* `res`: Contains other files needed by this bundle, such as HTML templates. May -contain additional subdirectories to organize these sources. -* `lib`: Contains JavaScript sources from third-party libraries. These are -separated from bundle sources in order to ignore them during code style checking -from the command line build. -* `test`: Contains JavaScript sources implementing [Jasmine](http://jasmine.github.io/) -tests, as well as a file named `suite.json` describing which files to test. -Should have the same folder structure as the `src` directory; see the section on -automated testing for more information. - -For example, the directory structure for bundle `platform/commonUI/dialog` looks -like: - - Platform - | - |-commonUI - | - +-dialog - | - |-res - | - |-src - | - |-test - | - |-bundle.json - | - +-README.md - -## Extensions - -While bundles provide groupings of related behaviors, the individual units of -behavior are called extensions. - -Extensions belong to categories; an extension category is the machine-readable -identifier used to identify groups of extensions. In the `extensions` property -of a bundle definition, the keys are extension categories and the values are -arrays of extension definitions. - -### General Extensions - -Extensions are intended as a general-purpose mechanism for adding new types of -functionality to Open MCT. - -An extension category is registered with Angular under the name of the -extension, plus a suffix of two square brackets; so, an Angular service (or, -generally, any other extension) can access the full set of registered -extensions, from all bundles, by including this string (e.g. `types[]` to get -all type definitions) in a dependency declaration. - -As a convention, extension categories are given single-word, plural nouns for -names within Open MCT (e.g. `types`.) This convention is not enforced by the -platform in any way. For extension categories introduced by external plugins, it -is recommended to prefix the extension category with a vendor identifier (or -similar) followed by a dot, to avoid collisions. - -### Extension Definitions - -The properties used in extension definitions are typically unique to each -category of extension; a few properties have standard interpretations by the -platform. - -* `implementation`: Identifies a JavaScript source file (in the sources -folder) which implements this extension. This JavaScript file is expected to -contain an AMD module (see http://requirejs.org/docs/whyamd.html#amd ) which -gives as its result a single constructor function. -* `depends`: An array of dependencies needed by this extension; these will be -passed on to Angular's [dependency injector](https://docs.angularjs.org/guide/di ) . -By default, this is treated as an empty array. Note that depends does not make -sense without `implementation` (since these dependencies will be passed to the -implementation when it is instantiated.) -* `priority`: A number or string indicating the priority order (see below) of -this extension instance. Before an extension category is registered with -AngularJS, the extensions of this category from all bundles will be concatenated -into a single array, and then sorted by priority. - -Extensions do not need to have an implementation. If no implementation is -provided, consumers of the extension category will receive the extension -definition as a plain JavaScript object. Otherwise, they will receive the -partialized (see below) constructor for that implementation, which will -additionally have all properties from the extension definition attached. - -#### Partial Construction - -In general, extensions are intended to be implemented as constructor functions, -which will be used elsewhere to instantiate new objects of that type. However, -the Angular-supported method for dependency injection is (effectively) -constructor-style injection; so, both declared dependencies and run-time -arguments are competing for space in a constructor's arguments. - -To resolve this, the Open MCT framework registers extension instances in a -partially constructed form. That is, the constructor exposed by the extension's -implementation is effectively decomposed into two calls; the first takes the -dependencies, and returns the constructor in its second form, which takes the -remaining arguments. - -This means that, when writing implementations, the constructor function should -be written to include all declared dependencies, followed by all run-time -arguments. When using extensions, only the run-time arguments need to be -provided. - -#### Priority - -Within each extension category, registration occurs in priority order. An -extension's priority may be specified as a `priority` property in its extension -definition; this may be a number, or a symbolic string. Extensions are -registered in reverse order (highest-priority first), and symbolic strings are -mapped to the numeric values as follows: - -* `fallback`: Negative infinity. Used for extensions that are not intended for -use (that is, they are meant to be overridden) but are present as an option of -last resort. -* `default`: `-100`. Used for extensions that are expected to be overridden, but -need a useful default. -* `none`: `0`. Also used if no priority is specified, or if an unknown or -malformed priority is specified. -* `optional`: `100`. Used for extensions that are meant to be used, but may be -overridden. -* `preferred`: `1000`. Used for extensions that are specifically intended to be -used, but still may be overridden in principle. -* `mandatory`: Positive infinity. Used when an extension should definitely not -be overridden. - -These symbolic names are chosen to support usage where many extensions may -satisfy a given need, but only one may be used; in this case, as a convention it -should be the lowest-ordered (highest-priority) extensions available. In other -cases, a full set (or multi-element subset) of extensions may be desired, with a -specific ordering; in these cases, it is preferable to specify priority -numerically when declaring extensions, and to understand that extensions will be -sorted according to these conventions when using them. - -### Angular Built-ins - -Several entities supported Angular are expressed and managed as extensions in -Open MCT. Specifically, these extension categories are _directives_, -_controllers_, _services_, _constants_, _runs_, and _routes_. - -#### Angular Directives - -New [directives]( https://docs.angularjs.org/guide/directive ) may be -registered as extensions of the directives category. Implementations of -directives in this category should take only dependencies as arguments, and -should return a directive definition object. - -The directive's name should be provided as a key property of its extension -definition, in camel-case format. - -#### Angular Controllers - -New [controllers]( https://docs.angularjs.org/guide/controller ) may be registered -as extensions of the controllers category. The implementation is registered -directly as the controller; its only constructor arguments are its declared -dependencies. - -The directive's identifier should be provided as a key property of its extension -definition. - - -#### Angular Services - -New [services](https://docs.angularjs.org/guide/services ) may be registered as -extensions of the services category. The implementation is registered via a -[service call]( https://docs.angularjs.org/api/auto/service/$provide#service ), so -it will be instantiated with the new operator. - -#### Angular Constants - -Constant values may be registered as extensions of the [ constants category](https://docs.angularjs.org/api/ng/type/angular.Module#constant ). -These extensions have no implementation; instead, they should contain a property - key , which is the name under which the constant will be registered, and a -property value , which is the constant value that will be registered. - -#### Angular Runs - -In some cases, you want to register code to run as soon as the application -starts; these can be registered as extensions of the [ runs category](https://docs.angularjs.org/api/ng/type/angular.Module#run ). -Implementations registered in this category will be invoked (with their declared -dependencies) when the Open MCT application first starts. (Note that, in -this case, the implementation is better thought of as just a function, as -opposed to a constructor function.) - -#### Angular Routes - -Extensions of category `routes` will be registered with Angular's [route provider](https://docs.angularjs.org/api/ngRoute/provider/$routeProvider ). -Extensions of this category have no implementations, and need only two -properties in their definition: - -* `when`: The value that will be passed as the path argument to `$routeProvider.when`; -specifically, the string that will appear in the trailing -part of the URL corresponding to this route. This property may be omitted, in -which case this extension instance will be treated as the default route. -* `templateUrl`: A path to the template to render for this route. Specified as a -path relative to the bundle's resource directory (`res` by default.) - -### Composite Services - -Composite services are described in the [Composite Services](../architecture/framework.md#composite-services) -section of the framework guide. - -A component should include the following properties in its extension definition: - -* `provides`: The symbolic identifier for the service that will be composed. The - fully-composed service will be registered with Angular under this name. -* `type`: One of `provider`, `aggregator` or `decorator` (as above) - -In addition to any declared dependencies, _aggregators_ and _decorators_ both -receive one more argument (immediately following declared dependencies) that is -provided by the framework. For an aggregator, this will be an array of all -providers of the same service (that is, with matching `provides` properties); -for a decorator, this will be whichever provider, decorator, or aggregator is -next in the sequence of decorators. - -Services exposed by the Open MCT platform are often declared as composite -services, as this form is open for a variety of common modifications. - -# Core API - -Most of Open MCT's relevant API is provided and/or mediated by the -framework; that is, much of developing for Open MCT is a matter of adding -extensions which access other parts of the platform by means of dependency -injection. - -The core bundle (`platform/core`) introduces a few additional object types meant -to be passed along by other services. - -## Domain Objects - -Domain objects are the most fundamental component of Open MCT's information -model. A domain object is some distinct thing relevant to a user's workflow, -such as a telemetry channel, display, or similar. Open MCT is a tool for -viewing, browsing, manipulating, and otherwise interacting with a graph of -domain objects. - -A domain object should be conceived of as the union of the following: - -* __Identifier__: A machine-readable string that uniquely identifies the domain -object within this application instance. -* __Model__: The persistent state of the domain object. A domain object's model -is a JavaScript object that can be losslessly converted to JSON. -* __Capabilities__: Dynamic behavior associated with the domain object. -Capabilities are JavaScript objects which provide additional methods for -interacting with the domain objects which expose those capabilities. Not all -domain objects expose all capabilities. - -At run-time, a domain object has the following interface: - -* `getId()`: Get the identifier for this domain object. -* `getModel()`: Get the plain state associated with this domain object. This -will return a JavaScript object that can be losslessly converted to JSON. Note -that the model returned here can be modified directly but should not be; -instead, use the mutation capability. -* `getCapability(key)`: Get the specified capability associated with this domain -object. This will return a JavaScript object whose interface is specific to the -type of capability being requested. If the requested capability is not exposed -by this domain object, this will return undefined . -* `hasCapability(key)`: Shorthand for checking if a domain object exposes the -requested capability. -* `useCapability(key, arguments )`: Shorthand for -`getCapability(key).invoke(arguments)`, with additional checking between calls. -If the provided capability has no invoke method, the return value here functions -as `getCapability` including returning `undefined` if the capability is not -exposed. - -### Identifier Syntax - -For most purposes, a domain object identifier can be treated as a purely -symbolic string; these are typically generated by Open MCT and plug-ins -should rarely be concerned with its internal structure. - -A domain object identifier has one or two parts, separated by a colon. - -* If two parts are present, the part before the colon refers to the space - in which the domain object resides. This may be a persistence space or - a purely symbolic space recognized by a specific model provider. The - part after the colon is the key to use when looking up the domain object - model within that space. -* If only one part is present, the domain object has no space specified, - and may presume to reside in the application-configured default space - defined by the `PERSISTENCE_SPACE` constant. -* Both the key and the space identifier may consist of any combination - of alphanumeric characters, underscores, dashes, and periods. - -Some examples: - -* A domain object with the identifier `foo:xyz` would have its model - loaded using key `xyz` from persistence space `foo`. -* A domain object with the identifier `bar` would have its model loaded - using key `bar` from the space identified by the `PERSISTENCE_SPACE` - constant. - -```bnf - ::= ":" | - ::= + - ::= + - ::= | | "-" | "." | "_" -``` - -## Domain Object Actions - -An `Action` is behavior that can be performed upon/using a `DomainObject`. An -Action has the following interface: - -* `perform()`: Do this action. For example, if one had an instance of a -`RemoveAction` invoking its perform method would cause the domain object which -exposed it to be removed from its container. -* `getMetadata()`: Get metadata associated with this action. Returns an object -containing: - * `name`: Human-readable name. - * `description`: Human-readable summary of this action. - * `glyph`: Single character to be displayed in Open MCT's icon font set. - * `context`: The context in which this action is being performed (see below) - -Action instances are typically obtained via a domain object's `action` -capability. - -### Action Contexts - -An action context is a JavaScript object with the following properties: - -* `domainObject`: The domain object being acted upon. -* `selectedObject`: Optional; the selection at the time of action (e.g. the -dragged object in a drag-and-drop operation.) - -## Telemetry - -Telemetry series data in Open MCT is represented by a common interface, and -packaged in a consistent manner to facilitate passing telemetry updates around -multiple visualizations. - -### Telemetry Requests - -A telemetry request is a JavaScript object containing the following properties: - -* `source`: A machine-readable identifier for the source of this telemetry. This -is useful when multiple distinct data sources are in use side-by-side. -* `key`: A machine-readable identifier for a unique series of telemetry within -that source. -* _Note: This API is still under development; additional properties, such as -start and end time, should be present in future versions of Open MCT._ - -Additional properties may be included in telemetry requests which have specific -interpretations for specific sources. - -### Telemetry Responses - -When returned from the `telemetryService` (see [Telemetry Services](#telemetry-service) -section), telemetry series data will be packaged in a `source -> key -> TelemetrySeries` -fashion. That is, telemetry is passed in an object containing key-value pairs. -Keys identify telemetry sources; values are objects containing additional -key-value pairs. In this object, keys identify individual telemetry series (and -match they `key` property from corresponding requests) and values are -`TelemetrySeries` objects (see below.) - -### Telemetry Series - -A telemetry series is a specific sequence of data, typically associated with a -specific instrument. Telemetry is modeled as an ordered sequence of domain and -range values, where domain values must be non-decreasing but range values do -not. (Typically, domain values are interpreted as UTC timestamps in milliseconds -relative to the UNIX epoch.) A series must have at least one domain and one -range, and may have more than one. - -Telemetry series data in Open MCT is expressed via the following -`TelemetrySeries` interface: - -* `getPointCount()`: Returns the number of unique points/samples in this series. -* `getDomainValue(index, [domain])`: Get the domain value at the specified index . -If a second domain argument is provided, this is taken as a string identifier -indicating which domain option (of, presumably, multiple) should be returned. -* `getRangeValue(index, [range])`: Get the domain value at the specified index . -If a second range argument is provided, this is taken as a string identifier -indicating which range option (of, presumably, multiple) should be returned. - -### Telemetry Metadata - -Domain objects which have associated telemetry also expose metadata about that -telemetry; this is retrievable via the `getMetadata()` of the telemetry -capability. This will return a single JavaScript object containing the following -properties: - -* `source`: The machine-readable identifier for the source of telemetry data for -this object. -* `key`: The machine-readable identifier for the individual telemetry series. -* `domains`: An array of supported domains (see TelemetrySeries above.) Each -domain should be expressed as an object which includes: - * `key`: Machine-readable identifier for this domain, as will be passed into - a getDomainValue(index, domain) call. - * `name`: Human-readable name for this domain. -* `ranges`: An array of supported ranges; same format as domains . - -Note that this metadata is also used as the prototype for telemetry requests -made using this capability. - -## Types -A domain object's type is represented as a Type object, which has the following -interface: - -* `getKey()`: Get the machine-readable identifier for this type. -* `getName()`: Get the human-readable name for this type. -* `getDescription()`: Get a human-readable summary of this type. -* `getGlyph()`: Get the single character to be rendered as an icon for this type -in Open MCT's custom font set. -* `getInitialModel()`: Get a domain object model that represents the initial -state (before user specification of properties) for domain objects of this type. -* `getDefinition()`: Get the extension definition for this type, as a JavaScript -object. -* `instanceOf(type)`: Check if this type is (or inherits from) a specified type . -This type can be either a string, in which case it is taken to be that type's - key , or it may be a `Type` instance. -* `hasFeature(feature)`: Returns a boolean value indicating whether or not this -type supports the specified feature, which is a symbolic string. -* `getProperties()`: Get all properties associated with this type, expressed as -an array of `TypeProperty` instances. - -### Type Features - -Features of a domain object type are expressed as symbolic string identifiers. -They are defined in practice by usage; currently, the Open MCT platform only -uses the creation feature to determine which domain object types should appear -in the Create menu. - -### Type Properties - -Types declare the user-editable properties of their domain object instances in -order to allow the forms which appear in the __Create__ and __Edit Properties__ -dialogs to be generated by the platform. A `TypeProperty` has the following interface: - -* `getValue(model)`: Get the current value for this property, as it appears in -the provided domain object model. -* `setValue(model, value)`: Set a new value for this property in the provided -domain object model . -* `getDefinition()`: Get the raw definition for this property as a JavaScript -object (as it was declared in this type's extension definition.) - -# Extension Categories - -The information in this section is focused on registering new extensions of -specific types; it does not contain a catalog of the extension instances of -these categories provided by the platform. Relevant summaries there are provided -in subsequent sections. - -## Actions Category - -An action is a thing that can be done to or using a domain object, typically as -initiated by the user. - -An action's implementation: - -* Should take a single `context` argument in its constructor. (See Action -Contexts, under Core API.) -* Should provide a method `perform` which causes the behavior associated with -the action to occur. -* May provide a method `getMetadata` which provides metadata associated with -the action. If omitted, one will be provided by the platform which includes -metadata from the action's extension definition. -* May provide a static method `appliesTo(context)` (that is, a function -available as a property of the implementation's constructor itself), which will -be used by the platform to filter out actions from contexts in which they are -inherently inapplicable. - -An action's bundle definition (and/or `getMetadata()` return value) may include: - -* `category`: A string or array of strings identifying which category or -categories an action falls into; used to determine when an action is displayed. -Categories supported by the platform include: - * `contextual`: Actions in a context menu. - * `view-control`: Actions triggered by buttons in the top-right of Browse - view. -* `key`: A machine-readable identifier for this action. -* `name`: A human-readable name for this action (e.g. to show in a menu) -* `description`: A human-readable summary of the behavior of this action. -* `glyph`: A single character which will be rendered in Open MCT's custom -font set as an icon for this action. - -## Capabilities Category - -Capabilities are exposed by domain objects (e.g. via the `getCapability` method) -but most commonly originate as extensions of this category. - -Extension definitions for capabilities should include both an implementation, -and a property named key whose value should be a string used as a -machine-readable identifier for that capability, e.g. when passed as the -argument to a domain object's `getCapability(key)` call. - -A capability's implementation should have methods specific to that capability; -that is, there is no common format for capability implementations, aside from -support for invocation via the `useCapability` shorthand. - -A capability's implementation will take a single argument (in addition to any -declared dependencies), which is the domain object that will expose that -capability. - -A capability's implementation may also expose a static method `appliesTo(model)` -which should return a boolean value, and will be used by the platform to filter -down capabilities to those which should be exposed by specific domain objects, -based on their domain object models. - -## Containers Category - -Containers provide options for the `mct-container` directive. - -The definition for an extension in the `containers` category should include: - -* `key`: An identifier for the container. -* `template`: An Angular template for the container, including an - `ng-transclude` where contained content should go. -* `attributes`: An array of attribute names. The values associated with - these attributes will be exposed in the template's scope under the - name provided by the `alias` property. -* `alias`: The property name in scope under which attributes will be - exposed. Optional; defaults to "container". - -Note that `templateUrl` is not supported for `containers`. - -## Controls Category - -Controls provide options for the `mct-control` directive. - -These standard control types are included in the forms bundle: - -* `textfield`: A text input to enter plain text. -* `numberfield`: A text input to enter numbers. -* `select`: A drop-down list of options. -* `checkbox`: A box which may be checked/unchecked. -* `color`: A color picker. -* `button`: A button. -* `datetime`: An input for UTC date/time entry; gives result as a UNIX -timestamp, in milliseconds since start of 1970, UTC. -* `composite`: A control parenting an array of other controls. -* `menu-button`: A drop-down list of items supporting custom behavior -on click. -* `dialog-button`: A button which opens a dialog allowing a single property -to be edited. -* `radio`: A radio button. - -New controls may be added as extensions of the controls category. Extensions of -this category have two properties: - -* `key`: The symbolic name for this control (matched against the control field -in rows of the form structure). -* `templateUrl`: The URL to the control's Angular template, relative to the -resources directory of the bundle which exposes the extension. - -Within the template for a control, the following variables will be included in -scope: - -* `ngModel`: The model where form input will be stored. Notably we also need to -look at field (see below) to determine which field in the model should be -modified. -* `ngRequired`: True if input is required. -* `ngPattern`: The pattern to match against (for text entry) -* `ngBlur`: A function that may be invoked to evaluate the expression - associated with the `ng-blur` attribute associated with the control. - * This should be called when the control has lost focus; for controls - which simply wrap or augment `input` elements, this should be fired - on `blur` events associated with those elements, while more complex - custom controls may fire this at the end of more specific interactions. -* `options`: The options for this control, as passed from the `options` property -of an individual row definition. -* `field`: Name of the field in `ngModel` which will hold the value for this -control. - -## Gestures Category - -A _gesture_ is a user action which can be taken upon a representation of a -domain object. - -Examples of gestures included in the platform are: - -* `drag`: For representations that can be used to initiate drag-and-drop -composition. -* `drop`: For representations that can be drop targets for drag-and-drop -composition. -* `menu`: For representations that can be used to popup a context menu. - -Gesture definitions have a property `key` which is used as a machine-readable -identifier for the gesture (e.g. `drag`, `drop`, `menu` above.) - -A gesture's implementation is instantiated once per representation that uses the -gesture. This class will receive the jqLite-wrapped `mct-representation` element -and the domain object being represented as arguments, and should do any -necessary "wiring" (e.g. listening for events) during its constructor call. The -gesture's implementation may also expose an optional `destroy()` method which -will be called when the gesture should be removed, to avoid memory leaks by way -of unremoved listeners. - -## Indicators Category - -An indicator is an element that should appear in the status area at the bottom -of a running Open MCT client instance. - -### Standard Indicators - -Indicators which wish to appear in the common form of an icon-text pair should -provide implementations with the following methods: - -* `getText()`: Provides the human-readable text that will be displayed for this -indicator. -* `getGlyph()`: Provides a single-character string that will be displayed as an -icon in Open MCT's custom font set. -* `getDescription()`: Provides a human-readable summary of the current state of -this indicator; will be displayed in a tooltip on hover. -* `getClass()`: Get a CSS class that will be applied to this indicator. -* `getTextClass()`: Get a CSS class that will be applied to this indicator's -text portion. -* `getGlyphClass()`: Get a CSS class that will be applied to this indicator's -icon portion. -* `configure()`: If present, a configuration icon will appear to the right of -this indicator, and clicking it will invoke this method. - -Note that all methods are optional, and are called directly from an Angular -template, so they should be appropriate to run during digest cycles. - -### Custom Indicators - -Indicators which wish to have an arbitrary appearance (instead of following the -icon-text convention commonly used) may specify a `template` property in their -extension definition. The value of this property will be used as the `key` for -an `mct-include` directive (so should refer to an extension of category - templates .) This template will be rendered to the status area. Indicators of -this variety do not need to provide an implementation. - -## Licenses Category - -The extension category `licenses` can be used to add entries into the 'Licensing -information' page, reachable from Open MCT's About dialog. - -Licenses may have the following properties, all of which are strings: - -* `name`: Human-readable name of the licensed component. (e.g. 'AngularJS'.) -* `version`: Human-readable version of the licensed component. (e.g. '1.2.26'.) -* `description`: Human-readable summary of the component. -* `author`: Name or names of entities to which authorship should be attributed. -* `copyright`: Copyright text to display for this component. -* `link`: URL to full license text. - -## Policies Category - -Policies are used to handle decisions made using Open MCT's `policyService`; -examples of these decisions are determining the applicability of certain -actions, or checking whether or not a domain object of one type can contain a -domain object of a different type. See the section on the Policies for an -overview of Open MCT's policy model. - -A policy's extension definition should include: - -* `category`: The machine-readable identifier for the type of policy decision -being supported here. For a list of categories supported by the platform, see -the section on Policies. Plugins may introduce and utilize additional policy -categories not in that list. -* `message`: Optional; a human-readable message describing the policy, intended -for display in situations where this specific policy has disallowed something. - -A policy's implementation should include a single method, `allow(candidate, -context)`. The specific types used for `candidate` and `context` vary by policy -category; in general, what is being asked is 'is this candidate allowed in this -context?' This method should return a boolean value. - -Open MCT's policy model requires consensus; a policy decision is allowed -when and only when all policies choose to allow it. As such, policies should -generally be written to reject a certain case, and allow (by returning `true`) -anything else. - -## Representations Category - -A representation is an Angular template used to display a domain object. The -`representations` extension category is used to add options for the -`mct-representation` directive. - -A representation definition should include the following properties: - -* `key`: The machine-readable name which identifies the representation. -* `templateUrl`: The path to the representation's Angular template. This path is -relative to the bundle's resources directory. -* `uses`: Optional; an array of capability names. Indicates that this -representation intends to use those capabilities of a domain object (via a -`useCapability` call), and expects to find the latest results of that -`useCapability` call in the scope of the presented template (under the same name -as the capability itself.) Note that, if `useCapability` returns a promise, this -will be resolved before being placed in the representation's scope. -* `gestures`: An array of keys identifying gestures (see the `gestures` -extension category) which should be available upon this representation. Examples -of gestures include `drag` (for representations that should act as draggable -sources for drag-drop operations) and `menu` (for representations which should -show a domain-object-specific context menu on right-click.) - -### Representation Scope - -While _representations_ do not have implementations, per se, they do refer to -Angular templates which need to interact with information (e.g. the domain -object being represented) provided by the platform. This information is passed -in through the template's scope, such that simple representations may be created -by providing only templates. (More complex representations will need controllers -which are referenced from templates. See https://docs.angularjs.org/guide/controller -for more information on controllers in Angular.) - -A representation's scope will contain: - -* `domainObject`: The represented domain object. -* `model`: The domain object's model. -* `configuration`: An object containing configuration information for this -representation (an empty object if there is no saved configuration.) The -contents of this object are managed entirely by the view/representation which -receives it. -* `representation`: An empty object, useful as a 'scratch pad' for -representation state. -* `ngModel`: An object passed through the ng-model attribute of the -`mct-representation` , if any. -* `parameters`: An object passed through the parameters attribute of the -`mct-representation`, if any. -* Any capabilities requested by the uses property of the representation -definition. - -## Representers Category - -The `representers` extension category is used to add additional behavior to the -`mct-representation` directive. This extension category is intended primarily -for use internal to the platform. - -Unlike _representations_, which describe specific ways to represent domain -objects, _representers_ are used to modify or augment the process of -representing domain objects in general. For example, support for the _gestures_ -extension category is added by a _representer_. - -A representer needs only provide an implementation. When an `mct-representation` -is linked (see https://docs.angularjs.org/guide/directive ) or when the -domain object being represented changes, a new _representer_ of each declared -type is instantiated. The constructor arguments for a _representer_ are the same -as the arguments to the link function in an Angular directive: `scope` the -Angular scope for this representation; `element` the jqLite-wrapped -`mct-representation` element, and `attrs` a set of key-value pairs of that -element's attributes. _Representers_ may wish to populate the scope, attach -event listeners to the element, etc. - -This implementation must provide a single method, `destroy()`, which will be -invoked when the representer is no longer needed. - -## Roots Category - -The extension category `roots` is used to provide root-level domain object -models. Root-level domain objects appear at the top-level of the tree hierarchy. -For example, the _My Items_ folder is added as an extension of this category. - -Extensions of this category should have the following properties: - -* `id`: The machine-readable identifier for the domain object being exposed. -* `model`: The model, as a JSON object, for the domain object being exposed. - -## Stylesheets Category - -The stylesheets extension category is used to add CSS files to style the -application. Extension definitions for this category should include one -property: - -* `stylesheetUrl`: Path and filename, including extension, for the stylesheet to -include. This path is relative to the bundle's resources folder (by default, -`res`) -* `theme`: Optional; if present, this stylesheet will only be included if this -value matches the `THEME` constant. - -To control the order of CSS files, use priority (see the section on Extension -Definitions above.) - -## Templates Category - -The `templates` extension category is used to expose Angular templates under -symbolic identifiers. These can then be utilized using the `mct-include` -directive, which behaves similarly to `ng-include` except that it uses these -symbolic identifiers instead of paths. - -A template's extension definition should include the following properties: - -* `key`: The machine-readable name which identifies this template, matched -against the value given to the key attribute of the `mct-include` directive. -* `templateUrl`: The path to the relevant Angular template. This path is -relative to the bundle's resources directory. - -Note that, when multiple templates are present with the same key , the one with -the highest priority will be used from `mct-include`. This behavior can be used -to override templates exposed by the platform (to change the logo which appears -in the bottom right, for instance.) - -Templates do not have implementations. - -## Types Category - -The types extension category describes types of domain objects which may -appear within Open MCT. - -A type's extension definition should have the following properties: - -* `key`: The machine-readable identifier for this domain object type. Will be -stored to and matched against the type property of domain object models. -* `name`: The human-readable name for this domain object type. -* `description`: A human-readable summary of this domain object type. -* `glyph`: A single character to be rendered as an icon in Open MCT's custom -font set. -* `model`: A domain object model, used as the initial state for created domain -objects of this type (before any properties are specified.) -* `features`: Optional; an array of strings describing features of this domain -object type. Currently, only creation is recognized by the platform; this is -used to determine that this type should appear in the Create menu. More -generally, this is used to support the `hasFeature(...)` method of the type -capability. -* `properties`: An array describing individual properties of this domain object -(as should appear in the _Create_ or the _Edit Properties_ dialog.) Each -property is described by an object containing the following properties: - * `control`: The key of the control (see `mct-control` and the `controls` - [extension category](#controls-category)) to use for editing this property. - * `property`: A string which will be used as the name of the property in the - domain object's model that the value for this property should be stored - under. If this value should be stored in an object nested within the domain - object model, then property should be specified as an array of strings - identifying these nested objects and, finally, the property itself. - * other properties as appropriate for a control of this type (each - property's definition will also be passed in as the structure for its - control.) See documentation of mct-form for more detail on these - properties. - -Types do not have implementations. - -## Versions Category -The versions extension category is used to introduce line items in Open MCT -Web's About dialog. These should have the following properties: - -* `name`: The name of this line item, as should appear in the left-hand side of -the list of version information in the About dialog. -* `value`: The value which should appear to the right of the name in the About -dialog. - -To control the ordering of line items within the About dialog, use `priority`. -(See section on [Extensions](#extensions) above.) - -This extension category does not have implementations. - -## Views Category - -The views extension category is used to determine which options appear to the -user as available views of domain objects of specific types. A view's extension -definition has the same properties as a representation (and views can be -utilized via `mct-representation`); additionally: - -* `name`: The human-readable name for this view type. -* description : A human-readable summary of this view type. -* `glyph`: A single character to be rendered as an icon in Open MCT's custom -font set. -* `type`: Optional; if present, this representation is only applicable for -domain object's of this type. -* `needs`: Optional array of strings; if present, this representation is only -applicable for domain objects which have the capabilities identified by these -strings. -* `delegation`: Optional boolean, intended to be used in conjunction with -`needs`; if present, allow required capabilities to be satisfied by means of -capability delegation. (See [Delegation](#delegation-capability)) -* `toolbar`: Optional; a definition for the toolbar which may appear in a -toolbar when using this view in Edit mode. This should be specified as a -structure for mct-toolbar , with additional properties available for each item in -that toolbar: - * `property`: A property name. This will refer to a property in the view's - current selection; that property on the selected object will be modifiable - as the `ng-model` of the displayed control in the toolbar. If the value of - the property is a function, it will be used as a getter-setter (called with - no arguments to use as a getter, called with a value to use as a setter.) - * `method`: A method to invoke (again, on the selected object) from the - toolbar control. Useful particularly for buttons (which don't edit a single - property, necessarily.) - -### View Scope - -Views do not have implementations, but do get the same properties in scope that -are provided for `representations`. - -When a view is in Edit mode, this scope will additionally contain: - -* `commit()`: A function which can be invoked to mark any changes to the view's - configuration as ready to persist. -* `selection`: An object representing the current selection state. - -#### Selection State - -A view's selection state is, conceptually, a set of JavaScript objects. The -presence of methods/properties on these objects determine which toolbar controls -are visible, and what state they manage and/or behavior they invoke. - -This set may contain up to two different objects: The _view proxy_, which is -used to make changes to the view as a whole, and the _selected object_, which is -used to represent some state within the view. (Future versions of Open MCT -may support multiple selected objects.) - -The `selection` object made available during Edit mode has the following -methods: - -* `proxy([object])`: Get (or set, if called with an argument) the current view -proxy. -* `select(object)`: Make this object the selected object. -* `deselect()`: Clear the currently selected object. -* `get()`: Get the currently selected object. Returns undefined if there is no -currently selected object. -* `selected(object)`: Check if the JavaScript object is currently in the -selection set. Returns true if the object is either the currently selected -object, or the current view proxy. -* `all()`: Get an array of all objects in the selection state. Will include -either or both of the view proxy and selected object. - -## Workers Category - -The `workers` extension category allows scripts to be run as web workers -using the `workerService`. - -An extension of this category has no implementation. The following properties -are supported: - -* `key`: A symbolic string used to identify this worker. -* `workerUrl`: The path, relative to this bundle's `src` folder, where - this worker's source code resides. -* `shared`: Optional; a boolean flag which, if true, indicates that this - worker should be instantiated as a - [`SharedWorker`](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker/SharedWorker). - Default value is `false`. - -# Directives - -Open MCT defines several Angular directives that are intended for use both -internally within the platform, and by plugins. - -## Container - -The `mct-container` is similar to the `mct-include` directive insofar as it allows -templates to be referenced by symbolic keys instead of by URL. Unlike -`mct-include` it supports transclusion. - -Unlike `mct-include` `mct-container` accepts a key as a plain string attribute, -instead of as an Angular expression. - -## Control - -The `mct-control` directive is used to display user input elements. Several -controls are included with the platform to wrap default input types. This -directive is primarily intended for internal use by the `mct-form` and -`mct-toolbar` directives. - -When using `mct-control` the attributes `ng-model` `ng-disabled` -`ng-required` and `ng-pattern` may also be used. These have the usual meaning -(as they would for an input element) except for `ng-model`; when used, it will -actually be `ngModel[field]` (see below) that is two-way bound by this control. -This allows `mct-control` elements to more easily delegate to other -`mct-control` instances, and also facilitates usage for generated forms. - -This directive supports the following additional attributes, all specified as -Angular expressions: - -* `key`: A machine-readable identifier for the specific type of control to -display. -* `options`: A set of options to display in this control. -* `structure`: In practice, contains the definition object which describes this -form row or toolbar item. Used to pass additional control-specific parameters. -* `field`: The field in the `ngModel` under which to read/store the property -associated with this control. - -## Drag - -The `mct-drag` directive is used to support drag-based gestures on HTML -elements. Note that this is not 'drag' in the 'drag-and-drop' sense, but 'drag' -in the more general 'mouse down, mouse move, mouse up' sense. - -This takes the form of three attributes: - -* `mct-drag`: An Angular expression to evaluate during drag movement. -* `mct-drag-down`: An Angular expression to evaluate when the drag starts. -* `mct-drag-up`: An Angular expression to evaluate when the drag ends. - -In each case, a variable `delta` will be provided to the expression; this is a -two-element array or the horizontal and vertical pixel offset of the current -mouse position relative to the mouse position where dragging began. - -## Form - -The `mct-form` directive is used to generate forms using a declarative structure, -and to gather back user input. It is applicable at the element level and -supports the following attributes: - -* `ng-model`: The object which should contain the full form input. Individual -fields in this model are bound to individual controls; the names used for these -fields are provided in the form structure (see below). -* `structure`: The structure of the form; e.g. sections, rows, their names, and -so forth. The value of this attribute should be an Angular expression. -* `name`: The name in the containing scope under which to publish form -"meta-state", e.g. `$valid` `$dirty` etc. This is as the behavior of `ng-form`. -Passed as plain text in the attribute. - -### Form Structure - -Forms in Open MCT have a common structure to permit consistent display. A -form is broken down into sections, which will be displayed in groups; each -section is broken down into rows, each of which provides a control for a single -property. Input from this form is two-way bound to the object passed via -`ng-model`. - -A form's structure is represented by a JavaScript object in the following form: - - { - "name": ... title to display for the form, as a string ..., - "sections": [ - { - "name": ... title to display for the section ..., - "rows": [ - { - "name": ... title to display for this row ..., - "control": ... symbolic key for the control ..., - "key": ... field name in ng-model ... - "pattern": ... optional, reg exp to match against ... - "required": ... optional boolean ... - "options": [ - "name": ... name to display (e.g. in a select) ..., - "value": ... value to store in the model ... - ] - }, - ... and other rows ... - ] - }, - ... and other sections ... - ] - } - -Note that `pattern` may be specified as a string, to simplify storing for -structures as JSON when necessary. The string should be given in a form -appropriate to pass to a `RegExp` constructor. - -### Form Controls - -A few standard control types are included in the platform/forms bundle: - -* `textfield`: An area to enter plain text. -* `select`: A drop-down list of options. -* `checkbox`: A box which may be checked/unchecked. -* `color`: A color picker. -* `button`: A button. -* `datetime`: An input for UTC date/time entry; gives result as a UNIX -timestamp, in milliseconds since start of 1970, UTC. - -## Include - -The `mct-include` directive is similar to ng-include , except that it takes a -symbolic identifier for a template instead of a URL. Additionally, templates -included via mct-include will have an isolated scope. - -The directive should be used at the element level and supports the following -attributes, all of which are specified as Angular expressions: - -* `key`: Machine-readable identifier for the template (of extension category -templates ) to be displayed. -* `ng-model`: _Optional_; will be passed into the template's scope as `ngModel`. -Intended usage is for two-way bound user input. -* `parameters`: _Optional_; will be passed into the template's scope as -parameters. Intended usage is for template-specific display parameters. - -## Representation - -The `mct-representation` directive is used to include templates which -specifically represent domain objects. Usage is similar to `mct-include`. - -The directive should be used at the element level and supports the following -attributes, all of which are specified as Angular expressions: - -* `key`: Machine-readable identifier for the representation (of extension -category _representations_ or _views_ ) to be displayed. -* `mct-object`: The domain object being represented. -* `ng-model`: Optional; will be passed into the template's scope as `ngModel`. -Intended usage is for two-way bound user input. -* `parameters`: Optional; will be passed into the template's scope as -parameters . Intended usage is for template-specific display parameters. - -## Resize - -The `mct-resize` directive is used to monitor the size of an HTML element. It is -specified as an attribute whose value is an Angular expression that will be -evaluated when the size of the HTML element changes. This expression will be -provided a single variable, `bounds` which is an object containing two -properties, `width` and `height` describing the size in pixels of the element. - -When using this directive, an attribute `mct-resize-interval` may optionally be -provided. Its value is an Angular expression describing the number of -milliseconds to wait before next checking the size of the HTML element; this -expression is evaluated when the directive is linked and reevaluated whenever -the size is checked. - -## Scroll - -The `mct-scroll-x` and `mct-scroll-y` directives are used to both monitor and -control the horizontal and vertical scroll bar state of an element, -respectively. They are intended to be used as attributes whose values are -assignable Angular expressions which two-way bind to the scroll bar state. - -## Toolbar - -The `mct-toolbar` directive is used to generate toolbars using a declarative -structure, and to gather back user input. It is applicable at the element level -and supports the following attributes: - -* `ng-model`: The object which should contain the full toolbar input. Individual -fields in this model are bound to individual controls; the names used for these -fields are provided in the form structure (see below). -* `structure`: The structure of the toolbar; e.g. sections, rows, their names, and -so forth. The value of this attribute should be an Angular expression. -* `name`: The name in the containing scope under which to publish form -"meta-state", e.g. `$valid`, `$dirty` etc. This is as the behavior of -`ng-form`. Passed as plain text in the attribute. - -Toolbars support the same control options as forms. - -### Toolbar Structure - -A toolbar's structure is defined similarly to forms, except instead of rows -there are items . - - { - "name": ... title to display for the form, as a string ..., - "sections": [ - { - "name": ... title to display for the section ..., - "items": [ - { - "name": ... title to display for this row ..., - "control": ... symbolic key for the control ..., - "key": ... field name in ng-model ... - "pattern": ... optional, reg exp to match against ... - "required": ... optional boolean ... - "options": [ - "name": ... name to display (e.g. in a select) ..., - "value": ... value to store in the model ... - ], - "disabled": ... true if control should be disabled ... - "size": ... size of the control (for textfields) ... - "click": ... function to invoke (for buttons) ... - "glyph": ... glyph to display (for buttons) ... - "text": ... text within control (for buttons) ... - }, - ... and other rows ... - ] - }, - ... and other sections ... - ] - } - -## Table - -The `mct-table` directive provides a generic table component, with optional -sorting and filtering capabilities. The table can be pre-populated with data -by setting the `rows` parameter, and it can be updated in real-time using the -`add:row` and `remove:row` broadcast events. The table will expand to occupy -100% of the size of its containing element. The table is highly optimized for -very large data sets. - -### Events - -The table supports two events for notifying that the rows have changed. For -performance reasons, the table does not monitor the content of `rows` -constantly. - -* `add:row`: A `$broadcast` event that will notify the table that a new row -has been added to the table. - -eg. The code below adds a new row, and alerts the table using the `add:row` -event. Sorting and filtering will be applied automatically by the table component. - -``` -$scope.rows.push(newRow); -$scope.$broadcast('add:row', $scope.rows.length-1); -``` - -* `remove:row`: A `$broadcast` event that will notify the table that a row -should be removed from the table. - -eg. The code below removes a row from the rows array, and then alerts the table -to its removal. - -``` -$scope.rows.slice(5, 1); -$scope.$broadcast('remove:row', 5); -``` - -### Parameters - -* `headers`: An array of string values which will constitute the column titles - that appear at the top of the table. Corresponding values are specified in - the rows using the header title provided here. -* `rows`: An array of objects containing row values. Each element in the -array must be an associative array, where the key corresponds to a column header. -* `enableFilter`: A boolean that if true, will enable searching and result -filtering. When enabled, each column will have a text input field that can be -used to filter the table rows in real time. -* `enableSort`: A boolean determining whether rows can be sorted. If true, -sorting will be enabled allowing sorting by clicking on column headers. Only -one column may be sorted at a time. -* `autoScroll`: A boolean value that if true, will cause the table to automatically -scroll to the bottom as new data arrives. Auto-scroll can be disengaged manually -by scrolling away from the bottom of the table, and can also be enabled manually -by scrolling to the bottom of the table rows. - -# Services - -The Open MCT platform provides a variety of services which can be retrieved -and utilized via dependency injection. These services fall into two categories: - -* _Composite Services_ are defined by a set of components extensions; plugins may -introduce additional components with matching interfaces to extend or augment -the functionality of the composed service. (See the Framework section on -Composite Services.) -* _Other services_ which are defined as standalone service objects; these can be -utilized by plugins but are not intended to be modified or augmented. - -## Composite Type Services - -This section describes the composite services exposed by Open MCT, -specifically focusing on their interface and contract. - -In many cases, the platform will include a provider for a service which consumes -a specific extension category; for instance, the `actionService` depends on -`actions[]` and will expose available actions based on the rules defined for -that extension category. - -In these cases, it will usually be simpler to add a new extension of a given -category (e.g. of category `actions`) even when the same behavior could be -introduced by a service component (e.g. an extension of category `components` -where `provides` is `actionService` and `type` is `provider`.) - -Occasionally, the extension category does not provide enough expressive power to -achieve a desired result. For instance, the Create menu is populated with -`create` actions, where one such action exists for each creatable type. Since -the framework does not provide a declarative means to introduce a new action per -type declaratively, the platform implements this explicitly in an `actionService` -component of type `provider`. Plugins may use a similar approach when the normal -extension mechanism is insufficient to achieve a desired result. - -### Action Service - -The [Action Service](../architecture/platform.md#action-service) -(`actionService`) -provides `Action` instances which are applicable in specific contexts. See Core -API for additional notes on the interface for actions. The `actionService` has -the following interface: - -* `getActions(context)`: Returns an array of Action objects which are applicable -in the specified action context. - -### Capability Service - -The [Capability Service](../architecture/platform.md#capability-service) -(`capabilityService`) -provides constructors for capabilities which will be exposed for a given domain -object. - -The capabilityService has the following interface: - -* `getCapabilities(model)`: Returns a an object containing key-value pairs, -representing capabilities which should be exposed by the domain object with this -model. Keys in this object are the capability keys (as used in a -`getCapability(...)` call) and values are either: - * Functions, in which case they will be used as constructors, which will - receive the domain object instance to which the capability applies as their - sole argument.The resulting object will be provided as the result of a - domain object's `getCapability(...)` call. Note that these instances are cached - by each object, but may be recreated when an object is mutated. - * Other objects, which will be used directly as the result of a domain - object's `getCapability(...)` call. - -### Dialog Service - -The `dialogService` provides a means for requesting user input via a modal -dialog. It has the following interface: - -* `getUserInput(formStructure, formState)`: Prompt the user to fill out a form. -The first argument describes the form's structure (as will be passed to - mct-form ) while the second argument contains the initial state of that form. -This returns a Promise for the state of the form after the user has filled it -in; this promise will be rejected if the user cancels input. -* `getUserChoice(dialogStructure)`: Prompt the user to make a single choice from -a set of options, which (in the platform implementation) will be expressed as -buttons in the displayed dialog. Returns a Promise for the user's choice, which -will be rejected if the user cancels input. - -### Dialog Structure - -The object passed as the `dialogStructure` to `getUserChoice` should have the -following properties: - -* `title`: The title to display at the top of the dialog. -* `hint`: Short message to display below the title. -* `template`: Identifying key (as will be passed to mct-include ) for the -template which will be used to populate the inner area of the dialog. -* `model`: Model to pass in the ng-model attribute of mct-include . -* `parameters`: Parameters to pass in the parameters attribute of mct-include . -* `options`: An array of options describing each button at the bottom. Each -option may have the following properties: - * `name`: Human-readable name to display in the button. - * `key`: Machine-readable key, to pass as the result of the resolved promise - when clicked. - * `description`: Description to show in tooltip on hover. - -### Domain Object Service - -The [Object Service](../architecture/platform.md#object-service) (`objectService`) -provides domain object instances. It has the following interface: - -* `getObjects(ids)`: For the provided array of domain object identifiers, -returns a Promise for an object containing key-value pairs, where keys are -domain object identifiers and values are corresponding DomainObject instances. -Note that the result may contain a superset or subset of the objects requested. - -### Gesture Service - -The `gestureService` is used to attach gestures (see extension category gestures) -to representations. It has the following interface: - -* `attachGestures(element, domainObject, keys)`: Attach gestures specified by -the provided gesture keys (an array of strings) to this jqLite-wrapped HTML -element , which represents the specified domainObject . Returns an object with a -single method `destroy()`, to be invoked when it is time to detach these -gestures. - -### Model Service - -The [Model Service](../architecture/platform.md#model-service) (`modelService`) -provides domain object models. It has the following interface: - -* `getModels(ids)`: For the provided array of domain object identifiers, returns -a Promise for an object containing key-value pairs, where keys are domain object -identifiers and values are corresponding domain object models. Note that the -result may contain a superset or subset of the models requested. - -### Persistence Service - -The [Persistence Service](../architecture/platform.md#persistence-service) (`persistenceService`) -provides the ability to load/store JavaScript objects -(presumably serializing/deserializing to JSON in the process.) This is used -primarily to store domain object models. It has the following interface: - -* `listSpaces()`: Returns a Promise for an array of strings identifying the -different persistence spaces this service supports. Spaces are intended to be -used to distinguish between different underlying persistence stores, to allow -these to live side by side. -* `listObjects()`: Returns a Promise for an array of strings identifying all -documents stored in this persistence service. -* `createObject(space, key, value)`: Create a new document in the specified -persistence space , identified by the specified key , the contents of which shall -match the specified value . Returns a promise that will be rejected if creation -fails. -* `readObject(space, key)`: Read an existing document in the specified -persistence space , identified by the specified key . Returns a promise for the -specified document; this promise will resolve to undefined if the document does -not exist. -* `updateObject(space, key, value)`: Update an existing document in the -specified persistence space , identified by the specified key , such that its -contents match the specified value . Returns a promise that will be rejected if -the update fails. -* `deleteObject(space, key)`: Delete an existing document from the specified -persistence space , identified by the specified key . Returns a promise which will -be rejected if deletion fails. - -### Policy Service - -The [Policy Service](../architecture/platform.md#policy-service) (`policyService`) -may be used to determine whether or not certain behaviors are -allowed within the application. It has the following interface: - -* `allow(category, candidate, context, [callback])`: Check if this decision -should be allowed. Returns a boolean. Its arguments are interpreted as: - * `category`: A string identifying which kind of decision is being made. See - the [section on Categories](#policy-categories) for categories supported by - the platform; plugins may define and utilize policies of additional - categories, as well. - * `candidate`: An object representing the thing which shall or shall not be - allowed. Usually, this will be an instance of an extension of the category - defined above. This does need to be the case; additional policies which are - not specific to any extension may also be defined and consulted using unique - category identifiers. In this case, the type of the object delivered for the - candidate may be unique to the policy type. - * `context`: An object representing the context in which the decision is - occurring. Its contents are specific to each policy category. - * `callback`: Optional; a function to call if the policy decision is rejected. - This function will be called with the message string (which may be - undefined) of whichever individual policy caused the operation to fail. - -### Telemetry Service - -The [Telemetry Service](../architecture/platform.md#telemetry-service) (`telemetryService`) -is used to acquire telemetry data. See the section on -Telemetry in Core API for more information on how both the arguments and -responses of this service are structured. - -When acquiring telemetry for display, it is recommended that the -`telemetryHandler` service be used instead of this service. The -`telemetryHandler` has additional support for subscribing to and requesting -telemetry data associated with domain objects or groups of domain objects. See -the [Other Services](#other-services) section for more information. - -The `telemetryService` has the following interface: - -* `requestTelemetry(requests)`: Issue a request for telemetry, matching the -specified telemetry requests . Returns a _ Promise _ for a telemetry response -object. -* `subscribe(callback, requests)`: Subscribe to real-time updates for telemetry, -matching the specified `requests`. The specified `callback` will be invoked with -telemetry response objects as they become available. This method returns a -function which can be invoked to terminate the subscription. - -### Type Service - -The [Type Service](../architecture/platform.md#type-service) (`typeService`) exposes -domain object types. It has the following interface: - -* `listTypes()`: Returns all domain object types supported in the application, -as an array of `Type` instances. -* `getType(key)`: Returns the `Type` instance identified by the provided key, or -undefined if no such type exists. - -### View Service - -The [View Service](../architecture/platform.md#view-service) (`viewService`) exposes -definitions for views of domain objects. It has the following interface: - -* `getViews(domainObject)`: Get an array of extension definitions of category -`views` which are valid and applicable to the specified `domainObject`. - -## Other Services - -### Drag and Drop - -The `dndService` provides information about the content of an active -drag-and-drop gesture within the application. It is intended to complement the -`DataTransfer` API of HTML5 drag-and-drop, by providing access to non-serialized -JavaScript objects being dragged, as well as by permitting inspection during -drag (which is normally prohibited by browsers for security reasons.) - -The `dndService` has the following methods: - -* `setData(key, value)`: Set drag data associated with a given type, specified -by the `key` argument. -* `getData(key)`: Get drag data associated with a given type, specified by the -`key` argument. -* `removeData(key)`: Clear drag data associated with a given type, specified by -the `key` argument. - -### Navigation - -The _Navigation_ service provides information about the current navigation state -of the application; that is, which object is the user currently viewing? This -service merely tracks this state and notifies listeners; it does not take -immediate action when navigation changes, although its listeners might. - -The `navigationService` has the following methods: - -* `getNavigation()`: Get the current navigation state. Returns a `DomainObject`. -* `setNavigation(domainObject)`: Set the current navigation state. Returns a -`DomainObject`. -* `addListener(callback)`: Listen for changes in navigation state. The provided -`callback` should be a `Function` which takes a single `DomainObject` as an -argument. -* `removeListener(callback)`: Stop listening for changes in navigation state. -The provided `callback` should be a `Function` which has previously been passed -to addListener . - -### Now - -The service now is a function which acts as a simple wrapper for `Date.now()`. -It is present mainly so that this functionality may be more easily mocked in -tests for scripts which use the current time. - -### Telemetry Formatter - -The _Telemetry Formatter_ is a utility for formatting domain and range values -read from a telemetry series. - -`telemetryFormatter` has the following methods: - -* `formatDomainValue(value)`: Format the provided domain value (which will be -assumed to be a timestamp) for display; returns a string. -* `formatRangeValue(value)`: Format the provided range value (a number) for -display; returns a string. - -### Telemetry Handler - -The _Telemetry Handler_ is a utility for retrieving telemetry data associated -with domain objects; it is particularly useful for dealing with cases where the -telemetry capability is delegated to contained objects (as occurs -in _Telemetry Panels_.) - -The `telemetryHandler` has the following methods: - -* `handle(domainObject, callback, [lossless])`: Subscribe to and issue future -requests for telemetry associated with the provided `domainObject`, invoking the -provided callback function when streaming data becomes available. Returns a -`TelemetryHandle` (see below.) - -#### Telemetry Handle - -A TelemetryHandle has the following methods: - -* `getTelemetryObjects()`: Get the domain objects (as a `DomainObject[]`) that -have a telemetry capability and are being handled here. Note that these are -looked up asynchronously, so this method may return an empty array if the -initial lookup is not yet completed. -* `promiseTelemetryObjects()`: As `getTelemetryObjects()`, but returns a Promise -that will be fulfilled when the lookup is complete. -* `unsubscribe()`: Unsubscribe to streaming telemetry updates associated with -this handle. -* `getDomainValue(domainObject)`: Get the most recent domain value received via -a streaming update for the specified `domainObject`. -* `getRangeValue(domainObject)`: Get the most recent range value received via a -streaming update for the specified `domainObject`. -* `getMetadata()`: Get metadata (as reported by the `getMetadata()` method of a -telemetry capability) associated with telemetry-providing domain objects. -Returns an array, which is in the same order as getTelemetryObjects() . -* `request(request, callback)`: Issue a new request for historical telemetry -data. The provided callback will be invoked when new data becomes available, -which may occur multiple times (e.g. if there are multiple domain objects.) It -will be invoked with the DomainObject for which a new series is available, and -the TelemetrySeries itself, in that order. -* `getSeries(domainObject)`: Get the latest `TelemetrySeries` (as resulted from -a previous `request(...)` call) available for this domain object. - -### Worker Service - -The `workerService` may be used to run web workers defined via the -`workers` extension category. It has the following method: - -* `run(key)`: Run the worker identified by the provided `key`. Returns - a `Worker` (or `SharedWorker`, if the specified worker is defined - as a shared worker); if the `key` is unknown, returns `undefined`. - -# Models -Domain object models in Open MCT are JavaScript objects describing the -persistent state of the domain objects they describe. Their contents include a -mix of commonly understood metadata attributes; attributes which are recognized -by and/or determine the applicability of specific extensions; and properties -specific to given types. - -## General Metadata - -Some properties of domain object models have a ubiquitous meaning through Open -MCT Web and can be utilized directly: - -* `name`: The human-readable name of the domain object. - -## Extension-specific Properties - -Other properties of domain object models have specific meaning imposed by other -extensions within the Open MCT platform. - -### Capability-specific Properties - -Some properties either trigger the presence/absence of certain capabilities, or -are managed by specific capabilities: - -* `composition`: An array of domain object identifiers that represents the -contents of this domain object (e.g. as will appear in the tree hierarchy.) -Understood by the composition capability; the presence or absence of this -property determines the presence or absence of that capability. -* `modified`: The timestamp (in milliseconds since the UNIX epoch) of the last -modification made to this domain object. Managed by the mutation capability. -* `persisted`: The timestamp (in milliseconds since the UNIX epoch) of the last -time when changes to this domain object were persisted. Managed by the - persistence capability. -* `relationships`: An object containing key-value pairs, where keys are symbolic -identifiers for relationship types, and values are arrays of domain object -identifiers. Used by the relationship capability; the presence or absence of -this property determines the presence or absence of that capability. -* `telemetry`: An object which serves as a template for telemetry requests -associated with this domain object (e.g. specifying `source` and `key`; see -Telemetry Requests under Core API.) Used by the telemetry capability; the -presence or absence of this property determines the presence or absence of that -capability. -* `type`: A string identifying the type of this domain object. Used by the `type` -capability. - -### View Configurations - -Persistent configurations for specific views of domain objects are stored in the -domain object model under the property configurations . This is an object -containing key-value pairs, where keys identify the view, and values are objects -containing view-specific (and view-managed) configuration properties. - -## Modifying Models -When interacting with a domain object's model, it is possible to make -modifications to it directly. __Don't!__ These changes may not be properly detected -by the platform, meaning that other representations of the domain object may not -be updated, changes may not be saved at the expected times, and generally, that -unexpected behavior may occur. Instead, use the `mutation` capability. - -# Capabilities - -Dynamic behavior associated with a domain object is expressed as capabilities. A -capability is a JavaScript object with an interface that is specific to the type -of capability in use. - -Often, there is a relationship between capabilities and services. For instance, -there is an action capability and an actionService , and there is a telemetry -capability as well as a `telemetryService`. Typically, the pattern here is that -the capability will utilize the service for the specific domain object. - -When interacting with domain objects, it is generally preferable to use a -capability instead of a service when the option is available. Capability -interfaces are typically easier to use and/or more powerful in these situations. -Additionally, this usage provides a more robust substitutability mechanism; for -instance, one could configure a plugin such that it provided a totally new -implementation of a given capability which might not invoke the underlying -service, while user code which interacts with capabilities remains indifferent -to this detail. - -## Action Capability - -The `action` capability is present for all domain objects. It allows applicable -`Action` instances to be retrieved and performed for specific domain objects. - -For example: - `domainObject.getCapability("action").perform("navigate"); ` - ...will initiate a navigate action upon the domain object, if an action with - key "navigate" is defined. - -This capability has the following interface: -* `getActions(context)`: Get the actions that are applicable in the specified -action `context`; the capability will fill in the `domainObject` field of this -context if necessary. If context is specified as a string, they will instead be -used as the `key` of the action context. Returns an array of `Action` instances. -* `perform(context)`: Perform an action. This will find and perform the first -matching action available for the specified action context , filling in the -`domainObject` field as necessary. If `context` is specified as a string, they -will instead be used as the `key` of the action context. Returns a `Promise` for -the result of the action that was performed, or `undefined` if no matching action -was found. - -## Composition Capability - -The `composition` capability provides access to domain objects that are -contained by this domain object. While the `composition` property of a domain -object's model describes these contents (by their identifiers), the -`composition` capability provides a means to load the corresponding -`DomainObject` instances in the same order. The absence of this property in the -model will result in the absence of this capability in the domain object. - -This capability has the following interface: - -* `invoke()`: Returns a `Promise` for an array of `DomainObject` instances. - -## Delegation Capability - -The delegation capability is used to communicate the intent of a domain object -to delegate responsibilities, which would normally handled by other -capabilities, to the domain objects in its composition. - -This capability has the following interface: - -* `getDelegates(key)`: Returns a Promise for an array of DomainObject instances, -to which this domain object wishes to delegate the capability with the specified -key . -* `invoke(key)`: Alias of getDelegates(key) . -* `doesDelegate(key)`: Returns true if the domain object does delegate the -capability with the specified key . - -The platform implementation of the delegation capability inspects the domain -object's type definition for a property delegates , whose value is an array of -strings describing which capabilities domain objects of that type wish to -delegate. If this property is not present, the delegation capability will not be -present in domain objects of that type. - -## Editor Capability - -The editor capability is meant primarily for internal use by Edit mode, and -helps to manage the behavior associated with exiting _Edit_ mode via _Save_ or -_Cancel_. Its interface is not intended for general use. However, -`domainObject.hasCapability(editor)` is a useful way of determining whether or -not we are looking at an object in _Edit_ mode. - -## Mutation Capability - -The `mutation` capability provides a means by which the contents of a domain -object's model can be modified. This capability is provided by the platform for -all domain objects, and has the following interface: - -* `mutate(mutator, [timestamp])`: Modify the domain object's model using the -specified `mutator` function. After changes are made, the `modified` property of -the model will be updated with the specified `timestamp` if one was provided, -or with the current system time. -* `invoke(...)`: Alias of `mutate`. - -Changes to domain object models should only be made via the `mutation` -capability; other platform behavior is likely to break (either by exhibiting -undesired behavior, or failing to exhibit desired behavior) if models are -modified by other means. - -### Mutator Function - -The mutator argument above is a function which will receive a cloned copy of the -domain object's model as a single argument. It may return: - -* A `Promise` in which case the resolved value of the promise will be used to -determine which of the following forms is used. -* Boolean `false` in which case the mutation is cancelled. -* A JavaScript object, in which case this object will be used as the new model -for this domain object. -* No value (or, equivalently, `undefined`), in which case the cloned copy -(including any changes made in place by the mutator function) will be used as -the new domain object model. - -## Persistence Capability - -The persistence capability provides a mean for interacting with the underlying -persistence service which stores this domain object's model. It has the -following interface: - -* `persist()`: Store the local version of this domain object, including any -changes, to the persistence store. Returns a Promise for a boolean value, which -will be true when the object was successfully persisted. -* `refresh()`: Replace this domain object's model with the most recent version -from persistence. Returns a Promise which will resolve when the change has -completed. -* `getSpace()`: Return the string which identifies the persistence space which -stores this domain object. - -## Relationship Capability - -The relationship capability provides a means for accessing other domain objects -with which this domain object has some typed relationship. It has the following -interface: - -* `listRelationships()`: List all types of relationships exposed by this object. -Returns an array of strings identifying the types of relationships. -* `getRelatedObjects(relationship)`: Get all domain objects to which this domain -object has the specified type of relationship, which is a string identifier -(as above.) Returns a `Promise` for an array of `DomainObject` instances. - -The platform implementation of the `relationship` capability is present for domain -objects which has a `relationships` property in their model, whose value is an -object containing key-value pairs, where keys are strings identifying -relationship types, and values are arrays of domain object identifiers. - -## Status Capability - -The `status` capability provides a way to flag domain objects as possessing -certain states, represented as simple strings. These states, in turn, are -reflected on `mct-representation` elements as classes (prefixed with -`s-status-`.) The `status` capability has the following interface: - -* `get()`: Returns an array of all status strings that currently apply - to this object. -* `set(status, state)`: Adds or removes a status flag to this domain object. - The `status` argument is the string to set; `state` is a boolean - indicating whether this status should be included (true) or removed (false). -* `listen(callback)`: Listen for changes in status. The provided `callback` - will be invoked with an array of all current status strings whenever status - changes. - -Plug-ins may add and/or recognize arbitrary status flags. Flags defined -and/or supported by the platform are: - - Status | CSS Class | Meaning ------------|--------------------|----------------------------------- -`editing` | `s-status-editing` | Domain object is being edited. -`pending` | `s-status-pending` | Domain object is partially loaded. - - -## Telemetry Capability - -The telemetry capability provides a means for accessing telemetry data -associated with a domain object. It has the following interface: - -* `requestData([request])`: Request telemetry data for this specific domain -object, using telemetry request parameters from the specified request if -provided. This capability will fill in telemetry request properties as-needed -for this domain object. Returns a `Promise` for a `TelemetrySeries`. -* `subscribe(callback, [request])`: Subscribe to telemetry data updates for -this specific domain object, using telemetry request parameters from the -specified request if provided. This capability will fill in telemetry request -properties as-needed for this domain object. The specified callback will be -invoked with TelemetrySeries instances as they arrive. Returns a function which -can be invoked to terminate the subscription, or undefined if no subscription -could be obtained. -* `getMetadata()`: Get metadata associated with this domain object's telemetry. - -The platform implementation of the `telemetry` capability is present for domain -objects which has a `telemetry` property in their model and/or type definition; -this object will serve as a template for telemetry requests made using this -object, and will also be returned by `getMetadata()` above. - -## Type Capability -The `type` capability exposes information about the domain object's type. It has -the same interface as `Type`; see Core API. - -## View Capability - -The `view` capability exposes views which are applicable to a given domain -object. It has the following interface: - -* `invoke()`: Returns an array of extension definitions for views which are -applicable for this domain object. - -# Actions - -Actions are reusable processes/behaviors performed by users within the system, -typically upon domain objects. - -## Action Categories - -The platform understands the following action categories (specifiable as the -`category` parameter of an action's extension definition.) - -* `contextual`: Appears in context menus. -* `view-control`: Appears in top-right area of view (as buttons) in Browse mode - -## Platform Actions -The platform defines certain actions which can be utilized by way of a domain -object's `action` capability. Unless otherwise specified, these act upon (and -modify) the object described by the `domainObject` property of the action's -context. - -* `cancel`: Cancel the current editing action (invoked from Edit mode.) -* `compose`: Place an object in another object's composition. The object to be -added should be provided as the `selectedObject` of the action context. -* `edit`: Start editing an object (enter Edit mode.) -* `fullscreen`: Enter full screen mode. -* `navigate`: Make this object the focus of navigation (e.g. highlight it within -the tree, display a view of it to the right.) -* `properties`: Show the 'Edit Properties' dialog. -* `remove`: Remove this domain object from its parent's composition. (The -parent, in this case, is whichever other domain object exposed this object by -way of its `composition` capability.) -* `save`: Save changes (invoked from Edit mode.) -* `window`: Open this object in a new window. - -# Policies - -Policies are consulted to determine when certain behavior in Open MCT is -allowed. Policy questions are assigned to certain categories, which broadly -describe the type of decision being made; within each category, policies have a -candidate (the thing which may or may not be allowed) and, optionally, a context -(describing, generally, the context in which the decision is occurring.) - -The types of objects passed for 'candidate' and 'context' vary by category; -these types are documented below. - -## Policy Categories - -The platform understands the following policy categories (specifiable as the -`category` parameter of an policy's extension definition.) - -* `action`: Determines whether or not a given action is allowable. The candidate -argument here is an Action; the context is its action context object. -* `composition`: Determines whether or not a given domain object(first argument, `parent`) can contain a candidate child object (second argument, `child`). -* `view`: Determines whether or not a view is applicable for a domain object. -The candidate argument is the view's extension definition; the context argument -is the `DomainObject` to be viewed. - -# Build-Test-Deploy -Open MCT is designed to support a broad variety of build and deployment -options. The sources can be deployed in the same directory structure used during -development. A few utilities are included to support development processes. - -## Command-line Build - -Open MCT is built using [`npm`](http://npmjs.com/) -and [`gulp`](http://gulpjs.com/). - -To install build dependencies (only needs to be run once): - -`npm install` - -To build: - -`npm run prepare` - -This will compile and minify JavaScript sources, as well as copy over assets. -The contents of the `dist` folder will contain a runnable Open MCT -instance (e.g. by starting an HTTP server in that directory), including: - -* A `main.js` file containing Open MCT source code. -* Various assets in the `example` and `platform` directories. -* An `index.html` that runs Open MCT in its default configuration. - -Additional `gulp` tasks are defined in [the gulpfile](gulpfile.js). - -Note that an internet connection is required to run this build, in order to -download build dependencies. - -## Test Suite - -Open MCT uses [Jasmine 1.3](http://jasmine.github.io/) and -[Karma](http://karma-runner.github.io) for automated testing. - -The test suite is configured to load any scripts ending with `Spec.js` found -in the `src` hierarchy. Full configuration details are found in -`karma.conf.js`. By convention, unit test scripts should be located -alongside the units that they test; for example, `src/foo/Bar.js` would be -tested by `src/foo/BarSpec.js`. (For legacy reasons, some existing tests may -be located in separate `test` folders near the units they test, but the -naming convention is otherwise the same.) - -Tests are written as AMD modules which depend (at minimum) upon the -unit under test. For example, `src/foo/BarSpec.js` could look like: - - /*global define,Promise,describe,it,expect,beforeEach*/ - - define( - ["./Bar"], - function (Bar) { - "use strict"; - - describe("Bar", function () { - it("does something", function () { - var bar = new Bar(); - expect(controller.baz()).toEqual("foo"); - }); - }); - } - ); - - -## Code Coverage - -In addition to running tests, the test runner will also capture code coverage -information using [Blanket.JS](http://blanketjs.org/) and display this at the -bottom of the screen. Currently, only statement coverage is displayed. - -## Deployment -Open MCT is built to be flexible in terms of the deployment strategies it -supports. In order to run in the browser, Open MCT needs: - -1. HTTP access to sources/resources for the framework, platform, and all active -bundles. -2. Access to any external services utilized by active bundles. (This means that -external services need to support HTTP or some other web-accessible interface, -like WebSockets.) - -Any HTTP server capable of serving flat files is sufficient for the first point. -The command-line build also packages Open MCT into a `.war` file for easier -deployment on containers such as Apache Tomcat. - -The second point may be less flexible, as it depends upon the specific services -to be utilized by Open MCT. Because of this, it is often the set of external -services (and the manner in which they are exposed) that determine how to deploy -Open MCT. - -One important constraint to consider in this context is the browser's same -origin policy. If external services are not on the same apparent host and port -as the client (from the perspective of the browser) then access may be -disallowed. There are two workarounds if this occurs: - -* Make the external service appear to be on the same host/port, either by -actually deploying it there, or by proxying requests to it. -* Enable CORS (cross-origin resource sharing) on the external service. This is -only possible if the external service can be configured to support CORS. Care -should be exercised if choosing this option to ensure that the chosen -configuration does not create a security vulnerability. - -Examples of deployment strategies (and the conditions under which they make the -most sense) include: - -* If the external services that Open MCT will utilize are all running on -[Apache Tomcat](https://tomcat.apache.org/), then it makes sense to run Open -MCT Web from the same Tomcat instance as a separate web application. The -`.war` artifact produced by the command line build facilitates this deployment -option. (See https://tomcat.apache.org/tomcat-8.0-doc/deployer-howto.html for -general information on deploying in Tomcat.) -* If a variety of external services will be running from a variety of -hosts/ports, then it may make sense to use a web server that supports proxying, -such as the [Apache HTTP Server](http://httpd.apache.org/). In this -configuration, the HTTP server would be configured to proxy (or reverse proxy) -requests at specific paths to the various external services, while providing -Open MCT as flat files from a different path. -* If a single server component is being developed to handle all server-side -needs of an Open MCT instance, it can make sense to serve Open MCT (as -flat files) from the same component using an embedded HTTP server such as -[Nancy](http://nancyfx.org/). -* If no external services are needed (or if the 'external services' will just -be generating flat files to read) it makes sense to utilize a lightweight flat -file HTTP server such as [Lighttpd](http://www.lighttpd.net/). In this -configuration, Open MCT sources/resources would be placed at one path, while -the files generated by the external service are placed at another path. -* If all external services support CORS, it may make sense to have an HTTP -server that is solely responsible for making Open MCT sources/resources -available, and to have Open MCT contact these external services directly. -Again, lightweight HTTP servers such as [Lighttpd](http://www.lighttpd.net/) -are useful in this circumstance. The downside of this option is that additional -configuration effort is required, both to enable CORS on the external services, -and to ensure that Open MCT can correctly locate these services. - -Another important consideration is authentication. By design, Open MCT does -not handle user authentication. Instead, this should typically be treated as a -deployment-time concern, where authentication is handled by the HTTP server -which provides Open MCT, or an external access management system. - -### Configuration -In most of the deployment options above, some level of configuration is likely -to be needed or desirable to make sure that bundles can reach the external -services they need to reach. Most commonly this means providing the path or URL -to an external service. - -Configurable parameters within Open MCT are specified via constants -(literally, as extensions of the `constants` category) and accessed via -dependency injection by the scripts which need them. Reasonable defaults for -these constants are provided in the bundle where they are used. Plugins are -encouraged to follow the same pattern. - -Constants may be specified in any bundle; if multiple constants are specified -with the same `key` the highest-priority one will be used. This allows default -values to be overridden by specifying constants with higher priority. - -This permits at least three configuration approaches: - -* Modify the constants defined in their original bundles when deploying. This is -generally undesirable due to the amount of manual work required and potential -for error, but is viable if there are a small number of constants to change. -* Add a separate configuration bundle which overrides the values of these -constants. This is particularly appropriate when multiple configurations (e.g. -development, test, production) need to be managed easily; these can be swapped -quickly by changing the set of active bundles in bundles.json. -* Deploy Open MCT and its external services in such a fashion that the -default paths to reach external services are all correct. - -### Configuration Constants - -The following constants have global significance: -* `PERSISTENCE_SPACE`: The space in which domain objects should be persisted - (or read from) when not otherwise specified. Typically this will not need - to be overridden by other bundles, but persistence adapters may wish to - consume this constant in order to provide persistence for that space. - -The following configuration constants are recognized by Open MCT bundles: -* Common UI elements - `platform/commonUI/general` - * `THEME`: A string identifying the current theme symbolically. Individual - stylesheets (the `stylesheets` extension category) may specify an optional - `theme` property which will be matched against this before inclusion. -* CouchDB adapter - `platform/persistence/couch` - * `COUCHDB_PATH`: URL or path to the CouchDB database to be used for domain - object persistence. Should not include a trailing slash. -* ElasticSearch adapter - `platform/persistence/elastic` - * `ELASTIC_ROOT`: URL or path to the ElasticSearch instance to be used for - domain object persistence. Should not include a trailing slash. - * `ELASTIC_PATH`: Path relative to the ElasticSearch instance where domain - object models should be persisted. Should take the form `/`. diff --git a/docs/src/index.md b/docs/src/index.md index a09c2f8232..3166ae6019 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -22,16 +22,5 @@ * The [Development Process](process/) document describes the Open MCT software development cycle. -## Legacy Documentation - -As we transition to a new API, the following documentation for the old API -(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. - - * The [Developer's Guide](guide/) goes into more detail about how to use the - platform and the functionality that it provides. - * The [Tutorials](https://github.com/nasa/openmct-tutorial) give examples of extending the platform to add functionality, and integrate with data sources. diff --git a/docs/src/process/index.md b/docs/src/process/index.md index fc8f7e6e91..ae781b0de8 100644 --- a/docs/src/process/index.md +++ b/docs/src/process/index.md @@ -7,9 +7,5 @@ documents: process points are repeated during development. * The [Version Guide](version.md) describes version numbering for Open MCT (both semantics and process.) -* Testing is described in two documents: - * The [Test Plan](testing/plan.md) summarizes the approaches used - to test Open MCT. - * The [Test Procedures](testing/procedures.md) document what - specific tests are performed to verify correctness, and how - they should be carried out. +* The [Test Plan](testing/plan.md) summarizes the approaches used + to test Open MCT. diff --git a/docs/src/process/testing/procedures.md b/docs/src/process/testing/procedures.md deleted file mode 100644 index 5ccf0def5b..0000000000 --- a/docs/src/process/testing/procedures.md +++ /dev/null @@ -1,169 +0,0 @@ -# Test Procedures - -## Introduction - -This document is intended to be used: - -* By testers, to verify that Open MCT behaves as specified. -* By the development team, to document new test cases and to provide - guidance on how to author these. - -## Writing Procedures - -### Template - -Procedures for individual tests should use the following template, -adapted from [https://swehb.nasa.gov/display/7150/SWE-114](). - -Property | Value ----------------|--------------------------------------------------------------- -Test ID | -Relevant reqs. | -Prerequisites | -Test input | -Instructions | -Expectation | -Eval. criteria | - -For multi-line descriptions, use an asterisk or similar indicator to refer -to a longer-form description below. - -#### Example Procedure - Edit a Layout - -Property | Value ----------------|--------------------------------------------------------------- -Test ID | MCT-TEST-000X - Edit a layout -Relevant reqs. | MCT-EDIT-000Y -Prerequisites | Create a layout, as in MCT-TEST-000Z -Test input | Domain object database XYZ -Instructions | See below * -Expectation | Change to editing context † -Eval. criteria | Visual inspection - -* Follow the following steps: - -1. Verify that the created layout is currently navigated-to, - as in MCT-TEST-00ZZ. -2. Click the Edit button, identified by a pencil icon and the text "Edit" - displayed on hover. - -† Right-hand viewing area should be surrounded by a dashed -blue border when a domain object is being edited. - -### Guidelines - -Test procedures should be written assuming minimal prior knowledge of the -application: Non-standard terms should only be used when they are documented -in [the glossary](#glossary), and shorthands used for user actions should -be accompanied by useful references to test procedures describing those -actions (when available) or descriptions in user documentation. - -Test cases should be narrow in scope; if a list of steps is excessively -long (or must be written vaguely to be kept short) it should be broken -down into multiple tests which reference one another. - -All requirements satisfied by Open MCT should be verifiable using -one or more test procedures. - -## Glossary - -This section will contain terms used in test procedures. This may link to -a common glossary, to avoid replication of content. - -## Procedures - -This section will contain specific test procedures. Presently, procedures -are placeholders describing general patterns for setting up and conducting -testing. - -### User Testing Setup - -These procedures describes a general pattern for setting up for user -testing. Specific deployments should customize this pattern with -relevant data and any additional steps necessary. - -Property | Value ----------------|--------------------------------------------------------------- -Test ID | MCT-TEST-SETUP0 - User Testing Setup -Relevant reqs. | TBD -Prerequisites | Build of relevant components -Test input | Exemplary database; exemplary telemetry data set -Instructions | See below -Expectation | Able to load application in a web browser (Google Chrome) -Eval. criteria | Visual inspection - -Instructions: - -1. Start telemetry server. -2. Start ElasticSearch. -3. Restore database snapshot to ElasticSearch. -4. Start telemetry playback. -5. Start HTTP server for client sources. - -### User Test Procedures - -Specific user test cases have not yet been authored. In their absence, -user testing is conducted by: - -* Reviewing the text of issues from the issue tracker to understand the - desired behavior, and exercising this behavior in the running application. - (For instance, by following steps to reproduce from the original issue.) - * Issues which appear to be resolved should be marked as such with comments - on the original issue (e.g. "verified during user testing MM/DD/YYYY".) - * Issues which appear not to have been resolved should be reopened with an - explanation of what unexpected behavior has been observed. - * In cases where an issue appears resolved as-worded but other related - undesirable behavior is observed during testing, a new issue should be - opened, and linked to from a comment in the original issues. -* General usage of new features and/or existing features which have undergone - recent changes. Defects or problems with usability should be documented - by filing issues in the issue tracker. -* Open-ended testing to discover defects, identify usability issues, and - generate feature requests. - -### Long-Duration Testing - -The purpose of long-duration testing is to identify performance issues -and/or other defects which are sensitive to the amount of time the -application is kept running. (Memory leaks, for instance.) - -Property | Value ----------------|--------------------------------------------------------------- -Test ID | MCT-TEST-LDT0 - Long-duration Testing -Relevant reqs. | TBD -Prerequisites | MCT-TEST-SETUP0 -Test input | (As for test setup.) -Instructions | See "Instructions" below * -Expectation | See "Expectations" below † -Eval. criteria | Visual inspection - -* Instructions: - -1. Start `top` or a similar tool to measure CPU usage and memory utilization. -2. Open several user-created displays (as many as would be realistically - opened during actual usage in a stressing case) in some combination of - separate tabs and windows (approximately as many tabs-per-window as - total windows.) -3. Ensure that playback data is set to run continuously for at least 24 hours - (e.g. on a loop.) -4. Record CPU usage and memory utilization. -5. In at least one tab, try some general user interface gestures and make - notes about the subjective experience of using the application. (Particularly, - the degree of responsiveness.) -6. Leave client displays open for 24 hours. -7. Record CPU usage and memory utilization again. -8. Make additional notes about the subjective experience of using the - application (again, particularly responsiveness.) -9. Check logs for any unexpected warnings or errors. - -† Expectations: - -* At the end of the test, CPU usage and memory usage should both be similar - to their levels at the start of the test. -* At the end of the test, subjective usage of the application should not - be observably different from the way it was at the start of the test. - (In particular, responsiveness should not decrease.) -* Logs should not contain any unexpected warnings or errors ("expected" - warnings or errors are those that have been documented and prioritized - as known issues, or those that are explained by transient conditions - external to the software, such as network outages.) diff --git a/example/export/ExportTelemetryAsCSVAction.js b/example/export/ExportTelemetryAsCSVAction.js deleted file mode 100644 index bc3a7e1202..0000000000 --- a/example/export/ExportTelemetryAsCSVAction.js +++ /dev/null @@ -1,89 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - 'use strict'; - - /** - * An example of using the `exportService`; queries for telemetry - * and provides the results as a CSV file. - * @param {platform/exporters.ExportService} exportService the - * service which will handle the CSV export - * @param {ActionContext} context the action's context - * @constructor - * @memberof example/export - * @implements {Action} - */ - function ExportTelemetryAsCSVAction(exportService, context) { - this.exportService = exportService; - this.context = context; - } - - ExportTelemetryAsCSVAction.prototype.perform = function () { - var context = this.context, - domainObject = context.domainObject, - telemetry = domainObject.getCapability("telemetry"), - metadata = telemetry.getMetadata(), - domains = metadata.domains, - ranges = metadata.ranges, - exportService = this.exportService; - - function getName(domainOrRange) { - return domainOrRange.name; - } - - telemetry.requestData({}).then(function (series) { - var headers = domains.map(getName).concat(ranges.map(getName)), - rows = [], - row, - i; - - function copyDomainsToRow(telemetryRow, index) { - domains.forEach(function (domain) { - telemetryRow[domain.name] = series.getDomainValue(index, domain.key); - }); - } - - function copyRangesToRow(telemetryRow, index) { - ranges.forEach(function (range) { - telemetryRow[range.name] = series.getRangeValue(index, range.key); - }); - } - - for (i = 0; i < series.getPointCount(); i += 1) { - row = {}; - copyDomainsToRow(row, i); - copyRangesToRow(row, i); - rows.push(row); - } - - exportService.exportCSV(rows, { headers: headers }); - }); - }; - - ExportTelemetryAsCSVAction.appliesTo = function (context) { - return context.domainObject - && context.domainObject.hasCapability("telemetry"); - }; - - return ExportTelemetryAsCSVAction; -}); diff --git a/example/export/bundle.js b/example/export/bundle.js deleted file mode 100644 index 0b23bc431c..0000000000 --- a/example/export/bundle.js +++ /dev/null @@ -1,46 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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([ - './ExportTelemetryAsCSVAction' -], function (ExportTelemetryAsCSVAction) { - "use strict"; - - return { - name: "example/export", - definition: { - "name": "Example of using CSV Export", - "extensions": { - "actions": [ - { - "key": "example.export", - "name": "Export Telemetry as CSV", - "implementation": ExportTelemetryAsCSVAction, - "category": "contextual", - "cssClass": "icon-download", - "depends": ["exportService"] - } - ] - } - } - }; -}); diff --git a/example/forms/bundle.js b/example/forms/bundle.js deleted file mode 100644 index 526ba7b622..0000000000 --- a/example/forms/bundle.js +++ /dev/null @@ -1,53 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/ExampleFormController" -], function ( - ExampleFormController -) { - "use strict"; - - return { - name: "example/forms", - definition: { - "name": "Declarative Forms example", - "sources": "src", - "extensions": { - "controllers": [ - { - "key": "ExampleFormController", - "implementation": ExampleFormController, - "depends": [ - "$scope" - ] - } - ], - "routes": [ - { - "templateUrl": "templates/exampleForm.html" - } - ] - } - } - }; -}); diff --git a/example/forms/res/templates/exampleForm.html b/example/forms/res/templates/exampleForm.html deleted file mode 100644 index 8518af74e8..0000000000 --- a/example/forms/res/templates/exampleForm.html +++ /dev/null @@ -1,42 +0,0 @@ - -
- - - - -
    -
  • Dirty: {{aForm.$dirty}}
  • -
  • Valid: {{aForm.$valid}}
  • -
- -
-        
-    
-
diff --git a/example/forms/src/ExampleFormController.js b/example/forms/src/ExampleFormController.js deleted file mode 100644 index 17d3059b2c..0000000000 --- a/example/forms/src/ExampleFormController.js +++ /dev/null @@ -1,205 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - "use strict"; - - function ExampleFormController($scope) { - $scope.state = { - - }; - - $scope.toolbar = { - name: "An example toolbar.", - sections: [ - { - description: "First section", - items: [ - { - name: "X", - description: "X coordinate", - control: "textfield", - pattern: "^\\d+$", - disabled: true, - size: 2, - key: "x" - }, - { - name: "Y", - description: "Y coordinate", - control: "textfield", - pattern: "^\\d+$", - size: 2, - key: "y" - }, - { - name: "W", - description: "Cell width", - control: "textfield", - pattern: "^\\d+$", - size: 2, - key: "w" - }, - { - name: "H", - description: "Cell height", - control: "textfield", - pattern: "^\\d+$", - size: 2, - key: "h" - } - - ] - }, - { - description: "Second section", - items: [ - { - control: "button", - csslass: "icon-save", - click: function () { - console.log("Save"); - } - }, - { - control: "button", - csslass: "icon-x", - description: "Button B", - click: function () { - console.log("Cancel"); - } - }, - { - control: "button", - csslass: "icon-trash", - description: "Button C", - disabled: true, - click: function () { - console.log("Delete"); - } - } - ] - }, - { - items: [ - { - control: "color", - key: "color" - } - ] - } - ] - }; - - $scope.form = { - name: "An example form.", - sections: [ - { - name: "First section", - rows: [ - { - name: "Check me", - control: "checkbox", - key: "checkMe" - }, - { - name: "Enter your name", - required: true, - control: "textfield", - key: "yourName" - }, - { - name: "Enter a number", - control: "textfield", - pattern: "^\\d+$", - key: "aNumber" - } - ] - }, - { - name: "Second section", - rows: [ - { - name: "Pick a date", - required: true, - description: "Enter date in form YYYY-DDD", - control: "datetime", - key: "aDate" - }, - { - name: "Choose something", - control: "select", - options: [ - { - name: "Hats", - value: "hats" - }, - { - name: "Bats", - value: "bats" - }, - { - name: "Cats", - value: "cats" - }, - { - name: "Mats", - value: "mats" - } - ], - key: "aChoice" - }, - { - name: "Choose something", - control: "select", - required: true, - options: [ - { - name: "Hats", - value: "hats" - }, - { - name: "Bats", - value: "bats" - }, - { - name: "Cats", - value: "cats" - }, - { - name: "Mats", - value: "mats" - } - ], - key: "aRequiredChoice" - } - ] - } - ] - }; - } - - return ExampleFormController; - } -); diff --git a/example/identity/bundle.js b/example/identity/bundle.js deleted file mode 100644 index 0faefd10dc..0000000000 --- a/example/identity/bundle.js +++ /dev/null @@ -1,48 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/ExampleIdentityService" -], function ( - ExampleIdentityService -) { - "use strict"; - - return { - name: "example/identity", - definition: { - "extensions": { - "components": [ - { - "implementation": ExampleIdentityService, - "provides": "identityService", - "type": "provider", - "depends": [ - "dialogService", - "$q" - ] - } - ] - } - } - }; -}); diff --git a/example/identity/src/ExampleIdentityService.js b/example/identity/src/ExampleIdentityService.js deleted file mode 100644 index 74887e7ccf..0000000000 --- a/example/identity/src/ExampleIdentityService.js +++ /dev/null @@ -1,94 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - "use strict"; - - var DEFAULT_IDENTITY = { - key: "user", - name: "Example User" - }, - DIALOG_STRUCTURE = { - name: "Identify Yourself", - sections: [{ - rows: [ - { - name: "User ID", - control: "textfield", - key: "key", - required: true - }, - { - name: "Human name", - control: "textfield", - key: "name", - required: true - } - ] - }] - }; - - /** - * Example implementation of an identity service. This prompts the - * user to enter a name and user ID; in a more realistic - * implementation, this would be read from a server, possibly - * prompting for a user name and password (or similar) as - * appropriate. - * - * @implements {IdentityService} - * @memberof platform/identity - */ - function ExampleIdentityProvider(dialogService, $q) { - this.dialogService = dialogService; - this.$q = $q; - - this.returnUser = this.returnUser.bind(this); - this.returnUndefined = this.returnUndefined.bind(this); - } - - ExampleIdentityProvider.prototype.getUser = function () { - if (this.user) { - return this.$q.when(this.user); - } else { - return this.dialogService.getUserInput(DIALOG_STRUCTURE, DEFAULT_IDENTITY) - .then(this.returnUser, this.returnUndefined); - } - }; - - /** - * @private - */ - ExampleIdentityProvider.prototype.returnUser = function (user) { - return this.user = user; - }; - - /** - * @private - */ - ExampleIdentityProvider.prototype.returnUndefined = function () { - return undefined; - }; - - return ExampleIdentityProvider; - } -); diff --git a/example/mobile/bundle.js b/example/mobile/bundle.js deleted file mode 100644 index 1a5a2f0695..0000000000 --- a/example/mobile/bundle.js +++ /dev/null @@ -1,41 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - "use strict"; - - return { - name: "example/mobile", - definition: { - "name": "Mobile", - "description": "Allows elements with pertinence to mobile usage and development", - "extensions": { - "stylesheets": [ - { - "stylesheetUrl": "css/mobile-example.css", - "priority": "mandatory" - } - ] - } - } - }; -}); diff --git a/example/mobile/res/sass/mobile-example.scss b/example/mobile/res/sass/mobile-example.scss deleted file mode 100644 index 66513ac25e..0000000000 --- a/example/mobile/res/sass/mobile-example.scss +++ /dev/null @@ -1,31 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 "../../../../platform/commonUI/general/res/sass/constants"; -@import "../../../../platform/commonUI/general/res/sass/mobile/constants"; -@import "../../../../platform/commonUI/general/res/sass/mobile/mixins"; - -@include phoneandtablet { - // Show the Create button - .create-button-holder { - display: block !important; - } -} diff --git a/example/msl/README.md b/example/msl/README.md deleted file mode 100644 index 0df2e1666b..0000000000 --- a/example/msl/README.md +++ /dev/null @@ -1,20 +0,0 @@ -To use this bundle, add the following paths to /main.js - -'./platform/features/conductor/bundle', -'./example/msl/bundle', - -An example plugin that integrates with public data from the Curiosity rover. -The data shown used by this plugin is published by the Centro de -Astrobiología (CSIC-INTA) at http://cab.inta-csic.es/rems/ - -Fetching data from this source requires a cross-origin request which will -fail on most modern browsers due to restrictions on such requests. As such, -it is proxied through a local proxy defined in app.js. In order to use this -example you will need to run app.js locally. - -This example shows integration with an historical telemetry source, as -opposed to a real-time data source that is streaming back current information -about the state of a system. This example is atypical of a historical data -source in that it fetches all data in one request. The server infrastructure -of an historical telemetry source should ideally allow queries bounded by -time and other data attributes. - diff --git a/example/msl/bundle.js b/example/msl/bundle.js deleted file mode 100644 index 2919f7e57f..0000000000 --- a/example/msl/bundle.js +++ /dev/null @@ -1,115 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/RemsTelemetryServerAdapter", - "./src/RemsTelemetryModelProvider", - "./src/RemsTelemetryProvider" -], function ( - RemsTelemetryServerAdapter, - RemsTelemetryModelProvider, - RemsTelemetryProvider -) { - "use strict"; - - return { - name: "example/msl", - definition: { - "name": "Mars Science Laboratory Data Adapter", - "extensions": { - "types": [ - { - "name": "Mars Science Laboratory", - "key": "msl.curiosity", - "cssClass": "icon-object" - }, - { - "name": "Instrument", - "key": "msl.instrument", - "cssClass": "icon-object", - "model": {"composition": []} - }, - { - "name": "Measurement", - "key": "msl.measurement", - "cssClass": "icon-telemetry", - "model": {"telemetry": {}}, - "telemetry": { - "source": "rems.source", - "domains": [ - { - "name": "Time", - "key": "utc", - "format": "utc" - } - ] - } - } - ], - "constants": [ - { - "key": "REMS_WS_URL", - "value": "/proxyUrl?url=http://cab.inta-csic.es/rems/wp-content/plugins/marsweather-widget/api.php" - } - ], - "roots": [ - { - "id": "msl:curiosity" - } - ], - "models": [ - { - "id": "msl:curiosity", - "priority": "preferred", - "model": { - "type": "msl.curiosity", - "name": "Mars Science Laboratory", - "composition": ["msl_tlm:rems"] - } - } - ], - "services": [ - { - "key": "rems.adapter", - "implementation": RemsTelemetryServerAdapter, - "depends": ["$http", "$log", "REMS_WS_URL"] - } - ], - "components": [ - { - "provides": "modelService", - "type": "provider", - "implementation": RemsTelemetryModelProvider, - "depends": ["rems.adapter"] - }, - { - "provides": "telemetryService", - "type": "provider", - "implementation": RemsTelemetryProvider, - "depends": ["rems.adapter", "$q"] - } - ] - } - } - }; -}); - diff --git a/example/msl/data/rems.json b/example/msl/data/rems.json deleted file mode 100644 index 085e01a022..0000000000 --- a/example/msl/data/rems.json +++ /dev/null @@ -1 +0,0 @@ -{"descriptions":{"disclaimer_en":"\t \n\t\t\tThe information contained into this file is provided by Centro de Astrobiologia\n\t\t\t(CAB) and is intended for outreach purposes only. Any other use is discouraged.\n\t\t\tCAB will take no responsibility for any result or publication made base on the \n\t\t\tcontent of this file. To access REMS scientific data, visit PDS at http:\/\/pds.nasa.gov.\n\n\t\t\tThe environmental magnitudes given into this file are obtained from the values\n\t\t\tread by the Rover Environmental Monitoring Station (REMS) on board the Mars Science\n\t\t\tLaboratory (MSL) rover on Mars. This file provides the environmental magnitudes at REMS\n\t\t\tlocation, so MSL rover influences those magnitudes (rover position,\n\t\t\trover temperature, rover orientation, rover shade, dust depositions on the rover, etc.)\n\n\t\t\tREMS does not take measurements continuously and it takes measurements at different\n\t\t\ttimes from one day to another. This fact has influence on the variation of the values\n\t\t\tgiven in this file from one day to another .\n\n\t\t\tFor different reasons (instrument maintenance, instrument calibration, instrument degradation, etc.), \n\t\t\tsome or all of the magnitudes in this file may not be available.\n\t\t","disclaimer_es":"\t\t\n\t\t\tLa informaci\u00f3n contenida en este fichero es facilitada por el Centro de Astrobiolog\u00eda\n\t\t\t(CAB) \u00fanicamente para fines divulgativos. Cualquier otro uso queda desaconsejado.\n\t\t\tCAB no se har\u00e1 responsable de ning\u00fan resultado o publicaci\u00f3n basados en el contenido \n\t\t\tde este fichero. Para acceder a los datos cient\u00edficos de REMS, visite el PDS en\n\t\t\thttp:\/\/pds.nasa.gov.\n\n\t\t\tLas magnitudes ambientales dadas es este fichero se obtienen de los valores le\u00eddos\n\t\t\tpor la Estaci\u00f3n de Monitoreo Ambiental del Rover (REMS, por sus siglas en ingl\u00e9s)\n\t\t\tabordo del Laboratorio Cient\u00edfico de Marte (MSL, por sus siglas en ingl\u00e9s). Este\n\t\t\tfichero da las magnitudes ambientales medidas por REMS, por lo que estas magnitudes \n\t\t\test\u00e1n influenciadas por el rover MSL (posici\u00f3n del rover, temperatura del\n\t\t\trover, orientaci\u00f3n del rover, sombras arrojadas por el rover, deposici\u00f3n de polvo sobre\n\t\t\tel rover, etc.)\n\n\t\t\tREMS no est\u00e1 tomando medidas continuamente y, adem\u00e1s, toma medidas a diferentes horas \n\t\t\tde un d\u00eda para otro. Estos hechos tienen influencia en la variaci\u00f3n de los valores\n\t\t\tdados en este fichero para d\u00edas sucesivos.\n\n\t\t\tPor diferentes razones (mantenimiento del instrumento, calibraci\u00f3n del instrumento, degradaci\u00f3n\n\t\t\tdel instrumento, etc.) puede que alguna o todas las magnitudes de este fichero no est\u00e9n disponibles.\n\t\t","sol_desc_en":"\n\t\t\tThe term sol is used to refer to the duration of a day on Mars. A sol is about 24 hours and 40 minutes. For Curiosity,\n\t\t\tsol 0 corresponds with its landing day on Mars.\n\t\t","sol_desc_es":"\n\t\t\tEl t\u00e9rmino sol hace referencia a la duraci\u00f3n de un d\u00eda en Marte. Un sol dura aproximadamente 24 horas y 40 minutos.\n\t\t\tPara Curiosity, el sol 0 corresponde al d\u00eda de su aterrizaje en Marte.\n\t\t","terrestrial_date_desc_en":"\n\t\t\tOne day on Earth is about 24 hours, while a sol (Martian day) is about 24 hours and 40 minutes.\n\t\t\tSo one single sol starts during one Earth day and finishes during the next Earth day. This \n\t\t\tis the Earth day on current sol at midday.\n\t\t","terrestrial_date_desc_es":"\n\t\t\tUn d\u00eda en la Tierra dura aproximadamente 24 horas, mientras que un sol (d\u00eda marciano) dura aproximadamente\n\t\t\t24 horas y 40 minutos. As\u00ed que un sol empieza durante un d\u00eda terrestre, pero termina durante el siguiente.\n\t\t\tEl d\u00eda terrestre dado es el que se corresponde con el mediod\u00eda del sol actual.\n\t\t","temp_desc_en":"\n\t\t\t\tMars is farther from the Sun than Earth, it makes that Mars is colder than our planet.\n\t\t\t\tMoreover, Martian\u2019s atmosphere, which is extremely tenuous, does not retain the heat; \n\t\t\t\thence the difference between day and night's temperatures is more pronounced than in our planet.\n\t\t\t","temp_desc_es":"\n\t\t\t\tMarte est\u00e1 m\u00e1s lejos del Sol que la Tierra, por lo que Marte es m\u00e1s frio que nuestro planeta.\n\t\t\t\tAdem\u00e1s, lo atm\u00f3sfera marciana, que es muy tenue, no retiene bien el calor, \n\t\t\t\tpor lo que las diferencias de temperatura entre el d\u00eda y la noche son m\u00e1s pronunciadas que\n\t\t\t\ten nuestro planeta.\n\t\t\t","pressure_desc_en":"\n\t\t\t\tPressure is a measure of the total mass in a column of air above us. Because\n\t\t\t\tMartian\u2019s atmosphere is extremely tenuous, pressure on Mars' surface is about\n\t\t\t\t160 times smaller than pressure on Earth. Average pressure on Martian surface \n\t\t\t\tis about 700 Pascals (100000 Pascals on Earth) Curiosity is into Gale crater,\n\t\t\t\twhich is about 5 kilometers (3 miles) depth. For this reason, pressure measured\n\t\t\t\tby REMS is usually higher than average pressure on the entire planet.\n\t\t\t","pressure_desc_es":"\n\t\t\t\tLa presi\u00f3n mide la masa total en una columna de aire sobre nosotros. Debido a que\n\t\t\t\tla atm\u00f3sfera marciana es muy tenue, la presi\u00f3n en la superficie de Marte es unas\n\t\t\t\t160 veces m\u00e1s baja que en la Tierra. La presi\u00f3n media en la superficie de Marte \n\t\t\t\tes de unos 700 Pascales (en la Tierra es de 100000) El rover Curiosity est\u00e1 en el \n\t\t\t\tinterior de un cr\u00e1ter, de unos 5 kil\u00f3metros (3 millas) de profundidad. Por esta\n\t\t\t\traz\u00f3n, la presi\u00f3n medida por REMS normalmente ser\u00e1 mayor que la media en el planeta.\n\t\t\t","abs_humidity_desc_en":"\n\t\t\t\tMartian's atmosphere contains water vapor, and humidity measures the amount \n\t\t\t\tof water vapor present in the air. REMS records the relative humidity, \n\t\t\t\twhich is a measure of the amount of water vapor in the air compared \n\t\t\t\twith the amount of water vapor the air can hold at the temperature it happens\n\t\t\t\tto be when you measure it. Water on Mars is also present as water ice, \n\t\t\t\tfor instance, at Mars poles. Until today, however, proof of liquid water \n\t\t\t\tin present-day Mars remains elusive.\n\t\t\t","abs_humidity_desc_es":"\n\t\t\t\tLa atm\u00f3sfera marciana contiene vapor de agua y la humedad mide \n\t\t\t\tla cantidad de vapor de agua presente en el aire. REMS registra la humedad\n\t\t\t\trelativa, que es una medida de la cantidad de vapor de agua que \n\t\t\t\thay en el aire en comparaci\u00f3n con la m\u00e1xima cantidad de vapor de agua\n\t\t\t\tque puede contener a la misma temperatura. El agua en Marte est\u00e1 presente \n\t\t\t\ttambi\u00e9n en forma de hielo, por ejemplo en los polos. Hasta la fecha, sin embargo, \n\t\t\t\tno se han encontrado pruebas de la existencia de agua l\u00edquida en el presente marciano.\n\t\t\t","wind_desc_en":"\n\t\t\t\tNASA Viking landers and NASA Pathfinder rover showed that the average wind speed\n\t\t\t\ton their location was pretty weak: 1 to 4 meters\/second (4 to 15 kilometers\/hour - \n\t\t\t\t2.5 to 9 miles\/hour). However, during a dust storm, winds can reach 30 meters\/second \n\t\t\t\t(110 kilometers\/hour - 68 miles\/hour) or more.\n\t\t\t","wind_desc_es":"\n\t\t\t\tLas Vikings landers y el rover Pathfinder de la NASA mostraron que la velocidad media\n\t\t\t\tdel viento en su localizaci\u00f3n era bastante baja: de 1 a 4 metros\/segundo (de 4 a \n\t\t\t\t15 kil\u00f3metros por hora - de 2.5 a 9 millas\/hora) Sin embargo, durante una tormenta\n\t\t\t\tde polvo, la velocidad del viento en Marte puede alcanzar los 30 metros\/segundo\n\t\t\t\t(110 kil\u00f3metros por hora - 68 millas\/hora) o m\u00e1s.\n\t\t\t","gts_temp_desc_en":"\n\t\t\t\tMartian's atmosphere is extremely tenuous, about 160 times thinner than Earth's,\n\t\t\t\tso heat from the Sun can easily escape. It makes that there are big differences\n\t\t\t\tbetween ground temperature and air temperature. Imagine you were on the Martian equator \n\t\t\t\tat noon, you would feel like summer at your feet, but winter in your head.\n\t\t\t","gts_temp_desc_es":"\n\t\t\t\tLa atm\u00f3sfera marciana es muy tenue, unas 160 veces m\u00e1s delgada que la de la Tierra,\n\t\t\t\tlo que hace que el calor proveniente del Sol pueda escapar con facilidad. Esto hace\n\t\t\t\tque haya grandes diferencias entre la temperatura del suelo y la del aire. Imagina\n\t\t\t\tpor un momento que est\u00e1s en el ecuador marciano al mediod\u00eda, sentir\u00edas\n\t\t\t\ten tus pies una temperatura veraniega, sin embargo ser\u00eda invierno para tu cabeza.\n\t\t\t","local_uv_irradiance_index_desc_en":"\n\t\t\t\tLocal ultraviolet (UV) irradiance index is an indicator of the intensity of the ultraviolet\n\t\t\t\tradiation from the Sun at Curiosity location. UV radiation is a damaging agent for life. \n\t\t\t\tOn Earth, ozone layer prevents damaging ultraviolet light from reaching the surface, to \n\t\t\t\tthe benefit of both plants and animals. However, on Mars, due to the absence of ozone in the \n\t\t\t\tatmosphere, ultraviolet radiation reaches the Martian surface.\n\t\t\t","local_uv_irradiance_index_desc_es":"\n\t\t\t\tEl \u00edndice de irradiaci\u00f3n ultravioleta local es un indicador de la intensidad de la radiaci\u00f3n\n\t\t\t\tultravioleta (UV) proveniente del Sol en la ubicaci\u00f3n del rover Curiosity. La radiaci\u00f3n UV es \n\t\t\t\tun agente da\u00f1ino para la vida. En la Tierra, la capa de ozono nos protege de ella. Sin embargo\n\t\t\t\ten Marte, debido a la ausencia de ozono en la atm\u00f3sfera, la radiaci\u00f3n ultravioleta alcanza\n\t\t\t\tla superficie.\n\t\t\t","atmo_opacity_desc_en":"\n\t\t\t\tWeather on Mars is more extreme than Earth's. Mars is cooler and with\n\t\t\t\tbigger differences between day and night temperatures. Moreover, \n\t\t\t\tdust storms lash its surface. However, Mars' and Earth's climates have\n\t\t\t\timportant similarities, such as the polar ice caps or seasonal changes.\n\t\t\t\tAs on Earth, on Mars we can have sunny, cloudy or windy days, for example.\n\t\t\t","atmo_opacity_desc_es":"\n\t\t\t\tEl clima en Marte es m\u00e1s extremo que en la Tierra. Marte es m\u00e1s frio y\n\t\t\t\tcon mayores diferencias entre las temperaturas del d\u00eda y de la noche.\n\t\t\t\tAdem\u00e1s, fuertes tormentas de polvo azotan su superficie. Sin embargo,\n\t\t\t\texisten importantes similitudes entre el clima marciano y el terrestre,\n\t\t\t\tcomo la existencia de casquetes polares o los cambios de estaciones.\n\t\t\t\tComo ocurre en la Tierra, en Marte podemos tener d\u00edas soleados, nublados\n\t\t\t\to ventosos, por ejemplo.\n\t\t\t","ls_desc_en":"\n\t\t\t\tA Martian year lasts about two Earth's year, which is the time\n\t\t\t\tMars takes to orbit the Sun. Solar longitude is an angle that\n\t\t\t\tgives the position of Mars on its orbit.\t\t\t\t \n\t\t\t","ls_desc_es":"\n\t\t\t\tUn a\u00f1o marciano dura aproximadamente dos a\u00f1os terrestres, el tiempo\n\t\t\t\tque Marte necesita para dar una vuelta completa alrededor del Sol.\n\t\t\t\tLa longitud solar es un \u00e1ngulo que nos da la posici\u00f3n de Marte en su \n\t\t\t\t\u00f3rbita.\n\t\t\t","season_desc_en":"\n\t\t\t\tA Martian year is divided in 12 months, as Earth's. However, Martian months are\n\t\t\t\tfrom 46 to 67 sols (Martian days) long. The longest one is the month 3 (67 sols),\n\t\t\t\tand the shortest one is the month 9 (46 sols) Martian months mark seasonal changes. \n\t\t\t\tIn the southern hemisphere (Curiosity rover location) the autumn starts in month 1; \n\t\t\t\tthe winter in month 4; the spring in month 7; and the summer in month 10.\n\t\t\t","season_desc_es":"\n\t\t\t\tEl a\u00f1o marciano se divide en 12 meses, como en la Tierra. Sin embargo, los meses\n\t\t\t\ten Marte duran entre 46 y 67 soles (d\u00edas marcianos). El m\u00e1s largo es el mes 3\n\t\t\t\t(67 soles) y el m\u00e1s corto es el mes 9 (46 soles). Los meses marcan los\n\t\t\t\tcambios de estaci\u00f3n. En el hemisferio sur (localizaci\u00f3n del rover Curiosity) el\n\t\t\t\toto\u00f1o comienza en el mes 1; el invierno, en el mes 4; la primavera, en el mes 7; y\n\t\t\t\tel verano, en el mes 10. \n\t\t\t\t\t\t\t\n\t\t\t","sunrise_sunset_desc_en":"\n\t\t\t\tThe duration of a Martian day (sol) is about 24 hours and 40 minutes. The duration\n\t\t\t\tof daylight varies along the Martian year, as on Earth.\n\t\t\t","sunrise_sunset_desc_es":"\n\t\t\t\tUn d\u00eda marciano (sol) dura aproximadamente 24 horas y 40 minutos. La duraci\u00f3n\n\t\t\t\tdel d\u00eda y de la noche var\u00eda a lo largo del a\u00f1o, como ocurre en la Tierra.\n\t\t\t"},"soles":[{"id":"1159","terrestrial_date":"2016-01-19","sol":"1228","ls":"97","season":"Month 4","min_temp":"-88","max_temp":"-28","pressure":"832","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"1"},{"id":"1158","terrestrial_date":"2016-01-18","sol":"1227","ls":"96","season":"Month 4","min_temp":"-88","max_temp":"-26","pressure":"833","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-97","max_gts_temp":"2"},{"id":"1157","terrestrial_date":"2016-01-17","sol":"1226","ls":"96","season":"Month 4","min_temp":"-87","max_temp":"-24","pressure":"835","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-97","max_gts_temp":"1"},{"id":"1156","terrestrial_date":"2016-01-16","sol":"1225","ls":"95","season":"Month 4","min_temp":"-87","max_temp":"-28","pressure":"836","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-98","max_gts_temp":"-1"},{"id":"1154","terrestrial_date":"2016-01-15","sol":"1224","ls":"95","season":"Month 4","min_temp":"-88","max_temp":"-29","pressure":"837","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-98","max_gts_temp":"1"},{"id":"1155","terrestrial_date":"2016-01-14","sol":"1223","ls":"94","season":"Month 4","min_temp":"-88","max_temp":"-26","pressure":"839","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-98","max_gts_temp":"0"},{"id":"1153","terrestrial_date":"2016-01-13","sol":"1222","ls":"94","season":"Month 4","min_temp":"-87","max_temp":"-28","pressure":"840","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-94","max_gts_temp":"0"},{"id":"1152","terrestrial_date":"2016-01-12","sol":"1221","ls":"93","season":"Month 4","min_temp":"-87","max_temp":"-28","pressure":"841","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-94","max_gts_temp":"-1"},{"id":"1151","terrestrial_date":"2016-01-11","sol":"1220","ls":"93","season":"Month 4","min_temp":"-87","max_temp":"-28","pressure":"842","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-94","max_gts_temp":"-3"},{"id":"1150","terrestrial_date":"2016-01-10","sol":"1219","ls":"93","season":"Month 4","min_temp":"-87","max_temp":"-27","pressure":"844","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-92","max_gts_temp":"-4"},{"id":"1149","terrestrial_date":"2016-01-09","sol":"1218","ls":"92","season":"Month 4","min_temp":"-86","max_temp":"-32","pressure":"845","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-96","max_gts_temp":"-6"},{"id":"1148","terrestrial_date":"2016-01-08","sol":"1217","ls":"92","season":"Month 4","min_temp":"-88","max_temp":"-27","pressure":"846","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-3"},{"id":"1147","terrestrial_date":"2016-01-07","sol":"1216","ls":"91","season":"Month 4","min_temp":"-86","max_temp":"-28","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-6"},{"id":"1146","terrestrial_date":"2016-01-06","sol":"1215","ls":"91","season":"Month 4","min_temp":"-85","max_temp":"-27","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:35","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"-3"},{"id":"1144","terrestrial_date":"2016-01-05","sol":"1214","ls":"90","season":"Month 4","min_temp":"-85","max_temp":"-24","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-12"},{"id":"1145","terrestrial_date":"2016-01-04","sol":"1213","ls":"90","season":"Month 4","min_temp":"-84","max_temp":"-27","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-12"},{"id":"1143","terrestrial_date":"2016-01-03","sol":"1212","ls":"89","season":"Month 3","min_temp":"-86","max_temp":"-28","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-13"},{"id":"1142","terrestrial_date":"2016-01-02","sol":"1211","ls":"89","season":"Month 3","min_temp":"-83","max_temp":"-22","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-12"},{"id":"1140","terrestrial_date":"2016-01-01","sol":"1210","ls":"88","season":"Month 3","min_temp":"-85","max_temp":"-23","pressure":"854","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"-12"},{"id":"1141","terrestrial_date":"2015-12-31","sol":"1209","ls":"88","season":"Month 3","min_temp":"-85","max_temp":"-24","pressure":"855","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-12"},{"id":"1139","terrestrial_date":"2015-12-30","sol":"1208","ls":"88","season":"Month 3","min_temp":"-85","max_temp":"-24","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-12"},{"id":"1138","terrestrial_date":"2015-12-29","sol":"1207","ls":"87","season":"Month 3","min_temp":"-85","max_temp":"-25","pressure":"858","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-13"},{"id":"1137","terrestrial_date":"2015-12-28","sol":"1206","ls":"87","season":"Month 3","min_temp":"-85","max_temp":"-24","pressure":"859","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-13"},{"id":"1134","terrestrial_date":"2015-12-27","sol":"1205","ls":"86","season":"Month 3","min_temp":"-86","max_temp":"-26","pressure":"861","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-13"},{"id":"1135","terrestrial_date":"2015-12-26","sol":"1204","ls":"86","season":"Month 3","min_temp":"-84","max_temp":"-25","pressure":"862","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-12"},{"id":"1136","terrestrial_date":"2015-12-25","sol":"1203","ls":"85","season":"Month 3","min_temp":"-85","max_temp":"-23","pressure":"863","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-13"},{"id":"1133","terrestrial_date":"2015-12-24","sol":"1202","ls":"85","season":"Month 3","min_temp":"-85","max_temp":"-22","pressure":"864","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-12"},{"id":"1132","terrestrial_date":"2015-12-23","sol":"1201","ls":"84","season":"Month 3","min_temp":"-85","max_temp":"-29","pressure":"866","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-13"},{"id":"1131","terrestrial_date":"2015-12-22","sol":"1200","ls":"84","season":"Month 3","min_temp":"-84","max_temp":"-27","pressure":"866","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:38","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-12"},{"id":"1130","terrestrial_date":"2015-12-21","sol":"1199","ls":"84","season":"Month 3","min_temp":"-86","max_temp":"-29","pressure":"868","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:38","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-14"},{"id":"1128","terrestrial_date":"2015-12-20","sol":"1198","ls":"83","season":"Month 3","min_temp":"-86","max_temp":"-23","pressure":"868","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:38","local_uv_irradiance_index":"Moderate","min_gts_temp":"-89","max_gts_temp":"-13"},{"id":"1127","terrestrial_date":"2015-12-18","sol":"1197","ls":"83","season":"Month 3","min_temp":"-85","max_temp":"-26","pressure":"869","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"17:38","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-13"},{"id":"1129","terrestrial_date":"2015-12-17","sol":"1196","ls":"82","season":"Month 3","min_temp":"-86","max_temp":"-27","pressure":"871","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"17:38","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-7"},{"id":"1126","terrestrial_date":"2015-12-16","sol":"1195","ls":"82","season":"Month 3","min_temp":"-86","max_temp":"-32","pressure":"872","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"17:39","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-6"},{"id":"1125","terrestrial_date":"2015-12-15","sol":"1194","ls":"81","season":"Month 3","min_temp":"-84","max_temp":"-29","pressure":"873","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"17:39","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-5"},{"id":"1124","terrestrial_date":"2015-12-14","sol":"1193","ls":"81","season":"Month 3","min_temp":"-84","max_temp":"-28","pressure":"875","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"17:39","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-10"},{"id":"1123","terrestrial_date":"2015-12-13","sol":"1192","ls":"80","season":"Month 3","min_temp":"-86","max_temp":"-24","pressure":"876","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"17:39","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"-10"},{"id":"1122","terrestrial_date":"2015-12-12","sol":"1191","ls":"80","season":"Month 3","min_temp":"-87","max_temp":"-28","pressure":"876","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"17:39","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"-11"},{"id":"1121","terrestrial_date":"2015-12-11","sol":"1190","ls":"79","season":"Month 3","min_temp":"-87","max_temp":"-29","pressure":"877","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"17:39","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"-12"},{"id":"1120","terrestrial_date":"2015-12-10","sol":"1189","ls":"79","season":"Month 3","min_temp":"-87","max_temp":"-24","pressure":"879","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"17:40","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-10"},{"id":"1119","terrestrial_date":"2015-12-09","sol":"1188","ls":"79","season":"Month 3","min_temp":"-90","max_temp":"-31","pressure":"881","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"17:40","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-11"},{"id":"1118","terrestrial_date":"2015-12-08","sol":"1187","ls":"78","season":"Month 3","min_temp":"-84","max_temp":"-29","pressure":"881","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"17:40","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-8"},{"id":"1117","terrestrial_date":"2015-12-07","sol":"1186","ls":"78","season":"Month 3","min_temp":"-86","max_temp":"-28","pressure":"881","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"17:40","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"-8"},{"id":"1116","terrestrial_date":"2015-12-06","sol":"1185","ls":"77","season":"Month 3","min_temp":"-84","max_temp":"-24","pressure":"881","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"17:40","local_uv_irradiance_index":"High","min_gts_temp":"-94","max_gts_temp":"-3"},{"id":"1115","terrestrial_date":"2015-12-05","sol":"1184","ls":"77","season":"Month 3","min_temp":"-85","max_temp":"-28","pressure":"882","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"17:41","local_uv_irradiance_index":"Moderate","min_gts_temp":"-94","max_gts_temp":"-4"},{"id":"1113","terrestrial_date":"2015-12-04","sol":"1183","ls":"76","season":"Month 3","min_temp":"-86","max_temp":"-26","pressure":"883","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"17:41","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-5"},{"id":"1114","terrestrial_date":"2015-12-03","sol":"1182","ls":"76","season":"Month 3","min_temp":"-85","max_temp":"-29","pressure":"884","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"17:41","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-6"},{"id":"1112","terrestrial_date":"2015-12-02","sol":"1181","ls":"75","season":"Month 3","min_temp":"-86","max_temp":"-24","pressure":"885","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"17:41","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-7"},{"id":"1111","terrestrial_date":"2015-12-01","sol":"1180","ls":"75","season":"Month 3","min_temp":"-86","max_temp":"-27","pressure":"886","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"17:41","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-11"},{"id":"1110","terrestrial_date":"2015-11-30","sol":"1179","ls":"75","season":"Month 3","min_temp":"-85","max_temp":"-25","pressure":"887","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:59","sunset":"17:42","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-12"},{"id":"1109","terrestrial_date":"2015-11-29","sol":"1178","ls":"74","season":"Month 3","min_temp":"-86","max_temp":"-26","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:59","sunset":"17:42","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-13"},{"id":"1108","terrestrial_date":"2015-11-28","sol":"1177","ls":"74","season":"Month 3","min_temp":"-84","max_temp":"-27","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:59","sunset":"17:42","local_uv_irradiance_index":"Moderate","min_gts_temp":"-89","max_gts_temp":"-12"},{"id":"1107","terrestrial_date":"2015-11-27","sol":"1176","ls":"73","season":"Month 3","min_temp":"-84","max_temp":"-31","pressure":"890","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:59","sunset":"17:42","local_uv_irradiance_index":"Moderate","min_gts_temp":"-89","max_gts_temp":"-12"},{"id":"1106","terrestrial_date":"2015-11-26","sol":"1175","ls":"73","season":"Month 3","min_temp":"-85","max_temp":"-23","pressure":"890","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:59","sunset":"17:43","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-11"},{"id":"1105","terrestrial_date":"2015-11-25","sol":"1174","ls":"72","season":"Month 3","min_temp":"-85","max_temp":"-25","pressure":"891","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"17:43","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-8"},{"id":"1103","terrestrial_date":"2015-11-24","sol":"1173","ls":"72","season":"Month 3","min_temp":"-87","max_temp":"-31","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"17:43","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"-14"},{"id":"1104","terrestrial_date":"2015-11-23","sol":"1172","ls":"71","season":"Month 3","min_temp":"-87","max_temp":"-26","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"17:43","local_uv_irradiance_index":"High","min_gts_temp":"-91","max_gts_temp":"-13"},{"id":"1099","terrestrial_date":"2015-11-22","sol":"1171","ls":"71","season":"Month 3","min_temp":"-87","max_temp":"-29","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"17:44","local_uv_irradiance_index":"High","min_gts_temp":"-90","max_gts_temp":"-15"},{"id":"1101","terrestrial_date":"2015-11-21","sol":"1170","ls":"71","season":"Month 3","min_temp":"-85","max_temp":"-31","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"17:44","local_uv_irradiance_index":"High","min_gts_temp":"-89","max_gts_temp":"-15"},{"id":"1100","terrestrial_date":"2015-11-20","sol":"1169","ls":"70","season":"Month 3","min_temp":"-89","max_temp":"-32","pressure":"894","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"17:44","local_uv_irradiance_index":"High","min_gts_temp":"-89","max_gts_temp":"-16"},{"id":"1102","terrestrial_date":"2015-11-19","sol":"1168","ls":"70","season":"Month 3","min_temp":"-84","max_temp":"-29","pressure":"894","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:01","sunset":"17:44","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-10"},{"id":"1098","terrestrial_date":"2015-11-18","sol":"1167","ls":"69","season":"Month 3","min_temp":"-84","max_temp":"-25","pressure":"894","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:01","sunset":"17:45","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-13"},{"id":"1097","terrestrial_date":"2015-11-17","sol":"1166","ls":"69","season":"Month 3","min_temp":"-84","max_temp":"-31","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:01","sunset":"17:45","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-12"},{"id":"1096","terrestrial_date":"2015-11-16","sol":"1165","ls":"68","season":"Month 3","min_temp":"-84","max_temp":"-35","pressure":"897","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:01","sunset":"17:45","local_uv_irradiance_index":"Moderate","min_gts_temp":"-89","max_gts_temp":"-61"},{"id":"1095","terrestrial_date":"2015-11-15","sol":"1164","ls":"68","season":"Month 3","min_temp":"-86","max_temp":"-35","pressure":"896","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:01","sunset":"17:45","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-14"},{"id":"1094","terrestrial_date":"2015-11-14","sol":"1163","ls":"67","season":"Month 3","min_temp":"-86","max_temp":"-29","pressure":"896","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:02","sunset":"17:46","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-12"},{"id":"1093","terrestrial_date":"2015-11-13","sol":"1162","ls":"67","season":"Month 3","min_temp":"-84","max_temp":"-27","pressure":"897","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:02","sunset":"17:46","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"-12"},{"id":"1092","terrestrial_date":"2015-11-12","sol":"1161","ls":"66","season":"Month 3","min_temp":"-83","max_temp":"-26","pressure":"898","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:02","sunset":"17:46","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"-13"},{"id":"1091","terrestrial_date":"2015-11-10","sol":"1160","ls":"66","season":"Month 3","min_temp":"-80","max_temp":"-28","pressure":"899","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:02","sunset":"17:46","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-15"},{"id":"1090","terrestrial_date":"2015-11-09","sol":"1159","ls":"66","season":"Month 3","min_temp":"-82","max_temp":"-28","pressure":"898","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:02","sunset":"17:47","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"-14"},{"id":"1089","terrestrial_date":"2015-11-08","sol":"1158","ls":"65","season":"Month 3","min_temp":"-82","max_temp":"-28","pressure":"898","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:03","sunset":"17:47","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-12"},{"id":"1087","terrestrial_date":"2015-11-07","sol":"1157","ls":"65","season":"Month 3","min_temp":"-82","max_temp":"-32","pressure":"900","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:03","sunset":"17:47","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"-14"},{"id":"1085","terrestrial_date":"2015-11-06","sol":"1156","ls":"64","season":"Month 3","min_temp":"-84","max_temp":"-30","pressure":"900","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:03","sunset":"17:47","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-13"},{"id":"1084","terrestrial_date":"2015-11-05","sol":"1155","ls":"64","season":"Month 3","min_temp":"-84","max_temp":"-26","pressure":"900","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:03","sunset":"17:48","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"-13"},{"id":"1088","terrestrial_date":"2015-11-04","sol":"1154","ls":"63","season":"Month 3","min_temp":"-84","max_temp":"-29","pressure":"900","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:04","sunset":"17:48","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"-13"},{"id":"1083","terrestrial_date":"2015-11-03","sol":"1153","ls":"63","season":"Month 3","min_temp":"-82","max_temp":"-31","pressure":"900","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:04","sunset":"17:48","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"-16"},{"id":"1086","terrestrial_date":"2015-11-02","sol":"1152","ls":"62","season":"Month 3","min_temp":"-80","max_temp":"-30","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:04","sunset":"17:49","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-17"},{"id":"1082","terrestrial_date":"2015-11-01","sol":"1151","ls":"62","season":"Month 3","min_temp":"-82","max_temp":"-31","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:04","sunset":"17:49","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-17"},{"id":"1081","terrestrial_date":"2015-10-31","sol":"1150","ls":"62","season":"Month 3","min_temp":"-82","max_temp":"-29","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:04","sunset":"17:49","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-17"},{"id":"1079","terrestrial_date":"2015-10-30","sol":"1149","ls":"61","season":"Month 3","min_temp":"-81","max_temp":"-23","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:05","sunset":"17:49","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"-17"},{"id":"1080","terrestrial_date":"2015-10-29","sol":"1148","ls":"61","season":"Month 3","min_temp":"-80","max_temp":"-28","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:05","sunset":"17:50","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"-15"},{"id":"1078","terrestrial_date":"2015-10-28","sol":"1147","ls":"60","season":"Month 3","min_temp":"-80","max_temp":"-29","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:05","sunset":"17:50","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-17"},{"id":"1077","terrestrial_date":"2015-10-27","sol":"1146","ls":"60","season":"Month 3","min_temp":"-82","max_temp":"-28","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:05","sunset":"17:50","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"-16"},{"id":"1076","terrestrial_date":"2015-10-26","sol":"1145","ls":"59","season":"Month 2","min_temp":"-82","max_temp":"-29","pressure":"903","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:06","sunset":"17:51","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"-12"},{"id":"1075","terrestrial_date":"2015-10-25","sol":"1144","ls":"59","season":"Month 2","min_temp":"-82","max_temp":"-28","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:06","sunset":"17:51","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-10"},{"id":"1074","terrestrial_date":"2015-10-24","sol":"1143","ls":"58","season":"Month 2","min_temp":"-82","max_temp":"-29","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:06","sunset":"17:51","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-17"},{"id":"1073","terrestrial_date":"2015-10-23","sol":"1142","ls":"58","season":"Month 2","min_temp":"-82","max_temp":"-23","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:06","sunset":"17:52","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"-14"},{"id":"1072","terrestrial_date":"2015-10-22","sol":"1141","ls":"57","season":"Month 2","min_temp":"-82","max_temp":"-28","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:06","sunset":"17:52","local_uv_irradiance_index":"Moderate","min_gts_temp":"-80","max_gts_temp":"-12"},{"id":"1071","terrestrial_date":"2015-10-21","sol":"1140","ls":"57","season":"Month 2","min_temp":"-81","max_temp":"-26","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:07","sunset":"17:52","local_uv_irradiance_index":"Moderate","min_gts_temp":"-80","max_gts_temp":"-16"},{"id":"1070","terrestrial_date":"2015-10-20","sol":"1139","ls":"57","season":"Month 2","min_temp":"-80","max_temp":"-25","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:07","sunset":"17:53","local_uv_irradiance_index":"Moderate","min_gts_temp":"-80","max_gts_temp":"-14"},{"id":"1067","terrestrial_date":"2015-10-19","sol":"1138","ls":"56","season":"Month 2","min_temp":"-82","max_temp":"-29","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:07","sunset":"17:53","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-15"},{"id":"1068","terrestrial_date":"2015-10-18","sol":"1137","ls":"56","season":"Month 2","min_temp":"-81","max_temp":"-26","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:07","sunset":"17:53","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"-14"},{"id":"1066","terrestrial_date":"2015-10-17","sol":"1136","ls":"55","season":"Month 2","min_temp":"-82","max_temp":"-23","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:08","sunset":"17:53","local_uv_irradiance_index":"Moderate","min_gts_temp":"-74","max_gts_temp":"-14"},{"id":"1069","terrestrial_date":"2015-10-16","sol":"1135","ls":"55","season":"Month 2","min_temp":"-81","max_temp":"-27","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:08","sunset":"17:54","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-15"},{"id":"1065","terrestrial_date":"2015-10-15","sol":"1134","ls":"54","season":"Month 2","min_temp":"-80","max_temp":"-27","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:08","sunset":"17:54","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-14"},{"id":"1064","terrestrial_date":"2015-10-14","sol":"1133","ls":"54","season":"Month 2","min_temp":"-82","max_temp":"-26","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:08","sunset":"17:54","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-14"},{"id":"1063","terrestrial_date":"2015-10-13","sol":"1132","ls":"53","season":"Month 2","min_temp":"-82","max_temp":"-27","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:09","sunset":"17:55","local_uv_irradiance_index":"Moderate","min_gts_temp":"-77","max_gts_temp":"-14"},{"id":"1062","terrestrial_date":"2015-10-12","sol":"1131","ls":"53","season":"Month 2","min_temp":"-81","max_temp":"-28","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:09","sunset":"17:55","local_uv_irradiance_index":"Moderate","min_gts_temp":"-77","max_gts_temp":"-14"},{"id":"1061","terrestrial_date":"2015-10-11","sol":"1130","ls":"53","season":"Month 2","min_temp":"-81","max_temp":"-25","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:09","sunset":"17:56","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-13"},{"id":"1060","terrestrial_date":"2015-10-10","sol":"1129","ls":"52","season":"Month 2","min_temp":"-80","max_temp":"-23","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:09","sunset":"17:56","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-14"},{"id":"1059","terrestrial_date":"2015-10-09","sol":"1128","ls":"52","season":"Month 2","min_temp":"-79","max_temp":"-27","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:10","sunset":"17:56","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-13"},{"id":"1058","terrestrial_date":"2015-10-08","sol":"1127","ls":"51","season":"Month 2","min_temp":"-80","max_temp":"-27","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:10","sunset":"17:57","local_uv_irradiance_index":"Moderate","min_gts_temp":"-77","max_gts_temp":"-13"},{"id":"1057","terrestrial_date":"2015-10-07","sol":"1126","ls":"51","season":"Month 2","min_temp":"-79","max_temp":"-21","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:10","sunset":"17:57","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-12"},{"id":"1056","terrestrial_date":"2015-10-06","sol":"1125","ls":"50","season":"Month 2","min_temp":"-79","max_temp":"-22","pressure":"900","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:10","sunset":"17:57","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-13"},{"id":"1055","terrestrial_date":"2015-10-04","sol":"1124","ls":"50","season":"Month 2","min_temp":"-80","max_temp":"-26","pressure":"900","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:11","sunset":"17:58","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-12"},{"id":"1054","terrestrial_date":"2015-10-03","sol":"1123","ls":"49","season":"Month 2","min_temp":"-79","max_temp":"-27","pressure":"900","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:11","sunset":"17:58","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-12"},{"id":"1053","terrestrial_date":"2015-10-02","sol":"1122","ls":"49","season":"Month 2","min_temp":"-79","max_temp":"-26","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:11","sunset":"17:58","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-13"},{"id":"1052","terrestrial_date":"2015-10-01","sol":"1121","ls":"48","season":"Month 2","min_temp":"-81","max_temp":"-25","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:12","sunset":"17:59","local_uv_irradiance_index":"Moderate","min_gts_temp":"-77","max_gts_temp":"-13"},{"id":"1051","terrestrial_date":"2015-09-30","sol":"1120","ls":"48","season":"Month 2","min_temp":"-80","max_temp":"-24","pressure":"900","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:12","sunset":"17:59","local_uv_irradiance_index":"Moderate","min_gts_temp":"-75","max_gts_temp":"-11"},{"id":"1050","terrestrial_date":"2015-09-29","sol":"1119","ls":"48","season":"Month 2","min_temp":"-81","max_temp":"-22","pressure":"899","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:12","sunset":"17:59","local_uv_irradiance_index":"Moderate","min_gts_temp":"-76","max_gts_temp":"-12"},{"id":"1049","terrestrial_date":"2015-09-28","sol":"1118","ls":"47","season":"Month 2","min_temp":"-80","max_temp":"-25","pressure":"898","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:12","sunset":"18:00","local_uv_irradiance_index":"Moderate","min_gts_temp":"-76","max_gts_temp":"-13"},{"id":"1048","terrestrial_date":"2015-09-27","sol":"1117","ls":"47","season":"Month 2","min_temp":"-79","max_temp":"-25","pressure":"898","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:13","sunset":"18:00","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-12"},{"id":"1046","terrestrial_date":"2015-09-26","sol":"1116","ls":"46","season":"Month 2","min_temp":"-79","max_temp":"-26","pressure":"898","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:13","sunset":"18:01","local_uv_irradiance_index":"Moderate","min_gts_temp":"-77","max_gts_temp":"-13"},{"id":"1047","terrestrial_date":"2015-09-25","sol":"1115","ls":"46","season":"Month 2","min_temp":"-80","max_temp":"-21","pressure":"897","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:13","sunset":"18:01","local_uv_irradiance_index":"Moderate","min_gts_temp":"-76","max_gts_temp":"-11"},{"id":"1045","terrestrial_date":"2015-09-24","sol":"1114","ls":"45","season":"Month 2","min_temp":"-79","max_temp":"-25","pressure":"896","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:13","sunset":"18:01","local_uv_irradiance_index":"Moderate","min_gts_temp":"-75","max_gts_temp":"-12"},{"id":"1044","terrestrial_date":"2015-09-23","sol":"1113","ls":"45","season":"Month 2","min_temp":"-79","max_temp":"-24","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:14","sunset":"18:02","local_uv_irradiance_index":"Moderate","min_gts_temp":"-74","max_gts_temp":"-12"},{"id":"1043","terrestrial_date":"2015-09-22","sol":"1112","ls":"44","season":"Month 2","min_temp":"-80","max_temp":"-24","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:14","sunset":"18:02","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-10"},{"id":"1042","terrestrial_date":"2015-09-21","sol":"1111","ls":"44","season":"Month 2","min_temp":"-79","max_temp":"-26","pressure":"896","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:14","sunset":"18:02","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"-13"},{"id":"1041","terrestrial_date":"2015-09-20","sol":"1110","ls":"43","season":"Month 2","min_temp":"-81","max_temp":"-25","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:15","sunset":"18:03","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"-8"},{"id":"1039","terrestrial_date":"2015-09-19","sol":"1109","ls":"43","season":"Month 2","min_temp":"-82","max_temp":"-26","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:15","sunset":"18:03","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"-7"},{"id":"1038","terrestrial_date":"2015-09-18","sol":"1108","ls":"42","season":"Month 2","min_temp":"-78","max_temp":"-25","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:15","sunset":"18:04","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-6"},{"id":"1040","terrestrial_date":"2015-09-17","sol":"1107","ls":"42","season":"Month 2","min_temp":"-79","max_temp":"-24","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:15","sunset":"18:04","local_uv_irradiance_index":"Moderate","min_gts_temp":"-80","max_gts_temp":"-7"},{"id":"1037","terrestrial_date":"2015-09-16","sol":"1106","ls":"42","season":"Month 2","min_temp":"-82","max_temp":"-22","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:16","sunset":"18:04","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"-8"},{"id":"1036","terrestrial_date":"2015-09-15","sol":"1105","ls":"41","season":"Month 2","min_temp":"-78","max_temp":"-25","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:16","sunset":"18:05","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"-9"},{"id":"1035","terrestrial_date":"2015-09-14","sol":"1104","ls":"41","season":"Month 2","min_temp":"-79","max_temp":"-25","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:16","sunset":"18:05","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"-6"},{"id":"1033","terrestrial_date":"2015-09-13","sol":"1103","ls":"40","season":"Month 2","min_temp":"-81","max_temp":"-26","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:17","sunset":"18:06","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-5"},{"id":"1032","terrestrial_date":"2015-09-12","sol":"1102","ls":"40","season":"Month 2","min_temp":"-84","max_temp":"-25","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:17","sunset":"18:06","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"-6"},{"id":"1034","terrestrial_date":"2015-09-11","sol":"1101","ls":"39","season":"Month 2","min_temp":"-80","max_temp":"-23","pressure":"891","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:17","sunset":"18:06","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-4"},{"id":"1031","terrestrial_date":"2015-09-10","sol":"1100","ls":"39","season":"Month 2","min_temp":"-79","max_temp":"-22","pressure":"890","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:17","sunset":"18:07","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-8"},{"id":"1030","terrestrial_date":"2015-09-09","sol":"1099","ls":"38","season":"Month 2","min_temp":"-78","max_temp":"-24","pressure":"891","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:18","sunset":"18:07","local_uv_irradiance_index":"Moderate","min_gts_temp":"-80","max_gts_temp":"-7"},{"id":"1029","terrestrial_date":"2015-09-08","sol":"1098","ls":"38","season":"Month 2","min_temp":"-77","max_temp":"-26","pressure":"890","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:18","sunset":"18:08","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"-10"},{"id":"1028","terrestrial_date":"2015-09-07","sol":"1097","ls":"37","season":"Month 2","min_temp":"-78","max_temp":"-27","pressure":"889","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:18","sunset":"18:08","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"-8"},{"id":"1025","terrestrial_date":"2015-09-06","sol":"1096","ls":"37","season":"Month 2","min_temp":"-79","max_temp":"-24","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:19","sunset":"18:08","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-7"},{"id":"1027","terrestrial_date":"2015-09-05","sol":"1095","ls":"36","season":"Month 2","min_temp":"-79","max_temp":"-24","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:19","sunset":"18:09","local_uv_irradiance_index":"Moderate","min_gts_temp":"-77","max_gts_temp":"-8"},{"id":"1026","terrestrial_date":"2015-09-04","sol":"1094","ls":"36","season":"Month 2","min_temp":"-80","max_temp":"-20","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:19","sunset":"18:09","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"-7"},{"id":"1024","terrestrial_date":"2015-09-03","sol":"1093","ls":"36","season":"Month 2","min_temp":"-77","max_temp":"-21","pressure":"887","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:20","sunset":"18:10","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"-4"},{"id":"1023","terrestrial_date":"2015-09-02","sol":"1092","ls":"35","season":"Month 2","min_temp":"-79","max_temp":"-23","pressure":"886","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:20","sunset":"18:10","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-8"},{"id":"1022","terrestrial_date":"2015-09-01","sol":"1091","ls":"35","season":"Month 2","min_temp":"-77","max_temp":"-21","pressure":"886","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:20","sunset":"18:10","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"-7"},{"id":"1021","terrestrial_date":"2015-08-31","sol":"1090","ls":"34","season":"Month 2","min_temp":"-78","max_temp":"-20","pressure":"886","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:20","sunset":"18:11","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"-6"},{"id":"1018","terrestrial_date":"2015-08-30","sol":"1089","ls":"34","season":"Month 2","min_temp":"-76","max_temp":"-19","pressure":"885","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:21","sunset":"18:11","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"-7"},{"id":"1020","terrestrial_date":"2015-08-29","sol":"1088","ls":"33","season":"Month 2","min_temp":"-77","max_temp":"-19","pressure":"885","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:21","sunset":"18:12","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"-7"},{"id":"1019","terrestrial_date":"2015-08-27","sol":"1087","ls":"33","season":"Month 2","min_temp":"-78","max_temp":"-19","pressure":"885","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:21","sunset":"18:12","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"-3"},{"id":"1016","terrestrial_date":"2015-08-26","sol":"1086","ls":"32","season":"Month 2","min_temp":"-77","max_temp":"-25","pressure":"885","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:22","sunset":"18:13","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"-2"},{"id":"1017","terrestrial_date":"2015-08-25","sol":"1085","ls":"32","season":"Month 2","min_temp":"-79","max_temp":"-23","pressure":"886","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:22","sunset":"18:13","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-10"},{"id":"1015","terrestrial_date":"2015-08-24","sol":"1084","ls":"31","season":"Month 2","min_temp":"-78","max_temp":"-22","pressure":"885","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:22","sunset":"18:13","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"-9"},{"id":"1014","terrestrial_date":"2015-08-23","sol":"1083","ls":"31","season":"Month 2","min_temp":"-80","max_temp":"-20","pressure":"883","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:23","sunset":"18:14","local_uv_irradiance_index":"Moderate","min_gts_temp":"-80","max_gts_temp":"-7"},{"id":"1012","terrestrial_date":"2015-08-22","sol":"1082","ls":"30","season":"Month 2","min_temp":"-79","max_temp":"-17","pressure":"882","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:23","sunset":"18:14","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-7"},{"id":"1011","terrestrial_date":"2015-08-21","sol":"1081","ls":"30","season":"Month 2","min_temp":"-77","max_temp":"-18","pressure":"882","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:23","sunset":"18:15","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"-7"},{"id":"1013","terrestrial_date":"2015-08-20","sol":"1080","ls":"29","season":"Month 1","min_temp":"-77","max_temp":"-17","pressure":"882","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:23","sunset":"18:15","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"-3"},{"id":"1010","terrestrial_date":"2015-08-19","sol":"1079","ls":"29","season":"Month 1","min_temp":"-80","max_temp":"-21","pressure":"882","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:24","sunset":"18:16","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"-3"},{"id":"1009","terrestrial_date":"2015-08-18","sol":"1078","ls":"29","season":"Month 1","min_temp":"-80","max_temp":"-18","pressure":"881","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:24","sunset":"18:16","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"1"},{"id":"1008","terrestrial_date":"2015-08-17","sol":"1077","ls":"28","season":"Month 1","min_temp":"-79","max_temp":"-16","pressure":"880","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:24","sunset":"18:16","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-2"},{"id":"1007","terrestrial_date":"2015-08-16","sol":"1076","ls":"28","season":"Month 1","min_temp":"-81","max_temp":"-14","pressure":"880","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:25","sunset":"18:17","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-1"},{"id":"1006","terrestrial_date":"2015-08-15","sol":"1075","ls":"27","season":"Month 1","min_temp":"-77","max_temp":"-13","pressure":"879","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:25","sunset":"18:17","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"-3"},{"id":"1005","terrestrial_date":"2015-08-14","sol":"1074","ls":"27","season":"Month 1","min_temp":"-77","max_temp":"-14","pressure":"878","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:25","sunset":"18:18","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"-2"},{"id":"1004","terrestrial_date":"2015-08-13","sol":"1073","ls":"26","season":"Month 1","min_temp":"-82","max_temp":"-15","pressure":"879","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:26","sunset":"18:18","local_uv_irradiance_index":"Moderate","min_gts_temp":"-77","max_gts_temp":"1"},{"id":"1003","terrestrial_date":"2015-08-12","sol":"1072","ls":"26","season":"Month 1","min_temp":"-78","max_temp":"-15","pressure":"879","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:26","sunset":"18:19","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"2"},{"id":"1002","terrestrial_date":"2015-08-11","sol":"1071","ls":"25","season":"Month 1","min_temp":"-78","max_temp":"-16","pressure":"878","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:26","sunset":"18:19","local_uv_irradiance_index":"High","min_gts_temp":"-68","max_gts_temp":"-4"},{"id":"1001","terrestrial_date":"2015-08-10","sol":"1070","ls":"25","season":"Month 1","min_temp":"-80","max_temp":"-14","pressure":"877","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:27","sunset":"18:19","local_uv_irradiance_index":"High","min_gts_temp":"-26","max_gts_temp":"-5"},{"id":"999","terrestrial_date":"2015-08-09","sol":"1069","ls":"24","season":"Month 1","min_temp":"-77","max_temp":"-22","pressure":"876","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:27","sunset":"18:20","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"-4"},{"id":"1000","terrestrial_date":"2015-08-08","sol":"1068","ls":"24","season":"Month 1","min_temp":"-76","max_temp":"-23","pressure":"874","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:27","sunset":"18:20","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"-3"},{"id":"998","terrestrial_date":"2015-08-07","sol":"1067","ls":"23","season":"Month 1","min_temp":"-79","max_temp":"-24","pressure":"875","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:27","sunset":"18:21","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"1"},{"id":"997","terrestrial_date":"2015-08-06","sol":"1066","ls":"23","season":"Month 1","min_temp":"-78","max_temp":"-14","pressure":"875","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:28","sunset":"18:21","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"0"},{"id":"995","terrestrial_date":"2015-08-05","sol":"1065","ls":"22","season":"Month 1","min_temp":"-78","max_temp":"-19","pressure":"873","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:28","sunset":"18:22","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"2"},{"id":"996","terrestrial_date":"2015-08-04","sol":"1064","ls":"22","season":"Month 1","min_temp":"-77","max_temp":"-22","pressure":"871","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:28","sunset":"18:22","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"2"},{"id":"994","terrestrial_date":"2015-08-03","sol":"1063","ls":"21","season":"Month 1","min_temp":"-79","max_temp":"-19","pressure":"871","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:29","sunset":"18:22","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"1"},{"id":"991","terrestrial_date":"2015-08-02","sol":"1062","ls":"21","season":"Month 1","min_temp":"-77","max_temp":"-24","pressure":"871","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:29","sunset":"18:23","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"2"},{"id":"993","terrestrial_date":"2015-08-01","sol":"1061","ls":"20","season":"Month 1","min_temp":"-77","max_temp":"-23","pressure":"871","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:29","sunset":"18:23","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"3"},{"id":"992","terrestrial_date":"2015-07-31","sol":"1060","ls":"20","season":"Month 1","min_temp":"-78","max_temp":"-16","pressure":"870","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:30","sunset":"18:24","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"2"},{"id":"990","terrestrial_date":"2015-07-30","sol":"1059","ls":"19","season":"Month 1","min_temp":"-78","max_temp":"-20","pressure":"870","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:30","sunset":"18:24","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"2"},{"id":"989","terrestrial_date":"2015-07-29","sol":"1058","ls":"19","season":"Month 1","min_temp":"-78","max_temp":"-22","pressure":"868","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:30","sunset":"18:25","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"1"},{"id":"988","terrestrial_date":"2015-07-28","sol":"1057","ls":"18","season":"Month 1","min_temp":"-78","max_temp":"-22","pressure":"867","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:30","sunset":"18:25","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"2"},{"id":"986","terrestrial_date":"2015-07-27","sol":"1056","ls":"18","season":"Month 1","min_temp":"-76","max_temp":"-21","pressure":"868","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:31","sunset":"18:25","local_uv_irradiance_index":"High","min_gts_temp":"-91","max_gts_temp":"4"},{"id":"987","terrestrial_date":"2015-07-26","sol":"1055","ls":"17","season":"Month 1","min_temp":"-77","max_temp":"-20","pressure":"868","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:31","sunset":"18:26","local_uv_irradiance_index":"High","min_gts_temp":"-90","max_gts_temp":"6"},{"id":"985","terrestrial_date":"2015-07-25","sol":"1054","ls":"17","season":"Month 1","min_temp":"-77","max_temp":"-11","pressure":"867","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:31","sunset":"18:26","local_uv_irradiance_index":"High","min_gts_temp":"-89","max_gts_temp":"6"},{"id":"984","terrestrial_date":"2015-07-24","sol":"1053","ls":"17","season":"Month 1","min_temp":"-79","max_temp":"-11","pressure":"865","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:32","sunset":"18:27","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"8"},{"id":"982","terrestrial_date":"2015-07-23","sol":"1052","ls":"16","season":"Month 1","min_temp":"-78","max_temp":"-12","pressure":"865","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:32","sunset":"18:27","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"1"},{"id":"983","terrestrial_date":"2015-07-21","sol":"1051","ls":"16","season":"Month 1","min_temp":"-76","max_temp":"-20","pressure":"864","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:32","sunset":"18:28","local_uv_irradiance_index":"High","min_gts_temp":"-91","max_gts_temp":"4"},{"id":"981","terrestrial_date":"2015-07-20","sol":"1050","ls":"15","season":"Month 1","min_temp":"-76","max_temp":"-22","pressure":"863","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:33","sunset":"18:28","local_uv_irradiance_index":"High","min_gts_temp":"-92","max_gts_temp":"6"},{"id":"980","terrestrial_date":"2015-07-19","sol":"1049","ls":"15","season":"Month 1","min_temp":"-75","max_temp":"-21","pressure":"864","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:33","sunset":"18:28","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"5"},{"id":"976","terrestrial_date":"2015-07-18","sol":"1048","ls":"14","season":"Month 1","min_temp":"-78","max_temp":"-15","pressure":"864","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:33","sunset":"18:29","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"2"},{"id":"977","terrestrial_date":"2015-07-17","sol":"1047","ls":"14","season":"Month 1","min_temp":"-77","max_temp":"-14","pressure":"863","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:33","sunset":"18:29","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"2"},{"id":"979","terrestrial_date":"2015-07-16","sol":"1046","ls":"13","season":"Month 1","min_temp":"-77","max_temp":"-12","pressure":"862","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:34","sunset":"18:30","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"2"},{"id":"978","terrestrial_date":"2015-07-15","sol":"1045","ls":"13","season":"Month 1","min_temp":"-80","max_temp":"-13","pressure":"861","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:34","sunset":"18:30","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"1"},{"id":"975","terrestrial_date":"2015-07-14","sol":"1044","ls":"12","season":"Month 1","min_temp":"-79","max_temp":"-20","pressure":"860","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:34","sunset":"18:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-76","max_gts_temp":"-3"},{"id":"974","terrestrial_date":"2015-07-13","sol":"1043","ls":"12","season":"Month 1","min_temp":"-77","max_temp":"-20","pressure":"860","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:35","sunset":"18:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-76","max_gts_temp":"-3"},{"id":"973","terrestrial_date":"2015-07-12","sol":"1042","ls":"11","season":"Month 1","min_temp":"-76","max_temp":"-20","pressure":"859","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:35","sunset":"18:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"-4"},{"id":"971","terrestrial_date":"2015-07-11","sol":"1041","ls":"11","season":"Month 1","min_temp":"-77","max_temp":"-22","pressure":"859","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:35","sunset":"18:32","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"0"},{"id":"972","terrestrial_date":"2015-07-10","sol":"1040","ls":"10","season":"Month 1","min_temp":"-77","max_temp":"-21","pressure":"858","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:35","sunset":"18:32","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"0"},{"id":"970","terrestrial_date":"2015-07-09","sol":"1039","ls":"10","season":"Month 1","min_temp":"-77","max_temp":"-21","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:36","sunset":"18:33","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"-1"},{"id":"969","terrestrial_date":"2015-07-08","sol":"1038","ls":"9","season":"Month 1","min_temp":"-76","max_temp":"-21","pressure":"858","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:36","sunset":"18:33","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"-1"},{"id":"968","terrestrial_date":"2015-07-07","sol":"1037","ls":"9","season":"Month 1","min_temp":"-80","max_temp":"-21","pressure":"856","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:36","sunset":"18:33","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"-1"},{"id":"967","terrestrial_date":"2015-07-06","sol":"1036","ls":"8","season":"Month 1","min_temp":"-76","max_temp":"-17","pressure":"856","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:36","sunset":"18:34","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"4"},{"id":"966","terrestrial_date":"2015-07-05","sol":"1035","ls":"8","season":"Month 1","min_temp":"-77","max_temp":"-12","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:37","sunset":"18:34","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"6"},{"id":"964","terrestrial_date":"2015-07-04","sol":"1034","ls":"7","season":"Month 1","min_temp":"-76","max_temp":"-14","pressure":"859","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:37","sunset":"18:35","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"-1"},{"id":"965","terrestrial_date":"2015-07-03","sol":"1033","ls":"7","season":"Month 1","min_temp":"-77","max_temp":"-14","pressure":"856","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:37","sunset":"18:35","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"-2"},{"id":"962","terrestrial_date":"2015-07-02","sol":"1032","ls":"6","season":"Month 1","min_temp":"-74","max_temp":"-16","pressure":"854","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:38","sunset":"18:35","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"0"},{"id":"963","terrestrial_date":"2015-07-01","sol":"1031","ls":"6","season":"Month 1","min_temp":"-76","max_temp":"-15","pressure":"854","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:38","sunset":"18:36","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"0"},{"id":"961","terrestrial_date":"2015-06-30","sol":"1030","ls":"5","season":"Month 1","min_temp":"-77","max_temp":"-15","pressure":"855","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:38","sunset":"18:36","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-1"},{"id":"959","terrestrial_date":"2015-06-29","sol":"1029","ls":"5","season":"Month 1","min_temp":"-75","max_temp":"-14","pressure":"856","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:38","sunset":"18:37","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"-2"},{"id":"960","terrestrial_date":"2015-06-28","sol":"1028","ls":"4","season":"Month 1","min_temp":"-75","max_temp":"-15","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:39","sunset":"18:37","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"-2"},{"id":"957","terrestrial_date":"2015-06-26","sol":"1026","ls":"3","season":"Month 1","min_temp":"-78","max_temp":"-16","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:39","sunset":"18:38","local_uv_irradiance_index":"Low","min_gts_temp":"-78","max_gts_temp":"-1"},{"id":"958","terrestrial_date":"2015-06-25","sol":"1025","ls":"3","season":"Month 1","min_temp":"-74","max_temp":"-14","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:39","sunset":"18:38","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-1"},{"id":"945","terrestrial_date":"2015-06-24","sol":"1024","ls":"2","season":"Month 1","min_temp":"-76","max_temp":"-15","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:39","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-1"},{"id":"943","terrestrial_date":"2015-06-23","sol":"1023","ls":"2","season":"Month 1","min_temp":"-76","max_temp":"-15","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:39","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"-1"},{"id":"944","terrestrial_date":"2015-06-22","sol":"1022","ls":"1","season":"Month 1","min_temp":"-75","max_temp":"-12","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:39","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"-2"},{"id":"942","terrestrial_date":"2015-06-21","sol":"1021","ls":"1","season":"Month 1","min_temp":"-76","max_temp":"-14","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:40","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"-1"},{"id":"938","terrestrial_date":"2015-06-20","sol":"1020","ls":"0","season":"Month 1","min_temp":"-63","max_temp":"-12","pressure":"832","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:40","local_uv_irradiance_index":"High","min_gts_temp":"-65","max_gts_temp":"1"},{"id":"954","terrestrial_date":"2015-06-19","sol":"1019","ls":"0","season":"Month 1","min_temp":"-81","max_temp":"-14","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:41","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"-2"},{"id":"956","terrestrial_date":"2015-06-18","sol":"1018","ls":"359","season":"Month 12","min_temp":"-79","max_temp":"-15","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:41","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-1"},{"id":"955","terrestrial_date":"2015-06-17","sol":"1017","ls":"359","season":"Month 12","min_temp":"-78","max_temp":"-12","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:41","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"-1"},{"id":"952","terrestrial_date":"2015-06-16","sol":"1016","ls":"358","season":"Month 12","min_temp":"-76","max_temp":"-11","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:42","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"0"},{"id":"951","terrestrial_date":"2015-06-14","sol":"1015","ls":"357","season":"Month 12","min_temp":"-75","max_temp":"-13","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:42","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"1"},{"id":"950","terrestrial_date":"2015-06-13","sol":"1014","ls":"357","season":"Month 12","min_temp":"-77","max_temp":"-14","pressure":"846","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:42","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"0"},{"id":"953","terrestrial_date":"2015-06-12","sol":"1013","ls":"356","season":"Month 12","min_temp":"-80","max_temp":"-12","pressure":"846","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:43","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"0"},{"id":"949","terrestrial_date":"2015-06-11","sol":"1012","ls":"356","season":"Month 12","min_temp":"-81","max_temp":"-16","pressure":"846","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:43","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"-1"},{"id":"948","terrestrial_date":"2015-06-10","sol":"1011","ls":"355","season":"Month 12","min_temp":"-78","max_temp":"-12","pressure":"845","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:43","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"0"},{"id":"947","terrestrial_date":"2015-06-09","sol":"1010","ls":"355","season":"Month 12","min_temp":"-74","max_temp":"-11","pressure":"846","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:44","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"-1"},{"id":"946","terrestrial_date":"2015-06-08","sol":"1009","ls":"354","season":"Month 12","min_temp":"-75","max_temp":"-12","pressure":"845","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:44","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"1"},{"id":"940","terrestrial_date":"2015-06-07","sol":"1008","ls":"354","season":"Month 12","min_temp":"-79","max_temp":"-12","pressure":"844","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:44","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"2"},{"id":"937","terrestrial_date":"2015-06-06","sol":"1007","ls":"353","season":"Month 12","min_temp":"-79","max_temp":"-12","pressure":"845","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:45","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"1"},{"id":"941","terrestrial_date":"2015-06-05","sol":"1006","ls":"353","season":"Month 12","min_temp":"-78","max_temp":"-13","pressure":"844","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:45","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"0"},{"id":"939","terrestrial_date":"2015-06-04","sol":"1005","ls":"352","season":"Month 12","min_temp":"-75","max_temp":"-12","pressure":"843","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:45","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"1"},{"id":"935","terrestrial_date":"2015-06-03","sol":"1004","ls":"352","season":"Month 12","min_temp":"-74","max_temp":"-9","pressure":"842","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:46","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"1"},{"id":"934","terrestrial_date":"2015-06-02","sol":"1003","ls":"351","season":"Month 12","min_temp":"-74","max_temp":"-10","pressure":"843","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:46","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"1"},{"id":"936","terrestrial_date":"2015-06-01","sol":"1002","ls":"351","season":"Month 12","min_temp":"-77","max_temp":"-12","pressure":"844","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:46","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"1"},{"id":"933","terrestrial_date":"2015-05-31","sol":"1001","ls":"350","season":"Month 12","min_temp":"-79","max_temp":"-12","pressure":"843","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:47","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"2"},{"id":"932","terrestrial_date":"2015-05-30","sol":"1000","ls":"350","season":"Month 12","min_temp":"-74","max_temp":"-12","pressure":"841","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:47","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"1"},{"id":"931","terrestrial_date":"2015-05-28","sol":"998","ls":"349","season":"Month 12","min_temp":"-73","max_temp":"-8","pressure":"842","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:48","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"1"},{"id":"930","terrestrial_date":"2015-05-27","sol":"997","ls":"348","season":"Month 12","min_temp":"-74","max_temp":"-13","pressure":"843","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:48","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"1"},{"id":"928","terrestrial_date":"2015-05-26","sol":"996","ls":"348","season":"Month 12","min_temp":"-72","max_temp":"-4","pressure":"842","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:48","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"2"},{"id":"929","terrestrial_date":"2015-05-25","sol":"995","ls":"347","season":"Month 12","min_temp":"-74","max_temp":"-4","pressure":"842","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:48","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"5"},{"id":"925","terrestrial_date":"2015-05-24","sol":"994","ls":"346","season":"Month 12","min_temp":"-79","max_temp":"-5","pressure":"842","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:49","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"3"},{"id":"927","terrestrial_date":"2015-05-23","sol":"993","ls":"346","season":"Month 12","min_temp":"-73","max_temp":"-8","pressure":"840","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:49","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"3"},{"id":"924","terrestrial_date":"2015-05-22","sol":"992","ls":"345","season":"Month 12","min_temp":"-73","max_temp":"-6","pressure":"842","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:49","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"4"},{"id":"926","terrestrial_date":"2015-05-21","sol":"991","ls":"345","season":"Month 12","min_temp":"-73","max_temp":"-3","pressure":"840","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:49","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"4"},{"id":"923","terrestrial_date":"2015-05-20","sol":"990","ls":"344","season":"Month 12","min_temp":"-76","max_temp":"-1","pressure":"839","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:50","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"9"},{"id":"921","terrestrial_date":"2015-05-19","sol":"989","ls":"344","season":"Month 12","min_temp":"-74","max_temp":"-10","pressure":"841","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:50","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"9"},{"id":"922","terrestrial_date":"2015-05-18","sol":"988","ls":"343","season":"Month 12","min_temp":"-75","max_temp":"-10","pressure":"840","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:50","local_uv_irradiance_index":"Moderate","min_gts_temp":"-77","max_gts_temp":"8"},{"id":"920","terrestrial_date":"2015-05-17","sol":"987","ls":"343","season":"Month 12","min_temp":"-74","max_temp":"-7","pressure":"839","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:50","local_uv_irradiance_index":"Moderate","min_gts_temp":"-77","max_gts_temp":"9"},{"id":"919","terrestrial_date":"2015-05-16","sol":"986","ls":"342","season":"Month 12","min_temp":"-74","max_temp":"-1","pressure":"840","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:51","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"9"},{"id":"918","terrestrial_date":"2015-05-15","sol":"985","ls":"342","season":"Month 12","min_temp":"-78","max_temp":"-5","pressure":"840","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:51","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"9"},{"id":"915","terrestrial_date":"2015-05-14","sol":"984","ls":"341","season":"Month 12","min_temp":"-74","max_temp":"-6","pressure":"840","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:51","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"11"},{"id":"916","terrestrial_date":"2015-05-13","sol":"983","ls":"340","season":"Month 12","min_temp":"-76","max_temp":"-6","pressure":"840","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:51","local_uv_irradiance_index":"Moderate","min_gts_temp":"-77","max_gts_temp":"12"},{"id":"917","terrestrial_date":"2015-05-12","sol":"982","ls":"340","season":"Month 12","min_temp":"-74","max_temp":"-4","pressure":"840","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:52","local_uv_irradiance_index":"Moderate","min_gts_temp":"-76","max_gts_temp":"7"},{"id":"914","terrestrial_date":"2015-05-11","sol":"981","ls":"339","season":"Month 12","min_temp":"-73","max_temp":"-3","pressure":"841","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:52","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"8"},{"id":"911","terrestrial_date":"2015-05-10","sol":"980","ls":"339","season":"Month 12","min_temp":"-73","max_temp":"1","pressure":"840","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:52","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"11"},{"id":"912","terrestrial_date":"2015-05-09","sol":"979","ls":"338","season":"Month 12","min_temp":"-79","max_temp":"-4","pressure":"841","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:52","local_uv_irradiance_index":"Moderate","min_gts_temp":"-80","max_gts_temp":"11"},{"id":"913","terrestrial_date":"2015-05-07","sol":"978","ls":"338","season":"Month 12","min_temp":"-73","max_temp":"-2","pressure":"842","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:52","local_uv_irradiance_index":"Moderate","min_gts_temp":"-78","max_gts_temp":"10"},{"id":"910","terrestrial_date":"2015-05-06","sol":"977","ls":"337","season":"Month 12","min_temp":"-75","max_temp":"-4","pressure":"841","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:53","local_uv_irradiance_index":"Moderate","min_gts_temp":"-77","max_gts_temp":"10"},{"id":"909","terrestrial_date":"2015-05-05","sol":"976","ls":"337","season":"Month 12","min_temp":"-75","max_temp":"-6","pressure":"842","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:53","local_uv_irradiance_index":"Moderate","min_gts_temp":"-77","max_gts_temp":"10"},{"id":"908","terrestrial_date":"2015-05-04","sol":"975","ls":"336","season":"Month 12","min_temp":"-73","max_temp":"-3","pressure":"843","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:53","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"14"},{"id":"907","terrestrial_date":"2015-05-03","sol":"974","ls":"336","season":"Month 12","min_temp":"-73","max_temp":"-3","pressure":"842","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:53","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"14"},{"id":"905","terrestrial_date":"2015-05-02","sol":"973","ls":"335","season":"Month 12","min_temp":"-72","max_temp":"-4","pressure":"844","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:53","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"16"},{"id":"904","terrestrial_date":"2015-05-01","sol":"972","ls":"334","season":"Month 12","min_temp":"-73","max_temp":"-3","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:53","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"14"},{"id":"906","terrestrial_date":"2015-04-30","sol":"971","ls":"334","season":"Month 12","min_temp":"-71","max_temp":"-3","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"Moderate","min_gts_temp":"-76","max_gts_temp":"14"},{"id":"903","terrestrial_date":"2015-04-29","sol":"970","ls":"333","season":"Month 12","min_temp":"-71","max_temp":"-4","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"11"},{"id":"902","terrestrial_date":"2015-04-28","sol":"969","ls":"333","season":"Month 12","min_temp":"-72","max_temp":"-2","pressure":"844","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"11"},{"id":"901","terrestrial_date":"2015-04-27","sol":"968","ls":"332","season":"Month 12","min_temp":"-71","max_temp":"-3","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"11"},{"id":"899","terrestrial_date":"2015-04-26","sol":"967","ls":"332","season":"Month 12","min_temp":"-74","max_temp":"-2","pressure":"844","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"12"},{"id":"900","terrestrial_date":"2015-04-25","sol":"966","ls":"331","season":"Month 12","min_temp":"-73","max_temp":"-12","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"9"},{"id":"898","terrestrial_date":"2015-04-24","sol":"965","ls":"331","season":"Month 12","min_temp":"-75","max_temp":"-10","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"8"},{"id":"897","terrestrial_date":"2015-04-23","sol":"964","ls":"330","season":"Month 12","min_temp":"-72","max_temp":"-13","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"9"},{"id":"896","terrestrial_date":"2015-04-22","sol":"963","ls":"329","season":"Month 11","min_temp":"-71","max_temp":"-5","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"10"},{"id":"894","terrestrial_date":"2015-04-21","sol":"962","ls":"329","season":"Month 11","min_temp":"-73","max_temp":"-2","pressure":"845","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"11"},{"id":"895","terrestrial_date":"2015-04-20","sol":"961","ls":"328","season":"Month 11","min_temp":"-71","max_temp":"-3","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"11"},{"id":"893","terrestrial_date":"2015-04-19","sol":"960","ls":"328","season":"Month 11","min_temp":"-76","max_temp":"-8","pressure":"846","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-86","max_gts_temp":"15"},{"id":"891","terrestrial_date":"2015-04-18","sol":"959","ls":"327","season":"Month 11","min_temp":"-78","max_temp":"-4","pressure":"846","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"14"},{"id":"892","terrestrial_date":"2015-04-17","sol":"958","ls":"327","season":"Month 11","min_temp":"-74","max_temp":"-9","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"17"},{"id":"890","terrestrial_date":"2015-04-16","sol":"957","ls":"326","season":"Month 11","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"--","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"--","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"889","terrestrial_date":"2015-04-13","sol":"954","ls":"324","season":"Month 11","min_temp":"-73","max_temp":"-3","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"11"},{"id":"887","terrestrial_date":"2015-04-12","sol":"953","ls":"324","season":"Month 11","min_temp":"-71","max_temp":"-5","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"12"},{"id":"886","terrestrial_date":"2015-04-11","sol":"952","ls":"323","season":"Month 11","min_temp":"-69","max_temp":"-6","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"14"},{"id":"888","terrestrial_date":"2015-04-10","sol":"951","ls":"323","season":"Month 11","min_temp":"-75","max_temp":"-4","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"14"},{"id":"885","terrestrial_date":"2015-04-09","sol":"950","ls":"322","season":"Month 11","min_temp":"-73","max_temp":"0","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"13"},{"id":"884","terrestrial_date":"2015-04-08","sol":"949","ls":"321","season":"Month 11","min_temp":"-72","max_temp":"-4","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"9"},{"id":"883","terrestrial_date":"2015-04-07","sol":"948","ls":"321","season":"Month 11","min_temp":"-73","max_temp":"-8","pressure":"854","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"6"},{"id":"882","terrestrial_date":"2015-04-06","sol":"947","ls":"320","season":"Month 11","min_temp":"-70","max_temp":"-3","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"6"},{"id":"879","terrestrial_date":"2015-04-05","sol":"946","ls":"320","season":"Month 11","min_temp":"-77","max_temp":"-2","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"6"},{"id":"881","terrestrial_date":"2015-04-04","sol":"945","ls":"319","season":"Month 11","min_temp":"-72","max_temp":"-1","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"5"},{"id":"878","terrestrial_date":"2015-04-03","sol":"944","ls":"318","season":"Month 11","min_temp":"-70","max_temp":"0","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"8"},{"id":"877","terrestrial_date":"2015-04-02","sol":"943","ls":"318","season":"Month 11","min_temp":"-73","max_temp":"-1","pressure":"854","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"5"},{"id":"880","terrestrial_date":"2015-03-31","sol":"942","ls":"317","season":"Month 11","min_temp":"-74","max_temp":"-1","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"6"},{"id":"875","terrestrial_date":"2015-03-30","sol":"941","ls":"317","season":"Month 11","min_temp":"-74","max_temp":"0","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"6"},{"id":"876","terrestrial_date":"2015-03-29","sol":"940","ls":"316","season":"Month 11","min_temp":"-73","max_temp":"-2","pressure":"861","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:54","local_uv_irradiance_index":"Very_High","min_gts_temp":"-76","max_gts_temp":"8"},{"id":"873","terrestrial_date":"2015-03-28","sol":"939","ls":"316","season":"Month 11","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"--","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"--","sunrise":"06:43","sunset":"18:54","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"874","terrestrial_date":"2015-03-26","sol":"937","ls":"314","season":"Month 11","min_temp":"-73","max_temp":"0","pressure":"863","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:54","local_uv_irradiance_index":"Very_High","min_gts_temp":"-77","max_gts_temp":"10"},{"id":"871","terrestrial_date":"2015-03-25","sol":"936","ls":"314","season":"Month 11","min_temp":"-72","max_temp":"-3","pressure":"865","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:54","local_uv_irradiance_index":"Very_High","min_gts_temp":"-75","max_gts_temp":"9"},{"id":"872","terrestrial_date":"2015-03-24","sol":"935","ls":"313","season":"Month 11","min_temp":"-75","max_temp":"-2","pressure":"862","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:54","local_uv_irradiance_index":"Very_High","min_gts_temp":"-74","max_gts_temp":"10"},{"id":"870","terrestrial_date":"2015-03-23","sol":"934","ls":"313","season":"Month 11","min_temp":"-73","max_temp":"1","pressure":"858","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:54","local_uv_irradiance_index":"Very_High","min_gts_temp":"-75","max_gts_temp":"9"},{"id":"869","terrestrial_date":"2015-03-22","sol":"933","ls":"312","season":"Month 11","min_temp":"-71","max_temp":"-4","pressure":"863","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:54","local_uv_irradiance_index":"Very_High","min_gts_temp":"-75","max_gts_temp":"11"},{"id":"866","terrestrial_date":"2015-03-21","sol":"932","ls":"311","season":"Month 11","min_temp":"-71","max_temp":"1","pressure":"859","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:53","local_uv_irradiance_index":"Very_High","min_gts_temp":"-75","max_gts_temp":"10"},{"id":"867","terrestrial_date":"2015-03-20","sol":"931","ls":"311","season":"Month 11","min_temp":"-69","max_temp":"-1","pressure":"864","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:53","local_uv_irradiance_index":"Very_High","min_gts_temp":"-76","max_gts_temp":"10"},{"id":"868","terrestrial_date":"2015-03-19","sol":"930","ls":"310","season":"Month 11","min_temp":"-75","max_temp":"-1","pressure":"865","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:53","local_uv_irradiance_index":"Very_High","min_gts_temp":"-78","max_gts_temp":"10"},{"id":"865","terrestrial_date":"2015-03-18","sol":"929","ls":"310","season":"Month 11","min_temp":"-75","max_temp":"0","pressure":"866","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:53","local_uv_irradiance_index":"Very_High","min_gts_temp":"-76","max_gts_temp":"11"},{"id":"864","terrestrial_date":"2015-03-17","sol":"928","ls":"309","season":"Month 11","min_temp":"-72","max_temp":"0","pressure":"862","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:53","local_uv_irradiance_index":"Very_High","min_gts_temp":"-74","max_gts_temp":"9"},{"id":"863","terrestrial_date":"2015-03-16","sol":"927","ls":"308","season":"Month 11","min_temp":"-76","max_temp":"-2","pressure":"862","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:39","sunset":"18:52","local_uv_irradiance_index":"Very_High","min_gts_temp":"-75","max_gts_temp":"11"},{"id":"862","terrestrial_date":"2015-03-15","sol":"926","ls":"308","season":"Month 11","min_temp":"-76","max_temp":"1","pressure":"864","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:39","sunset":"18:52","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"10"},{"id":"860","terrestrial_date":"2015-03-14","sol":"925","ls":"307","season":"Month 11","min_temp":"-71","max_temp":"-2","pressure":"862","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:38","sunset":"18:52","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"9"},{"id":"861","terrestrial_date":"2015-03-13","sol":"924","ls":"307","season":"Month 11","min_temp":"-74","max_temp":"-1","pressure":"867","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:38","sunset":"18:52","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"10"},{"id":"859","terrestrial_date":"2015-03-12","sol":"923","ls":"306","season":"Month 11","min_temp":"-72","max_temp":"-5","pressure":"867","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:38","sunset":"18:51","local_uv_irradiance_index":"Very_High","min_gts_temp":"-74","max_gts_temp":"14"},{"id":"858","terrestrial_date":"2015-03-11","sol":"922","ls":"305","season":"Month 11","min_temp":"-73","max_temp":"-2","pressure":"870","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:37","sunset":"18:51","local_uv_irradiance_index":"Very_High","min_gts_temp":"-75","max_gts_temp":"9"},{"id":"857","terrestrial_date":"2015-03-10","sol":"921","ls":"305","season":"Month 11","min_temp":"-70","max_temp":"2","pressure":"867","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:37","sunset":"18:51","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"9"},{"id":"856","terrestrial_date":"2015-03-09","sol":"920","ls":"304","season":"Month 11","min_temp":"-72","max_temp":"-2","pressure":"868","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:37","sunset":"18:51","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"9"},{"id":"855","terrestrial_date":"2015-03-08","sol":"919","ls":"304","season":"Month 11","min_temp":"-74","max_temp":"-3","pressure":"870","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:36","sunset":"18:50","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"9"},{"id":"853","terrestrial_date":"2015-03-07","sol":"918","ls":"303","season":"Month 11","min_temp":"-71","max_temp":"0","pressure":"867","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:36","sunset":"18:50","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"9"},{"id":"854","terrestrial_date":"2015-03-06","sol":"917","ls":"302","season":"Month 11","min_temp":"-76","max_temp":"-1","pressure":"871","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:35","sunset":"18:50","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"9"},{"id":"852","terrestrial_date":"2015-03-05","sol":"916","ls":"302","season":"Month 11","min_temp":"-71","max_temp":"-5","pressure":"872","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:35","sunset":"18:49","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"9"},{"id":"851","terrestrial_date":"2015-03-04","sol":"915","ls":"301","season":"Month 11","min_temp":"-71","max_temp":"-4","pressure":"878","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:34","sunset":"18:49","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"9"},{"id":"850","terrestrial_date":"2015-03-03","sol":"914","ls":"300","season":"Month 11","min_temp":"-71","max_temp":"0","pressure":"874","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:34","sunset":"18:49","local_uv_irradiance_index":"High","min_gts_temp":"-60","max_gts_temp":"8"},{"id":"848","terrestrial_date":"2015-03-02","sol":"913","ls":"300","season":"Month 11","min_temp":"-71","max_temp":"-4","pressure":"871","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:33","sunset":"18:48","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"10"},{"id":"849","terrestrial_date":"2015-03-01","sol":"912","ls":"299","season":"Month 10","min_temp":"-75","max_temp":"-4","pressure":"875","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:33","sunset":"18:48","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"8"},{"id":"846","terrestrial_date":"2015-02-28","sol":"911","ls":"299","season":"Month 10","min_temp":"-70","max_temp":"0","pressure":"874","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:33","sunset":"18:48","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"8"},{"id":"847","terrestrial_date":"2015-02-27","sol":"910","ls":"298","season":"Month 10","min_temp":"-73","max_temp":"0","pressure":"878","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:32","sunset":"18:47","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"9"},{"id":"845","terrestrial_date":"2015-02-26","sol":"909","ls":"297","season":"Month 10","min_temp":"-70","max_temp":"-2","pressure":"878","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:32","sunset":"18:47","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"8"},{"id":"844","terrestrial_date":"2015-02-25","sol":"908","ls":"297","season":"Month 10","min_temp":"-71","max_temp":"-3","pressure":"883","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:31","sunset":"18:46","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"8"},{"id":"842","terrestrial_date":"2015-02-24","sol":"907","ls":"296","season":"Month 10","min_temp":"-75","max_temp":"-1","pressure":"879","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:31","sunset":"18:46","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"8"},{"id":"843","terrestrial_date":"2015-02-22","sol":"906","ls":"296","season":"Month 10","min_temp":"-76","max_temp":"-3","pressure":"878","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:30","sunset":"18:46","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"9"},{"id":"840","terrestrial_date":"2015-02-21","sol":"905","ls":"295","season":"Month 10","min_temp":"-71","max_temp":"-2","pressure":"880","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:29","sunset":"18:45","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"8"},{"id":"841","terrestrial_date":"2015-02-20","sol":"904","ls":"294","season":"Month 10","min_temp":"-71","max_temp":"0","pressure":"878","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:29","sunset":"18:45","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"8"},{"id":"839","terrestrial_date":"2015-02-19","sol":"903","ls":"294","season":"Month 10","min_temp":"-71","max_temp":"-2","pressure":"882","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:28","sunset":"18:44","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"6"},{"id":"838","terrestrial_date":"2015-02-18","sol":"902","ls":"293","season":"Month 10","min_temp":"-68","max_temp":"0","pressure":"883","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:28","sunset":"18:44","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"5"},{"id":"837","terrestrial_date":"2015-02-17","sol":"901","ls":"292","season":"Month 10","min_temp":"-71","max_temp":"-2","pressure":"885","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:27","sunset":"18:43","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"11"},{"id":"836","terrestrial_date":"2015-02-16","sol":"900","ls":"292","season":"Month 10","min_temp":"-70","max_temp":"1","pressure":"883","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:27","sunset":"18:43","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"7"},{"id":"835","terrestrial_date":"2015-02-15","sol":"899","ls":"291","season":"Month 10","min_temp":"-75","max_temp":"-1","pressure":"881","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:26","sunset":"18:42","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"7"},{"id":"834","terrestrial_date":"2015-02-14","sol":"898","ls":"291","season":"Month 10","min_temp":"-72","max_temp":"2","pressure":"883","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:26","sunset":"18:42","local_uv_irradiance_index":"Very_High","min_gts_temp":"-75","max_gts_temp":"7"},{"id":"832","terrestrial_date":"2015-02-13","sol":"897","ls":"290","season":"Month 10","min_temp":"-72","max_temp":"5","pressure":"884","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:25","sunset":"18:41","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"7"},{"id":"833","terrestrial_date":"2015-02-12","sol":"896","ls":"289","season":"Month 10","min_temp":"-70","max_temp":"1","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:24","sunset":"18:41","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"8"},{"id":"831","terrestrial_date":"2015-02-11","sol":"895","ls":"289","season":"Month 10","min_temp":"-72","max_temp":"-4","pressure":"889","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:24","sunset":"18:40","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"5"},{"id":"830","terrestrial_date":"2015-02-10","sol":"894","ls":"288","season":"Month 10","min_temp":"-75","max_temp":"-4","pressure":"891","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:23","sunset":"18:40","local_uv_irradiance_index":"Moderate","min_gts_temp":"-74","max_gts_temp":"4"},{"id":"829","terrestrial_date":"2015-02-09","sol":"893","ls":"287","season":"Month 10","min_temp":"-72","max_temp":"2","pressure":"890","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:23","sunset":"18:39","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"4"},{"id":"828","terrestrial_date":"2015-02-08","sol":"892","ls":"287","season":"Month 10","min_temp":"-71","max_temp":"-3","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:22","sunset":"18:39","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"5"},{"id":"827","terrestrial_date":"2015-02-07","sol":"891","ls":"286","season":"Month 10","min_temp":"-72","max_temp":"-3","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:21","sunset":"18:38","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"5"},{"id":"826","terrestrial_date":"2015-02-06","sol":"890","ls":"286","season":"Month 10","min_temp":"-72","max_temp":"-4","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:21","sunset":"18:38","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"5"},{"id":"825","terrestrial_date":"2015-02-05","sol":"889","ls":"285","season":"Month 10","min_temp":"-70","max_temp":"2","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:20","sunset":"18:37","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"4"},{"id":"824","terrestrial_date":"2015-02-04","sol":"888","ls":"284","season":"Month 10","min_temp":"-70","max_temp":"-5","pressure":"896","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:20","sunset":"18:37","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"3"},{"id":"822","terrestrial_date":"2015-02-03","sol":"887","ls":"284","season":"Month 10","min_temp":"-73","max_temp":"-4","pressure":"897","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:19","sunset":"18:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"5"},{"id":"823","terrestrial_date":"2015-02-02","sol":"886","ls":"283","season":"Month 10","min_temp":"-73","max_temp":"-6","pressure":"894","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:18","sunset":"18:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"4"},{"id":"819","terrestrial_date":"2015-02-01","sol":"885","ls":"282","season":"Month 10","min_temp":"-71","max_temp":"-4","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:18","sunset":"18:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"4"},{"id":"821","terrestrial_date":"2015-01-31","sol":"884","ls":"282","season":"Month 10","min_temp":"-71","max_temp":"-5","pressure":"897","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:17","sunset":"18:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-74","max_gts_temp":"5"},{"id":"820","terrestrial_date":"2015-01-30","sol":"883","ls":"281","season":"Month 10","min_temp":"-74","max_temp":"-4","pressure":"897","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:16","sunset":"18:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-74","max_gts_temp":"3"},{"id":"818","terrestrial_date":"2015-01-29","sol":"882","ls":"280","season":"Month 10","min_temp":"-76","max_temp":"-6","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:16","sunset":"18:33","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"3"},{"id":"817","terrestrial_date":"2015-01-28","sol":"881","ls":"280","season":"Month 10","min_temp":"-73","max_temp":"-4","pressure":"899","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:15","sunset":"18:32","local_uv_irradiance_index":"Moderate","min_gts_temp":"-74","max_gts_temp":"4"},{"id":"816","terrestrial_date":"2015-01-27","sol":"880","ls":"279","season":"Month 10","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"--","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"--","sunrise":"06:14","sunset":"18:32","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"815","terrestrial_date":"2015-01-19","sol":"872","ls":"274","season":"Month 10","min_temp":"-72","max_temp":"1","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:09","sunset":"18:27","local_uv_irradiance_index":"Moderate","min_gts_temp":"-72","max_gts_temp":"5"},{"id":"814","terrestrial_date":"2015-01-18","sol":"871","ls":"273","season":"Month 10","min_temp":"-70","max_temp":"-7","pressure":"903","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:08","sunset":"18:26","local_uv_irradiance_index":"Moderate","min_gts_temp":"-60","max_gts_temp":"3"},{"id":"813","terrestrial_date":"2015-01-17","sol":"870","ls":"273","season":"Month 10","min_temp":"-74","max_temp":"-6","pressure":"909","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:07","sunset":"18:25","local_uv_irradiance_index":"Moderate","min_gts_temp":"-75","max_gts_temp":"4"},{"id":"812","terrestrial_date":"2015-01-15","sol":"869","ls":"272","season":"Month 10","min_temp":"-72","max_temp":"-4","pressure":"906","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:07","sunset":"18:25","local_uv_irradiance_index":"Moderate","min_gts_temp":"-72","max_gts_temp":"5"},{"id":"811","terrestrial_date":"2015-01-14","sol":"868","ls":"271","season":"Month 10","min_temp":"-71","max_temp":"-4","pressure":"908","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:06","sunset":"18:24","local_uv_irradiance_index":"Moderate","min_gts_temp":"-71","max_gts_temp":"3"},{"id":"810","terrestrial_date":"2015-01-13","sol":"867","ls":"271","season":"Month 10","min_temp":"-71","max_temp":"-2","pressure":"910","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:05","sunset":"18:23","local_uv_irradiance_index":"Moderate","min_gts_temp":"-72","max_gts_temp":"4"},{"id":"809","terrestrial_date":"2015-01-12","sol":"866","ls":"270","season":"Month 10","min_temp":"-71","max_temp":"-4","pressure":"911","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:05","sunset":"18:22","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"4"},{"id":"808","terrestrial_date":"2015-01-11","sol":"865","ls":"270","season":"Month 10","min_temp":"-70","max_temp":"-5","pressure":"913","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:04","sunset":"18:22","local_uv_irradiance_index":"Moderate","min_gts_temp":"-75","max_gts_temp":"4"},{"id":"806","terrestrial_date":"2015-01-10","sol":"864","ls":"269","season":"Month 9","min_temp":"-70","max_temp":"-1","pressure":"914","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:03","sunset":"18:21","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"3"},{"id":"805","terrestrial_date":"2015-01-09","sol":"863","ls":"268","season":"Month 9","min_temp":"-72","max_temp":"-13","pressure":"916","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:02","sunset":"18:20","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"3"},{"id":"807","terrestrial_date":"2015-01-08","sol":"862","ls":"268","season":"Month 9","min_temp":"-70","max_temp":"-2","pressure":"917","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:02","sunset":"18:20","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"11"},{"id":"804","terrestrial_date":"2015-01-07","sol":"861","ls":"267","season":"Month 9","min_temp":"-70","max_temp":"-7","pressure":"917","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:01","sunset":"18:19","local_uv_irradiance_index":"Moderate","min_gts_temp":"-71","max_gts_temp":"3"},{"id":"803","terrestrial_date":"2015-01-06","sol":"860","ls":"266","season":"Month 9","min_temp":"-69","max_temp":"-8","pressure":"916","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"18:18","local_uv_irradiance_index":"Moderate","min_gts_temp":"-71","max_gts_temp":"3"},{"id":"802","terrestrial_date":"2015-01-05","sol":"859","ls":"266","season":"Month 9","min_temp":"-72","max_temp":"-8","pressure":"915","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"18:18","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"3"},{"id":"800","terrestrial_date":"2015-01-04","sol":"858","ls":"265","season":"Month 9","min_temp":"-73","max_temp":"-6","pressure":"913","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:59","sunset":"18:17","local_uv_irradiance_index":"Moderate","min_gts_temp":"-72","max_gts_temp":"4"},{"id":"801","terrestrial_date":"2015-01-03","sol":"857","ls":"264","season":"Month 9","min_temp":"-76","max_temp":"0","pressure":"911","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"18:16","local_uv_irradiance_index":"Moderate","min_gts_temp":"-72","max_gts_temp":"3"},{"id":"795","terrestrial_date":"2015-01-02","sol":"856","ls":"264","season":"Month 9","min_temp":"-68","max_temp":"-3","pressure":"912","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"18:15","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"3"},{"id":"799","terrestrial_date":"2015-01-01","sol":"855","ls":"263","season":"Month 9","min_temp":"-69","max_temp":"0","pressure":"912","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"18:15","local_uv_irradiance_index":"Low","min_gts_temp":"-70","max_gts_temp":"3"},{"id":"798","terrestrial_date":"2014-12-31","sol":"854","ls":"262","season":"Month 9","min_temp":"-66","max_temp":"3","pressure":"910","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"18:14","local_uv_irradiance_index":"Low","min_gts_temp":"-70","max_gts_temp":"2"},{"id":"796","terrestrial_date":"2014-12-30","sol":"853","ls":"262","season":"Month 9","min_temp":"-67","max_temp":"0","pressure":"913","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"18:13","local_uv_irradiance_index":"Low","min_gts_temp":"-69","max_gts_temp":"2"},{"id":"797","terrestrial_date":"2014-12-29","sol":"852","ls":"261","season":"Month 9","min_temp":"-73","max_temp":"-3","pressure":"916","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"18:12","local_uv_irradiance_index":"Moderate","min_gts_temp":"-72","max_gts_temp":"4"},{"id":"794","terrestrial_date":"2014-12-28","sol":"851","ls":"260","season":"Month 9","min_temp":"-68","max_temp":"-6","pressure":"919","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"18:12","local_uv_irradiance_index":"Low","min_gts_temp":"-71","max_gts_temp":"2"},{"id":"789","terrestrial_date":"2014-12-27","sol":"850","ls":"260","season":"Month 9","min_temp":"-68","max_temp":"-1","pressure":"918","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"18:11","local_uv_irradiance_index":"Low","min_gts_temp":"-70","max_gts_temp":"2"},{"id":"787","terrestrial_date":"2014-12-26","sol":"849","ls":"259","season":"Month 9","min_temp":"-69","max_temp":"-1","pressure":"918","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"18:10","local_uv_irradiance_index":"Moderate","min_gts_temp":"-72","max_gts_temp":"2"},{"id":"792","terrestrial_date":"2014-12-25","sol":"848","ls":"258","season":"Month 9","min_temp":"-69","max_temp":"-4","pressure":"918","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"18:10","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"3"},{"id":"791","terrestrial_date":"2014-12-24","sol":"847","ls":"258","season":"Month 9","min_temp":"-69","max_temp":"-8","pressure":"918","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"18:09","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"4"},{"id":"785","terrestrial_date":"2014-12-23","sol":"846","ls":"257","season":"Month 9","min_temp":"-74","max_temp":"-7","pressure":"925","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"18:08","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"3"},{"id":"786","terrestrial_date":"2014-12-22","sol":"845","ls":"257","season":"Month 9","min_temp":"-73","max_temp":"0","pressure":"920","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:50","sunset":"18:07","local_uv_irradiance_index":"Moderate","min_gts_temp":"-71","max_gts_temp":"3"},{"id":"788","terrestrial_date":"2014-12-21","sol":"844","ls":"256","season":"Month 9","min_temp":"-68","max_temp":"5","pressure":"917","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:49","sunset":"18:07","local_uv_irradiance_index":"Low","min_gts_temp":"-70","max_gts_temp":"3"},{"id":"793","terrestrial_date":"2014-12-20","sol":"843","ls":"255","season":"Month 9","min_temp":"-69","max_temp":"1","pressure":"916","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:49","sunset":"18:06","local_uv_irradiance_index":"Low","min_gts_temp":"-72","max_gts_temp":"4"},{"id":"790","terrestrial_date":"2014-12-19","sol":"842","ls":"255","season":"Month 9","min_temp":"-69","max_temp":"-6","pressure":"914","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:48","sunset":"18:05","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"5"},{"id":"784","terrestrial_date":"2014-12-18","sol":"841","ls":"254","season":"Month 9","min_temp":"-75","max_temp":"-7","pressure":"914","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:47","sunset":"18:04","local_uv_irradiance_index":"Low","min_gts_temp":"-71","max_gts_temp":"5"},{"id":"783","terrestrial_date":"2014-12-17","sol":"840","ls":"253","season":"Month 9","min_temp":"-74","max_temp":"-4","pressure":"913","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:47","sunset":"18:04","local_uv_irradiance_index":"Low","min_gts_temp":"-71","max_gts_temp":"3"},{"id":"781","terrestrial_date":"2014-12-16","sol":"839","ls":"253","season":"Month 9","min_temp":"-70","max_temp":"-1","pressure":"917","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:46","sunset":"18:03","local_uv_irradiance_index":"Low","min_gts_temp":"-70","max_gts_temp":"2"},{"id":"782","terrestrial_date":"2014-12-15","sol":"838","ls":"252","season":"Month 9","min_temp":"-69","max_temp":"-1","pressure":"917","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:45","sunset":"18:02","local_uv_irradiance_index":"Low","min_gts_temp":"-70","max_gts_temp":"4"},{"id":"779","terrestrial_date":"2014-12-14","sol":"837","ls":"251","season":"Month 9","min_temp":"-69","max_temp":"4","pressure":"916","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:45","sunset":"18:02","local_uv_irradiance_index":"Moderate","min_gts_temp":"-71","max_gts_temp":"6"},{"id":"778","terrestrial_date":"2014-12-13","sol":"836","ls":"251","season":"Month 9","min_temp":"-69","max_temp":"-1","pressure":"916","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:44","sunset":"18:01","local_uv_irradiance_index":"Moderate","min_gts_temp":"-72","max_gts_temp":"5"},{"id":"780","terrestrial_date":"2014-12-12","sol":"835","ls":"250","season":"Month 9","min_temp":"-69","max_temp":"-1","pressure":"917","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:44","sunset":"18:00","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"4"},{"id":"777","terrestrial_date":"2014-12-11","sol":"834","ls":"249","season":"Month 9","min_temp":"-68","max_temp":"-3","pressure":"918","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:43","sunset":"18:00","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"4"},{"id":"776","terrestrial_date":"2014-12-09","sol":"833","ls":"249","season":"Month 9","min_temp":"-69","max_temp":"-1","pressure":"923","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:42","sunset":"17:59","local_uv_irradiance_index":"Moderate","min_gts_temp":"-72","max_gts_temp":"4"},{"id":"775","terrestrial_date":"2014-12-08","sol":"832","ls":"248","season":"Month 9","min_temp":"-68","max_temp":"-2","pressure":"924","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:42","sunset":"17:58","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"4"},{"id":"774","terrestrial_date":"2014-12-07","sol":"831","ls":"247","season":"Month 9","min_temp":"-68","max_temp":"-6","pressure":"920","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:41","sunset":"17:57","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"3"},{"id":"772","terrestrial_date":"2014-12-06","sol":"830","ls":"247","season":"Month 9","min_temp":"-68","max_temp":"-1","pressure":"918","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:41","sunset":"17:57","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"3"},{"id":"773","terrestrial_date":"2014-12-05","sol":"829","ls":"246","season":"Month 9","min_temp":"-71","max_temp":"-2","pressure":"914","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:40","sunset":"17:56","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"3"},{"id":"771","terrestrial_date":"2014-12-04","sol":"828","ls":"245","season":"Month 9","min_temp":"-71","max_temp":"-1","pressure":"914","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:39","sunset":"17:55","local_uv_irradiance_index":"Moderate","min_gts_temp":"-69","max_gts_temp":"3"},{"id":"769","terrestrial_date":"2014-12-03","sol":"827","ls":"245","season":"Month 9","min_temp":"-68","max_temp":"0","pressure":"911","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:39","sunset":"17:55","local_uv_irradiance_index":"Moderate","min_gts_temp":"-68","max_gts_temp":"2"},{"id":"770","terrestrial_date":"2014-12-02","sol":"826","ls":"244","season":"Month 9","min_temp":"-68","max_temp":"0","pressure":"914","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:38","sunset":"17:54","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"3"},{"id":"767","terrestrial_date":"2014-12-01","sol":"825","ls":"243","season":"Month 9","min_temp":"-67","max_temp":"1","pressure":"914","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:38","sunset":"17:53","local_uv_irradiance_index":"Moderate","min_gts_temp":"-69","max_gts_temp":"3"},{"id":"768","terrestrial_date":"2014-11-30","sol":"824","ls":"243","season":"Month 9","min_temp":"-67","max_temp":"2","pressure":"914","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:37","sunset":"17:53","local_uv_irradiance_index":"Moderate","min_gts_temp":"-69","max_gts_temp":"2"},{"id":"766","terrestrial_date":"2014-11-29","sol":"823","ls":"242","season":"Month 9","min_temp":"-69","max_temp":"0","pressure":"912","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:37","sunset":"17:52","local_uv_irradiance_index":"Moderate","min_gts_temp":"-71","max_gts_temp":"2"},{"id":"764","terrestrial_date":"2014-11-28","sol":"822","ls":"242","season":"Month 9","min_temp":"-71","max_temp":"1","pressure":"911","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:36","sunset":"17:51","local_uv_irradiance_index":"Moderate","min_gts_temp":"-71","max_gts_temp":"3"},{"id":"762","terrestrial_date":"2014-11-27","sol":"821","ls":"241","season":"Month 9","min_temp":"-68","max_temp":"2","pressure":"910","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:35","sunset":"17:51","local_uv_irradiance_index":"Moderate","min_gts_temp":"-69","max_gts_temp":"1"},{"id":"765","terrestrial_date":"2014-11-26","sol":"820","ls":"240","season":"Month 9","min_temp":"-68","max_temp":"-1","pressure":"910","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:35","sunset":"17:50","local_uv_irradiance_index":"Moderate","min_gts_temp":"-69","max_gts_temp":"2"},{"id":"763","terrestrial_date":"2014-11-25","sol":"819","ls":"240","season":"Month 9","min_temp":"-71","max_temp":"0","pressure":"913","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:34","sunset":"17:50","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"4"},{"id":"760","terrestrial_date":"2014-11-24","sol":"818","ls":"239","season":"Month 8","min_temp":"-68","max_temp":"0","pressure":"914","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:34","sunset":"17:49","local_uv_irradiance_index":"Moderate","min_gts_temp":"-72","max_gts_temp":"4"},{"id":"761","terrestrial_date":"2014-11-23","sol":"817","ls":"238","season":"Month 8","min_temp":"-69","max_temp":"0","pressure":"913","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:33","sunset":"17:48","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"2"},{"id":"758","terrestrial_date":"2014-11-22","sol":"816","ls":"238","season":"Month 8","min_temp":"-74","max_temp":"-7","pressure":"909","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:33","sunset":"17:48","local_uv_irradiance_index":"Moderate","min_gts_temp":"-69","max_gts_temp":"3"},{"id":"759","terrestrial_date":"2014-11-21","sol":"815","ls":"237","season":"Month 8","min_temp":"-69","max_temp":"-8","pressure":"905","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:32","sunset":"17:47","local_uv_irradiance_index":"Moderate","min_gts_temp":"-69","max_gts_temp":"3"},{"id":"757","terrestrial_date":"2014-11-20","sol":"814","ls":"236","season":"Month 8","min_temp":"-68","max_temp":"-3","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:32","sunset":"17:46","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"3"},{"id":"756","terrestrial_date":"2014-11-19","sol":"813","ls":"236","season":"Month 8","min_temp":"-67","max_temp":"2","pressure":"904","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:31","sunset":"17:46","local_uv_irradiance_index":"Moderate","min_gts_temp":"-69","max_gts_temp":"2"},{"id":"755","terrestrial_date":"2014-11-18","sol":"812","ls":"235","season":"Month 8","min_temp":"-75","max_temp":"3","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:31","sunset":"17:45","local_uv_irradiance_index":"Moderate","min_gts_temp":"-72","max_gts_temp":"4"},{"id":"754","terrestrial_date":"2014-11-17","sol":"811","ls":"234","season":"Month 8","min_temp":"-71","max_temp":"-6","pressure":"900","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:30","sunset":"17:45","local_uv_irradiance_index":"Moderate","min_gts_temp":"-71","max_gts_temp":"4"},{"id":"751","terrestrial_date":"2014-11-16","sol":"810","ls":"234","season":"Month 8","min_temp":"-69","max_temp":"3","pressure":"897","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:30","sunset":"17:44","local_uv_irradiance_index":"Moderate","min_gts_temp":"-71","max_gts_temp":"3"},{"id":"753","terrestrial_date":"2014-11-15","sol":"809","ls":"233","season":"Month 8","min_temp":"-70","max_temp":"-2","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:30","sunset":"17:43","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"4"},{"id":"752","terrestrial_date":"2014-11-14","sol":"808","ls":"232","season":"Month 8","min_temp":"-67","max_temp":"7","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:29","sunset":"17:43","local_uv_irradiance_index":"Moderate","min_gts_temp":"-71","max_gts_temp":"3"},{"id":"749","terrestrial_date":"2014-11-13","sol":"807","ls":"232","season":"Month 8","min_temp":"-71","max_temp":"1","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:29","sunset":"17:42","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"11"},{"id":"750","terrestrial_date":"2014-11-12","sol":"806","ls":"231","season":"Month 8","min_temp":"-69","max_temp":"2","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:42","local_uv_irradiance_index":"Moderate","min_gts_temp":"-75","max_gts_temp":"12"},{"id":"748","terrestrial_date":"2014-11-11","sol":"805","ls":"231","season":"Month 8","min_temp":"-70","max_temp":"1","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:41","local_uv_irradiance_index":"Moderate","min_gts_temp":"-75","max_gts_temp":"12"},{"id":"747","terrestrial_date":"2014-11-10","sol":"804","ls":"230","season":"Month 8","min_temp":"-73","max_temp":"0","pressure":"891","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:41","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"12"},{"id":"744","terrestrial_date":"2014-11-09","sol":"803","ls":"229","season":"Month 8","min_temp":"-69","max_temp":"0","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:27","sunset":"17:40","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"13"},{"id":"745","terrestrial_date":"2014-11-08","sol":"802","ls":"229","season":"Month 8","min_temp":"-69","max_temp":"7","pressure":"887","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:27","sunset":"17:40","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"13"},{"id":"746","terrestrial_date":"2014-11-07","sol":"801","ls":"228","season":"Month 8","min_temp":"-70","max_temp":"3","pressure":"884","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:39","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"13"},{"id":"742","terrestrial_date":"2014-11-06","sol":"800","ls":"227","season":"Month 8","min_temp":"-67","max_temp":"-2","pressure":"884","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:39","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"13"},{"id":"743","terrestrial_date":"2014-11-05","sol":"799","ls":"227","season":"Month 8","min_temp":"-70","max_temp":"-4","pressure":"884","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:38","local_uv_irradiance_index":"Moderate","min_gts_temp":"-74","max_gts_temp":"14"},{"id":"741","terrestrial_date":"2014-11-04","sol":"798","ls":"226","season":"Month 8","min_temp":"-67","max_temp":"0","pressure":"883","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:38","local_uv_irradiance_index":"Moderate","min_gts_temp":"-72","max_gts_temp":"10"},{"id":"740","terrestrial_date":"2014-11-03","sol":"797","ls":"225","season":"Month 8","min_temp":"-65","max_temp":"-1","pressure":"879","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-67","max_gts_temp":"11"},{"id":"737","terrestrial_date":"2014-11-01","sol":"796","ls":"225","season":"Month 8","min_temp":"-65","max_temp":"1","pressure":"877","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-67","max_gts_temp":"5"},{"id":"738","terrestrial_date":"2014-10-31","sol":"795","ls":"224","season":"Month 8","min_temp":"-68","max_temp":"1","pressure":"875","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-68","max_gts_temp":"6"},{"id":"739","terrestrial_date":"2014-10-30","sol":"794","ls":"223","season":"Month 8","min_temp":"-68","max_temp":"-5","pressure":"874","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-68","max_gts_temp":"6"},{"id":"736","terrestrial_date":"2014-10-29","sol":"793","ls":"223","season":"Month 8","min_temp":"-71","max_temp":"0","pressure":"877","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-69","max_gts_temp":"4"},{"id":"735","terrestrial_date":"2014-10-28","sol":"792","ls":"222","season":"Month 8","min_temp":"-71","max_temp":"0","pressure":"873","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-69","max_gts_temp":"3"},{"id":"734","terrestrial_date":"2014-10-27","sol":"791","ls":"222","season":"Month 8","min_temp":"-70","max_temp":"0","pressure":"867","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"4"},{"id":"733","terrestrial_date":"2014-10-26","sol":"790","ls":"221","season":"Month 8","min_temp":"-68","max_temp":"2","pressure":"864","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-69","max_gts_temp":"7"},{"id":"730","terrestrial_date":"2014-10-25","sol":"789","ls":"220","season":"Month 8","min_temp":"-68","max_temp":"-4","pressure":"862","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:33","local_uv_irradiance_index":"Moderate","min_gts_temp":"-69","max_gts_temp":"5"},{"id":"731","terrestrial_date":"2014-10-24","sol":"788","ls":"220","season":"Month 8","min_temp":"-68","max_temp":"-5","pressure":"862","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:33","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"5"},{"id":"732","terrestrial_date":"2014-10-23","sol":"787","ls":"219","season":"Month 8","min_temp":"-73","max_temp":"-7","pressure":"860","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:33","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"5"},{"id":"729","terrestrial_date":"2014-10-22","sol":"786","ls":"218","season":"Month 8","min_temp":"-74","max_temp":"-4","pressure":"861","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:32","local_uv_irradiance_index":"Moderate","min_gts_temp":"-69","max_gts_temp":"5"},{"id":"728","terrestrial_date":"2014-10-21","sol":"785","ls":"218","season":"Month 8","min_temp":"-74","max_temp":"-1","pressure":"858","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:32","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"6"},{"id":"726","terrestrial_date":"2014-10-20","sol":"784","ls":"217","season":"Month 8","min_temp":"-69","max_temp":"-4","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"9"},{"id":"727","terrestrial_date":"2014-10-19","sol":"783","ls":"216","season":"Month 8","min_temp":"-69","max_temp":"6","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"8"},{"id":"724","terrestrial_date":"2014-10-18","sol":"782","ls":"216","season":"Month 8","min_temp":"-71","max_temp":"9","pressure":"854","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-70","max_gts_temp":"8"},{"id":"725","terrestrial_date":"2014-10-17","sol":"781","ls":"215","season":"Month 8","min_temp":"-74","max_temp":"-5","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:30","local_uv_irradiance_index":"Moderate","min_gts_temp":"-73","max_gts_temp":"9"},{"id":"723","terrestrial_date":"2014-10-16","sol":"780","ls":"215","season":"Month 8","min_temp":"-72","max_temp":"0","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:30","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"14"},{"id":"722","terrestrial_date":"2014-10-15","sol":"779","ls":"214","season":"Month 8","min_temp":"-71","max_temp":"6","pressure":"845","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:30","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"14"},{"id":"721","terrestrial_date":"2014-10-14","sol":"778","ls":"213","season":"Month 8","min_temp":"-70","max_temp":"6","pressure":"846","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:29","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"13"},{"id":"720","terrestrial_date":"2014-10-13","sol":"777","ls":"213","season":"Month 8","min_temp":"-72","max_temp":"8","pressure":"841","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:29","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"14"},{"id":"718","terrestrial_date":"2014-10-12","sol":"776","ls":"212","season":"Month 8","min_temp":"-72","max_temp":"5","pressure":"841","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:29","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"13"},{"id":"717","terrestrial_date":"2014-10-11","sol":"775","ls":"211","season":"Month 8","min_temp":"-71","max_temp":"3","pressure":"838","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:28","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"14"},{"id":"719","terrestrial_date":"2014-10-10","sol":"774","ls":"211","season":"Month 8","min_temp":"-73","max_temp":"1","pressure":"838","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:28","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"14"},{"id":"716","terrestrial_date":"2014-10-09","sol":"773","ls":"210","season":"Month 8","min_temp":"-70","max_temp":"8","pressure":"838","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:28","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"14"},{"id":"715","terrestrial_date":"2014-10-08","sol":"772","ls":"210","season":"Month 8","min_temp":"-71","max_temp":"8","pressure":"835","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:27","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"13"},{"id":"714","terrestrial_date":"2014-10-07","sol":"771","ls":"209","season":"Month 7","min_temp":"-71","max_temp":"9","pressure":"836","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:27","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"14"},{"id":"713","terrestrial_date":"2014-10-06","sol":"770","ls":"208","season":"Month 7","min_temp":"-70","max_temp":"2","pressure":"829","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:27","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"14"},{"id":"711","terrestrial_date":"2014-10-05","sol":"769","ls":"208","season":"Month 7","min_temp":"-73","max_temp":"4","pressure":"829","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:26","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"15"},{"id":"712","terrestrial_date":"2014-10-04","sol":"768","ls":"207","season":"Month 7","min_temp":"-73","max_temp":"2","pressure":"826","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:26","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"14"},{"id":"710","terrestrial_date":"2014-10-03","sol":"767","ls":"206","season":"Month 7","min_temp":"-71","max_temp":"9","pressure":"824","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:26","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"14"},{"id":"709","terrestrial_date":"2014-10-02","sol":"766","ls":"206","season":"Month 7","min_temp":"-70","max_temp":"8","pressure":"824","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:26","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"14"},{"id":"708","terrestrial_date":"2014-10-01","sol":"765","ls":"205","season":"Month 7","min_temp":"-73","max_temp":"5","pressure":"820","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:25","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"14"},{"id":"707","terrestrial_date":"2014-09-30","sol":"764","ls":"205","season":"Month 7","min_temp":"-73","max_temp":"4","pressure":"821","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:25","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"14"},{"id":"706","terrestrial_date":"2014-09-29","sol":"763","ls":"204","season":"Month 7","min_temp":"-78","max_temp":"6","pressure":"817","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:25","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"15"},{"id":"703","terrestrial_date":"2014-09-28","sol":"762","ls":"203","season":"Month 7","min_temp":"-75","max_temp":"7","pressure":"814","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:25","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"14"},{"id":"705","terrestrial_date":"2014-09-27","sol":"761","ls":"203","season":"Month 7","min_temp":"-72","max_temp":"7","pressure":"814","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"14"},{"id":"704","terrestrial_date":"2014-09-25","sol":"760","ls":"202","season":"Month 7","min_temp":"-70","max_temp":"11","pressure":"810","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"14"},{"id":"702","terrestrial_date":"2014-09-24","sol":"759","ls":"201","season":"Month 7","min_temp":"-77","max_temp":"8","pressure":"809","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"13"},{"id":"701","terrestrial_date":"2014-09-23","sol":"758","ls":"201","season":"Month 7","min_temp":"-71","max_temp":"3","pressure":"810","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"14"},{"id":"700","terrestrial_date":"2014-09-22","sol":"757","ls":"200","season":"Month 7","min_temp":"-73","max_temp":"5","pressure":"807","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"14"},{"id":"699","terrestrial_date":"2014-09-21","sol":"756","ls":"200","season":"Month 7","min_temp":"-73","max_temp":"3","pressure":"806","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:23","local_uv_irradiance_index":"Moderate","min_gts_temp":"-77","max_gts_temp":"15"},{"id":"697","terrestrial_date":"2014-09-20","sol":"755","ls":"199","season":"Month 7","min_temp":"-74","max_temp":"2","pressure":"806","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:23","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"14"},{"id":"696","terrestrial_date":"2014-09-19","sol":"754","ls":"198","season":"Month 7","min_temp":"-73","max_temp":"6","pressure":"802","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:23","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"14"},{"id":"698","terrestrial_date":"2014-09-18","sol":"753","ls":"198","season":"Month 7","min_temp":"-73","max_temp":"8","pressure":"800","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:23","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"12"},{"id":"694","terrestrial_date":"2014-09-17","sol":"752","ls":"197","season":"Month 7","min_temp":"-71","max_temp":"-3","pressure":"798","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:23","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"8"},{"id":"695","terrestrial_date":"2014-09-16","sol":"751","ls":"197","season":"Month 7","min_temp":"-72","max_temp":"-6","pressure":"797","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"13"},{"id":"693","terrestrial_date":"2014-09-15","sol":"750","ls":"196","season":"Month 7","min_temp":"-72","max_temp":"4","pressure":"796","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"8"},{"id":"692","terrestrial_date":"2014-09-14","sol":"749","ls":"195","season":"Month 7","min_temp":"-73","max_temp":"3","pressure":"794","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"7"},{"id":"690","terrestrial_date":"2014-09-13","sol":"748","ls":"195","season":"Month 7","min_temp":"-71","max_temp":"5","pressure":"791","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"10"},{"id":"691","terrestrial_date":"2014-09-12","sol":"747","ls":"194","season":"Month 7","min_temp":"-73","max_temp":"6","pressure":"789","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"15"},{"id":"688","terrestrial_date":"2014-09-11","sol":"746","ls":"194","season":"Month 7","min_temp":"-76","max_temp":"2","pressure":"788","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"14"},{"id":"689","terrestrial_date":"2014-09-10","sol":"745","ls":"193","season":"Month 7","min_temp":"-74","max_temp":"1","pressure":"787","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"13"},{"id":"687","terrestrial_date":"2014-09-09","sol":"744","ls":"192","season":"Month 7","min_temp":"-75","max_temp":"-2","pressure":"786","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"10"},{"id":"686","terrestrial_date":"2014-09-08","sol":"743","ls":"192","season":"Month 7","min_temp":"-72","max_temp":"0","pressure":"786","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-67","max_gts_temp":"14"},{"id":"684","terrestrial_date":"2014-09-07","sol":"742","ls":"191","season":"Month 7","min_temp":"-72","max_temp":"0","pressure":"784","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-68","max_gts_temp":"4"},{"id":"683","terrestrial_date":"2014-09-06","sol":"741","ls":"191","season":"Month 7","min_temp":"-70","max_temp":"-1","pressure":"784","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-68","max_gts_temp":"4"},{"id":"685","terrestrial_date":"2014-09-05","sol":"740","ls":"190","season":"Month 7","min_temp":"-76","max_temp":"-2","pressure":"782","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-65","max_gts_temp":"2"},{"id":"682","terrestrial_date":"2014-09-04","sol":"739","ls":"189","season":"Month 7","min_temp":"-77","max_temp":"-1","pressure":"779","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"4"},{"id":"681","terrestrial_date":"2014-09-03","sol":"738","ls":"189","season":"Month 7","min_temp":"-75","max_temp":"0","pressure":"778","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"7"},{"id":"680","terrestrial_date":"2014-09-02","sol":"737","ls":"188","season":"Month 7","min_temp":"-74","max_temp":"3","pressure":"777","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"9"},{"id":"679","terrestrial_date":"2014-09-01","sol":"736","ls":"188","season":"Month 7","min_temp":"-76","max_temp":"0","pressure":"776","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"9"},{"id":"678","terrestrial_date":"2014-08-31","sol":"735","ls":"187","season":"Month 7","min_temp":"-73","max_temp":"1","pressure":"776","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"14"},{"id":"675","terrestrial_date":"2014-08-30","sol":"734","ls":"186","season":"Month 7","min_temp":"-73","max_temp":"-3","pressure":"776","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"10"},{"id":"674","terrestrial_date":"2014-08-29","sol":"733","ls":"186","season":"Month 7","min_temp":"-74","max_temp":"-2","pressure":"773","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"15"},{"id":"677","terrestrial_date":"2014-08-28","sol":"732","ls":"185","season":"Month 7","min_temp":"-75","max_temp":"-8","pressure":"773","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"13"},{"id":"673","terrestrial_date":"2014-08-27","sol":"731","ls":"185","season":"Month 7","min_temp":"-75","max_temp":"-4","pressure":"771","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"12"},{"id":"676","terrestrial_date":"2014-08-26","sol":"730","ls":"184","season":"Month 7","min_temp":"-76","max_temp":"3","pressure":"770","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"12"},{"id":"672","terrestrial_date":"2014-08-25","sol":"729","ls":"183","season":"Month 7","min_temp":"-75","max_temp":"3","pressure":"768","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"13"},{"id":"670","terrestrial_date":"2014-08-24","sol":"728","ls":"183","season":"Month 7","min_temp":"-74","max_temp":"1","pressure":"766","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"14"},{"id":"671","terrestrial_date":"2014-08-23","sol":"727","ls":"182","season":"Month 7","min_temp":"-76","max_temp":"1","pressure":"766","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"14"},{"id":"668","terrestrial_date":"2014-08-22","sol":"726","ls":"182","season":"Month 7","min_temp":"-75","max_temp":"1","pressure":"766","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"14"},{"id":"669","terrestrial_date":"2014-08-21","sol":"725","ls":"181","season":"Month 7","min_temp":"-73","max_temp":"-5","pressure":"764","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"13"},{"id":"667","terrestrial_date":"2014-08-19","sol":"724","ls":"181","season":"Month 7","min_temp":"-74","max_temp":"1","pressure":"763","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"14"},{"id":"666","terrestrial_date":"2014-08-18","sol":"723","ls":"180","season":"Month 7","min_temp":"-73","max_temp":"2","pressure":"761","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"14"},{"id":"665","terrestrial_date":"2014-08-17","sol":"722","ls":"179","season":"Month 6","min_temp":"-74","max_temp":"1","pressure":"760","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"14"},{"id":"664","terrestrial_date":"2014-08-16","sol":"721","ls":"179","season":"Month 6","min_temp":"-73","max_temp":"-5","pressure":"761","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"12"},{"id":"663","terrestrial_date":"2014-08-15","sol":"720","ls":"178","season":"Month 6","min_temp":"-74","max_temp":"-1","pressure":"760","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"13"},{"id":"662","terrestrial_date":"2014-08-14","sol":"719","ls":"178","season":"Month 6","min_temp":"-77","max_temp":"-1","pressure":"758","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"12"},{"id":"660","terrestrial_date":"2014-08-13","sol":"718","ls":"177","season":"Month 6","min_temp":"-77","max_temp":"3","pressure":"757","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"12"},{"id":"661","terrestrial_date":"2014-08-12","sol":"717","ls":"176","season":"Month 6","min_temp":"-76","max_temp":"5","pressure":"756","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"11"},{"id":"659","terrestrial_date":"2014-08-11","sol":"716","ls":"176","season":"Month 6","min_temp":"-75","max_temp":"2","pressure":"755","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"6"},{"id":"657","terrestrial_date":"2014-08-10","sol":"715","ls":"175","season":"Month 6","min_temp":"-73","max_temp":"2","pressure":"755","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:20","local_uv_irradiance_index":"Moderate","min_gts_temp":"-75","max_gts_temp":"3"},{"id":"655","terrestrial_date":"2014-08-09","sol":"714","ls":"175","season":"Month 6","min_temp":"-76","max_temp":"2","pressure":"754","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:20","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"8"},{"id":"656","terrestrial_date":"2014-08-08","sol":"713","ls":"174","season":"Month 6","min_temp":"-76","max_temp":"-12","pressure":"754","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"19"},{"id":"658","terrestrial_date":"2014-08-07","sol":"712","ls":"174","season":"Month 6","min_temp":"-77","max_temp":"-10","pressure":"752","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"18"},{"id":"654","terrestrial_date":"2014-08-06","sol":"711","ls":"173","season":"Month 6","min_temp":"-75","max_temp":"-11","pressure":"751","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-86","max_gts_temp":"18"},{"id":"653","terrestrial_date":"2014-08-05","sol":"710","ls":"172","season":"Month 6","min_temp":"-77","max_temp":"-12","pressure":"751","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-88","max_gts_temp":"15"},{"id":"652","terrestrial_date":"2014-08-04","sol":"709","ls":"172","season":"Month 6","min_temp":"-73","max_temp":"-11","pressure":"750","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"16"},{"id":"649","terrestrial_date":"2014-08-03","sol":"708","ls":"171","season":"Month 6","min_temp":"-76","max_temp":"1","pressure":"749","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"5"},{"id":"651","terrestrial_date":"2014-08-02","sol":"707","ls":"171","season":"Month 6","min_temp":"-76","max_temp":"1","pressure":"749","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"5"},{"id":"650","terrestrial_date":"2014-08-01","sol":"706","ls":"170","season":"Month 6","min_temp":"-76","max_temp":"0","pressure":"748","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"8"},{"id":"648","terrestrial_date":"2014-07-31","sol":"705","ls":"170","season":"Month 6","min_temp":"-76","max_temp":"-9","pressure":"746","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"14"},{"id":"647","terrestrial_date":"2014-07-30","sol":"704","ls":"169","season":"Month 6","min_temp":"-75","max_temp":"-5","pressure":"747","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"12"},{"id":"646","terrestrial_date":"2014-07-29","sol":"703","ls":"169","season":"Month 6","min_temp":"-75","max_temp":"-6","pressure":"747","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"9"},{"id":"645","terrestrial_date":"2014-07-28","sol":"702","ls":"168","season":"Month 6","min_temp":"-76","max_temp":"-2","pressure":"745","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"8"},{"id":"644","terrestrial_date":"2014-07-27","sol":"701","ls":"167","season":"Month 6","min_temp":"-77","max_temp":"-1","pressure":"745","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"8"},{"id":"643","terrestrial_date":"2014-07-26","sol":"700","ls":"167","season":"Month 6","min_temp":"-75","max_temp":"-2","pressure":"745","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"8"},{"id":"642","terrestrial_date":"2014-07-25","sol":"699","ls":"166","season":"Month 6","min_temp":"-76","max_temp":"-2","pressure":"744","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"9"},{"id":"641","terrestrial_date":"2014-07-24","sol":"698","ls":"166","season":"Month 6","min_temp":"-77","max_temp":"-3","pressure":"743","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"9"},{"id":"640","terrestrial_date":"2014-07-23","sol":"697","ls":"165","season":"Month 6","min_temp":"-74","max_temp":"-4","pressure":"743","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"8"},{"id":"639","terrestrial_date":"2014-07-22","sol":"696","ls":"165","season":"Month 6","min_temp":"-75","max_temp":"-2","pressure":"743","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-86","max_gts_temp":"9"},{"id":"638","terrestrial_date":"2014-07-21","sol":"695","ls":"164","season":"Month 6","min_temp":"-76","max_temp":"-1","pressure":"741","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"11"},{"id":"635","terrestrial_date":"2014-07-20","sol":"694","ls":"164","season":"Month 6","min_temp":"-75","max_temp":"-1","pressure":"740","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"2"},{"id":"636","terrestrial_date":"2014-07-19","sol":"693","ls":"163","season":"Month 6","min_temp":"-76","max_temp":"-2","pressure":"741","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:20","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"2"},{"id":"637","terrestrial_date":"2014-07-18","sol":"692","ls":"162","season":"Month 6","min_temp":"-76","max_temp":"-4","pressure":"742","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"6"},{"id":"634","terrestrial_date":"2014-07-17","sol":"691","ls":"162","season":"Month 6","min_temp":"-76","max_temp":"-8","pressure":"741","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"4"},{"id":"633","terrestrial_date":"2014-07-16","sol":"690","ls":"161","season":"Month 6","min_temp":"-77","max_temp":"-7","pressure":"741","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"5"},{"id":"632","terrestrial_date":"2014-07-15","sol":"689","ls":"161","season":"Month 6","min_temp":"-76","max_temp":"-6","pressure":"742","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"6"},{"id":"631","terrestrial_date":"2014-07-14","sol":"688","ls":"160","season":"Month 6","min_temp":"-77","max_temp":"-5","pressure":"741","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"8"},{"id":"630","terrestrial_date":"2014-07-12","sol":"687","ls":"160","season":"Month 6","min_temp":"-77","max_temp":"-2","pressure":"739","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"3"},{"id":"629","terrestrial_date":"2014-07-11","sol":"686","ls":"159","season":"Month 6","min_temp":"-76","max_temp":"-4","pressure":"738","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"2"},{"id":"628","terrestrial_date":"2014-07-10","sol":"685","ls":"159","season":"Month 6","min_temp":"-77","max_temp":"-2","pressure":"740","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:27","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"8"},{"id":"627","terrestrial_date":"2014-07-09","sol":"684","ls":"158","season":"Month 6","min_temp":"-75","max_temp":"-9","pressure":"741","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:27","sunset":"17:21","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"6"},{"id":"626","terrestrial_date":"2014-07-08","sol":"683","ls":"158","season":"Month 6","min_temp":"-79","max_temp":"-7","pressure":"741","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:27","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"8"},{"id":"625","terrestrial_date":"2014-07-07","sol":"682","ls":"157","season":"Month 6","min_temp":"-77","max_temp":"-16","pressure":"739","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:27","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"2"},{"id":"623","terrestrial_date":"2014-07-06","sol":"681","ls":"156","season":"Month 6","min_temp":"-79","max_temp":"-17","pressure":"738","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:21","local_uv_irradiance_index":"Moderate","min_gts_temp":"-80","max_gts_temp":"2"},{"id":"620","terrestrial_date":"2014-07-05","sol":"680","ls":"156","season":"Month 6","min_temp":"-76","max_temp":"-15","pressure":"740","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:21","local_uv_irradiance_index":"Moderate","min_gts_temp":"-80","max_gts_temp":"1"},{"id":"624","terrestrial_date":"2014-07-04","sol":"679","ls":"155","season":"Month 6","min_temp":"-77","max_temp":"-13","pressure":"738","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:21","local_uv_irradiance_index":"Moderate","min_gts_temp":"-80","max_gts_temp":"1"},{"id":"621","terrestrial_date":"2014-07-03","sol":"678","ls":"155","season":"Month 6","min_temp":"-77","max_temp":"-17","pressure":"739","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:22","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"-1"},{"id":"622","terrestrial_date":"2014-07-02","sol":"677","ls":"154","season":"Month 6","min_temp":"-78","max_temp":"-12","pressure":"737","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:22","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"0"},{"id":"619","terrestrial_date":"2014-07-01","sol":"676","ls":"154","season":"Month 6","min_temp":"-80","max_temp":"-17","pressure":"738","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:29","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-90","max_gts_temp":"9"},{"id":"618","terrestrial_date":"2014-06-30","sol":"675","ls":"153","season":"Month 6","min_temp":"-80","max_temp":"-12","pressure":"740","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:29","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-91","max_gts_temp":"10"},{"id":"617","terrestrial_date":"2014-06-29","sol":"674","ls":"153","season":"Month 6","min_temp":"-80","max_temp":"-17","pressure":"739","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:29","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-94","max_gts_temp":"7"},{"id":"616","terrestrial_date":"2014-06-28","sol":"673","ls":"152","season":"Month 6","min_temp":"-78","max_temp":"-16","pressure":"738","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:29","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-96","max_gts_temp":"8"},{"id":"615","terrestrial_date":"2014-06-27","sol":"672","ls":"152","season":"Month 6","min_temp":"-78","max_temp":"-16","pressure":"739","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:30","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"7"},{"id":"614","terrestrial_date":"2014-06-26","sol":"671","ls":"151","season":"Month 6","min_temp":"-79","max_temp":"-15","pressure":"740","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:30","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"6"},{"id":"612","terrestrial_date":"2014-06-25","sol":"670","ls":"151","season":"Month 6","min_temp":"-79","max_temp":"-7","pressure":"737","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:30","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"4"},{"id":"613","terrestrial_date":"2014-06-24","sol":"669","ls":"150","season":"Month 6","min_temp":"-84","max_temp":"-4","pressure":"735","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:30","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-91","max_gts_temp":"8"},{"id":"611","terrestrial_date":"2014-06-23","sol":"668","ls":"150","season":"Month 6","min_temp":"-75","max_temp":"-4","pressure":"734","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:30","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"6"},{"id":"606","terrestrial_date":"2014-06-22","sol":"667","ls":"149","season":"Month 5","min_temp":"-76","max_temp":"-7","pressure":"736","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:31","sunset":"17:22","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"0"},{"id":"608","terrestrial_date":"2014-06-21","sol":"666","ls":"148","season":"Month 5","min_temp":"-77","max_temp":"-7","pressure":"736","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:31","sunset":"17:23","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"0"},{"id":"610","terrestrial_date":"2014-06-20","sol":"665","ls":"148","season":"Month 5","min_temp":"-78","max_temp":"-4","pressure":"735","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:31","sunset":"17:23","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"7"},{"id":"607","terrestrial_date":"2014-06-19","sol":"664","ls":"147","season":"Month 5","min_temp":"-78","max_temp":"-8","pressure":"732","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:31","sunset":"17:23","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"0"},{"id":"609","terrestrial_date":"2014-06-18","sol":"663","ls":"147","season":"Month 5","min_temp":"-77","max_temp":"-10","pressure":"734","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:32","sunset":"17:23","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"4"},{"id":"605","terrestrial_date":"2014-06-17","sol":"662","ls":"146","season":"Month 5","min_temp":"-77","max_temp":"-11","pressure":"735","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:32","sunset":"17:23","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"4"},{"id":"604","terrestrial_date":"2014-06-16","sol":"661","ls":"146","season":"Month 5","min_temp":"-76","max_temp":"-10","pressure":"735","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:32","sunset":"17:23","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"1"},{"id":"601","terrestrial_date":"2014-06-15","sol":"660","ls":"145","season":"Month 5","min_temp":"-78","max_temp":"-12","pressure":"735","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:32","sunset":"17:23","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"1"},{"id":"603","terrestrial_date":"2014-06-14","sol":"659","ls":"145","season":"Month 5","min_temp":"-77","max_temp":"-14","pressure":"738","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:33","sunset":"17:23","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"1"},{"id":"602","terrestrial_date":"2014-06-13","sol":"658","ls":"144","season":"Month 5","min_temp":"-79","max_temp":"-10","pressure":"739","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:33","sunset":"17:23","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"1"},{"id":"600","terrestrial_date":"2014-06-12","sol":"657","ls":"144","season":"Month 5","min_temp":"-79","max_temp":"-6","pressure":"739","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:33","sunset":"17:23","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"1"},{"id":"599","terrestrial_date":"2014-06-11","sol":"656","ls":"143","season":"Month 5","min_temp":"-80","max_temp":"-13","pressure":"740","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:33","sunset":"17:23","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"-3"},{"id":"598","terrestrial_date":"2014-06-10","sol":"655","ls":"143","season":"Month 5","min_temp":"-77","max_temp":"-14","pressure":"741","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:33","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"0"},{"id":"597","terrestrial_date":"2014-06-09","sol":"654","ls":"142","season":"Month 5","min_temp":"-79","max_temp":"-8","pressure":"742","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:34","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"-4"},{"id":"596","terrestrial_date":"2014-06-08","sol":"653","ls":"142","season":"Month 5","min_temp":"-80","max_temp":"-13","pressure":"744","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:34","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"-4"},{"id":"594","terrestrial_date":"2014-06-07","sol":"652","ls":"141","season":"Month 5","min_temp":"-79","max_temp":"-12","pressure":"745","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:34","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"-3"},{"id":"595","terrestrial_date":"2014-06-05","sol":"651","ls":"141","season":"Month 5","min_temp":"-80","max_temp":"-8","pressure":"743","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:34","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"2"},{"id":"593","terrestrial_date":"2014-06-04","sol":"650","ls":"140","season":"Month 5","min_temp":"-80","max_temp":"-11","pressure":"743","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:35","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"0"},{"id":"592","terrestrial_date":"2014-06-03","sol":"649","ls":"140","season":"Month 5","min_temp":"-79","max_temp":"-14","pressure":"745","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:35","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"-3"},{"id":"591","terrestrial_date":"2014-06-02","sol":"648","ls":"139","season":"Month 5","min_temp":"-80","max_temp":"-20","pressure":"746","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:35","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"-2"},{"id":"590","terrestrial_date":"2014-06-01","sol":"647","ls":"139","season":"Month 5","min_temp":"-79","max_temp":"-19","pressure":"746","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:35","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"-2"},{"id":"587","terrestrial_date":"2014-05-31","sol":"646","ls":"138","season":"Month 5","min_temp":"-81","max_temp":"-16","pressure":"746","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:35","sunset":"17:24","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"0"},{"id":"589","terrestrial_date":"2014-05-30","sol":"645","ls":"138","season":"Month 5","min_temp":"-81","max_temp":"-8","pressure":"746","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:36","sunset":"17:25","local_uv_irradiance_index":"High","min_gts_temp":"-86","max_gts_temp":"0"},{"id":"588","terrestrial_date":"2014-05-29","sol":"644","ls":"137","season":"Month 5","min_temp":"-80","max_temp":"-10","pressure":"748","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:36","sunset":"17:25","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"0"},{"id":"586","terrestrial_date":"2014-05-28","sol":"643","ls":"137","season":"Month 5","min_temp":"-80","max_temp":"-14","pressure":"748","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:36","sunset":"17:25","local_uv_irradiance_index":"High","min_gts_temp":"-88","max_gts_temp":"-2"},{"id":"585","terrestrial_date":"2014-05-27","sol":"642","ls":"136","season":"Month 5","min_temp":"-80","max_temp":"-19","pressure":"749","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:36","sunset":"17:25","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"-2"},{"id":"584","terrestrial_date":"2014-05-26","sol":"641","ls":"136","season":"Month 5","min_temp":"-81","max_temp":"-19","pressure":"749","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:37","sunset":"17:25","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"-2"},{"id":"583","terrestrial_date":"2014-05-25","sol":"640","ls":"135","season":"Month 5","min_temp":"-81","max_temp":"-11","pressure":"750","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:37","sunset":"17:25","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-7"},{"id":"581","terrestrial_date":"2014-05-24","sol":"639","ls":"135","season":"Month 5","min_temp":"-80","max_temp":"-16","pressure":"750","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:37","sunset":"17:25","local_uv_irradiance_index":"Moderate","min_gts_temp":"-80","max_gts_temp":"-9"},{"id":"579","terrestrial_date":"2014-05-23","sol":"638","ls":"134","season":"Month 5","min_temp":"-80","max_temp":"-12","pressure":"751","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:37","sunset":"17:25","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"-9"},{"id":"580","terrestrial_date":"2014-05-22","sol":"637","ls":"134","season":"Month 5","min_temp":"-80","max_temp":"-18","pressure":"752","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:37","sunset":"17:25","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-5"},{"id":"582","terrestrial_date":"2014-05-21","sol":"636","ls":"133","season":"Month 5","min_temp":"-81","max_temp":"-19","pressure":"752","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:38","sunset":"17:25","local_uv_irradiance_index":"High","min_gts_temp":"-89","max_gts_temp":"0"},{"id":"578","terrestrial_date":"2014-05-20","sol":"635","ls":"133","season":"Month 5","min_temp":"-82","max_temp":"-10","pressure":"754","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:38","sunset":"17:26","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"-3"},{"id":"577","terrestrial_date":"2014-05-19","sol":"634","ls":"132","season":"Month 5","min_temp":"-82","max_temp":"-20","pressure":"753","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:38","sunset":"17:26","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"4"},{"id":"574","terrestrial_date":"2014-05-18","sol":"633","ls":"132","season":"Month 5","min_temp":"-81","max_temp":"-15","pressure":"754","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:38","sunset":"17:26","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"-3"},{"id":"575","terrestrial_date":"2014-05-17","sol":"632","ls":"131","season":"Month 5","min_temp":"-79","max_temp":"-18","pressure":"755","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:38","sunset":"17:26","local_uv_irradiance_index":"High","min_gts_temp":"-86","max_gts_temp":"-4"},{"id":"576","terrestrial_date":"2014-05-16","sol":"631","ls":"131","season":"Month 5","min_temp":"-81","max_temp":"-18","pressure":"756","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:39","sunset":"17:26","local_uv_irradiance_index":"High","min_gts_temp":"-88","max_gts_temp":"-1"},{"id":"573","terrestrial_date":"2014-05-15","sol":"630","ls":"130","season":"Month 5","min_temp":"-82","max_temp":"-20","pressure":"757","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:39","sunset":"17:26","local_uv_irradiance_index":"High","min_gts_temp":"-93","max_gts_temp":"-2"},{"id":"572","terrestrial_date":"2014-05-14","sol":"629","ls":"130","season":"Month 5","min_temp":"-84","max_temp":"-24","pressure":"759","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:39","sunset":"17:26","local_uv_irradiance_index":"Moderate","min_gts_temp":"-94","max_gts_temp":"-3"},{"id":"571","terrestrial_date":"2014-05-13","sol":"628","ls":"129","season":"Month 5","min_temp":"-81","max_temp":"-23","pressure":"759","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:39","sunset":"17:26","local_uv_irradiance_index":"Moderate","min_gts_temp":"-90","max_gts_temp":"-2"},{"id":"570","terrestrial_date":"2014-05-12","sol":"627","ls":"129","season":"Month 5","min_temp":"-82","max_temp":"-19","pressure":"759","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:39","sunset":"17:26","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"-3"},{"id":"567","terrestrial_date":"2014-05-11","sol":"626","ls":"128","season":"Month 5","min_temp":"-82","max_temp":"-21","pressure":"760","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:40","sunset":"17:26","local_uv_irradiance_index":"Moderate","min_gts_temp":"-94","max_gts_temp":"-3"},{"id":"569","terrestrial_date":"2014-05-10","sol":"625","ls":"128","season":"Month 5","min_temp":"-81","max_temp":"-24","pressure":"761","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:40","sunset":"17:27","local_uv_irradiance_index":"Moderate","min_gts_temp":"-95","max_gts_temp":"-4"},{"id":"568","terrestrial_date":"2014-05-09","sol":"624","ls":"127","season":"Month 5","min_temp":"-82","max_temp":"-19","pressure":"762","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:40","sunset":"17:27","local_uv_irradiance_index":"Moderate","min_gts_temp":"-92","max_gts_temp":"-2"},{"id":"566","terrestrial_date":"2014-05-08","sol":"623","ls":"127","season":"Month 5","min_temp":"-83","max_temp":"-21","pressure":"763","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:40","sunset":"17:27","local_uv_irradiance_index":"Moderate","min_gts_temp":"-92","max_gts_temp":"-2"},{"id":"565","terrestrial_date":"2014-05-07","sol":"622","ls":"126","season":"Month 5","min_temp":"-84","max_temp":"-19","pressure":"763","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:40","sunset":"17:27","local_uv_irradiance_index":"Moderate","min_gts_temp":"-92","max_gts_temp":"-3"},{"id":"564","terrestrial_date":"2014-05-06","sol":"621","ls":"126","season":"Month 5","min_temp":"-82","max_temp":"-21","pressure":"765","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:41","sunset":"17:27","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"-3"},{"id":"563","terrestrial_date":"2014-05-05","sol":"620","ls":"125","season":"Month 5","min_temp":"-83","max_temp":"-19","pressure":"765","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:41","sunset":"17:27","local_uv_irradiance_index":"Moderate","min_gts_temp":"-96","max_gts_temp":"-4"},{"id":"560","terrestrial_date":"2014-05-04","sol":"619","ls":"125","season":"Month 5","min_temp":"-82","max_temp":"-22","pressure":"766","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:41","sunset":"17:27","local_uv_irradiance_index":"Low","min_gts_temp":"-96","max_gts_temp":"-3"},{"id":"562","terrestrial_date":"2014-05-03","sol":"618","ls":"124","season":"Month 5","min_temp":"-83","max_temp":"-23","pressure":"769","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:41","sunset":"17:27","local_uv_irradiance_index":"Moderate","min_gts_temp":"-94","max_gts_temp":"-3"},{"id":"561","terrestrial_date":"2014-05-02","sol":"617","ls":"124","season":"Month 5","min_temp":"-84","max_temp":"-19","pressure":"769","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:41","sunset":"17:27","local_uv_irradiance_index":"Moderate","min_gts_temp":"-94","max_gts_temp":"-4"},{"id":"559","terrestrial_date":"2014-05-01","sol":"616","ls":"123","season":"Month 5","min_temp":"-82","max_temp":"-19","pressure":"769","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:42","sunset":"17:27","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"-4"},{"id":"558","terrestrial_date":"2014-04-29","sol":"615","ls":"123","season":"Month 5","min_temp":"-83","max_temp":"-23","pressure":"771","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:42","sunset":"17:28","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"-4"},{"id":"557","terrestrial_date":"2014-04-28","sol":"614","ls":"122","season":"Month 5","min_temp":"-82","max_temp":"-19","pressure":"772","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:42","sunset":"17:28","local_uv_irradiance_index":"Moderate","min_gts_temp":"-95","max_gts_temp":"-5"},{"id":"556","terrestrial_date":"2014-04-27","sol":"613","ls":"122","season":"Month 5","min_temp":"-84","max_temp":"-21","pressure":"773","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:42","sunset":"17:28","local_uv_irradiance_index":"Moderate","min_gts_temp":"-98","max_gts_temp":"-4"},{"id":"553","terrestrial_date":"2014-04-26","sol":"612","ls":"121","season":"Month 5","min_temp":"-85","max_temp":"-27","pressure":"774","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:42","sunset":"17:28","local_uv_irradiance_index":"Moderate","min_gts_temp":"-95","max_gts_temp":"-4"},{"id":"555","terrestrial_date":"2014-04-25","sol":"611","ls":"121","season":"Month 5","min_temp":"-84","max_temp":"-23","pressure":"775","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:43","sunset":"17:28","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"-5"},{"id":"554","terrestrial_date":"2014-04-24","sol":"610","ls":"120","season":"Month 5","min_temp":"-85","max_temp":"-20","pressure":"776","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:43","sunset":"17:28","local_uv_irradiance_index":"Moderate","min_gts_temp":"-94","max_gts_temp":"-5"},{"id":"552","terrestrial_date":"2014-04-23","sol":"609","ls":"120","season":"Month 5","min_temp":"-84","max_temp":"-20","pressure":"777","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:43","sunset":"17:28","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"-5"},{"id":"551","terrestrial_date":"2014-04-22","sol":"608","ls":"119","season":"Month 4","min_temp":"-85","max_temp":"-21","pressure":"777","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:43","sunset":"17:28","local_uv_irradiance_index":"Moderate","min_gts_temp":"-97","max_gts_temp":"-4"},{"id":"550","terrestrial_date":"2014-04-21","sol":"607","ls":"119","season":"Month 4","min_temp":"-83","max_temp":"-28","pressure":"779","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:43","sunset":"17:28","local_uv_irradiance_index":"Low","min_gts_temp":"-96","max_gts_temp":"-5"},{"id":"549","terrestrial_date":"2014-04-20","sol":"606","ls":"118","season":"Month 4","min_temp":"-84","max_temp":"-27","pressure":"780","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:43","sunset":"17:28","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-8"},{"id":"547","terrestrial_date":"2014-04-19","sol":"605","ls":"118","season":"Month 4","min_temp":"-83","max_temp":"-22","pressure":"781","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:44","sunset":"17:29","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-9"},{"id":"546","terrestrial_date":"2014-04-18","sol":"604","ls":"118","season":"Month 4","min_temp":"-84","max_temp":"-17","pressure":"782","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:44","sunset":"17:29","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-9"},{"id":"548","terrestrial_date":"2014-04-17","sol":"603","ls":"117","season":"Month 4","min_temp":"-83","max_temp":"-15","pressure":"783","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:44","sunset":"17:29","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"-9"},{"id":"545","terrestrial_date":"2014-04-16","sol":"602","ls":"117","season":"Month 4","min_temp":"-82","max_temp":"-22","pressure":"784","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:44","sunset":"17:29","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"-11"},{"id":"544","terrestrial_date":"2014-04-15","sol":"601","ls":"116","season":"Month 4","min_temp":"-82","max_temp":"-25","pressure":"785","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:44","sunset":"17:29","local_uv_irradiance_index":"Moderate","min_gts_temp":"-74","max_gts_temp":"-8"},{"id":"541","terrestrial_date":"2014-04-14","sol":"600","ls":"116","season":"Month 4","min_temp":"-81","max_temp":"-25","pressure":"787","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:45","sunset":"17:29","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-14"},{"id":"543","terrestrial_date":"2014-04-13","sol":"599","ls":"115","season":"Month 4","min_temp":"-84","max_temp":"-20","pressure":"788","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:45","sunset":"17:29","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"-9"},{"id":"542","terrestrial_date":"2014-04-12","sol":"598","ls":"115","season":"Month 4","min_temp":"-84","max_temp":"-25","pressure":"787","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:45","sunset":"17:29","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"-10"},{"id":"540","terrestrial_date":"2014-04-11","sol":"597","ls":"114","season":"Month 4","min_temp":"-84","max_temp":"-26","pressure":"790","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:45","sunset":"17:29","local_uv_irradiance_index":"Moderate","min_gts_temp":"-83","max_gts_temp":"-11"},{"id":"539","terrestrial_date":"2014-04-10","sol":"596","ls":"114","season":"Month 4","min_temp":"-82","max_temp":"-24","pressure":"791","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:45","sunset":"17:29","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"-10"},{"id":"538","terrestrial_date":"2014-04-09","sol":"595","ls":"113","season":"Month 4","min_temp":"-83","max_temp":"-25","pressure":"792","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:45","sunset":"17:30","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-12"},{"id":"537","terrestrial_date":"2014-04-08","sol":"594","ls":"113","season":"Month 4","min_temp":"-83","max_temp":"-22","pressure":"793","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:46","sunset":"17:30","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-15"},{"id":"536","terrestrial_date":"2014-04-07","sol":"593","ls":"112","season":"Month 4","min_temp":"-83","max_temp":"-23","pressure":"795","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:46","sunset":"17:30","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"-11"},{"id":"534","terrestrial_date":"2014-04-06","sol":"592","ls":"112","season":"Month 4","min_temp":"-83","max_temp":"-26","pressure":"795","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:46","sunset":"17:30","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-11"},{"id":"533","terrestrial_date":"2014-04-05","sol":"591","ls":"111","season":"Month 4","min_temp":"-82","max_temp":"-26","pressure":"795","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:46","sunset":"17:30","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"-11"},{"id":"535","terrestrial_date":"2014-04-04","sol":"590","ls":"111","season":"Month 4","min_temp":"-82","max_temp":"-26","pressure":"797","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:46","sunset":"17:30","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-11"},{"id":"531","terrestrial_date":"2014-04-03","sol":"589","ls":"110","season":"Month 4","min_temp":"-85","max_temp":"-27","pressure":"798","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:46","sunset":"17:30","local_uv_irradiance_index":"Moderate","min_gts_temp":"-94","max_gts_temp":"-10"},{"id":"532","terrestrial_date":"2014-04-02","sol":"588","ls":"110","season":"Month 4","min_temp":"-84","max_temp":"-24","pressure":"799","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:47","sunset":"17:30","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-8"},{"id":"530","terrestrial_date":"2014-04-01","sol":"587","ls":"109","season":"Month 4","min_temp":"-85","max_temp":"-28","pressure":"801","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:47","sunset":"17:30","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-9"},{"id":"529","terrestrial_date":"2014-03-31","sol":"586","ls":"109","season":"Month 4","min_temp":"-82","max_temp":"-24","pressure":"802","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:47","sunset":"17:30","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-8"},{"id":"527","terrestrial_date":"2014-03-30","sol":"585","ls":"109","season":"Month 4","min_temp":"-83","max_temp":"-26","pressure":"802","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:47","sunset":"17:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-9"},{"id":"528","terrestrial_date":"2014-03-29","sol":"584","ls":"108","season":"Month 4","min_temp":"-82","max_temp":"-25","pressure":"804","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:47","sunset":"17:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-89","max_gts_temp":"-8"},{"id":"526","terrestrial_date":"2014-03-28","sol":"583","ls":"108","season":"Month 4","min_temp":"-82","max_temp":"-27","pressure":"806","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:47","sunset":"17:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-10"},{"id":"525","terrestrial_date":"2014-03-27","sol":"582","ls":"107","season":"Month 4","min_temp":"-84","max_temp":"-27","pressure":"807","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:47","sunset":"17:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-9"},{"id":"524","terrestrial_date":"2014-03-26","sol":"581","ls":"107","season":"Month 4","min_temp":"-84","max_temp":"-28","pressure":"808","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:48","sunset":"17:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-9"},{"id":"523","terrestrial_date":"2014-03-25","sol":"580","ls":"106","season":"Month 4","min_temp":"-83","max_temp":"-24","pressure":"810","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:48","sunset":"17:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-10"},{"id":"522","terrestrial_date":"2014-03-24","sol":"579","ls":"106","season":"Month 4","min_temp":"-82","max_temp":"-22","pressure":"811","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:48","sunset":"17:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-8"},{"id":"521","terrestrial_date":"2014-03-22","sol":"578","ls":"105","season":"Month 4","min_temp":"-83","max_temp":"-23","pressure":"812","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:48","sunset":"17:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-9"},{"id":"519","terrestrial_date":"2014-03-21","sol":"577","ls":"105","season":"Month 4","min_temp":"-84","max_temp":"-27","pressure":"813","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:48","sunset":"17:31","local_uv_irradiance_index":"Moderate","min_gts_temp":"-90","max_gts_temp":"-11"},{"id":"520","terrestrial_date":"2014-03-20","sol":"576","ls":"104","season":"Month 4","min_temp":"-84","max_temp":"-26","pressure":"815","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:48","sunset":"17:32","local_uv_irradiance_index":"Moderate","min_gts_temp":"-90","max_gts_temp":"-8"},{"id":"518","terrestrial_date":"2014-03-19","sol":"575","ls":"104","season":"Month 4","min_temp":"-82","max_temp":"-26","pressure":"816","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:49","sunset":"17:32","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-10"},{"id":"517","terrestrial_date":"2014-03-18","sol":"574","ls":"103","season":"Month 4","min_temp":"-85","max_temp":"-23","pressure":"817","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:49","sunset":"17:32","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"-9"},{"id":"516","terrestrial_date":"2014-03-17","sol":"573","ls":"103","season":"Month 4","min_temp":"-84","max_temp":"-27","pressure":"819","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:49","sunset":"17:32","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-10"},{"id":"514","terrestrial_date":"2014-03-16","sol":"572","ls":"102","season":"Month 4","min_temp":"-85","max_temp":"-27","pressure":"820","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:49","sunset":"17:32","local_uv_irradiance_index":"Moderate","min_gts_temp":"-89","max_gts_temp":"-8"},{"id":"515","terrestrial_date":"2014-03-15","sol":"571","ls":"102","season":"Month 4","min_temp":"-84","max_temp":"-26","pressure":"821","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:49","sunset":"17:32","local_uv_irradiance_index":"Moderate","min_gts_temp":"-92","max_gts_temp":"-8"},{"id":"513","terrestrial_date":"2014-03-14","sol":"570","ls":"102","season":"Month 4","min_temp":"-84","max_temp":"-26","pressure":"823","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:49","sunset":"17:32","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-7"},{"id":"512","terrestrial_date":"2014-03-13","sol":"569","ls":"101","season":"Month 4","min_temp":"-85","max_temp":"-27","pressure":"825","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:49","sunset":"17:32","local_uv_irradiance_index":"Moderate","min_gts_temp":"-90","max_gts_temp":"-7"},{"id":"511","terrestrial_date":"2014-03-12","sol":"568","ls":"101","season":"Month 4","min_temp":"-86","max_temp":"-28","pressure":"825","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:50","sunset":"17:32","local_uv_irradiance_index":"High","min_gts_temp":"-86","max_gts_temp":"-9"},{"id":"510","terrestrial_date":"2014-03-11","sol":"567","ls":"100","season":"Month 4","min_temp":"-86","max_temp":"-28","pressure":"827","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:50","sunset":"17:33","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"-13"},{"id":"507","terrestrial_date":"2014-03-10","sol":"566","ls":"100","season":"Month 4","min_temp":"-86","max_temp":"-27","pressure":"829","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:50","sunset":"17:33","local_uv_irradiance_index":"High","min_gts_temp":"-86","max_gts_temp":"-13"},{"id":"508","terrestrial_date":"2014-03-09","sol":"565","ls":"99","season":"Month 4","min_temp":"-85","max_temp":"-27","pressure":"830","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:50","sunset":"17:33","local_uv_irradiance_index":"High","min_gts_temp":"-91","max_gts_temp":"-8"},{"id":"509","terrestrial_date":"2014-03-08","sol":"564","ls":"99","season":"Month 4","min_temp":"-86","max_temp":"-27","pressure":"831","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:50","sunset":"17:33","local_uv_irradiance_index":"Moderate","min_gts_temp":"-92","max_gts_temp":"-11"},{"id":"505","terrestrial_date":"2014-03-07","sol":"563","ls":"98","season":"Month 4","min_temp":"-87","max_temp":"-31","pressure":"833","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:50","sunset":"17:33","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-9"},{"id":"506","terrestrial_date":"2014-03-06","sol":"562","ls":"98","season":"Month 4","min_temp":"-85","max_temp":"-23","pressure":"834","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"17:33","local_uv_irradiance_index":"Moderate","min_gts_temp":"-92","max_gts_temp":"-11"},{"id":"504","terrestrial_date":"2014-03-05","sol":"561","ls":"97","season":"Month 4","min_temp":"-85","max_temp":"-23","pressure":"835","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"17:33","local_uv_irradiance_index":"Moderate","min_gts_temp":"-89","max_gts_temp":"-5"},{"id":"503","terrestrial_date":"2014-03-04","sol":"560","ls":"97","season":"Month 4","min_temp":"-86","max_temp":"-23","pressure":"836","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"17:33","local_uv_irradiance_index":"Moderate","min_gts_temp":"-97","max_gts_temp":"-6"},{"id":"502","terrestrial_date":"2014-03-03","sol":"559","ls":"96","season":"Month 4","min_temp":"-85","max_temp":"-27","pressure":"838","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"17:34","local_uv_irradiance_index":"High","min_gts_temp":"-93","max_gts_temp":"-3"},{"id":"500","terrestrial_date":"2014-03-02","sol":"558","ls":"96","season":"Month 4","min_temp":"-85","max_temp":"-26","pressure":"839","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"-6"},{"id":"498","terrestrial_date":"2014-03-01","sol":"557","ls":"96","season":"Month 4","min_temp":"-85","max_temp":"-29","pressure":"840","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-92","max_gts_temp":"-6"},{"id":"501","terrestrial_date":"2014-02-28","sol":"556","ls":"95","season":"Month 4","min_temp":"-85","max_temp":"-29","pressure":"842","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"-7"},{"id":"499","terrestrial_date":"2014-02-27","sol":"555","ls":"95","season":"Month 4","min_temp":"-85","max_temp":"-31","pressure":"843","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-95","max_gts_temp":"-9"},{"id":"497","terrestrial_date":"2014-02-26","sol":"554","ls":"94","season":"Month 4","min_temp":"-84","max_temp":"-22","pressure":"843","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-96","max_gts_temp":"-7"},{"id":"496","terrestrial_date":"2014-02-25","sol":"553","ls":"94","season":"Month 4","min_temp":"-84","max_temp":"-26","pressure":"845","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:34","local_uv_irradiance_index":"Moderate","min_gts_temp":"-90","max_gts_temp":"-10"},{"id":"493","terrestrial_date":"2014-02-24","sol":"552","ls":"93","season":"Month 4","min_temp":"-86","max_temp":"-29","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:34","local_uv_irradiance_index":"High","min_gts_temp":"-91","max_gts_temp":"-11"},{"id":"495","terrestrial_date":"2014-02-23","sol":"551","ls":"93","season":"Month 4","min_temp":"-85","max_temp":"-28","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-92","max_gts_temp":"-11"},{"id":"494","terrestrial_date":"2014-02-22","sol":"550","ls":"92","season":"Month 4","min_temp":"-85","max_temp":"-27","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-9"},{"id":"492","terrestrial_date":"2014-02-21","sol":"549","ls":"92","season":"Month 4","min_temp":"-87","max_temp":"-23","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"17:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-89","max_gts_temp":"-12"},{"id":"491","terrestrial_date":"2014-02-20","sol":"548","ls":"91","season":"Month 4","min_temp":"-86","max_temp":"-28","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:35","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"-10"},{"id":"488","terrestrial_date":"2014-02-19","sol":"547","ls":"91","season":"Month 4","min_temp":"-85","max_temp":"-29","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:35","local_uv_irradiance_index":"High","min_gts_temp":"-89","max_gts_temp":"-10"},{"id":"489","terrestrial_date":"2014-02-18","sol":"546","ls":"91","season":"Month 4","min_temp":"-85","max_temp":"-34","pressure":"855","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-13"},{"id":"490","terrestrial_date":"2014-02-17","sol":"545","ls":"90","season":"Month 4","min_temp":"-85","max_temp":"-29","pressure":"856","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:35","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-14"},{"id":"487","terrestrial_date":"2014-02-16","sol":"544","ls":"90","season":"Month 4","min_temp":"-86","max_temp":"-27","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"-16"},{"id":"486","terrestrial_date":"2014-02-15","sol":"543","ls":"89","season":"Month 3","min_temp":"-84","max_temp":"-26","pressure":"858","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-16"},{"id":"477","terrestrial_date":"2014-02-13","sol":"542","ls":"89","season":"Month 3","min_temp":"-85","max_temp":"-28","pressure":"859","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-11"},{"id":"482","terrestrial_date":"2014-02-12","sol":"541","ls":"88","season":"Month 3","min_temp":"-84","max_temp":"-27","pressure":"861","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"-11"},{"id":"481","terrestrial_date":"2014-02-11","sol":"540","ls":"88","season":"Month 3","min_temp":"-84","max_temp":"-29","pressure":"862","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-18"},{"id":"476","terrestrial_date":"2014-02-10","sol":"539","ls":"87","season":"Month 3","min_temp":"-85","max_temp":"-23","pressure":"864","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"17:36","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"-17"},{"id":"472","terrestrial_date":"2014-02-09","sol":"538","ls":"87","season":"Month 3","min_temp":"-85","max_temp":"-25","pressure":"865","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-8"},{"id":"469","terrestrial_date":"2014-02-08","sol":"537","ls":"86","season":"Month 3","min_temp":"-83","max_temp":"-28","pressure":"865","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-92","max_gts_temp":"-11"},{"id":"470","terrestrial_date":"2014-02-07","sol":"536","ls":"86","season":"Month 3","min_temp":"-83","max_temp":"-29","pressure":"867","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-94","max_gts_temp":"-12"},{"id":"468","terrestrial_date":"2014-02-06","sol":"535","ls":"86","season":"Month 3","min_temp":"-88","max_temp":"-29","pressure":"868","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-99","max_gts_temp":"-7"},{"id":"467","terrestrial_date":"2014-02-05","sol":"534","ls":"85","season":"Month 3","min_temp":"-86","max_temp":"-29","pressure":"869","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-101","max_gts_temp":"-6"},{"id":"466","terrestrial_date":"2014-02-04","sol":"533","ls":"85","season":"Month 3","min_temp":"-87","max_temp":"-30","pressure":"871","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-98","max_gts_temp":"-7"},{"id":"464","terrestrial_date":"2014-02-03","sol":"532","ls":"84","season":"Month 3","min_temp":"-88","max_temp":"-23","pressure":"872","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:37","local_uv_irradiance_index":"Moderate","min_gts_temp":"-97","max_gts_temp":"-10"},{"id":"465","terrestrial_date":"2014-02-02","sol":"531","ls":"84","season":"Month 3","min_temp":"-87","max_temp":"-22","pressure":"872","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:38","local_uv_irradiance_index":"Moderate","min_gts_temp":"-99","max_gts_temp":"-12"},{"id":"463","terrestrial_date":"2014-02-01","sol":"530","ls":"83","season":"Month 3","min_temp":"-87","max_temp":"-28","pressure":"873","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:38","local_uv_irradiance_index":"Moderate","min_gts_temp":"-99","max_gts_temp":"-11"},{"id":"462","terrestrial_date":"2014-01-31","sol":"529","ls":"83","season":"Month 3","min_temp":"-87","max_temp":"-23","pressure":"875","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"17:38","local_uv_irradiance_index":"Moderate","min_gts_temp":"-100","max_gts_temp":"-11"},{"id":"461","terrestrial_date":"2014-01-30","sol":"528","ls":"82","season":"Month 3","min_temp":"-86","max_temp":"-26","pressure":"876","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"17:38","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"-9"},{"id":"460","terrestrial_date":"2014-01-29","sol":"527","ls":"82","season":"Month 3","min_temp":"-86","max_temp":"-23","pressure":"877","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"17:38","local_uv_irradiance_index":"High","min_gts_temp":"-94","max_gts_temp":"-7"},{"id":"459","terrestrial_date":"2014-01-28","sol":"526","ls":"82","season":"Month 3","min_temp":"-87","max_temp":"-24","pressure":"878","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"17:39","local_uv_irradiance_index":"Moderate","min_gts_temp":"-90","max_gts_temp":"-10"},{"id":"456","terrestrial_date":"2014-01-27","sol":"525","ls":"81","season":"Month 3","min_temp":"-87","max_temp":"-29","pressure":"878","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"17:39","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-11"},{"id":"457","terrestrial_date":"2014-01-26","sol":"524","ls":"81","season":"Month 3","min_temp":"-85","max_temp":"-27","pressure":"880","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"17:39","local_uv_irradiance_index":"Moderate","min_gts_temp":"-96","max_gts_temp":"-7"},{"id":"458","terrestrial_date":"2014-01-25","sol":"523","ls":"80","season":"Month 3","min_temp":"-85","max_temp":"-25","pressure":"881","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"17:39","local_uv_irradiance_index":"Moderate","min_gts_temp":"-98","max_gts_temp":"-7"},{"id":"455","terrestrial_date":"2014-01-24","sol":"522","ls":"80","season":"Month 3","min_temp":"-85","max_temp":"-26","pressure":"881","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"17:39","local_uv_irradiance_index":"Moderate","min_gts_temp":"-98","max_gts_temp":"-7"},{"id":"454","terrestrial_date":"2014-01-23","sol":"521","ls":"79","season":"Month 3","min_temp":"-87","max_temp":"-26","pressure":"882","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"17:39","local_uv_irradiance_index":"Moderate","min_gts_temp":"-95","max_gts_temp":"-7"},{"id":"453","terrestrial_date":"2014-01-22","sol":"520","ls":"79","season":"Month 3","min_temp":"-86","max_temp":"-24","pressure":"884","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"17:40","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-9"},{"id":"452","terrestrial_date":"2014-01-21","sol":"519","ls":"78","season":"Month 3","min_temp":"-86","max_temp":"-25","pressure":"884","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"17:40","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-11"},{"id":"451","terrestrial_date":"2014-01-20","sol":"518","ls":"78","season":"Month 3","min_temp":"-85","max_temp":"-29","pressure":"885","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"17:40","local_uv_irradiance_index":"Moderate","min_gts_temp":"-100","max_gts_temp":"-9"},{"id":"448","terrestrial_date":"2014-01-19","sol":"517","ls":"77","season":"Month 3","min_temp":"-86","max_temp":"-27","pressure":"885","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"17:40","local_uv_irradiance_index":"Moderate","min_gts_temp":"-98","max_gts_temp":"-6"},{"id":"449","terrestrial_date":"2014-01-18","sol":"516","ls":"77","season":"Month 3","min_temp":"-86","max_temp":"-25","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"17:40","local_uv_irradiance_index":"Moderate","min_gts_temp":"-99","max_gts_temp":"-6"},{"id":"450","terrestrial_date":"2014-01-17","sol":"515","ls":"77","season":"Month 3","min_temp":"-86","max_temp":"-23","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"17:41","local_uv_irradiance_index":"Moderate","min_gts_temp":"-89","max_gts_temp":"-6"},{"id":"447","terrestrial_date":"2014-01-16","sol":"514","ls":"76","season":"Month 3","min_temp":"-86","max_temp":"-29","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"17:41","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-10"},{"id":"445","terrestrial_date":"2014-01-15","sol":"513","ls":"76","season":"Month 3","min_temp":"-86","max_temp":"-29","pressure":"889","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"17:41","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-10"},{"id":"444","terrestrial_date":"2014-01-14","sol":"512","ls":"75","season":"Month 3","min_temp":"-86","max_temp":"-24","pressure":"890","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"17:41","local_uv_irradiance_index":"Moderate","min_gts_temp":"-94","max_gts_temp":"-9"},{"id":"446","terrestrial_date":"2014-01-13","sol":"511","ls":"75","season":"Month 3","min_temp":"-85","max_temp":"-31","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"17:42","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"-10"},{"id":"441","terrestrial_date":"2014-01-12","sol":"510","ls":"74","season":"Month 3","min_temp":"-85","max_temp":"-31","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:59","sunset":"17:42","local_uv_irradiance_index":"Moderate","min_gts_temp":"-92","max_gts_temp":"-13"},{"id":"443","terrestrial_date":"2014-01-11","sol":"509","ls":"74","season":"Month 3","min_temp":"-86","max_temp":"-30","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:59","sunset":"17:42","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-13"},{"id":"442","terrestrial_date":"2014-01-10","sol":"508","ls":"73","season":"Month 3","min_temp":"-83","max_temp":"-29","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:59","sunset":"17:42","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-11"},{"id":"440","terrestrial_date":"2014-01-09","sol":"507","ls":"73","season":"Month 3","min_temp":"-85","max_temp":"-25","pressure":"894","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:59","sunset":"17:42","local_uv_irradiance_index":"Moderate","min_gts_temp":"-90","max_gts_temp":"-10"},{"id":"439","terrestrial_date":"2014-01-08","sol":"506","ls":"73","season":"Month 3","min_temp":"-86","max_temp":"-27","pressure":"894","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:59","sunset":"17:43","local_uv_irradiance_index":"Moderate","min_gts_temp":"-90","max_gts_temp":"-9"},{"id":"438","terrestrial_date":"2014-01-06","sol":"505","ls":"72","season":"Month 3","min_temp":"-85","max_temp":"-29","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"17:43","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-8"},{"id":"436","terrestrial_date":"2014-01-05","sol":"504","ls":"72","season":"Month 3","min_temp":"-85","max_temp":"-29","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"17:43","local_uv_irradiance_index":"Moderate","min_gts_temp":"-90","max_gts_temp":"-9"},{"id":"483","terrestrial_date":"2014-01-04","sol":"503","ls":"71","season":"Month 3","min_temp":"-86","max_temp":"-28","pressure":"897","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"17:43","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-10"},{"id":"437","terrestrial_date":"2014-01-03","sol":"502","ls":"71","season":"Month 3","min_temp":"-87","max_temp":"-30","pressure":"898","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"17:44","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-8"},{"id":"435","terrestrial_date":"2014-01-02","sol":"501","ls":"70","season":"Month 3","min_temp":"-86","max_temp":"-28","pressure":"898","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"17:44","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-10"},{"id":"430","terrestrial_date":"2014-01-01","sol":"500","ls":"70","season":"Month 3","min_temp":"-85","max_temp":"-23","pressure":"897","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:01","sunset":"17:44","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-11"},{"id":"432","terrestrial_date":"2013-12-31","sol":"499","ls":"69","season":"Month 3","min_temp":"-84","max_temp":"-30","pressure":"899","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:01","sunset":"17:44","local_uv_irradiance_index":"Moderate","min_gts_temp":"-90","max_gts_temp":"-9"},{"id":"424","terrestrial_date":"2013-12-30","sol":"498","ls":"69","season":"Month 3","min_temp":"-86","max_temp":"-28","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:01","sunset":"17:45","local_uv_irradiance_index":"Moderate","min_gts_temp":"-90","max_gts_temp":"-10"},{"id":"425","terrestrial_date":"2013-12-29","sol":"497","ls":"69","season":"Month 3","min_temp":"-86","max_temp":"-30","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:01","sunset":"17:45","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-9"},{"id":"428","terrestrial_date":"2013-12-28","sol":"496","ls":"68","season":"Month 3","min_temp":"-85","max_temp":"-26","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:01","sunset":"17:45","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-10"},{"id":"431","terrestrial_date":"2013-12-27","sol":"495","ls":"68","season":"Month 3","min_temp":"-86","max_temp":"-26","pressure":"900","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:02","sunset":"17:45","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-10"},{"id":"429","terrestrial_date":"2013-12-26","sol":"494","ls":"67","season":"Month 3","min_temp":"-85","max_temp":"-24","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:02","sunset":"17:46","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-9"},{"id":"426","terrestrial_date":"2013-12-25","sol":"493","ls":"67","season":"Month 3","min_temp":"-84","max_temp":"-32","pressure":"902","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:02","sunset":"17:46","local_uv_irradiance_index":"Moderate","min_gts_temp":"-89","max_gts_temp":"-14"},{"id":"427","terrestrial_date":"2013-12-24","sol":"492","ls":"66","season":"Month 3","min_temp":"-86","max_temp":"-30","pressure":"903","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:02","sunset":"17:46","local_uv_irradiance_index":"Moderate","min_gts_temp":"-92","max_gts_temp":"-13"},{"id":"433","terrestrial_date":"2013-12-23","sol":"491","ls":"66","season":"Month 3","min_temp":"-86","max_temp":"-30","pressure":"903","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:02","sunset":"17:46","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-13"},{"id":"434","terrestrial_date":"2013-12-22","sol":"490","ls":"65","season":"Month 3","min_temp":"-87","max_temp":"-31","pressure":"903","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:03","sunset":"17:47","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-10"},{"id":"423","terrestrial_date":"2013-12-21","sol":"489","ls":"65","season":"Month 3","min_temp":"-85","max_temp":"-29","pressure":"904","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:03","sunset":"17:47","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-11"},{"id":"480","terrestrial_date":"2013-12-20","sol":"488","ls":"64","season":"Month 3","min_temp":"-87","max_temp":"-23","pressure":"903","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:03","sunset":"17:47","local_uv_irradiance_index":"Moderate","min_gts_temp":"-89","max_gts_temp":"-11"},{"id":"473","terrestrial_date":"2013-12-19","sol":"487","ls":"64","season":"Month 3","min_temp":"-85","max_temp":"-30","pressure":"904","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:03","sunset":"17:47","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-8"},{"id":"422","terrestrial_date":"2013-12-18","sol":"486","ls":"64","season":"Month 3","min_temp":"-84","max_temp":"-31","pressure":"904","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:03","sunset":"17:48","local_uv_irradiance_index":"Moderate","min_gts_temp":"-91","max_gts_temp":"-12"},{"id":"484","terrestrial_date":"2013-12-17","sol":"485","ls":"63","season":"Month 3","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:04","sunset":"17:48","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"485","terrestrial_date":"2013-12-10","sol":"478","ls":"60","season":"Month 3","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:05","sunset":"17:50","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"421","terrestrial_date":"2013-12-09","sol":"477","ls":"60","season":"Month 3","min_temp":"-85","max_temp":"-26","pressure":"907","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:05","sunset":"17:50","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"-9"},{"id":"418","terrestrial_date":"2013-12-08","sol":"476","ls":"59","season":"Month 2","min_temp":"-85","max_temp":"-25","pressure":"906","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:06","sunset":"17:51","local_uv_irradiance_index":"Moderate","min_gts_temp":"-90","max_gts_temp":"-7"},{"id":"419","terrestrial_date":"2013-12-07","sol":"475","ls":"59","season":"Month 2","min_temp":"-85","max_temp":"-28","pressure":"906","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:06","sunset":"17:51","local_uv_irradiance_index":"Moderate","min_gts_temp":"-93","max_gts_temp":"-9"},{"id":"420","terrestrial_date":"2013-12-06","sol":"474","ls":"58","season":"Month 2","min_temp":"-84","max_temp":"-26","pressure":"906","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:06","sunset":"17:51","local_uv_irradiance_index":"Moderate","min_gts_temp":"-95","max_gts_temp":"-9"},{"id":"417","terrestrial_date":"2013-12-05","sol":"473","ls":"58","season":"Month 2","min_temp":"-86","max_temp":"-29","pressure":"907","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:06","sunset":"17:52","local_uv_irradiance_index":"Moderate","min_gts_temp":"-90","max_gts_temp":"-8"},{"id":"416","terrestrial_date":"2013-12-04","sol":"472","ls":"57","season":"Month 2","min_temp":"-84","max_temp":"-31","pressure":"907","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:07","sunset":"17:52","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-10"},{"id":"479","terrestrial_date":"2013-12-03","sol":"471","ls":"57","season":"Month 2","min_temp":"-84","max_temp":"-26","pressure":"906","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:07","sunset":"17:52","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-12"},{"id":"475","terrestrial_date":"2013-12-02","sol":"470","ls":"56","season":"Month 2","min_temp":"-85","max_temp":"-26","pressure":"907","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:07","sunset":"17:53","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-9"},{"id":"413","terrestrial_date":"2013-11-30","sol":"469","ls":"56","season":"Month 2","min_temp":"-85","max_temp":"-29","pressure":"908","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:07","sunset":"17:53","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-12"},{"id":"414","terrestrial_date":"2013-11-29","sol":"468","ls":"55","season":"Month 2","min_temp":"-85","max_temp":"-29","pressure":"907","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:07","sunset":"17:53","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-14"},{"id":"411","terrestrial_date":"2013-11-28","sol":"467","ls":"55","season":"Month 2","min_temp":"-84","max_temp":"-28","pressure":"907","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:08","sunset":"17:54","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-11"},{"id":"415","terrestrial_date":"2013-11-27","sol":"466","ls":"55","season":"Month 2","min_temp":"-85","max_temp":"-26","pressure":"907","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:08","sunset":"17:54","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"-12"},{"id":"412","terrestrial_date":"2013-11-26","sol":"465","ls":"54","season":"Month 2","min_temp":"-85","max_temp":"-23","pressure":"906","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:08","sunset":"17:54","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"-13"},{"id":"410","terrestrial_date":"2013-11-25","sol":"464","ls":"54","season":"Month 2","min_temp":"-84","max_temp":"-26","pressure":"906","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:08","sunset":"17:55","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"-13"},{"id":"409","terrestrial_date":"2013-11-24","sol":"463","ls":"53","season":"Month 2","min_temp":"-86","max_temp":"-26","pressure":"906","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:09","sunset":"17:55","local_uv_irradiance_index":"High","min_gts_temp":"-88","max_gts_temp":"-13"},{"id":"408","terrestrial_date":"2013-11-23","sol":"462","ls":"53","season":"Month 2","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:09","sunset":"17:55","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"474","terrestrial_date":"2013-11-18","sol":"457","ls":"51","season":"Month 2","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:10","sunset":"17:57","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"406","terrestrial_date":"2013-11-17","sol":"456","ls":"50","season":"Month 2","min_temp":"-83","max_temp":"-26","pressure":"905","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:11","sunset":"17:57","local_uv_irradiance_index":"High","min_gts_temp":"-89","max_gts_temp":"-12"},{"id":"407","terrestrial_date":"2013-11-16","sol":"455","ls":"50","season":"Month 2","min_temp":"-84","max_temp":"-28","pressure":"905","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:11","sunset":"17:58","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"-12"},{"id":"478","terrestrial_date":"2013-11-15","sol":"454","ls":"49","season":"Month 2","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:11","sunset":"17:58","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"471","terrestrial_date":"2013-11-05","sol":"444","ls":"45","season":"Month 2","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:14","sunset":"18:02","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"403","terrestrial_date":"2013-11-04","sol":"443","ls":"44","season":"Month 2","min_temp":"-81","max_temp":"-24","pressure":"901","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:14","sunset":"18:02","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"-11"},{"id":"405","terrestrial_date":"2013-11-03","sol":"442","ls":"44","season":"Month 2","min_temp":"-80","max_temp":"-22","pressure":"900","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:14","sunset":"18:03","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"-9"},{"id":"402","terrestrial_date":"2013-11-02","sol":"441","ls":"43","season":"Month 2","min_temp":"-81","max_temp":"-23","pressure":"900","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:15","sunset":"18:03","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"-10"},{"id":"404","terrestrial_date":"2013-11-01","sol":"440","ls":"43","season":"Month 2","min_temp":"-80","max_temp":"-25","pressure":"899","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:15","sunset":"18:03","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"-11"},{"id":"401","terrestrial_date":"2013-10-31","sol":"439","ls":"42","season":"Month 2","min_temp":"-80","max_temp":"-21","pressure":"899","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:15","sunset":"18:04","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"-15"},{"id":"400","terrestrial_date":"2013-10-30","sol":"438","ls":"42","season":"Month 2","min_temp":"-79","max_temp":"-26","pressure":"899","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:15","sunset":"18:04","local_uv_irradiance_index":"Moderate","min_gts_temp":"-84","max_gts_temp":"-14"},{"id":"399","terrestrial_date":"2013-10-29","sol":"437","ls":"41","season":"Month 2","min_temp":"-82","max_temp":"-27","pressure":"898","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:16","sunset":"18:05","local_uv_irradiance_index":"Moderate","min_gts_temp":"-89","max_gts_temp":"-10"},{"id":"398","terrestrial_date":"2013-10-28","sol":"436","ls":"41","season":"Month 2","min_temp":"-81","max_temp":"-24","pressure":"897","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:16","sunset":"18:05","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-7"},{"id":"396","terrestrial_date":"2013-10-27","sol":"435","ls":"40","season":"Month 2","min_temp":"-81","max_temp":"-24","pressure":"896","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:16","sunset":"18:05","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"-9"},{"id":"397","terrestrial_date":"2013-10-26","sol":"434","ls":"40","season":"Month 2","min_temp":"-80","max_temp":"-25","pressure":"896","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:17","sunset":"18:06","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"-11"},{"id":"394","terrestrial_date":"2013-10-24","sol":"433","ls":"40","season":"Month 2","min_temp":"-81","max_temp":"-26","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:17","sunset":"18:06","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-9"},{"id":"395","terrestrial_date":"2013-10-23","sol":"432","ls":"39","season":"Month 2","min_temp":"-80","max_temp":"-26","pressure":"896","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:17","sunset":"18:06","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-9"},{"id":"389","terrestrial_date":"2013-10-22","sol":"431","ls":"39","season":"Month 2","min_temp":"-83","max_temp":"-24","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:18","sunset":"18:07","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-9"},{"id":"390","terrestrial_date":"2013-10-21","sol":"430","ls":"38","season":"Month 2","min_temp":"-82","max_temp":"-24","pressure":"896","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:18","sunset":"18:07","local_uv_irradiance_index":"Moderate","min_gts_temp":"-88","max_gts_temp":"-5"},{"id":"387","terrestrial_date":"2013-10-20","sol":"429","ls":"38","season":"Month 2","min_temp":"-82","max_temp":"-21","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:18","sunset":"18:08","local_uv_irradiance_index":"Moderate","min_gts_temp":"-86","max_gts_temp":"-5"},{"id":"391","terrestrial_date":"2013-10-19","sol":"428","ls":"37","season":"Month 2","min_temp":"-81","max_temp":"-23","pressure":"894","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:18","sunset":"18:08","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-6"},{"id":"392","terrestrial_date":"2013-10-18","sol":"427","ls":"37","season":"Month 2","min_temp":"-81","max_temp":"-21","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:19","sunset":"18:09","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-4"},{"id":"388","terrestrial_date":"2013-10-17","sol":"426","ls":"36","season":"Month 2","min_temp":"-79","max_temp":"-22","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:19","sunset":"18:09","local_uv_irradiance_index":"Moderate","min_gts_temp":"-89","max_gts_temp":"-5"},{"id":"393","terrestrial_date":"2013-10-16","sol":"425","ls":"36","season":"Month 2","min_temp":"-81","max_temp":"-21","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:19","sunset":"18:09","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-5"},{"id":"386","terrestrial_date":"2013-10-15","sol":"424","ls":"35","season":"Month 2","min_temp":"-81","max_temp":"-22","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:20","sunset":"18:10","local_uv_irradiance_index":"Moderate","min_gts_temp":"-82","max_gts_temp":"-4"},{"id":"383","terrestrial_date":"2013-10-14","sol":"423","ls":"35","season":"Month 2","min_temp":"-81","max_temp":"-24","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:20","sunset":"18:10","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-11"},{"id":"384","terrestrial_date":"2013-10-13","sol":"422","ls":"34","season":"Month 2","min_temp":"-82","max_temp":"-20","pressure":"891","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:20","sunset":"18:11","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-7"},{"id":"382","terrestrial_date":"2013-10-12","sol":"421","ls":"34","season":"Month 2","min_temp":"-81","max_temp":"-24","pressure":"890","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:20","sunset":"18:11","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"-7"},{"id":"385","terrestrial_date":"2013-10-11","sol":"420","ls":"33","season":"Month 2","min_temp":"-80","max_temp":"-19","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:21","sunset":"18:11","local_uv_irradiance_index":"High","min_gts_temp":"-86","max_gts_temp":"-7"},{"id":"381","terrestrial_date":"2013-10-10","sol":"419","ls":"33","season":"Month 2","min_temp":"-82","max_temp":"-24","pressure":"891","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:21","sunset":"18:12","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"-5"},{"id":"380","terrestrial_date":"2013-10-09","sol":"418","ls":"33","season":"Month 2","min_temp":"-79","max_temp":"-21","pressure":"891","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:21","sunset":"18:12","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"-3"},{"id":"379","terrestrial_date":"2013-10-08","sol":"417","ls":"32","season":"Month 2","min_temp":"-82","max_temp":"-21","pressure":"890","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:22","sunset":"18:13","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"-2"},{"id":"378","terrestrial_date":"2013-10-07","sol":"416","ls":"32","season":"Month 2","min_temp":"-79","max_temp":"-18","pressure":"889","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:22","sunset":"18:13","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"-6"},{"id":"377","terrestrial_date":"2013-10-06","sol":"415","ls":"31","season":"Month 2","min_temp":"-82","max_temp":"-19","pressure":"890","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:22","sunset":"18:14","local_uv_irradiance_index":"High","min_gts_temp":"-86","max_gts_temp":"-4"},{"id":"375","terrestrial_date":"2013-10-05","sol":"414","ls":"31","season":"Month 2","min_temp":"-79","max_temp":"-18","pressure":"889","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:23","sunset":"18:14","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"-4"},{"id":"376","terrestrial_date":"2013-10-04","sol":"413","ls":"30","season":"Month 2","min_temp":"-82","max_temp":"-22","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:23","sunset":"18:14","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"-2"},{"id":"371","terrestrial_date":"2013-10-03","sol":"412","ls":"30","season":"Month 2","min_temp":"-80","max_temp":"-22","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:23","sunset":"18:15","local_uv_irradiance_index":"Moderate","min_gts_temp":"-79","max_gts_temp":"-2"},{"id":"372","terrestrial_date":"2013-10-02","sol":"411","ls":"29","season":"Month 1","min_temp":"-82","max_temp":"-17","pressure":"887","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:24","sunset":"18:15","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-8"},{"id":"373","terrestrial_date":"2013-10-01","sol":"410","ls":"29","season":"Month 1","min_temp":"-81","max_temp":"-14","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:24","sunset":"18:16","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"-7"},{"id":"368","terrestrial_date":"2013-09-30","sol":"409","ls":"28","season":"Month 1","min_temp":"-81","max_temp":"-17","pressure":"887","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:24","sunset":"18:16","local_uv_irradiance_index":"Moderate","min_gts_temp":"-95","max_gts_temp":"-2"},{"id":"369","terrestrial_date":"2013-09-29","sol":"408","ls":"28","season":"Month 1","min_temp":"-80","max_temp":"-16","pressure":"887","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:24","sunset":"18:17","local_uv_irradiance_index":"Moderate","min_gts_temp":"-95","max_gts_temp":"0"},{"id":"370","terrestrial_date":"2013-09-28","sol":"407","ls":"27","season":"Month 1","min_temp":"-81","max_temp":"-17","pressure":"887","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:25","sunset":"18:17","local_uv_irradiance_index":"Moderate","min_gts_temp":"-94","max_gts_temp":"0"},{"id":"374","terrestrial_date":"2013-09-27","sol":"406","ls":"27","season":"Month 1","min_temp":"-81","max_temp":"-15","pressure":"886","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:25","sunset":"18:17","local_uv_irradiance_index":"High","min_gts_temp":"-86","max_gts_temp":"1"},{"id":"366","terrestrial_date":"2013-09-26","sol":"405","ls":"26","season":"Month 1","min_temp":"-82","max_temp":"-25","pressure":"885","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:25","sunset":"18:18","local_uv_irradiance_index":"Moderate","min_gts_temp":"-87","max_gts_temp":"-6"},{"id":"367","terrestrial_date":"2013-09-25","sol":"404","ls":"26","season":"Month 1","min_temp":"-78","max_temp":"-20","pressure":"884","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:26","sunset":"18:18","local_uv_irradiance_index":"Moderate","min_gts_temp":"-85","max_gts_temp":"-6"},{"id":"364","terrestrial_date":"2013-09-24","sol":"403","ls":"25","season":"Month 1","min_temp":"-80","max_temp":"-18","pressure":"883","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:26","sunset":"18:19","local_uv_irradiance_index":"High","min_gts_temp":"-89","max_gts_temp":"-5"},{"id":"365","terrestrial_date":"2013-09-23","sol":"402","ls":"25","season":"Month 1","min_temp":"-78","max_temp":"-18","pressure":"883","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:26","sunset":"18:19","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"-3"},{"id":"362","terrestrial_date":"2013-09-22","sol":"401","ls":"25","season":"Month 1","min_temp":"-79","max_temp":"-15","pressure":"882","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:27","sunset":"18:20","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"-5"},{"id":"363","terrestrial_date":"2013-09-21","sol":"400","ls":"24","season":"Month 1","min_temp":"-79","max_temp":"-16","pressure":"881","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:27","sunset":"18:20","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"-6"},{"id":"361","terrestrial_date":"2013-09-20","sol":"399","ls":"24","season":"Month 1","min_temp":"-79","max_temp":"-16","pressure":"881","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:27","sunset":"18:20","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"-4"},{"id":"360","terrestrial_date":"2013-09-19","sol":"398","ls":"23","season":"Month 1","min_temp":"-79","max_temp":"-14","pressure":"880","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:28","sunset":"18:21","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"-6"},{"id":"359","terrestrial_date":"2013-09-18","sol":"397","ls":"23","season":"Month 1","min_temp":"-75","max_temp":"-15","pressure":"880","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:28","sunset":"18:21","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"-7"},{"id":"358","terrestrial_date":"2013-09-16","sol":"396","ls":"22","season":"Month 1","min_temp":"-78","max_temp":"-15","pressure":"879","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:28","sunset":"18:22","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"-5"},{"id":"357","terrestrial_date":"2013-09-15","sol":"395","ls":"22","season":"Month 1","min_temp":"-77","max_temp":"-20","pressure":"878","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:28","sunset":"18:22","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"-5"},{"id":"356","terrestrial_date":"2013-09-14","sol":"394","ls":"21","season":"Month 1","min_temp":"-79","max_temp":"-18","pressure":"878","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:29","sunset":"18:23","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"-4"},{"id":"355","terrestrial_date":"2013-09-13","sol":"393","ls":"21","season":"Month 1","min_temp":"-76","max_temp":"-18","pressure":"877","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:29","sunset":"18:23","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-5"},{"id":"354","terrestrial_date":"2013-09-12","sol":"392","ls":"20","season":"Month 1","min_temp":"-77","max_temp":"-17","pressure":"876","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:29","sunset":"18:23","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"-4"},{"id":"353","terrestrial_date":"2013-09-11","sol":"391","ls":"20","season":"Month 1","min_temp":"-78","max_temp":"-17","pressure":"875","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:30","sunset":"18:24","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"-9"},{"id":"352","terrestrial_date":"2013-09-10","sol":"390","ls":"19","season":"Month 1","min_temp":"-78","max_temp":"-16","pressure":"875","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:30","sunset":"18:24","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"-1"},{"id":"348","terrestrial_date":"2013-09-09","sol":"389","ls":"19","season":"Month 1","min_temp":"-79","max_temp":"-14","pressure":"875","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:30","sunset":"18:25","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-7"},{"id":"350","terrestrial_date":"2013-09-08","sol":"388","ls":"18","season":"Month 1","min_temp":"-79","max_temp":"-13","pressure":"875","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:31","sunset":"18:25","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"-6"},{"id":"349","terrestrial_date":"2013-09-07","sol":"387","ls":"18","season":"Month 1","min_temp":"-78","max_temp":"-13","pressure":"874","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:31","sunset":"18:26","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-7"},{"id":"347","terrestrial_date":"2013-09-06","sol":"386","ls":"17","season":"Month 1","min_temp":"-77","max_temp":"-12","pressure":"873","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:31","sunset":"18:26","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-7"},{"id":"351","terrestrial_date":"2013-09-05","sol":"385","ls":"17","season":"Month 1","min_temp":"-78","max_temp":"-12","pressure":"874","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:31","sunset":"18:26","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"-3"},{"id":"346","terrestrial_date":"2013-09-04","sol":"384","ls":"16","season":"Month 1","min_temp":"-77","max_temp":"-12","pressure":"875","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:32","sunset":"18:27","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"-4"},{"id":"342","terrestrial_date":"2013-09-03","sol":"383","ls":"16","season":"Month 1","min_temp":"-77","max_temp":"-12","pressure":"874","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:32","sunset":"18:27","local_uv_irradiance_index":"Moderate","min_gts_temp":"-81","max_gts_temp":"-6"},{"id":"344","terrestrial_date":"2013-09-02","sol":"382","ls":"15","season":"Month 1","min_temp":"-76","max_temp":"-14","pressure":"872","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:32","sunset":"18:28","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"-4"},{"id":"345","terrestrial_date":"2013-09-01","sol":"381","ls":"15","season":"Month 1","min_temp":"-79","max_temp":"-13","pressure":"871","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:33","sunset":"18:28","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"-4"},{"id":"343","terrestrial_date":"2013-08-31","sol":"380","ls":"14","season":"Month 1","min_temp":"-79","max_temp":"-13","pressure":"870","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:33","sunset":"18:29","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"-4"},{"id":"341","terrestrial_date":"2013-08-30","sol":"379","ls":"14","season":"Month 1","min_temp":"-79","max_temp":"-12","pressure":"870","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:33","sunset":"18:29","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"-2"},{"id":"339","terrestrial_date":"2013-08-29","sol":"378","ls":"13","season":"Month 1","min_temp":"-78","max_temp":"-18","pressure":"869","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:33","sunset":"18:29","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"-4"},{"id":"338","terrestrial_date":"2013-08-28","sol":"377","ls":"13","season":"Month 1","min_temp":"-78","max_temp":"-12","pressure":"870","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:34","sunset":"18:30","local_uv_irradiance_index":"High","min_gts_temp":"-86","max_gts_temp":"2"},{"id":"340","terrestrial_date":"2013-08-27","sol":"376","ls":"12","season":"Month 1","min_temp":"-78","max_temp":"-11","pressure":"870","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:34","sunset":"18:30","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"-2"},{"id":"336","terrestrial_date":"2013-08-26","sol":"375","ls":"12","season":"Month 1","min_temp":"-77","max_temp":"-9","pressure":"867","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:34","sunset":"18:31","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"-1"},{"id":"337","terrestrial_date":"2013-08-25","sol":"374","ls":"11","season":"Month 1","min_temp":"-79","max_temp":"-9","pressure":"866","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:35","sunset":"18:31","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"0"},{"id":"335","terrestrial_date":"2013-08-24","sol":"373","ls":"11","season":"Month 1","min_temp":"-79","max_temp":"-8","pressure":"866","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:35","sunset":"18:32","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"0"},{"id":"334","terrestrial_date":"2013-08-23","sol":"372","ls":"10","season":"Month 1","min_temp":"-76","max_temp":"-9","pressure":"866","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:35","sunset":"18:32","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"2"},{"id":"333","terrestrial_date":"2013-08-22","sol":"371","ls":"10","season":"Month 1","min_temp":"-77","max_temp":"-11","pressure":"865","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:35","sunset":"18:32","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"-3"},{"id":"332","terrestrial_date":"2013-08-21","sol":"370","ls":"9","season":"Month 1","min_temp":"-79","max_temp":"-9","pressure":"865","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:36","sunset":"18:33","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"-1"},{"id":"331","terrestrial_date":"2013-08-20","sol":"369","ls":"9","season":"Month 1","min_temp":"-75","max_temp":"-9","pressure":"865","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:36","sunset":"18:33","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"3"},{"id":"330","terrestrial_date":"2013-08-19","sol":"368","ls":"8","season":"Month 1","min_temp":"-77","max_temp":"-9","pressure":"863","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:36","sunset":"18:34","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"-3"},{"id":"328","terrestrial_date":"2013-08-18","sol":"367","ls":"8","season":"Month 1","min_temp":"-76","max_temp":"-9","pressure":"862","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:37","sunset":"18:34","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"-2"},{"id":"326","terrestrial_date":"2013-08-17","sol":"366","ls":"7","season":"Month 1","min_temp":"-76","max_temp":"-12","pressure":"861","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:37","sunset":"18:34","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"-3"},{"id":"329","terrestrial_date":"2013-08-16","sol":"365","ls":"7","season":"Month 1","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:37","sunset":"18:35","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"327","terrestrial_date":"2013-08-08","sol":"358","ls":"3","season":"Month 1","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:39","sunset":"18:38","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"325","terrestrial_date":"2013-08-07","sol":"357","ls":"3","season":"Month 1","min_temp":"-76","max_temp":"-7","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:39","sunset":"18:38","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-1"},{"id":"324","terrestrial_date":"2013-08-06","sol":"356","ls":"2","season":"Month 1","min_temp":"-77","max_temp":"-7","pressure":"856","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:39","sunset":"18:38","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"-1"},{"id":"321","terrestrial_date":"2013-08-05","sol":"355","ls":"2","season":"Month 1","min_temp":"-75","max_temp":"-7","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:39","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"0"},{"id":"322","terrestrial_date":"2013-08-04","sol":"354","ls":"1","season":"Month 1","min_temp":"-75","max_temp":"-13","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:39","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"-1"},{"id":"323","terrestrial_date":"2013-08-03","sol":"353","ls":"1","season":"Month 1","min_temp":"-75","max_temp":"-8","pressure":"855","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:39","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"-4"},{"id":"319","terrestrial_date":"2013-08-02","sol":"352","ls":"0","season":"Month 1","min_temp":"-77","max_temp":"-9","pressure":"854","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:40","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"-3"},{"id":"320","terrestrial_date":"2013-08-01","sol":"351","ls":"0","season":"Month 1","min_temp":"-75","max_temp":"-12","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:40","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"-4"},{"id":"318","terrestrial_date":"2013-07-31","sol":"350","ls":"359","season":"Month 12","min_temp":"-76","max_temp":"-6","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:41","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"0"},{"id":"316","terrestrial_date":"2013-07-30","sol":"349","ls":"359","season":"Month 12","min_temp":"-75","max_temp":"-12","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:41","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"-1"},{"id":"315","terrestrial_date":"2013-07-29","sol":"348","ls":"358","season":"Month 12","min_temp":"-74","max_temp":"-8","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:41","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"1"},{"id":"313","terrestrial_date":"2013-07-28","sol":"347","ls":"358","season":"Month 12","min_temp":"-77","max_temp":"-9","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:41","sunset":"18:42","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"2"},{"id":"314","terrestrial_date":"2013-07-27","sol":"346","ls":"357","season":"Month 12","min_temp":"-76","max_temp":"-7","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:42","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"1"},{"id":"312","terrestrial_date":"2013-07-26","sol":"345","ls":"357","season":"Month 12","min_temp":"-77","max_temp":"-7","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:42","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"3"},{"id":"317","terrestrial_date":"2013-07-25","sol":"344","ls":"356","season":"Month 12","min_temp":"-77","max_temp":"-6","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:43","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"2"},{"id":"311","terrestrial_date":"2013-07-24","sol":"343","ls":"356","season":"Month 12","min_temp":"-77","max_temp":"-11","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:43","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"2"},{"id":"309","terrestrial_date":"2013-07-23","sol":"342","ls":"355","season":"Month 12","min_temp":"-76","max_temp":"-7","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:43","local_uv_irradiance_index":"High","min_gts_temp":"-84","max_gts_temp":"2"},{"id":"310","terrestrial_date":"2013-07-22","sol":"341","ls":"355","season":"Month 12","min_temp":"-77","max_temp":"-6","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:44","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"4"},{"id":"307","terrestrial_date":"2013-07-21","sol":"340","ls":"354","season":"Month 12","min_temp":"-76","max_temp":"-6","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:44","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"5"},{"id":"308","terrestrial_date":"2013-07-20","sol":"339","ls":"354","season":"Month 12","min_temp":"-76","max_temp":"-8","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:44","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"3"},{"id":"306","terrestrial_date":"2013-07-19","sol":"338","ls":"353","season":"Month 12","min_temp":"-78","max_temp":"-7","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:45","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"3"},{"id":"304","terrestrial_date":"2013-07-18","sol":"337","ls":"353","season":"Month 12","min_temp":"-75","max_temp":"-7","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:45","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"3"},{"id":"305","terrestrial_date":"2013-07-17","sol":"336","ls":"352","season":"Month 12","min_temp":"-76","max_temp":"-8","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:45","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"4"},{"id":"302","terrestrial_date":"2013-07-16","sol":"335","ls":"352","season":"Month 12","min_temp":"-76","max_temp":"-7","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:46","local_uv_irradiance_index":"High","min_gts_temp":"-81","max_gts_temp":"5"},{"id":"301","terrestrial_date":"2013-07-15","sol":"334","ls":"351","season":"Month 12","min_temp":"-74","max_temp":"-6","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:46","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"1"},{"id":"299","terrestrial_date":"2013-07-14","sol":"333","ls":"350","season":"Month 12","min_temp":"-75","max_temp":"-5","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:46","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"2"},{"id":"300","terrestrial_date":"2013-07-13","sol":"332","ls":"350","season":"Month 12","min_temp":"-76","max_temp":"-5","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:47","local_uv_irradiance_index":"High","min_gts_temp":"-83","max_gts_temp":"4"},{"id":"303","terrestrial_date":"2013-07-12","sol":"331","ls":"349","season":"Month 12","min_temp":"-74","max_temp":"-3","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:47","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"6"},{"id":"297","terrestrial_date":"2013-07-11","sol":"330","ls":"349","season":"Month 12","min_temp":"-75","max_temp":"-5","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:47","local_uv_irradiance_index":"High","min_gts_temp":"-85","max_gts_temp":"8"},{"id":"298","terrestrial_date":"2013-07-10","sol":"329","ls":"348","season":"Month 12","min_temp":"-74","max_temp":"-7","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:48","local_uv_irradiance_index":"High","min_gts_temp":"-87","max_gts_temp":"7"},{"id":"293","terrestrial_date":"2013-07-09","sol":"328","ls":"348","season":"Month 12","min_temp":"-75","max_temp":"-5","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:48","local_uv_irradiance_index":"High","min_gts_temp":"-86","max_gts_temp":"8"},{"id":"296","terrestrial_date":"2013-07-08","sol":"327","ls":"347","season":"Month 12","min_temp":"-74","max_temp":"-8","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:48","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"7"},{"id":"295","terrestrial_date":"2013-07-07","sol":"326","ls":"347","season":"Month 12","min_temp":"-72","max_temp":"-5","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:48","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"5"},{"id":"294","terrestrial_date":"2013-07-06","sol":"325","ls":"346","season":"Month 12","min_temp":"-74","max_temp":"-8","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:49","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"8"},{"id":"292","terrestrial_date":"2013-07-04","sol":"324","ls":"346","season":"Month 12","min_temp":"-75","max_temp":"-8","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:49","local_uv_irradiance_index":"High","min_gts_temp":"-79","max_gts_temp":"8"},{"id":"290","terrestrial_date":"2013-07-03","sol":"323","ls":"345","season":"Month 12","min_temp":"-74","max_temp":"-6","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:49","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"4"},{"id":"291","terrestrial_date":"2013-07-02","sol":"322","ls":"345","season":"Month 12","min_temp":"-74","max_temp":"-5","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:50","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"3"},{"id":"289","terrestrial_date":"2013-07-01","sol":"321","ls":"344","season":"Month 12","min_temp":"-75","max_temp":"-5","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:50","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"3"},{"id":"269","terrestrial_date":"2013-06-30","sol":"320","ls":"344","season":"Month 12","min_temp":"-74","max_temp":"-4","pressure":"846","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:50","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"3"},{"id":"271","terrestrial_date":"2013-06-29","sol":"319","ls":"343","season":"Month 12","min_temp":"-73","max_temp":"-3","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:50","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"4"},{"id":"270","terrestrial_date":"2013-06-28","sol":"318","ls":"342","season":"Month 12","min_temp":"-74","max_temp":"-4","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:51","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"3"},{"id":"268","terrestrial_date":"2013-06-27","sol":"317","ls":"342","season":"Month 12","min_temp":"-72","max_temp":"-4","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:51","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"2"},{"id":"288","terrestrial_date":"2013-06-26","sol":"316","ls":"341","season":"Month 12","min_temp":"-74","max_temp":"-16","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:51","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"2"},{"id":"273","terrestrial_date":"2013-06-25","sol":"315","ls":"341","season":"Month 12","min_temp":"-74","max_temp":"-10","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:51","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"3"},{"id":"272","terrestrial_date":"2013-06-24","sol":"314","ls":"340","season":"Month 12","min_temp":"-73","max_temp":"-11","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:51","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"2"},{"id":"274","terrestrial_date":"2013-06-23","sol":"313","ls":"340","season":"Month 12","min_temp":"-77","max_temp":"-14","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:52","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"2"},{"id":"285","terrestrial_date":"2013-06-22","sol":"312","ls":"339","season":"Month 12","min_temp":"-71","max_temp":"-11","pressure":"845","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:52","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"-1"},{"id":"277","terrestrial_date":"2013-06-21","sol":"311","ls":"339","season":"Month 12","min_temp":"-74","max_temp":"-8","pressure":"846","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:52","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"-2"},{"id":"278","terrestrial_date":"2013-06-20","sol":"310","ls":"338","season":"Month 12","min_temp":"-71","max_temp":"-9","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:52","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"-2"},{"id":"284","terrestrial_date":"2013-06-19","sol":"309","ls":"338","season":"Month 12","min_temp":"-72","max_temp":"-7","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:52","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"-2"},{"id":"282","terrestrial_date":"2013-06-18","sol":"308","ls":"337","season":"Month 12","min_temp":"-73","max_temp":"-5","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:53","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"-1"},{"id":"279","terrestrial_date":"2013-06-17","sol":"307","ls":"336","season":"Month 12","min_temp":"-72","max_temp":"-8","pressure":"851","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:53","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"-3"},{"id":"280","terrestrial_date":"2013-06-16","sol":"306","ls":"336","season":"Month 12","min_temp":"-71","max_temp":"-8","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:53","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"2"},{"id":"275","terrestrial_date":"2013-06-15","sol":"305","ls":"335","season":"Month 12","min_temp":"-71","max_temp":"-5","pressure":"847","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:53","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"1"},{"id":"281","terrestrial_date":"2013-06-14","sol":"304","ls":"335","season":"Month 12","min_temp":"-70","max_temp":"-6","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:53","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"1"},{"id":"283","terrestrial_date":"2013-06-13","sol":"303","ls":"334","season":"Month 12","min_temp":"-71","max_temp":"-8","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:53","local_uv_irradiance_index":"High","min_gts_temp":"-74","max_gts_temp":"1"},{"id":"287","terrestrial_date":"2013-06-12","sol":"302","ls":"334","season":"Month 12","min_temp":"-71","max_temp":"-3","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"1"},{"id":"276","terrestrial_date":"2013-06-11","sol":"301","ls":"333","season":"Month 12","min_temp":"-73","max_temp":"-6","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"-4"},{"id":"286","terrestrial_date":"2013-06-10","sol":"300","ls":"333","season":"Month 12","min_temp":"-72","max_temp":"-8","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"-2"},{"id":"267","terrestrial_date":"2013-06-09","sol":"299","ls":"332","season":"Month 12","min_temp":"-71","max_temp":"-8","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-75","max_gts_temp":"-1"},{"id":"266","terrestrial_date":"2013-06-08","sol":"298","ls":"331","season":"Month 12","min_temp":"-72","max_temp":"-3","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-76","max_gts_temp":"3"},{"id":"265","terrestrial_date":"2013-06-07","sol":"297","ls":"331","season":"Month 12","min_temp":"-72","max_temp":"-7","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:47","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"2"},{"id":"264","terrestrial_date":"2013-06-06","sol":"296","ls":"330","season":"Month 12","min_temp":"-71","max_temp":"-9","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"1"},{"id":"263","terrestrial_date":"2013-06-05","sol":"295","ls":"330","season":"Month 12","min_temp":"-71","max_temp":"-15","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"-1"},{"id":"262","terrestrial_date":"2013-06-04","sol":"294","ls":"329","season":"Month 11","min_temp":"-72","max_temp":"-4","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"-1"},{"id":"261","terrestrial_date":"2013-06-03","sol":"293","ls":"329","season":"Month 11","min_temp":"-72","max_temp":"-4","pressure":"850","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"0"},{"id":"260","terrestrial_date":"2013-06-02","sol":"292","ls":"328","season":"Month 11","min_temp":"-71","max_temp":"-1","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"-1"},{"id":"259","terrestrial_date":"2013-06-01","sol":"291","ls":"327","season":"Month 11","min_temp":"-70","max_temp":"-4","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"0"},{"id":"258","terrestrial_date":"2013-05-31","sol":"290","ls":"327","season":"Month 11","min_temp":"-71","max_temp":"-3","pressure":"853","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"0"},{"id":"257","terrestrial_date":"2013-05-30","sol":"289","ls":"326","season":"Month 11","min_temp":"-71","max_temp":"-3","pressure":"854","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"0"},{"id":"256","terrestrial_date":"2013-05-29","sol":"288","ls":"326","season":"Month 11","min_temp":"-69","max_temp":"-4","pressure":"854","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"0"},{"id":"255","terrestrial_date":"2013-05-27","sol":"287","ls":"325","season":"Month 11","min_temp":"-72","max_temp":"-3","pressure":"856","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"-1"},{"id":"254","terrestrial_date":"2013-05-26","sol":"286","ls":"325","season":"Month 11","min_temp":"-71","max_temp":"-2","pressure":"854","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:46","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"-1"},{"id":"253","terrestrial_date":"2013-05-25","sol":"285","ls":"324","season":"Month 11","min_temp":"-70","max_temp":"-5","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"0"},{"id":"252","terrestrial_date":"2013-05-24","sol":"284","ls":"323","season":"Month 11","min_temp":"-71","max_temp":"-3","pressure":"854","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"-1"},{"id":"251","terrestrial_date":"2013-05-23","sol":"283","ls":"323","season":"Month 11","min_temp":"-68","max_temp":"-4","pressure":"854","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"1"},{"id":"250","terrestrial_date":"2013-05-22","sol":"282","ls":"322","season":"Month 11","min_temp":"-72","max_temp":"-2","pressure":"856","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"-1"},{"id":"249","terrestrial_date":"2013-05-21","sol":"281","ls":"322","season":"Month 11","min_temp":"-68","max_temp":"-2","pressure":"855","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"0"},{"id":"248","terrestrial_date":"2013-05-20","sol":"280","ls":"321","season":"Month 11","min_temp":"-69","max_temp":"-4","pressure":"856","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"0"},{"id":"247","terrestrial_date":"2013-05-19","sol":"279","ls":"321","season":"Month 11","min_temp":"-68","max_temp":"-5","pressure":"856","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:45","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-68","max_gts_temp":"-1"},{"id":"246","terrestrial_date":"2013-05-18","sol":"278","ls":"320","season":"Month 11","min_temp":"-67","max_temp":"-3","pressure":"855","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-67","max_gts_temp":"-1"},{"id":"245","terrestrial_date":"2013-05-17","sol":"277","ls":"319","season":"Month 11","min_temp":"-69","max_temp":"-4","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"-1"},{"id":"244","terrestrial_date":"2013-05-16","sol":"276","ls":"319","season":"Month 11","min_temp":"-69","max_temp":"-4","pressure":"858","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:55","local_uv_irradiance_index":"Moderate","min_gts_temp":"-71","max_gts_temp":"0"},{"id":"169","terrestrial_date":"2013-05-15","sol":"275","ls":"318","season":"Month 11","min_temp":"-67","max_temp":"-6","pressure":"860","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-68","max_gts_temp":"-1"},{"id":"168","terrestrial_date":"2013-05-14","sol":"274","ls":"318","season":"Month 11","min_temp":"-70","max_temp":"-2","pressure":"861","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:44","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-68","max_gts_temp":"-1"},{"id":"167","terrestrial_date":"2013-05-13","sol":"273","ls":"317","season":"Month 11","min_temp":"-70","max_temp":"-4","pressure":"861","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:55","local_uv_irradiance_index":"High","min_gts_temp":"-67","max_gts_temp":"-1"},{"id":"166","terrestrial_date":"2013-05-12","sol":"272","ls":"316","season":"Month 11","min_temp":"-71","max_temp":"-5","pressure":"864","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"-1"},{"id":"165","terrestrial_date":"2013-05-11","sol":"271","ls":"316","season":"Month 11","min_temp":"-69","max_temp":"-6","pressure":"864","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"2"},{"id":"164","terrestrial_date":"2013-05-10","sol":"270","ls":"315","season":"Month 11","min_temp":"-67","max_temp":"-6","pressure":"863","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:43","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"2"},{"id":"162","terrestrial_date":"2013-05-09","sol":"269","ls":"315","season":"Month 11","min_temp":"-72","max_temp":"-3","pressure":"866","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"2"},{"id":"161","terrestrial_date":"2013-05-08","sol":"268","ls":"314","season":"Month 11","min_temp":"-70","max_temp":"-5","pressure":"864","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:54","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"2"},{"id":"160","terrestrial_date":"2013-05-07","sol":"267","ls":"313","season":"Month 11","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:42","sunset":"18:54","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"159","terrestrial_date":"2013-05-02","sol":"262","ls":"311","season":"Month 11","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:53","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"158","terrestrial_date":"2013-05-01","sol":"261","ls":"310","season":"Month 11","min_temp":"-70","max_temp":"-4","pressure":"868","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:53","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"4"},{"id":"157","terrestrial_date":"2013-04-30","sol":"260","ls":"309","season":"Month 11","min_temp":"-70","max_temp":"-11","pressure":"875","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:40","sunset":"18:53","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"2"},{"id":"155","terrestrial_date":"2013-04-29","sol":"259","ls":"309","season":"Month 11","min_temp":"-72","max_temp":"-3","pressure":"871","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:39","sunset":"18:52","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"6"},{"id":"154","terrestrial_date":"2013-04-28","sol":"258","ls":"308","season":"Month 11","min_temp":"-71","max_temp":"-9","pressure":"869","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:39","sunset":"18:52","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"6"},{"id":"153","terrestrial_date":"2013-04-27","sol":"257","ls":"308","season":"Month 11","min_temp":"-70","max_temp":"-1","pressure":"871","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:39","sunset":"18:52","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"5"},{"id":"152","terrestrial_date":"2013-04-26","sol":"256","ls":"307","season":"Month 11","min_temp":"-70","max_temp":"-2","pressure":"871","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:38","sunset":"18:52","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"5"},{"id":"151","terrestrial_date":"2013-04-25","sol":"255","ls":"306","season":"Month 11","min_temp":"-69","max_temp":"-5","pressure":"877","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:38","sunset":"18:51","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"6"},{"id":"150","terrestrial_date":"2013-04-24","sol":"254","ls":"306","season":"Month 11","min_temp":"-70","max_temp":"-3","pressure":"871","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:37","sunset":"18:51","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"4"},{"id":"149","terrestrial_date":"2013-04-23","sol":"253","ls":"305","season":"Month 11","min_temp":"-71","max_temp":"-6","pressure":"877","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:37","sunset":"18:51","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"5"},{"id":"148","terrestrial_date":"2013-04-22","sol":"252","ls":"304","season":"Month 11","min_temp":"-71","max_temp":"-8","pressure":"874","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:37","sunset":"18:51","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"5"},{"id":"147","terrestrial_date":"2013-04-20","sol":"251","ls":"304","season":"Month 11","min_temp":"-71","max_temp":"-2","pressure":"876","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:36","sunset":"18:50","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"7"},{"id":"146","terrestrial_date":"2013-04-19","sol":"250","ls":"303","season":"Month 11","min_temp":"-70","max_temp":"-2","pressure":"877","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:36","sunset":"18:50","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"5"},{"id":"144","terrestrial_date":"2013-04-18","sol":"249","ls":"303","season":"Month 11","min_temp":"-69","max_temp":"-3","pressure":"873","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:35","sunset":"18:50","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"5"},{"id":"143","terrestrial_date":"2013-04-17","sol":"248","ls":"302","season":"Month 11","min_temp":"-70","max_temp":"-4","pressure":"877","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:35","sunset":"18:49","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"3"},{"id":"142","terrestrial_date":"2013-04-16","sol":"247","ls":"301","season":"Month 11","min_temp":"-71","max_temp":"-4","pressure":"873","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:35","sunset":"18:49","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"6"},{"id":"141","terrestrial_date":"2013-04-15","sol":"246","ls":"301","season":"Month 11","min_temp":"-73","max_temp":"-1","pressure":"878","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:34","sunset":"18:49","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"6"},{"id":"140","terrestrial_date":"2013-04-14","sol":"245","ls":"300","season":"Month 11","min_temp":"-70","max_temp":"-6","pressure":"879","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:34","sunset":"18:48","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"6"},{"id":"139","terrestrial_date":"2013-04-13","sol":"244","ls":"300","season":"Month 11","min_temp":"-69","max_temp":"-6","pressure":"878","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:33","sunset":"18:48","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"7"},{"id":"138","terrestrial_date":"2013-04-12","sol":"243","ls":"299","season":"Month 10","min_temp":"-71","max_temp":"-7","pressure":"884","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:33","sunset":"18:48","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"6"},{"id":"137","terrestrial_date":"2013-04-11","sol":"242","ls":"298","season":"Month 10","min_temp":"-70","max_temp":"-7","pressure":"881","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:32","sunset":"18:47","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"6"},{"id":"136","terrestrial_date":"2013-04-10","sol":"241","ls":"298","season":"Month 10","min_temp":"-72","max_temp":"0","pressure":"884","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:32","sunset":"18:47","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"5"},{"id":"135","terrestrial_date":"2013-04-09","sol":"240","ls":"297","season":"Month 10","min_temp":"-70","max_temp":"-6","pressure":"884","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:31","sunset":"18:47","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"5"},{"id":"133","terrestrial_date":"2013-04-08","sol":"239","ls":"297","season":"Month 10","min_temp":"-73","max_temp":"-1","pressure":"885","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:31","sunset":"18:46","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"5"},{"id":"132","terrestrial_date":"2013-04-07","sol":"238","ls":"296","season":"Month 10","min_temp":"-70","max_temp":"-2","pressure":"885","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:30","sunset":"18:46","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"7"},{"id":"131","terrestrial_date":"2013-04-06","sol":"237","ls":"295","season":"Month 10","min_temp":"-71","max_temp":"-5","pressure":"883","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:30","sunset":"18:45","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"6"},{"id":"130","terrestrial_date":"2013-04-05","sol":"236","ls":"295","season":"Month 10","min_temp":"-72","max_temp":"-3","pressure":"886","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:29","sunset":"18:45","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"6"},{"id":"129","terrestrial_date":"2013-04-04","sol":"235","ls":"294","season":"Month 10","min_temp":"-70","max_temp":"0","pressure":"886","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:29","sunset":"18:44","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"7"},{"id":"128","terrestrial_date":"2013-04-03","sol":"234","ls":"293","season":"Month 10","min_temp":"-69","max_temp":"-4","pressure":"890","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:28","sunset":"18:44","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"5"},{"id":"127","terrestrial_date":"2013-04-02","sol":"233","ls":"293","season":"Month 10","min_temp":"-69","max_temp":"-3","pressure":"889","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:28","sunset":"18:44","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"6"},{"id":"126","terrestrial_date":"2013-04-01","sol":"232","ls":"292","season":"Month 10","min_temp":"-69","max_temp":"-5","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:27","sunset":"18:43","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"6"},{"id":"125","terrestrial_date":"2013-03-31","sol":"231","ls":"292","season":"Month 10","min_temp":"-71","max_temp":"-6","pressure":"890","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:26","sunset":"18:43","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"7"},{"id":"124","terrestrial_date":"2013-03-30","sol":"230","ls":"291","season":"Month 10","min_temp":"-69","max_temp":"0","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:26","sunset":"18:42","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"7"},{"id":"122","terrestrial_date":"2013-03-29","sol":"229","ls":"290","season":"Month 10","min_temp":"-69","max_temp":"-4","pressure":"894","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:25","sunset":"18:42","local_uv_irradiance_index":"Very_High","min_gts_temp":"-70","max_gts_temp":"7"},{"id":"121","terrestrial_date":"2013-03-28","sol":"228","ls":"290","season":"Month 10","min_temp":"-71","max_temp":"-3","pressure":"894","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:25","sunset":"18:41","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"7"},{"id":"120","terrestrial_date":"2013-03-27","sol":"227","ls":"289","season":"Month 10","min_temp":"-70","max_temp":"4","pressure":"892","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:24","sunset":"18:41","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"7"},{"id":"119","terrestrial_date":"2013-03-26","sol":"226","ls":"288","season":"Month 10","min_temp":"-70","max_temp":"1","pressure":"894","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:24","sunset":"18:40","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"6"},{"id":"118","terrestrial_date":"2013-03-25","sol":"225","ls":"288","season":"Month 10","min_temp":"-71","max_temp":"-8","pressure":"894","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:23","sunset":"18:40","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"7"},{"id":"117","terrestrial_date":"2013-03-24","sol":"224","ls":"287","season":"Month 10","min_temp":"-69","max_temp":"-1","pressure":"894","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:22","sunset":"18:39","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"6"},{"id":"116","terrestrial_date":"2013-03-23","sol":"223","ls":"287","season":"Month 10","min_temp":"-71","max_temp":"-5","pressure":"895","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:22","sunset":"18:39","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"6"},{"id":"115","terrestrial_date":"2013-03-22","sol":"222","ls":"286","season":"Month 10","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:21","sunset":"18:38","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"113","terrestrial_date":"2013-03-15","sol":"215","ls":"281","season":"Month 10","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:17","sunset":"18:34","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"111","terrestrial_date":"2013-02-27","sol":"200","ls":"272","season":"Month 10","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:06","sunset":"18:24","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"109","terrestrial_date":"2013-02-26","sol":"199","ls":"271","season":"Month 10","min_temp":"-66","max_temp":"0","pressure":"917","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:06","sunset":"18:24","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"4"},{"id":"108","terrestrial_date":"2013-02-25","sol":"198","ls":"271","season":"Month 10","min_temp":"-67","max_temp":"-2","pressure":"914","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:05","sunset":"18:23","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"6"},{"id":"107","terrestrial_date":"2013-02-24","sol":"197","ls":"270","season":"Month 10","min_temp":"-68","max_temp":"-3","pressure":"915","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:04","sunset":"18:22","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"5"},{"id":"106","terrestrial_date":"2013-02-23","sol":"196","ls":"269","season":"Month 9","min_temp":"-66","max_temp":"-3","pressure":"916","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:04","sunset":"18:21","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"7"},{"id":"105","terrestrial_date":"2013-02-22","sol":"195","ls":"269","season":"Month 9","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:03","sunset":"18:21","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"104","terrestrial_date":"2013-02-19","sol":"192","ls":"267","season":"Month 9","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:01","sunset":"18:19","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"103","terrestrial_date":"2013-02-18","sol":"191","ls":"266","season":"Month 9","min_temp":"-67","max_temp":"-3","pressure":"921","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"06:00","sunset":"18:18","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"7"},{"id":"102","terrestrial_date":"2013-02-17","sol":"190","ls":"265","season":"Month 9","min_temp":"-66","max_temp":"-3","pressure":"917","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:59","sunset":"18:17","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"7"},{"id":"100","terrestrial_date":"2013-02-16","sol":"189","ls":"265","season":"Month 9","min_temp":"-68","max_temp":"-2","pressure":"920","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:59","sunset":"18:16","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"6"},{"id":"99","terrestrial_date":"2013-02-15","sol":"188","ls":"264","season":"Month 9","min_temp":"-68","max_temp":"-3","pressure":"920","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:58","sunset":"18:16","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"7"},{"id":"98","terrestrial_date":"2013-02-14","sol":"187","ls":"263","season":"Month 9","min_temp":"-67","max_temp":"-1","pressure":"921","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"18:15","local_uv_irradiance_index":"High","min_gts_temp":"-73","max_gts_temp":"7"},{"id":"97","terrestrial_date":"2013-02-13","sol":"186","ls":"263","season":"Month 9","min_temp":"-66","max_temp":"-2","pressure":"922","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:57","sunset":"18:14","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"5"},{"id":"96","terrestrial_date":"2013-02-12","sol":"185","ls":"262","season":"Month 9","min_temp":"-67","max_temp":"-5","pressure":"923","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:56","sunset":"18:14","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"7"},{"id":"95","terrestrial_date":"2013-02-11","sol":"184","ls":"261","season":"Month 9","min_temp":"-67","max_temp":"0","pressure":"923","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"18:13","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"6"},{"id":"94","terrestrial_date":"2013-02-10","sol":"183","ls":"261","season":"Month 9","min_temp":"-67","max_temp":"-1","pressure":"921","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:55","sunset":"18:12","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"6"},{"id":"93","terrestrial_date":"2013-02-09","sol":"182","ls":"260","season":"Month 9","min_temp":"-67","max_temp":"0","pressure":"921","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:54","sunset":"18:11","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"7"},{"id":"92","terrestrial_date":"2013-02-08","sol":"181","ls":"260","season":"Month 9","min_temp":"-67","max_temp":"1","pressure":"918","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:53","sunset":"18:11","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"6"},{"id":"91","terrestrial_date":"2013-02-07","sol":"180","ls":"259","season":"Month 9","min_temp":"-67","max_temp":"-1","pressure":"919","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"18:10","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"6"},{"id":"89","terrestrial_date":"2013-02-06","sol":"179","ls":"258","season":"Month 9","min_temp":"-66","max_temp":"-7","pressure":"920","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:52","sunset":"18:09","local_uv_irradiance_index":"High","min_gts_temp":"-72","max_gts_temp":"5"},{"id":"88","terrestrial_date":"2013-02-04","sol":"178","ls":"258","season":"Month 9","min_temp":"-66","max_temp":"-2","pressure":"920","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:51","sunset":"18:09","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"6"},{"id":"87","terrestrial_date":"2013-02-03","sol":"177","ls":"257","season":"Month 9","min_temp":"-66","max_temp":"-1","pressure":"921","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:50","sunset":"18:08","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"5"},{"id":"86","terrestrial_date":"2013-02-02","sol":"176","ls":"256","season":"Month 9","min_temp":"-67","max_temp":"0","pressure":"920","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:50","sunset":"18:07","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"6"},{"id":"85","terrestrial_date":"2013-02-01","sol":"175","ls":"256","season":"Month 9","min_temp":"-68","max_temp":"-4","pressure":"921","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:49","sunset":"18:06","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"6"},{"id":"84","terrestrial_date":"2013-01-31","sol":"174","ls":"255","season":"Month 9","min_temp":"-67","max_temp":"0","pressure":"921","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:48","sunset":"18:06","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"7"},{"id":"83","terrestrial_date":"2013-01-30","sol":"173","ls":"254","season":"Month 9","min_temp":"-67","max_temp":"0","pressure":"920","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:48","sunset":"18:05","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"6"},{"id":"82","terrestrial_date":"2013-01-29","sol":"172","ls":"254","season":"Month 9","min_temp":"-67","max_temp":"0","pressure":"923","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:47","sunset":"18:04","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"6"},{"id":"81","terrestrial_date":"2013-01-28","sol":"171","ls":"253","season":"Month 9","min_temp":"-67","max_temp":"1","pressure":"925","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:46","sunset":"18:03","local_uv_irradiance_index":"High","min_gts_temp":"-71","max_gts_temp":"6"},{"id":"80","terrestrial_date":"2013-01-27","sol":"170","ls":"252","season":"Month 9","min_temp":"-66","max_temp":"0","pressure":"925","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:46","sunset":"18:03","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"5"},{"id":"78","terrestrial_date":"2013-01-26","sol":"169","ls":"252","season":"Month 9","min_temp":"-66","max_temp":"0","pressure":"922","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:45","sunset":"18:02","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"6"},{"id":"77","terrestrial_date":"2013-01-25","sol":"168","ls":"251","season":"Month 9","min_temp":"-66","max_temp":"1","pressure":"923","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:45","sunset":"18:01","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"7"},{"id":"76","terrestrial_date":"2013-01-24","sol":"167","ls":"250","season":"Month 9","min_temp":"-65","max_temp":"-3","pressure":"920","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:44","sunset":"18:01","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"6"},{"id":"75","terrestrial_date":"2013-01-23","sol":"166","ls":"250","season":"Month 9","min_temp":"-65","max_temp":"-5","pressure":"922","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:43","sunset":"18:00","local_uv_irradiance_index":"High","min_gts_temp":"-67","max_gts_temp":"4"},{"id":"74","terrestrial_date":"2013-01-22","sol":"165","ls":"249","season":"Month 9","min_temp":"-65","max_temp":"-3","pressure":"922","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:43","sunset":"17:59","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"4"},{"id":"73","terrestrial_date":"2013-01-21","sol":"164","ls":"248","season":"Month 9","min_temp":"-64","max_temp":"-1","pressure":"919","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:42","sunset":"17:59","local_uv_irradiance_index":"High","min_gts_temp":"-68","max_gts_temp":"7"},{"id":"72","terrestrial_date":"2013-01-20","sol":"163","ls":"248","season":"Month 9","min_temp":"-65","max_temp":"-1","pressure":"919","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:41","sunset":"17:58","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"6"},{"id":"71","terrestrial_date":"2013-01-19","sol":"162","ls":"247","season":"Month 9","min_temp":"-65","max_temp":"-1","pressure":"919","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:41","sunset":"17:57","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"7"},{"id":"70","terrestrial_date":"2013-01-18","sol":"161","ls":"246","season":"Month 9","min_temp":"-65","max_temp":"-2","pressure":"919","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:40","sunset":"17:56","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"5"},{"id":"69","terrestrial_date":"2013-01-17","sol":"160","ls":"246","season":"Month 9","min_temp":"-67","max_temp":"-3","pressure":"919","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:40","sunset":"17:56","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"6"},{"id":"67","terrestrial_date":"2013-01-16","sol":"159","ls":"245","season":"Month 9","min_temp":"-65","max_temp":"-4","pressure":"918","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:39","sunset":"17:55","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"5"},{"id":"66","terrestrial_date":"2013-01-15","sol":"158","ls":"245","season":"Month 9","min_temp":"-66","max_temp":"-3","pressure":"922","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:39","sunset":"17:54","local_uv_irradiance_index":"Very_High","min_gts_temp":"-70","max_gts_temp":"4"},{"id":"65","terrestrial_date":"2013-01-14","sol":"157","ls":"244","season":"Month 9","min_temp":"-64","max_temp":"-2","pressure":"920","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:38","sunset":"17:54","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"5"},{"id":"64","terrestrial_date":"2013-01-13","sol":"156","ls":"243","season":"Month 9","min_temp":"-65","max_temp":"0","pressure":"922","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:37","sunset":"17:53","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"5"},{"id":"63","terrestrial_date":"2013-01-12","sol":"155","ls":"243","season":"Month 9","min_temp":"-64","max_temp":"0","pressure":"917","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:37","sunset":"17:52","local_uv_irradiance_index":"Very_High","min_gts_temp":"-70","max_gts_temp":"4"},{"id":"62","terrestrial_date":"2013-01-11","sol":"154","ls":"242","season":"Month 9","min_temp":"-65","max_temp":"-2","pressure":"917","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:36","sunset":"17:52","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"4"},{"id":"61","terrestrial_date":"2013-01-10","sol":"153","ls":"241","season":"Month 9","min_temp":"-65","max_temp":"1","pressure":"915","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:36","sunset":"17:51","local_uv_irradiance_index":"Very_High","min_gts_temp":"-70","max_gts_temp":"4"},{"id":"60","terrestrial_date":"2013-01-09","sol":"152","ls":"241","season":"Month 9","min_temp":"-63","max_temp":"1","pressure":"914","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:35","sunset":"17:51","local_uv_irradiance_index":"Very_High","min_gts_temp":"-69","max_gts_temp":"6"},{"id":"59","terrestrial_date":"2013-01-08","sol":"151","ls":"240","season":"Month 9","min_temp":"-65","max_temp":"-3","pressure":"915","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:35","sunset":"17:50","local_uv_irradiance_index":"Very_High","min_gts_temp":"-69","max_gts_temp":"5"},{"id":"58","terrestrial_date":"2013-01-07","sol":"150","ls":"239","season":"Month 8","min_temp":"-64","max_temp":"-3","pressure":"913","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:34","sunset":"17:49","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"6"},{"id":"56","terrestrial_date":"2013-01-06","sol":"149","ls":"239","season":"Month 8","min_temp":"-65","max_temp":"0","pressure":"914","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:34","sunset":"17:49","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"4"},{"id":"55","terrestrial_date":"2013-01-05","sol":"148","ls":"238","season":"Month 8","min_temp":"-65","max_temp":"-3","pressure":"912","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:33","sunset":"17:48","local_uv_irradiance_index":"Very_High","min_gts_temp":"-70","max_gts_temp":"5"},{"id":"54","terrestrial_date":"2013-01-04","sol":"147","ls":"237","season":"Month 8","min_temp":"-65","max_temp":"0","pressure":"914","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:33","sunset":"17:47","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"6"},{"id":"53","terrestrial_date":"2013-01-03","sol":"146","ls":"237","season":"Month 8","min_temp":"-65","max_temp":"-1","pressure":"908","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:32","sunset":"17:47","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"8"},{"id":"52","terrestrial_date":"2013-01-02","sol":"145","ls":"236","season":"Month 8","min_temp":"-64","max_temp":"-1","pressure":"909","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:32","sunset":"17:46","local_uv_irradiance_index":"Very_High","min_gts_temp":"-70","max_gts_temp":"7"},{"id":"51","terrestrial_date":"2013-01-01","sol":"144","ls":"235","season":"Month 8","min_temp":"-64","max_temp":"2","pressure":"907","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:31","sunset":"17:46","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"7"},{"id":"50","terrestrial_date":"2012-12-31","sol":"143","ls":"235","season":"Month 8","min_temp":"-63","max_temp":"-2","pressure":"908","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:31","sunset":"17:45","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"8"},{"id":"49","terrestrial_date":"2012-12-29","sol":"142","ls":"234","season":"Month 8","min_temp":"-65","max_temp":"0","pressure":"906","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:30","sunset":"17:44","local_uv_irradiance_index":"Very_High","min_gts_temp":"-73","max_gts_temp":"8"},{"id":"48","terrestrial_date":"2012-12-28","sol":"141","ls":"233","season":"Month 8","min_temp":"-64","max_temp":"-2","pressure":"904","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:30","sunset":"17:44","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"8"},{"id":"47","terrestrial_date":"2012-12-27","sol":"140","ls":"233","season":"Month 8","min_temp":"-66","max_temp":"-2","pressure":"903","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:29","sunset":"17:43","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"8"},{"id":"45","terrestrial_date":"2012-12-26","sol":"139","ls":"232","season":"Month 8","min_temp":"-66","max_temp":"0","pressure":"899","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:29","sunset":"17:43","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"9"},{"id":"44","terrestrial_date":"2012-12-25","sol":"138","ls":"232","season":"Month 8","min_temp":"-65","max_temp":"-1","pressure":"899","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:29","sunset":"17:42","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"8"},{"id":"43","terrestrial_date":"2012-12-24","sol":"137","ls":"231","season":"Month 8","min_temp":"-64","max_temp":"-1","pressure":"896","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:42","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"8"},{"id":"42","terrestrial_date":"2012-12-23","sol":"136","ls":"230","season":"Month 8","min_temp":"-65","max_temp":"-1","pressure":"897","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:41","local_uv_irradiance_index":"Very_High","min_gts_temp":"-74","max_gts_temp":"7"},{"id":"41","terrestrial_date":"2012-12-22","sol":"135","ls":"230","season":"Month 8","min_temp":"-65","max_temp":"-5","pressure":"894","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:27","sunset":"17:41","local_uv_irradiance_index":"Very_High","min_gts_temp":"-72","max_gts_temp":"8"},{"id":"40","terrestrial_date":"2012-12-21","sol":"134","ls":"229","season":"Month 8","min_temp":"-67","max_temp":"-1","pressure":"893","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:27","sunset":"17:40","local_uv_irradiance_index":"Very_High","min_gts_temp":"-74","max_gts_temp":"7"},{"id":"39","terrestrial_date":"2012-12-20","sol":"133","ls":"228","season":"Month 8","min_temp":"-65","max_temp":"1","pressure":"891","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:27","sunset":"17:39","local_uv_irradiance_index":"Very_High","min_gts_temp":"-69","max_gts_temp":"6"},{"id":"38","terrestrial_date":"2012-12-19","sol":"132","ls":"228","season":"Month 8","min_temp":"-65","max_temp":"-6","pressure":"890","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:39","local_uv_irradiance_index":"Very_High","min_gts_temp":"-69","max_gts_temp":"5"},{"id":"37","terrestrial_date":"2012-12-18","sol":"131","ls":"227","season":"Month 8","min_temp":"-65","max_temp":"-8","pressure":"889","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:38","local_uv_irradiance_index":"Very_High","min_gts_temp":"-70","max_gts_temp":"6"},{"id":"36","terrestrial_date":"2012-12-17","sol":"130","ls":"226","season":"Month 8","min_temp":"-65","max_temp":"-9","pressure":"888","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:38","local_uv_irradiance_index":"High","min_gts_temp":"-70","max_gts_temp":"5"},{"id":"34","terrestrial_date":"2012-12-16","sol":"129","ls":"226","season":"Month 8","min_temp":"-65","max_temp":"-2","pressure":"886","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:37","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"6"},{"id":"33","terrestrial_date":"2012-12-15","sol":"128","ls":"225","season":"Month 8","min_temp":"-67","max_temp":"-3","pressure":"883","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:37","local_uv_irradiance_index":"High","min_gts_temp":"-69","max_gts_temp":"6"},{"id":"32","terrestrial_date":"2012-12-14","sol":"127","ls":"224","season":"Month 8","min_temp":"-67","max_temp":"-1","pressure":"884","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:37","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"7"},{"id":"31","terrestrial_date":"2012-12-13","sol":"126","ls":"224","season":"Month 8","min_temp":"-66","max_temp":"-4","pressure":"880","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:36","local_uv_irradiance_index":"Very_High","min_gts_temp":"-71","max_gts_temp":"7"},{"id":"30","terrestrial_date":"2012-12-12","sol":"125","ls":"223","season":"Month 8","min_temp":"-68","max_temp":"-5","pressure":"880","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:36","local_uv_irradiance_index":"Very_High","min_gts_temp":"-66","max_gts_temp":"7"},{"id":"29","terrestrial_date":"2012-12-11","sol":"124","ls":"223","season":"Month 8","min_temp":"-66","max_temp":"-5","pressure":"876","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:35","local_uv_irradiance_index":"Very_High","min_gts_temp":"-63","max_gts_temp":"6"},{"id":"28","terrestrial_date":"2012-12-10","sol":"123","ls":"222","season":"Month 8","min_temp":"-66","max_temp":"-10","pressure":"875","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:35","local_uv_irradiance_index":"High","min_gts_temp":"-62","max_gts_temp":"2"},{"id":"27","terrestrial_date":"2012-12-09","sol":"122","ls":"221","season":"Month 8","min_temp":"-65","max_temp":"-3","pressure":"869","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:34","local_uv_irradiance_index":"Very_High","min_gts_temp":"-66","max_gts_temp":"3"},{"id":"26","terrestrial_date":"2012-12-08","sol":"121","ls":"221","season":"Month 8","min_temp":"-66","max_temp":"0","pressure":"869","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:34","local_uv_irradiance_index":"High","min_gts_temp":"-68","max_gts_temp":"9"},{"id":"25","terrestrial_date":"2012-12-07","sol":"120","ls":"220","season":"Month 8","min_temp":"-67","max_temp":"-3","pressure":"867","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:33","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"16"},{"id":"23","terrestrial_date":"2012-12-06","sol":"119","ls":"219","season":"Month 8","min_temp":"-66","max_temp":"-6","pressure":"866","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:33","local_uv_irradiance_index":"Very_High","min_gts_temp":"-78","max_gts_temp":"19"},{"id":"22","terrestrial_date":"2012-12-05","sol":"118","ls":"219","season":"Month 8","min_temp":"-65","max_temp":"-6","pressure":"864","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:33","local_uv_irradiance_index":"Very_High","min_gts_temp":"-77","max_gts_temp":"18"},{"id":"21","terrestrial_date":"2012-12-04","sol":"117","ls":"218","season":"Month 8","min_temp":"-66","max_temp":"-5","pressure":"861","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:32","local_uv_irradiance_index":"Very_High","min_gts_temp":"-76","max_gts_temp":"18"},{"id":"20","terrestrial_date":"2012-12-03","sol":"116","ls":"217","season":"Month 8","min_temp":"-67","max_temp":"-6","pressure":"859","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:32","local_uv_irradiance_index":"Very_High","min_gts_temp":"-78","max_gts_temp":"18"},{"id":"19","terrestrial_date":"2012-12-02","sol":"115","ls":"217","season":"Month 8","min_temp":"-66","max_temp":"-8","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:31","local_uv_irradiance_index":"Very_High","min_gts_temp":"-78","max_gts_temp":"17"},{"id":"18","terrestrial_date":"2012-12-01","sol":"114","ls":"216","season":"Month 8","min_temp":"-69","max_temp":"-6","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:31","local_uv_irradiance_index":"Very_High","min_gts_temp":"-78","max_gts_temp":"18"},{"id":"17","terrestrial_date":"2012-11-30","sol":"113","ls":"216","season":"Month 8","min_temp":"-66","max_temp":"-6","pressure":"857","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:31","local_uv_irradiance_index":"Very_High","min_gts_temp":"-77","max_gts_temp":"16"},{"id":"16","terrestrial_date":"2012-11-29","sol":"112","ls":"215","season":"Month 8","min_temp":"-65","max_temp":"-8","pressure":"852","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:30","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"18"},{"id":"15","terrestrial_date":"2012-11-28","sol":"111","ls":"214","season":"Month 8","min_temp":"-66","max_temp":"-4","pressure":"849","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:30","local_uv_irradiance_index":"Very_High","min_gts_temp":"-77","max_gts_temp":"18"},{"id":"14","terrestrial_date":"2012-11-27","sol":"110","ls":"214","season":"Month 8","min_temp":"-65","max_temp":"-5","pressure":"848","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:30","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"17"},{"id":"12","terrestrial_date":"2012-11-26","sol":"109","ls":"213","season":"Month 8","min_temp":"-64","max_temp":"-3","pressure":"844","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:29","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"16"},{"id":"11","terrestrial_date":"2012-11-25","sol":"108","ls":"212","season":"Month 8","min_temp":"-65","max_temp":"-4","pressure":"845","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:29","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"17"},{"id":"10","terrestrial_date":"2012-11-24","sol":"107","ls":"212","season":"Month 8","min_temp":"-66","max_temp":"-5","pressure":"844","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:29","local_uv_irradiance_index":"High","min_gts_temp":"-80","max_gts_temp":"17"},{"id":"9","terrestrial_date":"2012-11-23","sol":"106","ls":"211","season":"Month 8","min_temp":"-66","max_temp":"-8","pressure":"841","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:28","local_uv_irradiance_index":"High","min_gts_temp":"-78","max_gts_temp":"17"},{"id":"8","terrestrial_date":"2012-11-21","sol":"105","ls":"211","season":"Month 8","min_temp":"-66","max_temp":"-6","pressure":"839","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:28","local_uv_irradiance_index":"High","min_gts_temp":"-77","max_gts_temp":"17"},{"id":"7","terrestrial_date":"2012-11-20","sol":"104","ls":"210","season":"Month 8","min_temp":"-67","max_temp":"-5","pressure":"838","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:28","local_uv_irradiance_index":"Very_High","min_gts_temp":"-78","max_gts_temp":"18"},{"id":"6","terrestrial_date":"2012-11-19","sol":"103","ls":"209","season":"Month 7","min_temp":"-66","max_temp":"-3","pressure":"836","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:27","local_uv_irradiance_index":"Very_High","min_gts_temp":"-80","max_gts_temp":"19"},{"id":"5","terrestrial_date":"2012-11-18","sol":"102","ls":"209","season":"Month 7","min_temp":"-67","max_temp":"-3","pressure":"833","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:27","local_uv_irradiance_index":"Very_High","min_gts_temp":"-75","max_gts_temp":"17"},{"id":"4","terrestrial_date":"2012-11-17","sol":"101","ls":"208","season":"Month 7","min_temp":"-65","max_temp":"-2","pressure":"830","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:27","local_uv_irradiance_index":"Very_High","min_gts_temp":"-77","max_gts_temp":"16"},{"id":"3","terrestrial_date":"2012-11-16","sol":"100","ls":"207","season":"Month 7","min_temp":"-66","max_temp":"-1","pressure":"829","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:26","local_uv_irradiance_index":"Very_High","min_gts_temp":"-77","max_gts_temp":"13"},{"id":"242","terrestrial_date":"2012-11-15","sol":"99","ls":"207","season":"Month 7","min_temp":"-68","max_temp":"-1","pressure":"829","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:26","local_uv_irradiance_index":"Very_High","min_gts_temp":"-76","max_gts_temp":"14"},{"id":"241","terrestrial_date":"2012-11-14","sol":"98","ls":"206","season":"Month 7","min_temp":"-68","max_temp":"-1","pressure":"828","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:26","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"15"},{"id":"240","terrestrial_date":"2012-11-13","sol":"97","ls":"206","season":"Month 7","min_temp":"-68","max_temp":"-3","pressure":"828","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:26","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"15"},{"id":"239","terrestrial_date":"2012-11-12","sol":"96","ls":"205","season":"Month 7","min_temp":"-71","max_temp":"2","pressure":"826","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:25","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"15"},{"id":"238","terrestrial_date":"2012-11-11","sol":"95","ls":"204","season":"Month 7","min_temp":"-68","max_temp":"0","pressure":"822","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:25","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"15"},{"id":"237","terrestrial_date":"2012-11-10","sol":"94","ls":"204","season":"Month 7","min_temp":"-70","max_temp":"0","pressure":"822","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:25","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"16"},{"id":"236","terrestrial_date":"2012-11-09","sol":"93","ls":"203","season":"Month 7","min_temp":"-72","max_temp":"-1","pressure":"819","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:25","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"16"},{"id":"235","terrestrial_date":"2012-11-08","sol":"92","ls":"202","season":"Month 7","min_temp":"-74","max_temp":"-1","pressure":"820","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:24","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"15"},{"id":"234","terrestrial_date":"2012-11-07","sol":"91","ls":"202","season":"Month 7","min_temp":"-74","max_temp":"-1","pressure":"817","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:24","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"16"},{"id":"233","terrestrial_date":"2012-11-06","sol":"90","ls":"201","season":"Month 7","min_temp":"-71","max_temp":"0","pressure":"813","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:24","local_uv_irradiance_index":"Very_High","min_gts_temp":"-80","max_gts_temp":"16"},{"id":"231","terrestrial_date":"2012-11-05","sol":"89","ls":"201","season":"Month 7","min_temp":"-73","max_temp":"-1","pressure":"813","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:24","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"16"},{"id":"230","terrestrial_date":"2012-11-04","sol":"88","ls":"200","season":"Month 7","min_temp":"-70","max_temp":"-2","pressure":"811","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:24","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"15"},{"id":"229","terrestrial_date":"2012-11-03","sol":"87","ls":"199","season":"Month 7","min_temp":"-70","max_temp":"-2","pressure":"808","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:23","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"15"},{"id":"228","terrestrial_date":"2012-11-02","sol":"86","ls":"199","season":"Month 7","min_temp":"-71","max_temp":"-4","pressure":"808","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:23","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"15"},{"id":"227","terrestrial_date":"2012-11-01","sol":"85","ls":"198","season":"Month 7","min_temp":"-71","max_temp":"-1","pressure":"805","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:23","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"15"},{"id":"226","terrestrial_date":"2012-10-31","sol":"84","ls":"198","season":"Month 7","min_temp":"-70","max_temp":"0","pressure":"801","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:23","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"15"},{"id":"225","terrestrial_date":"2012-10-30","sol":"83","ls":"197","season":"Month 7","min_temp":"-72","max_temp":"0","pressure":"801","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:23","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"15"},{"id":"224","terrestrial_date":"2012-10-29","sol":"82","ls":"196","season":"Month 7","min_temp":"-72","max_temp":"0","pressure":"799","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"14"},{"id":"223","terrestrial_date":"2012-10-28","sol":"81","ls":"196","season":"Month 7","min_temp":"-72","max_temp":"-2","pressure":"798","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"13"},{"id":"222","terrestrial_date":"2012-10-27","sol":"80","ls":"195","season":"Month 7","min_temp":"-70","max_temp":"-3","pressure":"796","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"14"},{"id":"221","terrestrial_date":"2012-10-26","sol":"79","ls":"195","season":"Month 7","min_temp":"-73","max_temp":"-1","pressure":"795","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"Very_High","min_gts_temp":"-84","max_gts_temp":"14"},{"id":"220","terrestrial_date":"2012-10-25","sol":"78","ls":"194","season":"Month 7","min_temp":"-71","max_temp":"0","pressure":"793","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"14"},{"id":"219","terrestrial_date":"2012-10-24","sol":"77","ls":"193","season":"Month 7","min_temp":"-71","max_temp":"0","pressure":"792","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"15"},{"id":"218","terrestrial_date":"2012-10-23","sol":"76","ls":"193","season":"Month 7","min_temp":"-73","max_temp":"-1","pressure":"792","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:22","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"15"},{"id":"217","terrestrial_date":"2012-10-22","sol":"75","ls":"192","season":"Month 7","min_temp":"-73","max_temp":"-1","pressure":"791","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-84","max_gts_temp":"13"},{"id":"216","terrestrial_date":"2012-10-21","sol":"74","ls":"192","season":"Month 7","min_temp":"-72","max_temp":"-5","pressure":"790","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"13"},{"id":"215","terrestrial_date":"2012-10-20","sol":"73","ls":"191","season":"Month 7","min_temp":"-70","max_temp":"0","pressure":"788","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"13"},{"id":"214","terrestrial_date":"2012-10-19","sol":"72","ls":"190","season":"Month 7","min_temp":"-73","max_temp":"-2","pressure":"785","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"12"},{"id":"213","terrestrial_date":"2012-10-18","sol":"71","ls":"190","season":"Month 7","min_temp":"-71","max_temp":"-2","pressure":"784","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"12"},{"id":"212","terrestrial_date":"2012-10-17","sol":"70","ls":"189","season":"Month 7","min_temp":"-72","max_temp":"-1","pressure":"783","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"13"},{"id":"211","terrestrial_date":"2012-10-15","sol":"69","ls":"189","season":"Month 7","min_temp":"-73","max_temp":"0","pressure":"778","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"High","min_gts_temp":"-82","max_gts_temp":"12"},{"id":"210","terrestrial_date":"2012-10-14","sol":"68","ls":"188","season":"Month 7","min_temp":"-71","max_temp":"-2","pressure":"781","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-80","max_gts_temp":"12"},{"id":"209","terrestrial_date":"2012-10-13","sol":"67","ls":"187","season":"Month 7","min_temp":"-73","max_temp":"-6","pressure":"780","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"13"},{"id":"208","terrestrial_date":"2012-10-12","sol":"66","ls":"187","season":"Month 7","min_temp":"-73","max_temp":"-2","pressure":"778","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:18","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"12"},{"id":"207","terrestrial_date":"2012-10-11","sol":"65","ls":"186","season":"Month 7","min_temp":"-72","max_temp":"-2","pressure":"777","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"12"},{"id":"206","terrestrial_date":"2012-10-10","sol":"64","ls":"186","season":"Month 7","min_temp":"-74","max_temp":"0","pressure":"776","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"12"},{"id":"205","terrestrial_date":"2012-10-09","sol":"63","ls":"185","season":"Month 7","min_temp":"-73","max_temp":"0","pressure":"775","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"12"},{"id":"204","terrestrial_date":"2012-10-08","sol":"62","ls":"184","season":"Month 7","min_temp":"-72","max_temp":"-1","pressure":"774","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"11"},{"id":"203","terrestrial_date":"2012-10-07","sol":"61","ls":"184","season":"Month 7","min_temp":"-72","max_temp":"-2","pressure":"772","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"13"},{"id":"202","terrestrial_date":"2012-10-06","sol":"60","ls":"183","season":"Month 7","min_temp":"-75","max_temp":"-2","pressure":"772","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-84","max_gts_temp":"12"},{"id":"201","terrestrial_date":"2012-10-05","sol":"59","ls":"183","season":"Month 7","min_temp":"-76","max_temp":"-1","pressure":"771","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"11"},{"id":"200","terrestrial_date":"2012-10-04","sol":"58","ls":"182","season":"Month 7","min_temp":"-74","max_temp":"-3","pressure":"769","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"11"},{"id":"199","terrestrial_date":"2012-10-03","sol":"57","ls":"181","season":"Month 7","min_temp":"-73","max_temp":"-3","pressure":"769","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:19","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"12"},{"id":"198","terrestrial_date":"2012-10-02","sol":"56","ls":"181","season":"Month 7","min_temp":"-73","max_temp":"-4","pressure":"768","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-80","max_gts_temp":"10"},{"id":"197","terrestrial_date":"2012-10-01","sol":"55","ls":"180","season":"Month 7","min_temp":"-74","max_temp":"-2","pressure":"766","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-78","max_gts_temp":"11"},{"id":"196","terrestrial_date":"2012-09-30","sol":"54","ls":"180","season":"Month 7","min_temp":"-72","max_temp":"-9","pressure":"766","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-77","max_gts_temp":"10"},{"id":"195","terrestrial_date":"2012-09-29","sol":"53","ls":"179","season":"Month 6","min_temp":"-71","max_temp":"-5","pressure":"764","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"11"},{"id":"194","terrestrial_date":"2012-09-28","sol":"52","ls":"179","season":"Month 6","min_temp":"-74","max_temp":"-7","pressure":"762","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-84","max_gts_temp":"12"},{"id":"193","terrestrial_date":"2012-09-27","sol":"51","ls":"178","season":"Month 6","min_temp":"-76","max_temp":"-7","pressure":"762","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"13"},{"id":"192","terrestrial_date":"2012-09-26","sol":"50","ls":"177","season":"Month 6","min_temp":"-72","max_temp":"-10","pressure":"761","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:20","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-76","max_gts_temp":"11"},{"id":"191","terrestrial_date":"2012-09-25","sol":"49","ls":"177","season":"Month 6","min_temp":"-74","max_temp":"-10","pressure":"761","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"10"},{"id":"190","terrestrial_date":"2012-09-24","sol":"48","ls":"176","season":"Month 6","min_temp":"-75","max_temp":"0","pressure":"759","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-84","max_gts_temp":"12"},{"id":"189","terrestrial_date":"2012-09-23","sol":"47","ls":"176","season":"Month 6","min_temp":"-75","max_temp":"-9","pressure":"758","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"14"},{"id":"188","terrestrial_date":"2012-09-22","sol":"46","ls":"175","season":"Month 6","min_temp":"-74","max_temp":"-12","pressure":"758","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"13"},{"id":"187","terrestrial_date":"2012-09-21","sol":"45","ls":"175","season":"Month 6","min_temp":"-74","max_temp":"-9","pressure":"758","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-87","max_gts_temp":"11"},{"id":"186","terrestrial_date":"2012-09-20","sol":"44","ls":"174","season":"Month 6","min_temp":"-75","max_temp":"-10","pressure":"757","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:21","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-86","max_gts_temp":"13"},{"id":"185","terrestrial_date":"2012-09-19","sol":"43","ls":"173","season":"Month 6","min_temp":"-74","max_temp":"-12","pressure":"756","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-80","max_gts_temp":"9"},{"id":"184","terrestrial_date":"2012-09-18","sol":"42","ls":"173","season":"Month 6","min_temp":"-75","max_temp":"-7","pressure":"754","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-80","max_gts_temp":"7"},{"id":"183","terrestrial_date":"2012-09-17","sol":"41","ls":"172","season":"Month 6","min_temp":"-75","max_temp":"-12","pressure":"753","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"8"},{"id":"182","terrestrial_date":"2012-09-16","sol":"40","ls":"172","season":"Month 6","min_temp":"-75","max_temp":"-12","pressure":"753","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"8"},{"id":"181","terrestrial_date":"2012-09-15","sol":"39","ls":"171","season":"Month 6","min_temp":"-75","max_temp":"-8","pressure":"751","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"7"},{"id":"180","terrestrial_date":"2012-09-14","sol":"38","ls":"171","season":"Month 6","min_temp":"-73","max_temp":"-13","pressure":"750","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:22","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-78","max_gts_temp":"8"},{"id":"179","terrestrial_date":"2012-09-13","sol":"37","ls":"170","season":"Month 6","min_temp":"-73","max_temp":"0","pressure":"750","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-78","max_gts_temp":"7"},{"id":"178","terrestrial_date":"2012-09-12","sol":"36","ls":"169","season":"Month 6","min_temp":"-73","max_temp":"-1","pressure":"750","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-78","max_gts_temp":"7"},{"id":"177","terrestrial_date":"2012-09-11","sol":"35","ls":"169","season":"Month 6","min_temp":"-73","max_temp":"-1","pressure":"749","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-78","max_gts_temp":"6"},{"id":"176","terrestrial_date":"2012-09-10","sol":"34","ls":"168","season":"Month 6","min_temp":"-73","max_temp":"1","pressure":"748","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-78","max_gts_temp":"6"},{"id":"175","terrestrial_date":"2012-09-08","sol":"33","ls":"168","season":"Month 6","min_temp":"-73","max_temp":"-2","pressure":"748","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:23","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-80","max_gts_temp":"5"},{"id":"174","terrestrial_date":"2012-09-07","sol":"32","ls":"167","season":"Month 6","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:20","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"173","terrestrial_date":"2012-09-06","sol":"31","ls":"167","season":"Month 6","min_temp":"-74","max_temp":"-23","pressure":"745","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-80","max_gts_temp":"2"},{"id":"172","terrestrial_date":"2012-09-05","sol":"30","ls":"166","season":"Month 6","min_temp":"-74","max_temp":"-3","pressure":"747","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-80","max_gts_temp":"6"},{"id":"171","terrestrial_date":"2012-09-04","sol":"29","ls":"166","season":"Month 6","min_temp":"-75","max_temp":"-2","pressure":"747","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-78","max_gts_temp":"7"},{"id":"170","terrestrial_date":"2012-09-03","sol":"28","ls":"165","season":"Month 6","min_temp":"-75","max_temp":"-15","pressure":"745","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:24","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"5"},{"id":"163","terrestrial_date":"2012-09-02","sol":"27","ls":"164","season":"Month 6","min_temp":"-75","max_temp":"-15","pressure":"743","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"5"},{"id":"156","terrestrial_date":"2012-09-01","sol":"26","ls":"164","season":"Month 6","min_temp":"-76","max_temp":"-14","pressure":"745","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"6"},{"id":"145","terrestrial_date":"2012-08-31","sol":"25","ls":"163","season":"Month 6","min_temp":"-75","max_temp":"-11","pressure":"743","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:20","local_uv_irradiance_index":"Very_High","min_gts_temp":"-79","max_gts_temp":"6"},{"id":"134","terrestrial_date":"2012-08-30","sol":"24","ls":"163","season":"Month 6","min_temp":"-75","max_temp":"-7","pressure":"742","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"6"},{"id":"123","terrestrial_date":"2012-08-29","sol":"23","ls":"162","season":"Month 6","min_temp":"-75","max_temp":"-16","pressure":"741","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:25","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"9"},{"id":"114","terrestrial_date":"2012-08-28","sol":"22","ls":"162","season":"Month 6","min_temp":"-74","max_temp":"-6","pressure":"742","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"8"},{"id":"112","terrestrial_date":"2012-08-27","sol":"21","ls":"161","season":"Month 6","min_temp":"-74","max_temp":"-3","pressure":"741","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"7"},{"id":"110","terrestrial_date":"2012-08-26","sol":"20","ls":"161","season":"Month 6","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:21","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"101","terrestrial_date":"2012-08-25","sol":"19","ls":"160","season":"Month 6","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:21","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"90","terrestrial_date":"2012-08-24","sol":"18","ls":"160","season":"Month 6","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Higher","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:26","sunset":"17:21","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"79","terrestrial_date":"2012-08-23","sol":"17","ls":"159","season":"Month 6","min_temp":"-76","max_temp":"-4","pressure":"742","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:27","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"7"},{"id":"68","terrestrial_date":"2012-08-22","sol":"16","ls":"158","season":"Month 6","min_temp":"-77","max_temp":"0","pressure":"740","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:27","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-81","max_gts_temp":"9"},{"id":"57","terrestrial_date":"2012-08-21","sol":"15","ls":"158","season":"Month 6","min_temp":"-78","max_temp":"-15","pressure":"740","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:27","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"8"},{"id":"46","terrestrial_date":"2012-08-20","sol":"14","ls":"157","season":"Month 6","min_temp":"-74","max_temp":"-16","pressure":"740","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:27","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"9"},{"id":"35","terrestrial_date":"2012-08-19","sol":"13","ls":"157","season":"Month 6","min_temp":"-74","max_temp":"-15","pressure":"732","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-80","max_gts_temp":"8"},{"id":"24","terrestrial_date":"2012-08-18","sol":"12","ls":"156","season":"Month 6","min_temp":"-76","max_temp":"-18","pressure":"741","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-82","max_gts_temp":"8"},{"id":"13","terrestrial_date":"2012-08-17","sol":"11","ls":"156","season":"Month 6","min_temp":"-76","max_temp":"-11","pressure":"740","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:21","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"9"},{"id":"2","terrestrial_date":"2012-08-16","sol":"10","ls":"155","season":"Month 6","min_temp":"-75","max_temp":"-16","pressure":"739","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:22","local_uv_irradiance_index":"Very_High","min_gts_temp":"-83","max_gts_temp":"8"},{"id":"232","terrestrial_date":"2012-08-15","sol":"9","ls":"155","season":"Month 6","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:28","sunset":"17:22","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"},{"id":"1","terrestrial_date":"2012-08-07","sol":"1","ls":"150","season":"Month 6","min_temp":"--","max_temp":"--","pressure":"--","pressure_string":"Lower","abs_humidity":"--","wind_speed":"--","wind_direction":"--","atmo_opacity":"Sunny","sunrise":"05:30","sunset":"17:22","local_uv_irradiance_index":"--","min_gts_temp":"--","max_gts_temp":"--"}]} \ No newline at end of file diff --git a/example/msl/src/MSLDataDictionary.js b/example/msl/src/MSLDataDictionary.js deleted file mode 100644 index fb6974ff2d..0000000000 --- a/example/msl/src/MSLDataDictionary.js +++ /dev/null @@ -1,78 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - [], - /** - * A data dictionary describes the telemetry available from a data - * source and its data types. The data dictionary will be parsed by a custom - * server provider for this data source (in this case - * {@link RemsTelemetryServerAdapter}). - * - * Typically a data dictionary would be made available alongside the - * telemetry data source itself. - */ - function () { - return { - "name": "Mars Science Laboratory", - "identifier": "msl", - "instruments": [ - { - "name": "rems", - "identifier": "rems", - "measurements": [ - { - "name": "Min. Air Temperature", - "identifier": "min_temp", - "units": "Degrees (C)", - "type": "float" - }, - { - "name": "Max. Air Temperature", - "identifier": "max_temp", - "units": "Degrees (C)", - "type": "float" - }, - { - "name": "Atmospheric Pressure", - "identifier": "pressure", - "units": "Millibars", - "type": "float" - }, - { - "name": "Min. Ground Temperature", - "identifier": "min_gts_temp", - "units": "Degrees (C)", - "type": "float" - }, - { - "name": "Max. Ground Temperature", - "identifier": "max_gts_temp", - "units": "Degrees (C)", - "type": "float" - } - ] - } - ] - }; - } -); diff --git a/example/msl/src/RemsTelemetryModelProvider.js b/example/msl/src/RemsTelemetryModelProvider.js deleted file mode 100644 index 509c9d7ba8..0000000000 --- a/example/msl/src/RemsTelemetryModelProvider.js +++ /dev/null @@ -1,96 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - "use strict"; - - var PREFIX = "msl_tlm:", - FORMAT_MAPPINGS = { - float: "number", - integer: "number", - string: "string" - }; - - function RemsTelemetryModelProvider(adapter) { - - function isRelevant(id) { - return id.indexOf(PREFIX) === 0; - } - - function makeId(element) { - return PREFIX + element.identifier; - } - - function buildTaxonomy(dictionary) { - var models = {}; - - function addMeasurement(measurement, parent) { - var format = FORMAT_MAPPINGS[measurement.type]; - models[makeId(measurement)] = { - type: "msl.measurement", - name: measurement.name, - location: parent, - telemetry: { - key: measurement.identifier, - ranges: [{ - key: "value", - name: measurement.units, - units: measurement.units, - format: format - }] - } - }; - } - - function addInstrument(subsystem, spacecraftId) { - var measurements = (subsystem.measurements || []), - instrumentId = makeId(subsystem); - - models[instrumentId] = { - type: "msl.instrument", - name: subsystem.name, - location: spacecraftId, - composition: measurements.map(makeId) - }; - measurements.forEach(function (measurement) { - addMeasurement(measurement, instrumentId); - }); - } - - (dictionary.instruments || []).forEach(function (instrument) { - addInstrument(instrument, "msl:curiosity"); - }); - - return models; - } - - return { - getModels: function (ids) { - return ids.some(isRelevant) ? buildTaxonomy(adapter.dictionary) : {}; - } - }; - } - - return RemsTelemetryModelProvider; - } -); diff --git a/example/msl/src/RemsTelemetryProvider.js b/example/msl/src/RemsTelemetryProvider.js deleted file mode 100644 index 85340a9dbf..0000000000 --- a/example/msl/src/RemsTelemetryProvider.js +++ /dev/null @@ -1,83 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ( - ['./RemsTelemetrySeries'], - function (RemsTelemetrySeries) { - "use strict"; - - var SOURCE = "rems.source"; - - function RemsTelemetryProvider(adapter, $q) { - this.adapter = adapter; - this.$q = $q; - } - - /** - * Retrieve telemetry from this telemetry source. - * @memberOf example/msl - * @param {Array} requests An array of all request - * objects (which needs to be filtered to only those relevant to this - * source) - * @returns {Promise} A {@link Promise} resolved with a {@link RemsTelemetrySeries} - * object that wraps the telemetry returned from the telemetry source. - */ - RemsTelemetryProvider.prototype.requestTelemetry = function (requests) { - var packaged = {}, - relevantReqs, - adapter = this.adapter; - - function matchesSource(request) { - return (request.source === SOURCE); - } - - function addToPackage(history) { - packaged[SOURCE][history.id] = - new RemsTelemetrySeries(history.values); - } - - function handleRequest(request) { - return adapter.history(request).then(addToPackage); - } - - relevantReqs = requests.filter(matchesSource); - packaged[SOURCE] = {}; - - return this.$q.all(relevantReqs.map(handleRequest)) - .then(function () { - return packaged; - }); - }; - - /** - * This data source does not support real-time subscriptions - */ - RemsTelemetryProvider.prototype.subscribe = function (callback, requests) { - return function () {}; - }; - - RemsTelemetryProvider.prototype.unsubscribe = function (callback, requests) { - return function () {}; - }; - - return RemsTelemetryProvider; - } -); diff --git a/example/msl/src/RemsTelemetrySeries.js b/example/msl/src/RemsTelemetrySeries.js deleted file mode 100644 index bc5a38420a..0000000000 --- a/example/msl/src/RemsTelemetrySeries.js +++ /dev/null @@ -1,84 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - "use strict"; - - /** - * @typedef {Object} RemsTelemetryValue - * @memberOf example/msl - * @property {number} date The date/time of the telemetry value. Constitutes the domain value of this value pair - * @property {number} value The value of this telemetry datum. - * A floating point value representing some observable quantity (eg. - * temperature, air pressure, etc.) - */ - - /** - * A representation of a collection of telemetry data. The REMS - * telemetry data is time ordered, with the 'domain' value - * constituting the time stamp of each data value and the - * 'range' being the value itself. - * - * TelemetrySeries will typically wrap an array of telemetry data, - * and provide an interface for retrieving individual an telemetry - * value. - * @memberOf example/msl - * @param {Array} data An array of telemetry values - * @constructor - */ - function RemsTelemetrySeries(data) { - this.data = data; - } - - /** - * @returns {number} A count of the number of data values available in - * this series - */ - RemsTelemetrySeries.prototype.getPointCount = function () { - return this.data.length; - }; - - /** - * The domain value at the given index. The Rems telemetry data is - * time ordered, so the domain value is the time stamp of each data - * value. - * @param index - * @returns {number} the time value in ms since 1 January 1970 - */ - RemsTelemetrySeries.prototype.getDomainValue = function (index) { - return this.data[index].date; - }; - - /** - * The range value of the REMS data set is the value of the thing - * being measured, be it temperature, air pressure, etc. - * @param index The datum in the data series to return the range - * value of. - * @returns {number} A floating point number - */ - RemsTelemetrySeries.prototype.getRangeValue = function (index) { - return this.data[index].value; - }; - - return RemsTelemetrySeries; - } -); diff --git a/example/msl/src/RemsTelemetryServerAdapter.js b/example/msl/src/RemsTelemetryServerAdapter.js deleted file mode 100644 index a256c176d7..0000000000 --- a/example/msl/src/RemsTelemetryServerAdapter.js +++ /dev/null @@ -1,145 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ -/*jslint es5: true */ - -define( - [ - "./MSLDataDictionary", - "module" - ], - function (MSLDataDictionary, module) { - "use strict"; - - var TERRESTRIAL_DATE = "terrestrial_date", - LOCAL_DATA = "../data/rems.json"; - - /** - * Fetches historical data from the REMS instrument on the Curiosity - * Rover. - * @memberOf example/msl - * @param $q - * @param $http - * @param REMS_WS_URL The location of the REMS telemetry data. - * @constructor - */ - function RemsTelemetryServerAdapter($http, $log, REMS_WS_URL) { - this.localDataURI = module.uri.substring(0, module.uri.lastIndexOf('/') + 1) + LOCAL_DATA; - this.REMS_WS_URL = REMS_WS_URL; - this.$http = $http; - this.$log = $log; - this.promise = undefined; - - this.dataTransforms = { - //Convert from pascals to millibars - 'pressure': function pascalsToMillibars(pascals) { - return pascals / 100; - } - }; - } - - /** - * The data dictionary for this data source. - * @type {MSLDataDictionary} - */ - RemsTelemetryServerAdapter.prototype.dictionary = MSLDataDictionary; - - /** - * Fetches historical data from source, and associates it with the - * given request ID. - * @private - */ - RemsTelemetryServerAdapter.prototype.requestHistory = function (request) { - var self = this, - id = request.key; - - var dataTransforms = this.dataTransforms; - - function processResponse(response) { - var data = []; - /* - * History data is organised by Sol. Iterate over sols... - */ - response.data.soles.forEach(function (solData) { - /* - * Check that valid data exists - */ - if (!isNaN(solData[id])) { - var dataTransform = dataTransforms[id]; - /* - * Append each data point to the array of values - * for this data point property (min. temp, etc). - */ - data.unshift({ - date: Date.parse(solData[TERRESTRIAL_DATE]), - value: dataTransform ? dataTransform(solData[id]) : solData[id] - }); - } - }); - - return data; - } - - function fallbackToLocal() { - self.$log.warn("Loading REMS data failed, probably due to" - + " cross origin policy. Falling back to local data"); - - return self.$http.get(self.localDataURI); - } - - //Filter results to match request parameters - function filterResults(results) { - return results.filter(function (result) { - return result.date >= (request.start || Number.MIN_VALUE) - && result.date <= (request.end || Number.MAX_VALUE); - }); - } - - function packageAndResolve(results) { - return { - id: id, - values: results - }; - } - - return (this.promise = this.promise || this.$http.get(this.REMS_WS_URL)) - .catch(fallbackToLocal) - .then(processResponse) - .then(filterResults) - .then(packageAndResolve); - }; - - /** - * Requests historical telemetry for the named data attribute. In - * the case of REMS, this data source exposes multiple different - * data variables from the REMS instrument, including temperature - * and others - * @param id The telemetry data point key to be queried. - * @returns {Promise | Array} that resolves with an Array of {@link RemsTelemetryValue} objects for the request data key. - */ - RemsTelemetryServerAdapter.prototype.history = function (request) { - return this.requestHistory(request); - }; - - return RemsTelemetryServerAdapter; - } -); - diff --git a/example/notifications/bundle.js b/example/notifications/bundle.js deleted file mode 100644 index c06210a03b..0000000000 --- a/example/notifications/bundle.js +++ /dev/null @@ -1,90 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/DialogLaunchController", - "./src/NotificationLaunchController", - "./src/DialogLaunchIndicator", - "./src/NotificationLaunchIndicator", - "./res/dialog-launch.html", - "./res/notification-launch.html" -], function ( - DialogLaunchController, - NotificationLaunchController, - DialogLaunchIndicator, - NotificationLaunchIndicator, - DialogLaunch, - NotificationLaunch -) { - "use strict"; - - return { - name: "example/notifications", - definition: { - "extensions": { - "templates": [ - { - "key": "dialogLaunchTemplate", - "template": DialogLaunch - }, - { - "key": "notificationLaunchTemplate", - "template": NotificationLaunch - } - ], - "controllers": [ - { - "key": "DialogLaunchController", - "implementation": DialogLaunchController, - "depends": [ - "$scope", - "$timeout", - "$log", - "dialogService", - "notificationService" - ] - }, - { - "key": "NotificationLaunchController", - "implementation": NotificationLaunchController, - "depends": [ - "$scope", - "$timeout", - "$log", - "notificationService" - ] - } - ], - "indicators": [ - { - "implementation": DialogLaunchIndicator, - "priority": "fallback" - }, - { - "implementation": NotificationLaunchIndicator, - "priority": "fallback" - } - ] - } - } - }; -}); diff --git a/example/notifications/res/dialog-launch.html b/example/notifications/res/dialog-launch.html deleted file mode 100644 index f6b33d7b7c..0000000000 --- a/example/notifications/res/dialog-launch.html +++ /dev/null @@ -1,9 +0,0 @@ - - -
- - - - -
-
diff --git a/example/notifications/res/notification-launch.html b/example/notifications/res/notification-launch.html deleted file mode 100644 index 11c66566e8..0000000000 --- a/example/notifications/res/notification-launch.html +++ /dev/null @@ -1,9 +0,0 @@ - - -
- - - - -
-
diff --git a/example/notifications/src/DialogLaunchController.js b/example/notifications/src/DialogLaunchController.js deleted file mode 100644 index c1ee0f5793..0000000000 --- a/example/notifications/src/DialogLaunchController.js +++ /dev/null @@ -1,157 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - "use strict"; - - /** - * A controller for the dialog launch view. This view allows manual - * launching of dialogs for demonstration and testing purposes. It - * also demonstrates the use of the DialogService. - * @param $scope - * @param $timeout - * @param $log - * @param dialogService - * @param notificationService - * @constructor - */ - function DialogLaunchController($scope, $timeout, $log, dialogService, notificationService) { - - /* - Demonstrates launching a progress dialog and updating it - periodically with the progress of an ongoing process. - */ - $scope.launchProgress = function (knownProgress) { - var dialog, - model = { - title: "Progress Dialog Example", - progress: 0, - hint: "Do not navigate away from this page or close this browser tab while this operation is in progress.", - actionText: "Calculating...", - unknownProgress: !knownProgress, - unknownDuration: false, - severity: "info", - options: [ - { - label: "Cancel Operation", - callback: function () { - $log.debug("Operation cancelled"); - dialog.dismiss(); - } - }, - { - label: "Do something else...", - callback: function () { - $log.debug("Something else pressed"); - } - } - ] - }; - - function incrementProgress() { - model.progress = Math.min(100, Math.floor(model.progress + Math.random() * 30)); - model.progressText = ["Estimated time remaining: about ", 60 - Math.floor((model.progress / 100) * 60), " seconds"].join(" "); - if (model.progress < 100) { - $timeout(incrementProgress, 1000); - } - } - - dialog = dialogService.showBlockingMessage(model); - - if (dialog) { - //Do processing here - model.actionText = "Processing 100 objects..."; - if (knownProgress) { - $timeout(incrementProgress, 1000); - } - } else { - $log.error("Could not display modal dialog"); - } - }; - - /* - Demonstrates launching an error dialog - */ - $scope.launchError = function () { - var dialog, - model = { - title: "Error Dialog Example", - actionText: "Something happened, and it was not good.", - severity: "error", - options: [ - { - label: "Try Again", - callback: function () { - $log.debug("Try Again Pressed"); - dialog.dismiss(); - } - }, - { - label: "Cancel", - callback: function () { - $log.debug("Cancel Pressed"); - dialog.dismiss(); - } - } - ] - }; - dialog = dialogService.showBlockingMessage(model); - - if (!dialog) { - $log.error("Could not display modal dialog"); - } - }; - - /* - Demonstrates launching an error dialog - */ - $scope.launchInfo = function () { - var dialog, - model = { - title: "Info Dialog Example", - actionText: "This is an example of a blocking info" - + " dialog. This dialog can be used to draw the user's" - + " attention to an event.", - severity: "info", - primaryOption: { - label: "OK", - callback: function () { - $log.debug("OK Pressed"); - dialog.dismiss(); - } - } - }; - - dialog = dialogService.showBlockingMessage(model); - - if (!dialog) { - $log.error("Could not display modal dialog"); - } - }; - - } - - return DialogLaunchController; - } -); diff --git a/example/notifications/src/DialogLaunchIndicator.js b/example/notifications/src/DialogLaunchIndicator.js deleted file mode 100644 index 79fa8985ae..0000000000 --- a/example/notifications/src/DialogLaunchIndicator.js +++ /dev/null @@ -1,55 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - "use strict"; - - /** - * A tool for manually invoking dialogs. When included this - * indicator will allow for dialogs of different types to be - * launched for demonstration and testing purposes. - * @constructor - */ - - function DialogLaunchIndicator() { - - } - - DialogLaunchIndicator.template = 'dialogLaunchTemplate'; - - DialogLaunchIndicator.prototype.getGlyphClass = function () { - return 'ok'; - }; - - DialogLaunchIndicator.prototype.getText = function () { - return "Launch test dialog"; - }; - - DialogLaunchIndicator.prototype.getDescription = function () { - return "Launch test dialog"; - }; - - return DialogLaunchIndicator; - } -); diff --git a/example/notifications/src/NotificationLaunchController.js b/example/notifications/src/NotificationLaunchController.js deleted file mode 100644 index d364d15505..0000000000 --- a/example/notifications/src/NotificationLaunchController.js +++ /dev/null @@ -1,126 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - "use strict"; - - /** - * Allows launching of notification messages for the purposes of - * demonstration and testing. Also demonstrates use of - * the NotificationService. Notifications are non-blocking messages that - * appear at the bottom of the screen to inform the user of events - * in a non-intrusive way. For more information see the - * {@link NotificationService} - * @param $scope - * @param $timeout - * @param $log - * @param notificationService - * @constructor - */ - function NotificationLaunchController($scope, $timeout, $log, notificationService) { - var messageCounter = 1; - - function getExampleActionText() { - var actionTexts = [ - "Adipiscing turpis mauris in enim elementu hac, enim aliquam etiam.", - "Eros turpis, pulvinar turpis eros eu", - "Lundium nascetur a, lectus montes ac, parturient in natoque, duis risus risus pulvinar pid rhoncus, habitasse auctor natoque!" - ]; - - return actionTexts[Math.floor(Math.random() * 3)]; - } - - /** - * Launch a new notification with a severity level of 'Error'. - */ - $scope.newError = function () { - notificationService.notify({ - title: "Example error notification " + messageCounter++, - hint: "An error has occurred", - severity: "error" - }); - }; - - /** - * Launch a new notification with a severity of 'Alert'. - */ - $scope.newAlert = function () { - notificationService.notify({ - title: "Alert notification " + (messageCounter++), - hint: "This is an alert message", - severity: "alert", - autoDismiss: true - }); - }; - - /** - * Launch a new notification with a progress bar that is updated - * periodically, tracking an ongoing process. - */ - $scope.newProgress = function () { - let progress = 0; - var notificationModel = { - title: "Progress notification example", - severity: "info", - progress: progress, - actionText: getExampleActionText() - }; - let notification; - - /** - * Simulate an ongoing process and update the progress bar. - * @param notification - */ - function incrementProgress() { - progress = Math.min(100, Math.floor(progress + Math.random() * 30)); - let progressText = ["Estimated time" - + " remaining:" - + " about ", 60 - Math.floor((progress / 100) * 60), " seconds"].join(" "); - notification.progress(progress, progressText); - - if (progress < 100) { - $timeout(function () { - incrementProgress(notificationModel); - }, 1000); - } - } - - notification = notificationService.notify(notificationModel); - incrementProgress(); - }; - - /** - * Launch a new notification with severity level of INFO. - */ - $scope.newInfo = function () { - notificationService.info({ - title: "Example Info notification " + messageCounter++ - }); - }; - - } - - return NotificationLaunchController; - } -); diff --git a/example/notifications/src/NotificationLaunchIndicator.js b/example/notifications/src/NotificationLaunchIndicator.js deleted file mode 100644 index 9923dab83a..0000000000 --- a/example/notifications/src/NotificationLaunchIndicator.js +++ /dev/null @@ -1,55 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - "use strict"; - - /** - * A tool for manually invoking notifications. When included this - * indicator will allow for notifications of different types to be - * launched for demonstration and testing purposes. - * @constructor - */ - - function NotificationLaunchIndicator() { - - } - - NotificationLaunchIndicator.template = 'notificationLaunchTemplate'; - - NotificationLaunchIndicator.prototype.getGlyphClass = function () { - return 'ok'; - }; - - NotificationLaunchIndicator.prototype.getText = function () { - return "Launch notification"; - }; - - NotificationLaunchIndicator.prototype.getDescription = function () { - return "Launch notification"; - }; - - return NotificationLaunchIndicator; - } -); diff --git a/example/persistence/bundle.js b/example/persistence/bundle.js deleted file mode 100644 index 057e19b653..0000000000 --- a/example/persistence/bundle.js +++ /dev/null @@ -1,54 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/BrowserPersistenceProvider" -], function ( - BrowserPersistenceProvider -) { - "use strict"; - - return { - name: "example/persistence", - definition: { - "extensions": { - "components": [ - { - "provides": "persistenceService", - "type": "provider", - "implementation": BrowserPersistenceProvider, - "depends": [ - "$q", - "PERSISTENCE_SPACE" - ] - } - ], - "constants": [ - { - "key": "PERSISTENCE_SPACE", - "value": "mct" - } - ] - } - } - }; -}); diff --git a/example/persistence/src/BrowserPersistenceProvider.js b/example/persistence/src/BrowserPersistenceProvider.js deleted file mode 100644 index a39c424b82..0000000000 --- a/example/persistence/src/BrowserPersistenceProvider.js +++ /dev/null @@ -1,102 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * Stubbed implementation of a persistence provider, - * to permit objects to be created, saved, etc. - */ -define( - [], - function () { - 'use strict'; - - function BrowserPersistenceProvider($q, SPACE) { - var spaces = SPACE ? [SPACE] : [], - caches = {}, - promises = { - as: function (value) { - return $q.when(value); - } - }; - - spaces.forEach(function (space) { - caches[space] = {}; - }); - - return { - listSpaces: function () { - return promises.as(spaces); - }, - listObjects: function (space) { - var cache = caches[space]; - - return promises.as( - cache ? Object.keys(cache) : null - ); - }, - createObject: function (space, key, value) { - var cache = caches[space]; - - if (!cache || cache[key]) { - return promises.as(null); - } - - cache[key] = value; - - return promises.as(true); - }, - readObject: function (space, key) { - var cache = caches[space]; - - return promises.as( - cache ? cache[key] : null - ); - }, - updateObject: function (space, key, value) { - var cache = caches[space]; - - if (!cache || !cache[key]) { - return promises.as(null); - } - - cache[key] = value; - - return promises.as(true); - }, - deleteObject: function (space, key, value) { - var cache = caches[space]; - - if (!cache || !cache[key]) { - return promises.as(null); - } - - delete cache[key]; - - return promises.as(true); - } - }; - - } - - return BrowserPersistenceProvider; - } -); diff --git a/example/policy/bundle.js b/example/policy/bundle.js deleted file mode 100644 index b409db4102..0000000000 --- a/example/policy/bundle.js +++ /dev/null @@ -1,45 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/ExamplePolicy" -], function ( - ExamplePolicy -) { - "use strict"; - - return { - name: "example/policy", - definition: { - "name": "Example Policy", - "description": "Provides an example of using policies to prohibit actions.", - "extensions": { - "policies": [ - { - "implementation": ExamplePolicy, - "category": "action" - } - ] - } - } - }; -}); diff --git a/example/policy/src/ExamplePolicy.js b/example/policy/src/ExamplePolicy.js deleted file mode 100644 index 1746f34cbc..0000000000 --- a/example/policy/src/ExamplePolicy.js +++ /dev/null @@ -1,47 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - "use strict"; - - function ExamplePolicy() { - return { - /** - * Disallow the Remove action on objects whose name contains - * "foo." - */ - allow: function (action, context) { - var domainObject = (context || {}).domainObject, - model = (domainObject && domainObject.getModel()) || {}, - name = model.name || "", - metadata = action.getMetadata() || {}; - - return metadata.key !== 'remove' || name.indexOf('foo') < 0; - } - }; - } - - return ExamplePolicy; - } -); diff --git a/example/profiling/bundle.js b/example/profiling/bundle.js deleted file mode 100644 index e4199c5344..0000000000 --- a/example/profiling/bundle.js +++ /dev/null @@ -1,55 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/WatchIndicator", - "./src/DigestIndicator" -], function ( - WatchIndicator, - DigestIndicator -) { - "use strict"; - - return { - name: "example/profiling", - definition: { - "extensions": { - "indicators": [ - { - "implementation": WatchIndicator, - "depends": [ - "$interval", - "$rootScope" - ] - }, - { - "implementation": DigestIndicator, - "depends": [ - "$interval", - "$rootScope" - ] - } - ] - } - } - }; -}); diff --git a/example/profiling/src/DigestIndicator.js b/example/profiling/src/DigestIndicator.js deleted file mode 100644 index a34187a9fd..0000000000 --- a/example/profiling/src/DigestIndicator.js +++ /dev/null @@ -1,82 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - "use strict"; - - /** - * Displays the number of digests that have occurred since the - * indicator was first instantiated. - * @constructor - * @param $interval Angular's $interval - * @implements {Indicator} - */ - function DigestIndicator($interval, $rootScope) { - var digests = 0, - displayed = 0, - start = Date.now(); - - function update() { - var now = Date.now(), - secs = (now - start) / 1000; - displayed = Math.round(digests / secs); - start = now; - digests = 0; - } - - function increment() { - digests += 1; - } - - $rootScope.$watch(increment); - - // Update state every second - $interval(update, 1000); - - // Provide initial state, too - update(); - - return { - /** - * Get the CSS class that defines the icon - * to display in this indicator. This will appear - * as a dataflow icon. - * @returns {string} the cssClass of the dataflow icon - */ - getCssClass: function () { - return "icon-connectivity"; - }, - getText: function () { - return displayed + " digests/sec"; - }, - getDescription: function () { - return ""; - } - }; - } - - return DigestIndicator; - - } -); diff --git a/example/profiling/src/WatchIndicator.js b/example/profiling/src/WatchIndicator.js deleted file mode 100644 index 6a569dea1f..0000000000 --- a/example/profiling/src/WatchIndicator.js +++ /dev/null @@ -1,86 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - "use strict"; - - /** - * Updates a count of currently-active Angular watches. - * @constructor - * @param $interval Angular's $interval - */ - function WatchIndicator($interval, $rootScope) { - var watches = 0; - - function count(scope) { - if (scope) { - watches += (scope.$$watchers || []).length; - count(scope.$$childHead); - count(scope.$$nextSibling); - } - } - - function update() { - watches = 0; - count($rootScope); - } - - // Update state every second - $interval(update, 1000); - - // Provide initial state, too - update(); - - return { - /** - * Get the CSS class (single character used as an icon) - * to display in this indicator. This will return ".", - * which should appear as a database icon. - * @returns {string} the character of the database icon - */ - getCssClass: function () { - return "icon-database"; - }, - /** - * Get the text that should appear in the indicator. - * @returns {string} brief summary of connection status - */ - getText: function () { - return watches + " watches"; - }, - /** - * Get a longer-form description of the current connection - * space, suitable for display in a tooltip - * @returns {string} longer summary of connection status - */ - getDescription: function () { - return ""; - } - }; - } - - return WatchIndicator; - - } -); diff --git a/example/scratchpad/README.md b/example/scratchpad/README.md deleted file mode 100644 index 624a4786b4..0000000000 --- a/example/scratchpad/README.md +++ /dev/null @@ -1,2 +0,0 @@ -Example of using multiple persistence stores by exposing a root -object with a different space prefix. diff --git a/example/scratchpad/bundle.js b/example/scratchpad/bundle.js deleted file mode 100644 index 1e85ec1c06..0000000000 --- a/example/scratchpad/bundle.js +++ /dev/null @@ -1,63 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/ScratchPersistenceProvider" -], function ( - ScratchPersistenceProvider -) { - "use strict"; - - return { - name: "example/scratchpad", - definition: { - "extensions": { - "roots": [ - { - "id": "scratch:root" - } - ], - "models": [ - { - "id": "scratch:root", - "model": { - "type": "folder", - "composition": [], - "name": "Scratchpad" - }, - "priority": "preferred" - } - ], - "components": [ - { - "provides": "persistenceService", - "type": "provider", - "implementation": ScratchPersistenceProvider, - "depends": [ - "$q" - ] - } - ] - } - } - }; -}); diff --git a/example/scratchpad/src/ScratchPersistenceProvider.js b/example/scratchpad/src/ScratchPersistenceProvider.js deleted file mode 100644 index 207e40b497..0000000000 --- a/example/scratchpad/src/ScratchPersistenceProvider.js +++ /dev/null @@ -1,79 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - 'use strict'; - - /** - * The ScratchPersistenceProvider keeps JSON documents in memory - * and provides a persistence interface, but changes are lost on reload. - * @memberof example/scratchpad - * @constructor - * @implements {PersistenceService} - * @param q Angular's $q, for promises - */ - function ScratchPersistenceProvider($q) { - this.$q = $q; - this.table = {}; - } - - ScratchPersistenceProvider.prototype.listSpaces = function () { - return this.$q.when(['scratch']); - }; - - ScratchPersistenceProvider.prototype.listObjects = function (space) { - return this.$q.when( - space === 'scratch' ? Object.keys(this.table) : [] - ); - }; - - ScratchPersistenceProvider.prototype.createObject = function (space, key, value) { - if (space === 'scratch') { - this.table[key] = JSON.stringify(value); - } - - return this.$q.when(space === 'scratch'); - }; - - ScratchPersistenceProvider.prototype.readObject = function (space, key) { - return this.$q.when( - (space === 'scratch' && this.table[key]) - ? JSON.parse(this.table[key]) : undefined - ); - }; - - ScratchPersistenceProvider.prototype.deleteObject = function (space, key, value) { - if (space === 'scratch') { - delete this.table[key]; - } - - return this.$q.when(space === 'scratch'); - }; - - ScratchPersistenceProvider.prototype.updateObject = - ScratchPersistenceProvider.prototype.createObject; - - return ScratchPersistenceProvider; - } -); diff --git a/example/styleguide/bundle.js b/example/styleguide/bundle.js deleted file mode 100644 index e1af53082a..0000000000 --- a/example/styleguide/bundle.js +++ /dev/null @@ -1,188 +0,0 @@ -define([ - "./src/ExampleStyleGuideModelProvider", - "./src/MCTExample", - "./res/templates/intro.html", - "./res/templates/standards.html", - "./res/templates/colors.html", - "./res/templates/status.html", - "./res/templates/glyphs.html", - "./res/templates/controls.html", - "./res/templates/input.html", - "./res/templates/menus.html" -], function ( - ExampleStyleGuideModelProvider, - MCTExample, - introTemplate, - standardsTemplate, - colorsTemplate, - statusTemplate, - glyphsTemplate, - controlsTemplate, - inputTemplate, - menusTemplate -) { - return { - name: "example/styleguide", - definition: { - "name": "Open MCT Style Guide", - "description": "Examples and documentation illustrating UI styles in use in Open MCT.", - "extensions": - { - "types": [ - { - "key": "styleguide.intro", - "name": "Introduction", - "cssClass": "icon-page", - "description": "Introduction and overview to the style guide" - }, - { - "key": "styleguide.standards", - "name": "Standards", - "cssClass": "icon-page", - "description": "" - }, - { - "key": "styleguide.colors", - "name": "Colors", - "cssClass": "icon-page", - "description": "" - }, - { - "key": "styleguide.status", - "name": "status", - "cssClass": "icon-page", - "description": "Limits, telemetry paused, etc." - }, - { - "key": "styleguide.glyphs", - "name": "Glyphs", - "cssClass": "icon-page", - "description": "Glyphs overview" - }, - { - "key": "styleguide.controls", - "name": "Controls", - "cssClass": "icon-page", - "description": "Buttons, selects, HTML controls" - }, - { - "key": "styleguide.input", - "name": "Text Inputs", - "cssClass": "icon-page", - "description": "Various text inputs" - }, - { - "key": "styleguide.menus", - "name": "Menus", - "cssClass": "icon-page", - "description": "Context menus, dropdowns" - } - ], - "views": [ - { - "key": "styleguide.intro", - "type": "styleguide.intro", - "template": introTemplate, - "editable": false - }, - { - "key": "styleguide.standards", - "type": "styleguide.standards", - "template": standardsTemplate, - "editable": false - }, - { - "key": "styleguide.colors", - "type": "styleguide.colors", - "template": colorsTemplate, - "editable": false - }, - { - "key": "styleguide.status", - "type": "styleguide.status", - "template": statusTemplate, - "editable": false - }, - { - "key": "styleguide.glyphs", - "type": "styleguide.glyphs", - "template": glyphsTemplate, - "editable": false - }, - { - "key": "styleguide.controls", - "type": "styleguide.controls", - "template": controlsTemplate, - "editable": false - }, - { - "key": "styleguide.input", - "type": "styleguide.input", - "template": inputTemplate, - "editable": false - }, - { - "key": "styleguide.menus", - "type": "styleguide.menus", - "template": menusTemplate, - "editable": false - } - ], - "roots": [ - { - "id": "styleguide:home" - } - ], - "models": [ - { - "id": "styleguide:home", - "priority": "preferred", - "model": { - "type": "noneditable.folder", - "name": "Style Guide Home", - "location": "ROOT", - "composition": [ - "intro", - "standards", - "colors", - "status", - "glyphs", - "styleguide:ui-elements" - ] - } - }, - { - "id": "styleguide:ui-elements", - "priority": "preferred", - "model": { - "type": "noneditable.folder", - "name": "UI Elements", - "location": "styleguide:home", - "composition": [ - "controls", - "input", - "menus" - ] - } - } - ], - "directives": [ - { - "key": "mctExample", - "implementation": MCTExample - } - ], - "components": [ - { - "provides": "modelService", - "type": "provider", - "implementation": ExampleStyleGuideModelProvider, - "depends": [ - "$q" - ] - } - ] - } - } - }; -}); diff --git a/example/styleguide/res/images/diagram-containment.svg b/example/styleguide/res/images/diagram-containment.svg deleted file mode 100644 index a718ae33ac..0000000000 --- a/example/styleguide/res/images/diagram-containment.svg +++ /dev/null @@ -1 +0,0 @@ -dFolderActivity ModeTelemetry ElementClockTimerWeb PageDisplay LayoutTimelineFixedPacketActivityTablePlotCan contain their own type \ No newline at end of file diff --git a/example/styleguide/res/images/diagram-objects.svg b/example/styleguide/res/images/diagram-objects.svg deleted file mode 100644 index c457666dcf..0000000000 --- a/example/styleguide/res/images/diagram-objects.svg +++ /dev/null @@ -1 +0,0 @@ -Telemetry Elementdiagram-objectsDisplay LayoutPlotClockTable \ No newline at end of file diff --git a/example/styleguide/res/images/diagram-views.svg b/example/styleguide/res/images/diagram-views.svg deleted file mode 100644 index c62a2fc3a7..0000000000 --- a/example/styleguide/res/images/diagram-views.svg +++ /dev/null @@ -1 +0,0 @@ -objects-diagram \ No newline at end of file diff --git a/example/styleguide/res/templates/colors.html b/example/styleguide/res/templates/colors.html deleted file mode 100644 index 7de28dd774..0000000000 --- a/example/styleguide/res/templates/colors.html +++ /dev/null @@ -1,84 +0,0 @@ - -
- - - -
-

Open MCT Style Guide

-

Colors

- -
-

Overview

-

In mission operations, color is used to convey meaning. Alerts, warnings and status conditions are by convention communicated with colors in the green, yellow and red families. Colors must also be reserved for use in plots. As a result, Open MCT uses color selectively and sparingly. Follow these guidelines:

-
    -
  • Don't use red, orange, yellow or green colors in any element that isn't conveying some kind of status information.
  • -
  • Each theme has a key color (typically blue-ish) that should be used to emphasize interactive elements and important UI controls.
  • -
  • Within each theme values are used to push elements back or bring them forward, lowering or raising them in visual importance. - In this theme, Espresso, lighter colors are placed on a dark background. The lighter a color is, the more it comes toward the observer and is raised in importance. - In this theme, Snow, darker colors are placed on a light background. The darker a color is, the more it comes toward the observer and is raised in importance. -
  • -
  • For consistency, use a theme's pre-defined status colors.
  • -
-
- -
-

{{ colorSet.category }}

-

{{ colorSet.description }}

-
-
-
-
-
-
- - - - -
Name{{color.name}}
SASS{{color.constant}}
Value - {{color.valEspresso}} - {{color.valSnow}} -
-
-
-
-
\ No newline at end of file diff --git a/example/styleguide/res/templates/controls.html b/example/styleguide/res/templates/controls.html deleted file mode 100644 index 80ecfc137a..0000000000 --- a/example/styleguide/res/templates/controls.html +++ /dev/null @@ -1,172 +0,0 @@ - -
-

Open MCT Style Guide

-

Controls

- -
-

Standard Buttons

-
-
-

Use a standard button in locations where there's sufficient room and you must make it clear that the element is an interactive button element. Buttons can be displayed with only an icon, only text, or with icon and text combined.

-

Use an icon whenever possible to aid the user's recognition and recall. If both and icon and text are to be used, the text must be within a span with class .title-label.

-
- -Edit - - Edit - - -
-
- -
-

"Major" Buttons

-
-
-

Major buttons allow emphasis to be placed on a button. Use this on a single button when the user has a small number of choices, and one choice is a normal default. Just add .major to any element that uses .s-button.

-
-Ok -Cancel - -
-
- -
-

Button Sets

-
-
-

Use button sets to connect buttons that have related purpose or functionality. Buttons in a set round the outer corners of only the first and last buttons, any other buttons in the middle simply get division spacers.

-

To use, simply wrap two or more .s-button elements within .l-btn-set.

-
- - - - - - -
-
- -
-

Icon-only Buttons

-
-
-

When a button is presented within another control it may be advantageous to avoid visual clutter by using an icon-only button. These type of controls present an icon without the "base" of standard buttons. Icon-only buttons should only be used in a context where they are clearly an interactive element and not an object-type identifier, and should not be used with text.

-
- - -
-
- -
-

Checkboxes

-
-
-

Checkboxes use a combination of minimal additional markup with CSS to present a custom and common look-and-feel across platforms.

-

The basic structure is a label with a checkbox-type input and an em element inside. The em is needed as the holder of the custom element; the input itself is hidden. Putting everything inside the label allows the label itself to act as a clickable element.

-
- -
- -
-
-
-
- -
-

Radio Buttons

-
-
-

Radio buttons use the same technique as checkboxes above.

-
- -
- -
- -
-
-
- -
-

Selects

-
-
-

Similar to checkboxes and radio buttons, selects use a combination of minimal additional markup with CSS to present a custom and common look-and-feel across platforms. The select element is wrapped by another element, such as a div, which acts as the main display element for the styling. The select provides the click and select functionality, while having all of its native look-and-feel suppressed.

-
-
- -
-
-
-
- -
-

Local Controls

-
-
-

Local controls are typically buttons and selects that provide actions in close proximity to a component.

-

These controls can optionally be hidden to reduce clutter until the user hovers their cursor over an enclosing element. To use this approach, apply the class .has-local-controls to the element that should be aware of the hover and ensure that element encloses .h-local-controls.

-
-
- Some content in here -
- - -
-
-
- Hover here -
- - -
-
-
-
- -
diff --git a/example/styleguide/res/templates/glyphs.html b/example/styleguide/res/templates/glyphs.html deleted file mode 100644 index e5c56479cb..0000000000 --- a/example/styleguide/res/templates/glyphs.html +++ /dev/null @@ -1,216 +0,0 @@ - -
- -
-

Open MCT Style Guide

-

Glyphs

-
-

Symbolic glyphs are used extensively in Open MCT to call attention to interactive elements, identify objects, and aid in visual recall. Glyphs are made available in a custom symbols font, and have associated CSS classes for their usage. Using a font in this way (versus using images or sprites) has advantages in that each symbol is in effect a scalable vector that can be sized up or down as needed. Color can also quite easily be applied via CSS.

-

New glyphs can be added if needed. Take care to observe the following guidelines: -

    -
  • Symbols should be created at 512 pixels high, and no more than 512 pixels wide. This size is based on a "crisp" 16px approach. Find out more about crisp symbol fonts.
  • -
  • In general, the symbol should occupy most of a square area as possible; avoid symbol aspect ratios that are squat or tall.
  • -
  • For consistency and legibility, symbols are designed as mostly solid shapes. Avoid using thin lines or fine detail that will be lost when the icon is sized down. In general, no stroke should be less than 32 pixels.
  • -
  • Symbols should be legible down to a minimum of 12 x 12 pixels.
  • - -
-

-
- -
-

How to Use Glyphs

-
-
-

The easiest way to use a glyph is to include its CSS class in an element. The CSS adds a pseudo :before HTML element to whatever element it's attached to that makes proper use of the symbols font.

-

Alternately, you can use the .ui-symbol class in an object that contains encoded HTML entities. This method is only recommended if you cannot use the aforementioned CSS class approach.

-
- -

- -

-
  
-
-
-
- -
-

General User Interface Glyphs

-

Glyphs suitable for denoting general user interface verbs and nouns.

-
-
-
- - - - - -
Class.{{glyph.cssClass}}
Meaning{{glyph.meaning}}
CSS Content\{{glyph.cssContent}}
HTML Entity{{glyph.htmlEntity}}
-
-
-
- -
-

Control Glyphs

-

Glyphs created for use in various controls.

-
-
-
- - - - - -
Class.{{glyph.cssClass}}
Meaning{{glyph.meaning}}
CSS Content\{{glyph.cssContent}}
HTML Entity{{glyph.htmlEntity}}
-
-
-
- -
-

Object Type Glyphs

-

These glyphs are reserved exclusively to denote types of objects in the application. Only use them if you are referring to a pre-existing object type.

-
-
-
- - - - - -
Class.{{glyph.cssClass}}
Meaning{{glyph.meaning}}
CSS Content\{{glyph.cssContent}}
HTML Entity{{glyph.htmlEntity}}
-
-
-
- -
- diff --git a/example/styleguide/res/templates/input.html b/example/styleguide/res/templates/input.html deleted file mode 100644 index e61c70ca72..0000000000 --- a/example/styleguide/res/templates/input.html +++ /dev/null @@ -1,75 +0,0 @@ - -
-

Open MCT Style Guide

-

Text Input

-
-

Text inputs and textareas have a consistent look-and-feel across the application. The input's placeholder attribute is styled to appear visually different from an entered value.

-
- -
-

Text Inputs

-
-
-

Use a text input where the user should enter relatively short text entries.

-

A variety of size styles are available: .lg, .med and .sm. .lg text inputs dynamically scale their width to 100% of their container's width. Numeric inputs that benefit from right-alignment can be styled by adding .numeric.

-
- -

- -

- -

- -

- -

- -
-
-
- -
-

Textareas

-
-
-

Use a textarea where the user should enter relatively longer or multi-line text entries.

-

By default, textareas are styled to expand to 100% of the width and height of their container; additionally there are three size styles available that control the height of the element: .lg, .med and .sm.

-
-
- -
-
-
- -
-

- -

- -

- -
-
-
-
- diff --git a/example/styleguide/res/templates/intro.html b/example/styleguide/res/templates/intro.html deleted file mode 100644 index b115d16454..0000000000 --- a/example/styleguide/res/templates/intro.html +++ /dev/null @@ -1,73 +0,0 @@ - -
-

Open MCT Style Guide

-

Introduction

-
-

Open MCT is a robust, extensible telemetry monitoring and situational awareness system that provides a framework supporting fast and efficient multi-mission deployment. This guide will explore the major concepts and design elements of Open MCT. Its overall goal is to guide you in creating new features and plugins that seamlessly integrate with the base application.

-
- -
-

Everything Is An Object

-
-
-

First and foremost, Open MCT uses a “object-oriented” approach: everything in the system is an object. Objects come in different types, and some objects can contain other objects of given types. This is similar to how the file management system of all modern computers works: a folder object can contain any other type of object, a presentation file can contain an image. This is conceptually the same in Open MCT.

-

As you develop plugins for Open MCT, consider how a generalized component might be combined with others when designing to create a rich and powerful larger object, rather than adding a single monolithic, non-modular plugin. To solve a particular problem or allow a new feature in Open MCT, you may need to introduce more than just one new object type.

-
-
- -
-
-
- -
-

Object Types

-
-
-

In the same way that different types of files might be opened and edited by different applications, objects in Open MCT also have different types. For example, a Display Layout provides a way that other objects that display information can be combined and laid out in a canvas area to create a recallable display that suits the needs of the user that created it. A Telemetry Panel allows a user to collect together Telemetry Points and visualize them as a plot or a table.

-

Object types provide a containment model that guides the user in their choices while creating a new object, and allows view normalization when flipping between different views. When a given object may only contain other objects of certain types, advantages emerge: the result of adding new objects is more predictable, more alternate views can be provided because the similarities between the contained objects is close, and we can provide more helpful and pointed guidance to the user because we know what types of objects they might be working with at a given time.

-

The types of objects that a container can hold should be based on the purpose of the container and the views that it affords. For example, a Folder’s purpose is to allow a user to conceptually organize objects of all other types; a Folder must therefore be able to contain an object of any type.

-
-
- -
-
-
- -
-

Object Views

-
-
-

Views are simply different ways to view the content of a given object. For example, telemetry data could be viewed as a plot or a table. A clock can display its time in analog fashion or with digital numbers. In each view, all of the content is present; it’s just represented differently. When providing views for an object, all the content of the object should be present in each view.

-
-
- -
-
-
- - - -

-

-

-
diff --git a/example/styleguide/res/templates/mct-example.html b/example/styleguide/res/templates/mct-example.html deleted file mode 100644 index a7fb0b5d0b..0000000000 --- a/example/styleguide/res/templates/mct-example.html +++ /dev/null @@ -1,8 +0,0 @@ -
-

Markup

- -

-    
-

Example

-
-
diff --git a/example/styleguide/res/templates/menus.html b/example/styleguide/res/templates/menus.html deleted file mode 100644 index f59588044d..0000000000 --- a/example/styleguide/res/templates/menus.html +++ /dev/null @@ -1,168 +0,0 @@ - -
-

Open MCT Style Guide

-

Menus

- -
-

Context Menus

-
-
-

Context menus are used extensively in Open MCT. They are created dynamically upon a contextual click and positioned at the user's cursor position coincident with the element that invoked them. Context menus must use absolute position and utilize a z-index that places them above other in-page elements.

-

See User Interface Standards for more details on z-indexing in Open MCT. Context menus should be destroyed if the user clicks outside the menu element.

-
-
- -
-
-
- -
-

Dropdown Menus

-
-
-

Dropdown menus are a dedicated, more discoverable context menu for a given object. Like context menus, dropdown menus are used extensively in Open MCT, and are most often associated with object header elements. They visually manifest as a downward pointing arrow associated with an element, and when clicked displays a context menu at that location. See guidelines above about context menus in regards to z-indexing and element lifecycle.

-

Use a dropdown menu to encapsulate important the actions of an object in the object's header, or in a place that you'd use a context menu, but want to make the availability of the menu more apparent.

-
-
- -
- - - Object Header - - - - - - -
- -
-
-
- -
-

Checkbox Menus

-
-
-

Checkbox menus add checkbox options to each item of a dropdown menu. Use this to

-

Use a dropdown menu to encapsulate important the actions of an object in the object's header, or in a place that you'd use a context menu, but want to make the availability of the menu more apparent.

-
-
-
- -
-
-
-
-
- -
-

Palettes

-
-
-

Use a palette to provide color choices. Similar to context menus and dropdowns, palettes should be dismissed when a choice is made within them, or if the user clicks outside one. Selected palette choices should utilize the selected CSS class to visualize indicate that state.

-

Note that while this example uses static markup for illustrative purposes, don't do this - use a front-end framework with repeaters to build the color choices.

-
-
- - - -
-
-
- -
diff --git a/example/styleguide/res/templates/standards.html b/example/styleguide/res/templates/standards.html deleted file mode 100644 index 9ac87d000e..0000000000 --- a/example/styleguide/res/templates/standards.html +++ /dev/null @@ -1,48 +0,0 @@ - -
-

Open MCT Style Guide

-

Standards

- -
-

Absolute Positioning and Z-Indexing

-

Absolute positioning is used in Open MCT in the main envelope interface to handle layout and draggable pane splitters, for elements that must be dynamically created and positioned (like context menus) and for buttons that are placed over other elements, such as a plot's zoom/pan history and reset buttons. When using absolute positioning, follow these guidelines:

-
    -
  • Don't specify a z-index if you don't have to.
  • -
  • If you must specify a z-index, use the lowest number you that prevents your element from being covered and puts it at the correct level per the table below.
  • -
- - - - - - - - - - - - -
TypeDescriptionZ-index Range
Base interface itemsBase level elements0 - 1
Primary paneElements in the primary "view area" pane2
Inspector pane, splittersElements in the Inspector, and splitters themselves3
More base interface stuffBase level elements4 - 9
TreeviewLefthand treeview elements30 - 39
Help bubbles, rollover hintsInfobubbles, and similar50 - 59
Context, button and dropdown menusContext menus, button menus, etc. that must overlay other elements70 - 79
OverlaysModal overlay displays100 - 109
Event messagesAlerts, event dialogs1000
-
- -
\ No newline at end of file diff --git a/example/styleguide/res/templates/status.html b/example/styleguide/res/templates/status.html deleted file mode 100644 index 864a988f99..0000000000 --- a/example/styleguide/res/templates/status.html +++ /dev/null @@ -1,227 +0,0 @@ - - -
-

Open MCT Style Guide

-

Status Indication

- -
-

Status Classes

-
-
-

Status classes allow any block or inline-block element to be decorated in order to articulate a - status. Provided classes include color-only and color plus icon; custom icons can easily be - employed by using a color-only status class in combination with an glyph.

-
    -
  • Color only
  • -
      -
    • s-status-warning-hi
    • -
    • s-status-warning-lo
    • -
    • s-status-diagnostic
    • -
    • s-status-info
    • -
    • s-status-ok
    • -
    -
  • Color and icon
  • -
      -
    • s-status-icon-warning-hi
    • -
    • s-status-icon-warning-lo
    • -
    • s-status-icon-diagnostic
    • -
    • s-status-icon-info
    • -
    • s-status-icon-ok
    • -
    -
-
- -
WARNING HI
-
WARNING LOW
-
DIAGNOSTIC
-
INFO
-
OK
- - -
WARNING HI with icon
-
WARNING LOW with icon
-
DIAGNOSTIC with icon
-
INFO with icon
-
OK with icon
-
WARNING HI with custom icon
-
Some text with an inline element showing a Diagnostic status.
-
-
-
- -
-

Limit Classes

-
-
-

Limit classes are a specialized form of status, specifically meant to be applied to telemetry - displays to indicate that a limit threshold has been violated. Open MCT provides both severity - and direction classes; severity (yellow and red) can be used alone or in combination - with direction (upper or lower). Direction classes cannot be used on their own.

-

Like Status classes, Limits can be used as color-only, or color plus icon. Custom icons can - be applied in the same fashion as described above.

-
    -
  • Severity color alone
  • -
      -
    • s-limit-yellow: A yellow limit.
    • -
    • s-limit-red: A red limit.
    • -
    -
  • Severity color and icon
  • -
      -
    • s-limit-icon-yellow: A yellow limit with icon.
    • -
    • s-limit-icon-red: A red limit with icon.
    • -
    -
  • Direction indicators. MUST be used with a "color alone" limit class. See - examples for more.
  • -
      -
    • s-limit-upr: Upper limit.
    • -
    • s-limit-lwr: Lower limit.
    • -
    -
-
- -
Yellow limit
-
Red limit
- - -
Yellow limit with icon
-
Red limit with icon
-
Red Limit with a custom icon
-
Some text with an inline element showing a yellow limit.
- - -
Lower yellow limit
-
Upper red limit
- - - - - - - -
NameValue 1Value 2
ENG_PWR 49917.02370.23
ENG_PWR 499249.784-121.22
ENG_PWR 49930.4511.007
-
-
-
- -
-

Status Bar Indicators

-
-
-

Indicators are small iconic notification elements that appear in the Status Bar area of - the application at the window's bottom. Indicators should be used to articulate the state of a - system and optionally provide gestures related to that system. They use a combination of icon and - color to identify themselves and articulate a state respectively.

-

Recommendations

-
    -
  • Keep the icon consistent. The icon is the principal identifier of the system and is a valuable - recall aid for the user. Don't change the icon as a system's state changes, use color and - text for that purpose.
  • -
  • Don't use the same icon more than once. Select meaningful and distinct icons so the user - will be able to quickly identify what they're looking for.
  • -
- -

States

-
    -
  • Disabled: The system is not available to the user.
  • -
  • Off / Available: The system is accessible to the user but is not currently - "On" or has not been configured. If the Indicator directly provides gestures - related to the system, such as opening a configuration dialog box, then use - "Available"; if the user must act elsewhere or the system isn't user-controllable, - use "Off".
  • -
  • On: The system is enabled or configured; it is having an effect on the larger application.
  • -
  • Alert / Error: There has been a problem with the system. Generally, "Alert" - should be used to call attention to an issue that isn't critical, while "Error" - should be used to call attention to a problem that the user should really be aware of or do - something about.
  • -
- -

Structure

-

Indicators consist of a .ls-indicator - wrapper element with .icon-* classes for the type of thing they represent and - .s-status-* classes to articulate the current state. Title attributes should be used - to provide more verbose information about the thing and/or its status.

-

The wrapper encloses a .label element that is displayed on hover. This element should - include a brief statement of the current status, and can also include clickable elements - as <a> tags. An optional .count element can be included to display - information such as a number of messages.

-

Icon classes are as defined on the - - Glyphs page. Status classes applicable to Indicators are as follows:

-
    -
  • s-status-disabled
  • -
  • s-status-off
  • -
  • s-status-available
  • -
  • s-status-on
  • -
  • s-status-alert
  • -
  • s-status-error
  • -
-
-
- - System not enabled. - -
- -
- - Data connection available - Configure - - -
- -
- - Connected to Skynet - Change - Disconnect - - -
- -
- - Skynet at Turing Level 5 - - - - View Alerts - - 495 - -
-
-
-
-
diff --git a/example/styleguide/src/ExampleStyleGuideModelProvider.js b/example/styleguide/src/ExampleStyleGuideModelProvider.js deleted file mode 100644 index 1abe4b1124..0000000000 --- a/example/styleguide/src/ExampleStyleGuideModelProvider.js +++ /dev/null @@ -1,82 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - "use strict"; - - function ExampleStyleGuideModelProvider($q) { - var pages = {}; - - // Add pages - pages.intro = { - name: "Introduction", - type: "styleguide.intro", - location: "styleguide:home" - }; - pages.standards = { - name: "Standards", - type: "styleguide.standards", - location: "styleguide:home" - }; - pages.colors = { - name: "Colors", - type: "styleguide.colors", - location: "styleguide:home" - }; - pages.glyphs = { - name: "Glyphs", - type: "styleguide.glyphs", - location: "styleguide:home" - }; - pages.status = { - name: "Status Indication", - type: "styleguide.status", - location: "styleguide:home" - }; - pages.controls = { - name: "Controls", - type: "styleguide.controls", - location: "styleguide:ui-elements" - }; - pages.input = { - name: "Text Inputs", - type: "styleguide.input", - location: "styleguide:ui-elements" - }; - pages.menus = { - name: "Menus", - type: "styleguide.menus", - location: "styleguide:ui-elements" - }; - - return { - getModels: function () { - return $q.when(pages); - } - }; - } - - return ExampleStyleGuideModelProvider; - } -); diff --git a/example/styleguide/src/MCTExample.js b/example/styleguide/src/MCTExample.js deleted file mode 100644 index 43b82a2c44..0000000000 --- a/example/styleguide/src/MCTExample.js +++ /dev/null @@ -1,30 +0,0 @@ -define([ - '../res/templates/mct-example.html' -], function ( - MCTExampleTemplate -) { - - function MCTExample() { - function link($scope, $element, $attrs, controller, $transclude) { - var codeEl = $element.find('pre'); - var exampleEl = $element.find('div'); - - $transclude(function (clone) { - exampleEl.append(clone); - codeEl.text(exampleEl.html() - .replace(/ class="ng-scope"/g, "") - .replace(/ ng-scope"/g, '"')); - }); - } - - return { - restrict: "E", - template: MCTExampleTemplate, - transclude: true, - link: link, - replace: true - }; - } - - return MCTExample; -}); diff --git a/karma.conf.js b/karma.conf.js index 92871774b3..d8db916b00 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -102,7 +102,7 @@ module.exports = (config) => { reports: ['lcovonly', 'text-summary'], thresholds: { global: { - lines: 55 + lines: 52 } } }, diff --git a/package.json b/package.json index 434f7935c7..a0d92803a0 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,6 @@ "@percy/playwright": "1.0.1", "@playwright/test": "1.18.1", "allure-playwright": "2.0.0-beta.14", - "angular": ">=1.8.0", - "angular-route": "1.4.14", "babel-eslint": "10.1.0", "comma-separated-values": "3.6.4", "copy-webpack-plugin": "10.2.0", @@ -81,8 +79,8 @@ "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", + "lint": "eslint example src --ext .js,.vue openmct.js", + "lint:fix": "eslint example src --ext .js,.vue openmct.js --fix", "build:prod": "cross-env webpack --config webpack.prod.js", "build:dev": "webpack --config webpack.dev.js", "build:watch": "webpack --config webpack.dev.js --watch", diff --git a/platform/README.md b/platform/README.md deleted file mode 100644 index e5144829f1..0000000000 --- a/platform/README.md +++ /dev/null @@ -1,2 +0,0 @@ -This directory contains all bundles for the Open MCT platform, as well -as the framework which runs them. diff --git a/platform/commonUI/README.md b/platform/commonUI/README.md deleted file mode 100644 index 29e0f86c1c..0000000000 --- a/platform/commonUI/README.md +++ /dev/null @@ -1,17 +0,0 @@ -This directory contains bundles containing common user interface -elements of Open MCT; that is, the user interface for the application -as a whole (as opposed to for specific features) is implemented here. - -# Extensions - -This bundles adds a `stylesheets` extension category used to inject CSS -from bundles. These extensions are declaration-only (no scripted -implementation is needed or used); a single property, `stylesheetUrl`, -should be provided, with a path to the relevant CSS file (including -extension) relative to the resources directory for that bundle. - -Links to these CSS files are appended to the head when the application -is started. These are added in standard priority order (see documentation -for the framework layer); the order of inclusion of style sheets can -change the way they are handled/understood by the browser, so priority -can be used to provide control over this order. diff --git a/platform/commonUI/browse/bundle.js b/platform/commonUI/browse/bundle.js deleted file mode 100644 index 46cce1c8b2..0000000000 --- a/platform/commonUI/browse/bundle.js +++ /dev/null @@ -1,158 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/navigation/NavigationService", - "./src/navigation/NavigateAction", - "./src/navigation/OrphanNavigationHandler", - "./res/templates/browse.html", - "./res/templates/browse-object.html", - "./res/templates/browse/object-header.html", - "./res/templates/browse/object-header-frame.html", - "./res/templates/menu-arrow.html", - "./res/templates/back-arrow.html", - "./res/templates/browse/object-properties.html", - "./res/templates/browse/inspector-region.html" -], function ( - NavigationService, - NavigateAction, - OrphanNavigationHandler, - browseTemplate, - browseObjectTemplate, - objectHeaderTemplate, - objectHeaderFrameTemplate, - menuArrowTemplate, - backArrowTemplate, - objectPropertiesTemplate, - inspectorRegionTemplate -) { - - return { - name: "platform/commonUI/browse", - definition: { - "extensions": { - "routes": [ - ], - "constants": [ - { - "key": "DEFAULT_PATH", - "value": "mine", - "priority": "fallback" - } - ], - "representations": [ - { - "key": "browse-object", - "template": browseObjectTemplate, - "gestures": [ - "drop" - ], - "uses": [ - "view" - ] - }, - { - "key": "object-header", - "template": objectHeaderTemplate, - "uses": [ - "type" - ] - }, - { - "key": "object-header-frame", - "template": objectHeaderFrameTemplate, - "uses": [ - "type" - ] - }, - { - "key": "menu-arrow", - "template": menuArrowTemplate, - "uses": [ - "action" - ], - "gestures": [ - "menu" - ] - }, - { - "key": "back-arrow", - "uses": [ - "context" - ], - "template": backArrowTemplate - }, - { - "key": "object-properties", - "template": objectPropertiesTemplate - }, - { - "key": "inspector-region", - "template": inspectorRegionTemplate - } - ], - "services": [ - { - "key": "navigationService", - "implementation": NavigationService, - "depends": [ - "$window" - ] - } - ], - "actions": [ - { - "key": "navigate", - "implementation": NavigateAction, - "depends": [ - "navigationService" - ] - } - ], - "runs": [ - { - "implementation": OrphanNavigationHandler, - "depends": [ - "throttle", - "topic", - "navigationService" - ] - } - ], - "templates": [ - { - key: "browseRoot", - template: browseTemplate - }, - { - key: "browseObject", - template: browseObjectTemplate - }, - { - key: "inspectorRegion", - template: inspectorRegionTemplate - } - ] - } - } - }; -}); diff --git a/platform/commonUI/browse/res/templates/back-arrow.html b/platform/commonUI/browse/res/templates/back-arrow.html deleted file mode 100644 index 29ccc93a95..0000000000 --- a/platform/commonUI/browse/res/templates/back-arrow.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - diff --git a/platform/commonUI/browse/res/templates/browse-object.html b/platform/commonUI/browse/res/templates/browse-object.html deleted file mode 100644 index ecbf076737..0000000000 --- a/platform/commonUI/browse/res/templates/browse-object.html +++ /dev/null @@ -1,69 +0,0 @@ - -
-
-
- - - -
-
- - - - - - - -
-
-
-
- -
- - - -
- - -
-
-
diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html deleted file mode 100644 index 3cac7a6cce..0000000000 --- a/platform/commonUI/browse/res/templates/browse.html +++ /dev/null @@ -1,90 +0,0 @@ - - -
- -
- -
-
- - - - - - -
-
- - - -
- - -
- - -
- - - -
- - - -
- - -
-
-
-
-
-
- -
diff --git a/platform/commonUI/browse/res/templates/browse/inspector-region.html b/platform/commonUI/browse/res/templates/browse/inspector-region.html deleted file mode 100644 index b637e8e3c2..0000000000 --- a/platform/commonUI/browse/res/templates/browse/inspector-region.html +++ /dev/null @@ -1,39 +0,0 @@ - -
- - - -
- - -
- -
-
-
diff --git a/platform/commonUI/browse/res/templates/browse/object-header-frame.html b/platform/commonUI/browse/res/templates/browse/object-header-frame.html deleted file mode 100644 index d31adc85b1..0000000000 --- a/platform/commonUI/browse/res/templates/browse/object-header-frame.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - {{parameters.mode}} - {{model.name}} - - - diff --git a/platform/commonUI/browse/res/templates/browse/object-header.html b/platform/commonUI/browse/res/templates/browse/object-header.html deleted file mode 100644 index 25d72bb66c..0000000000 --- a/platform/commonUI/browse/res/templates/browse/object-header.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - {{parameters.mode}} - {{model.name}} - - - diff --git a/platform/commonUI/browse/res/templates/browse/object-properties.html b/platform/commonUI/browse/res/templates/browse/object-properties.html deleted file mode 100644 index 5efb649a22..0000000000 --- a/platform/commonUI/browse/res/templates/browse/object-properties.html +++ /dev/null @@ -1,64 +0,0 @@ - -
-
    -

    Properties

    -
  • -
    {{ data.name }}
    -
    {{ data.value }}
    -
  • -
- -
    -

    Location

    -
  • -
    This Link
    -
    -
    - - -
    -
    -
  • -
  • -
    Original
    -
    -
    - - -
    -
    -
  • -
-
diff --git a/platform/commonUI/browse/res/templates/menu-arrow.html b/platform/commonUI/browse/res/templates/menu-arrow.html deleted file mode 100644 index 025685d067..0000000000 --- a/platform/commonUI/browse/res/templates/menu-arrow.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - diff --git a/platform/commonUI/browse/src/InspectorRegion.js b/platform/commonUI/browse/src/InspectorRegion.js deleted file mode 100644 index be4d708a1b..0000000000 --- a/platform/commonUI/browse/src/InspectorRegion.js +++ /dev/null @@ -1,67 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - [ - '../../regions/src/Region' - ], - function (Region) { - - /** - * Defines the a default Inspector region. Captured in a class to - * allow for modular extension and customization of regions based on - * the typical case. - * @memberOf platform/commonUI/regions - * @constructor - */ - function InspectorRegion() { - Region.call(this, {'name': 'Inspector'}); - - this.buildRegion(); - } - - InspectorRegion.prototype = Object.create(Region.prototype); - InspectorRegion.prototype.constructor = Region; - - /** - * @private - */ - InspectorRegion.prototype.buildRegion = function () { - var metadataRegion = { - name: 'metadata', - title: 'Metadata Region', - // Which modes should the region part be visible in? If - // nothing provided here, then assumed that part is visible - // in both. The visibility or otherwise of a region part - // should be decided by a policy. In this case, 'modes' is a - // shortcut that is used by the EditableRegionPolicy. - modes: ['browse', 'edit'], - content: { - key: 'object-properties' - } - }; - this.addRegion(new Region(metadataRegion), 0); - }; - - return InspectorRegion; - } -); diff --git a/platform/commonUI/browse/src/navigation/NavigateAction.js b/platform/commonUI/browse/src/navigation/NavigateAction.js deleted file mode 100644 index 68409a048d..0000000000 --- a/platform/commonUI/browse/src/navigation/NavigateAction.js +++ /dev/null @@ -1,69 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 NavigateAction. Created by vwoeltje on 11/10/14. - */ -define( - [], - function () { - - /** - * The navigate action navigates to a specific domain object. - * @memberof platform/commonUI/browse - * @constructor - * @implements {Action} - */ - function NavigateAction(navigationService, context) { - this.domainObject = context.domainObject; - this.navigationService = navigationService; - } - - /** - * Navigate to the object described in the context. - * @returns {Promise} a promise that is resolved once the - * navigation has been updated - */ - NavigateAction.prototype.perform = function () { - if (this.navigationService.shouldNavigate()) { - this.navigationService.setNavigation(this.domainObject, true); - - return Promise.resolve({}); - } - - return Promise.reject('Navigation Prevented by User'); - }; - - /** - * Navigate as an action is only applicable when a domain object - * is described in the action context. - * @param {ActionContext} context the context in which the action - * will be performed - * @returns {boolean} true if applicable - */ - NavigateAction.appliesTo = function (context) { - return context.domainObject !== undefined; - }; - - return NavigateAction; - } -); diff --git a/platform/commonUI/browse/src/navigation/NavigationService.js b/platform/commonUI/browse/src/navigation/NavigationService.js deleted file mode 100644 index 294cda53db..0000000000 --- a/platform/commonUI/browse/src/navigation/NavigationService.js +++ /dev/null @@ -1,203 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 NavigationService. Created by vwoeltje on 11/10/14. - */ -define( - [], - function () { - - /** - * The navigation service maintains the application's current - * navigation state, and allows listening for changes thereto. - * - * @memberof platform/commonUI/browse - * @constructor - */ - function NavigationService($window) { - this.navigated = undefined; - this.callbacks = []; - this.checks = []; - this.$window = $window; - - this.oldUnload = $window.onbeforeunload; - $window.onbeforeunload = this.onBeforeUnload.bind(this); - } - - /** - * Get the current navigation state. - * - * @returns {DomainObject} the object that is navigated-to - */ - NavigationService.prototype.getNavigation = function () { - return this.navigated; - }; - - /** - * Navigate to a specified object. If navigation checks exist and - * return reasons to prevent navigation, it will prompt the user before - * continuing. Trying to navigate to the currently navigated object will - * do nothing. - * - * If a truthy value is passed for `force`, it will skip navigation - * and will not prevent navigation to an already selected object. - * - * @param {DomainObject} domainObject the domain object to navigate to - * @param {Boolean} force if true, force navigation to occur. - * @returns {Boolean} true if navigation occurred, otherwise false. - */ - NavigationService.prototype.setNavigation = function (domainObject, force) { - if (force) { - this.doNavigation(domainObject); - - return true; - } - - if (this.navigated === domainObject) { - return true; - } - - var doNotNavigate = this.shouldWarnBeforeNavigate(); - if (doNotNavigate && !this.$window.confirm(doNotNavigate)) { - return false; - } - - this.doNavigation(domainObject); - - return true; - }; - - /** - * Listen for changes in navigation. The passed callback will - * be invoked with the new domain object of navigation when - * this changes. - * - * @param {function} callback the callback to invoke when - * navigation state changes - */ - NavigationService.prototype.addListener = function (callback) { - this.callbacks.push(callback); - }; - - /** - * Stop listening for changes in navigation state. - * - * @param {function} callback the callback which should - * no longer be invoked when navigation state - * changes - */ - NavigationService.prototype.removeListener = function (callback) { - this.callbacks = this.callbacks.filter(function (cb) { - return cb !== callback; - }); - }; - - /** - * Check if navigation should proceed. May prompt a user for input - * if any checkFns return messages. Returns true if the user wishes to - * navigate, otherwise false. If using this prior to calling - * `setNavigation`, you should call `setNavigation` with `force=true` - * to prevent duplicate dialogs being displayed to the user. - * - * @returns {Boolean} true if the user wishes to navigate, otherwise false. - */ - NavigationService.prototype.shouldNavigate = function () { - var doNotNavigate = this.shouldWarnBeforeNavigate(); - - return !doNotNavigate || this.$window.confirm(doNotNavigate); - }; - - /** - * Register a check function to be called before any navigation occurs. - * Check functions should return a human readable "message" if - * there are any reasons to prevent navigation. Otherwise, they should - * return falsy. Returns a function which can be called to remove the - * check function. - * - * @param {Function} checkFn a function to call before navigation occurs. - * @returns {Function} removeCheck call to remove check - */ - NavigationService.prototype.checkBeforeNavigation = function (checkFn) { - this.checks.push(checkFn); - - return function removeCheck() { - this.checks = this.checks.filter(function (fn) { - return checkFn !== fn; - }); - }.bind(this); - }; - - /** - * Private method to actually perform navigation. - * - * @private - */ - NavigationService.prototype.doNavigation = function (value) { - this.navigated = value; - this.callbacks.forEach(function (callback) { - callback(value); - }); - }; - - /** - * Returns either a false value, or a string that should be displayed - * to the user before navigation is allowed. - * - * @private - */ - NavigationService.prototype.shouldWarnBeforeNavigate = function () { - var reasons = []; - this.checks.forEach(function (checkFn) { - var reason = checkFn(); - if (reason) { - reasons.push(reason); - } - }); - - if (reasons.length) { - return reasons.join('\n'); - } - - return false; - }; - - /** - * Listener for window on before unload event-- will warn before - * navigation is allowed. - * - * @private - */ - NavigationService.prototype.onBeforeUnload = function () { - var shouldWarnBeforeNavigate = this.shouldWarnBeforeNavigate(); - if (shouldWarnBeforeNavigate) { - return shouldWarnBeforeNavigate; - } - - if (this.oldUnload) { - return this.oldUnload.apply(undefined, [].slice.apply(arguments)); - } - }; - - return NavigationService; - } -); diff --git a/platform/commonUI/browse/src/navigation/OrphanNavigationHandler.js b/platform/commonUI/browse/src/navigation/OrphanNavigationHandler.js deleted file mode 100644 index ffcfd6e83c..0000000000 --- a/platform/commonUI/browse/src/navigation/OrphanNavigationHandler.js +++ /dev/null @@ -1,76 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Navigates away from orphan objects whenever they are detected. - * - * An orphan object is an object whose apparent parent does not - * actually contain it. This may occur in certain circumstances, such - * as when persistence succeeds for a newly-created object but fails - * for its parent. - * - * @param throttle the `throttle` service - * @param topic the `topic` service - * @param navigationService the `navigationService` - * @constructor - */ - function OrphanNavigationHandler(throttle, topic, navigationService) { - var throttledCheckNavigation; - - function getParent(domainObject) { - var context = domainObject.getCapability('context'); - - return context.getParent(); - } - - function preventOrphanNavigation(domainObject) { - var parent = getParent(domainObject); - parent.useCapability('composition') - .then(function (composees) { - var isOrphan = composees.every(function (c) { - return c.getId() !== domainObject.getId(); - }); - if (isOrphan) { - parent.getCapability('action').perform('navigate'); - } - }); - } - - function checkNavigation() { - var navigatedObject = navigationService.getNavigation(); - if (navigatedObject && navigatedObject.hasCapability('context')) { - if (!navigatedObject.getCapability('editor').isEditContextRoot()) { - preventOrphanNavigation(navigatedObject); - } - } - } - - throttledCheckNavigation = throttle(checkNavigation); - - navigationService.addListener(throttledCheckNavigation); - topic('mutation').listen(throttledCheckNavigation); - } - - return OrphanNavigationHandler; -}); diff --git a/platform/commonUI/browse/test/InspectorRegionSpec.js b/platform/commonUI/browse/test/InspectorRegionSpec.js deleted file mode 100644 index a78b378bcc..0000000000 --- a/platform/commonUI/browse/test/InspectorRegionSpec.js +++ /dev/null @@ -1,43 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * MCTIncudeSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../src/InspectorRegion"], - function (InspectorRegion) { - - describe("The inspector region", function () { - var inspectorRegion; - - beforeEach(function () { - inspectorRegion = new InspectorRegion(); - }); - - it("creates default region parts", function () { - expect(inspectorRegion.regions.length).toBe(1); - }); - - }); - } -); diff --git a/platform/commonUI/browse/test/navigation/NavigateActionSpec.js b/platform/commonUI/browse/test/navigation/NavigateActionSpec.js deleted file mode 100644 index 91c657f5e1..0000000000 --- a/platform/commonUI/browse/test/navigation/NavigateActionSpec.js +++ /dev/null @@ -1,85 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * MCTRepresentationSpec. Created by vwoeltje on 11/6/14. - */ -define([ - "../../src/navigation/NavigateAction" -], function ( - NavigateAction -) { - - describe("The navigate action", function () { - var mockNavigationService, - mockDomainObject, - action; - - beforeEach(function () { - mockNavigationService = jasmine.createSpyObj( - "navigationService", - [ - "shouldNavigate", - "setNavigation" - ] - ); - - mockDomainObject = {}; - - action = new NavigateAction( - mockNavigationService, - { domainObject: mockDomainObject } - ); - }); - - it("sets navigation if it is allowed", function () { - mockNavigationService.shouldNavigate.and.returnValue(true); - - return action.perform() - .then(function () { - expect(mockNavigationService.setNavigation) - .toHaveBeenCalledWith(mockDomainObject, true); - }); - }); - - it("does not set navigation if it is not allowed", function () { - mockNavigationService.shouldNavigate.and.returnValue(false); - var onSuccess = jasmine.createSpy('onSuccess'); - - return action.perform() - .then(onSuccess, function () { - expect(onSuccess).not.toHaveBeenCalled(); - expect(mockNavigationService.setNavigation) - .not - .toHaveBeenCalledWith(mockDomainObject); - }); - }); - - it("is only applicable when a domain object is in context", function () { - expect(NavigateAction.appliesTo({})).toBeFalsy(); - expect(NavigateAction.appliesTo({ - domainObject: mockDomainObject - })).toBeTruthy(); - }); - - }); -}); diff --git a/platform/commonUI/browse/test/navigation/NavigationServiceSpec.js b/platform/commonUI/browse/test/navigation/NavigationServiceSpec.js deleted file mode 100644 index 86a7ab1aec..0000000000 --- a/platform/commonUI/browse/test/navigation/NavigationServiceSpec.js +++ /dev/null @@ -1,88 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * MCTRepresentationSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/navigation/NavigationService"], - function (NavigationService) { - - describe("The navigation service", function () { - var $window, - navigationService; - - beforeEach(function () { - $window = jasmine.createSpyObj('$window', ['confirm']); - navigationService = new NavigationService($window); - }); - - it("stores navigation state", function () { - var testObject = { someKey: 42 }, - otherObject = { someKey: "some value" }; - expect(navigationService.getNavigation()) - .toBeUndefined(); - navigationService.setNavigation(testObject); - expect(navigationService.getNavigation()) - .toBe(testObject); - expect(navigationService.getNavigation()) - .toBe(testObject); - navigationService.setNavigation(otherObject); - expect(navigationService.getNavigation()) - .toBe(otherObject); - }); - - it("notifies listeners on change", function () { - var testObject = { someKey: 42 }, - callback = jasmine.createSpy("callback"); - - navigationService.addListener(callback); - expect(callback).not.toHaveBeenCalled(); - - navigationService.setNavigation(testObject); - expect(callback).toHaveBeenCalledWith(testObject); - }); - - it("does not notify listeners when no changes occur", function () { - var testObject = { someKey: 42 }, - callback = jasmine.createSpy("callback"); - - navigationService.addListener(callback); - navigationService.setNavigation(testObject); - navigationService.setNavigation(testObject); - expect(callback.calls.count()).toEqual(1); - }); - - it("stops notifying listeners after removal", function () { - var testObject = { someKey: 42 }, - callback = jasmine.createSpy("callback"); - - navigationService.addListener(callback); - navigationService.removeListener(callback); - - navigationService.setNavigation(testObject); - expect(callback).not.toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/commonUI/browse/test/navigation/OrphanNavigationHandlerSpec.js b/platform/commonUI/browse/test/navigation/OrphanNavigationHandlerSpec.js deleted file mode 100644 index 5a205b1f9a..0000000000 --- a/platform/commonUI/browse/test/navigation/OrphanNavigationHandlerSpec.js +++ /dev/null @@ -1,182 +0,0 @@ -/***************************************************************************** -* Open MCT, Copyright (c) 2014-2022, 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/navigation/OrphanNavigationHandler' -], function (OrphanNavigationHandler) { - describe("OrphanNavigationHandler", function () { - var mockTopic, - mockThrottle, - mockMutationTopic, - mockNavigationService, - mockDomainObject, - mockParentObject, - mockContext, - mockActionCapability, - mockEditor, - testParentComposition, - testId, - mockThrottledFns; - - beforeEach(function () { - testId = 'some-identifier'; - - mockThrottledFns = []; - - mockTopic = jasmine.createSpy('topic'); - mockThrottle = jasmine.createSpy('throttle'); - mockNavigationService = jasmine.createSpyObj('navigationService', [ - 'getNavigation', - 'addListener' - ]); - mockMutationTopic = jasmine.createSpyObj('mutationTopic', [ - 'listen' - ]); - mockDomainObject = jasmine.createSpyObj('domainObject', [ - 'getId', - 'getCapability', - 'hasCapability' - ]); - mockParentObject = jasmine.createSpyObj('domainObject', [ - 'getId', - 'getCapability', - 'useCapability' - ]); - mockContext = jasmine.createSpyObj('context', ['getParent']); - mockActionCapability = jasmine.createSpyObj('action', ['perform']); - mockEditor = jasmine.createSpyObj('editor', ['isEditContextRoot']); - - mockThrottle.and.callFake(function (fn) { - var mockThrottledFn = - jasmine.createSpy('throttled-' + mockThrottledFns.length); - mockThrottledFn.and.callFake(fn); - mockThrottledFns.push(mockThrottledFn); - - return mockThrottledFn; - }); - mockTopic.and.returnValue(mockMutationTopic); - mockDomainObject.getId.and.returnValue(testId); - mockDomainObject.getCapability.and.callFake(function (c) { - return { - context: mockContext, - editor: mockEditor - }[c]; - }); - mockDomainObject.hasCapability.and.callFake(function (c) { - return Boolean(mockDomainObject.getCapability(c)); - }); - mockParentObject.getCapability.and.callFake(function (c) { - return { - action: mockActionCapability - }[c]; - }); - testParentComposition = []; - mockParentObject.useCapability.and.returnValue(Promise.resolve(testParentComposition)); - - mockContext.getParent.and.returnValue(mockParentObject); - mockNavigationService.getNavigation.and.returnValue(mockDomainObject); - mockEditor.isEditContextRoot.and.returnValue(false); - - return new OrphanNavigationHandler( - mockThrottle, - mockTopic, - mockNavigationService - ); - }); - - it("listens for mutation with a throttled function", function () { - expect(mockMutationTopic.listen) - .toHaveBeenCalledWith(jasmine.any(Function)); - expect(mockThrottledFns.indexOf( - mockMutationTopic.listen.calls.mostRecent().args[0] - )).not.toEqual(-1); - }); - - it("listens for navigation changes with a throttled function", function () { - expect(mockNavigationService.addListener) - .toHaveBeenCalledWith(jasmine.any(Function)); - expect(mockThrottledFns.indexOf( - mockNavigationService.addListener.calls.mostRecent().args[0] - )).not.toEqual(-1); - }); - - [false, true].forEach(function (isOrphan) { - var prefix = isOrphan ? "" : "non-"; - describe("for " + prefix + "orphan objects", function () { - beforeEach(function () { - if (!isOrphan) { - testParentComposition.push(mockDomainObject); - } - }); - - [false, true].forEach(function (isEditRoot) { - var caseName = isEditRoot - ? "that are being edited" : "that are not being edited"; - - function itNavigatesAsExpected() { - if (isOrphan && !isEditRoot) { - it("navigates to the parent", function () { - return Promise.resolve().then(function () { - expect(mockActionCapability.perform) - .toHaveBeenCalledWith('navigate'); - }); - }); - } else { - it("does nothing", function () { - return Promise.resolve().then(function () { - expect(mockActionCapability.perform) - .not.toHaveBeenCalled(); - }); - }); - } - } - - describe(caseName, function () { - beforeEach(function () { - mockEditor.isEditContextRoot.and.returnValue(isEditRoot); - }); - - describe("when navigation changes", function () { - beforeEach(function () { - mockNavigationService.addListener.calls.mostRecent() - .args[0](mockDomainObject); - }); - itNavigatesAsExpected(); - }); - - describe("when mutation occurs", function () { - beforeEach(function () { - mockMutationTopic.listen.calls.mostRecent() - .args[0](mockParentObject); - }); - - itNavigatesAsExpected(); - }); - - }); - }); - }); - }); - - }); -}); - diff --git a/platform/commonUI/dialog/README.md b/platform/commonUI/dialog/README.md deleted file mode 100644 index c42cf3a95b..0000000000 --- a/platform/commonUI/dialog/README.md +++ /dev/null @@ -1,27 +0,0 @@ -This bundle provides `dialogService`, which can be used to prompt -for user input. - -## `getUserChoice` - -The `getUserChoice` method is useful for displaying a message and a set of -buttons. This method returns a promise which will resolve to the user's -chosen option (or, more specifically, its `key`), and will be rejected if -the user closes the dialog with the X in the top-right; - -The `dialogModel` given as an argument to this method should have the -following properties. - -* `title`: The title to display at the top of the dialog. -* `hint`: Short message to display below the title. -* `template`: Identifying key (as will be passed to `mct-include`) for - the template which will be used to populate the inner area of the dialog. -* `model`: Model to pass in the `ng-model` attribute of - `mct-include`. -* `parameters`: Parameters to pass in the `parameters` attribute of - `mct-include`. -* `options`: An array of options describing each button at the bottom. - Each option may have the following properties: - * `name`: Human-readable name to display in the button. - * `key`: Machine-readable key, to pass as the result of the resolved - promise when clicked. - * `description`: Description to show in tool tip on hover. diff --git a/platform/commonUI/dialog/bundle.js b/platform/commonUI/dialog/bundle.js deleted file mode 100644 index 095d8f4444..0000000000 --- a/platform/commonUI/dialog/bundle.js +++ /dev/null @@ -1,112 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/DialogService", - "./src/OverlayService", - "./res/templates/overlay-dialog.html", - "./res/templates/overlay-options.html", - "./res/templates/dialog.html", - "./res/templates/overlay-blocking-message.html", - "./res/templates/message.html", - "./res/templates/notification-message.html", - "./res/templates/overlay-message-list.html", - "./res/templates/overlay.html" -], function ( - DialogService, - OverlayService, - overlayDialogTemplate, - overlayOptionsTemplate, - dialogTemplate, - overlayBlockingMessageTemplate, - messageTemplate, - notificationMessageTemplate, - overlayMessageListTemplate, - overlayTemplate -) { - - return { - name: "platform/commonUI/dialog", - definition: { - "extensions": { - "services": [ - { - "key": "dialogService", - "implementation": DialogService, - "depends": [ - "overlayService", - "$q", - "$log", - "$document" - ] - }, - { - "key": "overlayService", - "implementation": OverlayService, - "depends": [ - "$document", - "$compile", - "$rootScope", - "$timeout" - ] - } - ], - "templates": [ - { - "key": "overlay-dialog", - "template": overlayDialogTemplate - }, - { - "key": "overlay-options", - "template": overlayOptionsTemplate - }, - { - "key": "form-dialog", - "template": dialogTemplate - }, - { - "key": "overlay-blocking-message", - "template": overlayBlockingMessageTemplate - }, - { - "key": "message", - "template": messageTemplate - }, - { - "key": "notification-message", - "template": notificationMessageTemplate - }, - { - "key": "overlay-message-list", - "template": overlayMessageListTemplate - } - ], - "containers": [ - { - "key": "overlay", - "template": overlayTemplate - } - ] - } - } - }; -}); diff --git a/platform/commonUI/dialog/res/templates/dialog.html b/platform/commonUI/dialog/res/templates/dialog.html deleted file mode 100644 index 88fafbe345..0000000000 --- a/platform/commonUI/dialog/res/templates/dialog.html +++ /dev/null @@ -1,43 +0,0 @@ - -
-
{{ngModel.title}}
-
All fields marked are required.
-
-
- - -
-
- - -
diff --git a/platform/commonUI/dialog/res/templates/message.html b/platform/commonUI/dialog/res/templates/message.html deleted file mode 100644 index c75878cfc5..0000000000 --- a/platform/commonUI/dialog/res/templates/message.html +++ /dev/null @@ -1,32 +0,0 @@ -
-
-
-
{{ngModel.title}}
-
-
- {{ngModel.hint}} - [{{ngModel.timestamp}}] -
-
-
- {{ngModel.actionText}} -
- -
-
- - -
-
-
\ No newline at end of file diff --git a/platform/commonUI/dialog/res/templates/notification-message.html b/platform/commonUI/dialog/res/templates/notification-message.html deleted file mode 100644 index 8fabb81081..0000000000 --- a/platform/commonUI/dialog/res/templates/notification-message.html +++ /dev/null @@ -1,25 +0,0 @@ -
-
-
-
{{ngModel.message}}
-
-
- -
-
-
- - -
-
diff --git a/platform/commonUI/dialog/res/templates/overlay-blocking-message.html b/platform/commonUI/dialog/res/templates/overlay-blocking-message.html deleted file mode 100644 index 40697d4881..0000000000 --- a/platform/commonUI/dialog/res/templates/overlay-blocking-message.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - diff --git a/platform/commonUI/dialog/res/templates/overlay-dialog.html b/platform/commonUI/dialog/res/templates/overlay-dialog.html deleted file mode 100644 index 789715f50e..0000000000 --- a/platform/commonUI/dialog/res/templates/overlay-dialog.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - diff --git a/platform/commonUI/dialog/res/templates/overlay-message-list.html b/platform/commonUI/dialog/res/templates/overlay-message-list.html deleted file mode 100644 index caabd7d4bf..0000000000 --- a/platform/commonUI/dialog/res/templates/overlay-message-list.html +++ /dev/null @@ -1,29 +0,0 @@ - -
-
-
{{ngModel.dialog.title}}
-
Displaying {{ngModel.dialog.messages.length}} messages -
- -
-
- -
-
- -
-
-
diff --git a/platform/commonUI/dialog/res/templates/overlay-options.html b/platform/commonUI/dialog/res/templates/overlay-options.html deleted file mode 100644 index 52f2e12e8a..0000000000 --- a/platform/commonUI/dialog/res/templates/overlay-options.html +++ /dev/null @@ -1,43 +0,0 @@ - - -
-
{{ngModel.dialog.title}}
-
{{ngModel.dialog.hint}}
-
-
- - -
-
- -
-
diff --git a/platform/commonUI/dialog/res/templates/overlay.html b/platform/commonUI/dialog/res/templates/overlay.html deleted file mode 100644 index af11f3b0c0..0000000000 --- a/platform/commonUI/dialog/res/templates/overlay.html +++ /dev/null @@ -1,30 +0,0 @@ - -
-
-
- -
-
-
diff --git a/platform/commonUI/dialog/src/DialogService.js b/platform/commonUI/dialog/src/DialogService.js deleted file mode 100644 index 45869b5a07..0000000000 --- a/platform/commonUI/dialog/src/DialogService.js +++ /dev/null @@ -1,271 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -/** - * This bundle implements the dialog service, which can be used to - * launch dialogs for user input & notifications. - * @namespace platform/commonUI/dialog - */ -define( - [], - function () { - /** - * The dialog service is responsible for handling window-modal - * communication with the user, such as displaying forms for user - * input. - * @memberof platform/commonUI/dialog - * @constructor - */ - function DialogService(overlayService, $q, $log, $document) { - this.overlayService = overlayService; - this.$q = $q; - this.$log = $log; - this.activeOverlay = undefined; - - this.findBody = function () { - return $document.find('body'); - }; - } - - /** - * @private - */ - DialogService.prototype.dismissOverlay = function (overlay) { - //Dismiss the overlay - overlay.dismiss(); - - //If dialog is the current active one, dismiss it - if (overlay === this.activeOverlay) { - this.activeOverlay = undefined; - } - }; - - DialogService.prototype.getDialogResponse = function (key, model, resultGetter, typeClass) { - // We will return this result as a promise, because user - // input is asynchronous. - var deferred = this.$q.defer(), - self = this, - overlay, - handleEscKeydown; - - // Confirm function; this will be passed in to the - // overlay-dialog template and associated with a - // OK button click - function confirm(value) { - // Pass along the result - deferred.resolve(resultGetter ? resultGetter() : value); - self.dismissOverlay(overlay); - } - - // Cancel function; this will be passed in to the - // overlay-dialog template and associated with a - // Cancel or X button click - function cancel() { - deferred.reject(); - self.findBody().off('keydown', handleEscKeydown); - self.dismissOverlay(overlay); - } - - handleEscKeydown = function (event) { - if (event.keyCode === 27) { - cancel(); - } - }; - - // Add confirm/cancel callbacks - model.confirm = confirm; - model.cancel = cancel; - - this.findBody().on('keydown', handleEscKeydown); - - if (this.canShowDialog(model)) { - // Add the overlay using the OverlayService, which - // will handle actual insertion into the DOM - overlay = this.activeOverlay = this.overlayService.createOverlay( - key, - model, - typeClass || "t-dialog" - ); - } else { - deferred.reject(); - } - - return deferred.promise; - }; - - /** - * Request user input via a window-modal dialog. - * - * @param {FormModel} formModel a description of the form - * to be shown (see platform/forms) - * @param {object} value the initial state of the form - * @returns {Promise} a promise for the form value that the - * user has supplied; this may be rejected if - * user input cannot be obtained (for instance, - * because the user cancelled the dialog) - */ - DialogService.prototype.getUserInput = function (formModel, value) { - var overlayModel = { - title: formModel.name, - message: formModel.message, - structure: formModel, - value: value - }; - - // Provide result from the model - function resultGetter() { - return overlayModel.value; - } - - // Show the overlay-dialog - return this.getDialogResponse( - "overlay-dialog", - overlayModel, - resultGetter - ); - }; - - /** - * Request that the user chooses from a set of options, - * which will be shown as buttons. - * - * @param dialogModel a description of the dialog to show - * @return {Promise} a promise for the user's choice - */ - DialogService.prototype.getUserChoice = function (dialogModel) { - // Show the overlay-options dialog - return this.getDialogResponse( - "overlay-options", - { dialog: dialogModel } - ); - }; - - /** - * Tests if a dialog can be displayed. A modal dialog may only be - * displayed if one is not already visible. - * Will log a warning message if it can't display a dialog. - * @returns {boolean} true if dialog is currently visible, false - * otherwise - */ - DialogService.prototype.canShowDialog = function (dialogModel) { - if (this.activeOverlay) { - // Only one dialog should be shown at a time. - // The application design should be such that - // we never even try to do this. - this.$log.warn([ - "Dialog already showing; ", - "unable to show ", - dialogModel.title - ].join("")); - - return false; - } else { - return true; - } - }; - - /** - * A user action that can be performed from a blocking dialog. These - * actions will be rendered as buttons within a blocking dialog. - * - * @typedef DialogOption - * @property {string} label a label to be displayed as the button - * text for this action - * @property {function} callback a function to be called when the - * button is clicked - */ - - /** - * @typedef DialogHandle - * @property {function} dismiss a function to dismiss the given dialog - */ - - /** - * A description of the model options that may be passed to the - * showBlockingMessage method. Note that the DialogModel described - * here is shared with the Notifications framework. - * @see NotificationService - * - * @typedef DialogModel - * @property {string} title the title to use for the dialog - * @property {string} severity the severity level of this message. - * These are defined in a bundle constant with key 'dialogSeverity' - * @property {string} hint the 'hint' message to show below the title - * @property {string} actionText text that indicates a current action, - * shown above a progress bar to indicate what's happening. - * @property {number} progress a percentage value (1-100) - * indicating the completion of the blocking task - * @property {boolean} delay adds a brief delay before loading - * the dialog. Useful for removing the dialog flicker when the - * conditions for displaying the dialog change rapidly. - * @property {string} progressText the message to show below a - * progress bar to indicate progress. For example, this might be - * used to indicate time remaining, or items still to process. - * @property {boolean} unknownProgress some tasks may be - * impossible to provide an estimate for. Providing a true value for - * this attribute will indicate to the user that the progress and - * duration cannot be estimated. - * @property {DialogOption} primaryOption an action that will - * be added to the dialog as a button. The primary action can be - * used as the suggested course of action for the user. Making it - * distinct from other actions allows it to be styled differently, - * and treated preferentially in banner mode. - * @property {DialogOption[]} options a list of actions that will - * be added to the dialog as buttons. - */ - - /** - * Displays a blocking (modal) dialog. This dialog can be used for - * displaying messages that require the user's - * immediate attention. The message may include an indication of - * progress, as well as a series of actions that - * the user can take if necessary - * @param {DialogModel} dialogModel defines options for the dialog - * @param {typeClass} string tells overlayService that this overlay should use appropriate CSS class - * @returns {boolean | {DialogHandle}} - */ - DialogService.prototype.showBlockingMessage = function (dialogModel) { - if (this.canShowDialog(dialogModel)) { - // Add the overlay using the OverlayService, which - // will handle actual insertion into the DOM - var self = this, - overlay = this.overlayService.createOverlay( - "overlay-blocking-message", - dialogModel, - "t-dialog-sm" - ); - - this.activeOverlay = overlay; - - return { - dismiss: function () { - self.dismissOverlay(overlay); - } - }; - } else { - return false; - } - }; - - return DialogService; - } -); diff --git a/platform/commonUI/dialog/src/OverlayService.js b/platform/commonUI/dialog/src/OverlayService.js deleted file mode 100644 index 2a73d584bb..0000000000 --- a/platform/commonUI/dialog/src/OverlayService.js +++ /dev/null @@ -1,113 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - // Template to inject into the DOM to show the dialog; really just points to - // the a specific template that can be included via mct-include - var TEMPLATE = ''; - - /** - * The OverlayService is responsible for pre-pending templates to - * the body of the document, which is useful for displaying templates - * which need to block the full screen. - * - * This is intended to be used by the DialogService; by design, it - * does not have any protections in place to prevent multiple overlays - * from being shown at once. (The DialogService does have these - * protections, and should be used for most overlay-type interactions, - * particularly where a multiple-overlay effect is not specifically - * desired). - * - * @memberof platform/commonUI/dialog - * @constructor - */ - function OverlayService($document, $compile, $rootScope, $timeout) { - this.$compile = $compile; - this.$timeout = $timeout; - - // Don't include $document and $rootScope directly; - // avoids https://docs.angularjs.org/error/ng/cpws - this.findBody = function () { - return $document.find('body'); - }; - - this.newScope = function () { - return $rootScope.$new(); - }; - } - - /** - * Add a new overlay to the document. This will be - * prepended to the document body; the overlay's - * template (as pointed to by the `key` argument) is - * responsible for having a useful z-order, and for - * blocking user interactions if appropriate. - * - * @param {string} key the symbolic key which identifies - * the template of the overlay to be shown - * @param {object} overlayModel the model to pass to the - * included overlay template (this will be passed - * in via ng-model) - * @param {string} typeClass the element class to use in rendering - * the overlay. Can be specified to provide custom styling of - * overlays - */ - OverlayService.prototype.createOverlay = function (key, overlayModel, typeClass) { - // Create a new scope for this overlay - var scope = this.newScope(), - element; - - // Stop showing the overlay; additionally, release the scope - // that it uses. - function dismiss() { - scope.$destroy(); - element.remove(); - } - - // If no model is supplied, just fill in a default "cancel" - overlayModel = overlayModel || { cancel: dismiss }; - - // Populate the scope; will be passed directly to the template - scope.overlay = overlayModel; - scope.key = key; - scope.typeClass = typeClass || 't-dialog'; - - this.$timeout(() => { - // Create the overlay element and add it to the document's body - element = this.$compile(TEMPLATE)(scope); - - // Append so that most recent dialog is last in DOM. This means the most recent dialog will be on top when - // multiple overlays with the same z-index are active. - this.findBody().append(element); - }); - - return { - dismiss: dismiss - }; - }; - - return OverlayService; - } -); diff --git a/platform/commonUI/dialog/test/DialogServiceSpec.js b/platform/commonUI/dialog/test/DialogServiceSpec.js deleted file mode 100644 index 28c5b6d97c..0000000000 --- a/platform/commonUI/dialog/test/DialogServiceSpec.js +++ /dev/null @@ -1,214 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * MCTIncudeSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../src/DialogService"], - function (DialogService) { - - describe("The dialog service", function () { - var mockOverlayService, - mockQ, - mockLog, - mockOverlay, - mockDeferred, - mockDocument, - mockBody, - dialogService; - - beforeEach(function () { - mockOverlayService = jasmine.createSpyObj( - "overlayService", - ["createOverlay"] - ); - mockQ = jasmine.createSpyObj( - "$q", - ["defer"] - ); - mockLog = jasmine.createSpyObj( - "$log", - ["warn", "info", "debug"] - ); - mockOverlay = jasmine.createSpyObj( - "overlay", - ["dismiss"] - ); - mockDeferred = jasmine.createSpyObj( - "deferred", - ["resolve", "reject"] - ); - mockDocument = jasmine.createSpyObj( - "$document", - ["find"] - ); - mockBody = jasmine.createSpyObj('body', ['on', 'off']); - mockDocument.find.and.returnValue(mockBody); - - mockDeferred.promise = "mock promise"; - - mockQ.defer.and.returnValue(mockDeferred); - mockOverlayService.createOverlay.and.returnValue(mockOverlay); - - dialogService = new DialogService( - mockOverlayService, - mockQ, - mockLog, - mockDocument - ); - }); - - it("adds an overlay when user input is requested", function () { - dialogService.getUserInput({}, {}); - expect(mockOverlayService.createOverlay).toHaveBeenCalled(); - }); - - it("allows user input to be canceled", function () { - dialogService.getUserInput({}, { someKey: "some value" }); - mockOverlayService.createOverlay.calls.mostRecent().args[1].cancel(); - expect(mockDeferred.reject).toHaveBeenCalled(); - expect(mockDeferred.resolve).not.toHaveBeenCalled(); - }); - - it("passes back the result of user input when confirmed", function () { - var value = { someKey: 42 }; - dialogService.getUserInput({}, value); - mockOverlayService.createOverlay.calls.mostRecent().args[1].confirm(); - expect(mockDeferred.reject).not.toHaveBeenCalled(); - expect(mockDeferred.resolve).toHaveBeenCalledWith(value); - }); - - it("logs a warning when a dialog is already showing", function () { - dialogService.getUserInput({}, {}); - expect(mockLog.warn).not.toHaveBeenCalled(); - dialogService.getUserInput({}, {}); - expect(mockLog.warn).toHaveBeenCalled(); - expect(mockDeferred.reject).toHaveBeenCalled(); - }); - - it("can show multiple dialogs if prior ones are dismissed", function () { - dialogService.getUserInput({}, {}); - expect(mockLog.warn).not.toHaveBeenCalled(); - mockOverlayService.createOverlay.calls.mostRecent().args[1].confirm(); - dialogService.getUserInput({}, {}); - expect(mockLog.warn).not.toHaveBeenCalled(); - expect(mockDeferred.reject).not.toHaveBeenCalled(); - }); - - it("provides an options dialogs", function () { - var dialogModel = {}; - dialogService.getUserChoice(dialogModel); - expect(mockOverlayService.createOverlay).toHaveBeenCalledWith( - 'overlay-options', - { - dialog: dialogModel, - confirm: jasmine.any(Function), - cancel: jasmine.any(Function) - }, - 't-dialog' - ); - }); - - it("invokes the overlay service with the correct parameters when" - + " a blocking dialog is requested", function () { - var dialogModel = {}; - expect(dialogService.showBlockingMessage(dialogModel)).not.toBe(false); - expect(mockOverlayService.createOverlay).toHaveBeenCalledWith( - "overlay-blocking-message", - dialogModel, - "t-dialog-sm" - ); - }); - - it("adds a keydown event listener to the body", function () { - dialogService.getUserInput({}, {}); - expect(mockDocument.find).toHaveBeenCalledWith("body"); - expect(mockBody.on).toHaveBeenCalledWith("keydown", jasmine.any(Function)); - }); - - it("destroys the event listener when the dialog is cancelled", function () { - dialogService.getUserInput({}, {}); - mockOverlayService.createOverlay.calls.mostRecent().args[1].cancel(); - expect(mockBody.off).toHaveBeenCalledWith("keydown", jasmine.any(Function)); - }); - - it("cancels the dialog when an escape keydown event is triggered", function () { - dialogService.getUserInput({}, {}); - mockBody.on.calls.mostRecent().args[1]({ - keyCode: 27 - }); - expect(mockDeferred.reject).toHaveBeenCalled(); - expect(mockDeferred.resolve).not.toHaveBeenCalled(); - }); - - it("ignores non escape keydown events", function () { - dialogService.getUserInput({}, {}); - mockBody.on.calls.mostRecent().args[1]({ - keyCode: 13 - }); - expect(mockDeferred.reject).not.toHaveBeenCalled(); - expect(mockDeferred.resolve).not.toHaveBeenCalled(); - }); - - describe("the blocking message dialog", function () { - var dialogModel = {}; - var dialogHandle; - - beforeEach(function () { - dialogHandle = dialogService.showBlockingMessage(dialogModel); - }); - - it("returns a handle to the dialog", function () { - expect(dialogHandle).not.toBe(undefined); - }); - - it("dismissing the dialog dismisses the overlay", function () { - dialogHandle.dismiss(); - expect(mockOverlay.dismiss).toHaveBeenCalled(); - }); - - it("individual dialogs can be dismissed", function () { - var secondDialogHandle, - secondMockOverlay; - - dialogHandle.dismiss(); - - secondMockOverlay = jasmine.createSpyObj( - "overlay", - ["dismiss"] - ); - mockOverlayService.createOverlay.and.returnValue(secondMockOverlay); - secondDialogHandle = dialogService.showBlockingMessage(dialogModel); - - //Dismiss the first dialog. It should only dismiss if it - // is active - dialogHandle.dismiss(); - expect(secondMockOverlay.dismiss).not.toHaveBeenCalled(); - secondDialogHandle.dismiss(); - expect(secondMockOverlay.dismiss).toHaveBeenCalled(); - }); - }); - - }); - } -); diff --git a/platform/commonUI/dialog/test/OverlayServiceSpec.js b/platform/commonUI/dialog/test/OverlayServiceSpec.js deleted file mode 100644 index e8f3a6dfce..0000000000 --- a/platform/commonUI/dialog/test/OverlayServiceSpec.js +++ /dev/null @@ -1,104 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * MCTIncudeSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../src/OverlayService"], - function (OverlayService) { - - describe("The overlay service", function () { - var mockDocument, - mockCompile, - mockRootScope, - mockBody, - mockTemplate, - mockElement, - mockScope, - mockTimeout, - overlayService; - - beforeEach(function () { - mockDocument = jasmine.createSpyObj("$document", ["find"]); - mockCompile = jasmine.createSpy("$compile"); - mockRootScope = jasmine.createSpyObj("$rootScope", ["$new"]); - mockBody = jasmine.createSpyObj("body", ["append"]); - mockTemplate = jasmine.createSpy("template"); - mockElement = jasmine.createSpyObj("element", ["remove"]); - mockScope = jasmine.createSpyObj("scope", ["$destroy"]); - mockTimeout = function (callback) { - callback(); - }; - - mockDocument.find.and.returnValue(mockBody); - mockCompile.and.returnValue(mockTemplate); - mockRootScope.$new.and.returnValue(mockScope); - mockTemplate.and.returnValue(mockElement); - - overlayService = new OverlayService( - mockDocument, - mockCompile, - mockRootScope, - mockTimeout - ); - }); - - it("prepends an mct-include to create overlays", function () { - overlayService.createOverlay("test", {}); - expect(mockCompile).toHaveBeenCalled(); - expect(mockCompile.calls.mostRecent().args[0].indexOf("mct-include")) - .not.toEqual(-1); - }); - - it("adds the templated element to the body", function () { - overlayService.createOverlay("test", {}); - expect(mockBody.append).toHaveBeenCalledWith(mockElement); - }); - - it("places the provided model/key in its template's scope", function () { - overlayService.createOverlay("test", { someKey: 42 }); - expect(mockScope.overlay).toEqual({ someKey: 42 }); - expect(mockScope.key).toEqual("test"); - - // Make sure this is actually what was rendered, too - expect(mockTemplate).toHaveBeenCalledWith(mockScope); - }); - - it("removes the prepended element on request", function () { - var overlay = overlayService.createOverlay("test", {}); - - // Verify precondition - expect(mockElement.remove).not.toHaveBeenCalled(); - expect(mockScope.$destroy).not.toHaveBeenCalled(); - - // Dismiss the overlay - overlay.dismiss(); - - // Now it should have been removed, and the scope destroyed - expect(mockElement.remove).toHaveBeenCalled(); - expect(mockScope.$destroy).toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/commonUI/edit/README.md b/platform/commonUI/edit/README.md deleted file mode 100644 index ca52b78f1a..0000000000 --- a/platform/commonUI/edit/README.md +++ /dev/null @@ -1,45 +0,0 @@ -Contains sources and resources associated with Edit mode. - -# Extensions - -# Toolbars - -Views may specify the contents of a toolbar through a `toolbar` -property in their bundle definition. This should appear as the -structure one would provide to the `mct-toolbar` directive, -except additional properties are recognized to support the -mediation between toolbar contents, user interaction, and the -current selection (as read from the `selection` property of the -view's scope.) These additional properties are: - -* `property`: Name of the property within a selected object. If, - for any given object in the selection, that field is a function, - then that function is assumed to be an accessor-mutator function - (that is, it will be called with no arguments to get, and with - an argument to set.) -* `method`: Name of a method to invoke upon a selected object when - a control is activated, e.g. on a button click. -* `exclusive`: Optional; true if this control should be considered - applicable only when all elements in the selection has - the associated property. Otherwise, only at least one member of the - current selection must have this property for the control to be shown. - -Controls in the toolbar are shown based on applicability to the -current selection. Applicability for a given member of the selection -is determined by the presence of absence of the named `property` -field. As a consequence of this, if `undefined` is a valid value for -that property, an accessor-mutator function must be used. Likewise, -if toolbar properties are meant to be view-global (as opposed to -per-selection) then the view must include some object to act as its -proxy in the current selection (in addition to whatever objects the -user will conceive of as part of the current selection), typically -with `inclusive` set to `true`. - -## Selection - -The `selection` property of a view's scope in Edit mode will be -initialized to an empty array. This array's contents may be modified -to implicitly change the contents of the toolbar based on the rules -described above. Care should be taken to modify this array in-place -instead of shadowing it (as the selection will typically -be a few scopes up the hierarchy from the view's actual scope.) diff --git a/platform/commonUI/edit/bundle.js b/platform/commonUI/edit/bundle.js deleted file mode 100644 index e474858740..0000000000 --- a/platform/commonUI/edit/bundle.js +++ /dev/null @@ -1,209 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/EditActionController", - "./src/controllers/EditPanesController", - "./src/controllers/EditObjectController", - "./src/actions/EditAndComposeAction", - "./src/actions/EditAction", - "./src/actions/SaveAction", - "./src/actions/SaveAndStopEditingAction", - "./src/actions/CancelAction", - "./src/policies/EditPersistableObjectsPolicy", - "./src/representers/EditRepresenter", - "./src/capabilities/EditorCapability", - "./res/templates/library.html", - "./res/templates/edit-object.html", - "./res/templates/edit-action-buttons.html", - "./res/templates/topbar-edit.html" -], function ( - EditActionController, - EditPanesController, - EditObjectController, - EditAndComposeAction, - EditAction, - SaveAction, - SaveAndStopEditingAction, - CancelAction, - EditPersistableObjectsPolicy, - EditRepresenter, - EditorCapability, - libraryTemplate, - editObjectTemplate, - editActionButtonsTemplate, - topbarEditTemplate -) { - return { - name: "platform/commonUI/edit", - definition: { - "extensions": { - "controllers": [ - { - "key": "EditActionController", - "implementation": EditActionController, - "depends": [ - "$scope" - ] - }, - { - "key": "EditPanesController", - "implementation": EditPanesController, - "depends": [ - "$scope" - ] - }, - { - "key": "EditObjectController", - "implementation": EditObjectController, - "depends": [ - "$scope", - "$location", - "navigationService" - ] - } - ], - "actions": [ - { - "key": "compose", - "implementation": EditAndComposeAction - }, - { - "key": "edit", - "implementation": EditAction, - "depends": [ - "$location", - "navigationService", - "$log" - ], - "description": "Edit", - "category": "view-control", - "cssClass": "major icon-pencil", - "group": "action", - "priority": 10 - }, - { - "key": "save-and-stop-editing", - "category": "save", - "implementation": SaveAndStopEditingAction, - "name": "Save and Finish Editing", - "cssClass": "icon-save labeled", - "description": "Save changes made to these objects.", - "depends": [ - "dialogService", - "notificationService" - ] - }, - { - "key": "save", - "category": "save", - "implementation": SaveAction, - "name": "Save and Continue Editing", - "cssClass": "icon-save labeled", - "description": "Save changes made to these objects.", - "depends": [ - "dialogService", - "notificationService" - ] - }, - { - "key": "cancel", - "category": "conclude-editing", - "implementation": CancelAction, - // Because we use the name as label for edit buttons and mct-control buttons need - // the label to be set to undefined in order to not apply the labeled CSS rule. - "name": undefined, - "cssClass": "icon-x no-label", - "description": "Discard changes made to these objects.", - "depends": [] - } - ], - "policies": [ - { - "category": "action", - "implementation": EditPersistableObjectsPolicy, - "depends": ["openmct"] - } - ], - "templates": [ - { - "key": "edit-library", - "template": libraryTemplate - } - ], - "representations": [ - { - "key": "edit-object", - "template": editObjectTemplate, - "uses": [ - "view" - ], - "gestures": [ - "drop" - ] - }, - { - "key": "edit-action-buttons", - "template": editActionButtonsTemplate, - "uses": [ - "action" - ] - }, - { - "key": "topbar-edit", - "template": topbarEditTemplate - } - ], - "representers": [ - { - "implementation": EditRepresenter, - "depends": [ - "$log" - ] - } - ], - "capabilities": [ - { - "key": "editor", - "name": "Editor Capability", - "description": "Provides transactional editing capabilities", - "implementation": EditorCapability, - "depends": [ - "openmct" - ] - } - ], - "runs": [ - { - depends: [ - "toolbars[]", - "openmct" - ], - implementation: function (toolbars, openmct) { - toolbars.forEach(openmct.toolbars.addProvider, openmct.toolbars); - } - } - ] - } - } - }; -}); diff --git a/platform/commonUI/edit/res/templates/edit-action-buttons.html b/platform/commonUI/edit/res/templates/edit-action-buttons.html deleted file mode 100644 index 7e69204014..0000000000 --- a/platform/commonUI/edit/res/templates/edit-action-buttons.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/platform/commonUI/edit/res/templates/edit-object.html b/platform/commonUI/edit/res/templates/edit-object.html deleted file mode 100644 index 12ab94c437..0000000000 --- a/platform/commonUI/edit/res/templates/edit-object.html +++ /dev/null @@ -1,78 +0,0 @@ - -
-
-
- - - - -
-
- - - - - -
-
-
-
- -
- - - - - -
- - -
-
- - - -
diff --git a/platform/commonUI/edit/res/templates/library.html b/platform/commonUI/edit/res/templates/library.html deleted file mode 100644 index 810b030e0a..0000000000 --- a/platform/commonUI/edit/res/templates/library.html +++ /dev/null @@ -1,25 +0,0 @@ - - - diff --git a/platform/commonUI/edit/res/templates/topbar-edit.html b/platform/commonUI/edit/res/templates/topbar-edit.html deleted file mode 100644 index 986840636b..0000000000 --- a/platform/commonUI/edit/res/templates/topbar-edit.html +++ /dev/null @@ -1,39 +0,0 @@ - -
- - -
- - - - - -
-
diff --git a/platform/commonUI/edit/src/actions/CancelAction.js b/platform/commonUI/edit/src/actions/CancelAction.js deleted file mode 100644 index 8a764463fb..0000000000 --- a/platform/commonUI/edit/src/actions/CancelAction.js +++ /dev/null @@ -1,90 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The "Cancel" action; the action triggered by clicking Cancel from - * Edit Mode. Exits the editing user interface and invokes object - * capabilities to persist the changes that have been made. - * @constructor - * @memberof platform/commonUI/edit - * @implements {Action} - */ - function CancelAction(context) { - this.domainObject = context.domainObject; - } - - /** - * Cancel editing. - * - * @returns {Promise} a promise that will be fulfilled when - * cancellation has completed - */ - CancelAction.prototype.perform = function () { - var domainObject = this.domainObject; - - function returnToBrowse() { - var parent; - - //If the object existed already, navigate to refresh view - // with previous object state. - if (domainObject.getModel().persisted) { - return domainObject.getCapability("action").perform("navigate"); - } else { - //If the object was new, and user has cancelled, then - //navigate back to parent because nothing to show. - return domainObject.getCapability("location").getOriginal().then(function (original) { - parent = original.getCapability("context").getParent(); - - return parent.getCapability("action").perform("navigate"); - }); - } - } - - function cancel() { - return domainObject.getCapability("editor").finish(); - } - - //Do navigation first in order to trigger unsaved changes dialog - return returnToBrowse() - .then(cancel); - }; - - /** - * Check if this action is applicable in a given context. - * This will ensure that a domain object is present in the context, - * and that this domain object is in Edit mode. - * @returns {boolean} true if applicable - */ - CancelAction.appliesTo = function (context) { - var domainObject = (context || {}).domainObject; - - return domainObject !== undefined - && domainObject.hasCapability('editor') - && domainObject.getCapability('editor').isEditContextRoot(); - }; - - return CancelAction; - } -); diff --git a/platform/commonUI/edit/src/actions/EditAction.js b/platform/commonUI/edit/src/actions/EditAction.js deleted file mode 100644 index a97f5fa5f1..0000000000 --- a/platform/commonUI/edit/src/actions/EditAction.js +++ /dev/null @@ -1,101 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 EditAction. Created by vwoeltje on 11/14/14. - */ -define( - [], - function () { - - // A no-op action to return in the event that the action cannot - // be completed. - var NULL_ACTION = { - perform: function () { - return undefined; - } - }; - - /** - * The Edit action is performed when the user wishes to enter Edit - * mode (typically triggered by the Edit button.) This will - * show the user interface for editing (by way of a change in - * route) - * @memberof platform/commonUI/edit - * @constructor - * @implements {Action} - */ - function EditAction($location, navigationService, $log, context) { - var domainObject = (context || {}).domainObject; - - // We cannot enter Edit mode if we have no domain object to - // edit, so verify that one was defined as part of the - // context. (This is also verified in appliesTo, so this - // would indicate abnormal behavior.) - if (!domainObject) { - $log.warn([ - "No domain object to edit; ", - "edit action is not valid." - ].join("")); - - return NULL_ACTION; - } - - this.domainObject = domainObject; - this.$location = $location; - this.navigationService = navigationService; - } - - /** - * Enter edit mode. - */ - EditAction.prototype.perform = function () { - - //If this is not the currently navigated object, then navigate - // to it. - if (this.navigationService.getNavigation() !== this.domainObject) { - this.navigationService.setNavigation(this.domainObject); - } - - this.domainObject.useCapability("editor"); - }; - - /** - * Check for applicability; verify that a domain object is present - * for this action to be performed upon. - * @param {ActionContext} context the context in which this action - * will be performed; should contain a `domainObject` property - */ - EditAction.appliesTo = function (context) { - var domainObject = (context || {}).domainObject, - type = domainObject && domainObject.getCapability('type'); - - // Only allow editing of types that support it and are not already - // being edited - return type && type.hasFeature('creation') - && domainObject.hasCapability('editor') - && !domainObject.getCapability('editor').isEditContextRoot(); - }; - - return EditAction; - } -); diff --git a/platform/commonUI/edit/src/actions/EditAndComposeAction.js b/platform/commonUI/edit/src/actions/EditAndComposeAction.js deleted file mode 100644 index 032e246033..0000000000 --- a/platform/commonUI/edit/src/actions/EditAndComposeAction.js +++ /dev/null @@ -1,59 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Add one domain object to another's composition. - * @constructor - * @memberof platform/commonUI/edit - * @implements {Action} - */ - function EditAndComposeAction(context) { - this.domainObject = (context || {}).domainObject; - this.selectedObject = (context || {}).selectedObject; - } - - EditAndComposeAction.prototype.perform = function () { - var self = this, - editAction = this.domainObject.getCapability('action').getActions("edit")[0]; - - // Link these objects - function doLink() { - var composition = self.domainObject - && self.domainObject.getCapability('composition'); - - return composition && composition.add(self.selectedObject); - } - - if (editAction) { - editAction.perform(); - } - - return this.selectedObject && doLink(); - }; - - return EditAndComposeAction; - } -); diff --git a/platform/commonUI/edit/src/actions/SaveAction.js b/platform/commonUI/edit/src/actions/SaveAction.js deleted file mode 100644 index 67ec1e1961..0000000000 --- a/platform/commonUI/edit/src/actions/SaveAction.js +++ /dev/null @@ -1,98 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['./SaveInProgressDialog'], - function (SaveInProgressDialog) { - - /** - * The "Save" action; it invokes object capabilities to persist - * the changes that have been made. - * @constructor - * @implements {Action} - * @memberof platform/commonUI/edit - */ - function SaveAction( - dialogService, - notificationService, - context - ) { - this.domainObject = (context || {}).domainObject; - this.dialogService = dialogService; - this.notificationService = notificationService; - } - - /** - * Save changes. - * - * @returns {Promise} a promise that will be fulfilled when - * cancellation has completed - * @memberof platform/commonUI/edit.SaveAction# - */ - SaveAction.prototype.perform = function () { - var self = this, - domainObject = this.domainObject, - dialog = new SaveInProgressDialog(this.dialogService); - - // Invoke any save behavior introduced by the editor capability; - // this is introduced by EditableDomainObject which is - // used to insulate underlying objects from changes made - // during editing. - function doSave() { - return domainObject.getCapability("editor").save(); - } - - function onSuccess() { - dialog.hide(); - self.notificationService.info("Save Succeeded"); - } - - function onFailure() { - dialog.hide(); - self.notificationService.error("Save Failed"); - } - - dialog.show(); - - return doSave() - .then(onSuccess) - .catch(onFailure); - }; - - /** - * Check if this action is applicable in a given context. - * This will ensure that a domain object is present in the context, - * and that this domain object is in Edit mode. - * @returns true if applicable - */ - SaveAction.appliesTo = function (context) { - var domainObject = (context || {}).domainObject; - - return domainObject !== undefined - && domainObject.hasCapability('editor') - && domainObject.getCapability('editor').isEditContextRoot() - && domainObject.getModel().persisted !== undefined; - }; - - return SaveAction; - } -); diff --git a/platform/commonUI/edit/src/actions/SaveAndStopEditingAction.js b/platform/commonUI/edit/src/actions/SaveAndStopEditingAction.js deleted file mode 100644 index fcc65d85c0..0000000000 --- a/platform/commonUI/edit/src/actions/SaveAndStopEditingAction.js +++ /dev/null @@ -1,75 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ["./SaveAction"], - function (SaveAction) { - - /** - * The "Save and Stop Editing" action performs a [Save action]{@link SaveAction} - * on the object under edit followed by exiting the edit user interface. - * @constructor - * @implements {Action} - * @memberof platform/commonUI/edit - */ - function SaveAndStopEditingAction( - dialogService, - notificationService, - context - ) { - this.context = context; - this.domainObject = (context || {}).domainObject; - this.dialogService = dialogService; - this.notificationService = notificationService; - } - - /** - * Trigger a save operation and exit edit mode. - * - * @returns {Promise} a promise that will be fulfilled when - * cancellation has completed - * @memberof platform/commonUI/edit.SaveAndStopEditingAction# - */ - SaveAndStopEditingAction.prototype.perform = function () { - var domainObject = this.domainObject, - saveAction = new SaveAction(this.dialogService, this.notificationService, this.context); - - function closeEditor() { - return domainObject.getCapability("editor").finish(); - } - - return saveAction.perform() - .then(closeEditor) - .catch(closeEditor); - }; - - /** - * Check if this action is applicable in a given context. - * This will ensure that a domain object is present in the context, - * and that this domain object is in Edit mode. - * @returns true if applicable - */ - SaveAndStopEditingAction.appliesTo = SaveAction.appliesTo; - - return SaveAndStopEditingAction; - } -); diff --git a/platform/commonUI/edit/src/actions/SaveInProgressDialog.js b/platform/commonUI/edit/src/actions/SaveInProgressDialog.js deleted file mode 100644 index ea419e7040..0000000000 --- a/platform/commonUI/edit/src/actions/SaveInProgressDialog.js +++ /dev/null @@ -1,24 +0,0 @@ -define([], function () { - function SaveInProgressDialog(dialogService) { - this.dialogService = dialogService; - this.dialog = undefined; - } - - SaveInProgressDialog.prototype.show = function () { - this.dialog = this.dialogService.showBlockingMessage({ - title: "Saving", - hint: "Do not navigate away from this page or close this browser tab while this message is displayed.", - unknownProgress: true, - severity: "info", - delay: true - }); - }; - - SaveInProgressDialog.prototype.hide = function () { - if (this.dialog) { - this.dialog.dismiss(); - } - }; - - return SaveInProgressDialog; -}); diff --git a/platform/commonUI/edit/src/capabilities/EditorCapability.js b/platform/commonUI/edit/src/capabilities/EditorCapability.js deleted file mode 100644 index ebd4fc042d..0000000000 --- a/platform/commonUI/edit/src/capabilities/EditorCapability.js +++ /dev/null @@ -1,64 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 capability that implements an editing 'session' for a domain - * object. An editing session is initiated via a call to .edit(). - * Once initiated, any persist operations will be queued pending a - * subsequent call to [.save()](@link #save) or [.finish()](@link - * #finish). - * @param domainObject - * @constructor - */ - function EditorCapability( - openmct, - domainObject - ) { - this.openmct = openmct; - this.domainObject = domainObject; - } - - /** - * Determines whether this object, or any of its ancestors are - * currently being edited. - * @returns boolean - */ - EditorCapability.prototype.inEditContext = function () { - return this.openmct.editor.isEditing(); - }; - - /** - * Is this the root editing object (ie. the object that the user - * clicked 'edit' on)? - * @returns {*} - */ - EditorCapability.prototype.isEditContextRoot = function () { - return this.openmct.editor.isEditing(); - }; - - return EditorCapability; - } -); diff --git a/platform/commonUI/edit/src/controllers/EditActionController.js b/platform/commonUI/edit/src/controllers/EditActionController.js deleted file mode 100644 index 8e45d4312d..0000000000 --- a/platform/commonUI/edit/src/controllers/EditActionController.js +++ /dev/null @@ -1,79 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 EditActionController. Created by vwoeltje on 11/17/14. - */ -define( - [], - function () { - - var SAVE_ACTION_CONTEXT = { category: 'save' }; - var OTHERS_ACTION_CONTEXT = { category: 'conclude-editing' }; - - /** - * Controller which supplies action instances for Save/Cancel. - * @memberof platform/commonUI/edit - * @constructor - */ - function EditActionController($scope) { - - function actionToMenuOption(action) { - return { - key: action, - name: action.getMetadata().name, - cssClass: action.getMetadata().cssClass - }; - } - - // Maintain all "conclude-editing" and "save" actions in the - // present context. - function updateActions() { - $scope.saveActions = $scope.action - ? $scope.action.getActions(SAVE_ACTION_CONTEXT) - : []; - - $scope.saveActionsAsMenuOptions = $scope.saveActions.map(actionToMenuOption); - - $scope.saveActionMenuClickHandler = function (clickedAction) { - clickedAction.perform(); - }; - - $scope.otherEditActions = $scope.action - ? $scope.action.getActions(OTHERS_ACTION_CONTEXT) - : []; - - // Required because Angular does not allow 'bind' - // in expressions. - $scope.actionPerformer = function (action) { - return action.perform.bind(action); - }; - } - - // Update set of actions whenever the action capability - // changes or becomes available. - $scope.$watch("action", updateActions); - } - - return EditActionController; - } -); diff --git a/platform/commonUI/edit/src/controllers/EditObjectController.js b/platform/commonUI/edit/src/controllers/EditObjectController.js deleted file mode 100644 index e91505f78e..0000000000 --- a/platform/commonUI/edit/src/controllers/EditObjectController.js +++ /dev/null @@ -1,86 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -/** - * This bundle implements Edit mode. - * @namespace platform/commonUI/edit - */ -define( - [], - function () { - - function cancelEditing(domainObject) { - var navigatedObject = domainObject, - editorCapability = navigatedObject - && navigatedObject.getCapability("editor"); - - return editorCapability - && editorCapability.finish(); - } - - /** - * Controller which is responsible for populating the scope for - * Edit mode - * @memberof platform/commonUI/edit - * @constructor - */ - function EditObjectController($scope, $location, navigationService) { - this.scope = $scope; - var domainObject = $scope.domainObject; - - var removeCheck = navigationService - .checkBeforeNavigation(function () { - return "Continuing will cause the loss of any unsaved changes."; - }); - - $scope.$on('$destroy', function () { - removeCheck(); - cancelEditing(domainObject); - }); - - function setViewForDomainObject() { - - var locationViewKey = $location.search().view; - - function selectViewIfMatching(view) { - if (view.key === locationViewKey) { - $scope.representation = $scope.representation || {}; - $scope.representation.selected = view; - } - } - - if (locationViewKey) { - ((domainObject && domainObject.useCapability('view')) || []) - .forEach(selectViewIfMatching); - } - } - - setViewForDomainObject(); - - $scope.doAction = function (action) { - return $scope[action] && $scope[action](); - }; - } - - return EditObjectController; - } -); diff --git a/platform/commonUI/edit/src/controllers/EditPanesController.js b/platform/commonUI/edit/src/controllers/EditPanesController.js deleted file mode 100644 index fdeddcbc67..0000000000 --- a/platform/commonUI/edit/src/controllers/EditPanesController.js +++ /dev/null @@ -1,66 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Supports the Library and Elements panes in Edit mode. - * @memberof platform/commonUI/edit - * @constructor - */ - function EditPanesController($scope) { - var self = this; - - // Update root object based on represented object - function updateRoot(domainObject) { - var root = self.rootDomainObject, - context = domainObject - && domainObject.getCapability('context'), - newRoot = context && context.getTrueRoot(), - oldId = root && root.getId(), - newId = newRoot && newRoot.getId(); - - // Only update if this has actually changed, - // to avoid excessive refreshing. - if (oldId !== newId) { - self.rootDomainObject = newRoot; - } - } - - // Update root when represented object changes - $scope.$watch('domainObject', updateRoot); - } - - /** - * Get the root-level domain object, as reported by the - * represented domain object. - * @returns {DomainObject} the root object - */ - EditPanesController.prototype.getRoot = function () { - return this.rootDomainObject; - }; - - return EditPanesController; - } -); diff --git a/platform/commonUI/edit/src/policies/EditPersistableObjectsPolicy.js b/platform/commonUI/edit/src/policies/EditPersistableObjectsPolicy.js deleted file mode 100644 index fecfea2e18..0000000000 --- a/platform/commonUI/edit/src/policies/EditPersistableObjectsPolicy.js +++ /dev/null @@ -1,57 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['objectUtils'], - function (objectUtils) { - - /** - * Policy that prevents editing of any object from a provider that does not - * support persistence (ie. the 'save' operation). Editing is prevented - * as a subsequent save would fail, causing the loss of a user's changes. - * @param openmct - * @constructor - */ - function EditPersistableObjectsPolicy(openmct) { - this.openmct = openmct; - } - - EditPersistableObjectsPolicy.prototype.allow = function (action, context) { - var domainObject = context.domainObject; - var key = action.getMetadata().key; - var category = (context || {}).category; - - // Use category to selectively block edit from the view. Edit action - // is also invoked during the create process which should be allowed, - // because it may be saved elsewhere - if ((key === 'edit' && category === 'view-control') || key === 'properties') { - let identifier = this.openmct.objects.parseKeyString(domainObject.getId()); - - return this.openmct.objects.isPersistable(identifier); - } - - return true; - }; - - return EditPersistableObjectsPolicy; - } -); diff --git a/platform/commonUI/edit/src/representers/EditRepresenter.js b/platform/commonUI/edit/src/representers/EditRepresenter.js deleted file mode 100644 index beae6e3556..0000000000 --- a/platform/commonUI/edit/src/representers/EditRepresenter.js +++ /dev/null @@ -1,99 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The EditRepresenter is responsible for implementing - * representation-level behavior relevant to Edit mode. - * Specifically, this listens for changes to view configuration - * or to domain object models, and triggers persistence when - * these are detected. - * - * This is exposed as an extension of category `representers`, - * which mct-representation will utilize to add additional - * behavior to each representation. - * - * This will be called once per mct-representation directive, - * and may be reused for different domain objects and/or - * representations resulting from changes there. - * - * @memberof platform/commonUI/edit - * @implements {Representer} - * @constructor - */ - function EditRepresenter($log, $scope) { - this.$log = $log; - this.$scope = $scope; - - this.$scope.commit = this.commit.bind(this); - } - - /** - * Commit any changes made to the in-scope model to the domain object. - * Also commits any changes made to $scope.configuration to the proper - * configuration value for the current representation. - * - * @param {String} message a message to log with the commit message. - */ - EditRepresenter.prototype.commit = function (message) { - var model = this.$scope.model, - configuration = this.$scope.configuration, - domainObject = this.domainObject; - - this.$log.debug([ - "Committing ", - domainObject && domainObject.getModel().name, - "(" + (domainObject && domainObject.getId()) + "):", - message - ].join(" ")); - - if (this.domainObject) { - if (this.key && configuration) { - model.configuration = model.configuration || {}; - model.configuration[this.key] = configuration; - } - - domainObject.useCapability('mutation', function () { - return model; - }); - } - }; - - // Handle a specific representation of a specific domain object - EditRepresenter.prototype.represent = function (representation, representedObject) { - this.domainObject = representedObject; - if (representation) { - this.key = representation.key; - } else { - delete this.key; - } - }; - - // Respond to the destruction of the current representation. - EditRepresenter.prototype.destroy = function () {}; - - return EditRepresenter; - } -); diff --git a/platform/commonUI/edit/test/actions/CancelActionSpec.js b/platform/commonUI/edit/test/actions/CancelActionSpec.js deleted file mode 100644 index fd8a2e35d7..0000000000 --- a/platform/commonUI/edit/test/actions/CancelActionSpec.js +++ /dev/null @@ -1,155 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/CancelAction"], - function (CancelAction) { - - describe("The Cancel action", function () { - var mockDomainObject, - mockParentObject, - capabilities = {}, - parentCapabilities = {}, - actionContext, - action; - - function mockPromise(value) { - return { - then: function (callback) { - return mockPromise(callback(value)); - } - }; - } - - beforeEach(function () { - mockDomainObject = jasmine.createSpyObj( - "domainObject", - [ - "getCapability", - "hasCapability", - "getModel" - ] - ); - mockDomainObject.getModel.and.returnValue({}); - - mockParentObject = jasmine.createSpyObj( - "parentObject", - [ - "getCapability" - ] - ); - mockParentObject.getCapability.and.callFake(function (name) { - return parentCapabilities[name]; - }); - - capabilities.editor = jasmine.createSpyObj( - "editor", - ["save", "finish", "isEditContextRoot"] - ); - capabilities.action = jasmine.createSpyObj( - "actionCapability", - [ - "perform" - ] - ); - capabilities.location = jasmine.createSpyObj( - "locationCapability", - [ - "getOriginal" - ] - ); - capabilities.location.getOriginal.and.returnValue(mockPromise(mockDomainObject)); - capabilities.context = jasmine.createSpyObj( - "contextCapability", - [ - "getParent" - ] - ); - capabilities.context.getParent.and.returnValue(mockParentObject); - - parentCapabilities.action = jasmine.createSpyObj( - "actionCapability", - [ - "perform" - ] - ); - - actionContext = { - domainObject: mockDomainObject - }; - - mockDomainObject.getCapability.and.callFake(function (name) { - return capabilities[name]; - }); - - mockDomainObject.hasCapability.and.callFake(function (name) { - return Boolean(capabilities[name]); - }); - - capabilities.editor.finish.and.returnValue(mockPromise(true)); - - action = new CancelAction(actionContext); - - }); - - it("only applies to domain object that is being edited", function () { - capabilities.editor.isEditContextRoot.and.returnValue(true); - expect(CancelAction.appliesTo(actionContext)).toBeTruthy(); - expect(mockDomainObject.hasCapability).toHaveBeenCalledWith("editor"); - - capabilities.editor.isEditContextRoot.and.returnValue(false); - expect(CancelAction.appliesTo(actionContext)).toBeFalsy(); - - mockDomainObject.hasCapability.and.returnValue(false); - expect(CancelAction.appliesTo(actionContext)).toBeFalsy(); - }); - - it("invokes the editor capability's cancel functionality when" - + " performed", function () { - mockDomainObject.getModel.and.returnValue({persisted: 1}); - //Return true from navigate action - capabilities.action.perform.and.returnValue(mockPromise(true)); - action.perform(); - - // Should have called finish - expect(capabilities.editor.finish).toHaveBeenCalled(); - - // Definitely shouldn't call save! - expect(capabilities.editor.save).not.toHaveBeenCalled(); - }); - - it("navigates to object if existing using navigate action", function () { - mockDomainObject.getModel.and.returnValue({persisted: 1}); - //Return true from navigate action - capabilities.action.perform.and.returnValue(mockPromise(true)); - action.perform(); - expect(capabilities.action.perform).toHaveBeenCalledWith("navigate"); - }); - - it("navigates to parent if new using navigate action", function () { - mockDomainObject.getModel.and.returnValue({persisted: undefined}); - action.perform(); - expect(parentCapabilities.action.perform).toHaveBeenCalledWith("navigate"); - }); - }); - } -); diff --git a/platform/commonUI/edit/test/actions/EditActionSpec.js b/platform/commonUI/edit/test/actions/EditActionSpec.js deleted file mode 100644 index f8c68bdfc8..0000000000 --- a/platform/commonUI/edit/test/actions/EditActionSpec.js +++ /dev/null @@ -1,108 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/EditAction"], - function (EditAction) { - - describe("The Edit action", function () { - var mockLocation, - mockNavigationService, - mockLog, - mockDomainObject, - mockType, - mockEditor, - actionContext, - capabilities, - action; - - beforeEach(function () { - mockLocation = jasmine.createSpyObj( - "$location", - ["path"] - ); - mockNavigationService = jasmine.createSpyObj( - "navigationService", - ["setNavigation", "getNavigation", "addListener", "removeListener"] - ); - mockLog = jasmine.createSpyObj( - "$log", - ["error", "warn", "info", "debug"] - ); - mockDomainObject = jasmine.createSpyObj( - "domainObject", - ["getId", "getModel", "getCapability", "hasCapability", "useCapability"] - ); - mockType = jasmine.createSpyObj( - "type", - ["hasFeature"] - ); - mockEditor = jasmine.createSpyObj( - "editorCapability", - ["edit", "isEditContextRoot"] - ); - - capabilities = { - type: mockType, - editor: mockEditor - }; - - mockDomainObject.getCapability.and.callFake(function (name) { - return capabilities[name]; - }); - mockDomainObject.hasCapability.and.returnValue(true); - mockType.hasFeature.and.returnValue(true); - - actionContext = { domainObject: mockDomainObject }; - - action = new EditAction( - mockLocation, - mockNavigationService, - mockLog, - actionContext - ); - }); - - it("is only applicable when an editable domain object is present", function () { - expect(EditAction.appliesTo(actionContext)).toBeTruthy(); - expect(EditAction.appliesTo({})).toBeFalsy(); - - expect(mockDomainObject.hasCapability).toHaveBeenCalledWith('editor'); - // Should have checked for creatability - expect(mockType.hasFeature).toHaveBeenCalledWith('creation'); - }); - - it("is only applicable to objects not already in edit mode", function () { - mockEditor.isEditContextRoot.and.returnValue(false); - expect(EditAction.appliesTo(actionContext)).toBe(true); - mockEditor.isEditContextRoot.and.returnValue(true); - expect(EditAction.appliesTo(actionContext)).toBe(false); - }); - - it ("invokes the Edit capability on the object", function () { - action.perform(); - expect(mockDomainObject.useCapability).toHaveBeenCalledWith("editor"); - }); - - }); - } -); diff --git a/platform/commonUI/edit/test/actions/EditAndComposeActionSpec.js b/platform/commonUI/edit/test/actions/EditAndComposeActionSpec.js deleted file mode 100644 index 898876a6a3..0000000000 --- a/platform/commonUI/edit/test/actions/EditAndComposeActionSpec.js +++ /dev/null @@ -1,119 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/EditAndComposeAction"], - function (EditAndComposeAction) { - - describe("The Link action", function () { - var mockDomainObject, - mockParent, - mockContext, - mockComposition, - mockActionCapability, - mockEditAction, - mockType, - actionContext, - model, - capabilities, - action; - - function mockPromise(value) { - return { - then: function (callback) { - return mockPromise(callback(value)); - } - }; - } - - beforeEach(function () { - mockDomainObject = jasmine.createSpyObj( - "domainObject", - ["getId", "getCapability"] - ); - mockParent = { - getModel: function () { - return model; - }, - getCapability: function (k) { - return capabilities[k]; - }, - useCapability: function (k, v) { - return capabilities[k].invoke(v); - } - }; - mockContext = jasmine.createSpyObj("context", ["getParent"]); - mockComposition = jasmine.createSpyObj("composition", ["invoke", "add"]); - mockType = jasmine.createSpyObj("type", ["hasFeature", "getKey"]); - mockActionCapability = jasmine.createSpyObj("actionCapability", ["getActions"]); - mockEditAction = jasmine.createSpyObj("editAction", ["perform"]); - - mockDomainObject.getId.and.returnValue("test"); - mockDomainObject.getCapability.and.returnValue(mockContext); - mockContext.getParent.and.returnValue(mockParent); - mockType.hasFeature.and.returnValue(true); - mockType.getKey.and.returnValue("layout"); - mockComposition.invoke.and.returnValue(mockPromise(true)); - mockComposition.add.and.returnValue(mockPromise(true)); - mockActionCapability.getActions.and.returnValue([]); - - capabilities = { - composition: mockComposition, - action: mockActionCapability, - type: mockType - }; - model = { - composition: ["a", "b", "c"] - }; - - actionContext = { - domainObject: mockParent, - selectedObject: mockDomainObject - }; - - action = new EditAndComposeAction(actionContext); - }); - - it("adds to the parent's composition when performed", function () { - action.perform(); - expect(mockComposition.add) - .toHaveBeenCalledWith(mockDomainObject); - }); - - it("enables edit mode for objects that have an edit action", function () { - mockActionCapability.getActions.and.returnValue([mockEditAction]); - action.perform(); - expect(mockEditAction.perform).toHaveBeenCalled(); - }); - - it("Does not enable edit mode for objects that do not have an" - + " edit action", function () { - mockActionCapability.getActions.and.returnValue([]); - action.perform(); - expect(mockEditAction.perform).not.toHaveBeenCalled(); - expect(mockComposition.add) - .toHaveBeenCalledWith(mockDomainObject); - }); - - }); - } -); diff --git a/platform/commonUI/edit/test/actions/SaveActionSpec.js b/platform/commonUI/edit/test/actions/SaveActionSpec.js deleted file mode 100644 index 9a6860f469..0000000000 --- a/platform/commonUI/edit/test/actions/SaveActionSpec.js +++ /dev/null @@ -1,159 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/SaveAction"], - function (SaveAction) { - - describe("The Save action", function () { - var mockDomainObject, - mockEditorCapability, - actionContext, - mockDialogService, - mockNotificationService, - mockActionCapability, - capabilities = {}, - action; - - function mockPromise(value) { - return { - then: function (callback) { - return mockPromise(callback(value)); - }, - catch: function (callback) { - return mockPromise(callback(value)); - } - }; - } - - beforeEach(function () { - mockDomainObject = jasmine.createSpyObj( - "domainObject", - [ - "getCapability", - "hasCapability", - "getModel", - "getOriginalObject" - ] - ); - mockEditorCapability = jasmine.createSpyObj( - "editor", - ["save", "isEditContextRoot"] - ); - mockActionCapability = jasmine.createSpyObj( - "actionCapability", - ["perform"] - ); - capabilities.editor = mockEditorCapability; - capabilities.action = mockActionCapability; - - actionContext = { - domainObject: mockDomainObject - }; - - mockDialogService = jasmine.createSpyObj( - "dialogService", - ["showBlockingMessage"] - ); - - mockNotificationService = jasmine.createSpyObj( - "notificationService", - ["info", "error"] - ); - - mockDomainObject.hasCapability.and.returnValue(true); - mockDomainObject.getCapability.and.callFake(function (capability) { - return capabilities[capability]; - }); - mockDomainObject.getModel.and.returnValue({persisted: 0}); - mockEditorCapability.save.and.returnValue(mockPromise(true)); - mockEditorCapability.isEditContextRoot.and.returnValue(true); - - action = new SaveAction(mockDialogService, mockNotificationService, actionContext); - }); - - it("only applies to domain object with an editor capability", function () { - expect(SaveAction.appliesTo(actionContext)).toBe(true); - expect(mockDomainObject.hasCapability).toHaveBeenCalledWith("editor"); - - mockDomainObject.hasCapability.and.returnValue(false); - mockDomainObject.getCapability.and.returnValue(undefined); - expect(SaveAction.appliesTo(actionContext)).toBe(false); - }); - - it("only applies to domain object that has already been persisted", - function () { - mockDomainObject.getModel.and.returnValue({persisted: undefined}); - expect(SaveAction.appliesTo(actionContext)).toBe(false); - }); - - it("uses the editor capability to save the object", - function () { - action.perform(); - expect(mockEditorCapability.save).toHaveBeenCalled(); - }); - - describe("in order to keep the user in the loop", function () { - var mockDialogHandle; - - beforeEach(function () { - mockDialogHandle = jasmine.createSpyObj("dialogHandle", ["dismiss"]); - mockDialogService.showBlockingMessage.and.returnValue(mockDialogHandle); - }); - - it("shows a dialog while saving", function () { - mockEditorCapability.save.and.returnValue(new Promise(function () { - })); - action.perform(); - expect(mockDialogService.showBlockingMessage).toHaveBeenCalled(); - expect(mockDialogHandle.dismiss).not.toHaveBeenCalled(); - }); - - it("hides the dialog when saving is complete", function () { - action.perform(); - expect(mockDialogService.showBlockingMessage).toHaveBeenCalled(); - expect(mockDialogHandle.dismiss).toHaveBeenCalled(); - }); - - it("notifies if saving succeeded", function () { - var mockCallback = jasmine.createSpy("callback"); - mockEditorCapability.save.and.returnValue(Promise.resolve()); - - return action.perform().then(mockCallback).then(function () { - expect(mockNotificationService.info).toHaveBeenCalled(); - expect(mockNotificationService.error).not.toHaveBeenCalled(); - }); - }); - - it("notifies if saving failed", function () { - var mockCallback = jasmine.createSpy("callback"); - mockEditorCapability.save.and.returnValue(Promise.reject("some failure reason")); - - return action.perform().then(mockCallback).then(function () { - expect(mockNotificationService.error).toHaveBeenCalled(); - expect(mockNotificationService.info).not.toHaveBeenCalled(); - }); - }); - }); - }); - } -); diff --git a/platform/commonUI/edit/test/actions/SaveAndStopEditingActionSpec.js b/platform/commonUI/edit/test/actions/SaveAndStopEditingActionSpec.js deleted file mode 100644 index cc791f570c..0000000000 --- a/platform/commonUI/edit/test/actions/SaveAndStopEditingActionSpec.js +++ /dev/null @@ -1,128 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/SaveAndStopEditingAction"], - function (SaveAndStopEditingAction) { - - describe("The Save and Stop Editing action", function () { - - // Some mocks appear unused because the - // underlying SaveAction that this action - // depends on is not mocked, so we mock some - // of SaveAction's own dependencies to make - // it run. - var mockDomainObject, - mockEditorCapability, - actionContext, - dialogService, - notificationService, - mockActionCapability, - capabilities = {}, - action; - - function mockPromise(value) { - return { - then: function (callback) { - return mockPromise(callback(value)); - }, - catch: function (callback) { - return mockPromise(callback(value)); - } - }; - } - - beforeEach(function () { - mockDomainObject = jasmine.createSpyObj( - "domainObject", - [ - "getCapability", - "hasCapability", - "getModel", - "getOriginalObject" - ] - ); - mockEditorCapability = jasmine.createSpyObj( - "editor", - ["save", "finish", "isEditContextRoot"] - ); - mockActionCapability = jasmine.createSpyObj( - "actionCapability", - ["perform"] - ); - capabilities.editor = mockEditorCapability; - capabilities.action = mockActionCapability; - - actionContext = { - domainObject: mockDomainObject - }; - dialogService = jasmine.createSpyObj( - "dialogService", - ["showBlockingMessage"] - ); - - notificationService = jasmine.createSpyObj( - "notificationService", - ["info", "error"] - ); - - mockDomainObject.hasCapability.and.returnValue(true); - mockDomainObject.getCapability.and.callFake(function (capability) { - return capabilities[capability]; - }); - mockDomainObject.getModel.and.returnValue({ persisted: 0 }); - mockEditorCapability.save.and.returnValue(mockPromise(true)); - mockEditorCapability.isEditContextRoot.and.returnValue(true); - - action = new SaveAndStopEditingAction(dialogService, notificationService, actionContext); - }); - - it("only applies to domain object with an editor capability", function () { - expect(SaveAndStopEditingAction.appliesTo(actionContext)).toBe(true); - expect(mockDomainObject.hasCapability).toHaveBeenCalledWith("editor"); - - mockDomainObject.hasCapability.and.returnValue(false); - mockDomainObject.getCapability.and.returnValue(undefined); - expect(SaveAndStopEditingAction.appliesTo(actionContext)).toBe(false); - }); - - it("only applies to domain object that has already been persisted", function () { - mockDomainObject.getModel.and.returnValue({ persisted: undefined }); - expect(SaveAndStopEditingAction.appliesTo(actionContext)).toBe(false); - }); - - it("does not close the editor before completing the save", function () { - mockEditorCapability.save.and.returnValue(new Promise(function () { - })); - action.perform(); - expect(mockEditorCapability.save).toHaveBeenCalled(); - expect(mockEditorCapability.finish).not.toHaveBeenCalled(); - }); - - it("closes the editor after saving", function () { - action.perform(); - expect(mockEditorCapability.save).toHaveBeenCalled(); - expect(mockEditorCapability.finish).toHaveBeenCalled(); - }); - }); - } -); diff --git a/platform/commonUI/edit/test/controllers/EditActionControllerSpec.js b/platform/commonUI/edit/test/controllers/EditActionControllerSpec.js deleted file mode 100644 index d750234456..0000000000 --- a/platform/commonUI/edit/test/controllers/EditActionControllerSpec.js +++ /dev/null @@ -1,106 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/EditActionController"], - function (EditActionController) { - - describe("The Edit Action controller", function () { - var mockSaveActionMetadata = { - name: "mocked-save-action", - cssClass: "mocked-save-action-css" - }; - - function fakeGetActions(actionContext) { - if (actionContext.category === "save") { - var mockedSaveActions = [ - jasmine.createSpyObj("mockSaveAction", ["getMetadata", "perform"]), - jasmine.createSpyObj("mockSaveAction", ["getMetadata", "perform"]) - ]; - mockedSaveActions.forEach(function (action) { - action.getMetadata.and.returnValue(mockSaveActionMetadata); - }); - - return mockedSaveActions; - } else if (actionContext.category === "conclude-editing") { - return ["a", "b", "c"]; - } else { - throw "EditActionController uses a context that's not covered by tests."; - } - } - - var mockScope, - mockActions, - controller; - - beforeEach(function () { - mockActions = jasmine.createSpyObj("action", ["getActions"]); - mockActions.getActions.and.callFake(fakeGetActions); - mockScope = jasmine.createSpyObj("$scope", ["$watch"]); - mockScope.action = mockActions; - controller = new EditActionController(mockScope); - }); - - function makeControllerUpdateActions() { - mockScope.$watch.calls.mostRecent().args[1](); - } - - it("watches scope that may change applicable actions", function () { - // The action capability - expect(mockScope.$watch).toHaveBeenCalledWith( - "action", - jasmine.any(Function) - ); - }); - - it("populates the scope with 'save' actions", function () { - makeControllerUpdateActions(); - expect(mockScope.saveActions.length).toEqual(2); - }); - - it("converts 'save' actions to their menu counterparts", function () { - makeControllerUpdateActions(); - var menuOptions = mockScope.saveActionsAsMenuOptions; - - expect(menuOptions.length).toEqual(2); - expect(menuOptions[0].key).toEqual(mockScope.saveActions[0]); - expect(menuOptions[1].key).toEqual(mockScope.saveActions[1]); - menuOptions.forEach(function (option) { - expect(option.name).toEqual(mockSaveActionMetadata.name); - expect(option.cssClass).toEqual(mockSaveActionMetadata.cssClass); - }); - }); - - it("uses a click handler to perform the clicked action", function () { - makeControllerUpdateActions(); - var sampleSaveAction = mockScope.saveActions[0]; - mockScope.saveActionMenuClickHandler(sampleSaveAction); - expect(sampleSaveAction.perform).toHaveBeenCalled(); - }); - - it("populates the scope with other editing actions", function () { - makeControllerUpdateActions(); - expect(mockScope.otherEditActions).toEqual(["a", "b", "c"]); - }); - }); - } -); diff --git a/platform/commonUI/edit/test/controllers/EditObjectControllerSpec.js b/platform/commonUI/edit/test/controllers/EditObjectControllerSpec.js deleted file mode 100644 index 5884e1526f..0000000000 --- a/platform/commonUI/edit/test/controllers/EditObjectControllerSpec.js +++ /dev/null @@ -1,138 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/EditObjectController"], - function (EditObjectController) { - - describe("The Edit Object controller", function () { - var mockScope, - mockObject, - testViews, - mockEditorCapability, - mockLocation, - mockNavigationService, - removeCheck, - mockStatusCapability, - mockCapabilities, - controller; - - beforeEach(function () { - mockScope = jasmine.createSpyObj( - "$scope", - ["$on", "$watch"] - ); - mockObject = jasmine.createSpyObj( - "domainObject", - ["getId", "getModel", "getCapability", "hasCapability", "useCapability"] - ); - mockEditorCapability = jasmine.createSpyObj( - "mockEditorCapability", - ["isEditContextRoot", "dirty", "finish"] - ); - mockStatusCapability = jasmine.createSpyObj('statusCapability', - ["get"] - ); - - mockCapabilities = { - "editor": mockEditorCapability, - "status": mockStatusCapability - }; - - mockLocation = jasmine.createSpyObj('$location', - ["search"] - ); - mockLocation.search.and.returnValue({"view": "fixed"}); - mockNavigationService = jasmine.createSpyObj('navigationService', - ["checkBeforeNavigation"] - ); - - removeCheck = jasmine.createSpy('removeCheck'); - mockNavigationService.checkBeforeNavigation.and.returnValue(removeCheck); - - mockObject.getId.and.returnValue("test"); - mockObject.getModel.and.returnValue({ name: "Test object" }); - mockObject.getCapability.and.callFake(function (key) { - return mockCapabilities[key]; - }); - - testViews = [ - { key: 'abc' }, - { - key: 'def', - someKey: 'some value' - }, - { key: 'xyz' } - ]; - - mockObject.useCapability.and.callFake(function (c) { - return (c === 'view') && testViews; - }); - mockLocation.search.and.returnValue({ view: 'def' }); - - mockScope.domainObject = mockObject; - - controller = new EditObjectController( - mockScope, - mockLocation, - mockNavigationService - ); - }); - - it("adds a check before navigation", function () { - expect(mockNavigationService.checkBeforeNavigation) - .toHaveBeenCalledWith(jasmine.any(Function)); - - var checkFn = mockNavigationService.checkBeforeNavigation.calls.mostRecent().args[0]; - - mockEditorCapability.isEditContextRoot.and.returnValue(false); - mockEditorCapability.dirty.and.returnValue(false); - - expect(checkFn()).toBe("Continuing will cause the loss of any unsaved changes."); - - mockEditorCapability.isEditContextRoot.and.returnValue(true); - expect(checkFn()).toBe("Continuing will cause the loss of any unsaved changes."); - - mockEditorCapability.dirty.and.returnValue(true); - expect(checkFn()) - .toBe("Continuing will cause the loss of any unsaved changes."); - - }); - - it("cleans up on destroy", function () { - expect(mockScope.$on) - .toHaveBeenCalledWith("$destroy", jasmine.any(Function)); - - mockScope.$on.calls.mostRecent().args[1](); - - expect(mockEditorCapability.finish).toHaveBeenCalled(); - expect(removeCheck).toHaveBeenCalled(); - }); - - it("sets the active view from query parameters", function () { - expect(mockScope.representation.selected) - .toEqual(testViews[1]); - }); - - }); - } -); diff --git a/platform/commonUI/edit/test/controllers/EditPanesControllerSpec.js b/platform/commonUI/edit/test/controllers/EditPanesControllerSpec.js deleted file mode 100644 index e499746d2f..0000000000 --- a/platform/commonUI/edit/test/controllers/EditPanesControllerSpec.js +++ /dev/null @@ -1,114 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/EditPanesController"], - function (EditPanesController) { - - describe("The Edit Panes controller", function () { - var mockScope, - mockDomainObject, - mockContext, - controller; - - beforeEach(function () { - mockScope = jasmine.createSpyObj("$scope", ["$watch"]); - mockDomainObject = jasmine.createSpyObj( - 'domainObject', - ['getId', 'getCapability'] - ); - mockContext = jasmine.createSpyObj( - 'context', - ['getTrueRoot'] - ); - - mockDomainObject.getId.and.returnValue('test-id'); - mockDomainObject.getCapability.and.returnValue(mockContext); - - // Return a new instance of the root object each time - mockContext.getTrueRoot.and.callFake(function () { - var mockRoot = jasmine.createSpyObj('root', ['getId']); - mockRoot.getId.and.returnValue('root-id'); - - return mockRoot; - }); - - controller = new EditPanesController(mockScope); - }); - - it("watches for the domain object in view", function () { - expect(mockScope.$watch).toHaveBeenCalledWith( - "domainObject", - jasmine.any(Function) - ); - }); - - it("exposes the root object found via the object's context capability", function () { - mockScope.$watch.calls.mostRecent().args[1](mockDomainObject); - - // Verify that the correct capability was used - expect(mockDomainObject.getCapability) - .toHaveBeenCalledWith('context'); - - // Should have exposed the root from getRoot - expect(controller.getRoot().getId()).toEqual('root-id'); - }); - - it("preserves the same root instance to avoid excessive refreshing", function () { - var firstRoot; - // Expose the domain object - mockScope.$watch.calls.mostRecent().args[1](mockDomainObject); - firstRoot = controller.getRoot(); - // Update! - mockScope.$watch.calls.mostRecent().args[1](mockDomainObject); - // Should still have the same object instance, to avoid - // triggering the watch used by the template we're supporting - expect(controller.getRoot()).toBe(firstRoot); - }); - - // Complements the test above; the object pointed to should change - // when the actual root has changed (detected by identifier) - it("updates the root when it changes", function () { - var firstRoot; - // Expose the domain object - mockScope.$watch.calls.mostRecent().args[1](mockDomainObject); - firstRoot = controller.getRoot(); - - // Change the exposed root - mockContext.getTrueRoot.and.callFake(function () { - var mockRoot = jasmine.createSpyObj('root', ['getId']); - mockRoot.getId.and.returnValue('other-root-id'); - - return mockRoot; - }); - - // Update! - mockScope.$watch.calls.mostRecent().args[1](mockDomainObject); - - // Should still have the same object instance, to avoid - // triggering the watch used by the template we're supporting - expect(controller.getRoot()).not.toBe(firstRoot); - expect(controller.getRoot().getId()).toEqual('other-root-id'); - }); - }); - } -); diff --git a/platform/commonUI/edit/test/policies/EditPersistableObjectsSpec.js b/platform/commonUI/edit/test/policies/EditPersistableObjectsSpec.js deleted file mode 100644 index 854a305463..0000000000 --- a/platform/commonUI/edit/test/policies/EditPersistableObjectsSpec.js +++ /dev/null @@ -1,102 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define( - ["../../src/policies/EditPersistableObjectsPolicy"], - function (EditPersistableObjectsPolicy) { - - describe("The Edit persistable objects policy", function () { - var mockDomainObject, - mockEditAction, - mockPropertiesAction, - mockOtherAction, - mockAPI, - mockObjectAPI, - testContext, - policy; - - beforeEach(function () { - mockDomainObject = jasmine.createSpyObj( - 'domainObject', - [ - 'getId' - ] - ); - - mockObjectAPI = jasmine.createSpyObj('objectAPI', [ - 'isPersistable', - 'parseKeyString' - ]); - - mockAPI = { - objects: mockObjectAPI - }; - - mockEditAction = jasmine.createSpyObj('edit', ['getMetadata']); - mockPropertiesAction = jasmine.createSpyObj('properties', ['getMetadata']); - mockOtherAction = jasmine.createSpyObj('other', ['getMetadata']); - - mockEditAction.getMetadata.and.returnValue({ key: 'edit' }); - mockPropertiesAction.getMetadata.and.returnValue({ key: 'properties' }); - mockOtherAction.getMetadata.and.returnValue({key: 'other'}); - - mockDomainObject.getId.and.returnValue('test:testId'); - - testContext = { - domainObject: mockDomainObject, - category: 'view-control' - }; - - policy = new EditPersistableObjectsPolicy(mockAPI); - }); - - it("Applies to edit action", function () { - expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled(); - - policy.allow(mockEditAction, testContext); - expect(mockObjectAPI.isPersistable).toHaveBeenCalled(); - }); - - it("Applies to properties action", function () { - expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled(); - - policy.allow(mockPropertiesAction, testContext); - expect(mockObjectAPI.isPersistable).toHaveBeenCalled(); - }); - - it("does not apply to other actions", function () { - expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled(); - - policy.allow(mockOtherAction, testContext); - expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled(); - }); - - it("Tests object provider for editability", function () { - mockObjectAPI.isPersistable.and.returnValue(false); - expect(policy.allow(mockEditAction, testContext)).toBe(false); - expect(mockObjectAPI.isPersistable).toHaveBeenCalled(); - mockObjectAPI.isPersistable.and.returnValue(true); - expect(policy.allow(mockEditAction, testContext)).toBe(true); - }); - }); - } -); diff --git a/platform/commonUI/edit/test/representers/EditRepresenterSpec.js b/platform/commonUI/edit/test/representers/EditRepresenterSpec.js deleted file mode 100644 index 068c0c4ae3..0000000000 --- a/platform/commonUI/edit/test/representers/EditRepresenterSpec.js +++ /dev/null @@ -1,87 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/representers/EditRepresenter' -], function ( - EditRepresenter -) { - describe('EditRepresenter', function () { - var $log, - $scope, - representer; - - beforeEach(function () { - $log = jasmine.createSpyObj('$log', ['debug']); - $scope = {}; - representer = new EditRepresenter($log, $scope); - }); - - it('injects a commit function in scope', function () { - expect($scope.commit).toEqual(jasmine.any(Function)); - }); - - describe('representation', function () { - var domainObject, - representation; - - beforeEach(function () { - domainObject = jasmine.createSpyObj('domainObject', [ - 'getId', - 'getModel', - 'useCapability' - ]); - - domainObject.getId.and.returnValue('anId'); - domainObject.getModel.and.returnValue({name: 'anObject'}); - - representation = { - key: 'someRepresentation' - }; - $scope.model = {name: 'anotherName'}; - $scope.configuration = {some: 'config'}; - representer.represent(representation, domainObject); - }); - - it('logs a message when commiting', function () { - $scope.commit('Test Message'); - expect($log.debug) - .toHaveBeenCalledWith('Committing anObject (anId): Test Message'); - }); - - it('mutates the object when committing', function () { - $scope.commit('Test Message'); - - expect(domainObject.useCapability) - .toHaveBeenCalledWith('mutation', jasmine.any(Function)); - - var mutateValue = domainObject.useCapability.calls.all()[0].args[1](); - - expect(mutateValue.configuration.someRepresentation) - .toEqual({some: 'config'}); - expect(mutateValue.name).toEqual('anotherName'); - }); - - }); - - }); -}); diff --git a/platform/commonUI/general/README.md b/platform/commonUI/general/README.md deleted file mode 100644 index 544baf08bc..0000000000 --- a/platform/commonUI/general/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Directives - -* `mct-scroll-x` is an attribute whose value is an assignable - Angular expression. This two-way binds that expression to the - horizontal scroll state of the element on which it is applied. -* `mct-scroll-y` is an attribute whose value is an assignable - Angular expression. This two-way binds that expression to the - vertical scroll state of the element on which it is applied. diff --git a/platform/commonUI/general/bundle.js b/platform/commonUI/general/bundle.js deleted file mode 100644 index 10e2f1a531..0000000000 --- a/platform/commonUI/general/bundle.js +++ /dev/null @@ -1,529 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/UrlService", - "./src/services/PopupService", - "./src/SplashScreenManager", - "./src/StyleSheetLoader", - "./src/controllers/TimeRangeController", - "./src/controllers/DateTimePickerController", - "./src/controllers/DateTimeFieldController", - "./src/controllers/TreeNodeController", - "./src/controllers/ActionGroupController", - "./src/controllers/ToggleController", - "./src/controllers/ClickAwayController", - "./src/controllers/ViewSwitcherController", - "./src/controllers/GetterSetterController", - "./src/controllers/SelectorController", - "./src/controllers/ObjectInspectorController", - "./src/controllers/BannerController", - "./src/directives/MCTContainer", - "./src/directives/MCTDrag", - "./src/directives/MCTSelectable", - "./src/directives/MCTClickElsewhere", - "./src/directives/MCTResize", - "./src/directives/MCTPopup", - "./src/directives/MCTScroll", - "./src/directives/MCTSplitPane", - "./src/directives/MCTSplitter", - "./src/directives/MCTTree", - "./src/directives/MCTIndicators", - "./src/filters/ReverseFilter", - "./res/templates/bottombar.html", - "./res/templates/controls/action-button.html", - "./res/templates/controls/input-filter.html", - "./res/templates/angular-indicator.html", - "./res/templates/message-banner.html", - "./res/templates/progress-bar.html", - "./res/templates/controls/time-controller.html", - "./res/templates/containers/accordion.html", - "./res/templates/subtree.html", - "./res/templates/tree.html", - "./res/templates/tree-node.html", - "./res/templates/label.html", - "./res/templates/controls/action-group.html", - "./res/templates/controls/switcher.html", - "./res/templates/object-inspector.html", - "./res/templates/controls/selector.html", - "./res/templates/controls/datetime-picker.html", - "./res/templates/controls/datetime-field.html" -], function ( - UrlService, - PopupService, - SplashScreenManager, - StyleSheetLoader, - TimeRangeController, - DateTimePickerController, - DateTimeFieldController, - TreeNodeController, - ActionGroupController, - ToggleController, - ClickAwayController, - ViewSwitcherController, - GetterSetterController, - SelectorController, - ObjectInspectorController, - BannerController, - MCTContainer, - MCTDrag, - MCTSelectable, - MCTClickElsewhere, - MCTResize, - MCTPopup, - MCTScroll, - MCTSplitPane, - MCTSplitter, - MCTTree, - MCTIndicators, - ReverseFilter, - bottombarTemplate, - actionButtonTemplate, - inputFilterTemplate, - indicatorTemplate, - messageBannerTemplate, - progressBarTemplate, - timeControllerTemplate, - accordionTemplate, - subtreeTemplate, - treeTemplate, - treeNodeTemplate, - labelTemplate, - actionGroupTemplate, - switcherTemplate, - objectInspectorTemplate, - selectorTemplate, - datetimePickerTemplate, - datetimeFieldTemplate -) { - - return { - name: "platform/commonUI/general", - definition: { - "name": "General UI elements", - "description": "General UI elements, meant to be reused across modes", - "resources": "res", - "extensions": { - "services": [ - { - "key": "urlService", - "implementation": UrlService, - "depends": [ - "$location" - ] - }, - { - "key": "popupService", - "implementation": PopupService, - "depends": [ - "$document", - "$window" - ] - } - ], - "runs": [ - { - "implementation": StyleSheetLoader, - "depends": [ - "stylesheets[]", - "$document", - "THEME", - "ASSETS_PATH" - ] - }, - { - "implementation": SplashScreenManager, - "depends": [ - "$document" - ] - } - ], - "filters": [ - { - "implementation": ReverseFilter, - "key": "reverse" - } - ], - "templates": [ - { - "key": "bottombar", - "template": bottombarTemplate - }, - { - "key": "action-button", - "template": actionButtonTemplate - }, - { - "key": "input-filter", - "template": inputFilterTemplate - }, - { - "key": "indicator", - "template": indicatorTemplate - }, - { - "key": "message-banner", - "template": messageBannerTemplate - }, - { - "key": "progress-bar", - "template": progressBarTemplate - }, - { - "key": "time-controller", - "template": timeControllerTemplate - } - ], - "controllers": [ - { - "key": "TimeRangeController", - "implementation": TimeRangeController, - "depends": [ - "$scope", - "$timeout", - "formatService", - "DEFAULT_TIME_FORMAT", - "now" - ] - }, - { - "key": "DateTimePickerController", - "implementation": DateTimePickerController, - "depends": [ - "$scope", - "now" - ] - }, - { - "key": "DateTimeFieldController", - "implementation": DateTimeFieldController, - "depends": [ - "$scope", - "formatService", - "DEFAULT_TIME_FORMAT" - ] - }, - { - "key": "TreeNodeController", - "implementation": TreeNodeController, - "depends": [ - "$scope", - "$timeout", - "navigationService" - ] - }, - { - "key": "ActionGroupController", - "implementation": ActionGroupController, - "depends": [ - "$scope" - ] - }, - { - "key": "ToggleController", - "implementation": ToggleController - }, - { - "key": "ClickAwayController", - "implementation": ClickAwayController, - "depends": [ - "$document", - "$timeout" - ] - }, - { - "key": "ViewSwitcherController", - "implementation": ViewSwitcherController, - "depends": [ - "$scope", - "$timeout" - ] - }, - { - "key": "GetterSetterController", - "implementation": GetterSetterController, - "depends": [ - "$scope" - ] - }, - { - "key": "SelectorController", - "implementation": SelectorController, - "depends": [ - "objectService", - "$scope" - ] - }, - { - "key": "ObjectInspectorController", - "implementation": ObjectInspectorController, - "depends": [ - "$scope", - "objectService" - ] - }, - { - "key": "BannerController", - "implementation": BannerController, - "depends": [ - "$scope", - "notificationService", - "dialogService" - ] - } - ], - "directives": [ - { - "key": "mctContainer", - "implementation": MCTContainer, - "depends": [ - "containers[]" - ] - }, - { - "key": "mctDrag", - "implementation": MCTDrag, - "depends": [ - "$document", - "agentService" - ] - }, - { - "key": "mctSelectable", - "implementation": MCTSelectable, - "depends": [ - "openmct" - ] - }, - { - "key": "mctClickElsewhere", - "implementation": MCTClickElsewhere, - "depends": [ - "$document" - ] - }, - { - "key": "mctResize", - "implementation": MCTResize, - "depends": [ - "$timeout" - ] - }, - { - "key": "mctPopup", - "implementation": MCTPopup, - "depends": [ - "$compile", - "popupService" - ] - }, - { - "key": "mctScrollX", - "implementation": MCTScroll, - "depends": [ - "$parse", - "MCT_SCROLL_X_PROPERTY", - "MCT_SCROLL_X_ATTRIBUTE" - ] - }, - { - "key": "mctScrollY", - "implementation": MCTScroll, - "depends": [ - "$parse", - "MCT_SCROLL_Y_PROPERTY", - "MCT_SCROLL_Y_ATTRIBUTE" - ] - }, - { - "key": "mctSplitPane", - "implementation": MCTSplitPane, - "depends": [ - "$parse", - "$log", - "$interval", - "$window" - ] - }, - { - "key": "mctSplitter", - "implementation": MCTSplitter - }, - { - "key": "mctTree", - "implementation": MCTTree, - "depends": ['gestureService', 'openmct'] - }, - { - "key": "mctIndicators", - "implementation": MCTIndicators, - "depends": ['openmct'] - } - ], - "constants": [ - { - "key": "MCT_SCROLL_X_PROPERTY", - "value": "scrollLeft" - }, - { - "key": "MCT_SCROLL_X_ATTRIBUTE", - "value": "mctScrollX" - }, - { - "key": "MCT_SCROLL_Y_PROPERTY", - "value": "scrollTop" - }, - { - "key": "MCT_SCROLL_Y_ATTRIBUTE", - "value": "mctScrollY" - }, - { - "key": "THEME", - "value": "unspecified", - "priority": "fallback" - }, - { - "key": "ASSETS_PATH", - "value": ".", - "priority": "fallback" - } - ], - "containers": [ - { - "key": "accordion", - "template": accordionTemplate, - "attributes": [ - "label" - ] - } - ], - "representations": [ - { - "key": "tree", - "template": subtreeTemplate, - "uses": [ - "composition" - ], - "type": "root", - "priority": "preferred" - }, - { - "key": "tree", - "template": treeTemplate - }, - { - "key": "subtree", - "template": subtreeTemplate, - "uses": [ - "composition" - ] - }, - { - "key": "tree-node", - "template": treeNodeTemplate, - "uses": [ - "action" - ] - }, - { - "key": "label", - "template": labelTemplate, - "uses": [ - "type", - "location" - ], - "gestures": [ - "drag", - "menu", - "info" - ] - }, - { - "key": "node", - "template": labelTemplate, - "uses": [ - "type" - ], - "gestures": [ - "drag", - "menu" - ] - }, - { - "key": "action-group", - "template": actionGroupTemplate, - "uses": [ - "action" - ] - }, - { - "key": "switcher", - "template": switcherTemplate, - "uses": [ - "view" - ] - }, - { - "key": "object-inspector", - "template": objectInspectorTemplate - } - ], - "controls": [ - { - "key": "selector", - "template": selectorTemplate - }, - { - "key": "datetime-picker", - "template": datetimePickerTemplate - }, - { - "key": "datetime-field", - "template": datetimeFieldTemplate - } - ], - "licenses": [ - { - "name": "Normalize.css", - "version": "1.1.2", - "description": "Browser style normalization", - "author": "Nicolas Gallagher, Jonathan Neal", - "website": "http://necolas.github.io/normalize.css/", - "copyright": "Copyright(c) Nicolas Gallagher and Jonathan Neal", - "license": "license-mit", - "link": "https://github.com/necolas/normalize.css/blob/v1.1.2/LICENSE.md" - }, - { - "name": "Zepto", - "version": "1.1.6", - "description": "DOM manipulation", - "author": "Thomas Fuchs", - "website": "http://zeptojs.com/", - "copyright": "Copyright(c) 2010-2016 Thomas Fuchs", - "license": "license-mit", - "link": "https://github.com/madrobby/zepto/blob/master/MIT-LICENSE" - } - ] - } - } - }; -}); diff --git a/platform/commonUI/general/res/templates/angular-indicator.html b/platform/commonUI/general/res/templates/angular-indicator.html deleted file mode 100644 index e13a91dbe4..0000000000 --- a/platform/commonUI/general/res/templates/angular-indicator.html +++ /dev/null @@ -1,26 +0,0 @@ - - -
- {{ngModel.getText()}} -
diff --git a/platform/commonUI/general/res/templates/bottombar.html b/platform/commonUI/general/res/templates/bottombar.html deleted file mode 100644 index ef3d58d349..0000000000 --- a/platform/commonUI/general/res/templates/bottombar.html +++ /dev/null @@ -1,28 +0,0 @@ - -
-
- -
- - -
diff --git a/platform/commonUI/general/res/templates/containers/accordion.html b/platform/commonUI/general/res/templates/containers/accordion.html deleted file mode 100644 index 222106ce36..0000000000 --- a/platform/commonUI/general/res/templates/containers/accordion.html +++ /dev/null @@ -1,34 +0,0 @@ - -
- {{container.label}} -
-
-
diff --git a/platform/commonUI/general/res/templates/controls/action-button.html b/platform/commonUI/general/res/templates/controls/action-button.html deleted file mode 100644 index ce231d99ec..0000000000 --- a/platform/commonUI/general/res/templates/controls/action-button.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - {{parameters.action.getMetadata().name}} - - diff --git a/platform/commonUI/general/res/templates/controls/action-group.html b/platform/commonUI/general/res/templates/controls/action-group.html deleted file mode 100644 index a1dc378b59..0000000000 --- a/platform/commonUI/general/res/templates/controls/action-group.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - diff --git a/platform/commonUI/general/res/templates/controls/breadcrumb.html b/platform/commonUI/general/res/templates/controls/breadcrumb.html deleted file mode 100644 index ce923da77e..0000000000 --- a/platform/commonUI/general/res/templates/controls/breadcrumb.html +++ /dev/null @@ -1,15 +0,0 @@ -
- - diff --git a/platform/commonUI/general/res/templates/controls/datetime-field.html b/platform/commonUI/general/res/templates/controls/datetime-field.html deleted file mode 100644 index 515c348b5e..0000000000 --- a/platform/commonUI/general/res/templates/controls/datetime-field.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - -
- - -
-
-
diff --git a/platform/commonUI/general/res/templates/controls/datetime-picker.html b/platform/commonUI/general/res/templates/controls/datetime-picker.html deleted file mode 100644 index 2e2cb69d36..0000000000 --- a/platform/commonUI/general/res/templates/controls/datetime-picker.html +++ /dev/null @@ -1,66 +0,0 @@ - - -
-
-
- - {{month}} {{year}} - -
-
- -
    -
  • -
    {{cell.day}}
    -
    {{cell.dayOfYear}}
    -
  • -
-
-
-
-
- - {{nameFor(key)}} - -
-
- -
- -
-
-
-
-
diff --git a/platform/commonUI/general/res/templates/controls/input-filter.html b/platform/commonUI/general/res/templates/controls/input-filter.html deleted file mode 100644 index 1c05a912e3..0000000000 --- a/platform/commonUI/general/res/templates/controls/input-filter.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - diff --git a/platform/commonUI/general/res/templates/controls/selector.html b/platform/commonUI/general/res/templates/controls/selector.html deleted file mode 100644 index adb6ee220e..0000000000 --- a/platform/commonUI/general/res/templates/controls/selector.html +++ /dev/null @@ -1,65 +0,0 @@ - -
-
-
Available
-
- - -
-
- -
-
Selected
-
-
    -
  • - - - - -
  • -
-
-
-
diff --git a/platform/commonUI/general/res/templates/controls/switcher.html b/platform/commonUI/general/res/templates/controls/switcher.html deleted file mode 100644 index d0872bc75b..0000000000 --- a/platform/commonUI/general/res/templates/controls/switcher.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - diff --git a/platform/commonUI/general/res/templates/controls/time-controller.html b/platform/commonUI/general/res/templates/controls/time-controller.html deleted file mode 100644 index eea0625a9f..0000000000 --- a/platform/commonUI/general/res/templates/controls/time-controller.html +++ /dev/null @@ -1,100 +0,0 @@ - -
-
- - - - - - - - to - - - - - - - -
- -
-
-
-
-
{{startInnerText}}
-
-
-
{{endInnerText}}
-
-
-
-
-
-
-
-
-
- -
-
-
- {{tick}} -
-
-
-
diff --git a/platform/commonUI/general/res/templates/label.html b/platform/commonUI/general/res/templates/label.html deleted file mode 100644 index 9dc2af8678..0000000000 --- a/platform/commonUI/general/res/templates/label.html +++ /dev/null @@ -1,31 +0,0 @@ - -
-
- -
-
{{model.name}}
-
diff --git a/platform/commonUI/general/res/templates/message-banner.html b/platform/commonUI/general/res/templates/message-banner.html deleted file mode 100644 index 861db30522..0000000000 --- a/platform/commonUI/general/res/templates/message-banner.html +++ /dev/null @@ -1,20 +0,0 @@ -
- - {{active.notification.model.title}} - - - - - - - -
diff --git a/platform/commonUI/general/res/templates/object-inspector.html b/platform/commonUI/general/res/templates/object-inspector.html deleted file mode 100644 index a735ade6a7..0000000000 --- a/platform/commonUI/general/res/templates/object-inspector.html +++ /dev/null @@ -1,49 +0,0 @@ - - -
- -
-
-
Inspection
- - -
-
- -
-
-

Elements

- - -
-
-
-
-
diff --git a/platform/commonUI/general/res/templates/progress-bar.html b/platform/commonUI/general/res/templates/progress-bar.html deleted file mode 100644 index 69883ed7ec..0000000000 --- a/platform/commonUI/general/res/templates/progress-bar.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - -
- {{ngModel.progressPerc}}% complete. - {{ngModel.progressText}} -
diff --git a/platform/commonUI/general/res/templates/subtree.html b/platform/commonUI/general/res/templates/subtree.html deleted file mode 100644 index 1dd428a822..0000000000 --- a/platform/commonUI/general/res/templates/subtree.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - diff --git a/platform/commonUI/general/res/templates/tree-node.html b/platform/commonUI/general/res/templates/tree-node.html deleted file mode 100644 index c8b0d28825..0000000000 --- a/platform/commonUI/general/res/templates/tree-node.html +++ /dev/null @@ -1,50 +0,0 @@ - - -
- -
- - -
-
-
diff --git a/platform/commonUI/general/res/templates/tree.html b/platform/commonUI/general/res/templates/tree.html deleted file mode 100644 index 18b81675b9..0000000000 --- a/platform/commonUI/general/res/templates/tree.html +++ /dev/null @@ -1,30 +0,0 @@ - -
    -
  • - - -
  • -
diff --git a/platform/commonUI/general/res/templates/tree/node.html b/platform/commonUI/general/res/templates/tree/node.html deleted file mode 100644 index 41f3a2b226..0000000000 --- a/platform/commonUI/general/res/templates/tree/node.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/platform/commonUI/general/res/templates/tree/toggle.html b/platform/commonUI/general/res/templates/tree/toggle.html deleted file mode 100644 index daa78ec9a0..0000000000 --- a/platform/commonUI/general/res/templates/tree/toggle.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/platform/commonUI/general/res/templates/tree/tree-label.html b/platform/commonUI/general/res/templates/tree/tree-label.html deleted file mode 100644 index da82af2337..0000000000 --- a/platform/commonUI/general/res/templates/tree/tree-label.html +++ /dev/null @@ -1,4 +0,0 @@ -
-
-
-
diff --git a/platform/commonUI/general/res/templates/tree/wait-node.html b/platform/commonUI/general/res/templates/tree/wait-node.html deleted file mode 100644 index 05ad199bca..0000000000 --- a/platform/commonUI/general/res/templates/tree/wait-node.html +++ /dev/null @@ -1,24 +0,0 @@ - -
  • - Loading... -
  • diff --git a/platform/commonUI/general/src/SplashScreenManager.js b/platform/commonUI/general/src/SplashScreenManager.js deleted file mode 100644 index bb15afb7ba..0000000000 --- a/platform/commonUI/general/src/SplashScreenManager.js +++ /dev/null @@ -1,44 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ( - -) { - - function SplashScreenManager($document) { - var splash; - $document = $document[0]; - splash = $document.querySelectorAll('.l-splash-holder')[0]; - if (!splash) { - return; - } - - splash.className += ' fadeout'; - splash.addEventListener('transitionend', function () { - splash.parentNode.removeChild(splash); - }); - } - - return SplashScreenManager; -}); diff --git a/platform/commonUI/general/src/StyleSheetLoader.js b/platform/commonUI/general/src/StyleSheetLoader.js deleted file mode 100644 index 10a85745ec..0000000000 --- a/platform/commonUI/general/src/StyleSheetLoader.js +++ /dev/null @@ -1,82 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 provides various general-purpose UI elements, including - * platform styling. - * @namespace platform/commonUI/general - */ -define( - [], - function () { - - /** - * The StyleSheetLoader adds links to style sheets exposed from - * various bundles as extensions of category `stylesheets`. - * @memberof platform/commonUI/general - * @constructor - * @param {object[]} stylesheets stylesheet extension definitions - * @param $document Angular's jqLite-wrapped document element - * @param {string} activeTheme the theme in use - * @param {string} [assetPath] the directory relative to which - * stylesheets will be found - */ - function StyleSheetLoader(stylesheets, $document, activeTheme, assetPath) { - var head = $document.find('head'), - document = $document[0]; - - // Procedure for adding a single stylesheet - function addStyleSheet(stylesheet) { - // Create a link element, and construct full path - var link = document.createElement('link'), - path = [ - assetPath, - stylesheet.bundle.path, - stylesheet.bundle.resources, - stylesheet.stylesheetUrl - ].join("/"); - - // Initialize attributes on the link - link.setAttribute("rel", "stylesheet"); - link.setAttribute("type", "text/css"); - link.setAttribute("href", path); - - // Append the link to the head element - head.append(link); - } - - // Stylesheets which specify themes should only be applied - // when that theme has been declared. - function matchesTheme(stylesheet) { - return stylesheet.theme === undefined - || stylesheet.theme === activeTheme; - } - - assetPath = assetPath || "."; - - // Add all stylesheets from extensions - stylesheets.filter(matchesTheme).forEach(addStyleSheet); - } - - return StyleSheetLoader; - } -); diff --git a/platform/commonUI/general/src/controllers/ActionGroupController.js b/platform/commonUI/general/src/controllers/ActionGroupController.js deleted file mode 100644 index ac55d8c2df..0000000000 --- a/platform/commonUI/general/src/controllers/ActionGroupController.js +++ /dev/null @@ -1,104 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ActionGroupController. Created by vwoeltje on 11/14/14. - */ -define( - [], - function () { - - /** - * Controller which keeps an up-to-date list of actions of - * a certain category, and additionally bins them into - * groups as described by their metadata. Used specifically - * to support button groups. - * - * This will maintain two fields in the scope: - * * `groups`: An array of arrays. Each element in the outer - * array corresponds to a group; the inner array contains - * the actions which are in that group. - * * `ungrouped`: All actions which did not have a defined - * group. - * - * @memberof platform/commonUI/general - * @constructor - */ - function ActionGroupController($scope) { - - // Separate out the actions that have been retrieved - // into groups, and populate scope with this. - function groupActions(actions) { - var groups = {}, - ungrouped = []; - - function assignToGroup(action) { - var metadata = action.getMetadata(), - group = metadata.group; - if (group) { - groups[group] = groups[group] || []; - groups[group].push(action); - } else { - ungrouped.push(action); - } - } - - (actions || []).forEach(assignToGroup); - - $scope.ungrouped = ungrouped; - $scope.groups = Object.keys(groups).sort().map(function (k) { - return groups[k]; - }); - } - - // Callback for when state which might influence action groupings - // changes. - function updateGroups() { - var actionCapability = $scope.action, - params = $scope.parameters || {}, - category = params.category; - - if (actionCapability && category) { - // Get actions by capability, and group them - groupActions(actionCapability.getActions({ - category: category - })); - } else { - // We don't have enough information to get any actions. - groupActions([]); - } - } - - // Changes to the represented object, to its action capability, or - // to the chosen action category may all require an update. - $scope.$watch("domainObject", updateGroups); - $scope.$watch("action", updateGroups); - $scope.$watch("parameters.category", updateGroups); - - // Start with empty arrays. - $scope.ungrouped = []; - $scope.groups = []; - } - - return ActionGroupController; - } -); diff --git a/platform/commonUI/general/src/controllers/BannerController.js b/platform/commonUI/general/src/controllers/BannerController.js deleted file mode 100644 index 6e28c9088d..0000000000 --- a/platform/commonUI/general/src/controllers/BannerController.js +++ /dev/null @@ -1,77 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 controller for banner notifications. Banner notifications are a - * non-blocking way of drawing the user's attention to an event such - * as system errors, or the progress or successful completion of an - * ongoing task. This controller provides scoped functions for - * dismissing and 'maximizing' notifications. See {@link NotificationService} - * for more details on Notifications. - * - * @param $scope - * @param notificationService - * @param dialogService - * @constructor - */ - function BannerController($scope, notificationService, dialogService) { - $scope.active = notificationService.active; - - $scope.action = function (action, $event) { - /* - Prevents default 'maximize' behaviour when clicking on - notification button - */ - $event.stopPropagation(); - - return action(); - }; - - $scope.dismiss = function (notification, $event) { - $event.stopPropagation(); - notification.dismiss(); - }; - - $scope.maximize = function (notification) { - if (notification.model.severity !== "info") { - var dialog; - notification.model.cancel = function () { - dialog.dismiss(); - }; - - //If the notification is dismissed by the user, close - // the dialog. - notification.on('dismiss', function () { - dialog.dismiss(); - }); - - dialog = dialogService.showBlockingMessage(notification.model); - } - }; - } - - return BannerController; - }); diff --git a/platform/commonUI/general/src/controllers/ClickAwayController.js b/platform/commonUI/general/src/controllers/ClickAwayController.js deleted file mode 100644 index e47b33a58a..0000000000 --- a/platform/commonUI/general/src/controllers/ClickAwayController.js +++ /dev/null @@ -1,97 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ClickAwayController is used to toggle things (such as context - * menus) where clicking elsewhere in the document while the toggle - * is in an active state is intended to dismiss the toggle. - * - * @memberof platform/commonUI/general - * @constructor - * @param $scope the scope in which this controller is active - * @param $document the document element, injected by Angular - */ - function ClickAwayController($document, $timeout) { - var self = this; - - this.state = false; - this.$document = $document; - - // Callback used by the document listener. Timeout ensures that - // `clickaway` action occurs after `toggle` if `toggle` is - // triggered by a click/mouseup. - this.clickaway = function () { - $timeout(function () { - self.deactivate(); - }); - }; - } - - // Track state, but also attach and detach a listener for - // mouseup events on the document. - ClickAwayController.prototype.deactivate = function () { - this.state = false; - this.$document.off("mouseup", this.clickaway); - }; - - ClickAwayController.prototype.activate = function () { - this.state = true; - this.$document.on("mouseup", this.clickaway); - }; - - /** - * Get the current state of the toggle. - * @return {boolean} true if active - */ - ClickAwayController.prototype.isActive = function () { - return this.state; - }; - - /** - * Set a new state for the toggle. - * @return {boolean} true to activate - */ - ClickAwayController.prototype.setState = function (newState) { - if (this.state !== newState) { - this.toggle(); - } - }; - - /** - * Toggle the current state; activate if it is inactive, - * deactivate if it is active. - */ - ClickAwayController.prototype.toggle = function () { - if (this.state) { - this.deactivate(); - } else { - this.activate(); - } - }; - - return ClickAwayController; - } -); diff --git a/platform/commonUI/general/src/controllers/DateTimeFieldController.js b/platform/commonUI/general/src/controllers/DateTimeFieldController.js deleted file mode 100644 index ea6b59e993..0000000000 --- a/platform/commonUI/general/src/controllers/DateTimeFieldController.js +++ /dev/null @@ -1,112 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Controller to support the date-time entry field. - * - * Accepts a `format` property in the `structure` attribute - * which allows a date/time to be specified via its symbolic - * key (as will be used to look up said format from the - * `formatService`.) - * - * {@see FormatService} - * @constructor - * @memberof platform/commonUI/general - * @param $scope the Angular scope for this controller - * @param {FormatService} formatService the service to user to format - * domain values - * @param {string} defaultFormat the format to request when no - * format has been otherwise specified - */ - function DateTimeFieldController($scope, formatService, defaultFormat) { - var formatter = formatService.getFormat(defaultFormat); - - function updateFromModel(value) { - // Only reformat if the value is different from user - // input (to avoid reformatting valid input while typing.) - if (!formatter.validate($scope.textValue) - || formatter.parse($scope.textValue) !== value) { - $scope.textValue = formatter.format(value); - $scope.textInvalid = false; - $scope.lastValidValue = $scope.textValue; - } - - $scope.pickerModel = { value: value }; - } - - function updateFromView(textValue) { - $scope.textInvalid = !formatter.validate(textValue); - if (!$scope.textInvalid) { - $scope.ngModel[$scope.field] = - formatter.parse(textValue); - $scope.lastValidValue = $scope.textValue; - } - } - - function updateFromPicker(value) { - if (value !== $scope.ngModel[$scope.field]) { - $scope.ngModel[$scope.field] = value; - updateFromModel(value); - if ($scope.ngBlur) { - $scope.ngBlur(); - } - - // If picker is active, dismiss it when valid value has been selected - // This 'if' is to avoid unnecessary validation if picker is not active - if ($scope.picker.active) { - if ($scope.structure.validate && $scope.structure.validate($scope.ngModel[$scope.field])) { - $scope.picker.active = false; - } else if (!$scope.structure.validate) { - //If picker visible, but no validation function, hide picker - $scope.picker.active = false; - } - } - } - } - - function setFormat(format) { - formatter = formatService.getFormat(format || defaultFormat); - updateFromModel($scope.ngModel[$scope.field]); - } - - function restoreTextValue() { - $scope.textValue = $scope.lastValidValue; - updateFromView($scope.textValue); - } - - $scope.restoreTextValue = restoreTextValue; - - $scope.picker = { active: false }; - - $scope.$watch('structure.format', setFormat); - $scope.$watch('ngModel[field]', updateFromModel); - $scope.$watch('pickerModel.value', updateFromPicker); - $scope.$watch('textValue', updateFromView); - } - - return DateTimeFieldController; - } -); diff --git a/platform/commonUI/general/src/controllers/DateTimePickerController.js b/platform/commonUI/general/src/controllers/DateTimePickerController.js deleted file mode 100644 index 55b14227a1..0000000000 --- a/platform/commonUI/general/src/controllers/DateTimePickerController.js +++ /dev/null @@ -1,207 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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) { - - var TIME_NAMES = { - 'hours': "Hour", - 'minutes': "Minute", - 'seconds': "Second" - }, - MONTHS = moment.months(), - TIME_OPTIONS = (function makeRanges() { - var arr = []; - while (arr.length < 60) { - arr.push(arr.length); - } - - return { - hours: arr.slice(0, 24), - minutes: arr, - seconds: arr - }; - }()); - - /** - * Controller to support the date-time picker. - * - * Adds/uses the following properties in scope: - * * `year`: Year being displayed in picker - * * `month`: Month being displayed - * * `table`: Table being displayed; array of arrays of - * * `day`: Day of month - * * `dayOfYear`: Day of year - * * `month`: Month associated with the day - * * `year`: Year associated with the day. - * * `date`: Date chosen - * * `year`: Year selected - * * `month`: Month selected (0-indexed) - * * `day`: Day of month selected - * * `time`: Chosen time (hours/minutes/seconds) - * * `hours`: Hours chosen - * * `minutes`: Minutes chosen - * * `seconds`: Seconds chosen - * - * Months are zero-indexed, day-of-months are one-indexed. - */ - function DateTimePickerController($scope, now) { - var year, - month, // For picker state, not model state - interacted = false; - - function generateTable() { - var m = moment.utc({ - year: year, - month: month - }).day(0), - table = [], - row, - col; - - for (row = 0; row < 6; row += 1) { - table.push([]); - for (col = 0; col < 7; col += 1) { - table[row].push({ - year: m.year(), - month: m.month(), - day: m.date(), - dayOfYear: m.dayOfYear() - }); - m.add(1, 'days'); // Next day! - } - } - - return table; - } - - function updateScopeForMonth() { - $scope.month = MONTHS[month]; - $scope.year = year; - $scope.table = generateTable(); - } - - function updateFromModel(ngModel) { - var m; - - m = moment.utc(ngModel); - - $scope.date = { - year: m.year(), - month: m.month(), - day: m.date() - }; - $scope.time = { - hours: m.hour(), - minutes: m.minute(), - seconds: m.second() - }; - - //window.alert($scope.date.day + " " + ngModel); - - // Zoom to that date in the picker, but - // only if the user hasn't interacted with it yet. - if (!interacted) { - year = m.year(); - month = m.month(); - updateScopeForMonth(); - } - } - - function updateFromView() { - var m = moment.utc({ - year: $scope.date.year, - month: $scope.date.month, - day: $scope.date.day, - hour: $scope.time.hours, - minute: $scope.time.minutes, - second: $scope.time.seconds - }); - $scope.ngModel[$scope.field] = m.valueOf(); - } - - $scope.isInCurrentMonth = function (cell) { - return cell.month === month; - }; - - $scope.isSelected = function (cell) { - var date = $scope.date || {}; - - return cell.day === date.day - && cell.month === date.month - && cell.year === date.year; - }; - - $scope.select = function (cell) { - $scope.date = $scope.date || {}; - $scope.date.month = cell.month; - $scope.date.year = cell.year; - $scope.date.day = cell.day; - updateFromView(); - }; - - $scope.dateEquals = function (d1, d2) { - return d1.year === d2.year - && d1.month === d2.month - && d1.day === d2.day; - }; - - $scope.changeMonth = function (delta) { - month += delta; - if (month > 11) { - month = 0; - year += 1; - } - - if (month < 0) { - month = 11; - year -= 1; - } - - interacted = true; - updateScopeForMonth(); - }; - - $scope.nameFor = function (key) { - return TIME_NAMES[key]; - }; - - $scope.optionsFor = function (key) { - return TIME_OPTIONS[key]; - }; - - updateScopeForMonth(); - - // Ensure some useful default - $scope.ngModel[$scope.field] = - $scope.ngModel[$scope.field] === undefined - ? now() : $scope.ngModel[$scope.field]; - - $scope.$watch('ngModel[field]', updateFromModel); - $scope.$watchCollection('date', updateFromView); - $scope.$watchCollection('time', updateFromView); - } - - return DateTimePickerController; - } -); diff --git a/platform/commonUI/general/src/controllers/GetterSetterController.js b/platform/commonUI/general/src/controllers/GetterSetterController.js deleted file mode 100644 index c8741ed51e..0000000000 --- a/platform/commonUI/general/src/controllers/GetterSetterController.js +++ /dev/null @@ -1,89 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * This controller acts as an adapter to permit getter-setter - * functions to be used as ng-model arguments to controls, - * such as the input-filter. This is supported natively in - * Angular 1.3+ via `ng-model-options`, so this controller - * should be made obsolete after any upgrade to Angular 1.3. - * - * It expects to find in scope a value `ngModel` which is a - * function which, when called with no arguments, acts as a - * getter, and when called with one argument, acts as a setter. - * - * It also publishes into the scope a value `getterSetter.value` - * which is meant to be used as an assignable expression. - * - * This controller watches both of these; when one changes, - * it will update the other's value to match. Because of this, - * the `ngModel` function should be both stable and computationally - * inexpensive, as it will be invoked often. - * - * Getter-setter style models can be preferable when there - * is significant indirection between templates; "dotless" - * expressions in `ng-model` can behave unexpectedly due to the - * rules of scope, but dots are lost when passed in via `ng-model` - * (so if a control is internally implemented using regular - * form elements, it can't transparently pass through the `ng-model` - * parameter it received.) Getter-setter functions are never the - * target of a scope assignment and so avoid this problem. - * - * @memberof platform/commonUI/general - * @constructor - * @param {Scope} $scope the controller's scope - */ - function GetterSetterController($scope) { - - // Update internal assignable state based on changes - // to the getter-setter function. - function updateGetterSetter() { - if (typeof $scope.ngModel === 'function') { - $scope.getterSetter.value = $scope.ngModel(); - } - } - - // Update the external getter-setter based on changes - // to the assignable state. - function updateNgModel() { - if (typeof $scope.ngModel === 'function') { - $scope.ngModel($scope.getterSetter.value); - } - } - - // Watch for changes to both expressions - $scope.$watch("ngModel()", updateGetterSetter); - $scope.$watch("getterSetter.value", updateNgModel); - - // Publish an assignable field into scope. - $scope.getterSetter = {}; - - } - - return GetterSetterController; - - } -); diff --git a/platform/commonUI/general/src/controllers/ObjectInspectorController.js b/platform/commonUI/general/src/controllers/ObjectInspectorController.js deleted file mode 100644 index a36e0e0a16..0000000000 --- a/platform/commonUI/general/src/controllers/ObjectInspectorController.js +++ /dev/null @@ -1,119 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ObjectInspectorController. Created by shale on 08/21/2015. - */ -define( - [], - function () { - - /** - * The ObjectInspectorController gets and formats the data for - * the inspector display - * - * @constructor - */ - function ObjectInspectorController($scope, objectService) { - $scope.primaryParents = []; - $scope.contextutalParents = []; - //$scope.isLink = false; - - // Gets an array of the contextual parents/ancestors of the selected object - function getContextualPath() { - var currentObj = $scope.domainObject, - currentParent, - parents = []; - - currentParent = currentObj - && currentObj.hasCapability('context') - && currentObj.getCapability('context').getParent(); - - while (currentParent && currentParent.getModel().type !== 'root' - && currentParent.hasCapability('context')) { - // Record this object - parents.unshift(currentParent); - - // Get the next one up the tree - currentObj = currentParent; - currentParent = currentObj.getCapability('context').getParent(); - } - - $scope.contextutalParents = parents; - } - - // Gets an array of the parents/ancestors of the selected object's - // primary location (locational of original non-link) - function getPrimaryPath(current) { - var location; - - // If this the the initial call of this recursive function - if (!current) { - current = $scope.domainObject; - $scope.primaryParents = []; - } - - location = current.getModel().location; - - if (location && location !== 'root') { - objectService.getObjects([location]).then(function (obj) { - var next = obj[location]; - - $scope.primaryParents.unshift(next); - getPrimaryPath(next); - }); - } - - } - - // Gets the metadata for the selected object - function getMetadata() { - $scope.metadata = $scope.domainObject - && $scope.domainObject.hasCapability('metadata') - && $scope.domainObject.useCapability('metadata'); - } - - // Set scope variables when the selected object changes - $scope.$watch('domainObject', function () { - $scope.isLink = $scope.domainObject - && $scope.domainObject.hasCapability('location') - && $scope.domainObject.getCapability('location').isLink(); - - if ($scope.isLink) { - getPrimaryPath(); - getContextualPath(); - } else { - $scope.primaryParents = []; - getContextualPath(); - } - - getMetadata(); - }); - - var mutation = $scope.domainObject.getCapability('mutation'); - var unlisten = mutation.listen(getMetadata); - $scope.$on('$destroy', unlisten); - } - - return ObjectInspectorController; - } -); diff --git a/platform/commonUI/general/src/controllers/SelectorController.js b/platform/commonUI/general/src/controllers/SelectorController.js deleted file mode 100644 index e7155961c9..0000000000 --- a/platform/commonUI/general/src/controllers/SelectorController.js +++ /dev/null @@ -1,164 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - var ROOT_ID = "ROOT"; - - /** - * Controller for the domain object selector control. - * @memberof platform/commonUI/general - * @constructor - * @param {ObjectService} objectService service from which to - * read domain objects - * @param $scope Angular scope for this controller - */ - function SelectorController(objectService, $scope) { - var treeModel = {}, - listModel = {}, - previousSelected, - self = this; - - // For watch; look at the user's selection in the tree - function getTreeSelection() { - return treeModel.selectedObject; - } - - // Store root object for subsequent exposure to template - function storeRoot(objects) { - self.rootObject = objects[ROOT_ID]; - } - - // Check that a selection is of the valid type - function validateTreeSelection(selectedObject) { - var type = selectedObject - && selectedObject.getCapability('type'); - - // Delegate type-checking to the capability... - if (!type || !type.instanceOf($scope.structure.type)) { - treeModel.selectedObject = previousSelected; - } - - // Track current selection to restore it if an invalid - // selection is made later. - previousSelected = treeModel.selectedObject; - } - - // Update the right-hand list of currently-selected objects - function updateList(ids) { - function updateSelectedObjects(objects) { - // Look up from the - function getObject(id) { - return objects[id]; - } - - self.selectedObjects = - ids.filter(getObject).map(getObject); - } - - // Look up objects by id, then populate right-hand list - objectService.getObjects(ids).then(updateSelectedObjects); - } - - // Reject attempts to select objects of the wrong type - $scope.$watch(getTreeSelection, validateTreeSelection); - - // Make sure right-hand list matches underlying model - $scope.$watchCollection(function () { - return self.getField(); - }, updateList); - - // Look up root object, then store it - objectService.getObjects([ROOT_ID]).then(storeRoot); - - this.$scope = $scope; - this.selectedObjects = []; - - // Expose tree/list model for use in template directly - this.treeModel = treeModel; - this.listModel = listModel; - } - - // Set the value of the field being edited - SelectorController.prototype.setField = function (value) { - this.$scope.ngModel[this.$scope.field] = value; - }; - - // Get the value of the field being edited - SelectorController.prototype.getField = function () { - return this.$scope.ngModel[this.$scope.field] || []; - }; - - /** - * Get the root object to show in the left-hand tree. - * @returns {DomainObject} the root object - */ - SelectorController.prototype.root = function () { - return this.rootObject; - }; - - /** - * Add a domain object to the list of selected objects. - * @param {DomainObject} the domain object to select - */ - SelectorController.prototype.select = function (domainObject) { - var id = domainObject && domainObject.getId(), - list = this.getField() || []; - // Only select if we have a valid id, - // and it isn't already selected - if (id && list.indexOf(id) === -1) { - this.setField(list.concat([id])); - } - }; - - /** - * Remove a domain object from the list of selected objects. - * @param {DomainObject} the domain object to select - */ - SelectorController.prototype.deselect = function (domainObject) { - var id = domainObject && domainObject.getId(), - list = this.getField() || []; - // Only change if this was a valid id, - // for an object which was already selected - if (id && list.indexOf(id) !== -1) { - // Filter it out of the current field - this.setField(list.filter(function (otherId) { - return otherId !== id; - })); - // Clear the current list selection - delete this.listModel.selectedObject; - } - }; - - /** - * Get the currently-selected domain objects. - * @returns {DomainObject[]} the current selection - */ - SelectorController.prototype.selected = function () { - return this.selectedObjects; - }; - - return SelectorController; - } -); diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js deleted file mode 100644 index 218180c0d7..0000000000 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ /dev/null @@ -1,313 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - var TICK_SPACING_PX = 150; - - /* format number as percent; 0.0-1.0 to "0%"-"100%" */ - function toPercent(p) { - return (100 * p) + "%"; - } - - function clamp(value, low, high) { - return Math.max(low, Math.min(high, value)); - } - - function copyBounds(bounds) { - return { - start: bounds.start, - end: bounds.end - }; - } - - /** - * Controller used by the `time-controller` template. - * @memberof platform/commonUI/general - * @constructor - * @param $scope the Angular scope for this controller - * @param {FormatService} formatService the service to user to format - * domain values - * @param {string} defaultFormat the format to request when no - * format has been otherwise specified - * @param {Function} now a function to return current system time - */ - function TimeRangeController($scope, $timeout, formatService, defaultFormat, now) { - this.$scope = $scope; - this.formatService = formatService; - this.defaultFormat = defaultFormat; - this.now = now; - - this.tickCount = 2; - this.innerMinimumSpan = 1000; // 1 second - this.outerMinimumSpan = 1000; // 1 second - this.initialDragValue = undefined; - this.formatter = formatService.getFormat(defaultFormat); - this.formStartChanged = false; - this.formEndChanged = false; - this.$timeout = $timeout; - - this.$scope.ticks = []; - - this.updateViewFromModel(this.$scope.ngModel); - this.updateFormModel(); - - [ - 'updateViewFromModel', - 'updateSpanWidth', - 'updateOuterStart', - 'updateOuterEnd', - 'updateFormat', - 'validateStart', - 'validateEnd', - 'onFormStartChange', - 'onFormEndChange' - ].forEach(function (boundFn) { - this[boundFn] = this[boundFn].bind(this); - }, this); - - this.$scope.$watchCollection("ngModel", this.updateViewFromModel); - this.$scope.$watch("spanWidth", this.updateSpanWidth); - this.$scope.$watch("ngModel.outer.start", this.updateOuterStart); - this.$scope.$watch("ngModel.outer.end", this.updateOuterEnd); - this.$scope.$watch("parameters.format", this.updateFormat); - this.$scope.$watch("formModel.start", this.onFormStartChange); - this.$scope.$watch("formModel.end", this.onFormEndChange); - } - - TimeRangeController.prototype.formatTimestamp = function (ts) { - return this.formatter.format(ts); - }; - - TimeRangeController.prototype.updateTicks = function () { - var i, p, ts, start, end, span; - end = this.$scope.ngModel.outer.end; - start = this.$scope.ngModel.outer.start; - span = end - start; - this.$scope.ticks = []; - for (i = 0; i < this.tickCount; i += 1) { - p = i / (this.tickCount - 1); - ts = p * span + start; - this.$scope.ticks.push(this.formatTimestamp(ts)); - } - }; - - TimeRangeController.prototype.updateSpanWidth = function (w) { - this.tickCount = Math.max(Math.floor(w / TICK_SPACING_PX), 2); - this.updateTicks(); - }; - - TimeRangeController.prototype.updateViewForInnerSpanFromModel = function ( - ngModel - ) { - var span = ngModel.outer.end - ngModel.outer.start; - - // Expose readable dates for the knobs - this.$scope.startInnerText = this.formatTimestamp(ngModel.inner.start); - this.$scope.endInnerText = this.formatTimestamp(ngModel.inner.end); - - // And positions for the knobs - this.$scope.startInnerPct = - toPercent((ngModel.inner.start - ngModel.outer.start) / span); - this.$scope.endInnerPct = - toPercent((ngModel.outer.end - ngModel.inner.end) / span); - }; - - TimeRangeController.prototype.defaultBounds = function () { - var t = this.now(); - - return { - start: t - 24 * 3600 * 1000, // One day - end: t - }; - }; - - TimeRangeController.prototype.updateViewFromModel = function (ngModel) { - ngModel = ngModel || {}; - ngModel.outer = ngModel.outer || this.defaultBounds(); - ngModel.inner = ngModel.inner || copyBounds(ngModel.outer); - - // Stick it back is scope (in case we just set defaults) - this.$scope.ngModel = ngModel; - - this.updateViewForInnerSpanFromModel(ngModel); - this.updateTicks(); - }; - - TimeRangeController.prototype.startLeftDrag = function () { - this.initialDragValue = this.$scope.ngModel.inner.start; - }; - - TimeRangeController.prototype.startRightDrag = function () { - this.initialDragValue = this.$scope.ngModel.inner.end; - }; - - TimeRangeController.prototype.startMiddleDrag = function () { - this.initialDragValue = { - start: this.$scope.ngModel.inner.start, - end: this.$scope.ngModel.inner.end - }; - }; - - TimeRangeController.prototype.toMillis = function (pixels) { - var span = - this.$scope.ngModel.outer.end - this.$scope.ngModel.outer.start; - - return (pixels / this.$scope.spanWidth) * span; - }; - - TimeRangeController.prototype.leftDrag = function (pixels) { - var delta = this.toMillis(pixels); - this.$scope.ngModel.inner.start = clamp( - this.initialDragValue + delta, - this.$scope.ngModel.outer.start, - this.$scope.ngModel.inner.end - this.innerMinimumSpan - ); - this.updateViewFromModel(this.$scope.ngModel); - }; - - TimeRangeController.prototype.rightDrag = function (pixels) { - var delta = this.toMillis(pixels); - this.$scope.ngModel.inner.end = clamp( - this.initialDragValue + delta, - this.$scope.ngModel.inner.start + this.innerMinimumSpan, - this.$scope.ngModel.outer.end - ); - this.updateViewFromModel(this.$scope.ngModel); - }; - - TimeRangeController.prototype.middleDrag = function (pixels) { - var delta = this.toMillis(pixels), - edge = delta < 0 ? 'start' : 'end', - opposite = delta < 0 ? 'end' : 'start'; - - // Adjust the position of the edge in the direction of drag - this.$scope.ngModel.inner[edge] = clamp( - this.initialDragValue[edge] + delta, - this.$scope.ngModel.outer.start, - this.$scope.ngModel.outer.end - ); - // Adjust opposite knob to maintain span - this.$scope.ngModel.inner[opposite] = - this.$scope.ngModel.inner[edge] - + this.initialDragValue[opposite] - - this.initialDragValue[edge]; - - this.updateViewFromModel(this.$scope.ngModel); - }; - - TimeRangeController.prototype.updateFormModel = function () { - this.$scope.formModel = { - start: ((this.$scope.ngModel || {}).outer || {}).start, - end: ((this.$scope.ngModel || {}).outer || {}).end - }; - }; - - TimeRangeController.prototype.updateOuterStart = function () { - var ngModel = this.$scope.ngModel; - - ngModel.inner.start = - Math.max(ngModel.outer.start, ngModel.inner.start); - ngModel.inner.end = Math.max( - ngModel.inner.start + this.innerMinimumSpan, - ngModel.inner.end - ); - - this.updateFormModel(); - this.updateViewForInnerSpanFromModel(ngModel); - this.updateTicks(); - }; - - TimeRangeController.prototype.updateOuterEnd = function () { - var ngModel = this.$scope.ngModel; - - ngModel.inner.end = - Math.min(ngModel.outer.end, ngModel.inner.end); - ngModel.inner.start = Math.min( - ngModel.inner.end - this.innerMinimumSpan, - ngModel.inner.start - ); - - this.updateFormModel(); - this.updateViewForInnerSpanFromModel(ngModel); - this.updateTicks(); - }; - - TimeRangeController.prototype.updateFormat = function (key) { - this.formatter = this.formatService.getFormat(key || this.defaultFormat); - this.updateViewForInnerSpanFromModel(this.$scope.ngModel); - this.updateTicks(); - }; - - TimeRangeController.prototype.updateBoundsFromForm = function () { - var self = this; - - //Allow Angular to trigger watches and determine whether values have changed. - this.$timeout(function () { - if (self.formStartChanged) { - self.$scope.ngModel.outer.start = - self.$scope.ngModel.inner.start = - self.$scope.formModel.start; - self.formStartChanged = false; - } - - if (self.formEndChanged) { - self.$scope.ngModel.outer.end = - self.$scope.ngModel.inner.end = - self.$scope.formModel.end; - self.formEndChanged = false; - } - }); - }; - - TimeRangeController.prototype.onFormStartChange = function ( - newValue, - oldValue - ) { - if (!this.formStartChanged && newValue !== oldValue) { - this.formStartChanged = true; - } - }; - - TimeRangeController.prototype.onFormEndChange = function ( - newValue, - oldValue - ) { - if (!this.formEndChanged && newValue !== oldValue) { - this.formEndChanged = true; - } - }; - - TimeRangeController.prototype.validateStart = function (startValue) { - return startValue - <= this.$scope.formModel.end - this.outerMinimumSpan; - }; - - TimeRangeController.prototype.validateEnd = function (endValue) { - return endValue - >= this.$scope.formModel.start + this.outerMinimumSpan; - }; - - return TimeRangeController; -}); diff --git a/platform/commonUI/general/src/controllers/ToggleController.js b/platform/commonUI/general/src/controllers/ToggleController.js deleted file mode 100644 index 2a8cc6e1f6..0000000000 --- a/platform/commonUI/general/src/controllers/ToggleController.js +++ /dev/null @@ -1,66 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ToggleController is used to activate/deactivate things. - * A common usage is for "twistie" - * - * @memberof platform/commonUI/general - * @constructor - */ - function ToggleController() { - this.state = false; - - this.setState = this.setState.bind(this); - } - - /** - * Get the current state of the toggle. - * @return {boolean} true if active - */ - ToggleController.prototype.isActive = function () { - return this.state; - }; - - /** - * Set a new state for the toggle. - * @return {boolean} true to activate - */ - ToggleController.prototype.setState = function (newState) { - this.state = newState; - }; - - /** - * Toggle the current state; activate if it is inactive, - * deactivate if it is active. - */ - ToggleController.prototype.toggle = function () { - this.state = !this.state; - }; - - return ToggleController; - } -); diff --git a/platform/commonUI/general/src/controllers/TreeNodeController.js b/platform/commonUI/general/src/controllers/TreeNodeController.js deleted file mode 100644 index 8a2a9ecb14..0000000000 --- a/platform/commonUI/general/src/controllers/TreeNodeController.js +++ /dev/null @@ -1,204 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 TreeNodeController. Created by vwoeltje on 11/10/14. - */ -define( - [], - function () { - - /** - * The TreeNodeController supports the tree node representation; - * a tree node has a label for the current object as well as a - * subtree which shows (and is not loaded until) the node is - * expanded. - * - * This controller tracks the following, so that the tree node - * template may update its state accordingly: - * - * * Whether or not the tree node has ever been expanded (this - * is used to lazily load, exactly once, the subtree) - * * Whether or not the node is currently the domain object - * of navigation (this gets highlighted differently to - * provide the user with visual feedback.) - * - * Additionally, this controller will automatically trigger - * node expansion when this tree node's _subtree_ will contain - * the navigated object (recursively, this becomes an - * expand-to-show-navigated-object behavior.) - * - * Finally, if a `callback` property is passed in through the - * `parameters` attribute of the `tree-node`, that callback - * will be invoked whenever a user clicks in a manner which - * would result in a selection. This callback is invoked - * even if the selection does not change (if you are only - * interested in changes, watch the `selectedObject` property - * of the object passed in `ng-model` instead.) - * - * @memberof platform/commonUI/general - * @constructor - */ - function TreeNodeController($scope, $timeout) { - var self = this, - selectedObject = ($scope.ngModel || {}).selectedObject; - - // Look up the id for a domain object. A convenience - // for mapping; additionally does some undefined-checking. - function getId(obj) { - return obj && obj.getId && obj.getId(); - } - - // Verify that id paths are equivalent, staring at - // index, ending at the end of the node path. - function checkPath(nodePath, navPath, index) { - index = index || 0; - - // The paths overlap if we have made it past the - // end of the node's path; otherwise, check the - // id at the current index for equality and perform - // a recursive step for subsequent ids in the paths, - // until we exceed path length or hit a mismatch. - return (index >= nodePath.length) - || ((navPath[index] === nodePath[index]) - && checkPath(nodePath, navPath, index + 1)); - } - - // Consider the currently-navigated object and update - // parameters which support display. - function checkSelection() { - var nodeObject = $scope.domainObject, - navObject = selectedObject, - nodeContext = nodeObject - && nodeObject.getCapability('context'), - navContext = navObject - && navObject.getCapability('context'), - nodePath, - navPath; - - // Deselect; we will reselect below, iff we are - // exactly at the end of the path. - self.isSelectedFlag = false; - - // Expand if necessary (if the navigated object will - // be in this node's subtree) - if (nodeContext && navContext) { - // Get the paths as arrays of identifiers - nodePath = nodeContext.getPath().map(getId); - navPath = navContext.getPath().map(getId); - - // Check to see if the node's path lies entirely - // within the navigation path; otherwise, navigation - // has happened in some other subtree. - if (navPath.length >= nodePath.length - && checkPath(nodePath, navPath)) { - - // nodePath is along the navPath; if it's - // at the end of the path, highlight; - // otherwise, expand. - if (nodePath.length === navPath.length) { - self.isSelectedFlag = true; - } else { // node path is shorter: Expand! - if ($scope.toggle) { - $scope.toggle.setState(true); - } - - self.trackExpansion(); - } - - } - } - } - - // Callback for the selection updates; track the currently - // navigated object and update display parameters as needed. - function setSelection(object) { - selectedObject = object; - checkSelection(); - } - - this.isSelectedFlag = false; - this.hasBeenExpandedFlag = false; - this.$timeout = $timeout; - this.$scope = $scope; - - // Listen for changes which will effect display parameters - $scope.$watch("ngModel.selectedObject", setSelection); - $scope.$watch("domainObject", checkSelection); - } - - /** - * Select the domain object represented by this node in the tree. - * This will both update the `selectedObject` property in - * the object passed in via `ng-model`, and will fire any `callback` - * passed in via `parameters`. - */ - TreeNodeController.prototype.select = function () { - if (this.$scope.ngModel) { - this.$scope.ngModel.selectedObject = - this.$scope.domainObject; - } - - if ((this.$scope.parameters || {}).callback) { - this.$scope.parameters.callback(this.$scope.domainObject); - } - }; - - /** - * This method should be called when a node is expanded - * to record that this has occurred, to support one-time - * lazy loading of the node's subtree. - */ - TreeNodeController.prototype.trackExpansion = function () { - var self = this; - if (!self.hasBeenExpanded()) { - // Run on a timeout; if a lot of expansion needs to - // occur (e.g. if the selection is several nodes deep) we - // want this to be spread across multiple digest cycles. - self.$timeout(function () { - self.hasBeenExpandedFlag = true; - }, 0); - } - }; - - /** - * Check if this not has ever been expanded. - * @returns true if it has been expanded - */ - TreeNodeController.prototype.hasBeenExpanded = function () { - return this.hasBeenExpandedFlag; - }; - - /** - * Check whether or not the domain object represented by - * this tree node should be highlighted. - * An object will be highlighted if it matches - * ngModel.selectedObject - * @returns true if this should be highlighted - */ - TreeNodeController.prototype.isSelected = function () { - return this.isSelectedFlag; - }; - - return TreeNodeController; - } -); diff --git a/platform/commonUI/general/src/controllers/ViewSwitcherController.js b/platform/commonUI/general/src/controllers/ViewSwitcherController.js deleted file mode 100644 index 49033569b5..0000000000 --- a/platform/commonUI/general/src/controllers/ViewSwitcherController.js +++ /dev/null @@ -1,73 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ViewSwitcherController. Created by vwoeltje on 11/7/14. - */ -define( - [], - function () { - - /** - * Controller for the view switcher; populates and maintains a list - * of applicable views for a represented domain object. - * @memberof platform/commonUI/general - * @constructor - */ - function ViewSwitcherController($scope, $timeout) { - // If the view capability gets refreshed, try to - // keep the same option chosen. - function findMatchingOption(options, selected) { - var i; - - if (selected) { - for (i = 0; i < options.length; i += 1) { - if (options[i].key === selected.key) { - return options[i]; - } - } - } - - return options[0]; - } - - // Get list of views, read from capability - function updateOptions(views) { - if (Array.isArray(views)) { - $timeout(function () { - $scope.ngModel.selected = findMatchingOption( - views, - ($scope.ngModel || {}).selected - ); - }, 0); - } - } - - // Update view options when the in-scope results of using the - // view capability change. - $scope.$watch("view", updateOptions); - } - - return ViewSwitcherController; - } -); - diff --git a/platform/commonUI/general/src/directives/MCTClickElsewhere.js b/platform/commonUI/general/src/directives/MCTClickElsewhere.js deleted file mode 100644 index a2193ab18f..0000000000 --- a/platform/commonUI/general/src/directives/MCTClickElsewhere.js +++ /dev/null @@ -1,77 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The `mct-click-elsewhere` directive will evaluate its - * associated expression whenever a `mousedown` occurs anywhere - * outside of the element that has the `mct-click-elsewhere` - * directive attached. This is useful for dismissing popups - * and the like. - */ - function MCTClickElsewhere($document) { - - // Link; install event handlers. - function link(scope, element, attrs) { - // Keep a reference to the body, to attach/detach - // mouse event handlers; mousedown and mouseup cannot - // only be attached to the element being linked, as the - // mouse may leave this element during the drag. - var body = $document.find('body'); - - function clickBody(event) { - var x = event.clientX, - y = event.clientY, - rect = element[0].getBoundingClientRect(), - xMin = rect.left, - xMax = xMin + rect.width, - yMin = rect.top, - yMax = yMin + rect.height; - - if (x < xMin || x > xMax || y < yMin || y > yMax) { - scope.$apply(function () { - scope.$eval(attrs.mctClickElsewhere); - }); - } - } - - body.on("mousedown", clickBody); - scope.$on("$destroy", function () { - body.off("mousedown", clickBody); - }); - } - - return { - // mct-drag only makes sense as an attribute - restrict: "A", - // Link function, to install event handlers - link: link - }; - } - - return MCTClickElsewhere; - } -); - diff --git a/platform/commonUI/general/src/directives/MCTContainer.js b/platform/commonUI/general/src/directives/MCTContainer.js deleted file mode 100644 index b85d20dd15..0000000000 --- a/platform/commonUI/general/src/directives/MCTContainer.js +++ /dev/null @@ -1,91 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 MCTContainer. Created by vwoeltje on 11/17/14. - */ -define( - [], - function () { - - /** - * The mct-container is similar to the mct-include directive - * insofar as it allows templates to be referenced by - * symbolic keys instead of by URL. Unlike mct-include, it - * supports transclusion. - * - * Unlike mct-include, mct-container accepts a key as a - * plain string attribute, instead of as an Angular - * expression. - * - * @memberof platform/commonUI/general - * @constructor - */ - function MCTContainer(containers) { - var containerMap = {}; - - // Initialize container map from extensions - containers.forEach(function (container) { - containerMap[container.key] = container; - }); - - return { - - // Allow only at the element level - restrict: 'E', - - // Support transclusion - transclude: true, - - // Create a new (non-isolate) scope - scope: true, - - // Populate initial scope based on attributes requested - // by the container definition - link: function (scope, element, attrs) { - var key = attrs.key, - container = containerMap[key], - alias = "container", - copiedAttributes = {}; - - if (container) { - alias = container.alias || alias; - (container.attributes || []).forEach(function (attr) { - copiedAttributes[attr] = attrs[attr]; - }); - } - - scope[alias] = copiedAttributes; - }, - - template: function (element, attrs) { - var key = attrs.key, - container = containerMap[key]; - - return container ? container.template : ""; - } - }; - } - - return MCTContainer; - } -); diff --git a/platform/commonUI/general/src/directives/MCTDrag.js b/platform/commonUI/general/src/directives/MCTDrag.js deleted file mode 100644 index ef87bbb5c1..0000000000 --- a/platform/commonUI/general/src/directives/MCTDrag.js +++ /dev/null @@ -1,177 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The mct-drag directive allows drag functionality - * (in the mousedown-mousemove-mouseup sense, as opposed to - * the drag-and-drop sense) to be attached to specific - * elements. This takes the form of three attributes: - * - * * `mct-drag`: An Angular expression to evaluate during - * drag movement. - * * `mct-drag-down`: An Angular expression to evaluate - * when the drag begins. - * * `mct-drag-up`: An Angular expression to evaluate when - * dragging ends. - * - * In each case, a variable `delta` will be provided to the - * expression; this is a two-element array or the horizontal - * and vertical pixel offset of the current mouse position - * relative to the mouse position where dragging began. - * - * @memberof platform/commonUI/general - * @constructor - * - */ - function MCTDrag($document, agentService) { - - // Link; install event handlers. - function link(scope, element, attrs) { - // Keep a reference to the body, to attach/detach - // mouse event handlers; mousedown and mouseup cannot - // only be attached to the element being linked, as the - // mouse may leave this element during the drag. - var body = $document.find('body'), - isMobile = agentService.isMobile(), - touchEvents, - initialPosition, - $event, - delta; - - if (isMobile) { - touchEvents = { - start: 'touchstart', - end: 'touchend', - move: 'touchmove' - }; - } else { - touchEvents = { - start: 'mousedown', - end: "mouseup", - move: "mousemove" - }; - } - - // Utility function to cause evaluation of mctDrag, - // mctDragUp, etc - function fireListener(name) { - // Evaluate the expression, with current delta - scope.$eval(attrs[name], { - delta: delta, - $event: $event - }); - - // Trigger prompt digestion - scope.$apply(); - } - - // Update positions (both actual and relative) - // based on a new mouse event object. - function updatePosition(event) { - // Get the current position, as an array - var currentPosition = [event.pageX, event.pageY]; - - // Track the initial position, if one hasn't been observed - initialPosition = initialPosition || currentPosition; - - // Compute relative position - delta = currentPosition.map(function (v, i) { - return v - initialPosition[i]; - }); - - // Also track the plain event for firing listeners - $event = event; - } - - // Called during a drag, on mousemove - function continueDrag(event) { - updatePosition(event); - fireListener("mctDrag"); - - // Don't show selection highlights, etc - event.preventDefault(); - - return false; - } - - // Called only when the drag ends (on mouseup) - function endDrag(event) { - // Detach event handlers - body.off(touchEvents.end, endDrag); - body.off(touchEvents.move, continueDrag); - - // Also call continueDrag, to fire mctDrag - // and do its usual position update - continueDrag(event); - - fireListener("mctDragUp"); - - // Clear out start-of-drag position, target - initialPosition = undefined; - - // Don't show selection highlights, etc - event.preventDefault(); - - return false; - } - - // Called on mousedown on the element - function startDrag(event) { - // Listen for mouse events at the body level, - // since the mouse may leave the element during - // the drag. - body.on(touchEvents.end, endDrag); - body.on(touchEvents.move, continueDrag); - - // Set an initial position - updatePosition(event); - - // Fire listeners, including mctDrag - fireListener("mctDragDown"); - fireListener("mctDrag"); - - // Don't show selection highlights, etc - event.preventDefault(); - - return false; - } - - // Listen for start event on the element - element.on(touchEvents.start, startDrag); - } - - return { - // mct-drag only makes sense as an attribute - restrict: "A", - // Link function, to install event handlers - link: link - }; - } - - return MCTDrag; - } -); - diff --git a/platform/commonUI/general/src/directives/MCTIndicators.js b/platform/commonUI/general/src/directives/MCTIndicators.js deleted file mode 100644 index f226003aaa..0000000000 --- a/platform/commonUI/general/src/directives/MCTIndicators.js +++ /dev/null @@ -1,40 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - function MCTIndicators(openmct) { - return { - restrict: "E", - link: function link(scope, element) { - openmct.indicators.indicatorElements - .forEach(function (indicatorElement) { - element.append(indicatorElement); - }); - } - }; - } - - return MCTIndicators; - } -); diff --git a/platform/commonUI/general/src/directives/MCTPopup.js b/platform/commonUI/general/src/directives/MCTPopup.js deleted file mode 100644 index 592aeffa2e..0000000000 --- a/platform/commonUI/general/src/directives/MCTPopup.js +++ /dev/null @@ -1,72 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - var TEMPLATE = "
    "; - - /** - * The `mct-popup` directive may be used to display elements - * which "pop up" over other parts of the page. Typically, this is - * done in conjunction with an `ng-if` to control the visibility - * of the popup. - * - * Example of usage: - * - * - * These are the contents of the popup! - * - * - * @constructor - * @memberof platform/commonUI/general - * @param $compile Angular's $compile service - * @param {platform/commonUI/general.PopupService} popupService - */ - function MCTPopup($compile, popupService) { - function link(scope, element, attrs, ctrl, transclude) { - var div = $compile(TEMPLATE)(scope), - rect = element.parent()[0].getBoundingClientRect(), - position = [rect.left, rect.top], - popup = popupService.display(div, position); - - div.addClass('t-popup'); - transclude(function (clone) { - div.append(clone); - }); - - scope.$on('$destroy', function () { - popup.dismiss(); - }); - } - - return { - restrict: "E", - transclude: true, - link: link, - scope: {} - }; - } - - return MCTPopup; - } -); diff --git a/platform/commonUI/general/src/directives/MCTResize.js b/platform/commonUI/general/src/directives/MCTResize.js deleted file mode 100644 index 55ba18168f..0000000000 --- a/platform/commonUI/general/src/directives/MCTResize.js +++ /dev/null @@ -1,123 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - // Default resize interval - var DEFAULT_INTERVAL = 100; - - /** - * The mct-resize directive allows the size of a displayed - * HTML element to be tracked. This is done by polling, - * since the DOM API does not currently provide suitable - * events to watch this reliably. - * - * Attributes related to this directive are interpreted as - * follows: - * - * * `mct-resize`: An Angular expression to evaluate when - * the size changes; the variable `bounds` will be provided - * with two fields, `width` and `height`, both in pixels. - * * `mct-resize-interval`: Optional; the interval, in milliseconds, - * at which to watch for updates. In some cases checking for - * resize can carry a cost (it forces recalculation of - * positions within the document) so it may be preferable to watch - * infrequently. If omitted, a default of 100ms will be used. - * This is an Angular expression, and it will be re-evaluated after - * each interval. - * - * @memberof platform/commonUI/general - * @constructor - * - */ - function MCTResize($timeout) { - - // Link; start listening for changes to an element's size - function link(scope, element, attrs) { - var lastBounds, - linking = true, - active = true; - - // Determine how long to wait before the next update - function currentInterval() { - return attrs.mctResizeInterval - ? scope.$eval(attrs.mctResizeInterval) - : DEFAULT_INTERVAL; - } - - // Evaluate mct-resize with the current bounds - function fireEval(bounds) { - // Only update when bounds actually change - if (!lastBounds - || lastBounds.width !== bounds.width - || lastBounds.height !== bounds.height) { - scope.$eval(attrs.mctResize, { bounds: bounds }); - if (!linking) { // Avoid apply-in-a-digest - scope.$apply(); - } - - lastBounds = bounds; - } - } - - // Callback to fire after each timeout; - // update bounds and schedule another timeout - function onInterval() { - if (!active) { - return; - } - - fireEval({ - width: element[0].offsetWidth, - height: element[0].offsetHeight - }); - $timeout(onInterval, currentInterval(), false); - } - - // Stop running in the background - function deactivate() { - active = false; - } - - // Unregister once out-of-scope - scope.$on("$destroy", deactivate); - - // Handle the initial callback - onInterval(); - - // Trigger scope.$apply on subsequent changes - linking = false; - } - - return { - // mct-resize only makes sense as an attribute - restrict: "A", - // Link function, to begin watching for changes - link: link - }; - } - - return MCTResize; - } -); diff --git a/platform/commonUI/general/src/directives/MCTScroll.js b/platform/commonUI/general/src/directives/MCTScroll.js deleted file mode 100644 index fa3de0c028..0000000000 --- a/platform/commonUI/general/src/directives/MCTScroll.js +++ /dev/null @@ -1,82 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 `mct-scroll-x` and `mct-scroll-y` directives. Listens - * for scroll events and publishes their results into scope; watches - * scope and updates scroll state to match. This varies for x- and y- - * directives only by the attribute name chosen to find the expression, - * and the property (scrollLeft or scrollTop) managed within the - * element. - * - * This is exposed as two directives in `bundle.json`; the difference - * is handled purely by parameterization. - * - * @memberof platform/commonUI/general - * @constructor - * @param $parse Angular's $parse - * @param {string} property property to manage within the HTML element - * @param {string} attribute attribute to look at for the assignable - * Angular expression - */ - function MCTScroll($parse, property, attribute) { - function link(scope, element, attrs) { - var expr = attrs[attribute], - parsed = $parse(expr); - - // Set the element's scroll to match the scope's state - function updateElement(value) { - element[0][property] = value; - } - - // Handle event; assign to scroll state to scope - function updateScope() { - parsed.assign(scope, element[0][property]); - scope.$apply(expr); - } - - // Initialize state in scope - parsed.assign(scope, element[0][property]); - - // Update element state when value in scope changes - scope.$watch(expr, updateElement); - - // Update state in scope when element is scrolled - element.on('scroll', updateScope); - } - - return { - // Restrict to attributes - restrict: "A", - // Use this link function - link: link - }; - } - - return MCTScroll; - - } -); diff --git a/platform/commonUI/general/src/directives/MCTSelectable.js b/platform/commonUI/general/src/directives/MCTSelectable.js deleted file mode 100644 index 3089db9768..0000000000 --- a/platform/commonUI/general/src/directives/MCTSelectable.js +++ /dev/null @@ -1,83 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The mct-selectable directive allows selection functionality - * (click) to be attached to specific elements. - * - * Example of how to use the directive: - * - * mct-selectable="{ - * // item is an optional domain object. - * item: domainObject, - * // Can define other arbitrary properties. - * elementProxy: element, - * controller: fixedController - * }" - * - * @memberof platform/commonUI/general - * @constructor - */ - function MCTSelectable(openmct) { - - // Link; install event handlers. - function link(scope, element, attrs) { - var isDestroyed = false; - scope.$on("$destroy", function () { - isDestroyed = true; - }); - - openmct.$injector.get('$timeout')(function () { - if (isDestroyed) { - return; - } - - var removeSelectable = openmct.selection.selectable( - element[0], - scope.$eval(attrs.mctSelectable), - Object.prototype.hasOwnProperty.call(attrs, 'mctInitSelect') - && scope.$eval(attrs.mctInitSelect) !== false - ); - - scope.$on("$destroy", function () { - removeSelectable(); - }); - }); - - } - - return { - // mct-selectable only makes sense as an attribute - restrict: "A", - // Link function, to install event handlers - link: link - }; - - } - - return MCTSelectable; - } -); diff --git a/platform/commonUI/general/src/directives/MCTSplitPane.js b/platform/commonUI/general/src/directives/MCTSplitPane.js deleted file mode 100644 index 8733fdcabf..0000000000 --- a/platform/commonUI/general/src/directives/MCTSplitPane.js +++ /dev/null @@ -1,263 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - // Pixel width to allocate for the splitter itself - var DEFAULT_ANCHOR = 'left', - POLLING_INTERVAL = 15, // milliseconds - CHILDREN_WARNING_MESSAGE = [ - "Invalid mct-split-pane contents.", - "This element should contain exactly three", - "child elements, where the middle-most element", - "is an mct-splitter." - ].join(" "), - ANCHOR_WARNING_MESSAGE = [ - "Unknown anchor provided to mct-split-pane,", - "defaulting to", - DEFAULT_ANCHOR + "." - ].join(" "), - ANCHORS = { - left: { - edge: "left", - opposite: "right", - dimension: "width", - orientation: "vertical" - }, - right: { - edge: "right", - opposite: "left", - dimension: "width", - orientation: "vertical", - reversed: true - }, - top: { - edge: "top", - opposite: "bottom", - dimension: "height", - orientation: "horizontal" - }, - bottom: { - edge: "bottom", - opposite: "top", - dimension: "height", - orientation: "horizontal", - reversed: true - } - }; - - /** - * Implements `mct-split-pane` directive. - * - * This takes the following attributes: - * * `position`: Two-way bound scope variable which will contain - * the pixel position of the splitter, offset from the appropriate - * edge. - * * `anchor`: Plain string, one of "left", "right", "top", - * or "bottom". - * - * When used, an `mct-split-pane` element should contain exactly - * three child elements, where the middle is an `mct-splitter` - * element. These should be included in either left-to-right - * or top-to-bottom order (depending on anchoring.) If the contents - * do not match this form, `mct-split-pane` will issue a warning - * and its behavior will be undefined. - * - * This directive works by setting the width of the element - * nearest the anchor edge, and then positioning the other elements - * based on its observed width. As such, `min-width`, `max-width`, - * etc. can be set on that element to control the splitter's - * allowable positions. - * - * @memberof platform/commonUI/general - * @constructor - */ - function MCTSplitPane($parse, $log, $interval, $window) { - function controller($scope, $element, $attrs) { - var anchorKey = $attrs.anchor || DEFAULT_ANCHOR, - positionParsed = $parse($attrs.position), - anchor, - activeInterval, - position, - splitterSize, - - alias = $attrs.alias !== undefined - ? "mctSplitPane-" + $attrs.alias : undefined, - - //convert string to number from localStorage - userWidthPreference = $window.localStorage.getItem(alias) === null - ? undefined : Number($window.localStorage.getItem(alias)); - - // Get relevant size (height or width) of DOM element - function getSize(domElement) { - return (anchor.orientation === 'vertical' - ? domElement.offsetWidth : domElement.offsetHeight); - } - - // Apply styles to child elements - function updateChildren(children) { - position = userWidthPreference || position; - - // Pick out correct elements to update, flowing from - // selected anchor edge. - var first = children.eq(anchor.reversed ? 2 : 0), - splitter = children.eq(1), - last = children.eq(anchor.reversed ? 0 : 2), - firstSize; - - splitterSize = getSize(splitter[0]); - first.css(anchor.edge, "0px"); - first.css(anchor.dimension, position + 'px'); - - // Get actual size (to obey min-width etc.) - firstSize = getSize(first[0]); - first.css(anchor.dimension, firstSize + 'px'); - splitter.css(anchor.edge, firstSize + 'px'); - splitter.css(anchor.opposite, "auto"); - - last.css(anchor.edge, firstSize + splitterSize + 'px'); - last.css(anchor.opposite, '0px'); - position = firstSize; - } - - // Update positioning of contained elements - function updateElementPositions() { - var children = $element.children(); - - // Check to make sure contents are well-formed - if (children.length !== 3 - || children[1].nodeName.toLowerCase() !== 'mct-splitter') { - $log.warn(CHILDREN_WARNING_MESSAGE); - - return; - } - - updateChildren(children); - } - - // Enforce minimum/maximum positions - function enforceExtrema() { - position = Math.max(position, 0); - position = Math.min(position, getSize($element[0])); - } - - // Getter-setter for the pixel offset of the splitter, - // relative to the current edge. - function getSetPosition(value) { - var prior = position; - if (typeof value === 'number') { - position = value; - enforceExtrema(); - updateElementPositions(); - - // Pass change up so this state can be shared - if (positionParsed.assign && position !== prior) { - positionParsed.assign($scope, position); - } - } - - return position; - } - - function setUserWidthPreference(value) { - if (alias) { - userWidthPreference = value; - } - } - - function persistToLocalStorage(value) { - if (alias) { - $window.localStorage.setItem(alias, value); - } - } - - // Dynamically apply a CSS class to elements when the user - // is actively resizing - function toggleClass(classToToggle) { - $element.children().toggleClass(classToToggle); - } - - // Make sure anchor parameter is something we know - if (!ANCHORS[anchorKey]) { - $log.warn(ANCHOR_WARNING_MESSAGE); - anchorKey = DEFAULT_ANCHOR; - } - - anchor = ANCHORS[anchorKey]; - - $scope.$watch($attrs.position, getSetPosition); - - $element.addClass("split-layout"); - $element.addClass(anchor.orientation); - - // Initialize positions - getSetPosition(getSize( - $element.children().eq(anchor.reversed ? 2 : 0)[0] - )); - - // And poll for position changes enforced by styles - activeInterval = $interval(function () { - getSetPosition(getSetPosition()); - }, POLLING_INTERVAL, 0, false); - // ...and stop polling when we're destroyed. - $scope.$on('$destroy', function () { - $interval.cancel(activeInterval); - }); - - // Interface exposed by controller, for mct-splitter to user - return { - anchor: function () { - return anchor; - }, - position: function (newPosition) { - if (arguments.length === 0) { - return getSetPosition(); - } - - setUserWidthPreference(newPosition); - - return getSetPosition(newPosition); - }, - startResizing: function () { - toggleClass('resizing'); - }, - endResizing: function (finalPosition) { - persistToLocalStorage(finalPosition); - toggleClass('resizing'); - } - }; - } - - return { - // Restrict to attributes - restrict: "E", - // Expose its controller - controller: ['$scope', '$element', '$attrs', controller] - }; - } - - return MCTSplitPane; - - } -); diff --git a/platform/commonUI/general/src/directives/MCTSplitter.js b/platform/commonUI/general/src/directives/MCTSplitter.js deleted file mode 100644 index 77520f9166..0000000000 --- a/platform/commonUI/general/src/directives/MCTSplitter.js +++ /dev/null @@ -1,90 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - // Pixel width to allocate for the splitter itself - var SPLITTER_TEMPLATE = "
    "; - - /** - * Implements `mct-splitter` directive. - * @memberof platform/commonUI/general - * @constructor - */ - function MCTSplitter() { - function link(scope, element, attrs, mctSplitPane) { - var initialPosition, - newPosition; - - element.addClass("splitter"); - - scope.splitter = { - // Begin moving this splitter - startMove: function () { - mctSplitPane.startResizing(); - initialPosition = mctSplitPane.position(); - }, - // Handle user changes to splitter position - move: function (delta) { - var anchor = mctSplitPane.anchor(), - index = anchor.orientation === "vertical" ? 0 : 1, - pixelDelta = delta[index] - * (anchor.reversed ? -1 : 1); - - // Update the position of this splitter - newPosition = initialPosition + pixelDelta; - - if (initialPosition !== newPosition) { - mctSplitPane.position(newPosition); - } - }, - // Grab the event when the user is done moving - // the splitter and pass it on - endMove: function () { - mctSplitPane.endResizing(newPosition); - } - }; - } - - return { - // Restrict to attributes - restrict: "E", - // Utilize the mct-split-pane controller - require: "^mctSplitPane", - // Expose its controller - link: link, - // Use the template defined above - template: SPLITTER_TEMPLATE, - // Create a new scope to put the splitter into - scope: true - }; - } - - return MCTSplitter; - - } -); diff --git a/platform/commonUI/general/src/directives/MCTTree.js b/platform/commonUI/general/src/directives/MCTTree.js deleted file mode 100644 index d6f7e15b1e..0000000000 --- a/platform/commonUI/general/src/directives/MCTTree.js +++ /dev/null @@ -1,86 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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([ - 'angular', - '../ui/TreeView' -], function (angular, TreeView) { - function MCTTree(gestureService, openmct) { - function link(scope, element) { - if (!scope.allowSelection) { - scope.allowSelection = function () { - return true; - }; - } - - if (!scope.onSelection) { - scope.onSelection = function () {}; - } - - var currentSelection = scope.selectedObject; - var treeView = new TreeView(gestureService, openmct); - - function setSelection(domainObject, event) { - if (currentSelection === domainObject) { - return; - } - - if (!scope.allowSelection(domainObject)) { - treeView.value(currentSelection); - - return; - } - - currentSelection = domainObject; - scope.onSelection(domainObject); - scope.selectedObject = domainObject; - if (event && event instanceof MouseEvent) { - scope.$apply(); - } - } - - var unobserve = treeView.observe(setSelection); - - element.append(angular.element(treeView.elements())); - - scope.$watch('selectedObject', function (object) { - currentSelection = object; - treeView.value(object); - }); - scope.$watch('rootObject', treeView.model.bind(treeView)); - scope.$on('$destroy', unobserve); - } - - return { - restrict: "E", - link: link, - scope: { - rootObject: "=", - selectedObject: "=", - onSelection: "=?", - allowSelection: "=?" - } - }; - } - - return MCTTree; -}); diff --git a/platform/commonUI/general/src/filters/ReverseFilter.js b/platform/commonUI/general/src/filters/ReverseFilter.js deleted file mode 100644 index 50ab18e504..0000000000 --- a/platform/commonUI/general/src/filters/ReverseFilter.js +++ /dev/null @@ -1,42 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 `reverse` filter, which reverses text strings. - * Useful in cases where text should be reversed for presentational - * reasons (e.g. in conjunction with CSS tricks involving text direction), - * allowing such behavior to be handled independently from the controller - * layer. - * - * @constructor - * @memberof platform/commonUI/general - */ - function ReverseFilter() { - return function reverse(value) { - return value && value.toString().split('').reverse().join(''); - }; - } - - return ReverseFilter; -}); diff --git a/platform/commonUI/general/src/services/Overlay.js b/platform/commonUI/general/src/services/Overlay.js deleted file mode 100644 index 6c4e37bf1d..0000000000 --- a/platform/commonUI/general/src/services/Overlay.js +++ /dev/null @@ -1,186 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 OverlayService. Created by deeptailor on 03/29/2018 - */ - -define(['zepto'], function ($) { - var OVERLAY_TEMPLATE = '' -+ '
    ' -+ '
    ' -+ ' ' -+ '
    ' -+ '
    ' -+ '
    ' -+ ' Done' -+ '
    ' -+ '
    ' -+ '
    '; - - /* - * An Overlay Service when instantiated creates an overlay dialog. - * @param {Object} options The options object required to instantiate the overlay service - * options = { - * $document: document object, - * $scope: angular $scope object, - * element: node to be injected into overlay as a view, - * overlayWillMount: callback executed before overlay is injected, - * overlayWillUnmount: callback executed before overlay is removed, - * overlayDidMount: callback executed after overlay is injected, - * overlayDidUnmount: callback executed after overlay is removed - * browseBarButtons: an array of desired buttons to be added to the browse bar of the overlay. - * the array should consist of button objects containing: - * a) class - css class to be added to the button div - * b) title - desired button title - * c) clickHandler - callback to be added to the click event listener of the button - * } - * $document, $scope and element are required - */ - - function Overlay(options) { - this.element = options.$element; - this.document = options.$document[0]; - this.$scope = options.$scope; - - this.overlayWillMount = options.overlayWillMount; - this.overlayWillUnmount = options.overlayWillUnmount; - - this.overlayDidMount = options.overlayDidMount; - this.overlayDidUnmount = options.overlayDidUnmount; - - this.browseBarButtons = options.browseBarButtons || []; - this.buttons = []; - - this.openOverlay = this.openOverlay.bind(this); - this.closeOverlay = this.closeOverlay.bind(this); - this.toggleOverlay = this.toggleOverlay.bind(this); - this.removeButtons = this.removeButtons.bind(this); - - this.isOverlayOpen = false; - } - - Overlay.prototype.openOverlay = function () { - - if (this.overlayWillMount && typeof this.overlayWillMount === 'function') { - this.overlayWillMount(); - } - - this.overlay = this.document.createElement('div'); - $(this.overlay).addClass('abs overlay l-large-view'); - this.overlay.innerHTML = OVERLAY_TEMPLATE; - - this.overlayContainer = this.overlay.querySelector('.t-contents'); - - this.closeButton = this.overlay.querySelector('a.close'); - this.closeButton.addEventListener('click', this.toggleOverlay); - - this.doneButton = this.overlay.querySelector('a.t-done'); - this.doneButton.addEventListener('click', this.toggleOverlay); - - this.blocker = this.overlay.querySelector('.abs.blocker'); - this.blocker.addEventListener('click', this.toggleOverlay); - - this.document.body.appendChild(this.overlay); - - this.overlayContainer.appendChild(this.element); - - this.browseBar = this.overlay.querySelector('.object-browse-bar .right'); - - if (this.browseBarButtons && Array.isArray(this.browseBarButtons)) { - this.browseBarButtons.forEach(function (buttonObject) { - var button = newButtonTemplate(buttonObject.class, buttonObject.title); - this.browseBar.prepend(button); - button.addEventListener('click', buttonObject.clickHandler); - this.buttons.push(button); - }.bind(this)); - } - - if (this.overlayDidMount && typeof this.overlayDidMount === 'function') { - this.overlayDidMount(); - } - }; - - Overlay.prototype.closeOverlay = function () { - - if (this.overlayWillUnmount && typeof this.overlayWillUnmount === 'function') { - this.overlayWillUnmount(); - } - - this.overlayContainer.removeChild(this.element); - this.document.body.removeChild(this.overlay); - - this.closeButton.removeEventListener('click', this.toggleOverlay); - this.closeButton = undefined; - - this.doneButton.removeEventListener('click', this.toggleOverlay); - this.doneButton = undefined; - - this.blocker.removeEventListener('click', this.toggleOverlay); - this.blocker = undefined; - - this.overlayContainer = undefined; - this.overlay = undefined; - - this.removeButtons(); - - if (this.overlayDidUnmount && typeof this.overlayDidUnmount === 'function') { - this.overlayDidUnmount(); - } - }; - - Overlay.prototype.toggleOverlay = function (event) { - if (event) { - event.stopPropagation(); - } - - if (!this.isOverlayOpen) { - this.openOverlay(); - this.isOverlayOpen = true; - } else { - this.closeOverlay(); - this.isOverlayOpen = false; - } - }; - - Overlay.prototype.removeButtons = function () { - this.buttons.forEach(function (button) { - button.remove(); - }.bind(this)); - - this.buttons = []; - }; - - function newButtonTemplate(classString, title) { - var NEW_BUTTON_TEMPLATE = '' - + '' + title + '' - + ''; - - var button = document.createElement('div'); - $(button).addClass('holder flex-elem'); - button.innerHTML = NEW_BUTTON_TEMPLATE; - - return button; - } - - return Overlay; -}); diff --git a/platform/commonUI/general/src/services/Popup.js b/platform/commonUI/general/src/services/Popup.js deleted file mode 100644 index 023e82f3f7..0000000000 --- a/platform/commonUI/general/src/services/Popup.js +++ /dev/null @@ -1,87 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 popup is an element that has been displayed at a particular - * location within the page. - * @constructor - * @memberof platform/commonUI/general - * @param element the jqLite-wrapped element - * @param {object} styles an object containing key-value pairs - * of styles used to position the element. - */ - function Popup(element, styles) { - this.styles = styles; - this.element = element; - - element.css(styles); - } - - /** - * Stop showing this popup. - */ - Popup.prototype.dismiss = function () { - this.element.remove(); - }; - - /** - * Check if this popup is positioned such that it appears to the - * left of its original location. - * @returns {boolean} true if the popup goes left - */ - Popup.prototype.goesLeft = function () { - return !this.styles.left; - }; - - /** - * Check if this popup is positioned such that it appears to the - * right of its original location. - * @returns {boolean} true if the popup goes right - */ - Popup.prototype.goesRight = function () { - return !this.styles.right; - }; - - /** - * Check if this popup is positioned such that it appears above - * its original location. - * @returns {boolean} true if the popup goes up - */ - Popup.prototype.goesUp = function () { - return !this.styles.top; - }; - - /** - * Check if this popup is positioned such that it appears below - * its original location. - * @returns {boolean} true if the popup goes down - */ - Popup.prototype.goesDown = function () { - return !this.styles.bottom; - }; - - return Popup; - } -); diff --git a/platform/commonUI/general/src/services/PopupService.js b/platform/commonUI/general/src/services/PopupService.js deleted file mode 100644 index b73b6f8b3b..0000000000 --- a/platform/commonUI/general/src/services/PopupService.js +++ /dev/null @@ -1,124 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['./Popup'], - function (Popup) { - - /** - * Displays popup elements at specific positions within the document. - * @memberof platform/commonUI/general - * @constructor - */ - function PopupService($document, $window) { - this.$document = $document; - this.$window = $window; - } - - /** - * Options controlling how the popup is displayed. - * - * @typedef PopupOptions - * @memberof platform/commonUI/general - * @property {number} [offsetX] the horizontal distance, in pixels, - * to offset the element in whichever direction it is - * displayed. Defaults to 0. - * @property {number} [offsetY] the vertical distance, in pixels, - * to offset the element in whichever direction it is - * displayed. Defaults to 0. - * @property {number} [marginX] the horizontal position, in pixels, - * after which to prefer to display the element to the left. - * If negative, this is relative to the right edge of the - * page. Defaults to half the window's width. - * @property {number} [marginY] the vertical position, in pixels, - * after which to prefer to display the element upward. - * If negative, this is relative to the right edge of the - * page. Defaults to half the window's height. - * @property {string} [leftClass] class to apply when shifting to the left - * @property {string} [rightClass] class to apply when shifting to the right - * @property {string} [upClass] class to apply when shifting upward - * @property {string} [downClass] class to apply when shifting downward - */ - - /** - * Display a popup at a particular location. The location chosen will - * be the corner of the element; the element will be positioned either - * to the left or the right of this point depending on available - * horizontal space, and will similarly be shifted upward or downward - * depending on available vertical space. - * - * @param element the jqLite-wrapped DOM element to pop up - * @param {number[]} position x,y position of the element, in - * pixel coordinates. Negative values are interpreted as - * relative to the right or bottom of the window. - * @param {PopupOptions} [options] additional options to control - * positioning of the popup - * @returns {platform/commonUI/general.Popup} the popup - */ - PopupService.prototype.display = function (element, position, options) { - var $document = this.$document, - $window = this.$window, - body = $document.find('body'), - winDim = [$window.innerWidth, $window.innerHeight], - styles = { position: 'absolute' }, - margin, - offset; - - function adjustNegatives(value, index) { - return value < 0 ? (value + winDim[index]) : value; - } - - // Defaults - options = options || {}; - offset = [ - options.offsetX !== undefined ? options.offsetX : 0, - options.offsetY !== undefined ? options.offsetY : 0 - ]; - margin = [options.marginX, options.marginY].map(function (m, i) { - return m === undefined ? (winDim[i] / 2) : m; - }).map(adjustNegatives); - - position = position.map(adjustNegatives); - - if (position[0] > margin[0]) { - styles.right = (winDim[0] - position[0] + offset[0]) + 'px'; - } else { - styles.left = (position[0] + offset[0]) + 'px'; - } - - if (position[1] > margin[1]) { - styles.bottom = (winDim[1] - position[1] + offset[1]) + 'px'; - } else { - styles.top = (position[1] + offset[1]) + 'px'; - } - - // Add the menu to the body - body.append(element); - - // Return a function to dismiss the bubble - return new Popup(element, styles); - }; - - return PopupService; - } -); - diff --git a/platform/commonUI/general/src/services/UrlService.js b/platform/commonUI/general/src/services/UrlService.js deleted file mode 100644 index 27a7c4756d..0000000000 --- a/platform/commonUI/general/src/services/UrlService.js +++ /dev/null @@ -1,94 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 UrlService. - */ -define( - [], - function () { - - /** - * The url service handles calls for url paths - * using domain objects. - * @constructor - * @memberof platform/commonUI/general - */ - function UrlService($location) { - this.$location = $location; - } - - /** - * Returns the Url path for a specific domain object - * without the index.html path and the view path - * @param {string} mode value of browse or edit mode - * for the path - * @param {DomainObject} value of the domain object - * to get the path of - * @returns {string} URL for the domain object - */ - UrlService.prototype.urlForLocation = function (mode, domainObject) { - var context = domainObject - && domainObject.getCapability('context'), - objectPath = context ? context.getPath() : [], - ids = objectPath.map(function (domainObj) { - return domainObj.getId(); - }); - - // Parses the path together. Starts with the - // default index.html file, then the mode passed - // into the service, followed by ids in the url - // joined by '/', and lastly the view path from - // the current location - return mode + "/" + ids.slice(1).join("/"); - }; - - /** - * Returns the Url path for a specific domain object - * including the index.html path and the view path - * allowing a new tab to hold the correct characteristics - * @param {string} mode value of browse or edit mode - * for the path - * @param {DomainObject} value of the domain object - * to get the path of - * @returns {string} URL for the domain object - */ - UrlService.prototype.urlForNewTab = function (mode, domainObject) { - var search = this.$location.search(), - arr = []; - for (var key in search) { - if (Object.prototype.hasOwnProperty.call(search, key)) { - arr.push(key + '=' + search[key]); - } - } - - var searchPath = "?" + arr.join('&'), - newTabPath = - "#" + this.urlForLocation(mode, domainObject) - + searchPath; - - return newTabPath; - }; - - return UrlService; - } -); diff --git a/platform/commonUI/general/src/ui/ToggleView.js b/platform/commonUI/general/src/ui/ToggleView.js deleted file mode 100644 index dfe9e92ee6..0000000000 --- a/platform/commonUI/general/src/ui/ToggleView.js +++ /dev/null @@ -1,65 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define([ - 'zepto', - '../../res/templates/tree/toggle.html' -], function ($, toggleTemplate) { - function ToggleView(state) { - this.expanded = Boolean(state); - this.callbacks = []; - this.el = $(toggleTemplate); - this.el.on('click', function () { - this.value(!this.expanded); - }.bind(this)); - } - - ToggleView.prototype.value = function (state) { - this.expanded = state; - - if (state) { - this.el.addClass('c-disclosure-triangle--expanded'); - } else { - this.el.removeClass('c-disclosure-triangle--expanded'); - } - - this.callbacks.forEach(function (callback) { - callback(state); - }); - }; - - ToggleView.prototype.observe = function (callback) { - this.callbacks.push(callback); - - return function () { - this.callbacks = this.callbacks.filter(function (c) { - return c !== callback; - }); - }.bind(this); - }; - - ToggleView.prototype.elements = function () { - return this.el; - }; - - return ToggleView; -}); diff --git a/platform/commonUI/general/src/ui/TreeLabelView.js b/platform/commonUI/general/src/ui/TreeLabelView.js deleted file mode 100644 index b1da93a1ff..0000000000 --- a/platform/commonUI/general/src/ui/TreeLabelView.js +++ /dev/null @@ -1,97 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define([ - 'zepto', - '../../res/templates/tree/tree-label.html' -], function ($, labelTemplate) { - - function TreeLabelView(gestureService) { - this.el = $(labelTemplate); - this.gestureService = gestureService; - } - - function isLink(domainObject) { - var location = domainObject.getCapability('location'); - - return location.isLink(); - } - - function getClass(domainObject) { - var type = domainObject.getCapability('type'); - - return type.getCssClass(); - } - - function removePreviousIconClass(el) { - $(el).removeClass(function (index, className) { - return (className.match (/\bicon-\S+/g) || []).join(' '); - }); - } - - TreeLabelView.prototype.updateView = function (domainObject) { - var titleEl = this.el.find('.t-title-label'), - iconEl = this.el.find('.t-item-icon'); - - removePreviousIconClass(iconEl); - - titleEl.text(domainObject ? domainObject.getModel().name : ""); - iconEl.addClass(domainObject ? getClass(domainObject) : ""); - - if (domainObject && isLink(domainObject)) { - iconEl.addClass('l-icon-link'); - } else { - iconEl.removeClass('l-icon-link'); - } - }; - - TreeLabelView.prototype.model = function (domainObject) { - if (this.unlisten) { - this.unlisten(); - delete this.unlisten; - } - - if (this.activeGestures) { - this.activeGestures.destroy(); - delete this.activeGestures; - } - - this.updateView(domainObject); - - if (domainObject) { - this.unlisten = domainObject.getCapability('mutation') - .listen(this.updateView.bind(this, domainObject)); - - this.activeGestures = this.gestureService.attachGestures( - this.elements(), - domainObject, - ['info', 'menu', 'drag'] - ); - } - }; - - TreeLabelView.prototype.elements = function () { - return this.el; - }; - - return TreeLabelView; -}); diff --git a/platform/commonUI/general/src/ui/TreeNodeView.js b/platform/commonUI/general/src/ui/TreeNodeView.js deleted file mode 100644 index e2125befda..0000000000 --- a/platform/commonUI/general/src/ui/TreeNodeView.js +++ /dev/null @@ -1,158 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define([ - 'zepto', - '../../res/templates/tree/node.html', - './ToggleView', - './TreeLabelView' -], function ($, nodeTemplate, ToggleView, TreeLabelView) { - - function TreeNodeView(gestureService, subtreeFactory, selectFn, openmct) { - this.li = $('
  • '); - this.openmct = openmct; - this.statusClasses = []; - - this.toggleView = new ToggleView(false); - this.toggleView.observe(function (state) { - if (state) { - if (!this.subtreeView) { - this.subtreeView = subtreeFactory(); - this.subtreeView.model(this.activeObject); - this.li.find('.c-tree__item-subtree').eq(0) - .append($(this.subtreeView.elements())); - } - - $(this.subtreeView.elements()).removeClass('hidden'); - } else if (this.subtreeView) { - $(this.subtreeView.elements()).addClass('hidden'); - } - }.bind(this)); - - this.labelView = new TreeLabelView(gestureService); - - $(this.labelView.elements()).on('click', function (event) { - selectFn(this.activeObject, event); - }.bind(this)); - - this.li.append($(nodeTemplate)); - this.li.find('span').eq(0) - .append($(this.toggleView.elements())) - .append($(this.labelView.elements())); - - this.model(undefined); - } - - TreeNodeView.prototype.updateStatusClasses = function (statuses) { - this.statusClasses.forEach(function (statusClass) { - this.li.removeClass(statusClass); - }.bind(this)); - - this.statusClasses = statuses.map(function (status) { - return 's-status-' + status; - }); - - this.statusClasses.forEach(function (statusClass) { - this.li.addClass(statusClass); - }.bind(this)); - }; - - TreeNodeView.prototype.model = function (domainObject) { - if (this.unlisten) { - this.unlisten(); - } - - this.activeObject = domainObject; - if (domainObject && domainObject.hasCapability('adapter')) { - var obj = domainObject.useCapability('adapter'); - var hasComposition = this.openmct.composition.get(obj) !== undefined; - if (hasComposition) { - $(this.toggleView.elements()).addClass('is-enabled'); - } else { - $(this.toggleView.elements()).removeClass('is-enabled'); - } - } - - if (domainObject && domainObject.hasCapability('status')) { - this.unlisten = domainObject.getCapability('status') - .listen(this.updateStatusClasses.bind(this)); - this.updateStatusClasses( - domainObject.getCapability('status').list() - ); - } - - this.labelView.model(domainObject); - if (this.subtreeView) { - this.subtreeView.model(domainObject); - } - }; - - function getIdPath(domainObject) { - var context = domainObject && domainObject.getCapability('context'); - - function getId(domainObj) { - return domainObj.getId(); - } - - return context ? context.getPath().map(getId) : []; - } - - TreeNodeView.prototype.value = function (domainObject) { - var activeIdPath = getIdPath(this.activeObject), - selectedIdPath = getIdPath(domainObject); - - if (this.onSelectionPath) { - this.li.find('.js-tree__item').eq(0).removeClass('is-selected'); - if (this.subtreeView) { - this.subtreeView.value(undefined); - } - } - - this.onSelectionPath = - Boolean(domainObject) - && Boolean(this.activeObject) - && (activeIdPath.length <= selectedIdPath.length) - && activeIdPath.every(function (id, index) { - return selectedIdPath[index] === id; - }); - - if (this.onSelectionPath) { - if (activeIdPath.length === selectedIdPath.length) { - this.li.find('.js-tree__item').eq(0).addClass('is-selected'); - } else { - // Expand to reveal the selection - this.toggleView.value(true); - this.subtreeView.value(domainObject); - } - } - }; - - /** - * - * @returns {HTMLElement[]} - */ - TreeNodeView.prototype.elements = function () { - return this.li; - }; - - return TreeNodeView; -}); diff --git a/platform/commonUI/general/src/ui/TreeView.js b/platform/commonUI/general/src/ui/TreeView.js deleted file mode 100644 index 25243ca972..0000000000 --- a/platform/commonUI/general/src/ui/TreeView.js +++ /dev/null @@ -1,141 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define([ - 'zepto', - './TreeNodeView', - '../../res/templates/tree/wait-node.html' -], function ($, TreeNodeView, spinnerTemplate) { - - function TreeView(gestureService, openmct, selectFn) { - this.ul = $('
      '); - this.nodeViews = []; - this.callbacks = []; - this.selectFn = selectFn || this.value.bind(this); - this.gestureService = gestureService; - this.pending = false; - this.openmct = openmct; - } - - TreeView.prototype.newTreeView = function () { - return new TreeView(this.gestureService, this.openmct, this.selectFn); - }; - - TreeView.prototype.setSize = function (sz) { - var nodeView; - - while (this.nodeViews.length < sz) { - nodeView = new TreeNodeView( - this.gestureService, - this.newTreeView.bind(this), - this.selectFn, - this.openmct - ); - this.nodeViews.push(nodeView); - this.ul.append($(nodeView.elements())); - } - - while (this.nodeViews.length > sz) { - nodeView = this.nodeViews.pop(); - $(nodeView.elements()).remove(); - } - }; - - TreeView.prototype.loadComposition = function () { - var self = this, - domainObject = this.activeObject; - - function addNode(domainObj, index) { - self.nodeViews[index].model(domainObj); - } - - function addNodes(domainObjects) { - if (self.pending) { - self.pending = false; - self.nodeViews = []; - self.ul.empty(); - } - - if (domainObject === self.activeObject) { - self.setSize(domainObjects.length); - domainObjects.forEach(addNode); - self.updateNodeViewSelection(); - } - } - - domainObject.useCapability('composition') - .then(addNodes); - }; - - TreeView.prototype.model = function (domainObject) { - if (this.unlisten) { - this.unlisten(); - } - - this.activeObject = domainObject; - this.ul.empty(); - - if (domainObject && domainObject.hasCapability('composition')) { - this.pending = true; - this.ul.append($(spinnerTemplate)); - this.unlisten = domainObject.getCapability('mutation') - .listen(this.loadComposition.bind(this)); - this.loadComposition(domainObject); - } else { - this.setSize(0); - } - }; - - TreeView.prototype.updateNodeViewSelection = function () { - this.nodeViews.forEach(function (nodeView) { - nodeView.value(this.selectedObject); - }.bind(this)); - }; - - TreeView.prototype.value = function (domainObject, event) { - this.selectedObject = domainObject; - this.updateNodeViewSelection(); - this.callbacks.forEach(function (callback) { - callback(domainObject, event); - }); - }; - - TreeView.prototype.observe = function (callback) { - this.callbacks.push(callback); - - return function () { - this.callbacks = this.callbacks.filter(function (c) { - return c !== callback; - }); - }.bind(this); - }; - - /** - * - * @returns {HTMLElement[]} - */ - TreeView.prototype.elements = function () { - return this.ul; - }; - - return TreeView; -}); diff --git a/platform/commonUI/general/test/SplashScreenManagerSpec.js b/platform/commonUI/general/test/SplashScreenManagerSpec.js deleted file mode 100644 index 37f39098c3..0000000000 --- a/platform/commonUI/general/test/SplashScreenManagerSpec.js +++ /dev/null @@ -1,90 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/SplashScreenManager' -], function (SplashScreenManager) { - - describe('SplashScreenManager', function () { - var $document, - splashElement; - - beforeEach(function () { - $document = jasmine.createSpyObj( - '$document', - ['querySelectorAll'] - ); - - splashElement = jasmine.createSpyObj( - 'splashElement', - ['addEventListener'] - ); - - splashElement.parentNode = jasmine.createSpyObj( - 'splashParent', - ['removeChild'] - ); - - splashElement.className = 'some-class-name'; - - $document.querySelectorAll.and.returnValue([splashElement]); - }); - - describe('when element exists', function () { - beforeEach(function () { - $document.querySelectorAll.and.returnValue([splashElement]); - - return new SplashScreenManager([$document]); - }); - - it('adds fade out class', function () { - expect(splashElement.className).toBe('some-class-name fadeout'); - }); - - it('removes the element when the transition ends', function () { - expect(splashElement.addEventListener) - .toHaveBeenCalledWith( - 'transitionend', - jasmine.any(Function) - ); - expect(splashElement.parentNode.removeChild) - .not - .toHaveBeenCalled(); - - splashElement.addEventListener.calls.mostRecent().args[1](); - expect(splashElement.parentNode.removeChild) - .toHaveBeenCalledWith(splashElement); - }); - }); - - it('does not error when element doesn\'t exist', function () { - $document.querySelectorAll.and.returnValue([]); - - function run() { - return new SplashScreenManager([$document]); - } - - expect(run).not.toThrow(); - }); - }); -}); - diff --git a/platform/commonUI/general/test/StyleSheetLoaderSpec.js b/platform/commonUI/general/test/StyleSheetLoaderSpec.js deleted file mode 100644 index cc88a4dd5f..0000000000 --- a/platform/commonUI/general/test/StyleSheetLoaderSpec.js +++ /dev/null @@ -1,120 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/StyleSheetLoader"], - function (StyleSheetLoader) { - - describe("The style sheet loader", function () { - var testStyleSheets, - mockDocument, - mockPlainDocument, - mockHead, - mockElement, - testBundle, - loader; // eslint-disable-line - - beforeEach(function () { - testBundle = { - path: "a/b", - resources: "c" - }; - - testStyleSheets = [ - { - stylesheetUrl: "d.css", - bundle: testBundle - }, - { - stylesheetUrl: "e.css", - bundle: testBundle - }, - { - stylesheetUrl: "f.css", - bundle: testBundle - } - ]; - - mockPlainDocument = - jasmine.createSpyObj("document", ["createElement"]); - mockDocument = [mockPlainDocument]; - mockDocument.find = jasmine.createSpy("$document.find"); - mockHead = jasmine.createSpyObj("head", ["append"]); - mockElement = jasmine.createSpyObj("link", ["setAttribute"]); - - mockDocument.find.and.returnValue(mockHead); - mockPlainDocument.createElement.and.returnValue(mockElement); - - loader = new StyleSheetLoader(testStyleSheets, mockDocument); - }); - - it("appends one link per stylesheet extension", function () { - expect(mockHead.append.calls.count()) - .toEqual(testStyleSheets.length); - }); - - it("appends links to the head", function () { - expect(mockDocument.find).toHaveBeenCalledWith('head'); - }); - - it("adjusts link locations", function () { - expect(mockElement.setAttribute) - .toHaveBeenCalledWith('href', "./a/b/c/d.css"); - }); - - describe("for themed stylesheets", function () { - var testTheme = "test-theme"; - - beforeEach(function () { - testStyleSheets = [{ - stylesheetUrl: "themed.css", - bundle: testBundle, - theme: testTheme - }, { - stylesheetUrl: "bad-theme.css", - bundle: testBundle, - theme: 'bad-theme' - }]; - - loader = new StyleSheetLoader( - testStyleSheets, - mockDocument, - testTheme - ); - }); - - it("includes matching themes", function () { - expect(mockElement.setAttribute) - .toHaveBeenCalledWith('href', "./a/b/c/themed.css"); - }); - - it("excludes mismatching themes", function () { - expect(mockElement.setAttribute) - .not - .toHaveBeenCalledWith('href', "./a/b/c/bad-theme.css"); - }); - }); - - }); - } -); - diff --git a/platform/commonUI/general/test/controllers/ActionGroupControllerSpec.js b/platform/commonUI/general/test/controllers/ActionGroupControllerSpec.js deleted file mode 100644 index fb49e2674c..0000000000 --- a/platform/commonUI/general/test/controllers/ActionGroupControllerSpec.js +++ /dev/null @@ -1,114 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/ActionGroupController"], - function (ActionGroupController) { - - describe("The action group controller", function () { - var mockScope, - mockActions, - controller; - - function mockAction(metadata, index) { - var action = jasmine.createSpyObj( - "action" + index, - ["perform", "getMetadata"] - ); - action.getMetadata.and.returnValue(metadata); - - return action; - } - - beforeEach(function () { - mockActions = jasmine.createSpyObj("action", ["getActions"]); - mockScope = jasmine.createSpyObj("$scope", ["$watch"]); - controller = new ActionGroupController(mockScope); - }); - - it("watches scope that may change applicable actions", function () { - // The action capability - expect(mockScope.$watch).toHaveBeenCalledWith( - "action", - jasmine.any(Function) - ); - // The category of action to load - expect(mockScope.$watch).toHaveBeenCalledWith( - "parameters.category", - jasmine.any(Function) - ); - }); - - it("populates the scope with grouped and ungrouped actions", function () { - mockScope.action = mockActions; - mockScope.parameters = { category: "test" }; - - mockActions.getActions.and.returnValue([ - { - group: "a", - someKey: 0 - }, - { - group: "a", - someKey: 1 - }, - { - group: "b", - someKey: 2 - }, - { - group: "a", - someKey: 3 - }, - { - group: "b", - someKey: 4 - }, - { someKey: 5 }, - { someKey: 6 }, - { - group: "a", - someKey: 7 - }, - { someKey: 8 } - ].map(mockAction)); - - // Call the watch - mockScope.$watch.calls.mostRecent().args[1](); - - // Should have grouped and ungrouped actions in scope now - expect(mockScope.groups.length).toEqual(2); - expect(mockScope.groups[0].length).toEqual(4); // a - expect(mockScope.groups[1].length).toEqual(2); // b - expect(mockScope.ungrouped.length).toEqual(3); // ungrouped - }); - - it("provides empty arrays when no action capability is available", function () { - // Call the watch - mockScope.$watch.calls.mostRecent().args[1](); - - expect(mockScope.groups.length).toEqual(0); - expect(mockScope.ungrouped.length).toEqual(0); - }); - }); - } -); diff --git a/platform/commonUI/general/test/controllers/ClickAwayControllerSpec.js b/platform/commonUI/general/test/controllers/ClickAwayControllerSpec.js deleted file mode 100644 index 62368aa20b..0000000000 --- a/platform/commonUI/general/test/controllers/ClickAwayControllerSpec.js +++ /dev/null @@ -1,92 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/ClickAwayController"], - function (ClickAwayController) { - - describe("The click-away controller", function () { - var mockDocument, - mockTimeout, - controller; - - beforeEach(function () { - mockDocument = jasmine.createSpyObj( - "$document", - ["on", "off"] - ); - mockTimeout = jasmine.createSpy('timeout'); - controller = new ClickAwayController( - mockDocument, - mockTimeout - ); - }); - - it("is initially inactive", function () { - expect(controller.isActive()).toBe(false); - }); - - it("does not listen to the document before being toggled", function () { - expect(mockDocument.on).not.toHaveBeenCalled(); - }); - - it("tracks enabled/disabled state when toggled", function () { - controller.toggle(); - expect(controller.isActive()).toBe(true); - controller.toggle(); - expect(controller.isActive()).toBe(false); - controller.toggle(); - expect(controller.isActive()).toBe(true); - controller.toggle(); - expect(controller.isActive()).toBe(false); - }); - - it("allows active state to be explicitly specified", function () { - controller.setState(true); - expect(controller.isActive()).toBe(true); - controller.setState(true); - expect(controller.isActive()).toBe(true); - controller.setState(false); - expect(controller.isActive()).toBe(false); - controller.setState(false); - expect(controller.isActive()).toBe(false); - }); - - it("registers a mouse listener when activated", function () { - controller.setState(true); - expect(mockDocument.on).toHaveBeenCalled(); - }); - - it("deactivates and detaches listener on document click", function () { - var callback, timeout; - controller.setState(true); - callback = mockDocument.on.calls.mostRecent().args[1]; - callback(); - timeout = mockTimeout.calls.mostRecent().args[0]; - timeout(); - expect(controller.isActive()).toEqual(false); - expect(mockDocument.off).toHaveBeenCalledWith("mouseup", callback); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/controllers/DateTimeFieldControllerSpec.js b/platform/commonUI/general/test/controllers/DateTimeFieldControllerSpec.js deleted file mode 100644 index 8294a1a3a1..0000000000 --- a/platform/commonUI/general/test/controllers/DateTimeFieldControllerSpec.js +++ /dev/null @@ -1,221 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/DateTimeFieldController", "moment"], - function (DateTimeFieldController, moment) { - - var TEST_FORMAT = "YYYY-MM-DD HH:mm:ss"; - - describe("The DateTimeFieldController", function () { - var mockScope, - mockFormatService, - mockFormat, - controller; - - function fireWatch(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']); - mockFormatService = - jasmine.createSpyObj('formatService', ['getFormat']); - mockFormat = jasmine.createSpyObj('format', [ - 'parse', - 'validate', - 'format' - ]); - - mockFormatService.getFormat.and.returnValue(mockFormat); - - mockFormat.validate.and.callFake(function (text) { - return moment.utc(text, TEST_FORMAT).isValid(); - }); - mockFormat.parse.and.callFake(function (text) { - return moment.utc(text, TEST_FORMAT).valueOf(); - }); - mockFormat.format.and.callFake(function (value) { - return moment.utc(value).format(TEST_FORMAT); - }); - - mockScope.ngModel = { testField: 12321 }; - mockScope.field = "testField"; - mockScope.structure = { format: "someFormat" }; - mockScope.ngBlur = jasmine.createSpy('blur'); - - controller = new DateTimeFieldController( - mockScope, - mockFormatService - ); - fireWatch("ngModel[field]", mockScope.ngModel.testField); - }); - - it("updates text from model values", function () { - var testTime = mockFormat.parse("1977-05-25 17:30:00"); - mockScope.ngModel.testField = testTime; - fireWatch("ngModel[field]", testTime); - expect(mockScope.textValue).toEqual("1977-05-25 17:30:00"); - }); - - describe("when valid text is entered", function () { - var newText; - - beforeEach(function () { - newText = "1977-05-25 17:30:00"; - mockScope.textValue = newText; - fireWatch("textValue", newText); - }); - - it("updates models from user-entered text", function () { - expect(mockScope.ngModel.testField) - .toEqual(mockFormat.parse(newText)); - expect(mockScope.textInvalid).toBeFalsy(); - }); - - it("does not indicate a blur event", function () { - expect(mockScope.ngBlur).not.toHaveBeenCalled(); - }); - }); - - describe("when a date is chosen via the date picker", function () { - var newValue; - - beforeEach(function () { - newValue = 12345654321; - mockScope.pickerModel.value = newValue; - fireWatch("pickerModel.value", newValue); - }); - - it("updates models", function () { - expect(mockScope.ngModel.testField).toEqual(newValue); - }); - - it("fires a blur event", function () { - expect(mockScope.ngBlur).toHaveBeenCalled(); - }); - }); - - it("exposes toggle state for date-time picker", function () { - expect(mockScope.picker.active).toBe(false); - }); - - describe("when user input is invalid", function () { - var newText, oldText, oldValue; - - beforeEach(function () { - newText = "Not a date"; - oldValue = mockScope.ngModel.testField; - oldText = mockScope.textValue; - mockScope.textValue = newText; - fireWatch("textValue", newText); - }); - - it("displays error state", function () { - expect(mockScope.textInvalid).toBeTruthy(); - }); - - it("does not modify model state", function () { - expect(mockScope.ngModel.testField).toEqual(oldValue); - }); - - it("does not modify user input", function () { - expect(mockScope.textValue).toEqual(newText); - }); - - it("restores valid text values on request", function () { - mockScope.restoreTextValue(); - expect(mockScope.textValue).toEqual(oldText); - }); - }); - - it("does not modify valid but irregular user input", function () { - // Don't want the controller "fixing" bad or - // irregularly-formatted input out from under - // the user's fingertips. - var newText = "2015-3-3 01:02:04", - oldValue = mockScope.ngModel.testField; - - mockFormat.validate.and.returnValue(true); - mockFormat.parse.and.returnValue(42); - mockScope.textValue = newText; - fireWatch("textValue", newText); - - expect(mockScope.textValue).toEqual(newText); - expect(mockScope.ngModel.testField).toEqual(42); - expect(mockScope.ngModel.testField).not.toEqual(oldValue); - }); - - it("obtains a format from the format service", function () { - fireWatch('structure.format', mockScope.structure.format); - expect(mockFormatService.getFormat) - .toHaveBeenCalledWith(mockScope.structure.format); - }); - - it("throws an error for unknown formats", function () { - mockFormatService.getFormat.and.returnValue(undefined); - expect(function () { - fireWatch("structure.format", "some-format"); - }).toThrow(); - }); - - describe("using the obtained format", function () { - var testValue = 1234321, - testText = "some text"; - - beforeEach(function () { - mockFormat.validate.and.returnValue(true); - mockFormat.parse.and.returnValue(testValue); - mockFormat.format.and.returnValue(testText); - }); - - it("parses user input", function () { - var newText = "some other new text"; - mockScope.textValue = newText; - fireWatch("textValue", newText); - expect(mockFormat.parse).toHaveBeenCalledWith(newText); - expect(mockScope.ngModel.testField).toEqual(testValue); - }); - - it("validates user input", function () { - var newText = "some other new text"; - mockScope.textValue = newText; - fireWatch("textValue", newText); - expect(mockFormat.validate).toHaveBeenCalledWith(newText); - }); - - it("formats model data for display", function () { - var newValue = 42; - mockScope.ngModel.testField = newValue; - fireWatch("ngModel[field]", newValue); - expect(mockFormat.format).toHaveBeenCalledWith(newValue); - expect(mockScope.textValue).toEqual(testText); - }); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js b/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js deleted file mode 100644 index 1a12f46a77..0000000000 --- a/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js +++ /dev/null @@ -1,193 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/DateTimePickerController", "moment"], - function (DateTimePickerController, moment) { - - describe("The DateTimePickerController", function () { - var mockScope, - mockNow, - controller; - - function fireWatch(expr, value) { - mockScope.$watch.calls.all().forEach(function (call) { - if (call.args[0] === expr) { - call.args[1](value); - } - }); - } - - function fireWatchCollection(expr, value) { - mockScope.$watchCollection.calls.all().forEach(function (call) { - if (call.args[0] === expr) { - call.args[1](value); - } - }); - } - - beforeEach(function () { - mockScope = jasmine.createSpyObj( - "$scope", - ["$apply", "$watch", "$watchCollection"] - ); - mockScope.ngModel = {}; - mockScope.field = "testField"; - mockNow = jasmine.createSpy('now'); - controller = new DateTimePickerController(mockScope, mockNow); - }); - - it("watches the model that was passed in", function () { - expect(mockScope.$watch).toHaveBeenCalledWith( - "ngModel[field]", - jasmine.any(Function) - ); - }); - - it("updates value in model when values in scope change", function () { - mockScope.date = { - year: 1998, - month: 0, - day: 6 - }; - mockScope.time = { - hours: 12, - minutes: 34, - seconds: 56 - }; - fireWatchCollection("date", mockScope.date); - expect(mockScope.ngModel[mockScope.field]) - .toEqual(moment.utc("1998-01-06 12:34:56").valueOf()); - }); - - describe("once initialized with model state", function () { - var testTime = moment.utc("1998-01-06 12:34:56").valueOf(); - - beforeEach(function () { - fireWatch("ngModel[field]", testTime); - }); - - it("exposes date/time values in scope", function () { - expect(mockScope.date.year).toEqual(1998); - expect(mockScope.date.month).toEqual(0); // Months are zero-indexed - expect(mockScope.date.day).toEqual(6); - expect(mockScope.time.hours).toEqual(12); - expect(mockScope.time.minutes).toEqual(34); - expect(mockScope.time.seconds).toEqual(56); - }); - - it("provides names for time properties", function () { - Object.keys(mockScope.time).forEach(function (key) { - expect(mockScope.nameFor(key)) - .toEqual(jasmine.any(String)); - }); - }); - - it("provides options for time properties", function () { - Object.keys(mockScope.time).forEach(function (key) { - expect(mockScope.optionsFor(key)) - .toEqual(jasmine.any(Array)); - }); - }); - - it("exposes times to populate calendar as a table", function () { - // Verify that data structure is as expected by template - expect(mockScope.table).toEqual(jasmine.any(Array)); - expect(mockScope.table[0]).toEqual(jasmine.any(Array)); - expect(mockScope.table[0][0]).toEqual({ - year: jasmine.any(Number), - month: jasmine.any(Number), - day: jasmine.any(Number), - dayOfYear: jasmine.any(Number) - }); - }); - - it("contains the current date in its initial table", function () { - var matchingCell; - // Should be able to find the selected date - mockScope.table.forEach(function (row) { - row.forEach(function (cell) { - if (cell.dayOfYear === 6) { - matchingCell = cell; - } - }); - }); - expect(matchingCell).toEqual({ - year: 1998, - month: 0, - day: 6, - dayOfYear: 6 - }); - }); - - it("allows the displayed month to be advanced", function () { - // Around the edges of the displayed calendar we - // may be in previous or subsequent month, so - // test around the middle. - var i, originalMonth = mockScope.table[2][0].month; - - function mod12(month) { - return ((month % 12) + 12) % 12; - } - - for (i = 1; i <= 12; i += 1) { - mockScope.changeMonth(1); - expect(mockScope.table[2][0].month) - .toEqual(mod12(originalMonth + i)); - } - - for (i = 11; i >= -12; i -= 1) { - mockScope.changeMonth(-1); - expect(mockScope.table[2][0].month) - .toEqual(mod12(originalMonth + i)); - } - }); - - it("allows checking if a cell is in the current month", function () { - expect(mockScope.isInCurrentMonth(mockScope.table[2][0])) - .toBe(true); - }); - - it("allows cells to be selected", function () { - mockScope.select(mockScope.table[2][0]); - expect(mockScope.isSelected(mockScope.table[2][0])) - .toBe(true); - mockScope.select(mockScope.table[2][1]); - expect(mockScope.isSelected(mockScope.table[2][0])) - .toBe(false); - expect(mockScope.isSelected(mockScope.table[2][1])) - .toBe(true); - }); - - it("allows cells to be compared", function () { - var table = mockScope.table; - expect(mockScope.dateEquals(table[2][0], table[2][1])) - .toBe(false); - expect(mockScope.dateEquals(table[2][1], table[2][1])) - .toBe(true); - }); - - }); - - }); - } -); diff --git a/platform/commonUI/general/test/controllers/GetterSetterControllerSpec.js b/platform/commonUI/general/test/controllers/GetterSetterControllerSpec.js deleted file mode 100644 index 92a0a5862a..0000000000 --- a/platform/commonUI/general/test/controllers/GetterSetterControllerSpec.js +++ /dev/null @@ -1,83 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/GetterSetterController"], - function (GetterSetterController) { - - describe("The getter-setter controller", function () { - var mockScope, - mockModel, - controller; - - beforeEach(function () { - mockScope = jasmine.createSpyObj("$scope", ["$watch"]); - mockModel = jasmine.createSpy("ngModel"); - mockScope.ngModel = mockModel; - controller = new GetterSetterController(mockScope); - }); - - it("watches for changes to external and internal mode", function () { - expect(mockScope.$watch).toHaveBeenCalledWith( - "ngModel()", - jasmine.any(Function) - ); - expect(mockScope.$watch).toHaveBeenCalledWith( - "getterSetter.value", - jasmine.any(Function) - ); - }); - - it("updates an external function when changes are detected", function () { - mockScope.getterSetter.value = "some new value"; - // Verify precondition - expect(mockScope.ngModel) - .not.toHaveBeenCalledWith("some new value"); - // Fire the matching watcher - mockScope.$watch.calls.all().forEach(function (call) { - if (call.args[0] === "getterSetter.value") { - call.args[1](mockScope.getterSetter.value); - } - }); - // Verify getter-setter was notified - expect(mockScope.ngModel) - .toHaveBeenCalledWith("some new value"); - }); - - it("updates internal state when external changes are detected", function () { - mockScope.ngModel.and.returnValue("some other new value"); - // Verify precondition - expect(mockScope.getterSetter.value).toBeUndefined(); - // Fire the matching watcher - mockScope.$watch.calls.all().forEach(function (call) { - if (call.args[0] === "ngModel()") { - call.args[1]("some other new value"); - } - }); - // Verify state in scope was updated - expect(mockScope.getterSetter.value) - .toEqual("some other new value"); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/controllers/ObjectInspectorControllerSpec.js b/platform/commonUI/general/test/controllers/ObjectInspectorControllerSpec.js deleted file mode 100644 index e56e25c111..0000000000 --- a/platform/commonUI/general/test/controllers/ObjectInspectorControllerSpec.js +++ /dev/null @@ -1,113 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * Created by shale on 08/24/2015. - */ -define( - ["../../src/controllers/ObjectInspectorController"], - function (ObjectInspectorController) { - - describe("The object inspector controller ", function () { - var mockScope, - mockObjectService, - mockPromise, - mockDomainObject, - mockContextCapability, - mockLocationCapability, - controller; - - beforeEach(function () { - mockScope = jasmine.createSpyObj( - "$scope", - ["$watch", "$on"] - ); - - mockObjectService = jasmine.createSpyObj( - "objectService", - ["getObjects"] - ); - mockPromise = jasmine.createSpyObj( - "promise", - ["then"] - ); - mockObjectService.getObjects.and.returnValue(mockPromise); - - mockDomainObject = jasmine.createSpyObj( - "selectedObject", - ["hasCapability", "getCapability", "useCapability", "getModel"] - ); - mockDomainObject.getModel.and.returnValue({location: 'somewhere'}); - mockDomainObject.hasCapability.and.returnValue(true); - - mockContextCapability = jasmine.createSpyObj( - "context capability", - ["getParent"] - ); - mockLocationCapability = jasmine.createSpyObj( - "location capability", - ["isLink"] - ); - - mockDomainObject.getCapability.and.callFake(function (param) { - if (param === 'location') { - return mockLocationCapability; - } else if (param === 'context') { - return mockContextCapability; - } else if (param === 'mutation') { - return { - listen: function () { - return true; - } - }; - } - }); - - mockScope.domainObject = mockDomainObject; - controller = new ObjectInspectorController(mockScope, mockObjectService); - }); - - it("watches for changes to the selected object", function () { - expect(mockScope.$watch).toHaveBeenCalledWith('domainObject', jasmine.any(Function)); - }); - - it("looks for contextual parent objects", function () { - mockScope.$watch.calls.mostRecent().args[1](); - expect(mockContextCapability.getParent).toHaveBeenCalled(); - }); - - it("if link, looks for primary parent objects", function () { - mockLocationCapability.isLink.and.returnValue(true); - - mockScope.$watch.calls.mostRecent().args[1](); - expect(mockDomainObject.getModel).toHaveBeenCalled(); - expect(mockObjectService.getObjects).toHaveBeenCalled(); - mockPromise.then.calls.mostRecent().args[0]({'somewhere': mockDomainObject}); - }); - - it("gets metadata", function () { - mockScope.$watch.calls.mostRecent().args[1](); - expect(mockDomainObject.useCapability).toHaveBeenCalledWith('metadata'); - }); - }); - } -); diff --git a/platform/commonUI/general/test/controllers/SelectorControllerSpec.js b/platform/commonUI/general/test/controllers/SelectorControllerSpec.js deleted file mode 100644 index cb22df32cf..0000000000 --- a/platform/commonUI/general/test/controllers/SelectorControllerSpec.js +++ /dev/null @@ -1,186 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/SelectorController"], - function (SelectorController) { - - describe("The controller for the 'selector' control", function () { - var mockObjectService, - mockScope, - mockDomainObject, - mockType, - mockDomainObjects, - controller; - - function promiseOf(v) { - return (v || {}).then ? v : { - then: function (callback) { - return promiseOf(callback(v)); - } - }; - } - - function makeMockObject(id) { - var mockObject = jasmine.createSpyObj( - 'object-' + id, - ['getId'] - ); - mockObject.getId.and.returnValue(id); - - return mockObject; - } - - beforeEach(function () { - mockObjectService = jasmine.createSpyObj( - 'objectService', - ['getObjects'] - ); - mockScope = jasmine.createSpyObj( - '$scope', - ['$watch', '$watchCollection'] - ); - mockDomainObject = jasmine.createSpyObj( - 'domainObject', - ['getCapability', 'hasCapability'] - ); - mockType = jasmine.createSpyObj( - 'type', - ['instanceOf'] - ); - mockDomainObjects = {}; - - ["ROOT", "abc", "def", "xyz"].forEach(function (id) { - mockDomainObjects[id] = makeMockObject(id); - }); - - mockDomainObject.getCapability.and.returnValue(mockType); - mockObjectService.getObjects.and.returnValue(promiseOf(mockDomainObjects)); - mockScope.field = "testField"; - mockScope.ngModel = {}; - - controller = new SelectorController( - mockObjectService, - mockScope - ); - }); - - it("loads the root object", function () { - expect(mockObjectService.getObjects) - .toHaveBeenCalledWith(["ROOT"]); - }); - - it("watches for changes in selection in left-hand tree", function () { - var testObject = { - a: 123, - b: 456 - }; - // This test is sensitive to ordering of watch calls - expect(mockScope.$watch.calls.count()).toEqual(1); - // Make sure we're watching the correct object - controller.treeModel.selectedObject = testObject; - expect(mockScope.$watch.calls.all()[0].args[0]()).toBe(testObject); - }); - - it("watches for changes in controlled property", function () { - var testValue = ["a", "b", 1, 2]; - // This test is sensitive to ordering of watch calls - expect(mockScope.$watchCollection.calls.count()).toEqual(1); - // Make sure we're watching the correct object - mockScope.ngModel = { testField: testValue }; - expect(mockScope.$watchCollection.calls.all()[0].args[0]()).toBe(testValue); - }); - - it("rejects selection of incorrect types", function () { - mockScope.structure = { type: "someType" }; - mockType.instanceOf.and.returnValue(false); - controller.treeModel.selectedObject = mockDomainObject; - // Fire the watch - mockScope.$watch.calls.all()[0].args[1](mockDomainObject); - // Should have cleared the selection - expect(controller.treeModel.selectedObject).toBeUndefined(); - // Verify interaction (that instanceOf got a useful argument) - expect(mockType.instanceOf).toHaveBeenCalledWith("someType"); - }); - - it("permits selection of matching types", function () { - mockScope.structure = { type: "someType" }; - mockType.instanceOf.and.returnValue(true); - controller.treeModel.selectedObject = mockDomainObject; - // Fire the watch - mockScope.$watch.calls.all()[0].args[1](mockDomainObject); - // Should have preserved the selection - expect(controller.treeModel.selectedObject).toEqual(mockDomainObject); - // Verify interaction (that instanceOf got a useful argument) - expect(mockType.instanceOf).toHaveBeenCalledWith("someType"); - }); - - it("loads objects when the underlying list changes", function () { - var testIds = ["abc", "def", "xyz"]; - // This test is sensitive to ordering of watch calls - expect(mockScope.$watchCollection.calls.count()).toEqual(1); - // Make sure we're watching the correct object - mockScope.ngModel = { testField: testIds }; - // Fire the watch - mockScope.$watchCollection.calls.all()[0].args[1](testIds); - // Should have loaded the corresponding objects - expect(mockObjectService.getObjects).toHaveBeenCalledWith(testIds); - }); - - it("exposes the root object to populate the left-hand tree", function () { - expect(controller.root()).toEqual(mockDomainObjects.ROOT); - }); - - it("adds objects to the underlying model", function () { - expect(mockScope.ngModel.testField).toBeUndefined(); - controller.select(mockDomainObjects.def); - expect(mockScope.ngModel.testField).toEqual(["def"]); - controller.select(mockDomainObjects.abc); - expect(mockScope.ngModel.testField).toEqual(["def", "abc"]); - }); - - it("removes objects to the underlying model", function () { - controller.select(mockDomainObjects.def); - controller.select(mockDomainObjects.abc); - expect(mockScope.ngModel.testField).toEqual(["def", "abc"]); - controller.deselect(mockDomainObjects.def); - expect(mockScope.ngModel.testField).toEqual(["abc"]); - }); - - it("provides a list of currently-selected objects", function () { - // Verify precondition - expect(controller.selected()).toEqual([]); - // Select some objects - controller.select(mockDomainObjects.def); - controller.select(mockDomainObjects.abc); - // Fire the watch for the id changes... - mockScope.$watchCollection.calls.all()[0].args[1]( - mockScope.$watchCollection.calls.all()[0].args[0]() - ); - // Should have loaded and exposed those objects - expect(controller.selected()).toEqual( - [mockDomainObjects.def, mockDomainObjects.abc] - ); - }); - }); - } -); diff --git a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js b/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js deleted file mode 100644 index 96d04ced70..0000000000 --- a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js +++ /dev/null @@ -1,317 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/TimeRangeController", "moment"], - function (TimeRangeController, moment) { - - var SEC = 1000, - MIN = 60 * SEC, - HOUR = 60 * MIN, - DAY = 24 * HOUR; - - describe("The TimeRangeController", function () { - var mockScope, - mockFormatService, - testDefaultFormat, - mockTimeout, - mockNow, - mockFormat, - controller; - - function fireWatch(expr, value) { - mockScope.$watch.calls.all().forEach(function (call) { - if (call.args[0] === expr) { - call.args[1](value); - } - }); - } - - function fireWatchCollection(expr, value) { - mockScope.$watchCollection.calls.all().forEach(function (call) { - if (call.args[0] === expr) { - call.args[1](value); - } - }); - } - - beforeEach(function () { - mockTimeout = function (fn) { - return fn(); - }; - - mockScope = jasmine.createSpyObj( - "$scope", - ["$apply", "$watch", "$watchCollection"] - ); - mockFormatService = jasmine.createSpyObj( - "formatService", - ["getFormat"] - ); - testDefaultFormat = 'utc'; - mockFormat = jasmine.createSpyObj( - "format", - ["validate", "format", "parse"] - ); - - mockFormatService.getFormat.and.returnValue(mockFormat); - - mockFormat.format.and.callFake(function (value) { - return moment.utc(value).format("YYYY-MM-DD HH:mm:ss"); - }); - - mockNow = jasmine.createSpy('now'); - - controller = new TimeRangeController( - mockScope, - mockTimeout, - mockFormatService, - testDefaultFormat, - mockNow - ); - }); - - it("watches the model that was passed in", function () { - expect(mockScope.$watchCollection) - .toHaveBeenCalledWith("ngModel", jasmine.any(Function)); - }); - - it("exposes start time validator", function () { - var testValue = 42000000; - mockScope.formModel = { end: testValue }; - expect(controller.validateStart(testValue + 1)) - .toBe(false); - expect(controller.validateStart(testValue - 60 * 60 * 1000 - 1)) - .toBe(true); - }); - - it("exposes end time validator", function () { - var testValue = 42000000; - mockScope.formModel = { start: testValue }; - expect(controller.validateEnd(testValue - 1)) - .toBe(false); - expect(controller.validateEnd(testValue + 60 * 60 * 1000 + 1)) - .toBe(true); - }); - - describe("when changes are made via form entry", function () { - beforeEach(function () { - mockScope.ngModel = { - outer: { - start: DAY * 2, - end: DAY * 3 - }, - inner: { - start: DAY * 2.25, - end: DAY * 2.75 - } - }; - mockScope.formModel = { - start: DAY * 10000, - end: DAY * 11000 - }; - }); - - it('updates all changed bounds when requested', function () { - fireWatchCollection("formModel", mockScope.formModel); - fireWatch("formModel.start", mockScope.formModel.start); - fireWatch("formModel.end", mockScope.formModel.end); - - expect(mockScope.ngModel.outer.start) - .not.toEqual(mockScope.formModel.start); - expect(mockScope.ngModel.inner.start) - .not.toEqual(mockScope.formModel.start); - - expect(mockScope.ngModel.outer.end) - .not.toEqual(mockScope.formModel.end); - expect(mockScope.ngModel.inner.end) - .not.toEqual(mockScope.formModel.end); - - controller.updateBoundsFromForm(); - - expect(mockScope.ngModel.outer.start) - .toEqual(mockScope.formModel.start); - expect(mockScope.ngModel.inner.start) - .toEqual(mockScope.formModel.start); - - expect(mockScope.ngModel.outer.end) - .toEqual(mockScope.formModel.end); - expect(mockScope.ngModel.inner.end) - .toEqual(mockScope.formModel.end); - }); - - it('updates changed start bound when requested', function () { - fireWatchCollection("formModel", mockScope.formModel); - fireWatch("formModel.start", mockScope.formModel.start); - - expect(mockScope.ngModel.outer.start) - .not.toEqual(mockScope.formModel.start); - expect(mockScope.ngModel.inner.start) - .not.toEqual(mockScope.formModel.start); - - expect(mockScope.ngModel.outer.end) - .not.toEqual(mockScope.formModel.end); - expect(mockScope.ngModel.inner.end) - .not.toEqual(mockScope.formModel.end); - - controller.updateBoundsFromForm(); - - expect(mockScope.ngModel.outer.start) - .toEqual(mockScope.formModel.start); - expect(mockScope.ngModel.inner.start) - .toEqual(mockScope.formModel.start); - - expect(mockScope.ngModel.outer.end) - .not.toEqual(mockScope.formModel.end); - expect(mockScope.ngModel.inner.end) - .not.toEqual(mockScope.formModel.end); - }); - - it('updates changed end bound when requested', function () { - fireWatchCollection("formModel", mockScope.formModel); - fireWatch("formModel.end", mockScope.formModel.end); - - expect(mockScope.ngModel.outer.start) - .not.toEqual(mockScope.formModel.start); - expect(mockScope.ngModel.inner.start) - .not.toEqual(mockScope.formModel.start); - - expect(mockScope.ngModel.outer.end) - .not.toEqual(mockScope.formModel.end); - expect(mockScope.ngModel.inner.end) - .not.toEqual(mockScope.formModel.end); - - controller.updateBoundsFromForm(); - - expect(mockScope.ngModel.outer.start) - .not.toEqual(mockScope.formModel.start); - expect(mockScope.ngModel.inner.start) - .not.toEqual(mockScope.formModel.start); - - expect(mockScope.ngModel.outer.end) - .toEqual(mockScope.formModel.end); - expect(mockScope.ngModel.inner.end) - .toEqual(mockScope.formModel.end); - }); - }); - - describe("when dragged", function () { - beforeEach(function () { - mockScope.ngModel = { - outer: { - start: DAY * 1000, - end: DAY * 1001 - }, - inner: { - start: DAY * 1000 + HOUR * 3, - end: DAY * 1001 - HOUR * 3 - } - }; - mockScope.spanWidth = 1000; - fireWatch("spanWidth", mockScope.spanWidth); - fireWatchCollection("ngModel", mockScope.ngModel); - }); - - it("updates the start time for left drags", function () { - controller.startLeftDrag(); - controller.leftDrag(250); - expect(mockScope.ngModel.inner.start) - .toEqual(DAY * 1000 + HOUR * 9); - }); - - it("updates the end time for right drags", function () { - controller.startRightDrag(); - controller.rightDrag(-250); - expect(mockScope.ngModel.inner.end) - .toEqual(DAY * 1000 + HOUR * 15); - }); - - it("updates both start and end for middle drags", function () { - controller.startMiddleDrag(); - controller.middleDrag(-125); - expect(mockScope.ngModel.inner).toEqual({ - start: DAY * 1000, - end: DAY * 1000 + HOUR * 18 - }); - controller.middleDrag(250); - expect(mockScope.ngModel.inner).toEqual({ - start: DAY * 1000 + HOUR * 6, - end: DAY * 1001 - }); - }); - - it("enforces a minimum inner span", function () { - controller.startRightDrag(); - controller.rightDrag(-9999999); - expect(mockScope.ngModel.inner.end) - .toBeGreaterThan(mockScope.ngModel.inner.start); - }); - }); - - describe("when outer bounds are changed", function () { - beforeEach(function () { - mockScope.ngModel = { - outer: { - start: DAY * 1000, - end: DAY * 1001 - }, - inner: { - start: DAY * 1000 + HOUR * 3, - end: DAY * 1001 - HOUR * 3 - } - }; - mockScope.spanWidth = 1000; - fireWatch("spanWidth", mockScope.spanWidth); - fireWatchCollection("ngModel", mockScope.ngModel); - }); - - it("enforces a minimum inner span when outer span changes", function () { - mockScope.ngModel.outer.end = - mockScope.ngModel.outer.start - DAY * 100; - fireWatch( - "ngModel.outer.end", - mockScope.ngModel.outer.end - ); - expect(mockScope.ngModel.inner.end) - .toBeGreaterThan(mockScope.ngModel.inner.start); - }); - - }); - - it("watches for changes in format selection", function () { - expect(mockFormatService.getFormat) - .not.toHaveBeenCalledWith('test-format'); - fireWatch("parameters.format", 'test-format'); - expect(mockFormatService.getFormat) - .toHaveBeenCalledWith('test-format'); - }); - - it("throws an error for unknown formats", function () { - mockFormatService.getFormat.and.returnValue(undefined); - expect(function () { - fireWatch("parameters.format", "some-format"); - }).toThrow(); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/controllers/ToggleControllerSpec.js b/platform/commonUI/general/test/controllers/ToggleControllerSpec.js deleted file mode 100644 index c47209a929..0000000000 --- a/platform/commonUI/general/test/controllers/ToggleControllerSpec.js +++ /dev/null @@ -1,62 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/ToggleController"], - function (ToggleController) { - - describe("The toggle controller", function () { - var controller; - - beforeEach(function () { - controller = new ToggleController(); - }); - - it("is initially inactive", function () { - expect(controller.isActive()).toBe(false); - }); - - it("tracks enabled/disabled state when toggled", function () { - controller.toggle(); - expect(controller.isActive()).toBe(true); - controller.toggle(); - expect(controller.isActive()).toBe(false); - controller.toggle(); - expect(controller.isActive()).toBe(true); - controller.toggle(); - expect(controller.isActive()).toBe(false); - }); - - it("allows active state to be explicitly specified", function () { - controller.setState(true); - expect(controller.isActive()).toBe(true); - controller.setState(true); - expect(controller.isActive()).toBe(true); - controller.setState(false); - expect(controller.isActive()).toBe(false); - controller.setState(false); - expect(controller.isActive()).toBe(false); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/controllers/TreeNodeControllerSpec.js b/platform/commonUI/general/test/controllers/TreeNodeControllerSpec.js deleted file mode 100644 index 559b8edd11..0000000000 --- a/platform/commonUI/general/test/controllers/TreeNodeControllerSpec.js +++ /dev/null @@ -1,209 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/TreeNodeController"], - function (TreeNodeController) { - - describe("The tree node controller", function () { - var mockScope, - mockTimeout, - mockDomainObject, - controller; - - function TestObject(id, context) { - return { - getId: function () { - return id; - }, - getCapability: function (key) { - return key === 'context' ? context : undefined; - } - }; - } - - beforeEach(function () { - mockScope = jasmine.createSpyObj("$scope", ["$watch", "$on", "$emit"]); - mockTimeout = jasmine.createSpy("$timeout"); - mockDomainObject = jasmine.createSpyObj( - "domainObject", - ["getId", "getCapability", "getModel", "useCapability"] - ); - - controller = new TreeNodeController(mockScope, mockTimeout); - }); - - it("allows tracking of expansion state", function () { - // The tree node tracks whether or not it has ever - // been expanded in order to lazily load the expanded - // portion of the tree. - expect(controller.hasBeenExpanded()).toBeFalsy(); - controller.trackExpansion(); - - // Expansion is tracked on a timeout, because too - // much expansion can result in an unstable digest. - expect(mockTimeout).toHaveBeenCalled(); - mockTimeout.calls.mostRecent().args[0](); - - expect(controller.hasBeenExpanded()).toBeTruthy(); - controller.trackExpansion(); - expect(controller.hasBeenExpanded()).toBeTruthy(); - }); - - it("tracks whether or not the represented object is currently navigated-to", function () { - // This is needed to highlight the current selection - var mockContext = jasmine.createSpyObj( - "context", - ["getParent", "getPath", "getRoot"] - ), - obj = new TestObject("test-object", mockContext); - - mockContext.getPath.and.returnValue([obj]); - - // Verify precondition - expect(controller.isSelected()).toBeFalsy(); - - // Change the represented domain object - mockScope.domainObject = obj; - - // Invoke the watch with the new selection - mockScope.$watch.calls.all()[0].args[1](obj); - - expect(controller.isSelected()).toBeTruthy(); - }); - - it("expands a node if it is on the navigation path", function () { - var mockParentContext = jasmine.createSpyObj( - "parentContext", - ["getParent", "getPath", "getRoot"] - ), - mockChildContext = jasmine.createSpyObj( - "childContext", - ["getParent", "getPath", "getRoot"] - ), - parent = new TestObject("parent", mockParentContext), - child = new TestObject("child", mockChildContext); - - mockChildContext.getParent.and.returnValue(parent); - mockChildContext.getPath.and.returnValue([parent, child]); - mockParentContext.getPath.and.returnValue([parent]); - - // Set up such that we are on, but not at the end of, a path - mockScope.ngModel = { selectedObject: child }; - mockScope.domainObject = parent; - mockScope.toggle = jasmine.createSpyObj("toggle", ["setState"]); - - // Invoke the watch with the new selection - mockScope.$watch.calls.all()[0].args[1](child); - - // Expansion is tracked on a timeout, because too - // much expansion can result in an unstable digest. - // Trigger that timeout. - expect(mockTimeout).toHaveBeenCalled(); - mockTimeout.calls.mostRecent().args[0](); - - expect(mockScope.toggle.setState).toHaveBeenCalledWith(true); - expect(controller.hasBeenExpanded()).toBeTruthy(); - expect(controller.isSelected()).toBeFalsy(); - - }); - - it("does not expand a node if it is not on the navigation path", function () { - var mockParentContext = jasmine.createSpyObj( - "parentContext", - ["getParent", "getPath", "getRoot"] - ), - mockChildContext = jasmine.createSpyObj( - "childContext", - ["getParent", "getPath", "getRoot"] - ), - parent = new TestObject("parent", mockParentContext), - child = new TestObject("child", mockChildContext); - - mockChildContext.getParent.and.returnValue(parent); - mockChildContext.getPath.and.returnValue([child, child]); - mockParentContext.getPath.and.returnValue([parent]); - - // Set up such that we are on, but not at the end of, a path - mockScope.ngModel = { selectedObject: child }; - mockScope.domainObject = parent; - mockScope.toggle = jasmine.createSpyObj("toggle", ["setState"]); - - // Invoke the watch with the new selection - mockScope.$watch.calls.all()[0].args[1](child); - - // Expansion is tracked on a timeout, because too - // much expansion can result in an unstable digest. - // We want to make sure no timeouts are pending here. - expect(mockTimeout).not.toHaveBeenCalled(); - expect(controller.hasBeenExpanded()).toBeFalsy(); - expect(controller.isSelected()).toBeFalsy(); - }); - - it("does not expand a node if no context is available", function () { - var mockParentContext = jasmine.createSpyObj( - "parentContext", - ["getParent", "getPath", "getRoot"] - ), - mockChildContext = jasmine.createSpyObj( - "childContext", - ["getParent", "getPath", "getRoot"] - ), - parent = new TestObject("parent", mockParentContext), - child = new TestObject("child", undefined); - - mockChildContext.getParent.and.returnValue(parent); - mockChildContext.getPath.and.returnValue([parent, child]); - mockParentContext.getPath.and.returnValue([parent]); - - // Set up such that we are on, but not at the end of, a path - mockScope.ngModel = { selectedObject: child }; - mockScope.domainObject = parent; - mockScope.toggle = jasmine.createSpyObj("toggle", ["setState"]); - - // Invoke the watch with the new selection - mockScope.$watch.calls.all()[0].args[1](child); - - expect(mockScope.toggle.setState).not.toHaveBeenCalled(); - expect(controller.hasBeenExpanded()).toBeFalsy(); - expect(controller.isSelected()).toBeFalsy(); - - }); - - it("exposes selected objects in scope", function () { - mockScope.domainObject = mockDomainObject; - mockScope.ngModel = {}; - controller.select(); - expect(mockScope.ngModel.selectedObject) - .toEqual(mockDomainObject); - }); - - it("invokes optional callbacks upon selection", function () { - mockScope.parameters = - { callback: jasmine.createSpy('callback') }; - controller.select(); - expect(mockScope.parameters.callback).toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/controllers/ViewSwitcherControllerSpec.js b/platform/commonUI/general/test/controllers/ViewSwitcherControllerSpec.js deleted file mode 100644 index 0a39708e16..0000000000 --- a/platform/commonUI/general/test/controllers/ViewSwitcherControllerSpec.js +++ /dev/null @@ -1,155 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * MCTRepresentationSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/controllers/ViewSwitcherController"], - function (ViewSwitcherController) { - - describe("The view switcher controller", function () { - var mockScope, - mockTimeout, - controller; - - beforeEach(function () { - mockScope = jasmine.createSpyObj("$scope", ["$watch"]); - mockTimeout = jasmine.createSpy("$timeout"); - mockTimeout.and.callFake(function (cb) { - cb(); - }); - mockScope.ngModel = {}; - controller = new ViewSwitcherController(mockScope, mockTimeout); - }); - - it("watches for changes in applicable views", function () { - // The view capability is used by associated - // representations, so "view" in scope should always - // be the list of applicable views. The view switcher - // controller should be watching this. - expect(mockScope.$watch).toHaveBeenCalledWith( - "view", - jasmine.any(Function) - ); - }); - - it("maintains the current selection when views change", function () { - var views = [ - { - key: "a", - name: "View A" - }, - { - key: "b", - name: "View B" - }, - { - key: "c", - name: "View C" - }, - { - key: "d", - name: "View D" - } - ]; - mockScope.$watch.calls.mostRecent().args[1](views); - mockScope.ngModel.selected = views[1]; - - // Change the set of applicable views - mockScope.$watch.calls.mostRecent().args[1]([ - { - key: "a", - name: "View A" - }, - { - key: "b", - name: "View B" - }, - { - key: "x", - name: "View X" - } - ]); - - // "b" is still in there, should remain selected - expect(mockScope.ngModel.selected).toEqual(views[1]); - }); - - it("chooses a default if a selected view becomes inapplicable", function () { - var views = [ - { - key: "a", - name: "View A" - }, - { - key: "b", - name: "View B" - }, - { - key: "c", - name: "View C" - }, - { - key: "d", - name: "View D" - } - ]; - mockScope.$watch.calls.mostRecent().args[1](views); - mockScope.ngModel.selected = views[1]; - - // Change the set of applicable views - mockScope.$watch.calls.mostRecent().args[1]([ - { - key: "a", - name: "View A" - }, - { - key: "c", - name: "View C" - }, - { - key: "x", - name: "View X" - } - ]); - - // "b" is still in there, should remain selected - expect(mockScope.ngModel.selected).not.toEqual(views[1]); - }); - - // Use of a timeout avoids infinite digest problems when deeply - // nesting switcher-driven views (e.g. in a layout.) See WTD-689 - it("updates initial selection on a timeout", function () { - // Verify precondition - expect(mockTimeout).not.toHaveBeenCalled(); - - // Invoke the watch for set of views - mockScope.$watch.calls.mostRecent().args[1]([]); - - // Should have run on a timeout - expect(mockTimeout).toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/directives/MCTClickElsewhereSpec.js b/platform/commonUI/general/test/directives/MCTClickElsewhereSpec.js deleted file mode 100644 index 73a89b7a38..0000000000 --- a/platform/commonUI/general/test/directives/MCTClickElsewhereSpec.js +++ /dev/null @@ -1,129 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define( - ["../../src/directives/MCTClickElsewhere"], - function (MCTClickElsewhere) { - - var JQLITE_METHODS = ["on", "off", "find", "parent"]; - - describe("The mct-click-elsewhere directive", function () { - var mockDocument, - mockScope, - mockElement, - testAttrs, - mockBody, - mockPlainEl, - testRect, - mctClickElsewhere; - - function testEvent(x, y) { - return { - clientX: x, - clientY: y, - preventDefault: jasmine.createSpy("preventDefault") - }; - } - - beforeEach(function () { - mockDocument = - jasmine.createSpyObj("$document", JQLITE_METHODS); - mockScope = - jasmine.createSpyObj("$scope", ["$eval", "$apply", "$on"]); - mockElement = - jasmine.createSpyObj("element", JQLITE_METHODS); - mockBody = - jasmine.createSpyObj("body", JQLITE_METHODS); - mockPlainEl = - jasmine.createSpyObj("htmlElement", ["getBoundingClientRect"]); - - testAttrs = { - mctClickElsewhere: "some Angular expression" - }; - testRect = { - left: 20, - top: 42, - width: 60, - height: 75 - }; - mockElement[0] = mockPlainEl; - mockPlainEl.getBoundingClientRect.and.returnValue(testRect); - - mockDocument.find.and.returnValue(mockBody); - - mctClickElsewhere = new MCTClickElsewhere(mockDocument); - mctClickElsewhere.link(mockScope, mockElement, testAttrs); - }); - - it("is valid as an attribute", function () { - expect(mctClickElsewhere.restrict).toEqual("A"); - }); - - it("detaches listeners when destroyed", function () { - expect(mockBody.off).not.toHaveBeenCalled(); - mockScope.$on.calls.all().forEach(function (call) { - if (call.args[0] === '$destroy') { - call.args[1](); - } - }); - expect(mockBody.off).toHaveBeenCalled(); - expect(mockBody.off.calls.mostRecent().args) - .toEqual(mockBody.on.calls.mostRecent().args); - }); - - it("listens for mousedown on the document's body", function () { - expect(mockBody.on) - .toHaveBeenCalledWith('mousedown', jasmine.any(Function)); - }); - - describe("when a click occurs outside the element's bounds", function () { - beforeEach(function () { - mockBody.on.calls.mostRecent().args[1](testEvent( - testRect.left + testRect.width + 10, - testRect.top + testRect.height + 10 - )); - }); - - it("triggers an evaluation of its related Angular expression", function () { - expect(mockScope.$apply).toHaveBeenCalled(); - mockScope.$apply.calls.mostRecent().args[0](); - expect(mockScope.$eval) - .toHaveBeenCalledWith(testAttrs.mctClickElsewhere); - }); - }); - - describe("when a click occurs within the element's bounds", function () { - beforeEach(function () { - mockBody.on.calls.mostRecent().args[1](testEvent( - testRect.left + testRect.width / 2, - testRect.top + testRect.height / 2 - )); - }); - - it("triggers no evaluation", function () { - expect(mockScope.$eval).not.toHaveBeenCalled(); - }); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/directives/MCTContainerSpec.js b/platform/commonUI/general/test/directives/MCTContainerSpec.js deleted file mode 100644 index 445f4dfdfd..0000000000 --- a/platform/commonUI/general/test/directives/MCTContainerSpec.js +++ /dev/null @@ -1,94 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define( - ["../../src/directives/MCTContainer"], - function (MCTContainer) { - - describe("The mct-container directive", function () { - var testContainers = [ - { - bundle: { - path: "a", - resources: "b" - }, - template: "
      foo
      ", - key: "abc" - }, - { - bundle: { - path: "x", - resources: "y" - }, - template: "bar", - key: "xyz", - attributes: ["someAttr", "someOtherAttr"] - } - ], - mctContainer; - - beforeEach(function () { - mctContainer = new MCTContainer(testContainers); - }); - - it("is applicable to elements", function () { - expect(mctContainer.restrict).toEqual("E"); - }); - - it("creates a new (non-isolate) scope", function () { - expect(mctContainer.scope).toBe(true); - }); - - it("chooses a template based on key", function () { - expect(mctContainer.template( - undefined, - { key: "abc" } - )).toEqual(testContainers[0].template); - - expect(mctContainer.template( - undefined, - { key: "xyz" } - )).toEqual(testContainers[1].template); - }); - - it("copies attributes needed by the container", function () { - var scope = {}; - - mctContainer.link( - scope, - undefined, - { - key: "xyz", - someAttr: "some value", - someOtherAttr: "some other value", - someExtraAttr: "should not be present" - } - ); - - expect(scope.container.someAttr).toEqual("some value"); - expect(scope.container.someOtherAttr).toEqual("some other value"); - expect(scope.container.someExtraAttr).toBeUndefined(); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/directives/MCTDragSpec.js b/platform/commonUI/general/test/directives/MCTDragSpec.js deleted file mode 100644 index f6dd53de8c..0000000000 --- a/platform/commonUI/general/test/directives/MCTDragSpec.js +++ /dev/null @@ -1,303 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define( - ["../../src/directives/MCTDrag"], - function (MCTDrag) { - - var JQLITE_METHODS = ["on", "off", "find"]; - - describe("The mct-drag directive in Mobile", function () { - var mockDocument, - mockAgentService, - mockScope, - mockElement, - testAttrs, - mockBody, - mctDrag; - - function testEvent(x, y) { - return { - pageX: x, - pageY: y, - preventDefault: jasmine.createSpy("preventDefault") - }; - } - - beforeEach(function () { - mockDocument = - jasmine.createSpyObj("$document", JQLITE_METHODS); - mockAgentService = - jasmine.createSpyObj("agentService", ["isMobile"]); - mockScope = - jasmine.createSpyObj("$scope", ["$eval", "$apply"]); - mockElement = - jasmine.createSpyObj("element", JQLITE_METHODS); - mockBody = - jasmine.createSpyObj("body", JQLITE_METHODS); - - testAttrs = { - mctDragDown: "starting a drag", - mctDrag: "continuing a drag", - mctDragUp: "ending a drag" - }; - - mockDocument.find.and.returnValue(mockBody); - mockAgentService.isMobile.and.returnValue(true); - - mctDrag = new MCTDrag(mockDocument, mockAgentService); - mctDrag.link(mockScope, mockElement, testAttrs); - }); - - it("is valid as an attribute", function () { - expect(mctDrag.restrict).toEqual("A"); - }); - - it("listens for touchstart on its element", function () { - expect(mockElement.on).toHaveBeenCalledWith( - "touchstart", - jasmine.any(Function) - ); - - // Verify no interactions with body as well - expect(mockBody.on).not.toHaveBeenCalled(); - }); - - it("invokes mctDragDown when dragging begins", function () { - var event = testEvent(42, 60); - mockElement.on.calls.mostRecent().args[1](event); - expect(mockScope.$eval).toHaveBeenCalledWith( - testAttrs.mctDragDown, - { - delta: [0, 0], - $event: event - } - ); - }); - - it("listens for touchmove after dragging begins", function () { - mockElement.on.calls.mostRecent().args[1](testEvent(42, 60)); - expect(mockBody.on).toHaveBeenCalledWith( - "touchmove", - jasmine.any(Function) - ); - expect(mockBody.on).toHaveBeenCalledWith( - "touchend", - jasmine.any(Function) - ); - }); - - it("invokes mctDrag expression during drag", function () { - var event; - - mockElement.on.calls.mostRecent().args[1](testEvent(42, 60)); - - // Find and invoke the touchmove listener - mockBody.on.calls.all().forEach(function (call) { - if (call.args[0] === 'touchmove') { - call.args[1](event = testEvent(52, 200)); - } - }); - - // Should have passed that delta to mct-drag expression - expect(mockScope.$eval).toHaveBeenCalledWith( - testAttrs.mctDrag, - { - delta: [10, 140], - $event: event - } - ); - }); - - it("invokes mctDragUp expression after drag", function () { - var event; - - mockElement.on.calls.mostRecent().args[1](testEvent(42, 60)); - - // Find and invoke the touchmove listener - mockBody.on.calls.all().forEach(function (call) { - if (call.args[0] === 'touchmove') { - call.args[1](testEvent(52, 200)); - } - }); - // Find and invoke the touchmove listener - mockBody.on.calls.all().forEach(function (call) { - if (call.args[0] === 'touchend') { - call.args[1](event = testEvent(40, 71)); - } - }); - - // Should have passed that delta to mct-drag-up expression - // and that delta should have been relative to the - // initial position - expect(mockScope.$eval).toHaveBeenCalledWith( - testAttrs.mctDragUp, - { - delta: [-2, 11], - $event: event - } - ); - - // Should also have unregistered listeners - expect(mockBody.off).toHaveBeenCalled(); - }); - - }); - - describe("The mct-drag directive in Desktop", function () { - var mockDocument, - mockAgentService, - mockScope, - mockElement, - testAttrs, - mockBody, - mctDrag; - - function testEvent(x, y) { - return { - pageX: x, - pageY: y, - preventDefault: jasmine.createSpy("preventDefault") - }; - } - - beforeEach(function () { - mockDocument = - jasmine.createSpyObj("$document", JQLITE_METHODS); - mockAgentService = - jasmine.createSpyObj("agentService", ["isMobile"]); - mockScope = - jasmine.createSpyObj("$scope", ["$eval", "$apply"]); - mockElement = - jasmine.createSpyObj("element", JQLITE_METHODS); - mockBody = - jasmine.createSpyObj("body", JQLITE_METHODS); - - testAttrs = { - mctDragDown: "starting a drag", - mctDrag: "continuing a drag", - mctDragUp: "ending a drag" - }; - - mockDocument.find.and.returnValue(mockBody); - mockAgentService.isMobile.and.returnValue(false); - - mctDrag = new MCTDrag(mockDocument, mockAgentService); - mctDrag.link(mockScope, mockElement, testAttrs); - }); - - it("is valid as an attribute", function () { - expect(mctDrag.restrict).toEqual("A"); - }); - - it("listens for mousedown on its element", function () { - expect(mockElement.on).toHaveBeenCalledWith( - "mousedown", - jasmine.any(Function) - ); - - // Verify no interactions with body as well - expect(mockBody.on).not.toHaveBeenCalled(); - }); - - it("invokes mctDragDown when dragging begins", function () { - var event = testEvent(42, 60); - mockElement.on.calls.mostRecent().args[1](event); - expect(mockScope.$eval).toHaveBeenCalledWith( - testAttrs.mctDragDown, - { - delta: [0, 0], - $event: event - } - ); - }); - - it("listens for mousemove after dragging begins", function () { - mockElement.on.calls.mostRecent().args[1](testEvent(42, 60)); - expect(mockBody.on).toHaveBeenCalledWith( - "mousemove", - jasmine.any(Function) - ); - expect(mockBody.on).toHaveBeenCalledWith( - "mouseup", - jasmine.any(Function) - ); - }); - - it("invokes mctDrag expression during drag", function () { - var event; - - mockElement.on.calls.mostRecent().args[1](testEvent(42, 60)); - - // Find and invoke the mousemove listener - mockBody.on.calls.all().forEach(function (call) { - if (call.args[0] === 'mousemove') { - call.args[1](event = testEvent(52, 200)); - } - }); - - // Should have passed that delta to mct-drag expression - expect(mockScope.$eval).toHaveBeenCalledWith( - testAttrs.mctDrag, - { - delta: [10, 140], - $event: event - } - ); - }); - - it("invokes mctDragUp expression after drag", function () { - var event; - - mockElement.on.calls.mostRecent().args[1](testEvent(42, 60)); - - // Find and invoke the mousemove listener - mockBody.on.calls.all().forEach(function (call) { - if (call.args[0] === 'mousemove') { - call.args[1](testEvent(52, 200)); - } - }); - // Find and invoke the mousemove listener - mockBody.on.calls.all().forEach(function (call) { - if (call.args[0] === 'mouseup') { - call.args[1](event = testEvent(40, 71)); - } - }); - - // Should have passed that delta to mct-drag-up expression - // and that delta should have been relative to the - // initial position - expect(mockScope.$eval).toHaveBeenCalledWith( - testAttrs.mctDragUp, - { - delta: [-2, 11], - $event: event - } - ); - - // Should also have unregistered listeners - expect(mockBody.off).toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/directives/MCTPopupSpec.js b/platform/commonUI/general/test/directives/MCTPopupSpec.js deleted file mode 100644 index 67e81f3e4d..0000000000 --- a/platform/commonUI/general/test/directives/MCTPopupSpec.js +++ /dev/null @@ -1,132 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define( - ["../../src/directives/MCTPopup"], - function (MCTPopup) { - - var JQLITE_METHODS = [ - "on", - "off", - "find", - "parent", - "css", - "addClass", - "append" - ]; - - describe("The mct-popup directive", function () { - var mockCompile, - mockPopupService, - mockPopup, - mockScope, - mockElement, - testAttrs, - mockTransclude, - mockParentEl, - mockNewElement, - testRect, - mctPopup; - - beforeEach(function () { - mockCompile = - jasmine.createSpy("$compile"); - mockPopupService = - jasmine.createSpyObj("popupService", ["display"]); - mockPopup = - jasmine.createSpyObj("popup", ["dismiss"]); - mockScope = - jasmine.createSpyObj("$scope", ["$eval", "$apply", "$on"]); - mockElement = - jasmine.createSpyObj("element", JQLITE_METHODS); - mockTransclude = - jasmine.createSpy("transclude"); - mockParentEl = - jasmine.createSpyObj("parent", ["getBoundingClientRect"]); - mockNewElement = - jasmine.createSpyObj("newElement", JQLITE_METHODS); - - testAttrs = { - mctClickElsewhere: "some Angular expression" - }; - testRect = { - left: 20, - top: 42, - width: 60, - height: 75 - }; - - mockCompile.and.callFake(function () { - var mockFn = jasmine.createSpy(); - mockFn.and.returnValue(mockNewElement); - - return mockFn; - }); - mockElement.parent.and.returnValue([mockParentEl]); - mockParentEl.getBoundingClientRect.and.returnValue(testRect); - mockPopupService.display.and.returnValue(mockPopup); - - mctPopup = new MCTPopup(mockCompile, mockPopupService); - - mctPopup.link( - mockScope, - mockElement, - testAttrs, - null, - mockTransclude - ); - }); - - it("is valid as an element", function () { - expect(mctPopup.restrict).toEqual("E"); - }); - - describe("creates an element which", function () { - it("displays as a popup", function () { - expect(mockPopupService.display).toHaveBeenCalledWith( - mockNewElement, - [testRect.left, testRect.top] - ); - }); - - it("displays transcluded content", function () { - var mockClone = - jasmine.createSpyObj('clone', JQLITE_METHODS); - mockTransclude.calls.mostRecent().args[0](mockClone); - expect(mockNewElement.append) - .toHaveBeenCalledWith(mockClone); - }); - - it("is removed when its containing scope is destroyed", function () { - expect(mockPopup.dismiss).not.toHaveBeenCalled(); - mockScope.$on.calls.all().forEach(function (call) { - if (call.args[0] === '$destroy') { - call.args[1](); - } - }); - expect(mockPopup.dismiss).toHaveBeenCalled(); - }); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/directives/MCTResizeSpec.js b/platform/commonUI/general/test/directives/MCTResizeSpec.js deleted file mode 100644 index 509c4c6b7d..0000000000 --- a/platform/commonUI/general/test/directives/MCTResizeSpec.js +++ /dev/null @@ -1,166 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define( - ["../../src/directives/MCTResize"], - function (MCTResize) { - - describe("The mct-resize directive", function () { - var mockTimeout, - mockScope, - testElement, - testAttrs, - mctResize; - - beforeEach(function () { - mockTimeout = jasmine.createSpy("$timeout"); - mockScope = jasmine.createSpyObj("$scope", ["$eval", "$on", "$apply"]); - - testElement = { - offsetWidth: 100, - offsetHeight: 200 - }; - testAttrs = { mctResize: "some-expr" }; - - mctResize = new MCTResize(mockTimeout); - }); - - it("is applicable as an attribute only", function () { - expect(mctResize.restrict).toEqual("A"); - }); - - it("starts tracking size changes upon link", function () { - expect(mockTimeout).not.toHaveBeenCalled(); - mctResize.link(mockScope, [testElement], testAttrs); - expect(mockTimeout).toHaveBeenCalledWith( - jasmine.any(Function), - jasmine.any(Number), - false - ); - expect(mockScope.$eval).toHaveBeenCalledWith( - testAttrs.mctResize, - { - bounds: { - width: 100, - height: 200 - } - } - ); - }); - - it("reports size changes on a timeout", function () { - mctResize.link(mockScope, [testElement], testAttrs); - - // Change the element's apparent size - testElement.offsetWidth = 300; - testElement.offsetHeight = 350; - - // Shouldn't know about this yet... - expect(mockScope.$eval).not.toHaveBeenCalledWith( - testAttrs.mctResize, - { - bounds: { - width: 300, - height: 350 - } - } - ); - - // Fire the timeout - mockTimeout.calls.mostRecent().args[0](); - - // Should have triggered an evaluation of mctResize - // with the new width & height - expect(mockScope.$eval).toHaveBeenCalledWith( - testAttrs.mctResize, - { - bounds: { - width: 300, - height: 350 - } - } - ); - }); - - it("stops size checking for size changes after destroy", function () { - mctResize.link(mockScope, [testElement], testAttrs); - - // First, make sure there's a $destroy observer - expect(mockScope.$on) - .toHaveBeenCalledWith("$destroy", jasmine.any(Function)); - - // Should have scheduled the first timeout - expect(mockTimeout.calls.count()).toEqual(1); - - // Fire the timeout - mockTimeout.calls.mostRecent().args[0](); - - // Should have scheduled another timeout - expect(mockTimeout.calls.count()).toEqual(2); - - // Broadcast a destroy event - mockScope.$on.calls.mostRecent().args[1](); - - testElement.offsetWidth = 300; - testElement.offsetHeight = 350; - mockScope.$eval.calls.reset(); - - // Fire the timeout - mockTimeout.calls.mostRecent().args[0](); - - // Should NOT have scheduled another timeout - expect(mockTimeout.calls.count()).toEqual(2); - expect(mockScope.$eval).not.toHaveBeenCalled(); - }); - - it("triggers a digest cycle when size changes", function () { - var applyCount; - mctResize.link(mockScope, [testElement], testAttrs); - applyCount = mockScope.$apply.calls.count(); - - // Change the element's apparent size - testElement.offsetWidth = 300; - testElement.offsetHeight = 350; - - // Fire the timeout - mockTimeout.calls.mostRecent().args[0](); - - // No more apply calls - expect(mockScope.$apply.calls.count()) - .toBeGreaterThan(applyCount); - }); - - it("does not trigger a digest cycle when size does not change", function () { - var applyCount; - mctResize.link(mockScope, [testElement], testAttrs); - applyCount = mockScope.$apply.calls.count(); - - // Fire the timeout - mockTimeout.calls.mostRecent().args[0](); - - // No more apply calls - expect(mockScope.$apply.calls.count()).toEqual(applyCount); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/directives/MCTScrollSpec.js b/platform/commonUI/general/test/directives/MCTScrollSpec.js deleted file mode 100644 index 7213fd5945..0000000000 --- a/platform/commonUI/general/test/directives/MCTScrollSpec.js +++ /dev/null @@ -1,114 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ -define( - ['../../src/directives/MCTScroll'], - function (MCTScroll) { - - var EVENT_PROPERTY = "testProperty", - ATTRIBUTE = "testAttribute", - EXPRESSION = "some.expression"; - - // MCTScroll is the commonality between mct-scroll-x and - // mct-scroll-y; it gets the event property to watch and - // the attribute which contains the associated assignable - // expression. - describe("An mct-scroll-* directive", function () { - var mockParse, - mockParsed, - mockScope, - mockElement, - testAttrs, - mctScroll; - - beforeEach(function () { - mockParse = jasmine.createSpy('$parse'); - mockParsed = jasmine.createSpy('parsed'); - mockParsed.assign = jasmine.createSpy('assign'); - - mockScope = jasmine.createSpyObj('$scope', ['$watch', '$apply']); - mockElement = [{ testProperty: 42 }]; - mockElement.on = jasmine.createSpy('on'); - - mockParse.and.returnValue(mockParsed); - - testAttrs = {}; - testAttrs[ATTRIBUTE] = EXPRESSION; - - mctScroll = new MCTScroll( - mockParse, - EVENT_PROPERTY, - ATTRIBUTE - ); - mctScroll.link(mockScope, mockElement, testAttrs); - }); - - it("is available for attributes", function () { - expect(mctScroll.restrict).toEqual('A'); - }); - - it("does not create an isolate scope", function () { - expect(mctScroll.scope).toBeUndefined(); - }); - - it("watches for changes in observed expression", function () { - expect(mockScope.$watch).toHaveBeenCalledWith( - EXPRESSION, - jasmine.any(Function) - ); - // Should have been only watch (other tests need this to be true) - expect(mockScope.$watch.calls.count()).toEqual(1); - }); - - it("listens for scroll events", function () { - expect(mockElement.on).toHaveBeenCalledWith( - 'scroll', - jasmine.any(Function) - ); - // Should have been only listener (other tests need this to be true) - expect(mockElement.on.calls.count()).toEqual(1); - }); - - it("publishes initial scroll state", function () { - expect(mockParse).toHaveBeenCalledWith(EXPRESSION); - expect(mockParsed.assign).toHaveBeenCalledWith(mockScope, 42); - }); - - it("updates scroll state when scope changes", function () { - mockScope.$watch.calls.mostRecent().args[1](64); - expect(mockElement[0].testProperty).toEqual(64); - }); - - it("updates scope when scroll state changes", function () { - mockElement[0].testProperty = 12321; - mockElement.on.calls.mostRecent().args[1]({ target: mockElement[0] }); - expect(mockParsed.assign).toHaveBeenCalledWith(mockScope, 12321); - expect(mockScope.$apply).toHaveBeenCalledWith(EXPRESSION); - }); - - // This would trigger an infinite digest exception - it("does not call $apply during construction", function () { - expect(mockScope.$apply).not.toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/directives/MCTSplitPaneSpec.js b/platform/commonUI/general/test/directives/MCTSplitPaneSpec.js deleted file mode 100644 index 6109ab0566..0000000000 --- a/platform/commonUI/general/test/directives/MCTSplitPaneSpec.js +++ /dev/null @@ -1,233 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define( - ["../../src/directives/MCTSplitPane"], - function (MCTSplitPane) { - - var JQLITE_METHODS = [ - 'on', - 'addClass', - 'children', - 'eq', - 'toggleClass', - 'css' - ]; - - describe("The mct-split-pane directive", function () { - var mockParse, - mockLog, - mockInterval, - mockParsed, - mctSplitPane, - mockWindow = {}; - - beforeEach(function () { - mockParse = jasmine.createSpy('$parse'); - mockLog = - jasmine.createSpyObj('$log', ['warn', 'info', 'debug']); - mockInterval = jasmine.createSpy('$interval'); - mockInterval.cancel = jasmine.createSpy('mockCancel'); - mockParsed = jasmine.createSpy('parsed'); - mockParsed.assign = jasmine.createSpy('assign'); - mockParse.and.returnValue(mockParsed); - - mockWindow.localStorage = { - store: {}, - setItem: function (key, value) { - this.store[key] = value; - }, - getItem: function (key) { - return this.store[key]; - } - }; - - mctSplitPane = new MCTSplitPane( - mockParse, - mockLog, - mockInterval, - mockWindow - ); - }); - - it("is only applicable as an element", function () { - expect(mctSplitPane.restrict).toEqual("E"); - }); - - describe("when its controller is applied", function () { - var mockScope, - mockElement, - testAttrs, - mockChildren, - mockFirstPane, - mockSplitter, - mockSecondPane, - controller; - - function fireOn(eventType) { - mockScope.$on.calls.all().forEach(function (call) { - if (call.args[0] === eventType) { - call.args[1](); - } - }); - } - - beforeEach(function () { - mockScope = - jasmine.createSpyObj('$scope', ['$apply', '$watch', '$on']); - mockElement = - jasmine.createSpyObj('element', JQLITE_METHODS); - testAttrs = {alias: 'rightSide'}; - mockChildren = - jasmine.createSpyObj('children', JQLITE_METHODS); - mockFirstPane = - jasmine.createSpyObj('firstPane', JQLITE_METHODS); - mockSplitter = - jasmine.createSpyObj('splitter', JQLITE_METHODS); - mockSecondPane = - jasmine.createSpyObj('secondPane', JQLITE_METHODS); - - mockElement.children.and.returnValue(mockChildren); - mockElement[0] = { - offsetWidth: 12321, - offsetHeight: 45654 - }; - mockChildren.eq.and.callFake(function (i) { - return [mockFirstPane, mockSplitter, mockSecondPane][i]; - }); - mockFirstPane[0] = { - offsetWidth: 123, - offsetHeight: 456 - }; - mockSplitter[0] = { - nodeName: 'mct-splitter', - offsetWidth: 10, - offsetHeight: 456 - }; - mockSecondPane[0] = { - offsetWidth: 10, - offsetHeight: 456 - }; - - mockChildren[0] = mockFirstPane[0]; - mockChildren[1] = mockSplitter[0]; - mockChildren[3] = mockSecondPane[0]; - mockChildren.length = 3; - - controller = mctSplitPane.controller[3]( - mockScope, - mockElement, - testAttrs - ); - }); - - it("sets an interval which does not trigger digests", function () { - expect(mockInterval.calls.mostRecent().args[3]).toBe(false); - }); - - it("exposes its splitter's initial position", function () { - expect(controller.position()).toEqual( - mockFirstPane[0].offsetWidth - ); - }); - - it("exposes the current anchoring mode", function () { - expect(controller.anchor()).toEqual({ - edge: 'left', - opposite: 'right', - dimension: 'width', - orientation: 'vertical' - }); - }); - - it("applies resizing class to children when resizing", function () { - controller.startResizing(); - expect(mockChildren.toggleClass).toHaveBeenCalledWith('resizing'); - }); - - it("removes resizing class from children when resizing action ends", function () { - controller.endResizing(0); - expect(mockChildren.toggleClass).toHaveBeenCalledWith('resizing'); - }); - - it("allows positions to be set", function () { - var testValue = mockChildren[0].offsetWidth + 50; - controller.position(testValue); - expect(mockFirstPane.css).toHaveBeenCalledWith( - 'width', - (testValue) + 'px' - ); - }); - - it("issues no warnings under nominal usage", function () { - expect(mockLog.warn).not.toHaveBeenCalled(); - }); - - it("warns if no mct-splitter is present", function () { - mockSplitter[0].nodeName = "not-mct-splitter"; - controller = mctSplitPane.controller[3]( - mockScope, - mockElement, - testAttrs - ); - expect(mockLog.warn).toHaveBeenCalled(); - }); - - it("warns if an unknown anchor key is given", function () { - testAttrs.anchor = "middle"; - controller = mctSplitPane.controller[3]( - mockScope, - mockElement, - testAttrs - ); - expect(mockLog.warn).toHaveBeenCalled(); - }); - - it("updates positions on a timer", function () { - mockFirstPane[0].offsetWidth += 100; - // Should not reflect the change yet - expect(controller.position()).not.toEqual( - mockFirstPane[0].offsetWidth - ); - mockInterval.calls.mostRecent().args[0](); - expect(controller.position()).toEqual( - mockFirstPane[0].offsetWidth - ); - }); - - it("cancels the active interval when scope is destroyed", function () { - expect(mockInterval.cancel).not.toHaveBeenCalled(); - fireOn('$destroy'); - expect(mockInterval.cancel).toHaveBeenCalled(); - }); - - it("saves user preference to localStorage when user is done resizing", function () { - controller.endResizing(100); - expect(Number(mockWindow.localStorage.getItem('mctSplitPane-rightSide'))).toEqual(100); - }); - - }); - - }); - - } -); diff --git a/platform/commonUI/general/test/directives/MCTSplitterSpec.js b/platform/commonUI/general/test/directives/MCTSplitterSpec.js deleted file mode 100644 index da83da7eca..0000000000 --- a/platform/commonUI/general/test/directives/MCTSplitterSpec.js +++ /dev/null @@ -1,110 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define( - ["../../src/directives/MCTSplitter"], - function (MCTSplitter) { - - describe("The mct-splitter directive", function () { - var mctSplitter; - - beforeEach(function () { - mctSplitter = new MCTSplitter(); - }); - - it("is applicable to elements", function () { - expect(mctSplitter.restrict).toEqual("E"); - }); - - it("depends on the mct-split-pane controller", function () { - expect(mctSplitter.require).toEqual("^mctSplitPane"); - }); - - describe("when linked", function () { - var mockScope, - mockElement, - testAttrs, - mockSplitPane; - - beforeEach(function () { - mockScope = jasmine.createSpyObj( - '$scope', - ['$on', '$watch'] - ); - mockElement = jasmine.createSpyObj( - 'element', - ['addClass'] - ); - testAttrs = {}; - mockSplitPane = jasmine.createSpyObj( - 'mctSplitPane', - ['position', 'startResizing', 'endResizing', 'anchor'] - ); - - mctSplitter.link( - mockScope, - mockElement, - testAttrs, - mockSplitPane - ); - }); - - it("adds a splitter class", function () { - expect(mockElement.addClass) - .toHaveBeenCalledWith('splitter'); - }); - - describe("and then manipulated", function () { - var testPosition; - - beforeEach(function () { - testPosition = 12321; - mockSplitPane.position.and.returnValue(testPosition); - mockSplitPane.anchor.and.returnValue({ - orientation: 'vertical', - reversed: false - }); - mockScope.splitter.startMove(); - }); - - it("tell's the splitter when it is resizing", function () { - expect(mockSplitPane.startResizing) - .toHaveBeenCalled(); - }); - - it("repositions during drag", function () { - mockScope.splitter.move([10, 0]); - expect(mockSplitPane.position) - .toHaveBeenCalledWith(testPosition + 10); - }); - - it("tell's the splitter when it is done resizing", function () { - mockScope.splitter.move([10, 0]); - mockScope.splitter.endMove(); - expect(mockSplitPane.endResizing).toHaveBeenCalledWith(testPosition + 10); - }); - - }); - }); - }); - } -); diff --git a/platform/commonUI/general/test/directives/MCTTreeSpec.js b/platform/commonUI/general/test/directives/MCTTreeSpec.js deleted file mode 100644 index f7ff523755..0000000000 --- a/platform/commonUI/general/test/directives/MCTTreeSpec.js +++ /dev/null @@ -1,146 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define([ - '../../src/directives/MCTTree', - '../../src/ui/TreeView' -], function (MCTTree, TreeView) { - describe("The mct-tree directive", function () { - var mockParse, - mockGestureService, - mockExpr, - mctTree; - - function makeMockDomainObject(id) { - var mockDomainObject = jasmine.createSpyObj('domainObject-' + id, [ - 'getId', - 'getModel', - 'getCapability', - 'hasCapability' - ]); - mockDomainObject.getId.and.returnValue(id); - mockDomainObject.getModel.and.returnValue({}); - - return mockDomainObject; - } - - beforeEach(function () { - mockGestureService = jasmine.createSpyObj( - 'gestureService', - ['attachGestures'] - ); - mockParse = jasmine.createSpy('$parse'); - mockExpr = jasmine.createSpy('expr'); - mockExpr.assign = jasmine.createSpy('assign'); - mockParse.and.returnValue(mockExpr); - spyOn(TreeView.prototype, 'observe').and.callThrough(); - - mctTree = new MCTTree(mockParse, mockGestureService); - }); - - it("is applicable as an element", function () { - expect(mctTree.restrict).toEqual("E"); - }); - - it("two-way binds", function () { - expect(mctTree.scope).toEqual({ - rootObject: "=", - selectedObject: "=", - allowSelection: "=?", - onSelection: "=?" - }); - }); - - describe("link", function () { - var mockScope, - mockElement, - testAttrs; - - beforeEach(function () { - mockScope = - jasmine.createSpyObj('$scope', ['$watch', '$on', '$apply']); - mockElement = jasmine.createSpyObj('element', ['append']); - testAttrs = { mctModel: "some-expression" }; - mockScope.$parent = - jasmine.createSpyObj('$scope', ['$watch', '$on']); - mctTree.link(mockScope, mockElement, testAttrs); - }); - - it("populates the mct-tree element", function () { - expect(mockElement.append).toHaveBeenCalled(); - }); - - it("watches for selected-object expression in the parent", function () { - expect(mockScope.$watch).toHaveBeenCalledWith( - "selectedObject", - jasmine.any(Function) - ); - }); - - it("watches for changes to root-object", function () { - expect(mockScope.$watch).toHaveBeenCalledWith( - "rootObject", - jasmine.any(Function) - ); - }); - - it("listens for the $destroy event", function () { - expect(mockScope.$on).toHaveBeenCalledWith( - "$destroy", - jasmine.any(Function) - ); - }); - - it("watches for changes in tree view", function () { - - }); - - // https://github.com/nasa/openmct/issues/1114 - it("does not trigger $apply during $watches", function () { - mockScope.mctObject = makeMockDomainObject('root'); - mockScope.mctMode = makeMockDomainObject('selection'); - mockScope.$watch.calls.all().forEach(function (call) { - call.args[1](mockScope[call.args[0]]); - }); - expect(mockScope.$apply).not.toHaveBeenCalled(); - }); - it("does trigger $apply from tree manipulation", function () { - if (/PhantomJS/g.test(window.navigator.userAgent)) { - console.log('Unable to run test in PhantomJS due to lack of support for event constructors'); - - return; - } - - // White-boxy; we know this is the setter for the tree's value - var treeValueFn = TreeView.prototype.observe.calls.all()[0].args[0]; - - mockScope.mctObject = makeMockDomainObject('root'); - mockScope.mctMode = makeMockDomainObject('selection'); - - treeValueFn(makeMockDomainObject('other'), new MouseEvent("click")); - - expect(mockScope.$apply).toHaveBeenCalled(); - }); - }); - }); - -}); diff --git a/platform/commonUI/general/test/filters/ReverseFilterSpec.js b/platform/commonUI/general/test/filters/ReverseFilterSpec.js deleted file mode 100644 index 1807ed55e0..0000000000 --- a/platform/commonUI/general/test/filters/ReverseFilterSpec.js +++ /dev/null @@ -1,43 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/filters/ReverseFilter'], - function (ReverseFilter) { - - describe("The reverse filter", function () { - var reverse; - - beforeEach(function () { - reverse = new ReverseFilter(); - }); - - it("reverses text", function () { - expect(reverse('foo')).toEqual('oof'); - }); - - it("returns undefined for undefined inputs", function () { - expect(reverse(undefined)).toBeUndefined(); - }); - }); - } -); diff --git a/platform/commonUI/general/test/services/PopupServiceSpec.js b/platform/commonUI/general/test/services/PopupServiceSpec.js deleted file mode 100644 index 15844759c5..0000000000 --- a/platform/commonUI/general/test/services/PopupServiceSpec.js +++ /dev/null @@ -1,98 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PopupService"], - function (PopupService) { - - describe("PopupService", function () { - var mockDocument, - testWindow, - mockBody, - mockElement, - popupService; - - beforeEach(function () { - mockDocument = jasmine.createSpyObj('$document', ['find']); - testWindow = { - innerWidth: 1000, - innerHeight: 800 - }; - mockBody = jasmine.createSpyObj('body', ['append']); - mockElement = jasmine.createSpyObj('element', [ - 'css', - 'remove' - ]); - - mockDocument.find.and.callFake(function (query) { - return query === 'body' && mockBody; - }); - - popupService = new PopupService(mockDocument, testWindow); - }); - - it("adds elements to the body of the document", function () { - popupService.display(mockElement, [0, 0]); - expect(mockBody.append).toHaveBeenCalledWith(mockElement); - }); - - describe("when positioned in appropriate quadrants", function () { - it("orients elements relative to the top-left", function () { - popupService.display(mockElement, [25, 50]); - expect(mockElement.css).toHaveBeenCalledWith({ - position: 'absolute', - left: '25px', - top: '50px' - }); - }); - - it("orients elements relative to the top-right", function () { - popupService.display(mockElement, [800, 50]); - expect(mockElement.css).toHaveBeenCalledWith({ - position: 'absolute', - right: '200px', - top: '50px' - }); - }); - - it("orients elements relative to the bottom-right", function () { - popupService.display(mockElement, [800, 650]); - expect(mockElement.css).toHaveBeenCalledWith({ - position: 'absolute', - right: '200px', - bottom: '150px' - }); - }); - - it("orients elements relative to the bottom-left", function () { - popupService.display(mockElement, [120, 650]); - expect(mockElement.css).toHaveBeenCalledWith({ - position: 'absolute', - left: '120px', - bottom: '150px' - }); - }); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/services/PopupSpec.js b/platform/commonUI/general/test/services/PopupSpec.js deleted file mode 100644 index 8e0ac2beb8..0000000000 --- a/platform/commonUI/general/test/services/PopupSpec.js +++ /dev/null @@ -1,74 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/Popup"], - function (Popup) { - - describe("Popup", function () { - var mockElement, - testStyles, - popup; - - beforeEach(function () { - mockElement = - jasmine.createSpyObj('element', ['css', 'remove']); - testStyles = { - left: '12px', - top: '14px' - }; - popup = new Popup(mockElement, testStyles); - }); - - it("applies CSS styles when instantiated", function () { - expect(mockElement.css) - .toHaveBeenCalledWith(testStyles); - }); - - it("reports the orientation of the popup", function () { - var otherStyles = { - right: '12px', - bottom: '14px' - }, - otherPopup = new Popup(mockElement, otherStyles); - - expect(popup.goesLeft()).toBeFalsy(); - expect(popup.goesRight()).toBeTruthy(); - expect(popup.goesUp()).toBeFalsy(); - expect(popup.goesDown()).toBeTruthy(); - - expect(otherPopup.goesLeft()).toBeTruthy(); - expect(otherPopup.goesRight()).toBeFalsy(); - expect(otherPopup.goesUp()).toBeTruthy(); - expect(otherPopup.goesDown()).toBeFalsy(); - }); - - it("removes elements when dismissed", function () { - expect(mockElement.remove).not.toHaveBeenCalled(); - popup.dismiss(); - expect(mockElement.remove).toHaveBeenCalled(); - }); - - }); - - } -); diff --git a/platform/commonUI/general/test/services/UrlServiceSpec.js b/platform/commonUI/general/test/services/UrlServiceSpec.js deleted file mode 100644 index c1169d7edc..0000000000 --- a/platform/commonUI/general/test/services/UrlServiceSpec.js +++ /dev/null @@ -1,98 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * MCTRepresentationSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/services/UrlService"], - function (UrlService) { - - describe("The url service", function () { - var urlService, - mockLocation, - mockDomainObject, - mockContext, - mockMode, - testViews; - - beforeEach(function () { - // Creates a mockLocation, used to - // do the view search - mockLocation = jasmine.createSpyObj( - "$location", - ["path", "search"] - ); - - // The mockDomainObject is initialized as a - // spy object to ultimately be passed into the - // urlService urlFor function - mockDomainObject = jasmine.createSpyObj( - "domainObject", - ["getId", "getCapability", "getModel", "useCapability"] - ); - mockContext = jasmine.createSpyObj('context', ['getPath']); - testViews = [ - { key: 'abc' }, - { - key: 'def', - someKey: 'some value' - }, - { key: 'xyz' } - ]; - mockMode = "browse"; - - // The mockContext is set a path - // for the mockDomainObject - mockContext.getPath.and.returnValue( - [mockDomainObject] - ); - - // view capability used with the testviews made - mockDomainObject.useCapability.and.callFake(function (c) { - return (c === 'view') && testViews; - }); - - // context capability used with the mockContext created - // so the variables including context in the urlFor are - // initialized and reached - mockDomainObject.getCapability.and.callFake(function (c) { - return c === 'context' && mockContext; - }); - - // Uses the mockLocation to get the current - // "mock" website's view - mockLocation.search.and.returnValue({ view: 'def' }); - - urlService = new UrlService(mockLocation); - }); - - it("get url for a location using domainObject and mode", function () { - urlService.urlForLocation(mockMode, mockDomainObject); - }); - - it("get url for a new tab using domainObject and mode", function () { - urlService.urlForNewTab(mockMode, mockDomainObject); - }); - }); - } -); diff --git a/platform/commonUI/general/test/suite.json b/platform/commonUI/general/test/suite.json deleted file mode 100644 index 09d0bfd097..0000000000 --- a/platform/commonUI/general/test/suite.json +++ /dev/null @@ -1,29 +0,0 @@ -[ - "controllers/ActionGroupController", - "controllers/BottomBarController", - "controllers/ClickAwayController", - "controllers/ContextMenuController", - "controllers/DateTimeFieldController", - "controllers/DateTimePickerController", - "controllers/GetterSetterController", - "controllers/ObjectInspectorController", - "controllers/SelectorController", - "controllers/TimeRangeController", - "controllers/ToggleController", - "controllers/TreeNodeController", - "controllers/ViewSwitcherController", - "directives/MCTClickElsewhere", - "directives/MCTContainer", - "directives/MCTDrag", - "directives/MCTPopup", - "directives/MCTResize", - "directives/MCTScroll", - "directives/MCTSplitPane", - "directives/MCTSplitter", - "filters/ReverseFilter", - "services/Popup", - "services/PopupService", - "services/UrlService", - "StyleSheetLoader", - "UnsupportedBrowserWarning" -] diff --git a/platform/commonUI/general/test/ui/TreeViewSpec.js b/platform/commonUI/general/test/ui/TreeViewSpec.js deleted file mode 100644 index 94f773ca45..0000000000 --- a/platform/commonUI/general/test/ui/TreeViewSpec.js +++ /dev/null @@ -1,290 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/ui/TreeView', - 'zepto' -], function (TreeView, $) { - - xdescribe("TreeView", function () { - var mockGestureService, - mockGestureHandle, - mockDomainObject, - mockMutation, - mockUnlisten, - testCapabilities, - treeView; - - function makeMockDomainObject(id, model, capabilities) { - var mockDomainObj = jasmine.createSpyObj( - 'domainObject-' + id, - [ - 'getId', - 'getModel', - 'getCapability', - 'hasCapability', - 'useCapability' - ] - ); - mockDomainObj.getId.and.returnValue(id); - mockDomainObj.getModel.and.returnValue(model); - mockDomainObj.hasCapability.and.callFake(function (c) { - return Boolean(capabilities[c]); - }); - mockDomainObj.getCapability.and.callFake(function (c) { - return capabilities[c]; - }); - mockDomainObj.useCapability.and.callFake(function (c) { - return capabilities[c] && capabilities[c].invoke(); - }); - - return mockDomainObj; - } - - beforeEach(function () { - mockGestureService = jasmine.createSpyObj( - 'gestureService', - ['attachGestures'] - ); - - mockGestureHandle = jasmine.createSpyObj('gestures', ['destroy']); - - mockGestureService.attachGestures.and.returnValue(mockGestureHandle); - - mockMutation = jasmine.createSpyObj('mutation', ['listen']); - mockUnlisten = jasmine.createSpy('unlisten'); - mockMutation.listen.and.returnValue(mockUnlisten); - - testCapabilities = { mutation: mockMutation }; - - mockDomainObject = - makeMockDomainObject('parent', {}, testCapabilities); - - treeView = new TreeView(mockGestureService); - }); - - describe("elements", function () { - var elements; - - beforeEach(function () { - elements = treeView.elements(); - }); - - it("is an unordered list", function () { - expect(elements[0].tagName.toLowerCase()) - .toEqual('ul'); - }); - }); - - describe("model", function () { - var mockComposition; - - function makeGenericCapabilities() { - var mockStatus = - jasmine.createSpyObj('status', ['listen', 'list']); - - mockStatus.list.and.returnValue([]); - - return { - context: jasmine.createSpyObj('context', ['getPath']), - type: jasmine.createSpyObj('type', ['getCssClass']), - location: jasmine.createSpyObj('location', ['isLink']), - mutation: jasmine.createSpyObj('mutation', ['listen']), - status: mockStatus - }; - } - - beforeEach(function () { - mockComposition = ['a', 'b', 'c'].map(function (id) { - var testCaps = makeGenericCapabilities(), - mockChild = - makeMockDomainObject(id, {}, testCaps); - - testCaps.context.getPath - .and.returnValue([mockDomainObject, mockChild]); - - return mockChild; - }); - - testCapabilities.composition = - jasmine.createSpyObj('composition', ['invoke']); - testCapabilities.composition.invoke - .and.returnValue(Promise.resolve(mockComposition)); - - treeView.model(mockDomainObject); - - return testCapabilities.composition.invoke(); - }); - - it("adds one node per composition element", function () { - expect(treeView.elements()[0].childElementCount) - .toEqual(mockComposition.length); - }); - - it("listens for mutation", function () { - expect(testCapabilities.mutation.listen) - .toHaveBeenCalledWith(jasmine.any(Function)); - }); - - describe("when mutation occurs", function () { - beforeEach(function () { - mockComposition.pop(); - testCapabilities.mutation.listen - .calls.mostRecent().args[0](mockDomainObject.getModel()); - - return testCapabilities.composition.invoke(); - }); - - it("continues to show one node per composition element", function () { - expect(treeView.elements()[0].childElementCount) - .toEqual(mockComposition.length); - }); - }); - - describe("when replaced with a non-compositional domain object", function () { - beforeEach(function () { - delete testCapabilities.composition; - treeView.model(mockDomainObject); - }); - - it("stops listening for mutation", function () { - expect(mockUnlisten).toHaveBeenCalled(); - }); - - it("removes all tree nodes", function () { - expect(treeView.elements()[0].childElementCount) - .toEqual(0); - }); - }); - - describe("when selection state changes", function () { - var selectionIndex = 1; - - beforeEach(function () { - treeView.value(mockComposition[selectionIndex]); - }); - - it("communicates selection state to an appropriate node", function () { - var selected = $(treeView.elements()[0]).find('.selected'); - expect(selected.length).toEqual(1); - }); - }); - - describe("when a context-less object is selected", function () { - beforeEach(function () { - var testCaps = makeGenericCapabilities(), - mockDomainObj = - makeMockDomainObject('xyz', {}, testCaps); - delete testCaps.context; - treeView.value(mockDomainObj); - }); - - it("clears all selection state", function () { - var selected = $(treeView.elements()[0]).find('.selected'); - expect(selected.length).toEqual(0); - }); - }); - - describe("when children contain children", function () { - beforeEach(function () { - var newCapabilities = makeGenericCapabilities(), - gcCapabilities = makeGenericCapabilities(), - mockNewChild = - makeMockDomainObject('d', {}, newCapabilities), - mockGrandchild = - makeMockDomainObject('gc', {}, gcCapabilities); - - newCapabilities.composition = - jasmine.createSpyObj('composition', ['invoke']); - newCapabilities.composition.invoke - .and.returnValue(Promise.resolve([mockGrandchild])); - mockComposition.push(mockNewChild); - - newCapabilities.context.getPath.and.returnValue([ - mockDomainObject, - mockNewChild - ]); - gcCapabilities.context.getPath.and.returnValue([ - mockDomainObject, - mockNewChild, - mockGrandchild - ]); - - testCapabilities.mutation.listen - .calls.mostRecent().args[0](mockDomainObject); - - return testCapabilities.composition.invoke().then(function () { - treeView.value(mockGrandchild); - - return newCapabilities.composition.invoke(); - }); - }); - - it("creates inner trees", function () { - expect($(treeView.elements()[0]).find('ul').length) - .toEqual(1); - }); - }); - - describe("when status changes", function () { - var testStatuses; - - beforeEach(function () { - var mockStatus = mockComposition[1].getCapability('status'); - - testStatuses = ['foo']; - - mockStatus.list.and.returnValue(testStatuses); - mockStatus.listen.calls.mostRecent().args[0](testStatuses); - }); - - it("reflects the status change in the tree", function () { - expect($(treeView.elements()).find('.s-status-foo').length) - .toEqual(1); - }); - }); - }); - - describe("observe", function () { - var mockCallback, - unobserve; - - beforeEach(function () { - mockCallback = jasmine.createSpy('callback'); - unobserve = treeView.observe(mockCallback); - }); - - it("notifies listeners when value is changed", function () { - treeView.value(mockDomainObject, {some: event}); - expect(mockCallback) - .toHaveBeenCalledWith(mockDomainObject, {some: event}); - }); - - it("does not notify listeners when deactivated", function () { - unobserve(); - treeView.value(mockDomainObject); - expect(mockCallback).not.toHaveBeenCalled(); - }); - }); - }); - -}); diff --git a/platform/commonUI/inspect/bundle.js b/platform/commonUI/inspect/bundle.js deleted file mode 100644 index f986ce6280..0000000000 --- a/platform/commonUI/inspect/bundle.js +++ /dev/null @@ -1,117 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/gestures/InfoGesture", - "./src/gestures/InfoButtonGesture", - "./src/services/InfoService", - "./res/info-table.html", - "./res/info-bubble.html", - "./res/bubble.html", - "./res/templates/info-button.html" -], function ( - InfoGesture, - InfoButtonGesture, - InfoService, - infoTableTemplate, - infoBubbleTemplate, - bubbleTemplate, - infoButtonTemplate -) { - - return { - name: "platform/commonUI/inspect", - definition: { - "extensions": { - "templates": [ - { - "key": "info-table", - "template": infoTableTemplate - }, - { - "key": "info-bubble", - "template": infoBubbleTemplate - } - ], - "containers": [ - { - "key": "bubble", - "template": bubbleTemplate, - "attributes": [ - "bubbleTitle", - "bubbleLayout" - ], - "alias": "bubble" - } - ], - "gestures": [ - { - "key": "info", - "implementation": InfoGesture, - "depends": [ - "$timeout", - "agentService", - "infoService", - "INFO_HOVER_DELAY" - ] - }, - { - "key": "infobutton", - "implementation": InfoButtonGesture, - "depends": [ - "$document", - "agentService", - "infoService" - ] - } - ], - "services": [ - { - "key": "infoService", - "implementation": InfoService, - "depends": [ - "$compile", - "$rootScope", - "popupService", - "agentService" - ] - } - ], - "constants": [ - { - "key": "INFO_HOVER_DELAY", - "value": 2000 - } - ], - "representations": [ - { - "key": "info-button", - "template": infoButtonTemplate, - "gestures": [ - "infobutton" - ] - } - ] - } - } - }; -}); diff --git a/platform/commonUI/inspect/res/bubble.html b/platform/commonUI/inspect/res/bubble.html deleted file mode 100644 index f528d6432f..0000000000 --- a/platform/commonUI/inspect/res/bubble.html +++ /dev/null @@ -1,9 +0,0 @@ -
      -
      -
      - {{bubble.bubbleTitle}} -
      - -
      -
      diff --git a/platform/commonUI/inspect/res/info-bubble.html b/platform/commonUI/inspect/res/info-bubble.html deleted file mode 100644 index 82545cb29e..0000000000 --- a/platform/commonUI/inspect/res/info-bubble.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - diff --git a/platform/commonUI/inspect/res/info-table.html b/platform/commonUI/inspect/res/info-table.html deleted file mode 100644 index 0c89a498d9..0000000000 --- a/platform/commonUI/inspect/res/info-table.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - -
      {{property.name}} - {{property.value}} -
      diff --git a/platform/commonUI/inspect/res/infobubble.html b/platform/commonUI/inspect/res/infobubble.html deleted file mode 100644 index d46d5e3d05..0000000000 --- a/platform/commonUI/inspect/res/infobubble.html +++ /dev/null @@ -1,71 +0,0 @@ - -
      - - -
      -
      -
      -
      {{title}} -
      - - - - - -
      {{property.label}}{{property.value}}
      -
      -
      -
      diff --git a/platform/commonUI/inspect/res/templates/info-button.html b/platform/commonUI/inspect/res/templates/info-button.html deleted file mode 100644 index 1d696161f0..0000000000 --- a/platform/commonUI/inspect/res/templates/info-button.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - diff --git a/platform/commonUI/inspect/src/InfoConstants.js b/platform/commonUI/inspect/src/InfoConstants.js deleted file mode 100644 index 6ad20a8535..0000000000 --- a/platform/commonUI/inspect/src/InfoConstants.js +++ /dev/null @@ -1,47 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 provides support for object inspection (specifically, metadata - * show in bubbles on hover.) - * @namespace platform/commonUI/inspect - */ - -define({ - BUBBLE_TEMPLATE: "" - + "" - + "" - + "", - // Options and classes for bubble - BUBBLE_OPTIONS: { - offsetX: 0, - offsetY: -26 - }, - BUBBLE_MOBILE_POSITION: [0, -25], - // Max width and margins allowed for bubbles; - // defined in /platform/commonUI/general/res/sass/_constants.scss - BUBBLE_MARGIN_LR: 10, - BUBBLE_MAX_WIDTH: 300 -}); diff --git a/platform/commonUI/inspect/src/gestures/InfoButtonGesture.js b/platform/commonUI/inspect/src/gestures/InfoButtonGesture.js deleted file mode 100644 index 305787729c..0000000000 --- a/platform/commonUI/inspect/src/gestures/InfoButtonGesture.js +++ /dev/null @@ -1,115 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The `info` gesture displays domain object metadata in a - * bubble on hover. - * - * @constructor - * @param $document Angular's `$document` - * @param {InfoService} infoService a service which shows info bubbles - * @param element jqLite-wrapped DOM element - * @param {DomainObject} domainObject the domain object for which to - * show information - */ - function InfoGestureButton($document, agentService, infoService, element, domainObject) { - var dismissBubble, - touchPosition, - body = $document.find('body'); - - function trackPosition(event) { - // Record touch position, so bubble can be shown at latest - // touch position, also offset by 22px to left (accounts for - // a finger-sized touch on the info button) - touchPosition = [event.clientX - 22, event.clientY]; - } - - // Hides the bubble and detaches the - // body hidebubble listener - function hideBubble() { - // If a bubble is showing, dismiss it - if (dismissBubble) { - dismissBubble(); - dismissBubble = undefined; - } - - // Detaches body touch listener - body.off('touchstart', hideBubble); - } - - // Displays the bubble by tracking position of - // touch, using infoService to display the bubble, - // and then on any body touch the bubble is dismissed - function showBubble(event) { - trackPosition(event); - event.stopPropagation(); - // Show the bubble, but on any touchstart on the - // body (anywhere) call hidebubble - dismissBubble = infoService.display( - "info-table", - domainObject.getModel().name, - domainObject.useCapability('metadata'), - touchPosition - ); - - // On any touch on the body, default body touches/events - // are prevented, the bubble is dismissed, and the touchstart - // body event is unbound, reallowing gestures - body.on('touchstart', function (evt) { - evt.preventDefault(); - hideBubble(); - body.unbind('touchstart'); - }); - } - - // Checks if you are on a mobile device, if the device is - // mobile (agentService.isMobile() = true), then - // the a click on something (info button) brings up - // the bubble - if (agentService.isMobile()) { - element.on('click', showBubble); - } - - return { - /** - * Detach any event handlers associated with this gesture. - * @memberof InfoGesture - * @method - */ - destroy: function () { - // Dismiss any active bubble... - hideBubble(); - // ...and detach listeners - element.off('click', showBubble); - } - }; - } - - return InfoGestureButton; - - } - -); diff --git a/platform/commonUI/inspect/src/gestures/InfoGesture.js b/platform/commonUI/inspect/src/gestures/InfoGesture.js deleted file mode 100644 index e2a692370a..0000000000 --- a/platform/commonUI/inspect/src/gestures/InfoGesture.js +++ /dev/null @@ -1,149 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The `info` gesture displays domain object metadata in a - * bubble on hover. - * - * @memberof platform/commonUI/inspect - * @constructor - * @implements {Gesture} - * @param $timeout Angular's `$timeout` - * @param {InfoService} infoService a service which shows info bubbles - * @param {number} delay delay, in milliseconds, before bubble appears - * @param element jqLite-wrapped DOM element - * @param {DomainObject} domainObject the domain object for which to - * show information - */ - function InfoGesture($timeout, agentService, infoService, delay, element, domainObject) { - var self = this; - - // Callback functions to preserve the "this" pointer (in the - // absence of Function.prototype.bind) - this.showBubbleCallback = function (event) { - self.showBubble(event); - }; - - this.hideBubbleCallback = function (event) { - self.hideBubble(event); - }; - - this.trackPositionCallback = function (event) { - self.trackPosition(event); - }; - - this.element = element; - this.$timeout = $timeout; - this.infoService = infoService; - this.delay = delay; - this.domainObject = domainObject; - - // Checks if you are on a mobile device, if the device is - // not mobile (agentService.isMobile() = false), then - // the pendingBubble and therefore hovering is allowed - if (!agentService.isMobile()) { - // Show bubble (on a timeout) on mouse over - element.on('mouseenter', this.showBubbleCallback); - } - } - - InfoGesture.prototype.trackPosition = function (event) { - // Record mouse position, so bubble can be shown at latest - // mouse position (not just where the mouse entered) - this.mousePosition = [event.clientX, event.clientY]; - }; - - InfoGesture.prototype.hideBubble = function () { - // If a bubble is showing, dismiss it - if (this.dismissBubble) { - this.dismissBubble(); - this.element.off('mouseleave', this.hideBubbleCallback); - this.dismissBubble = undefined; - } - - // If a bubble will be shown on a timeout, cancel that - if (this.pendingBubble) { - this.$timeout.cancel(this.pendingBubble); - this.element.off('mousemove', this.trackPositionCallback); - this.element.off('mouseleave', this.hideBubbleCallback); - this.pendingBubble = undefined; - } - - // Also clear mouse position so we don't have a ton of tiny - // arrays allocated while user mouses over things - this.mousePosition = undefined; - }; - - InfoGesture.prototype.showBubble = function (event) { - var self = this; - - function displayBubble() { - self.dismissBubble = self.infoService.display( - "info-table", - self.domainObject.getModel().name, - self.domainObject.useCapability('metadata'), - self.mousePosition - ); - self.element.off('mousemove', self.trackPositionCallback); - self.pendingBubble = undefined; - } - - this.trackPosition(event); - - // Do nothing if we're already scheduled to show a bubble. - // This may happen due to redundant event firings caused - // by https://github.com/angular/angular.js/issues/12795 - if (this.pendingBubble) { - return; - } - - // Also need to track position during hover - this.element.on('mousemove', this.trackPositionCallback); - - // Show the bubble, after a suitable delay (if mouse has - // left before this time is up, this will be canceled.) - this.pendingBubble = this.$timeout(displayBubble, this.delay); - - this.element.on('mouseleave', this.hideBubbleCallback); - }; - - /** - * Detach any event handlers associated with this gesture. - * @method - */ - InfoGesture.prototype.destroy = function () { - // Dismiss any active bubble... - this.hideBubble(); - // ...and detach listeners - this.element.off('mouseenter', this.showBubbleCallback); - }; - - return InfoGesture; - - } - -); - diff --git a/platform/commonUI/inspect/src/services/InfoService.js b/platform/commonUI/inspect/src/services/InfoService.js deleted file mode 100644 index aed1a33297..0000000000 --- a/platform/commonUI/inspect/src/services/InfoService.js +++ /dev/null @@ -1,106 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['../InfoConstants'], - function (InfoConstants) { - - var BUBBLE_TEMPLATE = InfoConstants.BUBBLE_TEMPLATE, - MOBILE_POSITION = InfoConstants.BUBBLE_MOBILE_POSITION, - OPTIONS = InfoConstants.BUBBLE_OPTIONS; - - /** - * Displays informative content ("info bubbles") for the user. - * @memberof platform/commonUI/inspect - * @constructor - */ - function InfoService($compile, $rootScope, popupService, agentService) { - this.$compile = $compile; - this.$rootScope = $rootScope; - this.popupService = popupService; - this.agentService = agentService; - } - - /** - * Display an info bubble at the specified location. - * @param {string} templateKey template to place in bubble - * @param {string} title title for the bubble - * @param {*} content content to pass to the template, via - * `ng-model` - * @param {number[]} x,y position of the info bubble, in - * pixel coordinates. - * @returns {Function} a function that may be invoked to - * dismiss the info bubble - */ - InfoService.prototype.display = function (templateKey, title, content, position) { - var $compile = this.$compile, - $rootScope = this.$rootScope, - scope = $rootScope.$new(), - span = $compile('')(scope), - bubbleSpaceLR = InfoConstants.BUBBLE_MARGIN_LR - + InfoConstants.BUBBLE_MAX_WIDTH, - options, - popup, - bubble; - - options = Object.create(OPTIONS); - options.marginX = -bubbleSpaceLR; - - // prevent bubble from appearing right under pointer, - // which causes hover callback to be called multiple times - options.offsetX = 1; - - // On a phone, bubble takes up more screen real estate, - // so position it differently (toward the bottom) - if (this.agentService.isPhone()) { - position = MOBILE_POSITION; - options = {}; - } - - popup = this.popupService.display(span, position, options); - - // Pass model & container parameters into the scope - scope.bubbleModel = content; - scope.bubbleTemplate = templateKey; - scope.bubbleTitle = title; - // Style the bubble according to how it was positioned - scope.bubbleLayout = [ - popup.goesUp() ? 'arw-btm' : 'arw-top', - popup.goesLeft() ? 'arw-right' : 'arw-left' - ].join(' '); - - // Create the info bubble, now that we know how to - // point the arrow... - bubble = $compile(BUBBLE_TEMPLATE)(scope); - span.append(bubble); - - // Return a function to dismiss the info bubble - return function dismiss() { - popup.dismiss(); - scope.$destroy(); - }; - }; - - return InfoService; - } -); - diff --git a/platform/commonUI/inspect/test/gestures/InfoButtonGestureSpec.js b/platform/commonUI/inspect/test/gestures/InfoButtonGestureSpec.js deleted file mode 100644 index e896367bf4..0000000000 --- a/platform/commonUI/inspect/test/gestures/InfoButtonGestureSpec.js +++ /dev/null @@ -1,148 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/gestures/InfoButtonGesture'], - function (InfoButtonGesture) { - - describe("The info button gesture", function () { - var mockDocument, - mockBody, - mockAgentService, - mockInfoService, - mockElement, - mockDomainObject, - mockEvent, - mockScope, - mockOff, - testMetadata, - mockHide, - gesture, - fireGesture, - fireDismissGesture; - - beforeEach(function () { - mockDocument = jasmine.createSpyObj('$document', ['find']); - mockBody = jasmine.createSpyObj('body', ['on', 'off', 'scope', 'css', 'unbind']); - mockDocument.find.and.returnValue(mockBody); - mockAgentService = jasmine.createSpyObj('agentService', ['isMobile', 'isPhone']); - mockInfoService = jasmine.createSpyObj( - 'infoService', - ['display'] - ); - mockElement = jasmine.createSpyObj( - 'element', - ['on', 'off', 'scope', 'css'] - ); - mockDomainObject = jasmine.createSpyObj( - 'domainObject', - ['getId', 'getCapability', 'useCapability', 'getModel'] - ); - - mockEvent = jasmine.createSpyObj("event", ["preventDefault", "stopPropagation"]); - mockEvent.pageX = 0; - mockEvent.pageY = 0; - mockScope = jasmine.createSpyObj('$scope', ['$on']); - mockOff = jasmine.createSpy('$off'); - testMetadata = [{ - name: "Test name", - value: "Test value" - }]; - mockHide = jasmine.createSpy('hide'); - - mockDomainObject.getModel.and.returnValue({ name: "Test Object" }); - mockDomainObject.useCapability.and.callFake(function (c) { - return (c === 'metadata') ? testMetadata : undefined; - }); - mockElement.scope.and.returnValue(mockScope); - mockScope.$on.and.returnValue(mockOff); - mockInfoService.display.and.returnValue(mockHide); - mockAgentService.isMobile.and.returnValue(true); - gesture = new InfoButtonGesture( - mockDocument, - mockAgentService, - mockInfoService, - mockElement, - mockDomainObject - ); - fireGesture = mockElement.on.calls.mostRecent().args[1]; - }); - - it("expect click on the representation", function () { - // Fires a click call on element and then - // expects the click to have happened - fireGesture(mockEvent); - expect(mockElement.on).toHaveBeenCalledWith( - "click", - jasmine.any(Function) - ); - }); - - it("expect click then dismiss on the representation", function () { - // Fire the click and then expect the click - fireGesture(mockEvent); - expect(mockElement.on).toHaveBeenCalledWith( - "click", - jasmine.any(Function) - ); - - // Get the touch start on the body - // and fire the dismiss gesture - fireDismissGesture = mockBody.on.calls.mostRecent().args[1]; - fireDismissGesture(mockEvent); - // Expect Body to have been touched, event.preventDefault() - // to be called, then the mockBody listener to be detached - // lastly unbind the touchstart used to dismiss so other - // events can be called - expect(mockBody.on).toHaveBeenCalledWith( - "touchstart", - jasmine.any(Function) - ); - expect(mockEvent.preventDefault).toHaveBeenCalled(); - expect(mockBody.off).toHaveBeenCalledWith( - "touchstart", - jasmine.any(Function) - ); - expect(mockBody.unbind).toHaveBeenCalledWith( - 'touchstart' - ); - }); - - it("detaches a callback for info bubble events when destroyed", function () { - expect(mockElement.off).not.toHaveBeenCalled(); - - gesture.destroy(); - - expect(mockElement.off).toHaveBeenCalledWith( - "click", - jasmine.any(Function) - ); - }); - - // https://github.com/nasa/openmct/issues/948 - it("does not try to access scope", function () { - expect(mockElement.scope).not.toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/commonUI/inspect/test/gestures/InfoGestureSpec.js b/platform/commonUI/inspect/test/gestures/InfoGestureSpec.js deleted file mode 100644 index 5769cfd45a..0000000000 --- a/platform/commonUI/inspect/test/gestures/InfoGestureSpec.js +++ /dev/null @@ -1,188 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/gestures/InfoGesture'], - function (InfoGesture) { - - describe("The info gesture", function () { - var mockTimeout, - mockAgentService, - mockInfoService, - testDelay = 12321, - mockElement, - mockDomainObject, - mockScope, - mockOff, - testMetadata, - mockPromise, - mockHide, - gesture; - - function fireEvent(evt, value) { - mockElement.on.calls.all().forEach(function (call) { - if (call.args[0] === evt) { - call.args[1](value); - } - }); - } - - beforeEach(function () { - mockTimeout = jasmine.createSpy('$timeout'); - mockTimeout.cancel = jasmine.createSpy('cancel'); - mockAgentService = jasmine.createSpyObj('agentService', ['isMobile']); - mockInfoService = jasmine.createSpyObj( - 'infoService', - ['display'] - ); - mockElement = jasmine.createSpyObj( - 'element', - ['on', 'off', 'scope', 'css'] - ); - mockDomainObject = jasmine.createSpyObj( - 'domainObject', - ['getId', 'getCapability', 'useCapability', 'getModel'] - ); - mockScope = jasmine.createSpyObj('$scope', ['$on']); - mockOff = jasmine.createSpy('$off'); - testMetadata = [{ - name: "Test name", - value: "Test value" - }]; - mockPromise = jasmine.createSpyObj('promise', ['then']); - mockHide = jasmine.createSpy('hide'); - - mockDomainObject.getModel.and.returnValue({ name: "Test Object" }); - mockDomainObject.useCapability.and.callFake(function (c) { - return (c === 'metadata') ? testMetadata : undefined; - }); - mockElement.scope.and.returnValue(mockScope); - mockScope.$on.and.returnValue(mockOff); - mockTimeout.and.returnValue(mockPromise); - mockInfoService.display.and.returnValue(mockHide); - - gesture = new InfoGesture( - mockTimeout, - mockAgentService, - mockInfoService, - testDelay, - mockElement, - mockDomainObject - ); - }); - - it("listens for mouseenter on the representation", function () { - expect(mockElement.on) - .toHaveBeenCalledWith('mouseenter', jasmine.any(Function)); - }); - - it("displays an info bubble on a delay after mouseenter", function () { - fireEvent("mouseenter", { - clientX: 1977, - clientY: 42 - }); - expect(mockTimeout) - .toHaveBeenCalledWith(jasmine.any(Function), testDelay); - mockTimeout.calls.mostRecent().args[0](); - expect(mockInfoService.display).toHaveBeenCalledWith( - jasmine.any(String), - "Test Object", - testMetadata, - [1977, 42] - ); - }); - - it("does not display info bubble if mouse leaves too soon", function () { - fireEvent("mouseenter", { - clientX: 1977, - clientY: 42 - }); - fireEvent("mouseleave", { - clientX: 1977, - clientY: 42 - }); - expect(mockTimeout.cancel).toHaveBeenCalledWith(mockPromise); - expect(mockInfoService.display).not.toHaveBeenCalled(); - }); - - it("hides a shown bubble when mouse leaves", function () { - fireEvent("mouseenter", { - clientX: 1977, - clientY: 42 - }); - mockTimeout.calls.mostRecent().args[0](); - expect(mockHide).not.toHaveBeenCalled(); // verify precondition - fireEvent("mouseleave", {}); - expect(mockHide).toHaveBeenCalled(); - }); - - it("tracks mouse position", function () { - fireEvent("mouseenter", { - clientX: 1977, - clientY: 42 - }); - fireEvent("mousemove", { - clientX: 1999, - clientY: 11 - }); - fireEvent("mousemove", { - clientX: 1984, - clientY: 11 - }); - mockTimeout.calls.mostRecent().args[0](); - // Should have displayed at the latest observed mouse position - expect(mockInfoService.display).toHaveBeenCalledWith( - jasmine.any(String), - "Test Object", - testMetadata, - [1984, 11] - ); - }); - - it("hides shown bubbles when destroyed", function () { - fireEvent("mouseenter", { - clientX: 1977, - clientY: 42 - }); - mockTimeout.calls.mostRecent().args[0](); - expect(mockHide).not.toHaveBeenCalled(); // verify precondition - gesture.destroy(); - expect(mockHide).toHaveBeenCalled(); - }); - - it("detaches listeners when destroyed", function () { - fireEvent("mouseenter", { - clientX: 1977, - clientY: 42 - }); - gesture.destroy(); - mockElement.on.calls.all().forEach(function (call) { - expect(mockElement.off).toHaveBeenCalledWith( - call.args[0], - call.args[1] - ); - }); - }); - - }); - } -); diff --git a/platform/commonUI/inspect/test/services/InfoServiceSpec.js b/platform/commonUI/inspect/test/services/InfoServiceSpec.js deleted file mode 100644 index 96be4af78b..0000000000 --- a/platform/commonUI/inspect/test/services/InfoServiceSpec.js +++ /dev/null @@ -1,142 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/InfoService'], - function (InfoService) { - - describe("The info service", function () { - var mockCompile, - mockRootScope, - mockPopupService, - mockAgentService, - mockScope, - mockElements, - mockPopup, - service; - - beforeEach(function () { - mockCompile = jasmine.createSpy('$compile'); - mockRootScope = jasmine.createSpyObj('$rootScope', ['$new']); - mockAgentService = jasmine.createSpyObj('agentService', ['isMobile', 'isPhone']); - mockPopupService = jasmine.createSpyObj( - 'popupService', - ['display'] - ); - mockPopup = jasmine.createSpyObj('popup', [ - 'dismiss', - 'goesLeft', - 'goesRight', - 'goesUp', - 'goesDown' - ]); - - mockScope = jasmine.createSpyObj("scope", ["$destroy"]); - mockElements = []; - - mockPopupService.display.and.returnValue(mockPopup); - mockCompile.and.callFake(function () { - var mockCompiledTemplate = jasmine.createSpy('template'), - mockElement = jasmine.createSpyObj('element', [ - 'css', - 'remove', - 'append' - ]); - mockCompiledTemplate.and.returnValue(mockElement); - mockElements.push(mockElement); - - return mockCompiledTemplate; - }); - mockRootScope.$new.and.returnValue(mockScope); - - service = new InfoService( - mockCompile, - mockRootScope, - mockPopupService, - mockAgentService - ); - }); - - it("creates elements and displays them as popups", function () { - service.display('', '', {}, [123, 456]); - expect(mockPopupService.display).toHaveBeenCalledWith( - mockElements[0], - [123, 456], - jasmine.any(Object) - ); - }); - - it("provides a function to remove displayed info bubbles", function () { - var fn = service.display('', '', {}, [0, 0]); - expect(mockPopup.dismiss).not.toHaveBeenCalled(); - fn(); - expect(mockPopup.dismiss).toHaveBeenCalled(); - }); - - it("when on phone device, positions at bottom", function () { - mockAgentService.isPhone.and.returnValue(true); - service = new InfoService( - mockCompile, - mockRootScope, - mockPopupService, - mockAgentService - ); - service.display('', '', {}, [123, 456]); - expect(mockPopupService.display).toHaveBeenCalledWith( - mockElements[0], - [0, -25], - jasmine.any(Object) - ); - }); - - [false, true].forEach(function (goesLeft) { - [false, true].forEach(function (goesUp) { - var vertical = goesUp ? "up" : "down", - horizontal = goesLeft ? "left" : "right", - location = [vertical, horizontal].join('-'); - describe("when bubble goes " + location, function () { - var expectedLocation = [ - goesUp ? "bottom" : "top", - goesLeft ? "right" : "left" - ].join('-'); - - beforeEach(function () { - mockPopup.goesUp.and.returnValue(goesUp); - mockPopup.goesDown.and.returnValue(!goesUp); - mockPopup.goesLeft.and.returnValue(goesLeft); - mockPopup.goesRight.and.returnValue(!goesLeft); - service.display('', '', {}, [10, 10]); - }); - - it("positions the arrow in the " + expectedLocation, function () { - expect(mockScope.bubbleLayout).toEqual([ - goesUp ? "arw-btm" : "arw-top", - goesLeft ? "arw-right" : "arw-left" - ].join(' ')); - }); - }); - }); - }); - - }); - } -); diff --git a/platform/commonUI/mobile/bundle.js b/platform/commonUI/mobile/bundle.js deleted file mode 100644 index 3349df3898..0000000000 --- a/platform/commonUI/mobile/bundle.js +++ /dev/null @@ -1,44 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 -) { - return { - name: "platform/commonUI/mobile", - definition: { - "extensions": { - "services": [ - { - "key": "agentService", - "implementation": AgentService, - "depends": [ - "$window" - ] - } - ] - } - } - }; -}); diff --git a/platform/commonUI/mobile/src/AgentService.js b/platform/commonUI/mobile/src/AgentService.js deleted file mode 100644 index 2ef9ee1224..0000000000 --- a/platform/commonUI/mobile/src/AgentService.js +++ /dev/null @@ -1,31 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/utils/agent/Agent.js"], function (Agent) { - function AngularAgentServiceWrapper(window) { - const AS = Agent.default; - - return new AS(window); - } - - return AngularAgentServiceWrapper; -}); diff --git a/platform/commonUI/mobile/src/AgentServiceSpec.js b/platform/commonUI/mobile/src/AgentServiceSpec.js deleted file mode 100644 index 7e1f58b6e1..0000000000 --- a/platform/commonUI/mobile/src/AgentServiceSpec.js +++ /dev/null @@ -1,96 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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); - }); -}); diff --git a/platform/commonUI/notification/bundle.js b/platform/commonUI/notification/bundle.js deleted file mode 100644 index 38210ad8b3..0000000000 --- a/platform/commonUI/notification/bundle.js +++ /dev/null @@ -1,47 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/NotificationService" -], function ( - NotificationService -) { - - return { - name: "platform/commonUI/notification", - definition: { - "extensions": { - "services": [ - { - "key": "notificationService", - "implementation": function (openmct) { - return new NotificationService.default(openmct); - }, - "depends": [ - "openmct" - ] - } - ] - } - } - }; -}); diff --git a/platform/commonUI/notification/src/NotificationService.js b/platform/commonUI/notification/src/NotificationService.js deleted file mode 100644 index 00faf832c4..0000000000 --- a/platform/commonUI/notification/src/NotificationService.js +++ /dev/null @@ -1,64 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ -export default class NotificationService { - constructor(openmct) { - this.openmct = openmct; - } - info(message) { - if (typeof message === 'string') { - return this.openmct.notifications.info(message); - } else { - if (Object.prototype.hasOwnProperty.call(message, 'progress')) { - return this.openmct.notifications.progress(message.title, message.progress, message.progressText); - } else { - return this.openmct.notifications.info(message.title); - } - } - } - alert(message) { - if (typeof message === 'string') { - return this.openmct.notifications.alert(message); - } else { - return this.openmct.notifications.alert(message.title); - } - } - error(message) { - if (typeof message === 'string') { - return this.openmct.notifications.error(message); - } else { - return this.openmct.notifications.error(message.title); - } - } - notify(options) { - switch (options.severity) { - case 'info': - return this.info(options); - case 'alert': - return this.alert(options); - case 'error': - return this.error(options); - } - } - getAllNotifications() { - return this.openmct.notifications.notifications; - } -} diff --git a/platform/commonUI/regions/bundle.js b/platform/commonUI/regions/bundle.js deleted file mode 100644 index 6666257445..0000000000 --- a/platform/commonUI/regions/bundle.js +++ /dev/null @@ -1,55 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/InspectorController', - './src/EditableRegionPolicy' -], function ( - InspectorController, - EditableRegionPolicy -) { - - return { - name: "platform/commonUI/regions", - definition: { - "extensions": { - "controllers": [ - { - "key": "InspectorController", - "implementation": InspectorController, - "depends": [ - "$scope", - "openmct", - "$document" - ] - } - ], - "policies": [ - { - "category": "region", - "implementation": EditableRegionPolicy - } - ] - } - } - }; -}); diff --git a/platform/commonUI/regions/src/EditableRegionPolicy.js b/platform/commonUI/regions/src/EditableRegionPolicy.js deleted file mode 100644 index 3c704a25e6..0000000000 --- a/platform/commonUI/regions/src/EditableRegionPolicy.js +++ /dev/null @@ -1,56 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 policy for determining whether a region part should be visible or - * not, based on its editability and the current state of the domain - * object . - * @constructor - * @implements {Policy} - * @memberof platform/commonUI/regions - */ - function EditableRegionPolicy() { - } - - EditableRegionPolicy.prototype.allow = function (regionPart, domainObject) { - if (!regionPart.modes) { - return true; - } - - if (domainObject.hasCapability('editor') && domainObject.getCapability('editor').inEditContext()) { - //If the domain object is in edit mode, only include a part - // if it is marked editable - return regionPart.modes.indexOf('edit') !== -1; - } else { - //If the domain object is not in edit mode, return any parts - // that are not explicitly marked editable - return regionPart.modes.indexOf('browse') !== -1; - } - }; - - return EditableRegionPolicy; - } -); diff --git a/platform/commonUI/regions/src/InspectorController.js b/platform/commonUI/regions/src/InspectorController.js deleted file mode 100644 index c2ee08fbfd..0000000000 --- a/platform/commonUI/regions/src/InspectorController.js +++ /dev/null @@ -1,93 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The InspectorController listens for the selection changes and adds the selection - * object to the scope. - * - * @constructor - */ - function InspectorController($scope, openmct, $document) { - var self = this; - self.$scope = $scope; - - /** - * Callback handler for the selection change event. - * Adds the selection object to the scope. If the selected item has an inspector view, - * it puts the key in the scope. If provider view exists, it shows the view. - */ - function setSelection(selection) { - if (selection[0]) { - var view = openmct.inspectorViews.get(selection); - var container = $document[0].querySelectorAll('.inspector-provider-view')[0]; - container.innerHTML = ""; - - if (view) { - self.providerView = true; - view.show(container); - } else { - self.providerView = false; - var selectedItem = selection[0].context.oldItem; - - if (selectedItem) { - $scope.inspectorKey = selectedItem.getCapability("type").typeDef.inspector; - } - } - } - - self.$scope.selection = selection; - } - - openmct.selection.on("change", setSelection); - - setSelection(openmct.selection.get()); - - $scope.$on("$destroy", function () { - openmct.selection.off("change", setSelection); - }); - } - - /** - * Gets the selected item. - * - * @returns a domain object - */ - InspectorController.prototype.selectedItem = function () { - return this.$scope.selection[0] && this.$scope.selection[0].context.oldItem; - }; - - /** - * Checks if a provider view exists. - * - * @returns 'true' if provider view exists, 'false' otherwise - */ - InspectorController.prototype.hasProviderView = function () { - return this.providerView; - }; - - return InspectorController; - } -); diff --git a/platform/commonUI/regions/src/Region.js b/platform/commonUI/regions/src/Region.js deleted file mode 100644 index d0626dbc9c..0000000000 --- a/platform/commonUI/regions/src/Region.js +++ /dev/null @@ -1,99 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * @typeDef {object} PartContents - * @property {string} key If the part is defined as a - * representation, the key corresponding to the representation. - * @memberOf platform/commonUI/regions - */ - - /** - * @typeDef {object} RegionConfiguration - * @property {string} name A unique name for this region part - * @property {PartContents} [content] the details of the region being - * defined - * @property {Array} [modes] the modes that this region - * should be included in. Options are 'edit' and 'browse'. By - * default, will be included in both. Inclusion of regions is - * determined by policies of category 'region'. By default, the - * {EditableRegionPolicy} will be applied. - * @memberOf platform/commonUI/regions - */ - - /** - * Defines the interface for a screen region. A screen region is a - * section of the browse an edit screens for an object. Regions are - * declared in object type definitions. - * @memberOf platform/commonUI/regions - * @abstract - * @constructor - */ - function Region(configuration) { - configuration = configuration || {}; - this.name = configuration.name; - this.content = configuration.content; - this.modes = configuration.modes; - - this.regions = []; - } - - /** - * Adds a sub-region to this region. - * @param {Region} region the part to add - * @param {number} [index] the position to insert the region. By default - * will add to the end - */ - Region.prototype.addRegion = function (region, index) { - if (index) { - this.regions.splice(index, 0, region); - } else { - this.regions.push(region); - } - }; - - /** - * Removes a sub-region from this region. - * @param {Region | number | strnig} region The region to - * remove. If a number, will remove the region at that index. If a - * string, will remove the region with the matching name. If an - * object, will attempt to remove that object from the Region - */ - Region.prototype.removeRegion = function (region) { - if (typeof region === 'number') { - this.regions.splice(region, 1); - } else if (typeof region === 'string') { - this.regions = this.regions.filter(function (thisRegion) { - return thisRegion.name !== region; - }); - } else { - this.regions.splice(this.regions.indexOf(region), 1); - } - }; - - return Region; - } -); diff --git a/platform/commonUI/regions/test/EditableRegionPolicySpec.js b/platform/commonUI/regions/test/EditableRegionPolicySpec.js deleted file mode 100644 index 26db0f80df..0000000000 --- a/platform/commonUI/regions/test/EditableRegionPolicySpec.js +++ /dev/null @@ -1,74 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/EditableRegionPolicy'], - function (EditableRegionPolicy) { - - describe("The editable region policy ", function () { - - var editableRegionPolicy, - mockDomainObject, - mockEditorCapability, - mockBrowseRegionPart = { - modes: 'browse' - }, - mockEditRegionPart = { - modes: 'edit' - }, - mockAllModesRegionPart = {}; - - beforeEach(function () { - editableRegionPolicy = new EditableRegionPolicy(); - - mockEditorCapability = jasmine.createSpyObj("editorCapability", [ - "inEditContext" - ]); - mockDomainObject = jasmine.createSpyObj("domainObject", [ - "hasCapability", "getCapability" - ]); - mockDomainObject.hasCapability.and.returnValue(true); - mockDomainObject.getCapability.and.returnValue(mockEditorCapability); - }); - - it("includes only browse region parts for object not in edit mode", function () { - mockEditorCapability.inEditContext.and.returnValue(false); - expect(editableRegionPolicy.allow(mockBrowseRegionPart, mockDomainObject)).toBe(true); - expect(editableRegionPolicy.allow(mockEditRegionPart, mockDomainObject)).toBe(false); - }); - - it("includes only edit region parts for object in edit mode", function () { - mockEditorCapability.inEditContext.and.returnValue(true); - expect(editableRegionPolicy.allow(mockBrowseRegionPart, mockDomainObject)).toBe(false); - expect(editableRegionPolicy.allow(mockEditRegionPart, mockDomainObject)).toBe(true); - }); - - it("includes region parts with no mode specification", function () { - mockEditorCapability.inEditContext.and.returnValue(false); - expect(editableRegionPolicy.allow(mockAllModesRegionPart, mockDomainObject)).toBe(true); - mockEditorCapability.inEditContext.and.returnValue(true); - expect(editableRegionPolicy.allow(mockAllModesRegionPart, mockDomainObject)).toBe(true); - }); - - }); - } -); diff --git a/platform/commonUI/regions/test/InspectorControllerSpec.js b/platform/commonUI/regions/test/InspectorControllerSpec.js deleted file mode 100644 index f55372b0ec..0000000000 --- a/platform/commonUI/regions/test/InspectorControllerSpec.js +++ /dev/null @@ -1,120 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/InspectorController'], - function (InspectorController) { - - describe("The inspector controller ", function () { - var mockScope, - mockDomainObject, - mockOpenMCT, - mockSelection, - mockInspectorViews, - mockTypeDef, - controller, - container, - $document = [], - selectable = []; - - beforeEach(function () { - mockTypeDef = { - typeDef: { - inspector: "some-key" - } - }; - - mockDomainObject = jasmine.createSpyObj('domainObject', [ - 'getCapability' - ]); - mockDomainObject.getCapability.and.returnValue(mockTypeDef); - - mockScope = jasmine.createSpyObj('$scope', - ['$on', 'selection'] - ); - - selectable[0] = { - context: { - oldItem: mockDomainObject - } - }; - - mockSelection = jasmine.createSpyObj("selection", [ - 'on', - 'off', - 'get' - ]); - mockSelection.get.and.returnValue(selectable); - - mockInspectorViews = jasmine.createSpyObj('inspectorViews', ['get']); - mockOpenMCT = { - selection: mockSelection, - inspectorViews: mockInspectorViews - }; - - container = jasmine.createSpy('container', ['innerHTML']); - $document[0] = jasmine.createSpyObj("$document", ['querySelectorAll']); - $document[0].querySelectorAll.and.returnValue([container]); - - controller = new InspectorController(mockScope, mockOpenMCT, $document); - }); - - it("listens for selection change event", function () { - expect(mockOpenMCT.selection.on).toHaveBeenCalledWith( - 'change', - jasmine.any(Function) - ); - - expect(controller.selectedItem()).toEqual(mockDomainObject); - - var mockItem = jasmine.createSpyObj('domainObject', [ - 'getCapability' - ]); - mockItem.getCapability.and.returnValue(mockTypeDef); - selectable[0].context.oldItem = mockItem; - - mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable); - - expect(controller.selectedItem()).toEqual(mockItem); - }); - - it("cleans up on scope destroy", function () { - expect(mockScope.$on).toHaveBeenCalledWith( - '$destroy', - jasmine.any(Function) - ); - - mockScope.$on.calls.all()[0].args[1](); - - expect(mockOpenMCT.selection.off).toHaveBeenCalledWith( - 'change', - jasmine.any(Function) - ); - }); - - it("adds selection object to scope", function () { - expect(mockScope.selection).toEqual(selectable); - expect(controller.selectedItem()).toEqual(mockDomainObject); - }); - }); - } -); diff --git a/platform/commonUI/regions/test/RegionSpec.js b/platform/commonUI/regions/test/RegionSpec.js deleted file mode 100644 index b6e3eab3eb..0000000000 --- a/platform/commonUI/regions/test/RegionSpec.js +++ /dev/null @@ -1,103 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/Region'], - function (Region) { - - describe("The region class ", function () { - - var region, - part2 = new Region({'name': 'part2'}); - - beforeEach(function () { - region = new Region(); - region.regions = [ - new Region({name: 'part1'}), - new Region({name: 'part3'}), - new Region({name: 'part4'}) - ]; - }); - - it("adding a region at a specified index adds it in that" - + " position", function () { - - region.addRegion(part2, 1); - - expect(region.regions.length).toBe(4); - expect(region.regions[1]).toBe(part2); - }); - - it("adding a region without an index adds it at the end", function () { - var partN = new Region({'name': 'partN'}); - - region.addRegion(partN); - - expect(region.regions.length).toBe(4); - expect(region.regions[region.regions.length - 1]).toBe(partN); - }); - - describe("removing a region", function () { - var partName = "part2"; - - beforeEach(function () { - region.regions = [ - new Region({name: 'part1'}), - part2, - new Region({name: 'part3'}), - new Region({name: 'part4'}) - ]; - }); - - it("with a string matches on region name", function () { - expect(region.regions.length).toBe(4); - expect(region.regions.indexOf(part2)).toBe(1); - - region.removeRegion(partName); - - expect(region.regions.length).toBe(3); - expect(region.regions.indexOf(part2)).toBe(-1); - }); - - it("with a number removes by index", function () { - expect(region.regions.length).toBe(4); - expect(region.regions.indexOf(part2)).toBe(1); - - region.removeRegion(1); - - expect(region.regions.length).toBe(3); - expect(region.regions.indexOf(part2)).toBe(-1); - }); - - it("with object matches that object", function () { - expect(region.regions.length).toBe(4); - expect(region.regions.indexOf(part2)).toBe(1); - - region.removeRegion(part2); - - expect(region.regions.length).toBe(3); - expect(region.regions.indexOf(part2)).toBe(-1); - }); - }); - }); - } -); diff --git a/platform/containment/README.md b/platform/containment/README.md deleted file mode 100644 index b72c3674fa..0000000000 --- a/platform/containment/README.md +++ /dev/null @@ -1,2 +0,0 @@ -Implements support for rules which determine which objects are allowed -to contain other objects, typically by type. diff --git a/platform/containment/bundle.js b/platform/containment/bundle.js deleted file mode 100644 index a1cd8ba295..0000000000 --- a/platform/containment/bundle.js +++ /dev/null @@ -1,76 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/CompositionPolicy", - "./src/CompositionMutabilityPolicy", - "./src/CompositionModelPolicy", - "./src/ComposeActionPolicy", - "./src/PersistableCompositionPolicy" -], function ( - CompositionPolicy, - CompositionMutabilityPolicy, - CompositionModelPolicy, - ComposeActionPolicy, - PersistableCompositionPolicy -) { - - return { - name: "platform/containment", - definition: { - "extensions": { - "policies": [ - { - "category": "composition", - "implementation": CompositionPolicy, - "message": "Objects of this type cannot contain objects of that type." - }, - { - "category": "composition", - "implementation": CompositionMutabilityPolicy, - "message": "Objects of this type cannot be modified." - }, - { - "category": "composition", - "implementation": CompositionModelPolicy, - "message": "Objects of this type cannot contain other objects." - }, - { - "category": "action", - "implementation": ComposeActionPolicy, - "depends": [ - "$injector", - "openmct" - ], - "message": "Objects of this type cannot contain objects of that type." - }, - { - "category": "composition", - "implementation": PersistableCompositionPolicy, - "depends": ["openmct"], - "message": "Change cannot be made to composition of non-persistable object" - } - ] - } - } - }; -}); diff --git a/platform/containment/src/ComposeActionPolicy.js b/platform/containment/src/ComposeActionPolicy.js deleted file mode 100644 index 8d5b470cd1..0000000000 --- a/platform/containment/src/ComposeActionPolicy.js +++ /dev/null @@ -1,78 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Restrict `compose` actions to cases where composition - * is explicitly allowed. - * - * Note that this is a policy that needs the `policyService`, - * since it's delegated to a different policy category. - * To avoid a circular dependency, the service is obtained via - * Angular's `$injector`. - * @constructor - * @memberof platform/containment - * @implements {Policy.} - */ - function ComposeActionPolicy($injector, openmct) { - this.getPolicyService = function () { - return $injector.get('policyService'); - }; - - this.openmct = openmct; - } - - ComposeActionPolicy.prototype.allowComposition = function (containerObject, selectedObject) { - - // Get a reference to the policy service if needed... - this.policyService = this.policyService || this.getPolicyService(); - - // ...and delegate to the composition policy - return containerObject.getId() !== selectedObject.getId() - && this.openmct.composition.checkPolicy(containerObject.useCapability('adapter'), - selectedObject.useCapability('adapter')); - }; - - /** - * Check whether or not a compose action should be allowed - * in this context. - * @returns {boolean} true if it may be allowed - * @memberof platform/containment.ComposeActionPolicy# - */ - ComposeActionPolicy.prototype.allow = function (candidate, context) { - if (candidate.getMetadata().key === 'compose') { - return this.allowComposition( - (context || {}).domainObject, - (context || {}).selectedObject - ); - } - - return true; - }; - - return ComposeActionPolicy; - - } -); diff --git a/platform/containment/src/CompositionModelPolicy.js b/platform/containment/src/CompositionModelPolicy.js deleted file mode 100644 index 11f27449e9..0000000000 --- a/platform/containment/src/CompositionModelPolicy.js +++ /dev/null @@ -1,26 +0,0 @@ - -define( - [], - function () { - - /** - * Policy allowing composition only for domain object types which - * have a composition property. - * @constructor - * @memberof platform/containment - * @implements {Policy.} - */ - function CompositionModelPolicy() { - } - - CompositionModelPolicy.prototype.allow = function (candidate) { - var candidateType = candidate.getCapability('type'); - - return Array.isArray( - (candidateType.getInitialModel() || {}).composition - ); - }; - - return CompositionModelPolicy; - } -); diff --git a/platform/containment/src/CompositionMutabilityPolicy.js b/platform/containment/src/CompositionMutabilityPolicy.js deleted file mode 100644 index 24fc08477f..0000000000 --- a/platform/containment/src/CompositionMutabilityPolicy.js +++ /dev/null @@ -1,45 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Disallow composition changes to objects which are not mutable. - * @memberof platform/containment - * @constructor - * @implements {Policy.} - */ - function CompositionMutabilityPolicy() { - } - - CompositionMutabilityPolicy.prototype.allow = function (candidate) { - // Equate creatability with mutability; that is, users - // can only modify objects of types they can create, and - // vice versa. - return candidate.getCapability('type').hasFeature('creation'); - }; - - return CompositionMutabilityPolicy; - } -); diff --git a/platform/containment/src/CompositionPolicy.js b/platform/containment/src/CompositionPolicy.js deleted file mode 100644 index 38aff60f27..0000000000 --- a/platform/containment/src/CompositionPolicy.js +++ /dev/null @@ -1,71 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -/** - * This bundle implements "containment" rules, which determine which objects - * can be contained within which other objects. - * @namespace platform/containment - */ -define( - [], - function () { - - /** - * Determines whether a given object can contain a candidate child object. - * @constructor - * @memberof platform/containment - * @implements {Policy.} - */ - function CompositionPolicy() { - } - - CompositionPolicy.prototype.allow = function (parent, child) { - var parentDef = parent.getCapability('type').getDefinition(); - - // A parent without containment rules can contain anything. - if (!parentDef.contains) { - return true; - } - - // If any containment rule matches context type, the candidate - // can contain this type. - return parentDef.contains.some(function (c) { - // Simple containment rules are supported typeKeys. - if (typeof c === 'string') { - return c === child.getCapability('type').getKey(); - } - - // More complicated rules require context to have all specified - // capabilities. - if (!Array.isArray(c.has)) { - c.has = [c.has]; - } - - return c.has.every(function (capability) { - return child.hasCapability(capability); - }); - }); - }; - - return CompositionPolicy; - } -); diff --git a/platform/containment/src/PersistableCompositionPolicy.js b/platform/containment/src/PersistableCompositionPolicy.js deleted file mode 100644 index 824fb17906..0000000000 --- a/platform/containment/src/PersistableCompositionPolicy.js +++ /dev/null @@ -1,61 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -/** - * This bundle implements "containment" rules, which determine which objects - * can be contained within which other objects. - * @namespace platform/containment - */ -define( - ['objectUtils'], - function (objectUtils) { - - function PersistableCompositionPolicy(openmct) { - this.openmct = openmct; - } - - /** - * Only allow changes to composition if the changes can be saved. This in - * effect prevents selection of objects from the locator that do not - * support persistence. - * @param parent - * @param child - * @returns {boolean} - */ - PersistableCompositionPolicy.prototype.allow = function (parent) { - // If object is in edit mode, allow composition because it is - // part of object creation, and the object may be saved to another - // namespace that does support persistence. The EditPersistableObjectsPolicy - // prevents editing of objects that cannot be persisted, so we can assume that this - // is a new object. - if (!(parent.hasCapability('editor') && parent.getCapability('editor').isEditContextRoot())) { - let identifier = this.openmct.objects.parseKeyString(parent.getId()); - - return this.openmct.objects.isPersistable(identifier); - } - - return true; - }; - - return PersistableCompositionPolicy; - } -); diff --git a/platform/containment/test/ComposeActionPolicySpec.js b/platform/containment/test/ComposeActionPolicySpec.js deleted file mode 100644 index 2a8faa7e61..0000000000 --- a/platform/containment/test/ComposeActionPolicySpec.js +++ /dev/null @@ -1,95 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/ComposeActionPolicy"], - function (ComposeActionPolicy) { - xdescribe("The compose action policy", function () { - var mockInjector, - mockPolicyService, - mockTypes, - mockDomainObjects, - mockAction, - testContext, - policy; - - beforeEach(function () { - mockInjector = jasmine.createSpyObj('$injector', ['get']); - mockPolicyService = jasmine.createSpyObj( - 'policyService', - ['allow'] - ); - mockTypes = ['a', 'b'].map(function (type) { - var mockType = jasmine.createSpyObj('type-' + type, ['getKey']); - mockType.getKey.and.returnValue(type); - - return mockType; - }); - mockDomainObjects = ['a', 'b'].map(function (id, index) { - var mockDomainObject = jasmine.createSpyObj( - 'domainObject-' + id, - ['getId', 'getCapability'] - ); - mockDomainObject.getId.and.returnValue(id); - mockDomainObject.getCapability.and.callFake(function (c) { - return c === 'type' && mockTypes[index]; - }); - - return mockDomainObject; - }); - mockAction = jasmine.createSpyObj('action', ['getMetadata']); - - testContext = { - key: 'compose', - domainObject: mockDomainObjects[0], - selectedObject: mockDomainObjects[1] - }; - - mockAction.getMetadata.and.returnValue(testContext); - mockInjector.get.and.callFake(function (service) { - return service === 'policyService' && mockPolicyService; - }); - - policy = new ComposeActionPolicy(mockInjector); - }); - - it("defers to composition policy", function () { - mockPolicyService.allow.and.returnValue(false); - expect(policy.allow(mockAction, testContext)).toBeFalsy(); - mockPolicyService.allow.and.returnValue(true); - expect(policy.allow(mockAction, testContext)).toBeTruthy(); - - expect(mockPolicyService.allow).toHaveBeenCalledWith( - 'composition', - mockDomainObjects[0], - mockDomainObjects[1] - ); - }); - - it("allows actions other than compose", function () { - testContext.key = 'somethingElse'; - mockPolicyService.allow.and.returnValue(false); - expect(policy.allow(mockAction, testContext)).toBeTruthy(); - }); - }); - } -); diff --git a/platform/containment/test/CompositionModelPolicySpec.js b/platform/containment/test/CompositionModelPolicySpec.js deleted file mode 100644 index c2ebb9e45d..0000000000 --- a/platform/containment/test/CompositionModelPolicySpec.js +++ /dev/null @@ -1,30 +0,0 @@ - -define( - ["../src/CompositionModelPolicy"], - function (CompositionModelPolicy) { - - describe("The composition model policy", function () { - var mockObject, - mockType, - policy; - - beforeEach(function () { - mockType = jasmine.createSpyObj('type', ['getInitialModel']); - mockObject = { - getCapability: function () { - return mockType; - } - }; - policy = new CompositionModelPolicy(); - }); - - it("only allows composition for types which will have a composition property", function () { - mockType.getInitialModel.and.returnValue({}); - expect(policy.allow(mockObject)).toBeFalsy(); - mockType.getInitialModel.and.returnValue({ composition: [] }); - expect(policy.allow(mockObject)).toBeTruthy(); - }); - }); - - } -); diff --git a/platform/containment/test/CompositionMutabilityPolicySpec.js b/platform/containment/test/CompositionMutabilityPolicySpec.js deleted file mode 100644 index 720cc464e6..0000000000 --- a/platform/containment/test/CompositionMutabilityPolicySpec.js +++ /dev/null @@ -1,51 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/CompositionMutabilityPolicy"], - function (CompositionMutabilityPolicy) { - - describe("The composition mutability policy", function () { - var mockObject, - mockType, - policy; - - beforeEach(function () { - mockType = jasmine.createSpyObj('type', ['hasFeature']); - mockObject = { - getCapability: function () { - return mockType; - } - }; - policy = new CompositionMutabilityPolicy(); - }); - - it("only allows composition for types which can be created/modified", function () { - expect(policy.allow(mockObject)).toBeFalsy(); - mockType.hasFeature.and.returnValue(true); - expect(policy.allow(mockObject)).toBeTruthy(); - expect(mockType.hasFeature).toHaveBeenCalledWith('creation'); - }); - }); - - } -); diff --git a/platform/containment/test/CompositionPolicySpec.js b/platform/containment/test/CompositionPolicySpec.js deleted file mode 100644 index 23adfaeb3b..0000000000 --- a/platform/containment/test/CompositionPolicySpec.js +++ /dev/null @@ -1,131 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/CompositionPolicy"], - function (CompositionPolicy) { - describe("Composition policy", function () { - var mockParentObject, - typeA, - typeB, - typeC, - mockChildObject, - policy; - - beforeEach(function () { - mockParentObject = jasmine.createSpyObj('domainObject', [ - 'getCapability' - ]); - - typeA = jasmine.createSpyObj( - 'type A-- the particular kind', - ['getKey', 'getDefinition'] - ); - typeA.getKey.and.returnValue('a'); - typeA.getDefinition.and.returnValue({ - contains: ['a'] - }); - - typeB = jasmine.createSpyObj( - 'type B-- anything goes', - ['getKey', 'getDefinition'] - ); - typeB.getKey.and.returnValue('b'); - typeB.getDefinition.and.returnValue({ - contains: ['a', 'b'] - }); - - typeC = jasmine.createSpyObj( - 'type C-- distinguishing and interested in telemetry', - ['getKey', 'getDefinition'] - ); - typeC.getKey.and.returnValue('c'); - typeC.getDefinition.and.returnValue({ - contains: [{has: 'telemetry'}] - }); - - mockChildObject = jasmine.createSpyObj( - 'childObject', - ['getCapability', 'hasCapability'] - ); - - policy = new CompositionPolicy(); - }); - - describe('enforces simple containment rules', function () { - - it('allows when type matches', function () { - mockParentObject.getCapability.and.returnValue(typeA); - - mockChildObject.getCapability.and.returnValue(typeA); - expect(policy.allow(mockParentObject, mockChildObject)) - .toBeTruthy(); - - mockParentObject.getCapability.and.returnValue(typeB); - expect(policy.allow(mockParentObject, mockChildObject)) - .toBeTruthy(); - - mockChildObject.getCapability.and.returnValue(typeB); - expect(policy.allow(mockParentObject, mockChildObject)) - .toBeTruthy(); - }); - - it('disallows when type doesn\'t match', function () { - - mockParentObject.getCapability.and.returnValue(typeA); - mockChildObject.getCapability.and.returnValue(typeB); - expect(policy.allow(mockParentObject, mockChildObject)) - .toBeFalsy(); - - mockChildObject.getCapability.and.returnValue(typeC); - expect(policy.allow(mockParentObject, mockChildObject)) - .toBeFalsy(); - }); - - }); - - describe('enforces capability-based containment rules', function () { - it('allows when object has capability', function () { - mockParentObject.getCapability.and.returnValue(typeC); - - mockChildObject.hasCapability.and.returnValue(true); - expect(policy.allow(mockParentObject, mockChildObject)) - .toBeTruthy(); - expect(mockChildObject.hasCapability) - .toHaveBeenCalledWith('telemetry'); - }); - - it('skips when object doesn\'t have capability', function () { - mockChildObject.hasCapability.and.returnValue(false); - - mockParentObject.getCapability.and.returnValue(typeC); - - expect(policy.allow(mockParentObject, mockChildObject)) - .toBeFalsy(); - expect(mockChildObject.hasCapability) - .toHaveBeenCalledWith('telemetry'); - }); - }); - - }); - } -); diff --git a/platform/containment/test/PersistableCompositionPolicySpec.js b/platform/containment/test/PersistableCompositionPolicySpec.js deleted file mode 100644 index 6921613663..0000000000 --- a/platform/containment/test/PersistableCompositionPolicySpec.js +++ /dev/null @@ -1,85 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PersistableCompositionPolicy"], - function (PersistableCompositionPolicy) { - describe("Persistable Composition policy", function () { - var objectAPI; - var mockOpenMCT; - var persistableCompositionPolicy; - var mockParent; - var mockChild; - var mockEditorCapability; - - beforeEach(function () { - objectAPI = jasmine.createSpyObj('objectsAPI', [ - 'isPersistable', - 'parseKeyString' - ]); - - mockOpenMCT = { - objects: objectAPI - }; - mockParent = jasmine.createSpyObj('domainObject', [ - 'hasCapability', - 'getCapability', - 'getId' - ]); - mockParent.hasCapability.and.returnValue(true); - mockParent.getId.and.returnValue('someNamespace:someId'); - mockChild = {}; - mockEditorCapability = jasmine.createSpyObj('domainObject', [ - 'isEditContextRoot' - ]); - mockParent.getCapability.and.returnValue(mockEditorCapability); - persistableCompositionPolicy = new PersistableCompositionPolicy(mockOpenMCT); - }); - - //Parent - // - getCapability ('editor') - // - isEditContextRoot - // - openMct.objects.getProvider - - it("Does not allow composition for objects that are not persistable", function () { - mockEditorCapability.isEditContextRoot.and.returnValue(false); - objectAPI.isPersistable.and.returnValue(true); - expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true); - objectAPI.isPersistable.and.returnValue(false); - expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(false); - }); - - it("Always allows composition of objects in edit mode to support object creation", function () { - mockEditorCapability.isEditContextRoot.and.returnValue(true); - objectAPI.isPersistable.and.returnValue(true); - expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true); - expect(objectAPI.isPersistable).not.toHaveBeenCalled(); - - mockEditorCapability.isEditContextRoot.and.returnValue(false); - objectAPI.isPersistable.and.returnValue(true); - expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true); - expect(objectAPI.isPersistable).toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/core/README.md b/platform/core/README.md deleted file mode 100644 index 422ab4ce63..0000000000 --- a/platform/core/README.md +++ /dev/null @@ -1,3 +0,0 @@ -This bundle contains core software components of Open MCT. These -components describe MCT's information model, and are responsible for -introducing the API and infrastructure which supports domain objects. diff --git a/platform/core/bundle.js b/platform/core/bundle.js deleted file mode 100644 index 660b354b9e..0000000000 --- a/platform/core/bundle.js +++ /dev/null @@ -1,357 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/objects/DomainObjectProvider", - "./src/capabilities/CoreCapabilityProvider", - "./src/models/StaticModelProvider", - "./src/models/ModelAggregator", - "./src/models/ModelCacheService", - "./src/models/PersistedModelProvider", - "./src/models/CachingModelDecorator", - "./src/types/TypeProvider", - "./src/actions/ActionProvider", - "./src/actions/ActionAggregator", - "./src/actions/LoggingActionDecorator", - "./src/views/ViewProvider", - "./src/identifiers/IdentifierProvider", - "./src/capabilities/CompositionCapability", - "./src/capabilities/RelationshipCapability", - "./src/types/TypeCapability", - "./src/actions/ActionCapability", - "./src/views/ViewCapability", - "./src/capabilities/PersistenceCapability", - "./src/capabilities/MetadataCapability", - "./src/capabilities/MutationCapability", - "./src/capabilities/DelegationCapability", - "./src/capabilities/InstantiationCapability", - "./src/services/Now", - "./src/services/Throttle", - "./src/services/Topic", - "./src/services/Instantiate" -], function ( - DomainObjectProvider, - CoreCapabilityProvider, - StaticModelProvider, - ModelAggregator, - ModelCacheService, - PersistedModelProvider, - CachingModelDecorator, - TypeProvider, - ActionProvider, - ActionAggregator, - LoggingActionDecorator, - ViewProvider, - IdentifierProvider, - CompositionCapability, - RelationshipCapability, - TypeCapability, - ActionCapability, - ViewCapability, - PersistenceCapability, - MetadataCapability, - MutationCapability, - DelegationCapability, - InstantiationCapability, - Now, - Throttle, - Topic, - Instantiate -) { - - return { - name: "platform/core", - definition: { - "name": "Open MCT Core", - "description": "Defines core concepts of Open MCT.", - "sources": "src", - "configuration": { - "paths": { - "uuid": "uuid" - } - }, - "extensions": { - "components": [ - { - "provides": "objectService", - "type": "provider", - "implementation": DomainObjectProvider, - "depends": [ - "modelService", - "instantiate" - ] - }, - { - "provides": "capabilityService", - "type": "provider", - "implementation": CoreCapabilityProvider, - "depends": [ - "capabilities[]", - "$log" - ] - }, - { - "provides": "modelService", - "type": "provider", - "implementation": StaticModelProvider, - "depends": [ - "models[]", - "$q", - "$log" - ] - }, - { - "provides": "modelService", - "type": "aggregator", - "implementation": ModelAggregator, - "depends": [ - "$q" - ] - }, - { - "provides": "modelService", - "type": "provider", - "implementation": PersistedModelProvider, - "depends": [ - "persistenceService", - "$q", - "now", - "PERSISTENCE_SPACE" - ] - }, - { - "provides": "modelService", - "type": "decorator", - "implementation": CachingModelDecorator, - "depends": [ - "cacheService" - ] - }, - { - "provides": "typeService", - "type": "provider", - "implementation": TypeProvider, - "depends": [ - "types[]" - ] - }, - { - "provides": "actionService", - "type": "provider", - "implementation": ActionProvider, - "depends": [ - "actions[]", - "$log" - ] - }, - { - "provides": "actionService", - "type": "aggregator", - "implementation": ActionAggregator - }, - { - "provides": "actionService", - "type": "decorator", - "implementation": LoggingActionDecorator, - "depends": [ - "$log" - ] - }, - { - "provides": "viewService", - "type": "provider", - "implementation": ViewProvider, - "depends": [ - "views[]", - "$log" - ] - }, - { - "provides": "identifierService", - "type": "provider", - "implementation": IdentifierProvider, - "depends": [ - "PERSISTENCE_SPACE" - ] - } - ], - "types": [ - { - "properties": [ - { - "control": "textfield", - "name": "Title", - "key": "name", - "property": "name", - "pattern": "\\S+", - "required": true, - "cssClass": "l-input-lg" - }, - { - "name": "Notes", - "key": "notes", - "property": "notes", - "control": "textarea", - "required": false, - "cssClass": "l-textarea-sm" - } - ] - }, - { - "key": "root", - "name": "Root", - "cssClass": "icon-folder" - } - ], - "capabilities": [ - { - "key": "composition", - "implementation": CompositionCapability, - "depends": [ - "$injector" - ] - }, - { - "key": "relationship", - "implementation": RelationshipCapability, - "depends": [ - "$injector" - ] - }, - { - "key": "type", - "implementation": TypeCapability, - "depends": [ - "typeService" - ] - }, - { - "key": "action", - "implementation": ActionCapability, - "depends": [ - "$q", - "actionService" - ] - }, - { - "key": "view", - "implementation": ViewCapability, - "depends": [ - "viewService" - ] - }, - { - "key": "persistence", - "implementation": PersistenceCapability, - "depends": [ - "cacheService", - "persistenceService", - "identifierService", - "notificationService", - "$q", - "openmct" - ] - }, - { - "key": "metadata", - "implementation": MetadataCapability - }, - { - "key": "mutation", - "implementation": MutationCapability, - "depends": [ - "topic", - "now" - ] - }, - { - "key": "delegation", - "implementation": DelegationCapability, - "depends": [ - "$q" - ] - }, - { - "key": "instantiation", - "implementation": InstantiationCapability, - "depends": [ - "$injector", - "identifierService", - "now" - ] - } - ], - "services": [ - { - "key": "cacheService", - "implementation": ModelCacheService - }, - { - "key": "now", - "implementation": Now - }, - { - "key": "throttle", - "implementation": Throttle, - "depends": [ - "$timeout" - ] - }, - { - "key": "topic", - "implementation": Topic, - "depends": [ - "$log" - ] - }, - { - "key": "instantiate", - "implementation": Instantiate, - "depends": [ - "capabilityService", - "identifierService", - "cacheService" - ] - } - ], - "constants": [ - { - "key": "PERSISTENCE_SPACE", - "value": "mct" - } - ], - "licenses": [ - { - "name": "Math.uuid.js", - "version": "1.4.7", - "description": "Unique identifier generation (code adapted.)", - "author": "Robert Kieffer", - "website": "https://github.com/broofa/node-uuid", - "copyright": "Copyright(c) 2010-2012 Robert Kieffer", - "license": "license-mit", - "link": "http://opensource.org/licenses/MIT" - } - ] - } - } - }; -}); diff --git a/platform/core/src/actions/ActionAggregator.js b/platform/core/src/actions/ActionAggregator.js deleted file mode 100644 index 2d640971b7..0000000000 --- a/platform/core/src/actions/ActionAggregator.js +++ /dev/null @@ -1,124 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Actions are reusable processes/behaviors performed by users within - * the system, typically upon domain objects. Actions are commonly - * exposed to users as menu items or buttons. - * - * Actions are usually registered via the `actions` extension - * category, or (in advanced cases) via an `actionService` - * implementation. - * - * @interface Action - */ - - /** - * Perform the behavior associated with this action. The return type - * may vary depending on which action has been performed; in general, - * no return value should be expected. - * - * @method Action#perform - */ - - /** - * Get metadata associated with this action. - * - * @method Action#getMetadata - * @returns {ActionMetadata} - */ - - /** - * Metadata associated with an Action. Actions of specific types may - * extend this with additional properties. - * - * @typedef {Object} ActionMetadata - * @property {string} key machine-readable identifier for this action - * @property {string} name human-readable name for this action - * @property {string} description human-readable description - * @property {string} cssClass CSS class for icon - * @property {ActionContext} context the context in which the action - * will be performed. - */ - - /** - * Provides actions that can be performed within specific contexts. - * - * @interface ActionService - */ - - /** - * Get actions which can be performed within a certain context. - * - * @method ActionService#getActions - * @param {ActionContext} context the context in which the action will - * be performed - * @return {Action[]} relevant actions - */ - - /** - * A description of the context in which an action may occur. - * - * @typedef ActionContext - * @property {DomainObject} [domainObject] the domain object being - * acted upon. - * @property {DomainObject} [selectedObject] the selection at the - * time of action (e.g. the dragged object in a - * drag-and-drop operation.) - * @property {string} [key] the machine-readable identifier of - * the relevant action - * @property {string} [category] a string identifying the category - * of action being performed - */ - - /** - * The ActionAggregator makes several actionService - * instances act as those they were one. When requesting - * actions for a given context, results from all - * services will be assembled and concatenated. - * - * @memberof platform/core - * @constructor - * @implements {ActionService} - * @param {ActionService[]} actionProviders an array - * of action services - */ - function ActionAggregator(actionProviders) { - this.actionProviders = actionProviders; - } - - ActionAggregator.prototype.getActions = function (context) { - // Get all actions from all providers, reduce down - // to one array by concatenation - return this.actionProviders.map(function (provider) { - return provider.getActions(context); - }).reduce(function (a, b) { - return a.concat(b); - }, []); - }; - - return ActionAggregator; - } -); diff --git a/platform/core/src/actions/ActionCapability.js b/platform/core/src/actions/ActionCapability.js deleted file mode 100644 index 2a9fc8c4a1..0000000000 --- a/platform/core/src/actions/ActionCapability.js +++ /dev/null @@ -1,119 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ActionCapability. Created by vwoeltje on 11/10/14. - */ -define( - ['lodash'], - function (_) { - - /** - * The ActionCapability allows applicable Actions to be retrieved and - * performed for specific domain objects, e.g.: - * - * `domainObject.getCapability("action").perform("navigate");` - * - * ...will initiate a navigate action upon the domain object, - * if an action with key "navigate" is defined. - * - * @param {*} $q Angular's $q service, for promises - * @param {ActionService} actionService the service from - * which to retrieve actions. - * @param {DomainObject} domainObject the object upon - * which the action will be performed (also, the - * action which exposes the capability.) - * - * @memberof platform/core - * @constructor - */ - function ActionCapability($q, actionService, domainObject) { - this.$q = $q; - this.actionService = actionService; - this.domainObject = domainObject; - } - - /** - * Perform an action. This will find and perform the - * first matching action available for the specified - * context or key. - * - * @param {ActionContext|string} context the context in which - * to perform the action; this is passed along to - * the action service to match against available - * actions. The "domainObject" field will automatically - * be populated with the domain object that exposed - * this capability. If given as a string, this will - * be taken as the "key" field to match against - * specific actions. - * @returns {Promise} the result of the action that was - * performed, or undefined if no matching action - * was found. - * @memberof platform/core.ActionCapability# - */ - ActionCapability.prototype.getActions = function (context) { - // Get all actions which are valid in this context; - // this simply redirects to the action service, - // but additionally adds a domainObject field. - var baseContext; - if (typeof context === 'string') { - baseContext = { key: context }; - } else { - baseContext = context || {}; - } - - var actionContext = Object.assign({}, baseContext); - actionContext.domainObject = this.domainObject; - - return this.actionService.getActions(actionContext); - }; - - /** - * Get actions which are available for this domain object, - * in this context. - * - * @param {ActionContext|string} context the context in which - * to perform the action; this is passed along to - * the action service to match against available - * actions. The "domainObject" field will automatically - * be populated with the domain object that exposed - * this capability. If given as a string, this will - * be taken as the "key" field to match against - * specific actions. - * @returns {Action[]} an array of matching actions - * @memberof platform/core.ActionCapability# - */ - ActionCapability.prototype.perform = function (context, flag) { - // Alias to getActions(context)[0].perform, with a - // check for empty arrays. - var actions = this.getActions(context); - - return this.$q.when( - (actions && actions.length > 0) - ? actions[0].perform(flag) - : undefined - ); - }; - - return ActionCapability; - } -); diff --git a/platform/core/src/actions/ActionProvider.js b/platform/core/src/actions/ActionProvider.js deleted file mode 100644 index 0134bc45f2..0000000000 --- a/platform/core/src/actions/ActionProvider.js +++ /dev/null @@ -1,157 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ActionProvider. Created by vwoeltje on 11/7/14. - */ -define( - [], - function () { - - /** - * An ActionProvider (implementing ActionService) provides actions - * that are applicable in specific contexts, chosen from a set - * of actions exposed via extension (specifically, the "actions" - * category of extension.) - * - * @memberof platform/core - * @imeplements {ActionService} - * @constructor - */ - function ActionProvider(actions, $log) { - var self = this; - - this.$log = $log; - - // Build up look-up tables - this.actions = actions; - this.actionsByKey = {}; - this.actionsByCategory = {}; - actions.forEach(function (Action) { - // Get an action's category or categories - var categories = Action.category || []; - - // Convert to an array if necessary - categories = Array.isArray(categories) - ? categories : [categories]; - - // Store action under all relevant categories - categories.forEach(function (category) { - self.actionsByCategory[category] = - self.actionsByCategory[category] || []; - self.actionsByCategory[category].push(Action); - }); - - // Store action by ekey as well - if (Action.key) { - self.actionsByKey[Action.key] = - self.actionsByKey[Action.key] || []; - self.actionsByKey[Action.key].push(Action); - } - }); - } - - ActionProvider.prototype.getActions = function (actionContext) { - var context = (actionContext || {}), - category = context.category, - key = context.key, - $log = this.$log, - candidates; - - // Instantiate an action; invokes the constructor and - // additionally fills in the action's getMetadata method - // with the extension definition (if no getMetadata - // method was supplied.) - function instantiateAction(Action, ctxt) { - var action = new Action(ctxt), - metadata; - - // Provide a getMetadata method that echos - // declarative bindings, as well as context, - // unless the action has defined its own. - if (!action.getMetadata) { - metadata = Object.create(Action.definition || {}); - metadata.context = ctxt; - action.getMetadata = function () { - return metadata; - }; - } - - return action; - } - - // Filter the array of actions down to those which are - // applicable in a given context, according to the static - // appliesTo method of given actions (if defined), and - // instantiate those applicable actions. - function createIfApplicable(actions, ctxt) { - function isApplicable(Action) { - return Action.appliesTo ? Action.appliesTo(ctxt) : true; - } - - function instantiate(Action) { - try { - return instantiateAction(Action, ctxt); - } catch (e) { - $log.error([ - "Could not instantiate action", - Action.key, - "due to:", - e.message - ].join(" ")); - - return undefined; - } - } - - function isDefined(action) { - return action !== undefined; - } - - return (actions || []).filter(isApplicable) - .map(instantiate) - .filter(isDefined); - } - - // Match actions to the provided context by comparing "key" - // and/or "category" parameters, if specified. - candidates = this.actions; - if (key) { - candidates = this.actionsByKey[key]; - if (category) { - candidates = candidates.filter(function (Action) { - return Action.category === category; - }); - } - } else if (category) { - candidates = this.actionsByCategory[category]; - } - - // Instantiate those remaining actions, with additional - // filtering per any appliesTo methods defined on those - // actions. - return createIfApplicable(candidates, context); - }; - - return ActionProvider; - } -); diff --git a/platform/core/src/actions/LoggingActionDecorator.js b/platform/core/src/actions/LoggingActionDecorator.js deleted file mode 100644 index 21f988587c..0000000000 --- a/platform/core/src/actions/LoggingActionDecorator.js +++ /dev/null @@ -1,80 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 LoggingActionDecorator. Created by vwoeltje on 11/17/14. - */ -define( - [], - function () { - - /** - * The LoggingActionDecorator decorates an ActionService such that - * the actions it exposes always emit a log message when they are - * performed. - * - * @memberof platform/core - * @constructor - * @implements {ActionService} - * @param $log Angular's logging service - * @param {ActionService} actionService the decorated action service - */ - function LoggingActionDecorator($log, actionService) { - this.$log = $log; - this.actionService = actionService; - } - - LoggingActionDecorator.prototype.getActions = function () { - var actionService = this.actionService, - $log = this.$log; - - // Decorate the perform method of the specified action, such that - // it emits a log message whenever performed. - function addLogging(action) { - var logAction = Object.create(action), - metadata = action.getMetadata() || {}, - context = metadata.context || {}, - domainObject = context.domainObject; - - logAction.perform = function () { - $log.info([ - "Performing action ", - metadata.key, - " upon ", - domainObject && domainObject.getId() - ].join("")); - - return action.perform.apply(action, arguments); - }; - - return logAction; - } - - return actionService.getActions.apply( - actionService, - arguments - ).map(addLogging); - }; - - return LoggingActionDecorator; - } -); diff --git a/platform/core/src/capabilities/CompositionCapability.js b/platform/core/src/capabilities/CompositionCapability.js deleted file mode 100644 index f0eaefdf95..0000000000 --- a/platform/core/src/capabilities/CompositionCapability.js +++ /dev/null @@ -1,162 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 CompositionCapability. Created by vwoeltje on 11/7/14. - */ -define( - ['./ContextualDomainObject'], - function (ContextualDomainObject) { - - /** - * Composition capability. A domain object's composition is the set of - * domain objects it contains. This is available as an array of - * identifiers in the model; the composition capability makes this - * available as an array of domain object instances, which may - * require consulting the object service (e.g. to trigger a database - * query to retrieve the nested object models.) - * - * @memberof platform/core - * @constructor - * @implements {Capability} - */ - function CompositionCapability($injector, domainObject) { - // Get a reference to the object service from $injector - this.injectObjectService = function () { - this.objectService = $injector.get("objectService"); - }; - - this.domainObject = domainObject; - } - - /** - * Add a domain object to the composition of this domain object. - * - * If no index is given, this is added to the end of the composition. - * - * @param {DomainObject|string} domainObject the domain object to add, - * or simply its identifier - * @param {number} [index] the index at which to add the object - * @returns {Promise.} a promise for the added object - * in its new context - */ - CompositionCapability.prototype.add = function (domainObject, index) { - var self = this, - id = typeof domainObject === 'string' - ? domainObject : domainObject.getId(), - model = self.domainObject.getModel(), - composition = model.composition, - oldIndex = composition.indexOf(id); - - // Find the object with the above id, used to contextualize - function findObject(objects) { - var i; - for (i = 0; i < objects.length; i += 1) { - if (objects[i].getId() === id) { - return objects[i]; - } - } - } - - function contextualize(mutationResult) { - return mutationResult && self.invoke().then(findObject); - } - - function addIdToModel(objModel) { - // Pick a specific index if needed. - index = isNaN(index) ? composition.length : index; - // Also, don't put past the end of the array - index = Math.min(composition.length, index); - - // Remove the existing instance of the id - if (oldIndex !== -1) { - objModel.composition.splice(oldIndex, 1); - } - - // ...and add it back at the appropriate index. - objModel.composition.splice(index, 0, id); - } - - // If no index has been specified already and the id is already - // present, nothing to do. If the id is already at that index, - // also nothing to do, so cancel mutation. - if ((isNaN(index) && oldIndex !== -1) || (index === oldIndex)) { - return contextualize(true); - } - - return this.domainObject.useCapability('mutation', addIdToModel) - .then(contextualize); - }; - - /** - * Request the composition of this object. - * @returns {Promise.} a list of all domain - * objects which compose this domain object. - */ - CompositionCapability.prototype.invoke = function () { - var domainObject = this.domainObject, - model = domainObject.getModel(), - ids; - - // Then filter out non-existent objects, - // and wrap others (such that they expose a - // "context" capability) - function contextualizeObjects(objects) { - return ids.filter(function (id) { - return objects[id]; - }).map(function (id) { - return new ContextualDomainObject(objects[id], domainObject); - }); - } - - // Lazily acquire object service (avoids cyclical dependency) - if (!this.objectService) { - this.injectObjectService(); - } - - // Make a new request if we haven't made one, or if the - // object has been modified. - if (!this.lastPromise || this.lastModified !== model.modified) { - ids = model.composition || []; - this.lastModified = model.modified; - // Load from the underlying object service - this.lastPromise = this.objectService.getObjects(ids) - .then(contextualizeObjects); - } - - return this.lastPromise; - }; - - /** - * Test to determine whether or not this capability should be exposed - * by a domain object based on its model. Checks for the presence of - * a composition field, that must be an array. - * @param model the domain object model - * @returns {boolean} true if this object has a composition - */ - CompositionCapability.appliesTo = function (model) { - return Array.isArray((model || {}).composition); - }; - - return CompositionCapability; - } -); diff --git a/platform/core/src/capabilities/ContextCapability.js b/platform/core/src/capabilities/ContextCapability.js deleted file mode 100644 index 42819ea900..0000000000 --- a/platform/core/src/capabilities/ContextCapability.js +++ /dev/null @@ -1,111 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ContextCapability. Created by vwoeltje on 11/17/14. - */ -define( - [], - function () { - - /** - * The `context` capability of a domain object (retrievable with - * `domainObject.getCapability("context")`) allows an object's - * hierarchical parents and ancestors to be retrieved (specifically, - * those whose `composition` capability was used to access this - * object.) - * - * @memberof platform/core - * @constructor - * @implements {Capability} - */ - function ContextCapability(parentObject, domainObject) { - this.parentObject = parentObject; - this.domainObject = domainObject; - } - - /** - * Get the immediate parent of a domain object. - * - * A domain object may be contained in multiple places; its - * parent (as exposed by this capability) is the domain - * object from which this object was accessed, usually - * by way of a `composition` capability. - * - * @returns {DomainObject} the immediate parent of this - * domain object. - */ - ContextCapability.prototype.getParent = function () { - return this.parentObject; - }; - - /** - * Get an array containing the complete direct ancestry - * of this domain object, including the domain object - * itself. - * - * A domain object may be contained in multiple places; its - * parent and all ancestors (as exposed by this capability) - * serve as a record of how this specific domain object - * instance was reached. - * - * The first element in the returned array is the deepest - * ancestor; subsequent elements are progressively more - * recent ancestors, with the domain object which exposed - * the capability occupying the last element of the array. - * - * @returns {DomainObject[]} the full composition ancestry - * of the domain object which exposed this - * capability. - */ - ContextCapability.prototype.getPath = function () { - var parentObject = this.parentObject, - parentContext = - parentObject && parentObject.getCapability('context'), - parentPath = parentContext - ? parentContext.getPath() : [this.parentObject]; - - return parentPath.concat([this.domainObject]); - }; - - /** - * Get the deepest ancestor available for this domain object; - * equivalent to `getPath()[0]`. - * - * See notes on `getPath()` for how ancestry is defined in - * the context of this capability. - * - * @returns {DomainObject} the deepest ancestor of the domain - * object which exposed this capability. - */ - ContextCapability.prototype.getRoot = function () { - var parentContext = this.parentObject - && this.parentObject.getCapability('context'); - - return parentContext - ? parentContext.getRoot() - : (this.parentObject || this.domainObject); - }; - - return ContextCapability; - } -); diff --git a/platform/core/src/capabilities/ContextualDomainObject.js b/platform/core/src/capabilities/ContextualDomainObject.js deleted file mode 100644 index 69d490b42f..0000000000 --- a/platform/core/src/capabilities/ContextualDomainObject.js +++ /dev/null @@ -1,66 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ContextualDomainObject. Created by vwoeltje on 11/18/14. - */ -define( - ["./ContextCapability"], - function (ContextCapability) { - - /** - * Wraps a domain object, such that it exposes a `context` capability. - * A domain object may be contained by multiple other domain objects; - * the `context` capability allows two instances of the same domain - * object to be distinguished from one another based on which - * specific instance of a containing object exposed them (by way of a - * `composition` capability.) - * - * @param {DomainObject} domainObject the domain object for which - * context should be exposed - * @param {DomainObject} parentObject the domain object from which - * the wrapped object was retrieved - * - * @memberof platform/core - * @constructor - * @implements {DomainObject} - */ - function ContextualDomainObject(domainObject, parentObject) { - // Prototypally inherit from the domain object, and - // instantiate its context capability ahead of time. - var contextualObject = Object.create(domainObject), - contextCapability = - new ContextCapability(parentObject, domainObject); - - // Intercept requests for a context capability. - contextualObject.getCapability = function (name) { - return name === "context" - ? contextCapability - : domainObject.getCapability.apply(this, arguments); - }; - - return contextualObject; - } - - return ContextualDomainObject; - } -); diff --git a/platform/core/src/capabilities/CoreCapabilityProvider.js b/platform/core/src/capabilities/CoreCapabilityProvider.js deleted file mode 100644 index 645a74f74b..0000000000 --- a/platform/core/src/capabilities/CoreCapabilityProvider.js +++ /dev/null @@ -1,110 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 CoreCapabilityProvider. Created by vwoeltje on 11/7/14. - */ -define( - [], - function () { - - /** - * A capability provides an interface with dealing with some - * dynamic behavior associated with a domain object. - * @interface Capability - */ - - /** - * Optional; if present, will be used by `DomainObject#useCapability` - * to simplify interaction with a specific capability. Parameters - * and return values vary depending on capability type. - * @method Capability#invoke - */ - - /** - * Provides capabilities based on extension definitions, - * matched to domain object models. - * - * @param {Array.} an array - * of constructor functions for capabilities, as - * exposed by extensions defined at the bundle level. - * - * @memberof platform/core - * @constructor - */ - function CoreCapabilityProvider(capabilities, $log) { - // Filter by invoking the capability's appliesTo method - function filterCapabilities(model, id) { - return capabilities.filter(function (capability) { - return capability.appliesTo - ? capability.appliesTo(model, id) - : true; - }); - } - - // Package capabilities as key-value pairs - function packageCapabilities(caps) { - var result = {}; - caps.forEach(function (capability) { - if (capability.key) { - result[capability.key] = - result[capability.key] || capability; - } else { - $log.warn("No key defined for capability; skipping."); - } - }); - - return result; - } - - function getCapabilities(model, id) { - return packageCapabilities(filterCapabilities(model, id)); - } - - return { - /** - * Get all capabilities associated with a given domain - * object. - * - * This returns a promise for an object containing key-value - * pairs, where keys are capability names and values are - * either: - * - * * Capability instances - * * Capability constructors (which take a domain object - * as their argument.) - * - * - * @param {*} model the object model - * @returns {Object.} all - * capabilities known to be valid for this model, as - * key-value pairs - * @memberof platform/core.CoreCapabilityProvider# - */ - getCapabilities: getCapabilities - }; - } - - return CoreCapabilityProvider; - } -); - diff --git a/platform/core/src/capabilities/DelegationCapability.js b/platform/core/src/capabilities/DelegationCapability.js deleted file mode 100644 index 443bfa1b28..0000000000 --- a/platform/core/src/capabilities/DelegationCapability.js +++ /dev/null @@ -1,129 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 DelegationCapability. Created by vwoeltje on 11/18/14. - */ -define( - [], - function () { - - /** - * The `delegation` capability allows a domain object to indicate - * that it wishes to delegate responsibility for some other - * capability to some other domain objects. - * - * This is specifically useful in the case of telemetry panels, - * which delegate responsibility for the `telemetry` capability - * to their contained objects. - * - * A type of domain object may indicate that it wishes to delegate - * responsibility for one or more capabilities to the members of - * its composition; this is done by included a `delegates` field - * in the type's definition, which contains an array of names of - * capabilities to be delegated. - * - * @param $q Angular's $q, for promises - * @param {DomainObject} domainObject the delegating domain object - * @memberof platform/core - * @constructor - * @implements {Capability} - */ - function DelegationCapability($q, domainObject) { - var type = domainObject.getCapability("type"), - self = this; - - this.$q = $q; - this.delegateCapabilities = {}; - this.domainObject = domainObject; - - // Generate set for easy lookup of capability delegation - if (type && type.getDefinition) { - (type.getDefinition().delegates || []).forEach(function (key) { - self.delegateCapabilities[key] = true; - }); - } - } - - /** - * Get the domain objects which are intended to be delegated - * responsibility for some specific capability. - * - * @param {string} key the name of the delegated capability - * @returns {DomainObject[]} the domain objects to which - * responsibility for this capability is delegated. - * @memberof platform/core.DelegationCapability# - */ - DelegationCapability.prototype.getDelegates = function (key) { - var domainObject = this.domainObject; - - function filterObjectsWithCapability(capability) { - return function (objects) { - return objects.filter(function (obj) { - return obj.hasCapability(capability); - }); - }; - } - - function promiseChildren() { - return domainObject.useCapability('composition'); - } - - return this.doesDelegateCapability(key) - ? promiseChildren().then( - filterObjectsWithCapability(key) - ) - : this.$q.when([]); - }; - - /** - * Check if the domain object which exposed this capability - * wishes to delegate another capability. - * - * @param {string} key the capability to check for - * @returns {boolean} true if the capability is delegated - */ - DelegationCapability.prototype.doesDelegateCapability = function (key) { - return Boolean(this.delegateCapabilities[key]); - }; - - /** - * Invoke this capability; alias of `getDelegates`, used to - * simplify usage, e.g.: - * - * `domainObject.useCapability("delegation", "telemetry")` - * - * ...will retrieve all members of a domain object's - * composition which have a "telemetry" capability. - * - * @param {string} the name of the delegated capability - * @returns {DomainObject[]} the domain objects to which - * responsibility for this capability is delegated. - * @memberof platform/core.DelegationCapability# - */ - DelegationCapability.prototype.invoke = - DelegationCapability.prototype.getDelegates; - - return DelegationCapability; - - } -); diff --git a/platform/core/src/capabilities/InstantiationCapability.js b/platform/core/src/capabilities/InstantiationCapability.js deleted file mode 100644 index 70788fdfbf..0000000000 --- a/platform/core/src/capabilities/InstantiationCapability.js +++ /dev/null @@ -1,85 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['./ContextualDomainObject'], - function (ContextualDomainObject) { - - /** - * Implements the `instantiation` capability. This allows new domain - * objects to be instantiated. - * - * @constructor - * @memberof platform/core - * @param $injector Angular's `$injector` - * @implements {Capability} - */ - function InstantiationCapability( - $injector, - identifierService, - now, - domainObject - ) { - this.$injector = $injector; - this.identifierService = identifierService; - this.domainObject = domainObject; - this.now = now; - } - - /** - * Instantiate a new domain object with the provided model. - * - * This domain object will have been simply instantiated; it will not - * have been persisted, nor will it have been added to the - * composition of the object which exposed this capability. - * - * @param {object} the model for the new domain object - * @returns {DomainObject} the new domain object - */ - InstantiationCapability.prototype.instantiate = function (model) { - var parsedId = - this.identifierService.parse(this.domainObject.getId()), - space = parsedId.getDefinedSpace(), - id = this.identifierService.generate(space); - - model.modified = this.now(); - - // Lazily initialize; instantiate depends on capabilityService, - // which depends on all capabilities, including this one. - this.instantiateFn = this.instantiateFn - || this.$injector.get("instantiate"); - - var newObject = this.instantiateFn(model, id); - - return new ContextualDomainObject(newObject, this.domainObject); - }; - - /** - * Alias of `instantiate`. - * @see {platform/core.CreationCapability#instantiate} - */ - InstantiationCapability.prototype.invoke = - InstantiationCapability.prototype.instantiate; - - return InstantiationCapability; - } -); diff --git a/platform/core/src/capabilities/MetadataCapability.js b/platform/core/src/capabilities/MetadataCapability.js deleted file mode 100644 index fa8f93516b..0000000000 --- a/platform/core/src/capabilities/MetadataCapability.js +++ /dev/null @@ -1,92 +0,0 @@ - -define( - ['moment'], - function (moment) { - - /** - * A piece of information about a domain object. - * @typedef {Object} MetadataProperty - * @property {string} name the human-readable name of this property - * @property {string} value the human-readable value of this property, - * for this specific domain object - */ - - var TIME_FORMAT = "YYYY-MM-DD HH:mm:ss"; - - /** - * Implements the `metadata` capability of a domain object, providing - * properties of that object for display. - * - * Usage: `domainObject.useCapability("metadata")` - * - * ...which will return an array of objects containing `name` and - * `value` properties describing that domain object (suitable for - * display.) - * - * @param {DomainObject} domainObject the domain object whose - * metadata is to be exposed - * @implements {Capability} - * @constructor - * @memberof platform/core - */ - function MetadataCapability(domainObject) { - this.domainObject = domainObject; - } - - /** - * Get metadata about this object. - * @returns {MetadataProperty[]} metadata about this object - */ - MetadataCapability.prototype.invoke = function () { - var domainObject = this.domainObject, - model = domainObject.getModel(); - - function hasDisplayableValue(metadataProperty) { - var t = typeof metadataProperty.value; - - return (t === 'string' || t === 'number'); - } - - function formatTimestamp(timestamp) { - return typeof timestamp === 'number' - ? (moment.utc(timestamp).format(TIME_FORMAT) + " UTC") - : undefined; - } - - function getProperties() { - var type = domainObject.getCapability('type'); - - function lookupProperty(typeProperty) { - return { - name: typeProperty.getDefinition().name, - value: typeProperty.getValue(model) - }; - } - - return (type ? type.getProperties() : []).map(lookupProperty); - } - - function getCommonMetadata() { - var type = domainObject.getCapability('type'); - - // Note that invalid values will be filtered out later - return [ - { - name: "Updated", - value: formatTimestamp(model.modified) - }, - { - name: "Type", - value: type && type.getName() - } - ]; - } - - return getProperties().concat(getCommonMetadata()) - .filter(hasDisplayableValue); - }; - - return MetadataCapability; - } -); - diff --git a/platform/core/src/capabilities/MutationCapability.js b/platform/core/src/capabilities/MutationCapability.js deleted file mode 100644 index 766ae0b6ee..0000000000 --- a/platform/core/src/capabilities/MutationCapability.js +++ /dev/null @@ -1,189 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 MutationCapability. Created by vwoeltje on 11/12/14. - */ -define( - [], - function () { - - var GENERAL_TOPIC = "mutation", - TOPIC_PREFIX = "mutation:"; - - // Utility function to overwrite a destination object - // with the contents of a source object. - function copyValues(destination, source) { - // First, remove all previously-existing keys - Object.keys(destination).forEach(function (k) { - delete destination[k]; - }); - // Second, write all new keys - Object.keys(source).forEach(function (k) { - destination[k] = source[k]; - }); - } - - // Utility function to cast to a promise, without waiting - // for nextTick if a value is non-promise-like. - function fastPromise(value) { - return (value || {}).then ? value : { - then: function (callback) { - return fastPromise(callback(value)); - } - }; - } - - /** - * The `mutation` capability allows a domain object's model to be - * modified. Wrapping such modifications in calls made through - * this capability allows these changes to be tracked (e.g. to - * ensure that a domain object's `modified` timestamp is kept - * up-to-date.) - * - * Usage: - * - * ``` - * domainObject.useCapability("mutation", function (model) { - * // make changes to model here... - * }); - * ``` - * - * @param {Function} topic a service for creating listeners - * @param {Function} now a service to get the current time - * @param {DomainObject} domainObject the domain object - * which will expose this capability - * @memberof platform/core - * @constructor - * @implements {Capability} - */ - function MutationCapability(topic, now, domainObject) { - this.generalMutationTopic = - topic(GENERAL_TOPIC); - this.specificMutationTopic = - topic(TOPIC_PREFIX + domainObject.getId()); - - this.now = now; - this.domainObject = domainObject; - } - - /** - * Modify the domain object's model, using a provided - * function. This function will receive a copy of the - * domain object's model as an argument; behavior - * varies depending on that function's return value: - * - * * If no value (or undefined) is returned by the mutator, - * the state of the model object delivered as the mutator's - * argument will become the domain object's new model. - * This is useful for writing code that modifies the model - * directly. - * * If a plain object is returned, that object will be used - * as the domain object's new model. - * * If boolean `false` is returned, the mutation will be - * cancelled. - * * If a promise is returned, its resolved value will be - * handled as one of the above. - * - * - * @param {Function} mutator the function which will make - * changes to the domain object's model. - * @param {number} [timestamp] timestamp to record for - * this mutation (otherwise, system time will be - * used) - * @returns {Promise.} a promise for the result - * of the mutation; true if changes were made. - */ - MutationCapability.prototype.mutate = function (mutator, timestamp) { - // Get the object's model and clone it, so the - // mutator function has a temporary copy to work with. - var domainObject = this.domainObject, - now = this.now, - generalTopic = this.generalMutationTopic, - specificTopic = this.specificMutationTopic, - model = domainObject.getModel(), - clone = JSON.parse(JSON.stringify(model)), - useTimestamp = arguments.length > 1; - - function notifyListeners(newModel) { - generalTopic.notify(domainObject); - specificTopic.notify(newModel); - } - - // Function to handle copying values to the actual - function handleMutation(mutationResult) { - // If mutation result was undefined, just use - // the clone; this allows the mutator to omit return - // values and just change the model directly. - var result = mutationResult || clone; - - // Allow mutators to change their mind by - // returning false. - if (mutationResult !== false) { - // Copy values if result was a different object - // (either our clone or some other new thing) - let modelHasChanged = _.isEqual(model, result) === false; - if (modelHasChanged) { - copyValues(model, result); - } - - if (modelHasChanged - || (useTimestamp !== undefined) - || (model.modified === undefined)) { - model.modified = useTimestamp ? timestamp : now(); - } - - notifyListeners(model); - } - - // Report the result of the mutation - return mutationResult !== false; - } - - // Invoke the provided mutator, then make changes to - // the underlying model (if applicable.) - return fastPromise(mutator(clone)).then(handleMutation); - }; - - /** - * Listen for mutations of this domain object's model. - * The provided listener will be invoked with the domain - * object's new model after any changes. To stop listening, - * invoke the function returned by this method. - * @param {Function} listener function to call on mutation - * @returns {Function} a function to stop listening - * @memberof platform/core.MutationCapability# - */ - MutationCapability.prototype.listen = function (listener) { - return this.specificMutationTopic.listen(listener); - }; - - /** - * Alias of `mutate`, used to support useCapability. - */ - MutationCapability.prototype.invoke = - MutationCapability.prototype.mutate; - - return MutationCapability; - } -); - diff --git a/platform/core/src/capabilities/PersistenceCapability.js b/platform/core/src/capabilities/PersistenceCapability.js deleted file mode 100644 index 211b68235f..0000000000 --- a/platform/core/src/capabilities/PersistenceCapability.js +++ /dev/null @@ -1,206 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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(["objectUtils"], - function (objectUtils) { - - /** - * Defines the `persistence` capability, used to trigger the - * writing of changes to a domain object to an underlying - * persistence store. - * - * @param {PersistenceService} persistenceService the underlying - * provider of persistence capabilities. - * @param {string} space the name of the persistence space to - * use (this is an arbitrary string, useful in principle - * for distinguishing different persistence stores from - * one another.) - * @param {DomainObject} the domain object which shall expose - * this capability - * - * @memberof platform/core - * @constructor - * @implements {Capability} - */ - function PersistenceCapability( - cacheService, - persistenceService, - identifierService, - notificationService, - $q, - openmct, - domainObject - ) { - // Cache modified timestamp - this.modified = domainObject.getModel().modified; - - this.domainObject = domainObject; - this.cacheService = cacheService; - this.identifierService = identifierService; - this.persistenceService = persistenceService; - this.notificationService = notificationService; - this.$q = $q; - this.openmct = openmct; - } - - /** - * Checks if the value returned is falsey, and if so returns a - * rejected promise - */ - function rejectIfFalsey(value, $q) { - if (!value) { - return Promise.reject("Error persisting object"); - } else { - return value; - } - } - - function formatError(error) { - if (error && error.message) { - return error.message; - } else if (error && typeof error === "string") { - return error; - } else { - return "unknown error"; - } - } - - /** - * Display a notification message if an error has occurred during - * persistence. - */ - function notifyOnError(error, domainObject, notificationService, $q) { - var errorMessage = "Unable to persist " + domainObject.getModel().name; - if (error) { - errorMessage += ": " + formatError(error); - } - - notificationService.error({ - title: "Error persisting " + domainObject.getModel().name, - hint: errorMessage, - dismissable: true - }); - - return Promise.reject(error); - } - - /** - * Persist any changes which have been made to this - * domain object's model. - * @returns {Promise} a promise which will be resolved - * if persistence is successful, and rejected - * if not. - */ - PersistenceCapability.prototype.persist = function () { - var self = this, - domainObject = this.domainObject; - - const identifier = { - namespace: this.getSpace(), - key: this.getKey() - }; - - let newStyleObject = objectUtils.toNewFormat(domainObject.getModel(), identifier); - - return this.openmct.objects - .save(newStyleObject) - .then(function (result) { - return rejectIfFalsey(result, self.$q); - }).catch(function (error) { - return notifyOnError(error, domainObject, self.notificationService, self.$q); - }); - }; - - /** - * Update this domain object to match the latest from - * persistence. - * @returns {Promise} a promise which will be resolved - * when the update is complete - */ - PersistenceCapability.prototype.refresh = function () { - var domainObject = this.domainObject; - var $q = this.$q; - - // Update a domain object's model upon refresh - function updateModel(model) { - if (model === undefined) { - //Get failed, reject promise - return $q.reject('Got empty object model'); - } else { - var modified = model.modified; - - return domainObject.useCapability("mutation", function () { - return model; - }, modified); - - } - } - - if (domainObject.getModel().persisted === undefined) { - return this.$q.when(true); - } - - return this.persistenceService.readObject( - this.getSpace(), - this.getKey() - ).then(updateModel); - }; - - /** - * Get the space in which this domain object is persisted; - * this is useful when, for example, decided which space a - * newly-created domain object should be persisted to (by - * default, this should be the space of its containing - * object.) - * - * @returns {string} the name of the space which should - * be used to persist this object - */ - PersistenceCapability.prototype.getSpace = function () { - var id = this.domainObject.getId(); - - return this.identifierService.parse(id).getSpace(); - }; - - /** - * Check if this domain object has been persisted at some - * point. - * @returns {boolean} true if the object has been persisted - */ - PersistenceCapability.prototype.persisted = function () { - return this.domainObject.getModel().persisted !== undefined; - }; - - /** - * Get the key for this domain object in the given space. - * - * @returns {string} the key of the object in it's space. - */ - PersistenceCapability.prototype.getKey = function () { - var id = this.domainObject.getId(); - - return this.identifierService.parse(id).getKey(); - }; - - return PersistenceCapability; - } -); diff --git a/platform/core/src/capabilities/RelationshipCapability.js b/platform/core/src/capabilities/RelationshipCapability.js deleted file mode 100644 index 8d7e67e85a..0000000000 --- a/platform/core/src/capabilities/RelationshipCapability.js +++ /dev/null @@ -1,128 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Relationship capability. Describes a domain objects relationship - * to other domain objects within the system, and provides a way to - * access related objects. - * - * For most cases, this is not the capability to use; the - * `composition` capability describes the more general relationship - * between objects typically seen (e.g. in the tree.) This capability - * is instead intended for the more unusual case of relationships - * which are not intended to appear in the tree, but are instead - * intended only for special, limited usage. - * - * @memberof platform/core - * @constructor - * @implements {Capability} - */ - function RelationshipCapability($injector, domainObject) { - // Get a reference to the object service from $injector - this.injectObjectService = function () { - this.objectService = $injector.get("objectService"); - }; - - this.lastPromise = {}; - this.domainObject = domainObject; - } - - /** - * List all types of relationships exposed by this - * object. - * @returns {string[]} a list of all relationship types - */ - RelationshipCapability.prototype.listRelationships = function listRelationships() { - var relationships = - (this.domainObject.getModel() || {}).relationships || {}; - - // Check if this key really does expose an array of ids - // (to filter out malformed relationships) - function isArray(key) { - return Array.isArray(relationships[key]); - } - - return Object.keys(relationships).filter(isArray).sort(); - }; - - /** - * Request related objects, with a given relationship type. - * This will typically require asynchronous lookup, so this - * returns a promise. - * @param {string} key the type of relationship - * @returns {Promise.} a promise for related - * domain objects - */ - RelationshipCapability.prototype.getRelatedObjects = function (key) { - var model = this.domainObject.getModel(), - ids; - - // Package objects as an array - function packageObject(objects) { - return ids.map(function (id) { - return objects[id]; - }).filter(function (obj) { - return obj; - }); - } - - // Clear cached promises if modification has occurred - if (this.lastModified !== model.modified) { - this.lastPromise = {}; - this.lastModified = model.modified; - } - - // Make a new request if needed - if (!this.lastPromise[key]) { - ids = (model.relationships || {})[key] || []; - this.lastModified = model.modified; - // Lazily initialize object service now that we need it - if (!this.objectService) { - this.injectObjectService(); - } - - // Load from the underlying object service - this.lastPromise[key] = this.objectService.getObjects(ids) - .then(packageObject); - } - - return this.lastPromise[key]; - }; - - /** - * Test to determine whether or not this capability should be exposed - * by a domain object based on its model. Checks for the presence of - * a `relationships` field, that must be an object. - * @param model the domain object model - * @returns {boolean} true if this object has relationships - */ - RelationshipCapability.appliesTo = function (model) { - return Boolean((model || {}).relationships); - }; - - return RelationshipCapability; - } -); diff --git a/platform/core/src/identifiers/Identifier.js b/platform/core/src/identifiers/Identifier.js deleted file mode 100644 index 6029ea9f34..0000000000 --- a/platform/core/src/identifiers/Identifier.js +++ /dev/null @@ -1,84 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - var SEPARATOR = ":"; - - /** - * Provides an interface for interpreting domain object identifiers; - * in particular, parses out persistence space/key pairs associated - * with the domain object. - * - * @memberof platform/core - * @constructor - * @param {string} id the domain object identifier - * @param {string} defaultSpace the persistence space to use if - * one is not encoded in the identifier - */ - function Identifier(id, defaultSpace) { - var separatorIndex = id.indexOf(SEPARATOR); - - if (separatorIndex > -1) { - this.key = id.substring(separatorIndex + 1); - this.space = id.substring(0, separatorIndex); - this.definedSpace = this.space; - } else { - this.key = id; - this.space = defaultSpace; - this.definedSpace = undefined; - } - } - - /** - * Get the key under which the identified domain object's model - * should be persisted, within its persistence space. - * @returns {string} the key within its persistence space - */ - Identifier.prototype.getKey = function () { - return this.key; - }; - - /** - * Get the space in which the identified domain object's model should - * be persisted. - * @returns {string} the persistence space - */ - Identifier.prototype.getSpace = function () { - return this.space; - }; - - /** - * Get the persistence space, if any, which has been explicitly - * encoded in this domain object's identifier. Returns undefined - * if no such space has been specified. - * @returns {string} the persistence space, or undefined - */ - Identifier.prototype.getDefinedSpace = function () { - return this.definedSpace; - }; - - return Identifier; - } -); diff --git a/platform/core/src/identifiers/IdentifierProvider.js b/platform/core/src/identifiers/IdentifierProvider.js deleted file mode 100644 index 7cc3e35b7e..0000000000 --- a/platform/core/src/identifiers/IdentifierProvider.js +++ /dev/null @@ -1,65 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ["uuid", "./Identifier"], - function (uuid, Identifier) { - - /** - * Parses and generates domain object identifiers. - * @param {string} defaultSpace the default persistence space - * @constructor - * @memberof {platform/core} - */ - function IdentifierProvider(defaultSpace) { - this.defaultSpace = defaultSpace; - } - - /** - * Generate a new domain object identifier. A persistence space - * may optionally be included; if not specified, no space will - * be encoded into the identifier. - * @param {string} [space] the persistence space to encode - * in this identifier - * @returns {string} a new domain object identifier - */ - IdentifierProvider.prototype.generate = function (space) { - var id = uuid(); - if (space !== undefined) { - id = space + ":" + id; - } - - return id; - }; - - /** - * Parse a domain object identifier to examine its component - * parts (e.g. its persistence space.) - * @returns {platform/core.Identifier} the parsed identifier - */ - IdentifierProvider.prototype.parse = function (id) { - return new Identifier(id, this.defaultSpace); - }; - - return IdentifierProvider; - } -); diff --git a/platform/core/src/models/CachingModelDecorator.js b/platform/core/src/models/CachingModelDecorator.js deleted file mode 100644 index bd4e3c7f20..0000000000 --- a/platform/core/src/models/CachingModelDecorator.js +++ /dev/null @@ -1,65 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The caching model decorator maintains a cache of loaded domain - * object models, and ensures that duplicate models for the same - * object are not provided. - * @memberof platform/core - * @constructor - * @param {ModelService} modelService this service to decorate - * @implements {ModelService} - */ - function CachingModelDecorator(cacheService, modelService) { - this.cacheService = cacheService; - this.modelService = modelService; - } - - CachingModelDecorator.prototype.getModels = function (ids) { - var loadFromCache = ids.filter(function cached(id) { - return this.cacheService.has(id); - }, this), - loadFromService = ids.filter(function notCached(id) { - return !this.cacheService.has(id); - }, this); - - if (!loadFromCache.length) { - return this.modelService.getModels(loadFromService); - } - - return this.modelService.getModels(loadFromService) - .then(function (modelResults) { - loadFromCache.forEach(function (id) { - modelResults[id] = this.cacheService.get(id); - }, this); - - return modelResults; - }.bind(this)); - }; - - return CachingModelDecorator; - } -); diff --git a/platform/core/src/models/ModelAggregator.js b/platform/core/src/models/ModelAggregator.js deleted file mode 100644 index 709b49c369..0000000000 --- a/platform/core/src/models/ModelAggregator.js +++ /dev/null @@ -1,99 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ModelAggregator. Created by vwoeltje on 11/7/14. - */ -define( - [], - function () { - - /** - * Allow domain object models to be looked up by their identifiers. - * - * @interface ModelService - */ - - /** - * Get domain object models. - * - * This may provide either a superset or a subset of the models - * requested. Absence of a model means it does not exist within - * this service instance. - * - * @method ModelService#getModels - * @param {string[]} ids identifiers for models desired. - * @returns {Promise.} a promise for an object mapping - * string identifiers to domain object models. - */ - - /** - * Allows multiple services which provide models for domain objects - * to be treated as one. - * - * @memberof platform/core - * @constructor - * @implements {ModelService} - * @param $q Angular's $q, for promises - * @param {ModelService[]} providers the model providers to be - * aggregated - */ - function ModelAggregator($q, providers) { - this.providers = providers; - this.$q = $q; - } - - // Pick a domain object model to use, favoring the one - // with the most recent timestamp - function pick(a, b) { - var aModified = (a || {}).modified || Number.NEGATIVE_INFINITY, - bModified = (b || {}).modified || Number.NEGATIVE_INFINITY; - - return (aModified > bModified) ? a : (b || a); - } - - // Merge results from multiple providers into one - // large result object. - function mergeModels(provided, ids) { - var result = {}; - ids.forEach(function (id) { - provided.forEach(function (models) { - if (models[id]) { - result[id] = pick(result[id], models[id]); - } - }); - }); - - return result; - } - - ModelAggregator.prototype.getModels = function (ids) { - return this.$q.all(this.providers.map(function (provider) { - return provider.getModels(ids); - })).then(function (provided) { - return mergeModels(provided, ids); - }); - }; - - return ModelAggregator; - } -); diff --git a/platform/core/src/models/ModelCacheService.js b/platform/core/src/models/ModelCacheService.js deleted file mode 100644 index 2e158c7b86..0000000000 --- a/platform/core/src/models/ModelCacheService.js +++ /dev/null @@ -1,85 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define([], function () { - - /** - * Provides a cache for domain object models which exist in memory, - * but may or may not exist in backing persistence stores. - * @constructor - * @memberof platform/core - */ - function ModelCacheService() { - this.cache = {}; - } - - /** - * Put a domain object model in the cache. - * @param {string} id the domain object's identifier - * @param {object} model the domain object's model - */ - ModelCacheService.prototype.put = function (id, model) { - this.cache[id] = model; - }; - - /** - * Retrieve a domain object model from the cache. - * @param {string} id the domain object's identifier - * @returns {object} the domain object's model - */ - ModelCacheService.prototype.get = function (id) { - return this.cache[id]; - }; - - /** - * Check if a domain object model is in the cache. - * @param {string} id the domain object's identifier - * @returns {boolean} true if present; false if not - */ - ModelCacheService.prototype.has = function (id) { - return Object.prototype.hasOwnProperty.call(this.cache, id); - }; - - /** - * Remove a domain object model from the cache. - * @param {string} id the domain object's identifier - */ - ModelCacheService.prototype.remove = function (id) { - delete this.cache[id]; - }; - - /** - * Retrieve all cached domain object models. These are given - * as an object containing key-value pairs, where keys are - * domain object identifiers and values are domain object models. - * @returns {object} all domain object models - */ - ModelCacheService.prototype.all = function () { - return this.cache; - }; - - ModelCacheService.prototype.flush = function () { - this.cache = {}; - }; - - return ModelCacheService; -}); diff --git a/platform/core/src/models/PersistedModelProvider.js b/platform/core/src/models/PersistedModelProvider.js deleted file mode 100644 index 60b27d2917..0000000000 --- a/platform/core/src/models/PersistedModelProvider.js +++ /dev/null @@ -1,136 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 PersistedModelProvider. Created by vwoeltje on 11/12/14. - */ -define( - [], - function () { - - /** - * A model service which reads domain object models from an external - * persistence service. - * - * Identifiers will be interpreted as follows: - * * If no colon is present, the model will be read from the default - * persistence space. - * * If a colon is present, everything before the first colon will be - * taken to refer to the persistence space, and everything after - * will be taken to be that model's key within this space. (If - * no such space exists within the `persistenceService`, that - * identifier will simply be ignored.) - * - * @memberof platform/core - * @constructor - * @implements {ModelService} - * @param {PersistenceService} persistenceService the service in which - * domain object models are persisted. - * @param $q Angular's $q service, for working with promises - * @param {function} now a function which provides the current time - * @param {string} space the name of the persistence space(s) - * from which models should be retrieved by default - */ - function PersistedModelProvider(persistenceService, $q, now, space) { - this.persistenceService = persistenceService; - this.$q = $q; - this.now = now; - this.defaultSpace = space; - } - - PersistedModelProvider.prototype.getModels = function (ids) { - var persistenceService = this.persistenceService, - $q = this.$q, - now = this.now, - defaultSpace = this.defaultSpace, - parsedIds; - - // Load a single object model from any persistence spaces - function loadModel(parsedId) { - return persistenceService - .readObject(parsedId.space, parsedId.key); - } - - // Ensure that models read from persistence have some - // sensible timestamp indicating they've been persisted. - function addPersistedTimestamp(model) { - if (model && (model.persisted === undefined)) { - model.persisted = model.modified !== undefined - ? model.modified : now(); - } - - return model; - } - - // Package the result as id->model - function packageResult(parsedIdsToPackage, models) { - var result = {}; - parsedIdsToPackage.forEach(function (parsedId, index) { - var id = parsedId.id; - if (models[index]) { - result[id] = models[index]; - } - }); - - return result; - } - - function loadModels(parsedIdsToLoad) { - return $q.all(parsedIdsToLoad.map(loadModel)) - .then(function (models) { - return packageResult( - parsedIdsToLoad, - models.map(addPersistedTimestamp) - ); - }); - } - - function restrictToSpaces(spaces) { - return parsedIds.filter(function (parsedId) { - return spaces.indexOf(parsedId.space) !== -1; - }); - } - - parsedIds = ids.map(function (id) { - var parts = id.split(":"); - - return (parts.length > 1) - ? { - id: id, - space: parts[0], - key: parts.slice(1).join(":") - } - : { - id: id, - space: defaultSpace, - key: id - }; - }); - - return persistenceService.listSpaces() - .then(restrictToSpaces) - .then(loadModels); - }; - - return PersistedModelProvider; - } -); diff --git a/platform/core/src/models/StaticModelProvider.js b/platform/core/src/models/StaticModelProvider.js deleted file mode 100644 index f1f2b040ca..0000000000 --- a/platform/core/src/models/StaticModelProvider.js +++ /dev/null @@ -1,71 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 StaticModelProvider. Created by vwoeltje on 11/7/14. - */ -define( - [], - function () { - - /** - * Loads static models, provided as declared extensions of bundles. - * @memberof platform/core - * @constructor - */ - function StaticModelProvider(models, $q, $log) { - var modelMap = {}; - - function addModelToMap(model) { - // Skip models which don't look right - if (typeof model !== 'object' - || typeof model.id !== 'string' - || typeof model.model !== 'object') { - $log.warn([ - "Skipping malformed domain object model exposed by ", - ((model || {}).bundle || {}).path - ].join("")); - } else { - modelMap[model.id] = model.model; - } - } - - // Prepopulate maps with models to make subsequent lookup faster. - models.forEach(addModelToMap); - - this.modelMap = modelMap; - this.$q = $q; - } - - StaticModelProvider.prototype.getModels = function (ids) { - var modelMap = this.modelMap, - result = {}; - ids.forEach(function (id) { - result[id] = modelMap[id]; - }); - - return this.$q.when(result); - }; - - return StaticModelProvider; - } -); diff --git a/platform/core/src/objects/DomainObjectImpl.js b/platform/core/src/objects/DomainObjectImpl.js deleted file mode 100644 index e42a8f747b..0000000000 --- a/platform/core/src/objects/DomainObjectImpl.js +++ /dev/null @@ -1,142 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 DomainObject. Created by vwoeltje on 11/7/14. - */ -define( - [], - function () { - - /** - * A domain object is an entity of interest to the user. - * - * @interface DomainObject - */ - - /** - * Get the unique identifier for this domain object. - * - * @method DomainObject#getId - * @return {string} the domain object's unique identifier - */ - - /** - * Get the domain object's model. This is useful to - * directly look up known properties of an object, but - * direct modification of a returned model is generally - * discouraged and may result in errors. Instead, an - * object's `mutation` capability should be used. - * - * @method DomainObject#getModel - * @return {object} the domain object's persistent state - */ - - /** - * Get a capability associated with this object. - * Capabilities are looked up by string identifiers; - * prior knowledge of a capability's interface is - * necessary. - * - * @method DomainObject#getCapability - * @param {string} key the identifier for the capability - * @return {Capability} the named capability, or undefined - * if not present. - */ - - /** - * Check if this domain object supports a capability - * with the provided name. - * - * @method DomainObject#hasCapability - * @param {string} key the identifier for the capability - * @return {boolean} true if this domain object has this capability - */ - - /** - * Use a capability of an object; the behavior of this method - * depends on the interface of the capability, and whether - * or not it is present. - * - * * If the capability is not present for this object, - * no operation occurs. - * * If the capability is present and has an `invoke` method, - * that method is called with any additional arguments - * provided, and its return value is returned. - * * If the capability is present but has no `invoke` method, - * this capability itself is returned. - * - * @method DomainObject#useCapability - * @param {string} name the name of the capability to invoke - * @param {...*} [arguments] to pass to the invocation - * @returns {*|Capability} the result of invocation (see description) - */ - - /** - * Construct a new domain object with the specified - * identifier, model, and capabilities. - * - * @param {string} id the object's unique identifier - * @param {object} model the "JSONifiable" state of the object - * @param {Object.|function} capabilities all - * capabilities to be exposed by this object - * @memberof platform/core - * @constructor - */ - function DomainObjectImpl(id, model, capabilities) { - this.id = id; - this.model = model; - this.capabilities = capabilities; - } - - DomainObjectImpl.prototype.getId = function () { - return this.id; - }; - - DomainObjectImpl.prototype.getModel = function () { - return this.model; - }; - - DomainObjectImpl.prototype.getCapability = function (name) { - var capability = this.capabilities[name]; - - return typeof capability === 'function' - ? capability(this) : capability; - }; - - DomainObjectImpl.prototype.hasCapability = function (name) { - return this.getCapability(name) !== undefined; - }; - - DomainObjectImpl.prototype.useCapability = function (name) { - // Get tail of args to pass to invoke - var args = Array.prototype.slice.apply(arguments, [1]), - capability = this.getCapability(name); - - return (capability && capability.invoke) - ? capability.invoke.apply(capability, args) - : capability; - }; - - return DomainObjectImpl; - } -); diff --git a/platform/core/src/objects/DomainObjectProvider.js b/platform/core/src/objects/DomainObjectProvider.js deleted file mode 100644 index 5c71542924..0000000000 --- a/platform/core/src/objects/DomainObjectProvider.js +++ /dev/null @@ -1,93 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -/** - * This bundle implements core components of Open MCT's service - * infrastructure and information model. - * @namespace platform/core - */ -define( - [], - function () { - - /** - * Provides instances of domain objects, as retrieved by their - * identifiers. - * - * @interface ObjectService - */ - - /** - * Get a set of objects associated with a list of identifiers. - * The provided result may contain a subset or a superset of - * the total number of objects. - * - * @method ObjectService#getObjects - * @param {string[]} ids the identifiers for domain objects - * of interest. - * @return {Promise>} a promise - * for an object containing key-value pairs, where keys - * are string identifiers for domain objects, and - * values are the corresponding domain objects themselves. - */ - - /** - * Construct a new provider for domain objects. - * - * @param {ModelService} modelService the service which shall - * provide models (persistent state) for domain objects - * @param {Function} instantiate a service to instantiate new - * domain object instances - * @param $q Angular's $q, for promise consolidation - * @memberof platform/core - * @constructor - */ - function DomainObjectProvider(modelService, instantiate) { - this.modelService = modelService; - this.instantiate = instantiate; - } - - DomainObjectProvider.prototype.getObjects = function getObjects(ids) { - var modelService = this.modelService, - instantiate = this.instantiate; - - // Assemble the results from the model service and the - // capability service into one value, suitable to return - // from this service. - function assembleResult(models) { - var result = {}; - ids.forEach(function (id) { - if (models[id]) { - // Create the domain object - result[id] = instantiate(models[id], id); - } - }); - - return result; - } - - return modelService.getModels(ids).then(assembleResult); - }; - - return DomainObjectProvider; - } -); diff --git a/platform/core/src/services/Instantiate.js b/platform/core/src/services/Instantiate.js deleted file mode 100644 index d7371a8541..0000000000 --- a/platform/core/src/services/Instantiate.js +++ /dev/null @@ -1,61 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['../objects/DomainObjectImpl'], - function (DomainObjectImpl) { - - /** - * The `instantiate` service allows new domain object instances to be - * created. These objects are not persisted to any back-end or - * placed anywhere in the object hierarchy by default. - * - * Usage: `instantiate(model, [id])` - * - * ...returns a new instance of a domain object with the specified - * model. An identifier may be provided; if omitted, one will be - * generated instead. - * - * @constructor - * @memberof platform/core - * @param {CapabilityService} capabilityService the service which will - * provide instantiated domain objects with their capabilities - * @param {IdentifierService} identifierService service to generate - * new identifiers - */ - function Instantiate( - capabilityService, - identifierService, - cacheService - ) { - return function (model, id) { - var capabilities = capabilityService.getCapabilities(model); - id = id || identifierService.generate(); - cacheService.put(id, model); - - return new DomainObjectImpl(id, model, capabilities); - }; - } - - return Instantiate; - } -); diff --git a/platform/core/src/services/Now.js b/platform/core/src/services/Now.js deleted file mode 100644 index e53983d0e5..0000000000 --- a/platform/core/src/services/Now.js +++ /dev/null @@ -1,48 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define( - [], - function () { - - /** - * Defines the `now` service, which is a simple wrapper upon - * `Date.now()` which can be injected to support testability. - * - * @returns {Function} a function which returns current system time - * @memberof platform/core - */ - function Now() { - /** - * Get the current time. - * @returns {number} current time, in milliseconds since - * 1970-01-01 00:00:00Z - * @memberof platform/core.Now# - */ - return function () { - return Date.now(); - }; - } - - return Now; - } -); diff --git a/platform/core/src/services/Throttle.js b/platform/core/src/services/Throttle.js deleted file mode 100644 index 2ced7bcea2..0000000000 --- a/platform/core/src/services/Throttle.js +++ /dev/null @@ -1,93 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Throttler for function executions, registered as the `throttle` - * service. - * - * Usage: - * - * throttle(fn, delay, [apply]) - * - * Returns a function that, when invoked, will invoke `fn` after - * `delay` milliseconds, only if no other invocations are pending. - * The optional argument `apply` determines whether or not a - * digest cycle should be triggered. - * - * The returned function will itself return a `Promise` which will - * resolve to the returned value of `fn` whenever that is invoked. - * - * In cases where arguments are provided, only the most recent - * set of arguments will be passed on to the throttled function - * at the time it is executed. - * - * @returns {Function} - * @memberof platform/core - */ - function Throttle($timeout) { - /** - * Throttle this function. - * @param {Function} fn the function to throttle - * @param {number} [delay] the delay, in milliseconds, before - * executing this function; defaults to 0. - * @param {boolean} apply true if a `$apply` call should be - * invoked after this function executes; defaults to - * `false`. - * @memberof platform/core.Throttle# - */ - return function (fn, delay, apply) { - var promise, - args = []; - - function invoke() { - // Clear the active timeout so a new one starts next time. - promise = undefined; - - // Invoke the function with the latest supplied arguments. - return fn.apply(null, args); - } - - // Defaults - delay = delay || 0; - apply = apply || false; - - return function () { - // Store arguments from this invocation - args = Array.prototype.slice.apply(arguments, [0]); - // Start a timeout if needed - promise = promise || $timeout(invoke, delay, apply); - - // Return whichever timeout is active (to get - // a promise for the results of fn) - return promise; - }; - }; - } - - return Throttle; - } -); - diff --git a/platform/core/src/services/Topic.js b/platform/core/src/services/Topic.js deleted file mode 100644 index 263982502c..0000000000 --- a/platform/core/src/services/Topic.js +++ /dev/null @@ -1,97 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - var ERROR_PREFIX = "Error when notifying listener: "; - - /** - * The `topic` service provides a way to create both named, - * shared listeners and anonymous, private listeners. - * - * Usage: - * - * ``` - * var t = topic('foo'); // Use/create a named topic - * t.listen(function () { ... }); - * t.notify({ some: "message" }); - * ``` - * - * Named topics are shared; multiple calls to `topic` - * with the same argument will return a single object instance. - * Anonymous topics (where `topic` has been called with no - * arguments) are private; each call returns a new instance. - * - * @returns {Function} - * @memberof platform/core - */ - function Topic($log) { - var topics = {}; - - function createTopic() { - var listeners = []; - - return { - listen: function (listener) { - listeners.push(listener); - - return function unlisten() { - listeners = listeners.filter(function (l) { - return l !== listener; - }); - }; - }, - notify: function (message) { - listeners.forEach(function (listener) { - try { - listener(message); - } catch (e) { - $log.error(ERROR_PREFIX + e.message); - $log.error(e); - } - }); - } - }; - } - - /** - * Use and (if necessary) create a new topic. - * @param {string} [key] name of the topic to use - * @memberof platform/core.Topic# - */ - return function (key) { - if (arguments.length < 1) { - return createTopic(); - } else { - topics[key] = topics[key] || createTopic(); - - return topics[key]; - } - }; - } - - return Topic; - } -); - diff --git a/platform/core/src/types/MergeModels.js b/platform/core/src/types/MergeModels.js deleted file mode 100644 index a1e25cb8d9..0000000000 --- a/platform/core/src/types/MergeModels.js +++ /dev/null @@ -1,106 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * Defines MergedModel, which allows a deep merge of domain object - * models, or JSONifiable JavaScript objects generally. - * - */ -define( - function () { - - /** - * Utility function for merging domain object models (or any - * JavaScript object which follows the same conventions.) - * Performs a "deep merge", resolving conflicts (occurrences - * of the same property in both objects) such that: - * - * * Non-conflicting properties are both contained in the - * result object. - * * Conflicting properties which are both arrays are - * concatenated. - * * Conflicting properties which are both objects are - * merged recursively. - * * Conflicting properties which do not fall into any of the - * preceding categories are taken from the second argument, - * shadowing any values from the first. - * - * An optional third argument, the "merger", may be provided. - * This may be either a function, or an object containing - * key-value pairs where keys are strings (corresponding to - * the names of properties) and values are other mergers - * (either functions or objects.) - * - * * If the merger is a function, it will be used upon the - * two input objects in lieu of the behavior described - * above. - * * If the merger is an object, then its values will be - * used as mergers when resolving properties with - * corresponding keys in the recursive step. - * - * - * @param modelA the first object to be merged - * @param modelB the second object to be merged - * @param merger the merger, as described above - * @returns {*} the result of merging `modelA` and `modelB` - * @constructor - * @memberof platform/core - */ - function mergeModels(modelA, modelB, merger) { - var mergeFunction; - - function mergeArrays(a, b) { - return a.concat(b); - } - - function mergeObjects(a, b) { - var result = {}; - Object.keys(a).forEach(function (k) { - result[k] = Object.prototype.hasOwnProperty.call(b, k) - ? mergeModels(a[k], b[k], (merger || {})[k]) - : a[k]; - }); - Object.keys(b).forEach(function (k) { - // Copy any properties not already merged - if (!Object.prototype.hasOwnProperty.call(a, k)) { - result[k] = b[k]; - } - }); - - return result; - } - - function mergeOther(a, b) { - return b; - } - - mergeFunction = (merger && Function.isFunction(merger)) ? merger - : (Array.isArray(modelA) && Array.isArray(modelB)) ? mergeArrays - : (modelA instanceof Object && modelB instanceof Object) ? mergeObjects - : mergeOther; - - return mergeFunction(modelA, modelB); - } - - return mergeModels; - } -); diff --git a/platform/core/src/types/TypeCapability.js b/platform/core/src/types/TypeCapability.js deleted file mode 100644 index 6b8d9d065b..0000000000 --- a/platform/core/src/types/TypeCapability.js +++ /dev/null @@ -1,55 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 TypeCapability. Created by vwoeltje on 11/10/14. - */ -define( - [], - function () { - - /** - * The `type` capability makes information about a domain object's - * type directly available when working with that object, by way - * of a `domainObject.getCapability('type')` invocation. - * - * @memberof platform/core - * @constructor - * @augments {Type} - * @implements {Capability} - * @param {TypeService} typeService the service which - * provides type information - * @param {DomainObject} domainObject the domain object - * which exposes the type capability - */ - function TypeCapability(typeService, domainObject) { - var typeKey = domainObject.getModel().type, - type = typeService.getType(typeKey); - - // Simply return the type, but wrap with Object.create - // to avoid exposing the type object directly. - return Object.create(type); - } - - return TypeCapability; - } -); diff --git a/platform/core/src/types/TypeImpl.js b/platform/core/src/types/TypeImpl.js deleted file mode 100644 index 0cd19600d6..0000000000 --- a/platform/core/src/types/TypeImpl.js +++ /dev/null @@ -1,194 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['./TypeProperty'], - function (TypeProperty) { - - /** - * Describes a type of domain object. - * - * @interface Type - */ - - /** - * Get the string key which identifies this type. - * This is the type's machine-readable name/identifier, - * and will correspond to the "type" field of the models - * of domain objects of this type. - * - * @returns {string} the key which identifies this type - * @method Type#getKey - */ - /** - * Get the human-readable name for this type, as should - * be displayed in the user interface when referencing - * this type. - * - * @returns {string} the human-readable name of this type - * @method Type#getName - */ - /** - * Get the human-readable description for this type, as should - * be displayed in the user interface when describing - * this type. - * - * @returns {string} the human-readable description of this type - * @method Type#getDescription - */ - /** - * Get the cssClass associated with this type. cssClass is a - * string which will appear as an icon (when - * displayed in an appropriate font) which visually - * distinguish types from one another. - * - * @returns {string} the cssClass for this type - * @method Type#getCssClass - */ - /** - * Get an array of properties associated with objects of - * this type, as might be shown in a Create wizard or - * an Edit Properties view. - * - * @return {TypeProperty[]} properties associated with - * objects of this type - * @method Type#getPropertiees - */ - /** - * Get the initial state of a model for domain objects of - * this type. - * - * @return {object} initial domain object model - * @method Type#getInitialModel - */ - /** - * Get the raw type definition for this type. This is an - * object containing key-value pairs of type metadata; - * this allows the retrieval and use of custom type - * properties which are not recognized within this interface. - * - * @returns {object} the raw definition for this type - * @method Type#getDefinition - */ - /** - * Check if this type is or inherits from some other type. - * - * @param {string|Type} key either - * a string key for a type, or an instance of a type - * object, which this - * @returns {boolean} true - * @method Type#instanceOf - */ - /** - * Check if a type should support a given feature. This simply - * checks for the presence or absence of the feature key in - * the type definition's "feature" field. - * @param {string} feature a string identifying the feature - * @returns {boolean} true if the feature is supported - * @method Type#hasFeature - */ - - /** - * Construct a new type. Types describe categories of - * domain objects. - * - * @implements {Type} - * @param {TypeDefinition} typeDef an object containing - * key-value pairs describing a type and its - * relationship to other types. - * @constructor - * @memberof platform/core - */ - function TypeImpl(typeDef) { - var inheritList = typeDef.inherits || [], - featureSet = {}; - - (typeDef.features || []).forEach(function (feature) { - featureSet[feature] = true; - }); - - this.typeDef = typeDef; - this.featureSet = featureSet; - this.inheritList = inheritList; - } - - TypeImpl.prototype.getKey = function () { - return this.typeDef.key; - }; - - TypeImpl.prototype.getName = function () { - return this.typeDef.name; - }; - - TypeImpl.prototype.getDescription = function () { - return this.typeDef.description; - }; - - TypeImpl.prototype.getCssClass = function () { - return this.typeDef.cssClass; - }; - - TypeImpl.prototype.getProperties = function () { - return (this.typeDef.properties || []).map(function (propertyDef) { - return new TypeProperty(propertyDef); - }); - }; - - /** - * Returns the default model for an object of this type. Note that - * this method returns a clone of the original model, so if using this - * method heavily, consider caching the result to optimize performance. - * - * @return {object} The default model for an object of this type. - */ - TypeImpl.prototype.getInitialModel = function () { - return JSON.parse(JSON.stringify(this.typeDef.model || {})); - }; - - TypeImpl.prototype.getDefinition = function () { - return this.typeDef; - }; - - TypeImpl.prototype.instanceOf = function instanceOf(key) { - var typeDef = this.typeDef, - inheritList = this.inheritList; - - if (key === typeDef.key) { - return true; - } else if (inheritList.indexOf(key) > -1) { - return true; - } else if (!key) { - return true; - } else if (key !== null && typeof key === 'object') { - return key.getKey ? this.instanceOf(key.getKey()) : false; - } else { - return false; - } - }; - - TypeImpl.prototype.hasFeature = function (feature) { - return this.featureSet[feature] || false; - }; - - return TypeImpl; - } -); diff --git a/platform/core/src/types/TypeProperty.js b/platform/core/src/types/TypeProperty.js deleted file mode 100644 index 3de6792101..0000000000 --- a/platform/core/src/types/TypeProperty.js +++ /dev/null @@ -1,163 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['./TypePropertyConversion'], - function (TypePropertyConversion) { - - /** - * Instantiate a property associated with domain objects of a - * given type. This provides an interface by which - * - * @memberof platform/core - * @constructor - */ - function TypeProperty(propertyDefinition) { - // Load an appropriate conversion - this.conversion = new TypePropertyConversion( - propertyDefinition.conversion || "identity" - ); - this.propertyDefinition = propertyDefinition; - } - - // Check if a value is defined; used to check if initial array - // values have been populated. - function isUnpopulatedArray(value) { - var i; - - if (!Array.isArray(value) || value.length === 0) { - return false; - } - - for (i = 0; i < value.length; i += 1) { - if (value[i] !== undefined) { - return false; - } - } - - return true; - } - - // Specify a field deeply within an object - function specifyValue(object, propertyPath, value) { - // If path is not an array, just set the property - if (!Array.isArray(propertyPath)) { - object[propertyPath] = value; - } else if (propertyPath.length > 1) { - // Otherwise, look up in defined sequence - object[propertyPath[0]] = object[propertyPath[0]] || {}; - specifyValue( - object[propertyPath[0]], - propertyPath.slice(1), - value - ); - } else if (propertyPath.length === 1) { - object[propertyPath[0]] = value; - } - } - - // Perform a lookup for a value from an object, - // which may recursively look at contained objects - // based on the path provided. - function lookupValue(object, propertyPath) { - var value; - - // Can't look up from a non-object - if (!object) { - return undefined; - } - - // If path is not an array, just look up the property - if (!Array.isArray(propertyPath)) { - return object[propertyPath]; - } - - // Otherwise, look up in the sequence defined in the array - if (propertyPath.length > 0) { - value = object[propertyPath[0]]; - - return propertyPath.length > 1 - ? lookupValue(value, propertyPath.slice(1)) - : value; - } - - // Fallback; property path was empty - return undefined; - } - - /** - * Retrieve the value associated with this property - * from a given model. - * @param {object} model a domain object model to read from - * @returns {*} the value for this property, as read from the model - */ - TypeProperty.prototype.getValue = function (model) { - var property = this.propertyDefinition.property - || this.propertyDefinition.key, - initialValue = - property && lookupValue(model, property); - - // Provide an empty array if this is a multi-item - // property. - if (Array.isArray(this.propertyDefinition.items)) { - initialValue = initialValue - || new Array(this.propertyDefinition.items.length); - } - - return this.conversion.toFormValue(initialValue); - }; - - /** - * Set a value associated with this property in - * an object's model. - * @param {object} model a domain object model to update - * @param {*} value the new value to set for this property - */ - TypeProperty.prototype.setValue = function (model, value) { - var property = this.propertyDefinition.property - || this.propertyDefinition.key; - - // If an array contains all undefined values, treat it - // as undefined, to filter back out arrays for input - // that never got entered. - value = isUnpopulatedArray(value) ? undefined : value; - - // Convert to a value suitable for storage in the - // domain object's model - value = this.conversion.toModelValue(value); - - return property - ? specifyValue(model, property, value) - : undefined; - }; - - /** - * Get the raw definition for this property. - * @returns {TypePropertyDefinition} - */ - TypeProperty.prototype.getDefinition = function () { - return this.propertyDefinition; - }; - - return TypeProperty; - } -); diff --git a/platform/core/src/types/TypePropertyConversion.js b/platform/core/src/types/TypePropertyConversion.js deleted file mode 100644 index 5eaf6e3a85..0000000000 --- a/platform/core/src/types/TypePropertyConversion.js +++ /dev/null @@ -1,99 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - var conversions = { - number: { - toModelValue: parseFloat, - toFormValue: function (modelValue) { - return (typeof modelValue === 'number') - ? modelValue.toString(10) : undefined; - } - }, - identity: { - toModelValue: function (v) { - return v; - }, - toFormValue: function (v) { - return v; - } - } - }, - ARRAY_SUFFIX = '[]'; - - // Utility function to handle arrays of conversions - function ArrayConversion(conversion) { - return { - toModelValue: function (formValue) { - return formValue && formValue.map(conversion.toModelValue); - }, - toFormValue: function (modelValue) { - return modelValue && modelValue.map(conversion.toFormValue); - } - }; - } - - /** - * Look up an appropriate conversion between form values and model - * values, e.g. to numeric values. - * @constructor - * @memberof platform/core - */ - function TypePropertyConversion(name) { - if (name - && name.length > ARRAY_SUFFIX.length - && name.indexOf(ARRAY_SUFFIX, name.length - ARRAY_SUFFIX.length) !== -1) { - return new ArrayConversion( - new TypePropertyConversion( - name.substring(0, name.length - ARRAY_SUFFIX.length) - ) - ); - } else { - if (!conversions[name]) { - throw new Error("Unknown conversion type: " + name); - } - - return conversions[name]; - } - } - - /** - * Convert a value from its format as read from a form, to a - * format appropriate to store in a model. - * @method platform/core.TypePropertyConversion#toModelValue - * @param {*} formValue value as read from a form - * @returns {*} value to store in a model - */ - - /** - * Convert a value from its format as stored in a model, to a - * format appropriate to display in a form. - * @method platform/core.TypePropertyConversion#toFormValue - * @param {*} modelValue value as stored in a model - * @returns {*} value to display within a form - */ - - return TypePropertyConversion; - } -); diff --git a/platform/core/src/types/TypeProvider.js b/platform/core/src/types/TypeProvider.js deleted file mode 100644 index 4e40110fa9..0000000000 --- a/platform/core/src/types/TypeProvider.js +++ /dev/null @@ -1,197 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['./TypeImpl', './MergeModels'], - function (TypeImpl, mergeModels) { - - /** - * Provides domain object types that are available/recognized within - * the system. - * - * @interface TypeService - */ - /** - * Get a specific type by name. - * - * @method TypeService#getType - * @param {string} key the key (machine-readable identifier) - * for the type of interest - * @returns {Type} the type identified by this key - */ - /** - * List all known types. - * - * @method TypeService#listTypes - * @returns {Type[]} all known types - */ - - var TO_CONCAT = ['inherits', 'capabilities', 'properties', 'features'], - TO_MERGE = ['model']; - - function copyKeys(a, b) { - Object.keys(b).forEach(function (k) { - a[k] = b[k]; - }); - } - - function removeDuplicates(array) { - var set = {}; - - return array ? array.filter(function (element) { - // Don't filter objects (e.g. property definitions) - if (element instanceof Object && !(element instanceof String)) { - return true; - } - - return set[element] - ? false - : (set[element] = true); - }) : array; - } - - // Reduce an array of type definitions to a single type definition, - // which has merged all properties in order. - function collapse(typeDefs) { - var collapsed = typeDefs.reduce(function (a, b) { - var result = {}; - copyKeys(result, a); - copyKeys(result, b); - - // Special case: Do a merge, e.g. on "model" - TO_MERGE.forEach(function (k) { - if (a[k] && b[k]) { - result[k] = mergeModels(a[k], b[k]); - } - }); - - // Special case: Concatenate certain arrays - TO_CONCAT.forEach(function (k) { - if (a[k] || b[k]) { - result[k] = (a[k] || []).concat(b[k] || []); - } - }); - - return result; - }, {}); - - // Remove any duplicates from the collapsed array - TO_CONCAT.forEach(function (k) { - if (collapsed[k]) { - collapsed[k] = removeDuplicates(collapsed[k]); - } - }); - - return collapsed; - } - - /** - * A type provider provides information about types of domain objects - * within the running Open MCT instance. - * - * @param {Array} types the raw type - * definitions for this type. - * @memberof platform/core - * @constructor - */ - function TypeProvider(types) { - var rawTypeDefinitions = types, - typeDefinitions = (function (typeDefArray) { - var result = {}; - typeDefArray.forEach(function (typeDef) { - var k = typeDef.key; - if (k) { - result[k] = (result[k] || []).concat(typeDef); - } - }); - - return result; - }(rawTypeDefinitions)); - - this.typeMap = {}; - this.typeDefinitions = typeDefinitions; - this.rawTypeDefinitions = types; - } - - TypeProvider.prototype.listTypes = function () { - var self = this; - - return removeDuplicates( - this.rawTypeDefinitions.filter(function (def) { - return def.key; - }).map(function (def) { - return def.key; - }).map(function (key) { - return self.getType(key); - }) - ); - }; - - TypeProvider.prototype.getType = function (key) { - var typeDefinitions = this.typeDefinitions, - self = this; - - function getUndefinedType() { - return (self.undefinedType = self.undefinedType || collapse( - self.rawTypeDefinitions.filter(function (typeDef) { - return !typeDef.key; - }) - )); - } - - function asArray(value) { - return Array.isArray(value) ? value : [value]; - } - - function lookupTypeDef(typeKey) { - function buildTypeDef(typeKeyToBuild) { - var typeDefs = typeDefinitions[typeKeyToBuild] || [], - inherits = typeDefs.map(function (typeDef) { - return asArray(typeDef.inherits || []); - }).reduce(function (a, b) { - return a.concat(b); - }, []), - def = collapse( - [getUndefinedType()].concat( - inherits.map(lookupTypeDef) - ).concat(typeDefs) - ); - - // Always provide a default name - def.model = def.model || {}; - def.model.name = def.model.name - || ("Unnamed " + (def.name || "Object")); - - return def; - } - - return (self.typeMap[typeKey] = - self.typeMap[typeKey] || buildTypeDef(typeKey)); - } - - return new TypeImpl(lookupTypeDef(key)); - }; - - return TypeProvider; - } - -); diff --git a/platform/core/src/views/ViewCapability.js b/platform/core/src/views/ViewCapability.js deleted file mode 100644 index b587f47e0c..0000000000 --- a/platform/core/src/views/ViewCapability.js +++ /dev/null @@ -1,58 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ViewCapability. Created by vwoeltje on 11/10/14. - */ -define( - [], - function () { - - /** - * A `view` capability can be used to retrieve an array of - * all views (or, more specifically, the declarative metadata - * thereabout) which are applicable to a specific domain - * object. - * - * @memberof platform/core - * @implements {Capability} - * @constructor - */ - function ViewCapability(viewService, domainObject) { - this.viewService = viewService; - this.domainObject = domainObject; - } - - /** - * Get all view definitions which are applicable to - * this object. - * @returns {View[]} an array of view definitions - * which are applicable to this object. - * @memberof platform/core.ViewCapability# - */ - ViewCapability.prototype.invoke = function () { - return this.viewService.getViews(this.domainObject); - }; - - return ViewCapability; - } -); diff --git a/platform/core/src/views/ViewProvider.js b/platform/core/src/views/ViewProvider.js deleted file mode 100644 index 1ed4d9803d..0000000000 --- a/platform/core/src/views/ViewProvider.js +++ /dev/null @@ -1,161 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ViewProvider. Created by vwoeltje on 11/10/14. - */ -define( - [], - function () { - - /** - * Provides definitions for views that are available for specific - * domain objects. - * - * @interface ViewService - */ - - /** - * Get all views which are applicable to this domain object. - * - * @method ViewService#getViews - * @param {DomainObject} domainObject the domain object to view - * @returns {View[]} all views which can be used to visualize - * this domain object. - */ - - /** - * A view provider allows view definitions (defined as extensions) - * to be read, and takes responsibility for filtering these down - * to a set that is applicable to specific domain objects. This - * filtering is parameterized by the extension definitions - * themselves; specifically: - * - * * Definitions with a `needs` property containing an array of - * strings are only applicable to domain objects which have - * all those capabilities. - * * If the view definition has a `delegation` property that - * is truthy, then domain objects which delegate capabilities - * from the `needs` property will be treated as having those - * capabilities for purposes of determining view applicability. - * * Definitions with a `type` property are only applicable to - * domain object's whose `type` capability matches or inherits - * from that type. - * - * Views themselves are primarily metadata, such as name, icon and - * description (to be shown in the UI); they do not contain any - * information directly applicable to rendering to the DOM, although - * they do contain sufficient information (such as a `templateUrl`, - * used in the representation bundle) to retrieve those details. - * The role of a view provider and of a view capability is to - * describe what views are available, not how to instantiate them. - * - * @memberof platform/core - * @constructor - * @param {View[]} an array of view definitions - * @param $log Angular's logging service - * @implements {ViewService} - */ - function ViewProvider(views, $log) { - - // Views without defined keys cannot be used in the user - // interface, and can result in unexpected behavior. These - // are filtered out using this function. - function validate(view) { - var key = view.key; - - // Leave a log message to support detection of this issue. - if (!key) { - $log.warn([ - "No key specified for view in ", - (view.bundle || {}).path, - "; omitting this view." - ].join("")); - } - - return key; - } - - // Filter out any key-less views - this.views = views.filter(validate); - } - - ViewProvider.prototype.getViews = function (domainObject) { - var type = domainObject.useCapability("type"); - - // Check if an object has all capabilities designated as `needs` - // for a view. Exposing a capability via delegation is taken to - // satisfy this filter if `allowDelegation` is true. - function capabilitiesMatch(domainObj, capabilities, allowDelegation) { - var delegation = domainObj.getCapability("delegation"); - - allowDelegation = allowDelegation && (delegation !== undefined); - - // Check if an object has (or delegates, if allowed) a - // capability. - function hasCapability(c) { - return domainObj.hasCapability(c) - || (allowDelegation && delegation.doesDelegateCapability(c)); - } - - // For the reduce step below. - function and(a, b) { - return a && b; - } - - // Do a bulk `and` operation over all needed capabilities. - return capabilities.map(hasCapability).reduce(and, true); - } - - // Check if a view and domain object type can be paired; - // both can restrict the others they accept. - function viewMatchesType(view, objType) { - var views = objType && (objType.getDefinition() || {}).views, - matches = true; - - // View is restricted to a certain type - if (view.type) { - matches = matches && objType && objType.instanceOf(view.type); - } - - // Type wishes to restrict its specific views - if (Array.isArray(views)) { - matches = matches && (views.indexOf(view.key) > -1); - } - - return matches; - } - - // First, filter views by type (matched to domain object type.) - // Second, filter by matching capabilities. - return this.views.filter(function (view) { - return viewMatchesType(view, type) && capabilitiesMatch( - domainObject, - view.needs || [], - view.delegation || false - ); - }); - }; - - return ViewProvider; - } -); diff --git a/platform/core/test/actions/ActionAggregatorSpec.js b/platform/core/test/actions/ActionAggregatorSpec.js deleted file mode 100644 index fa4309bbbd..0000000000 --- a/platform/core/test/actions/ActionAggregatorSpec.js +++ /dev/null @@ -1,73 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ActionAggregatorSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/actions/ActionAggregator"], - function (ActionAggregator) { - - describe("Action aggregator", function () { - var mockAggregators, - aggregator; - - function createMockActionProvider(actions, i) { - var spy = jasmine.createSpyObj("agg" + i, ["getActions"]); - spy.getActions.and.returnValue(actions); - - return spy; - } - - beforeEach(function () { - mockAggregators = [ - ["a", "b"], - ["c"], - ["d", "e", "f"] - ].map(createMockActionProvider); - aggregator = new ActionAggregator(mockAggregators); - }); - - it("consolidates results from aggregated services", function () { - expect(aggregator.getActions()).toEqual( - ["a", "b", "c", "d", "e", "f"] - ); - }); - - it("passes context along to all aggregated services", function () { - var context = { domainObject: "something" }; - - // Verify precondition - mockAggregators.forEach(function (mockAgg) { - expect(mockAgg.getActions).not.toHaveBeenCalled(); - }); - - aggregator.getActions(context); - - // All services should have been called with this context - mockAggregators.forEach(function (mockAgg) { - expect(mockAgg.getActions).toHaveBeenCalledWith(context); - }); - }); - }); - } -); diff --git a/platform/core/test/actions/ActionCapabilitySpec.js b/platform/core/test/actions/ActionCapabilitySpec.js deleted file mode 100644 index 37e2876dc0..0000000000 --- a/platform/core/test/actions/ActionCapabilitySpec.js +++ /dev/null @@ -1,96 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ActionCapabilitySpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/actions/ActionCapability"], - function (ActionCapability) { - - describe("The action capability", function () { - var mockQ, - mockAction, - mockActionService, - mockDomainObject, - capability; - - beforeEach(function () { - mockAction = jasmine.createSpyObj( - "action", - ["perform", "getMetadata"] - ); - mockActionService = jasmine.createSpyObj( - "actionService", - ["getActions"] - ); - mockQ = jasmine.createSpyObj( - "$q", - ["when"] - ); - mockDomainObject = jasmine.createSpyObj( - "domainObject", - ["getId", "getModel", "getCapability", "hasCapability", "useCapability"] - ); - - mockActionService.getActions.and.returnValue([mockAction, {}]); - - capability = new ActionCapability( - mockQ, - mockActionService, - mockDomainObject - ); - }); - - it("retrieves action for domain objects from the action service", function () { - // Verify precondition - expect(mockActionService.getActions).not.toHaveBeenCalled(); - - // Call getActions - expect(capability.getActions("some key")).toEqual([mockAction, {}]); - - // Verify interaction - expect(mockActionService.getActions).toHaveBeenCalledWith({ - key: "some key", - domainObject: mockDomainObject - }); - }); - - it("promises the result of performed actions", function () { - var mockPromise = jasmine.createSpyObj("promise", ["then"]); - mockQ.when.and.returnValue(mockPromise); - mockAction.perform.and.returnValue("the action's result"); - - // Verify precondition - expect(mockAction.perform).not.toHaveBeenCalled(); - - // Perform via capability - expect(capability.perform()).toEqual(mockPromise); - - // Verify that the action's result is what was wrapped - expect(mockQ.when).toHaveBeenCalledWith("the action's result"); - - }); - - }); - } -); diff --git a/platform/core/test/actions/ActionProviderSpec.js b/platform/core/test/actions/ActionProviderSpec.js deleted file mode 100644 index f6f3b8f9c0..0000000000 --- a/platform/core/test/actions/ActionProviderSpec.js +++ /dev/null @@ -1,204 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ActionProviderSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/actions/ActionProvider"], - function (ActionProvider) { - - describe("The action provider", function () { - var mockLog, - actions, - actionProvider; - - function SimpleAction() { - return { - perform: function () { - return "simple"; - } - }; - } - - function CategorizedAction() { - return { - perform: function () { - return "categorized"; - } - }; - } - - CategorizedAction.category = "someCategory"; - - function KeyedAction() { - return { - perform: function () { - return "keyed"; - } - }; - } - - KeyedAction.key = "someKey"; - - function CategorizedKeyedAction() { - return { - perform: function () { - return "both"; - } - }; - } - - CategorizedKeyedAction.key = "someKey"; - CategorizedKeyedAction.category = "someCategory"; - - function MetadataAction() { - return { - perform: function () { - return "metadata"; - }, - getMetadata: function () { - return "custom metadata"; - } - }; - } - - MetadataAction.key = "metadata"; - - beforeEach(function () { - mockLog = jasmine.createSpyObj( - '$log', - ['error', 'warn', 'info', 'debug'] - ); - actions = [ - SimpleAction, - CategorizedAction, - KeyedAction, - CategorizedKeyedAction, - MetadataAction - ]; - actionProvider = new ActionProvider(actions); - }); - - it("exposes provided action extensions", function () { - var provided = actionProvider.getActions(); - - // Should have gotten all actions - expect(provided.length).toEqual(actions.length); - - // Verify that this was the action we expected - expect(provided[0].perform()).toEqual("simple"); - }); - - it("matches provided actions by key", function () { - var provided = actionProvider.getActions({ key: "someKey" }); - - // Only two should have matched - expect(provided.length).toEqual(2); - - // Verify that this was the action we expected - expect(provided[0].perform()).toEqual("keyed"); - }); - - it("matches provided actions by category", function () { - var provided = actionProvider.getActions({ category: "someCategory" }); - - // Only two should have matched - expect(provided.length).toEqual(2); - - // Verify that this was the action we expected - expect(provided[0].perform()).toEqual("categorized"); - }); - - it("matches provided actions by both category and key", function () { - var provided = actionProvider.getActions({ - category: "someCategory", - key: "someKey" - }); - - // Only two should have matched - expect(provided.length).toEqual(1); - - // Verify that this was the action we expected - expect(provided[0].perform()).toEqual("both"); - }); - - it("adds a getMetadata method when none is defined", function () { - var provided = actionProvider.getActions({ - category: "someCategory", - key: "someKey" - }); - - // Should be defined, even though the action didn't define this - expect(provided[0].getMetadata).toBeDefined(); - - // Should have static fields, plus context - expect(provided[0].getMetadata().context).toEqual({ - key: "someKey", - category: "someCategory" - }); - - }); - - it("does not override defined getMetadata methods", function () { - var provided = actionProvider.getActions({ key: "metadata" }); - expect(provided[0].getMetadata()).toEqual("custom metadata"); - }); - - describe("when actions throw errors during instantiation", function () { - var errorText, - provided; - - beforeEach(function () { - errorText = "some error text"; - - function BadAction() { - throw new Error(errorText); - } - - provided = new ActionProvider( - [SimpleAction, BadAction], - mockLog - ).getActions(); - }); - - it("logs an error", function () { - expect(mockLog.error) - .toHaveBeenCalledWith(jasmine.any(String)); - }); - - it("reports the error's message", function () { - expect( - mockLog.error.calls.mostRecent().args[0].indexOf(errorText) - ).not.toEqual(-1); - }); - - it("still provides valid actions", function () { - expect(provided.length).toEqual(1); - expect(provided[0].perform()).toEqual("simple"); - }); - - }); - - }); - } -); diff --git a/platform/core/test/actions/LoggingActionDecoratorSpec.js b/platform/core/test/actions/LoggingActionDecoratorSpec.js deleted file mode 100644 index fc8066ad0c..0000000000 --- a/platform/core/test/actions/LoggingActionDecoratorSpec.js +++ /dev/null @@ -1,71 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * LoggingActionDecoratorSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/actions/LoggingActionDecorator"], - function (LoggingActionDecorator) { - - describe("The logging action decorator", function () { - var mockLog, - mockAction, - mockActionService, - decorator; - - beforeEach(function () { - mockAction = jasmine.createSpyObj( - "action", - ["perform", "getMetadata"] - ); - mockActionService = jasmine.createSpyObj( - "actionService", - ["getActions"] - ); - mockLog = jasmine.createSpyObj( - "$log", - ["error", "warn", "info", "debug"] - ); - - mockActionService.getActions.and.returnValue([mockAction]); - - decorator = new LoggingActionDecorator( - mockLog, - mockActionService - ); - }); - - it("logs when actions are performed", function () { - // Verify precondition - expect(mockLog.info).not.toHaveBeenCalled(); - - // Perform an action, retrieved through the decorator - decorator.getActions()[0].perform(); - - // That should have been logged. - expect(mockLog.info).toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/core/test/capabilities/CompositionCapabilitySpec.js b/platform/core/test/capabilities/CompositionCapabilitySpec.js deleted file mode 100644 index 7f2d0c05fa..0000000000 --- a/platform/core/test/capabilities/CompositionCapabilitySpec.js +++ /dev/null @@ -1,214 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * CompositionCapabilitySpec. Created by vwoeltje on 11/6/14. - */ -define( - [ - "../../src/capabilities/CompositionCapability", - "../../src/capabilities/ContextualDomainObject" - ], - function (CompositionCapability, ContextualDomainObject) { - - var DOMAIN_OBJECT_METHODS = [ - "getId", - "getModel", - "getCapability", - "hasCapability", - "useCapability" - ]; - - describe("The composition capability", function () { - var mockDomainObject, - mockInjector, - mockObjectService, - composition; - - // Composition Capability makes use of promise chaining, - // so support that, but don't introduce complication of - // native promises. - function mockPromise(value) { - return (value || {}).then ? value : { - then: function (callback) { - return mockPromise(callback(value)); - } - }; - } - - beforeEach(function () { - mockDomainObject = jasmine.createSpyObj( - "domainObject", - DOMAIN_OBJECT_METHODS - ); - - mockObjectService = jasmine.createSpyObj( - "objectService", - ["getObjects"] - ); - - mockInjector = { - get: function (name) { - return (name === "objectService") && mockObjectService; - } - }; - - mockObjectService.getObjects.and.returnValue(mockPromise([])); - - composition = new CompositionCapability( - mockInjector, - mockDomainObject - ); - }); - - it("applies only to models with a composition field", function () { - expect(CompositionCapability.appliesTo({ composition: [] })) - .toBeTruthy(); - expect(CompositionCapability.appliesTo({})) - .toBeFalsy(); - }); - - it("requests ids found in model's composition from the object service", function () { - var ids = ["a", "b", "c", "xyz"]; - - mockDomainObject.getModel.and.returnValue({ composition: ids }); - - composition.invoke(); - - expect(mockObjectService.getObjects).toHaveBeenCalledWith(ids); - }); - - it("adds a context capability to returned domain objects", function () { - var result, - mockChild = jasmine.createSpyObj("child", DOMAIN_OBJECT_METHODS); - - mockDomainObject.getModel.and.returnValue({ composition: ["x"] }); - mockObjectService.getObjects.and.returnValue(mockPromise({x: mockChild})); - mockChild.getCapability.and.returnValue(undefined); - - composition.invoke().then(function (c) { - result = c; - }); - - // Should have been added by a wrapper - expect(result[0].getCapability('context')).toBeDefined(); - - }); - - it("allows domain objects to be added", function () { - var result, - testModel = { composition: [] }, - mockChild = jasmine.createSpyObj("child", DOMAIN_OBJECT_METHODS); - - mockDomainObject.getModel.and.returnValue(testModel); - mockObjectService.getObjects.and.returnValue(mockPromise({a: mockChild})); - mockChild.getCapability.and.returnValue(undefined); - mockChild.getId.and.returnValue('a'); - - mockDomainObject.useCapability.and.callFake(function (key, mutator) { - if (key === 'mutation') { - mutator(testModel); - - return mockPromise(true); - } - }); - - composition.add(mockChild).then(function (domainObject) { - result = domainObject; - }); - - expect(testModel.composition).toEqual(['a']); - - // Should have returned the added object in its new context - expect(result.getId()).toEqual('a'); - expect(result.getCapability('context')).toBeDefined(); - expect(result.getCapability('context').getParent()) - .toEqual(mockDomainObject); - }); - - it("does not re-add IDs which are already present", function () { - var result, - testModel = { composition: ['a'] }, - mockChild = jasmine.createSpyObj("child", DOMAIN_OBJECT_METHODS); - - mockDomainObject.getModel.and.returnValue(testModel); - mockObjectService.getObjects.and.returnValue(mockPromise({a: mockChild})); - mockChild.getCapability.and.returnValue(undefined); - mockChild.getId.and.returnValue('a'); - - mockDomainObject.useCapability.and.callFake(function (key, mutator) { - if (key === 'mutation') { - mutator(testModel); - - return mockPromise(true); - } - }); - - composition.add(mockChild).then(function (domainObject) { - result = domainObject; - }); - - // Still just 'a' - expect(testModel.composition).toEqual(['a']); - - // Should have returned the added object in its new context - expect(result.getId()).toEqual('a'); - expect(result.getCapability('context')).toBeDefined(); - expect(result.getCapability('context').getParent()) - .toEqual(mockDomainObject); - }); - - it("can add objects at a specified index", function () { - var result, - testModel = { composition: ['a', 'b', 'c'] }, - mockChild = jasmine.createSpyObj("child", DOMAIN_OBJECT_METHODS); - - mockDomainObject.getModel.and.returnValue(testModel); - mockObjectService.getObjects.and.returnValue(mockPromise({a: mockChild})); - mockChild.getCapability.and.returnValue(undefined); - mockChild.getId.and.returnValue('a'); - - mockDomainObject.useCapability.and.callFake(function (key, mutator) { - if (key === 'mutation') { - mutator(testModel); - - return mockPromise(true); - } - }); - - composition.add(mockChild, 1).then(function (domainObject) { - result = domainObject; - }); - - // Still just 'a' - expect(testModel.composition).toEqual(['b', 'a', 'c']); - - // Should have returned the added object in its new context - expect(result.getId()).toEqual('a'); - expect(result.getCapability('context')).toBeDefined(); - expect(result.getCapability('context').getParent()) - .toEqual(mockDomainObject); - }); - - }); - } -); diff --git a/platform/core/test/capabilities/ContextCapabilitySpec.js b/platform/core/test/capabilities/ContextCapabilitySpec.js deleted file mode 100644 index 0880c1706a..0000000000 --- a/platform/core/test/capabilities/ContextCapabilitySpec.js +++ /dev/null @@ -1,79 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ContextCapability. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/capabilities/ContextCapability"], - function (ContextCapability) { - - var DOMAIN_OBJECT_METHODS = [ - "getId", - "getModel", - "getCapability", - "hasCapability", - "useCapability" - ]; - - describe("The context capability", function () { - var mockDomainObject, - mockParent, - mockGrandparent, - mockContext, - context; - - beforeEach(function () { - mockDomainObject = jasmine.createSpyObj("domainObject", DOMAIN_OBJECT_METHODS); - mockParent = jasmine.createSpyObj("parent", DOMAIN_OBJECT_METHODS); - mockGrandparent = jasmine.createSpyObj("grandparent", DOMAIN_OBJECT_METHODS); - mockContext = jasmine.createSpyObj("context", ["getParent", "getRoot", "getPath"]); - - mockParent.getCapability.and.returnValue(mockContext); - mockContext.getParent.and.returnValue(mockGrandparent); - mockContext.getRoot.and.returnValue(mockGrandparent); - mockContext.getPath.and.returnValue([mockGrandparent, mockParent]); - - context = new ContextCapability(mockParent, mockDomainObject); - }); - - it("allows an object's parent to be retrieved", function () { - expect(context.getParent()).toEqual(mockParent); - }); - - it("allows an object's full ancestry to be retrieved", function () { - expect(context.getPath()).toEqual([mockGrandparent, mockParent, mockDomainObject]); - }); - - it("allows the deepest ancestor of an object to be retrieved", function () { - expect(context.getRoot()).toEqual(mockGrandparent); - }); - - it("treats ancestors with no context capability as deepest ancestors", function () { - mockParent.getCapability.and.returnValue(undefined); - expect(context.getPath()).toEqual([mockParent, mockDomainObject]); - expect(context.getRoot()).toEqual(mockParent); - }); - - }); - } -); diff --git a/platform/core/test/capabilities/ContextualDomainObjectSpec.js b/platform/core/test/capabilities/ContextualDomainObjectSpec.js deleted file mode 100644 index c59e151b7a..0000000000 --- a/platform/core/test/capabilities/ContextualDomainObjectSpec.js +++ /dev/null @@ -1,78 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ContextualDomainObjectSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/capabilities/ContextualDomainObject"], - function (ContextualDomainObject) { - - var DOMAIN_OBJECT_METHODS = [ - "getId", - "getModel", - "getCapability", - "hasCapability", - "useCapability" - ]; - - describe("A contextual domain object", function () { - var mockParent, - mockDomainObject, - model, - contextualDomainObject; - - beforeEach(function () { - mockParent = jasmine.createSpyObj("parent", DOMAIN_OBJECT_METHODS); - mockDomainObject = jasmine.createSpyObj("parent", DOMAIN_OBJECT_METHODS); - - model = { someKey: "some value" }; - - mockDomainObject.getCapability.and.returnValue("some capability"); - mockDomainObject.getModel.and.returnValue(model); - - contextualDomainObject = new ContextualDomainObject( - mockDomainObject, - mockParent - ); - }); - - it("adds a context capability to a domain object", function () { - var context = contextualDomainObject.getCapability('context'); - - // Expect something that looks like a context capability - expect(context).toBeDefined(); - expect(context.getPath).toBeDefined(); - expect(context.getRoot).toBeDefined(); - expect(context.getParent()).toEqual(mockParent); - }); - - it("does not shadow other domain object methods", function () { - expect(contextualDomainObject.getModel()) - .toEqual(model); - expect(contextualDomainObject.getCapability("other")) - .toEqual("some capability"); - }); - - }); - } -); diff --git a/platform/core/test/capabilities/CoreCapabilityProviderSpec.js b/platform/core/test/capabilities/CoreCapabilityProviderSpec.js deleted file mode 100644 index 82609d603a..0000000000 --- a/platform/core/test/capabilities/CoreCapabilityProviderSpec.js +++ /dev/null @@ -1,112 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * CoreCapabilityProviderSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/capabilities/CoreCapabilityProvider"], - function (CoreCapabilityProvider) { - - describe("The core capability provider", function () { - var mockLog, - provider; - - function BasicCapability() { - return; - } - - BasicCapability.key = "basic"; - - function ApplicableCapability() { - return; - } - - ApplicableCapability.key = "applicable"; - ApplicableCapability.appliesTo = function (model) { - return !model.isNotApplicable; - }; - - function KeylessCapability() { - return; - } - - beforeEach(function () { - KeylessCapability.key = undefined; - - mockLog = jasmine.createSpyObj( - "$log", - ["error", "warn", "info", "debug"] - ); - - provider = new CoreCapabilityProvider([ - BasicCapability, - ApplicableCapability, - KeylessCapability - ], mockLog); - }); - - it("returns capabilities for models, from extensions", function () { - expect(provider.getCapabilities({})).toEqual({ - basic: BasicCapability, - applicable: ApplicableCapability - }); - }); - - it("filters out capabilities which do not apply to models", function () { - expect(provider.getCapabilities({ isNotApplicable: true })).toEqual({ - basic: BasicCapability - }); - }); - - it("logs a warning when capability extensions have not defined keys", function () { - // Verify precondition - expect(mockLog.warn).not.toHaveBeenCalled(); - - provider.getCapabilities({}); - - expect(mockLog.warn).toHaveBeenCalled(); - - }); - - it("does not log a warning when all capability extensions are valid", function () { - KeylessCapability.key = "someKey"; - provider.getCapabilities({}); - expect(mockLog.warn).not.toHaveBeenCalled(); - }); - - it("prefers higher-priority capability", function () { - KeylessCapability.key = BasicCapability.key; - expect(provider.getCapabilities({}).basic) - .toEqual(BasicCapability); - }); - - // https://github.com/nasa/openmctweb/issues/49 - it("does not log a warning for multiple capabilities with the same key", function () { - KeylessCapability.key = BasicCapability.key; - provider.getCapabilities({}); - expect(mockLog.warn).not.toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/core/test/capabilities/DelegationCapabilitySpec.js b/platform/core/test/capabilities/DelegationCapabilitySpec.js deleted file mode 100644 index 4f277e50ff..0000000000 --- a/platform/core/test/capabilities/DelegationCapabilitySpec.js +++ /dev/null @@ -1,110 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * DelegationCapabilitySpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/capabilities/DelegationCapability"], - function (DelegationCapability) { - - describe("The delegation capability", function () { - var captured, - typeDef = {}, - type, - capabilities, - children = [], - object = {}, - delegation; - - function capture(k) { - return function (v) { - captured[k] = v; - }; - } - - function TestDomainObject(caps, id) { - return { - getId: function () { - return id; - }, - getCapability: function (name) { - return caps[name]; - }, - useCapability: function (name) { - return this.getCapability(name).invoke(); - }, - hasCapability: function (name) { - return this.getCapability(name) !== undefined; - } - }; - } - - function mockPromise(value) { - return { - then: function (callback) { - return value.then - ? value : mockPromise(callback(value)); - } - }; - } - - beforeEach(function () { - captured = {}; - typeDef = {}; - typeDef.delegates = ["foo"]; - type = { - getDefinition: function () { - return typeDef; - } - }; - children = []; - capabilities = { - type: type, - composition: { - invoke: function () { - return mockPromise(children); - } - } - }; - object = new TestDomainObject(capabilities); - - delegation = new DelegationCapability({ when: mockPromise }, object); - }); - - it("provides a list of children which expose a desired capability", function () { - - children = [ - new TestDomainObject({ foo: true }, 'has-capability'), - new TestDomainObject({ }, 'does-not-have-capability') - ]; - - // Look up delegates - delegation.getDelegates('foo').then(capture('delegates')); - - // Expect only the first child to be a delegate - expect(captured.delegates.length).toEqual(1); - expect(captured.delegates[0].getId()).toEqual('has-capability'); - }); - }); - } -); diff --git a/platform/core/test/capabilities/InstantiationCapabilitySpec.js b/platform/core/test/capabilities/InstantiationCapabilitySpec.js deleted file mode 100644 index 1f9ea9a97c..0000000000 --- a/platform/core/test/capabilities/InstantiationCapabilitySpec.js +++ /dev/null @@ -1,94 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/InstantiationCapability"], - function (InstantiationCapability) { - - describe("The 'instantiation' capability", function () { - var mockInjector, - mockIdentifierService, - mockInstantiate, - mockIdentifier, - mockNow, - mockDomainObject, - instantiation; - - beforeEach(function () { - mockInjector = jasmine.createSpyObj("$injector", ["get"]); - mockInstantiate = jasmine.createSpy("instantiate"); - mockIdentifierService = jasmine.createSpyObj( - 'identifierService', - ['parse', 'generate'] - ); - mockIdentifier = jasmine.createSpyObj( - 'identifier', - ['getSpace', 'getKey', 'getDefinedSpace'] - ); - mockDomainObject = jasmine.createSpyObj( - 'domainObject', - ['getId', 'getCapability', 'getModel'] - ); - - mockInjector.get.and.callFake(function (key) { - return { - 'instantiate': mockInstantiate - }[key]; - }); - mockIdentifierService.parse.and.returnValue(mockIdentifier); - mockIdentifierService.generate.and.returnValue("some-id"); - - mockNow = jasmine.createSpy(); - mockNow.and.returnValue(1234321); - - instantiation = new InstantiationCapability( - mockInjector, - mockIdentifierService, - mockNow, - mockDomainObject - ); - }); - - it("aliases 'instantiate' as 'invoke'", function () { - expect(instantiation.invoke).toBe(instantiation.instantiate); - }); - - it("uses instantiate and contextualize to create domain objects", function () { - var mockDomainObj = jasmine.createSpyObj('domainObject', [ - 'getId', - 'getModel', - 'getCapability', - 'useCapability', - 'hasCapability' - ]), testModel = { someKey: "some value" }; - mockInstantiate.and.returnValue(mockDomainObj); - instantiation.instantiate(testModel); - expect(mockInstantiate) - .toHaveBeenCalledWith({ - someKey: "some value", - modified: mockNow() - }, jasmine.any(String)); - }); - - }); - } -); diff --git a/platform/core/test/capabilities/MetadataCapabilitySpec.js b/platform/core/test/capabilities/MetadataCapabilitySpec.js deleted file mode 100644 index 9d087c5363..0000000000 --- a/platform/core/test/capabilities/MetadataCapabilitySpec.js +++ /dev/null @@ -1,99 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/MetadataCapability'], - function (MetadataCapability) { - - describe("The metadata capability", function () { - var mockDomainObject, - mockType, - mockProperties, - testModel, - metadata; - - function getCapability(key) { - return key === 'type' ? mockType : undefined; - } - - function findValue(properties, name) { - var i; - for (i = 0; i < properties.length; i += 1) { - if (properties[i].name === name) { - return properties[i].value; - } - } - } - - beforeEach(function () { - mockDomainObject = jasmine.createSpyObj( - 'domainObject', - ['getId', 'getCapability', 'useCapability', 'getModel'] - ); - mockType = jasmine.createSpyObj( - 'type', - ['getProperties', 'getName'] - ); - mockProperties = ['a', 'b', 'c'].map(function (k) { - var mockProperty = jasmine.createSpyObj( - 'property-' + k, - ['getValue', 'getDefinition'] - ); - mockProperty.getValue.and.returnValue("Value " + k); - mockProperty.getDefinition.and.returnValue({ name: "Property " + k}); - - return mockProperty; - }); - testModel = { name: "" }; - - mockDomainObject.getId.and.returnValue("Test id"); - mockDomainObject.getModel.and.returnValue(testModel); - mockDomainObject.getCapability.and.callFake(getCapability); - mockDomainObject.useCapability.and.callFake(getCapability); - mockType.getProperties.and.returnValue(mockProperties); - mockType.getName.and.returnValue("Test type"); - - metadata = new MetadataCapability(mockDomainObject); - }); - - it("reads properties from the domain object model", function () { - metadata.invoke(); - mockProperties.forEach(function (mockProperty) { - expect(mockProperty.getValue).toHaveBeenCalledWith(testModel); - }); - }); - - it("reports type-specific properties", function () { - var properties = metadata.invoke(); - expect(findValue(properties, 'Property a')).toEqual("Value a"); - expect(findValue(properties, 'Property b')).toEqual("Value b"); - expect(findValue(properties, 'Property c')).toEqual("Value c"); - }); - - it("reports generic properties", function () { - var properties = metadata.invoke(); - expect(findValue(properties, 'Type')).toEqual("Test type"); - }); - - }); - } -); diff --git a/platform/core/test/capabilities/MutationCapabilitySpec.js b/platform/core/test/capabilities/MutationCapabilitySpec.js deleted file mode 100644 index f9a70719f7..0000000000 --- a/platform/core/test/capabilities/MutationCapabilitySpec.js +++ /dev/null @@ -1,139 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * MutationCapabilitySpec. Created by vwoeltje on 11/6/14. - */ -define( - [ - "../../src/capabilities/MutationCapability", - "../../src/services/Topic" - ], - function (MutationCapability, Topic) { - - describe("The mutation capability", function () { - var testModel, - topic, - mockNow, - domainObject = { - getId: function () { - return "test-id"; - }, - getModel: function () { - return testModel; - } - }, - mutation; - - beforeEach(function () { - testModel = { number: 6 }; - topic = new Topic(); - mockNow = jasmine.createSpy('now'); - mockNow.and.returnValue(12321); - mutation = new MutationCapability( - topic, - mockNow, - domainObject - ); - }); - - it("allows mutation of a model", function () { - mutation.invoke(function (m) { - m.number = m.number * 7; - }); - expect(testModel.number).toEqual(42); - }); - - it("allows setting a model", function () { - mutation.invoke(function () { - return { someKey: "some value" }; - }); - expect(testModel.number).toBeUndefined(); - expect(testModel.someKey).toEqual("some value"); - }); - - it("allows model mutation to be aborted", function () { - mutation.invoke(function (m) { - m.number = m.number * 7; - - return false; // Should abort change - }); - // Number should not have been changed - expect(testModel.number).toEqual(6); - }); - - it("attaches a timestamp on mutation", function () { - // Verify precondition - expect(testModel.modified).toBeUndefined(); - mutation.invoke(function (m) { - m.number = m.number * 7; - }); - // Should have gotten a timestamp from 'now' - expect(testModel.modified).toEqual(12321); - }); - - it("allows a timestamp to be provided", function () { - mutation.invoke(function (m) { - m.number = m.number * 7; - }, 42); - // Should have gotten a timestamp from 'now' - expect(testModel.modified).toEqual(42); - }); - - it("notifies listeners of mutation", function () { - var mockCallback = jasmine.createSpy('callback'); - mutation.listen(mockCallback); - mutation.invoke(function (m) { - m.number = 8; - }); - expect(mockCallback).toHaveBeenCalled(); - expect(mockCallback.calls.mostRecent().args[0].number) - .toEqual(8); - }); - - it("allows listeners to stop listening", function () { - var mockCallback = jasmine.createSpy('callback'); - mutation.listen(mockCallback)(); // Unlisten immediately - mutation.invoke(function (m) { - m.number = 8; - }); - expect(mockCallback).not.toHaveBeenCalled(); - }); - - it("shares listeners across instances", function () { - var mockCallback = jasmine.createSpy('callback'), - otherMutation = new MutationCapability( - topic, - mockNow, - domainObject - ); - mutation.listen(mockCallback); - otherMutation.invoke(function (m) { - m.number = 8; - }); - expect(mockCallback).toHaveBeenCalled(); - expect(mockCallback.calls.mostRecent().args[0].number) - .toEqual(8); - }); - }); - } -); diff --git a/platform/core/test/capabilities/PersistenceCapabilitySpec.js b/platform/core/test/capabilities/PersistenceCapabilitySpec.js deleted file mode 100644 index 67189a6889..0000000000 --- a/platform/core/test/capabilities/PersistenceCapabilitySpec.js +++ /dev/null @@ -1,196 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ -/** - * PersistenceCapabilitySpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/capabilities/PersistenceCapability"], - function (PersistenceCapability) { - - describe("The persistence capability", function () { - var mockPersistenceService, - mockIdentifierService, - mockDomainObject, - mockIdentifier, - mockNofificationService, - mockCacheService, - mockQ, - key = "persistence key", - id = "object identifier", - model, - SPACE = "some space", - persistence, - mockOpenMCT, - mockNewStyleDomainObject; - - function asPromise(value, doCatch) { - return (value || {}).then ? value : { - then: function (callback) { - return asPromise(callback(value)); - }, - catch: function (callback) { - //Define a default 'happy' catch, that skips over the - // catch callback - return doCatch ? asPromise(callback(value)) : asPromise(value); - } - }; - } - - beforeEach(function () { - model = { - someKey: "some value", - name: "domain object" - }; - - mockPersistenceService = jasmine.createSpyObj( - "persistenceService", - ["updateObject", "readObject", "createObject", "deleteObject"] - ); - - mockIdentifierService = jasmine.createSpyObj( - 'identifierService', - ['parse', 'generate'] - ); - mockIdentifier = jasmine.createSpyObj( - 'identifier', - ['getSpace', 'getKey', 'getDefinedSpace'] - ); - mockQ = jasmine.createSpyObj( - "$q", - ["reject", "when"] - ); - mockNofificationService = jasmine.createSpyObj( - "notificationService", - ["error"] - ); - mockCacheService = jasmine.createSpyObj( - "cacheService", - ["get", "put", "remove", "all"] - ); - - mockDomainObject = { - getId: function () { - return id; - }, - getModel: function () { - return model; - }, - useCapability: jasmine.createSpy() - }; - - mockNewStyleDomainObject = Object.assign({}, model); - mockNewStyleDomainObject.identifier = { - namespace: SPACE, - key: key - }; - - // Simulate mutation capability - mockDomainObject.useCapability.and.callFake(function (capability, mutator) { - if (capability === 'mutation') { - model = mutator(model) || model; - } - }); - - mockOpenMCT = {}; - mockOpenMCT.objects = jasmine.createSpyObj('Object API', ['save']); - - mockIdentifierService.parse.and.returnValue(mockIdentifier); - mockIdentifier.getSpace.and.returnValue(SPACE); - mockIdentifier.getKey.and.returnValue(key); - mockQ.when.and.callFake(asPromise); - persistence = new PersistenceCapability( - mockCacheService, - mockPersistenceService, - mockIdentifierService, - mockNofificationService, - mockQ, - mockOpenMCT, - mockDomainObject - ); - }); - - describe("successful persistence", function () { - beforeEach(function () { - mockOpenMCT.objects.save.and.returnValue(Promise.resolve(true)); - }); - it("creates unpersisted objects with the persistence service", function () { - // Verify precondition; no call made during constructor - expect(mockOpenMCT.objects.save).not.toHaveBeenCalled(); - - persistence.persist(); - - expect(mockOpenMCT.objects.save).toHaveBeenCalledWith(mockNewStyleDomainObject); - }); - - it("reports which persistence space an object belongs to", function () { - expect(persistence.getSpace()).toEqual(SPACE); - }); - - it("refreshes the domain object model from persistence", function () { - var refreshModel = {someOtherKey: "some other value"}; - model.persisted = 1; - mockPersistenceService.readObject.and.returnValue(asPromise(refreshModel)); - persistence.refresh(); - expect(model).toEqual(refreshModel); - }); - - it("does not trigger error notification on successful" - + " persistence", function () { - let rejected = false; - - return persistence.persist() - .catch(() => rejected = true) - .then(() => { - expect(rejected).toBe(false); - expect(mockNofificationService.error).not.toHaveBeenCalled(); - }); - }); - }); - - describe("unsuccessful persistence", function () { - beforeEach(function () { - mockOpenMCT.objects.save.and.returnValue(Promise.resolve(false)); - }); - it("rejects on falsey persistence result", function () { - let rejected = false; - - return persistence.persist() - .catch(() => rejected = true) - .then(() => { - expect(rejected).toBe(true); - }); - }); - - it("notifies user on persistence failure", function () { - let rejected = false; - - return persistence.persist() - .catch(() => rejected = true) - .then(() => { - expect(rejected).toBe(true); - expect(mockNofificationService.error).toHaveBeenCalled(); - }); - }); - }); - }); - } -); diff --git a/platform/core/test/capabilities/RelationshipCapabilitySpec.js b/platform/core/test/capabilities/RelationshipCapabilitySpec.js deleted file mode 100644 index 8b42c54d44..0000000000 --- a/platform/core/test/capabilities/RelationshipCapabilitySpec.js +++ /dev/null @@ -1,144 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * CompositionCapabilitySpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/capabilities/RelationshipCapability"], - function (RelationshipCapability) { - - var DOMAIN_OBJECT_METHODS = [ - "getId", - "getModel", - "getCapability", - "hasCapability", - "useCapability" - ]; - - describe("The relationship capability", function () { - var mockDomainObject, - mockInjector, - mockObjectService, - relationship; - - // Composition Capability makes use of promise chaining, - // so support that, but don't introduce complication of - // native promises. - function mockPromise(value) { - return { - then: function (callback) { - return mockPromise(callback(value)); - } - }; - } - - beforeEach(function () { - mockDomainObject = jasmine.createSpyObj( - "domainObject", - DOMAIN_OBJECT_METHODS - ); - - mockObjectService = jasmine.createSpyObj( - "objectService", - ["getObjects"] - ); - - mockInjector = { - get: function (name) { - return (name === "objectService") && mockObjectService; - } - }; - - mockObjectService.getObjects.and.returnValue(mockPromise([])); - - relationship = new RelationshipCapability( - mockInjector, - mockDomainObject - ); - }); - - it("applies only to models with a 'relationships' field", function () { - expect(RelationshipCapability.appliesTo({ relationships: {} })) - .toBeTruthy(); - expect(RelationshipCapability.appliesTo({})) - .toBeFalsy(); - }); - - it("requests ids found in model's composition from the object service", function () { - var ids = ["a", "b", "c", "xyz"]; - - mockDomainObject.getModel.and.returnValue({ relationships: { xyz: ids } }); - - relationship.getRelatedObjects('xyz'); - - expect(mockObjectService.getObjects).toHaveBeenCalledWith(ids); - }); - - it("provides a list of relationship types", function () { - mockDomainObject.getModel.and.returnValue({ - relationships: { - abc: ['a', 'b'], - def: "not an array, should be ignored", - xyz: [] - } - }); - expect(relationship.listRelationships()).toEqual(['abc', 'xyz']); - }); - - it("avoids redundant requests", function () { - // Lookups can be expensive, so this capability - // should have some self-caching - mockDomainObject.getModel - .and.returnValue({ relationships: { xyz: ['a'] } }); - - // Call twice; response should be the same object instance - expect(relationship.getRelatedObjects('xyz')) - .toBe(relationship.getRelatedObjects('xyz')); - - // Should have only made one call - expect(mockObjectService.getObjects.calls.count()) - .toEqual(1); - }); - - it("makes new requests on modification", function () { - // Lookups can be expensive, so this capability - // should have some self-caching - var testModel; - - testModel = { relationships: { xyz: ['a'] } }; - - mockDomainObject.getModel.and.returnValue(testModel); - - // Call twice, but as if modification had occurred in between - relationship.getRelatedObjects('xyz'); - testModel.modified = 123; - relationship.getRelatedObjects('xyz'); - - // Should have only made one call - expect(mockObjectService.getObjects.calls.count()) - .toEqual(2); - }); - - }); - } -); diff --git a/platform/core/test/identifiers/IdentifierProviderSpec.js b/platform/core/test/identifiers/IdentifierProviderSpec.js deleted file mode 100644 index c1c8da21fb..0000000000 --- a/platform/core/test/identifiers/IdentifierProviderSpec.js +++ /dev/null @@ -1,56 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/identifiers/IdentifierProvider"], - function (IdentifierProvider) { - - describe("IdentifierProvider", function () { - var defaultSpace, - provider; - - beforeEach(function () { - defaultSpace = "some-default-space"; - provider = new IdentifierProvider(defaultSpace); - }); - - it("generates unique identifiers", function () { - expect(provider.generate()) - .not.toEqual(provider.generate()); - }); - - it("allows spaces to be specified for generated identifiers", function () { - var specificSpace = "some-specific-space", - id = provider.generate(specificSpace); - expect(id).toEqual(jasmine.any(String)); - expect(provider.parse(id).getDefinedSpace()) - .toEqual(specificSpace); - }); - - it("parses identifiers using the default space", function () { - expect(provider.parse("some-unprefixed-id").getSpace()) - .toEqual(defaultSpace); - }); - - }); - } -); diff --git a/platform/core/test/identifiers/IdentifierSpec.js b/platform/core/test/identifiers/IdentifierSpec.js deleted file mode 100644 index d17afe8a27..0000000000 --- a/platform/core/test/identifiers/IdentifierSpec.js +++ /dev/null @@ -1,80 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/identifiers/Identifier"], - function (Identifier) { - - describe("A parsed domain object identifier", function () { - var id, - defaultSpace, - identifier; - - beforeEach(function () { - defaultSpace = "someDefaultSpace"; - }); - - describe("when space is encoded", function () { - var idSpace, idKey; - - beforeEach(function () { - idSpace = "a-specific-space"; - idKey = "a-specific-key"; - id = idSpace + ":" + idKey; - identifier = new Identifier(id, defaultSpace); - }); - - it("provides the encoded space", function () { - expect(identifier.getSpace()).toEqual(idSpace); - }); - - it("provides the key within that space", function () { - expect(identifier.getKey()).toEqual(idKey); - }); - - it("provides the defined space", function () { - expect(identifier.getDefinedSpace()).toEqual(idSpace); - }); - }); - - describe("when space is not encoded", function () { - beforeEach(function () { - id = "a-generic-id"; - identifier = new Identifier(id, defaultSpace); - }); - - it("provides the default space", function () { - expect(identifier.getSpace()).toEqual(defaultSpace); - }); - - it("provides the id as the key", function () { - expect(identifier.getKey()).toEqual(id); - }); - - it("provides no defined space", function () { - expect(identifier.getDefinedSpace()).toEqual(undefined); - }); - }); - - }); - } -); diff --git a/platform/core/test/models/CachingModelDecoratorSpec.js b/platform/core/test/models/CachingModelDecoratorSpec.js deleted file mode 100644 index a016b096e9..0000000000 --- a/platform/core/test/models/CachingModelDecoratorSpec.js +++ /dev/null @@ -1,157 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/CachingModelDecorator", - "../../src/models/ModelCacheService" - ], - function (CachingModelDecorator, ModelCacheService) { - - xdescribe("The caching model decorator", function () { - var mockModelService, - mockCallback, - testModels, - decorator; - - function asPromise(value) { - return (value || {}).then ? value : { - then: function (callback) { - return asPromise(callback(value)); - } - }; - } - - function fakePromise() { - var chains = [], - callbacks = []; - - return { - then: function (callback) { - var next = fakePromise(); - callbacks.push(callback); - chains.push(next); - - return next; - }, - resolve: function (value) { - callbacks.forEach(function (cb, i) { - chains[i].resolve(cb(value)); - }); - } - }; - } - - beforeEach(function () { - mockCallback = jasmine.createSpy(); - mockModelService = jasmine.createSpyObj('modelService', ['getModels']); - testModels = { - a: { someKey: "some value" }, - b: { someOtherKey: "some other value" } - }; - mockModelService.getModels.and.returnValue(asPromise(testModels)); - decorator = new CachingModelDecorator( - new ModelCacheService(), - mockModelService - ); - }); - - it("loads models from its wrapped model service", function () { - decorator.getModels(['a', 'b']).then(mockCallback); - expect(mockCallback).toHaveBeenCalledWith(testModels); - }); - - it("does not try to reload cached models", function () { - mockModelService.getModels.and.returnValue(asPromise({ a: testModels.a })); - decorator.getModels(['a']); - mockModelService.getModels.and.returnValue(asPromise(testModels)); - decorator.getModels(['a', 'b']); - expect(mockModelService.getModels).not.toHaveBeenCalledWith(['a', 'b']); - expect(mockModelService.getModels.calls.mostRecent().args[0]).toEqual(['b']); - }); - - it("does not call its wrapped model service if not needed", function () { - decorator.getModels(['a', 'b']); - expect(mockModelService.getModels.calls.count()).toEqual(1); - decorator.getModels(['a', 'b']).then(mockCallback); - expect(mockModelService.getModels.calls.count()).toEqual(1); - // Verify that we still got back our models, even though - // no new call to the wrapped service was made - expect(mockCallback).toHaveBeenCalledWith(testModels); - }); - - it("ensures a single object instance, even for multiple concurrent calls", function () { - var promiseA, promiseB; - - promiseA = fakePromise(); - promiseB = fakePromise(); - - // Issue two calls before those promises resolve - mockModelService.getModels.and.returnValue(promiseA); - decorator.getModels(['a']); - mockModelService.getModels.and.returnValue(promiseB); - decorator.getModels(['a']).then(mockCallback); - - // Then resolve those promises. Note that we're whiteboxing here - // to figure out which promises to resolve (that is, we know that - // two thens are chained after each getModels) - promiseA.resolve(testModels); - promiseB.resolve({ - a: { someNewKey: "some other value" } - }); - - // Ensure that we have a pointer-identical instance - expect(mockCallback.calls.mostRecent().args[0].a) - .toEqual({ someNewKey: "some other value" }); - expect(mockCallback.calls.mostRecent().args[0].a) - .toBe(testModels.a); - }); - - it("is robust against updating with undefined values", function () { - var promiseA, promiseB; - - promiseA = fakePromise(); - promiseB = fakePromise(); - - // Issue two calls before those promises resolve - mockModelService.getModels.and.returnValue(promiseA); - decorator.getModels(['a']); - mockModelService.getModels.and.returnValue(promiseB); - decorator.getModels(['a']).then(mockCallback); - - // Some model providers might erroneously add undefined values - // under requested keys, so handle that - promiseA.resolve({ - a: undefined - }); - promiseB.resolve({ - a: { someNewKey: "some other value" } - }); - - // Should still have gotten the model - expect(mockCallback.calls.mostRecent().args[0].a) - .toEqual({ someNewKey: "some other value" }); - }); - - }); - } -); diff --git a/platform/core/test/models/ModelAggregatorSpec.js b/platform/core/test/models/ModelAggregatorSpec.js deleted file mode 100644 index 66ecbc25f7..0000000000 --- a/platform/core/test/models/ModelAggregatorSpec.js +++ /dev/null @@ -1,84 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ModelAggregatorSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/models/ModelAggregator"], - function (ModelAggregator) { - - describe("The model aggregator", function () { - var mockQ, - mockProviders, - modelList = [ - { - "a": { someKey: "some value" }, - "b": undefined - }, - { - "b": { someOtherKey: "some other value" }, - "a": undefined - } - ], - aggregator; - - beforeEach(function () { - mockQ = jasmine.createSpyObj("$q", ["all"]); - mockProviders = modelList.map(function (models, i) { - var mockProvider = jasmine.createSpyObj( - "mockProvider" + i, - ["getModels"] - ); - mockProvider.getModels.and.returnValue(models); - - return mockProvider; - }); - - mockQ.all.and.returnValue({ - then: function (c) { - return c(modelList); - } - }); - - aggregator = new ModelAggregator(mockQ, mockProviders); - }); - - it("aggregates results promised by multiple providers", function () { - expect(aggregator.getModels(["a", "b"])).toEqual({ - "a": { someKey: "some value" }, - "b": { someOtherKey: "some other value" } - }); - }); - - it("passes ids to all aggregated providers", function () { - aggregator.getModels(["a", "b"]); - - mockProviders.forEach(function (mockProvider) { - expect(mockProvider.getModels) - .toHaveBeenCalledWith(["a", "b"]); - }); - }); - - }); - } -); diff --git a/platform/core/test/models/ModelCacheServiceSpec.js b/platform/core/test/models/ModelCacheServiceSpec.js deleted file mode 100644 index b426f695fc..0000000000 --- a/platform/core/test/models/ModelCacheServiceSpec.js +++ /dev/null @@ -1,68 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/ModelCacheService'], function (ModelCacheService) { - describe("ModelCacheService", function () { - var testIds, - testModels, - cacheService; - - beforeEach(function () { - testIds = ['a', 'b', 'c', 'd']; - testModels = testIds.reduce(function (models, id) { - models[id] = { someKey: "some value for " + id }; - - return models; - }, {}); - cacheService = new ModelCacheService(); - }); - - describe("when populated with models", function () { - beforeEach(function () { - testIds.forEach(function (id) { - cacheService.put(id, testModels[id]); - }); - }); - - it("indicates that it has these models", function () { - testIds.forEach(function (id) { - expect(cacheService.has(id)).toBe(true); - }); - }); - - it("provides all of these models", function () { - expect(cacheService.all()).toEqual(testModels); - }); - - it("allows models to be retrieved", function () { - testIds.forEach(function (id) { - expect(cacheService.get(id)).toEqual(testModels[id]); - }); - }); - - it("allows models to be removed", function () { - cacheService.remove('a'); - expect(cacheService.has('a')).toBe(false); - }); - }); - }); -}); diff --git a/platform/core/test/models/PersistedModelProviderSpec.js b/platform/core/test/models/PersistedModelProviderSpec.js deleted file mode 100644 index a0eea71d9e..0000000000 --- a/platform/core/test/models/PersistedModelProviderSpec.js +++ /dev/null @@ -1,173 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * PersistedModelProviderSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/models/PersistedModelProvider"], - function (PersistedModelProvider) { - - describe("The persisted model provider", function () { - var mockQ, - mockPersistenceService, - SPACE = "space0", - modTimes, - mockNow, - provider; - - function mockPromise(value) { - return (value || {}).then ? value : { - then: function (callback) { - return mockPromise(callback(value)); - }, - testValue: value - }; - } - - function mockAll(mockPromises) { - return mockPromise(mockPromises.map(function (p) { - return p.testValue; - })); - } - - beforeEach(function () { - modTimes = {}; - mockQ = { - when: mockPromise, - all: mockAll - }; - mockPersistenceService = jasmine.createSpyObj( - 'persistenceService', - [ - 'createObject', - 'readObject', - 'updateObject', - 'deleteObject', - 'listSpaces', - 'listObjects' - ] - ); - mockNow = jasmine.createSpy("now"); - - mockPersistenceService.readObject - .and.callFake(function (space, id) { - return mockPromise({ - space: space, - id: id, - modified: (modTimes[space] || {})[id], - persisted: 0 - }); - }); - mockPersistenceService.listSpaces - .and.returnValue(mockPromise([SPACE])); - - provider = new PersistedModelProvider( - mockPersistenceService, - mockQ, - mockNow, - SPACE - ); - }); - - it("reads object models from persistence", function () { - var models; - - provider.getModels(["a", "x", "zz"]).then(function (m) { - models = m; - }); - - expect(models).toEqual({ - a: { - space: SPACE, - id: "a", - persisted: 0, - modified: undefined - }, - x: { - space: SPACE, - id: "x", - persisted: 0, - modified: undefined - }, - zz: { - space: SPACE, - id: "zz", - persisted: 0, - modified: undefined - } - }); - }); - - it("ensures that persisted timestamps are present", function () { - var mockCallback = jasmine.createSpy("callback"), - testModels = { - a: { - modified: 123, - persisted: 1984, - name: "A" - }, - b: { - persisted: 1977, - name: "B" - }, - c: { - modified: 42, - name: "C" - }, - d: { name: "D" } - }; - - mockPersistenceService.readObject.and.callFake( - function (space, id) { - return mockPromise(testModels[id]); - } - ); - mockNow.and.returnValue(12321); - - provider.getModels(Object.keys(testModels)).then(mockCallback); - - expect(mockCallback).toHaveBeenCalledWith({ - a: { - modified: 123, - persisted: 1984, - name: "A" - }, - b: { - persisted: 1977, - name: "B" - }, - c: { - modified: 42, - persisted: 42, - name: "C" - }, - d: { - persisted: 12321, - name: "D" - } - }); - }); - - }); - } -); diff --git a/platform/core/test/models/StaticModelProviderSpec.js b/platform/core/test/models/StaticModelProviderSpec.js deleted file mode 100644 index ff0ada6469..0000000000 --- a/platform/core/test/models/StaticModelProviderSpec.js +++ /dev/null @@ -1,109 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * StaticModelProviderSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/models/StaticModelProvider"], - function (StaticModelProvider) { - - describe("The static model provider", function () { - var models = [ - { - "id": "a", - "model": { - "name": "Thing A", - "someProperty": "Some Value A" - } - }, - { - "id": "b", - "model": { - "name": "Thing B", - "someProperty": "Some Value B" - } - } - ], - mockLog, - mockQ, - provider; - - beforeEach(function () { - mockQ = jasmine.createSpyObj("$q", ["when"]); - mockLog = jasmine.createSpyObj("$log", ["error", "warn", "info", "debug"]); - provider = new StaticModelProvider(models, mockQ, mockLog); - }); - - it("provides models from extension declarations", function () { - var mockPromise = { - then: function () { - return; - } - }; - mockQ.when.and.returnValue(mockPromise); - - // Verify that we got the promise as the return value - expect(provider.getModels(["a", "b"])).toEqual(mockPromise); - - // Verify that the promise has the desired models - expect(mockQ.when.calls.count()).toEqual(1); - expect(mockQ.when.calls.mostRecent().args[0].a.name).toEqual("Thing A"); - expect(mockQ.when.calls.mostRecent().args[0].a.someProperty).toEqual("Some Value A"); - expect(mockQ.when.calls.mostRecent().args[0].b.name).toEqual("Thing B"); - expect(mockQ.when.calls.mostRecent().args[0].b.someProperty).toEqual("Some Value B"); - }); - - it("does not provide models which are not in extension declarations", function () { - provider.getModels(["c"]); - - // Verify that the promise has the desired models - expect(mockQ.when.calls.count()).toEqual(1); - expect(mockQ.when.calls.mostRecent().args[0].c).toBeUndefined(); - }); - - it("logs a warning when model definitions are malformed", function () { - // Verify precondition - expect(mockLog.warn).not.toHaveBeenCalled(); - - // Shouldn't fail with an exception - expect(new StaticModelProvider([ - { "bad": "no id" }, - { "id": "...but no model..." }, - { "model": "...and no id..." }, - { - "id": -40, - "model": {} - }, - { - "model": "should be an object", - "id": "x" - } - ], mockQ, mockLog)).toBeDefined(); - - // Should show warnings - expect(mockLog.warn.calls.count()).toEqual(5); - }); - - }); - } -); diff --git a/platform/core/test/objects/DomainObjectProviderSpec.js b/platform/core/test/objects/DomainObjectProviderSpec.js deleted file mode 100644 index f8ef1d4e6d..0000000000 --- a/platform/core/test/objects/DomainObjectProviderSpec.js +++ /dev/null @@ -1,86 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * DomainObjectProviderSpec. Created by vwoeltje on 11/6/14. - */ -define( - [ - "../../src/objects/DomainObjectProvider", - "../../src/objects/DomainObjectImpl" - ], - function (DomainObjectProvider, DomainObjectImpl) { - - describe("The domain object provider", function () { - var mockModelService, - mockInstantiate, - provider; - - function mockPromise(value) { - return (value && value.then) ? value : { - then: function (callback) { - return mockPromise(callback(value)); - }, - // Provide a synchronous way to get a value out - // of this phony promise. - testValue: value - }; - } - - beforeEach(function () { - mockModelService = jasmine.createSpyObj( - "modelService", - ["getModels"] - ); - mockInstantiate = jasmine.createSpy("instantiate"); - - mockInstantiate.and.callFake(function (model, id) { - return new DomainObjectImpl(id, model, {}); - }); - - provider = new DomainObjectProvider( - mockModelService, - mockInstantiate - ); - }); - - it("requests models from the model service", function () { - var ids = ["a", "b", "c"]; - mockModelService.getModels.and.returnValue(mockPromise({})); - provider.getObjects(ids); - expect(mockModelService.getModels).toHaveBeenCalledWith(ids); - }); - - it("instantiates objects with provided models", function () { - var ids = ["a", "b", "c"], - model = { someKey: "some value"}, - result; - mockModelService.getModels.and.returnValue(mockPromise({ a: model })); - result = provider.getObjects(ids).testValue; - expect(mockInstantiate).toHaveBeenCalledWith(model, 'a'); - expect(result.a.getId()).toEqual("a"); - expect(result.a.getModel()).toEqual(model); - }); - - }); - } -); diff --git a/platform/core/test/objects/DomainObjectSpec.js b/platform/core/test/objects/DomainObjectSpec.js deleted file mode 100644 index 4b2a445058..0000000000 --- a/platform/core/test/objects/DomainObjectSpec.js +++ /dev/null @@ -1,87 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * DomainObjectSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/objects/DomainObjectImpl"], - function (DomainObject) { - - describe("A domain object", function () { - var testId = "test id", - testModel = { someKey: "some value"}, - testCapabilities = { - "static": "some static capability", - "dynamic": function (domainObject) { - return "Dynamically generated for " - + domainObject.getId(); - }, - "invokable": { - invoke: function (arg) { - return "invoked with " + arg; - } - } - }, - domainObject; - - beforeEach(function () { - domainObject = new DomainObject( - testId, - testModel, - testCapabilities - ); - }); - - it("reports its id", function () { - expect(domainObject.getId()).toEqual(testId); - }); - - it("reports its model", function () { - expect(domainObject.getModel()).toEqual(testModel); - }); - - it("reports static capabilities", function () { - expect(domainObject.getCapability("static")) - .toEqual("some static capability"); - }); - - it("instantiates dynamic capabilities", function () { - expect(domainObject.getCapability("dynamic")) - .toEqual("Dynamically generated for test id"); - }); - - it("allows for checking for the presence of capabilities", function () { - Object.keys(testCapabilities).forEach(function (capability) { - expect(domainObject.hasCapability(capability)).toBeTruthy(); - }); - expect(domainObject.hasCapability("somethingElse")).toBeFalsy(); - }); - - it("allows for shorthand capability invocation", function () { - expect(domainObject.useCapability("invokable", "a specific value")) - .toEqual("invoked with a specific value"); - }); - - }); - } -); diff --git a/platform/core/test/services/InstantiateSpec.js b/platform/core/test/services/InstantiateSpec.js deleted file mode 100644 index 319efd6bd4..0000000000 --- a/platform/core/test/services/InstantiateSpec.js +++ /dev/null @@ -1,108 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/Instantiate"], - function (Instantiate) { - - describe("The 'instantiate' service", function () { - - var mockCapabilityService, - mockIdentifierService, - mockCapabilityConstructor, - mockCapabilityInstance, - mockCacheService, - idCounter, - testModel, - instantiate, - domainObject; - - beforeEach(function () { - idCounter = 0; - - mockCapabilityService = jasmine.createSpyObj( - 'capabilityService', - ['getCapabilities'] - ); - mockIdentifierService = jasmine.createSpyObj( - 'identifierService', - ['parse', 'generate'] - ); - mockCapabilityConstructor = jasmine.createSpy('capability'); - mockCapabilityInstance = {}; - mockCapabilityService.getCapabilities.and.returnValue({ - something: mockCapabilityConstructor - }); - mockCapabilityConstructor.and.returnValue(mockCapabilityInstance); - - mockIdentifierService.generate.and.callFake(function (space) { - return (space ? (space + ":") : "") - + "some-id-" + (idCounter += 1); - }); - - mockCacheService = jasmine.createSpyObj( - 'cacheService', - ['get', 'put', 'remove', 'all'] - ); - - testModel = { someKey: "some value" }; - - instantiate = new Instantiate( - mockCapabilityService, - mockIdentifierService, - mockCacheService - ); - domainObject = instantiate(testModel); - }); - - it("loads capabilities from the capability service", function () { - expect(mockCapabilityService.getCapabilities) - .toHaveBeenCalledWith(testModel); - }); - - it("exposes loaded capabilities from the created object", function () { - expect(domainObject.getCapability('something')) - .toBe(mockCapabilityInstance); - expect(mockCapabilityConstructor) - .toHaveBeenCalledWith(domainObject); - }); - - it("exposes the provided model", function () { - expect(domainObject.getModel()).toEqual(testModel); - }); - - it("provides unique identifiers", function () { - expect(domainObject.getId()).toEqual(jasmine.any(String)); - expect(instantiate(testModel).getId()) - .not.toEqual(domainObject.getId()); - }); - - it("caches the instantiated model", function () { - expect(mockCacheService.put).toHaveBeenCalledWith( - domainObject.getId(), - testModel - ); - }); - }); - - } -); diff --git a/platform/core/test/services/NowSpec.js b/platform/core/test/services/NowSpec.js deleted file mode 100644 index 9a07a05756..0000000000 --- a/platform/core/test/services/NowSpec.js +++ /dev/null @@ -1,47 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/Now"], - function (Now) { - - describe("The 'now' service", function () { - var now = new Now(); - - it("reports system time", function () { - var a = Date.now(), - b = now(), - c = Date.now(); - - // Clock could, in principle, tick between evaluating the - // expressions above. We can't predict or prevent this but - // want the test to be stable, so we only verify that now() - // returns a value that makes sense given a previous and - // subsequent measurement from Date.now() - expect(a <= b).toBeTruthy(); - expect(b <= c).toBeTruthy(); - expect(b).toBeDefined(); - }); - - }); - } -); diff --git a/platform/core/test/services/ThrottleSpec.js b/platform/core/test/services/ThrottleSpec.js deleted file mode 100644 index 885728492a..0000000000 --- a/platform/core/test/services/ThrottleSpec.js +++ /dev/null @@ -1,71 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/Throttle"], - function (Throttle) { - - describe("The 'throttle' service", function () { - var throttle, - mockTimeout, - mockFn, - mockPromise; - - beforeEach(function () { - mockTimeout = jasmine.createSpy("$timeout"); - mockPromise = jasmine.createSpyObj("promise", ["then"]); - mockFn = jasmine.createSpy("fn"); - mockTimeout.and.returnValue(mockPromise); - throttle = new Throttle(mockTimeout); - }); - - it("provides functions which run on a timeout", function () { - var throttled = throttle(mockFn); - // Verify precondition: Not called at throttle-time - expect(mockTimeout).not.toHaveBeenCalled(); - expect(throttled()).toEqual(mockPromise); - expect(mockFn).not.toHaveBeenCalled(); - expect(mockTimeout) - .toHaveBeenCalledWith(jasmine.any(Function), 0, false); - }); - - it("schedules only one timeout at a time", function () { - var throttled = throttle(mockFn); - throttled(); - throttled(); - throttled(); - expect(mockTimeout.calls.count()).toEqual(1); - }); - - it("schedules additional invocations after resolution", function () { - var throttled = throttle(mockFn); - throttled(); - mockTimeout.calls.mostRecent().args[0](); // Resolve timeout - throttled(); - mockTimeout.calls.mostRecent().args[0](); - throttled(); - mockTimeout.calls.mostRecent().args[0](); - expect(mockTimeout.calls.count()).toEqual(3); - }); - }); - } -); diff --git a/platform/core/test/services/TopicSpec.js b/platform/core/test/services/TopicSpec.js deleted file mode 100644 index f369def8d2..0000000000 --- a/platform/core/test/services/TopicSpec.js +++ /dev/null @@ -1,88 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/Topic"], - function (Topic) { - - describe("The 'topic' service", function () { - var topic, - mockLog, - testMessage, - mockCallback; - - beforeEach(function () { - testMessage = { someKey: "some value"}; - mockLog = jasmine.createSpyObj( - '$log', - ['error', 'warn', 'info', 'debug'] - ); - mockCallback = jasmine.createSpy('callback'); - topic = new Topic(mockLog); - }); - - it("notifies listeners on a topic", function () { - topic("abc").listen(mockCallback); - topic("abc").notify(testMessage); - expect(mockCallback).toHaveBeenCalledWith(testMessage); - }); - - it("does not notify listeners across topics", function () { - topic("abc").listen(mockCallback); - topic("xyz").notify(testMessage); - expect(mockCallback).not.toHaveBeenCalledWith(testMessage); - }); - - it("does not notify listeners after unlistening", function () { - topic("abc").listen(mockCallback)(); // Unlisten immediately - topic("abc").notify(testMessage); - expect(mockCallback).not.toHaveBeenCalledWith(testMessage); - }); - - it("provides anonymous private topics", function () { - var t1 = topic(), t2 = topic(); - - t1.listen(mockCallback); - t2.notify(testMessage); - expect(mockCallback).not.toHaveBeenCalledWith(testMessage); - t1.notify(testMessage); - expect(mockCallback).toHaveBeenCalledWith(testMessage); - }); - - it("is robust against errors thrown by listeners", function () { - var mockBadCallback = jasmine.createSpy("bad-callback"), - t = topic(); - - mockBadCallback.and.callFake(function () { - throw new Error("I'm afraid I can't do that."); - }); - - t.listen(mockBadCallback); - t.listen(mockCallback); - - t.notify(testMessage); - expect(mockCallback).toHaveBeenCalledWith(testMessage); - }); - - }); - } -); diff --git a/platform/core/test/types/MergeModelsSpec.js b/platform/core/test/types/MergeModelsSpec.js deleted file mode 100644 index 50fa400377..0000000000 --- a/platform/core/test/types/MergeModelsSpec.js +++ /dev/null @@ -1,63 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * MergeModelsSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/types/MergeModels"], - function (mergeModels) { - - describe("Model merger", function () { - it("merges models", function () { - expect(mergeModels( - { - "a": "property a", - "b": [1, 2, 3], - "c": { - x: 42, - z: [0] - }, - "d": "should be ignored" - }, - { - "b": [4], - "c": { - y: "property y", - z: ["h"] - }, - "d": "property d" - } - )).toEqual({ - "a": "property a", - "b": [1, 2, 3, 4], - "c": { - x: 42, - y: "property y", - z: [0, "h"] - }, - "d": "property d" - }); - }); - }); - } -); diff --git a/platform/core/test/types/TypeCapabilitySpec.js b/platform/core/test/types/TypeCapabilitySpec.js deleted file mode 100644 index d982377e85..0000000000 --- a/platform/core/test/types/TypeCapabilitySpec.js +++ /dev/null @@ -1,66 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * TypeCapabilitySpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/types/TypeCapability"], - function (TypeCapability) { - - describe("The type capability", function () { - var mockTypeService, - mockDomainObject, - mockType, - type; - - beforeEach(function () { - mockTypeService = jasmine.createSpyObj( - "typeService", - ["getType"] - ); - mockDomainObject = jasmine.createSpyObj( - "domainObject", - ["getId", "getModel", "getCapability"] - ); - mockType = { - someKey: "some value", - someOtherProperty: "some other property", - aThirdProperty: "a third property" - }; - - mockTypeService.getType.and.returnValue(mockType); - mockDomainObject.getModel.and.returnValue({type: "mockType"}); - - type = new TypeCapability(mockTypeService, mockDomainObject); - }); - - it("looks up an object's type from type service", function () { - expect(type.someKey).toEqual(mockType.someKey); - expect(type.someOtherProperty).toEqual(mockType.someOtherProperty); - expect(type.aThirdProperty).toEqual(mockType.aThirdProperty); - expect(mockTypeService.getType).toHaveBeenCalledWith("mockType"); - }); - - }); - } -); diff --git a/platform/core/test/types/TypeImplSpec.js b/platform/core/test/types/TypeImplSpec.js deleted file mode 100644 index bddcd9db47..0000000000 --- a/platform/core/test/types/TypeImplSpec.js +++ /dev/null @@ -1,117 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/types/TypeImpl'], - function (TypeImpl) { - - describe("Type definition wrapper", function () { - var testTypeDef, - type; - - beforeEach(function () { - testTypeDef = { - key: 'test-type', - name: 'Test Type', - description: 'A type, for testing', - cssClass: 'icon-telemetry-panel', - inherits: ['test-parent-1', 'test-parent-2'], - features: ['test-feature-1'], - properties: [{}], - model: {someKey: "some value"} - }; - type = new TypeImpl(testTypeDef); - }); - - it("exposes key from definition", function () { - expect(type.getKey()).toEqual('test-type'); - }); - - it("exposes name from definition", function () { - expect(type.getName()).toEqual('Test Type'); - }); - - it("exposes description from definition", function () { - expect(type.getDescription()).toEqual('A type, for testing'); - }); - - it("exposes CSS class from definition", function () { - expect(type.getCssClass()).toEqual('icon-telemetry-panel'); - }); - - it("exposes its underlying type definition", function () { - expect(type.getDefinition()).toEqual(testTypeDef); - }); - - it("supports instance-of checks by type key", function () { - expect(type.instanceOf('test-parent-1')).toBeTruthy(); - expect(type.instanceOf('test-parent-2')).toBeTruthy(); - expect(type.instanceOf('some-other-type')).toBeFalsy(); - }); - - it("supports instance-of checks by specific type key", function () { - expect(type.instanceOf('test-type')).toBeTruthy(); - }); - - it("supports instance-of checks by type object", function () { - expect(type.instanceOf({ - getKey: function () { - return 'test-parent-1'; - } - })).toBeTruthy(); - expect(type.instanceOf({ - getKey: function () { - return 'some-other-type'; - } - })).toBeFalsy(); - }); - - it("correctly recognizes instance-of checks upon itself", function () { - expect(type.instanceOf(type)).toBeTruthy(); - }); - - it("recognizes that all types are instances of the undefined type", function () { - expect(type.instanceOf()).toBeTruthy(); - expect(type.instanceOf({ getKey: function () {} })).toBeTruthy(); - }); - - it("allows features to be exposed", function () { - expect(type.hasFeature('test-feature-1')).toBeTruthy(); - expect(type.hasFeature('test-feature-2')).toBeFalsy(); - }); - - it("provides an initial model, if defined", function () { - expect(type.getInitialModel().someKey).toEqual("some value"); - }); - - it("provides a fresh initial model each time", function () { - var model = type.getInitialModel(); - model.someKey = "some other value"; - expect(type.getInitialModel().someKey).toEqual("some value"); - }); - - it("provides type properties", function () { - expect(type.getProperties().length).toEqual(1); - }); - }); - } -); diff --git a/platform/core/test/types/TypePropertyConversionSpec.js b/platform/core/test/types/TypePropertyConversionSpec.js deleted file mode 100644 index 67c6c4a2f7..0000000000 --- a/platform/core/test/types/TypePropertyConversionSpec.js +++ /dev/null @@ -1,65 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/types/TypePropertyConversion'], - function (TypePropertyConversion) { - - describe("Type property conversion", function () { - - it("allows non-conversion when parameter is 'identity'", function () { - var conversion = new TypePropertyConversion("identity"); - [42, "42", { a: 42 }].forEach(function (v) { - expect(conversion.toFormValue(v)).toBe(v); - expect(conversion.toModelValue(v)).toBe(v); - }); - }); - - it("allows numeric conversion", function () { - var conversion = new TypePropertyConversion("number"); - expect(conversion.toFormValue(42)).toBe("42"); - expect(conversion.toModelValue("42")).toBe(42); - }); - - it("supports array conversions", function () { - var conversion = new TypePropertyConversion("number[]"); - expect(conversion.toFormValue([42, 44]).length).toEqual(2); - expect(conversion.toFormValue([42, 44])[0]).toBe("42"); - expect(conversion.toModelValue(["11", "42"])[1]).toBe(42); - }); - - it("throws exceptions on unrecognized conversions", function () { - var caught = false; - - try { - // eslint-disable-next-line - new TypePropertyConversion("some-unknown-conversion"); - } catch (e) { - caught = true; - } - - expect(caught).toBeTruthy(); - }); - - }); - } -); diff --git a/platform/core/test/types/TypePropertySpec.js b/platform/core/test/types/TypePropertySpec.js deleted file mode 100644 index 49519bd450..0000000000 --- a/platform/core/test/types/TypePropertySpec.js +++ /dev/null @@ -1,129 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/types/TypeProperty'], - function (TypeProperty) { - - describe("Type property", function () { - - it("allows retrieval of its definition", function () { - var definition = { - key: "hello", - someOtherKey: "hm?" - }; - expect( - new TypeProperty(definition).getDefinition() - ).toEqual(definition); - }); - - it("sets properties in object models", function () { - var definition = { - key: "someKey", - property: "someProperty" - }, - model = {}, - property = new TypeProperty(definition); - property.setValue(model, "some value"); - expect(model.someProperty).toEqual("some value"); - }); - - it("gets properties from object models", function () { - var definition = { - key: "someKey", - property: "someProperty" - }, - model = { someProperty: "some value"}, - property = new TypeProperty(definition); - expect(property.getValue(model)).toEqual("some value"); - }); - - it("sets properties by path", function () { - var definition = { - key: "someKey", - property: ["some", "property"] - }, - model = {}, - property = new TypeProperty(definition); - property.setValue(model, "some value"); - expect(model.some.property).toEqual("some value"); - }); - - it("gets properties by path", function () { - var definition = { - key: "someKey", - property: ["some", "property"] - }, - model = { some: { property: "some value" } }, - property = new TypeProperty(definition); - expect(property.getValue(model)).toEqual("some value"); - }); - - it("stops looking for properties when a path is invalid", function () { - var definition = { - key: "someKey", - property: ["some", "property"] - }, - property = new TypeProperty(definition); - expect(property.getValue(undefined)).toBeUndefined(); - }); - - it("gives undefined for empty paths", function () { - var definition = { - key: "someKey", - property: [] - }, - model = { some: { property: "some value" } }, - property = new TypeProperty(definition); - expect(property.getValue(model)).toBeUndefined(); - }); - - it("provides empty arrays for values that are array-like", function () { - var definition = { - property: "someProperty", - items: [{}, {}, {}] - }, - model = {}, - property = new TypeProperty(definition); - expect(property.getValue(model)) - .toEqual([undefined, undefined, undefined]); - }); - - it("detects and ignores empty arrays on setValue", function () { - var definition = { - property: "someProperty", - items: [{}, {}, {}] - }, - model = {}, - property = new TypeProperty(definition); - - property.setValue(model, [undefined, undefined, undefined]); - expect(model.someProperty).toBeUndefined(); - - // Verify that this only happens when all are undefined - property.setValue(model, [undefined, "x", 42]); - expect(model.someProperty).toEqual([undefined, "x", 42]); - }); - - }); - } -); diff --git a/platform/core/test/types/TypeProviderSpec.js b/platform/core/test/types/TypeProviderSpec.js deleted file mode 100644 index 2aeb67069f..0000000000 --- a/platform/core/test/types/TypeProviderSpec.js +++ /dev/null @@ -1,147 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/types/TypeProvider'], - function (TypeProvider) { - - describe("Type provider", function () { - - var captured = {}, - testTypeDefinitions = [ - { - key: 'basic', - cssClass: "icon-magnify-in", - name: "Basic Type" - }, - { - key: 'multi1', - cssClass: "icon-trash", - description: "Multi1 Description", - capabilities: ['a1', 'b1'] - }, - { - key: 'multi2', - cssClass: "icon-magnify-out", - capabilities: ['a2', 'b2', 'c2'] - }, - { - key: 'single-subtype', - inherits: 'basic', - name: "Basic Subtype", - description: "A test subtype" - }, - { - key: 'multi-subtype', - inherits: ['multi1', 'multi2'], - name: "Multi-parent Subtype", - capabilities: ['a3'] - }, - { - name: "Default" - } - ], - provider; - - beforeEach(function () { - captured = {}; - provider = new TypeProvider(testTypeDefinitions); - }); - - it("looks up non-inherited types by name", function () { - captured.type = provider.getType('basic'); - - expect(captured.type.getCssClass()).toEqual("icon-magnify-in"); - expect(captured.type.getName()).toEqual("Basic Type"); - expect(captured.type.getDescription()).toBeUndefined(); - }); - - it("supports single inheritance", function () { - captured.type = provider.getType('single-subtype'); - - expect(captured.type.getCssClass()).toEqual("icon-magnify-in"); - expect(captured.type.getName()).toEqual("Basic Subtype"); - expect(captured.type.getDescription()).toEqual("A test subtype"); - }); - - it("supports multiple inheritance", function () { - captured.type = provider.getType('multi-subtype'); - - expect(captured.type.getCssClass()).toEqual("icon-magnify-out"); - expect(captured.type.getName()).toEqual("Multi-parent Subtype"); - expect(captured.type.getDescription()).toEqual("Multi1 Description"); - }); - - it("concatenates capabilities in order", function () { - captured.type = provider.getType('multi-subtype'); - - expect(captured.type.getDefinition().capabilities).toEqual( - ['a1', 'b1', 'a2', 'b2', 'c2', 'a3'] - ); - }); - - it("allows lookup of the undefined type", function () { - captured.type = provider.getType(undefined); - - expect(captured.type.getName()).toEqual("Default"); - }); - - it("concatenates capabilities of all undefined types", function () { - captured.type = new TypeProvider( - testTypeDefinitions.concat([ - { capabilities: ['a', 'b', 'c'] }, - { capabilities: ['x', 'y', 'z'] } - ]) - ).getType(undefined); - - expect(captured.type.getDefinition().capabilities).toEqual( - ['a', 'b', 'c', 'x', 'y', 'z'] - ); - - }); - - it("includes capabilities from undefined type in all types", function () { - captured.type = new TypeProvider( - testTypeDefinitions.concat([ - { capabilities: ['a', 'b', 'c'] }, - { capabilities: ['x', 'y', 'z'] } - ]) - ).getType('multi-subtype'); - - expect(captured.type.getDefinition().capabilities).toEqual( - ['a', 'b', 'c', 'x', 'y', 'z', 'a1', 'b1', 'a2', 'b2', 'c2', 'a3'] - ); - }); - - it("allows types to be listed", function () { - captured.types = provider.listTypes(); - - expect(captured.types.length).toEqual( - testTypeDefinitions.filter(function (t) { - return t.key; - }).length - ); - }); - - }); - } -); diff --git a/platform/core/test/views/ViewCapabilitySpec.js b/platform/core/test/views/ViewCapabilitySpec.js deleted file mode 100644 index e4df086cc2..0000000000 --- a/platform/core/test/views/ViewCapabilitySpec.js +++ /dev/null @@ -1,58 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ViewCapabilitySpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/views/ViewCapability"], - function (ViewCapability) { - - describe("A view capability", function () { - var mockViewService, - mockDomainObject, - views = [{key: "someView"}], - view; - - beforeEach(function () { - mockViewService = jasmine.createSpyObj( - "viewService", - ["getViews"] - ); - mockDomainObject = jasmine.createSpyObj( - "domainObject", - ["getId", "getModel", "getCapability"] - ); - mockViewService.getViews.and.returnValue(views); - view = new ViewCapability(mockViewService, mockDomainObject); - }); - - it("issues invocations to the view service", function () { - expect(view.invoke()).toEqual(views); - expect(mockViewService.getViews).toHaveBeenCalledWith( - mockDomainObject - ); - }); - - }); - } -); diff --git a/platform/core/test/views/ViewProviderSpec.js b/platform/core/test/views/ViewProviderSpec.js deleted file mode 100644 index 2244aeff8a..0000000000 --- a/platform/core/test/views/ViewProviderSpec.js +++ /dev/null @@ -1,167 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ViewProviderSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/views/ViewProvider"], - function (ViewProvider) { - - describe("The view provider", function () { - var viewA = { - key: "a" - }, - viewB = { - key: "b", - needs: ["someCapability"] - }, - viewC = { - key: "c", - needs: ["someCapability"], - delegation: true - }, - capabilities = {}, - delegates = {}, - delegation, - mockDomainObject = {}, - mockLog, - provider; - - beforeEach(function () { - // Simulate the expected API - mockDomainObject.hasCapability = function (c) { - return capabilities[c] !== undefined; - }; - - mockDomainObject.getCapability = function (c) { - return capabilities[c]; - }; - - mockDomainObject.useCapability = function (c, v) { - return capabilities[c] && capabilities[c].invoke(v); - }; - - mockLog = jasmine.createSpyObj("$log", ["warn", "info", "debug"]); - - capabilities = {}; - delegates = {}; - - delegation = { - doesDelegateCapability: function (c) { - return delegates[c] !== undefined; - } - }; - - provider = new ViewProvider([viewA, viewB, viewC], mockLog); - }); - - it("reports views provided as extensions", function () { - capabilities.someCapability = true; - expect(provider.getViews(mockDomainObject)) - .toEqual([viewA, viewB, viewC]); - }); - - it("filters views by needed capabilities", function () { - //capabilities.someCapability = true; - expect(provider.getViews(mockDomainObject)) - .toEqual([viewA]); - }); - - it("allows delegation of needed capabilities when specified", function () { - //capabilities.someCapability = true; - capabilities.delegation = delegation; - delegates.someCapability = true; - expect(provider.getViews(mockDomainObject)) - .toEqual([viewA, viewC]); - }); - - it("warns if keys are omitted from views", function () { - // Verify that initial construction issued no warning - expect(mockLog.warn).not.toHaveBeenCalled(); - // Recreate with no keys; that view should be filtered out - expect( - new ViewProvider( - [viewA, { some: "bad view" }], - mockLog - ).getViews(mockDomainObject) - ).toEqual([viewA]); - // We should have also received a warning, to support debugging - expect(mockLog.warn).toHaveBeenCalledWith(jasmine.any(String)); - }); - - it("restricts typed views to matching types", function () { - var testType = "testType", - testView = { - key: "x", - type: testType - }, - viewProvider = new ViewProvider([testView], mockLog); - - // Include a "type" capability - capabilities.type = jasmine.createSpyObj( - "type", - ["instanceOf", "invoke", "getDefinition"] - ); - capabilities.type.invoke.and.returnValue(capabilities.type); - - // Should be included when types match - capabilities.type.instanceOf.and.returnValue(true); - expect(viewProvider.getViews(mockDomainObject)) - .toEqual([testView]); - expect(capabilities.type.instanceOf) - .toHaveBeenCalledWith(testType); - - // ...but not when they don't - capabilities.type.instanceOf.and.returnValue(false); - expect(viewProvider.getViews(mockDomainObject)) - .toEqual([]); - - }); - - it("enforces view restrictions from types", function () { - var testView = { key: "x" }, - viewProvider = new ViewProvider([testView], mockLog); - - // Include a "type" capability - capabilities.type = jasmine.createSpyObj( - "type", - ["instanceOf", "invoke", "getDefinition"] - ); - capabilities.type.invoke.and.returnValue(capabilities.type); - - // Should be included when view keys match - capabilities.type.getDefinition - .and.returnValue({ views: [testView.key]}); - expect(viewProvider.getViews(mockDomainObject)) - .toEqual([testView]); - - // ...but not when they don't - capabilities.type.getDefinition - .and.returnValue({ views: ["somethingElse"]}); - expect(viewProvider.getViews(mockDomainObject)) - .toEqual([]); - }); - - }); - } -); diff --git a/platform/data/README.md b/platform/data/README.md deleted file mode 100644 index dfcf85e2c9..0000000000 --- a/platform/data/README.md +++ /dev/null @@ -1,2 +0,0 @@ -This bundle is responsible for introducing a reusable infrastructure -and set of APIs for using time-series data in Open MCT. diff --git a/platform/entanglement/README.md b/platform/entanglement/README.md deleted file mode 100644 index aaf517decf..0000000000 --- a/platform/entanglement/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Entanglement - -Entanglement is the process of moving, copying, and linking domain objects -in such a way that their relationships are impossible to discern. - -This bundle provides move, copy, and link functionality. Achieving a state of -entanglement is left up to the end user. - - -## Services implement logic - -Each method (move, copy, link) is implemented as a service, and each service -provides two functions: `validate` and `perform`. - -`validate(object, parentCandidate)` returns true if the `object` can be -move/copy/linked into the `parentCandidate`'s composition. - -`perform(object, parentObject)` move/copy/links the `object` into the -`parentObject`'s composition. - -## Actions implement user interactions - -Actions are used to expose move/copy/link to the user. They prompt for input -where necessary, and complete the actions. diff --git a/platform/entanglement/bundle.js b/platform/entanglement/bundle.js deleted file mode 100644 index 35cf92245b..0000000000 --- a/platform/entanglement/bundle.js +++ /dev/null @@ -1,124 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/SetPrimaryLocationAction", - "./src/services/LocatingCreationDecorator", - "./src/services/LocatingObjectDecorator", - "./src/policies/CopyPolicy", - "./src/policies/CrossSpacePolicy", - "./src/capabilities/LocationCapability", - "./src/services/CopyService", - "./src/services/LocationService" -], function ( - SetPrimaryLocationAction, - LocatingCreationDecorator, - LocatingObjectDecorator, - CopyPolicy, - CrossSpacePolicy, - LocationCapability, - CopyService, - LocationService -) { - - return { - name: "platform/entanglement", - definition: { - "name": "Entanglement", - "description": "Tools to assist you in entangling the world of WARP.", - "configuration": {}, - "extensions": { - "actions": [ - { - "key": "locate", - "name": "Set Primary Location", - "description": "Set a domain object's primary location.", - "cssClass": "", - "category": "contextual", - "implementation": SetPrimaryLocationAction - } - ], - "components": [ - { - "type": "decorator", - "provides": "creationService", - "implementation": LocatingCreationDecorator - }, - { - "type": "decorator", - "provides": "objectService", - "implementation": LocatingObjectDecorator, - "depends": [ - "$q", - "$log" - ] - } - ], - "policies": [ - { - "category": "action", - "implementation": CrossSpacePolicy - }, - { - "category": "action", - "implementation": CopyPolicy - } - ], - "capabilities": [ - { - "key": "location", - "name": "Location Capability", - "description": "Provides a capability for retrieving the location of an object based upon it's context.", - "implementation": LocationCapability, - "depends": [ - "$q", - "$injector" - ] - } - ], - "services": [ - { - "key": "copyService", - "name": "Copy Service", - "description": "Provides a service for copying objects", - "implementation": CopyService, - "depends": [ - "$q", - "policyService", - "openmct" - ] - }, - { - "key": "locationService", - "name": "Location Service", - "description": "Provides a service for prompting a user for locations.", - "implementation": LocationService, - "depends": [ - "dialogService" - ] - } - ], - "licenses": [] - } - } - }; -}); diff --git a/platform/entanglement/src/actions/AbstractComposeAction.js b/platform/entanglement/src/actions/AbstractComposeAction.js deleted file mode 100644 index a04438f90a..0000000000 --- a/platform/entanglement/src/actions/AbstractComposeAction.js +++ /dev/null @@ -1,163 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['./CancelError'], - function (CancelError) { - var CANCEL_MESSAGE = "User cancelled location selection."; - - /** - * Common interface exposed by services which support move, copy, - * and link actions. - * @interface platform/entanglement.AbstractComposeService - * @private - */ - /** - * Change the composition of the specified objects. Note that this - * should only be invoked after successfully validating. - * - * @param {DomainObject} domainObject the domain object to - * move, copy, or link. - * @param {DomainObject} parent the domain object whose composition - * will be changed to contain the domainObject (or its duplicate) - * @returns {Promise} A promise that is fulfilled when the - * duplicate operation has completed. - * @method platform/entanglement.AbstractComposeService#perform - */ - /** - * Check if this composition change is valid for these objects. - * - * @param {DomainObject} domainObject the domain object to - * move, copy, or link. - * @param {DomainObject} parent the domain object whose composition - * will be changed to contain the domainObject (or its duplicate) - * @returns {boolean} true if this composition change is allowed - * @method platform/entanglement.AbstractComposeService#validate - */ - - /** - * Template class for Move, Copy, and Link actions. - * - * @implements {Action} - * @constructor - * @private - * @memberof platform/entanglement - * @param {PolicyService} policyService the policy service to use to - * verify that variants of this action are allowed - * @param {platform/entanglement.LocationService} locationService a - * service to request destinations from the user - * @param {platform/entanglement.AbstractComposeService} composeService - * a service which will handle actual changes to composition - * @param {ActionContext} the context in which the action will be performed - * @param {string} verb the verb to display for the action (e.g. "Move") - * @param {string} [suffix] a string to display in the dialog title; - * default is "to a new location" - */ - function AbstractComposeAction( - policyService, - locationService, - composeService, - context, - verb, - suffix - ) { - if (context.selectedObject) { - this.newParent = context.domainObject; - this.object = context.selectedObject; - } else { - this.object = context.domainObject; - } - - this.currentParent = this.object - .getCapability('context') - .getParent(); - - this.context = context; - this.policyService = policyService; - this.locationService = locationService; - this.composeService = composeService; - this.verb = verb || "Compose"; - this.suffix = suffix || "To a New Location"; - } - - AbstractComposeAction.prototype.cloneContext = function () { - var clone = {}, original = this.context; - Object.keys(original).forEach(function (k) { - clone[k] = original[k]; - }); - - return clone; - }; - - AbstractComposeAction.prototype.perform = function () { - var dialogTitle, - label, - validateLocation, - self = this, - locationService = this.locationService, - composeService = this.composeService, - currentParent = this.currentParent, - newParent = this.newParent, - object = this.object; - - if (newParent) { - return composeService.perform(object, newParent); - } - - dialogTitle = [this.verb, object.getModel().name, this.suffix] - .join(" "); - - label = this.verb + " To"; - - validateLocation = function (newParentObj) { - var newContext = self.cloneContext(); - newContext.selectedObject = object; - newContext.domainObject = newParentObj; - - return composeService.validate(object, newParentObj) - && self.policyService.allow("action", self, newContext); - }; - - return locationService.getLocationFromUser( - dialogTitle, - label, - validateLocation, - currentParent - ).then(function (newParentObj) { - return composeService.perform(object, newParentObj); - }, function () { - return Promise.reject(new CancelError(CANCEL_MESSAGE)); - }.bind(this)); - }; - - AbstractComposeAction.appliesTo = function (context) { - var applicableObject = - context.selectedObject || context.domainObject; - - return Boolean(applicableObject - && applicableObject.hasCapability('context')); - }; - - return AbstractComposeAction; - } -); - diff --git a/platform/entanglement/src/actions/CancelError.js b/platform/entanglement/src/actions/CancelError.js deleted file mode 100644 index f28db7d003..0000000000 --- a/platform/entanglement/src/actions/CancelError.js +++ /dev/null @@ -1,32 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - function CancelError() { - Error.apply(this, arguments); - this.name = CancelError; - } - - CancelError.prototype = Object.create(Error.prototype); - - return CancelError; -}); diff --git a/platform/entanglement/src/actions/SetPrimaryLocationAction.js b/platform/entanglement/src/actions/SetPrimaryLocationAction.js deleted file mode 100644 index ef1b8ab4fb..0000000000 --- a/platform/entanglement/src/actions/SetPrimaryLocationAction.js +++ /dev/null @@ -1,66 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 "Set Primary Location" action, which sets a - * location property for objects to match their contextual - * location. - * - * @implements {Action} - * @constructor - * @private - * @memberof platform/entanglement - * @param {ActionContext} context the context in which the action - * will be performed - */ - function SetPrimaryLocationAction(context) { - this.domainObject = context.domainObject; - } - - SetPrimaryLocationAction.prototype.perform = function () { - var location = this.domainObject.getCapability('location'); - - return location.setPrimaryLocation( - location.getContextualLocation() - ); - }; - - SetPrimaryLocationAction.appliesTo = function (context, view, openmct) { - let domainObject = (context || {}).domainObject; - - if (!domainObject || (domainObject.model && domainObject.model.locked)) { - return false; - } - - let isPersistable = openmct.objects.isPersistable(domainObject.id); - - return isPersistable && domainObject.hasCapability("location") - && (domainObject.getModel().location === undefined); - }; - - return SetPrimaryLocationAction; - } -); - diff --git a/platform/entanglement/src/capabilities/LocationCapability.js b/platform/entanglement/src/capabilities/LocationCapability.js deleted file mode 100644 index 3fc0fee017..0000000000 --- a/platform/entanglement/src/capabilities/LocationCapability.js +++ /dev/null @@ -1,128 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The location capability allows a domain object to know its current - * parent, and also know its original parent. When a domain object's - * current parent is its original parent, the object is considered an - * original, otherwise it's a link. - * - * @constructor - */ - function LocationCapability($q, $injector, domainObject) { - this.domainObject = domainObject; - this.$q = $q; - this.$injector = $injector; - - return this; - } - - /** - * Get an instance of this domain object in its original location. - * - * @returns {Promise.} a promise for the original - * instance of this domain object - */ - LocationCapability.prototype.getOriginal = function () { - var id; - - if (this.isOriginal()) { - return this.$q.when(this.domainObject); - } - - id = this.domainObject.getId(); - - this.objectService = - this.objectService || this.$injector.get("objectService"); - - // Assume that an object will be correctly contextualized when - // loaded directly from the object service; this is true - // so long as LocatingObjectDecorator is present, and that - // decorator is also contained in this bundle. - return this.objectService.getObjects([id]) - .then(function (objects) { - return objects[id]; - }); - }; - - /** - * Set the primary location (the parent id) of the current domain - * object. - * - * @param {String} location the primary location to persist. - * @returns {Promise} a promise that is resolved when the operation - * completes. - */ - LocationCapability.prototype.setPrimaryLocation = function (location) { - return this.domainObject.useCapability( - 'mutation', - function (model) { - model.location = location; - } - ); - }; - - /** - * Returns the contextual location of the current domain object. Only - * valid for domain objects that have a context capability. - * - * @returns {String} the contextual location of the object; the id of - * its parent. - */ - LocationCapability.prototype.getContextualLocation = function () { - var context = this.domainObject.getCapability("context"); - - if (!context) { - return; - } - - return context.getParent().getId(); - }; - - /** - * Returns true if the domainObject is a link, false if it's an - * original. - * - * @returns {Boolean} - */ - LocationCapability.prototype.isLink = function () { - var model = this.domainObject.getModel(); - - return model.location !== this.getContextualLocation(); - }; - - /** - * Returns true if the domainObject is an original, false if it's a - * link. - * - * @returns {Boolean} - */ - LocationCapability.prototype.isOriginal = function () { - return !this.isLink(); - }; - - return LocationCapability; - } -); diff --git a/platform/entanglement/src/policies/CopyPolicy.js b/platform/entanglement/src/policies/CopyPolicy.js deleted file mode 100644 index 24f71d7527..0000000000 --- a/platform/entanglement/src/policies/CopyPolicy.js +++ /dev/null @@ -1,56 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Disallow duplication when the object to be duplicated is not - * creatable. - * @constructor - * @implements {Policy} - * @memberof platform/entanglement - */ - function CopyPolicy() { - } - - function allowCreation(domainObject) { - var type = domainObject && domainObject.getCapability('type'); - - return Boolean(type && type.hasFeature('creation')); - } - - function selectedObject(context) { - return context.selectedObject || context.domainObject; - } - - CopyPolicy.prototype.allow = function (action, context) { - var key = action.getMetadata().key; - - if (key === 'copy') { - return allowCreation(selectedObject(context)); - } - - return true; - }; - - return CopyPolicy; -}); diff --git a/platform/entanglement/src/policies/CrossSpacePolicy.js b/platform/entanglement/src/policies/CrossSpacePolicy.js deleted file mode 100644 index 2519dcf5d1..0000000000 --- a/platform/entanglement/src/policies/CrossSpacePolicy.js +++ /dev/null @@ -1,69 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - var DISALLOWED_ACTIONS = ["move"]; - - /** - * This policy prevents performing move/copy/link actions across - * different persistence spaces (e.g. linking to an object in - * a private space from an object in a public space.) - * @memberof {platform/entanglement} - * @constructor - * @implements {Policy} - */ - function CrossSpacePolicy() { - } - - function lookupSpace(domainObject) { - var persistence = domainObject - && domainObject.getCapability("persistence"); - - return persistence && persistence.getSpace(); - } - - function isCrossSpace(context) { - var domainObject = context.domainObject, - selectedObject = context.selectedObject; - - return selectedObject !== undefined - && domainObject !== undefined - && lookupSpace(domainObject) !== lookupSpace(selectedObject); - } - - CrossSpacePolicy.prototype.allow = function (action, context) { - var key = action.getMetadata().key; - - if (DISALLOWED_ACTIONS.indexOf(key) !== -1) { - return !isCrossSpace(context); - } - - return true; - }; - - return CrossSpacePolicy; - - } -); diff --git a/platform/entanglement/src/services/CopyService.js b/platform/entanglement/src/services/CopyService.js deleted file mode 100644 index 0a887224c5..0000000000 --- a/platform/entanglement/src/services/CopyService.js +++ /dev/null @@ -1,109 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ["./CopyTask"], - function (CopyTask) { - - /** - * CopyService provides an interface for deep copying objects from one - * location to another. It also provides a method for determining if - * an object can be copied to a specific location. - * @constructor - * @memberof platform/entanglement - * @implements {platform/entanglement.AbstractComposeService} - */ - function CopyService($q, policyService, openmct) { - this.$q = $q; - this.policyService = policyService; - this.openmct = openmct; - } - - CopyService.prototype.validate = function (object, parentCandidate) { - if (!parentCandidate || !parentCandidate.getId) { - return false; - } - - if (parentCandidate.getId() === object.getId()) { - return false; - } - - return this.openmct.composition.checkPolicy(parentCandidate.useCapability('adapter'), object.useCapability('adapter')); - }; - - /** - * A function used to check if a domain object should be cloned - * or not. - * @callback platform/entanglement.CopyService~filter - * @param {DomainObject} domainObject the object to be cloned - * @returns {boolean} true if the object should be cloned; false - * if it should be linked - */ - - /** - * Creates a duplicate of the object tree starting at domainObject to - * the new parent specified. - * - * Any domain objects which cannot be created will not be cloned; - * instead, these will appear as links. If a filtering function - * is provided, any objects which fail that check will also be - * linked instead of cloned - * - * @param {DomainObject} domainObject the object to duplicate - * @param {DomainObject} parent the destination for the clone - * @param {platform/entanglement.CopyService~filter} [filter] - * an optional function used to filter out objects from - * the cloning process - * @returns a promise that will be completed with the clone of - * domainObject when the duplication is successful. - */ - CopyService.prototype.perform = function (domainObject, parent, filter) { - var policyService = this.policyService; - - // Combines caller-provided filter (if any) with the - // baseline behavior of respecting creation policy. - function filterWithPolicy(domainObj) { - return (!filter || filter(domainObj)) - && policyService.allow( - "creation", - domainObj.getCapability("type") - ); - } - - if (this.validate(domainObject, parent)) { - return new CopyTask( - domainObject, - parent, - filterWithPolicy, - this.$q - ).perform(); - } else { - throw new Error( - "Tried to copy objects without validating first." - ); - } - }; - - return CopyService; - } -); - diff --git a/platform/entanglement/src/services/CopyTask.js b/platform/entanglement/src/services/CopyTask.js deleted file mode 100644 index 7117c1d67d..0000000000 --- a/platform/entanglement/src/services/CopyTask.js +++ /dev/null @@ -1,276 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * This class encapsulates the process of copying a domain object - * and all of its children. - * - * @param {DomainObject} domainObject The object to copy - * @param {DomainObject} parent The new location of the cloned object tree - * @param {platform/entanglement.CopyService~filter} filter - * a function used to filter out objects from - * the cloning process - * @param $q Angular's $q, for promises - * @constructor - */ - function CopyTask(domainObject, parent, filter, $q) { - this.domainObject = domainObject; - this.parent = parent; - this.firstClone = undefined; - this.$q = $q; - this.deferred = undefined; - this.filter = filter; - this.persisted = 0; - this.clones = []; - this.idMap = {}; - } - - function composeChild(child, parent, setLocation) { - //Once copied, associate each cloned - // composee with its parent clone - - parent.getModel().composition.push(child.getId()); - - //If a location is not specified, set it. - if (setLocation && child.getModel().location === undefined) { - child.getModel().location = parent.getId(); - } - - return child; - } - - function cloneObjectModel(objectModel) { - var clone = JSON.parse(JSON.stringify(objectModel)); - - /** - * Reset certain fields. - */ - //If has a composition, set it to an empty array. Will be - // recomposed later with the ids of its cloned children. - if (clone.composition) { - //Important to set it to an empty array here, otherwise - // hasCapability("composition") returns false; - clone.composition = []; - } - - delete clone.persisted; - delete clone.modified; - delete clone.location; - - return clone; - } - - /** - * Will persist a list of {@link objectClones}. It will persist all - * simultaneously, irrespective of order in the list. This may - * result in automatic request batching by the browser. - */ - function persistObjects(self) { - return self.$q.all(self.clones.map(function (clone) { - return clone.getCapability("persistence").persist().then(function () { - self.deferred.notify({ - phase: "copying", - totalObjects: self.clones.length, - processed: ++self.persisted - }); - }); - })).then(function () { - return self; - }); - } - - /** - * Will add a list of clones to the specified parent's composition - */ - function addClonesToParent(self) { - return self.parent.getCapability("composition") - .add(self.firstClone) - .then(function (addedClone) { - return self.parent.getCapability("persistence").persist() - .then(function () { - return addedClone; - }); - }); - } - - /** - * Update identifiers in a cloned object model (or part of - * a cloned object model) to reflect new identifiers after - * copying. - * @private - */ - CopyTask.prototype.rewriteIdentifiers = function (obj, idMap) { - function lookupValue(value) { - return (typeof value === 'string' && idMap[value]) || value; - } - - if (Array.isArray(obj)) { - obj.forEach(function (value, index) { - obj[index] = lookupValue(value); - this.rewriteIdentifiers(obj[index], idMap); - }, this); - } else if (obj && typeof obj === 'object') { - Object.keys(obj).forEach(function (key) { - var value = obj[key]; - obj[key] = lookupValue(value); - if (idMap[key]) { - delete obj[key]; - obj[idMap[key]] = value; - } - - this.rewriteIdentifiers(value, idMap); - }, this); - } - }; - - /** - * Given an array of objects composed by a parent, clone them, then - * add them to the parent. - * @private - * @returns {*} - */ - CopyTask.prototype.copyComposees = function (composees, clonedParent, originalParent) { - var self = this, - idMap = {}; - - return (composees || []).reduce(function (promise, originalComposee) { - //If the composee is composed of other - // objects, chain a promise.. - return promise.then(function () { - // ...to recursively copy it (and its children) - return self.copy(originalComposee, originalParent).then(function (clonedComposee) { - //Map the original composee's ID to that of its - // clone so that we can replace any references to it - // in the parent - idMap[originalComposee.getId()] = clonedComposee.getId(); - - //Compose the child within its parent. Cloned - // objects will need to also have their location - // set, however linked objects will not. - return composeChild(clonedComposee, clonedParent, clonedComposee !== originalComposee); - }); - }); - }, self.$q.when(undefined) - ).then(function () { - //Replace any references in the cloned parent to - // contained objects that have been composed with the - // Ids of the clones - self.rewriteIdentifiers(clonedParent.getModel(), idMap); - - //Add the clone to the list of clones that will - //be returned by this function - self.clones.push(clonedParent); - - return clonedParent; - }); - }; - - /** - * A recursive function that will perform a bottom-up copy of - * the object tree with originalObject at the root. Recurses to - * the farthest leaf, then works its way back up again, - * cloning objects, and composing them with their child clones - * as it goes - * @private - * @returns {DomainObject} If the type of the original object allows for - * duplication, then a duplicate of the object, otherwise the object - * itself (to allow linking to non duplicatable objects). - */ - CopyTask.prototype.copy = function (originalObject) { - var self = this, - clone; - - //Check if the type of the object being copied allows for - // creation of new instances. If it does not, then a link to the - // original will be created instead. - if (this.filter(originalObject)) { - //create a new clone of the original object. Use the - // creation capability of the targetParent to create the - // new clone. This will ensure that the correct persistence - // space is used. - clone = this.parent.useCapability("instantiation", cloneObjectModel(originalObject.getModel())); - - //Iterate through child tree - return this.$q.when(originalObject.useCapability('composition')).then(function (composees) { - self.deferred.notify({phase: "preparing"}); - - //Duplicate the object's children, and their children, and - // so on down to the leaf nodes of the tree. - //If it is a link, don't both with children - return self.copyComposees(composees, clone, originalObject); - }); - } else { - //Creating a link, no need to iterate children - return self.$q.when(originalObject); - } - - }; - - /** - * Will build a graph of an object and all of its child objects in - * memory - * @private - * @param domainObject The original object to be copied - * @param parent The parent of the original object to be copied - * @returns {Promise} resolved with an array of clones of the models - * of the object tree being copied. Copying is done in a bottom-up - * fashion, so that the last member in the array is a clone of the model - * object being copied. The clones are all full composed with - * references to their own children. - */ - CopyTask.prototype.buildCopyPlan = function () { - var self = this; - - return this.copy(self.domainObject, self.parent).then(function (domainObjectClone) { - if (domainObjectClone !== self.domainObject) { - domainObjectClone.getModel().location = self.parent.getId(); - } - - self.firstClone = domainObjectClone; - - return self; - }); - }; - - /** - * Execute the copy task with the objects provided in the constructor. - * @returns {promise} Which will resolve with a clone of the object - * once complete. - */ - CopyTask.prototype.perform = function () { - this.deferred = this.$q.defer(); - - this.buildCopyPlan() - .then(persistObjects) - .then(addClonesToParent) - .then(this.deferred.resolve, this.deferred.reject); - - return this.deferred.promise; - }; - - return CopyTask; - } -); diff --git a/platform/entanglement/src/services/LocatingCreationDecorator.js b/platform/entanglement/src/services/LocatingCreationDecorator.js deleted file mode 100644 index 979f9e034a..0000000000 --- a/platform/entanglement/src/services/LocatingCreationDecorator.js +++ /dev/null @@ -1,47 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Adds a `location` property to newly-created domain objects. - * @constructor - * @augments {platform/commonUI/browse.CreationService} - * @memberof platform/entanglement - */ - function LocatingCreationDecorator(creationService) { - this.creationService = creationService; - } - - LocatingCreationDecorator.prototype.createObject = function (model, parent) { - if (parent && parent.getId) { - model.location = parent.getId(); - } - - return this.creationService.createObject(model, parent); - }; - - return LocatingCreationDecorator; - } -); - diff --git a/platform/entanglement/src/services/LocatingObjectDecorator.js b/platform/entanglement/src/services/LocatingObjectDecorator.js deleted file mode 100644 index 69c18a6464..0000000000 --- a/platform/entanglement/src/services/LocatingObjectDecorator.js +++ /dev/null @@ -1,95 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['../../../core/src/capabilities/ContextualDomainObject'], - function (ContextualDomainObject) { - - /** - * Ensures that domain objects are loaded with a context capability - * that reflects their location. - * @constructor - * @implements {ObjectService} - * @memberof platform/entanglement - */ - function LocatingObjectDecorator($q, $log, objectService) { - this.$log = $log; - this.objectService = objectService; - this.$q = $q; - } - - LocatingObjectDecorator.prototype.getObjects = function (ids, abortSignal) { - var $q = this.$q, - $log = this.$log, - objectService = this.objectService, - result = {}; - - // Load a single object using location to establish a context - function loadObjectInContext(id, exclude) { - function attachContext(objects) { - var domainObject = (objects || {})[id], - model = domainObject && domainObject.getModel(), - location = (model || {}).location; - - // If no location is defined, we can't look up a context. - if (!location) { - return domainObject; - } - - // Avoid looping indefinitely on cyclical locations - if (exclude[id]) { - $log.warn([ - "LocatingObjectDecorator detected a cycle", - "while attempted to define a context for", - id + ";", - "no context will be added and unexpected behavior", - "may follow." - ].join(" ")); - - return domainObject; - } - - // Record that we've visited this ID to detect cycles. - exclude[id] = true; - - // Do the recursive step to get the parent... - return loadObjectInContext(location, exclude) - .then(function (parent) { - // ...and then contextualize with it! - return new ContextualDomainObject(domainObject, parent); - }); - } - - return objectService.getObjects([id], abortSignal).then(attachContext); - } - - ids.forEach(function (id) { - result[id] = loadObjectInContext(id, {}); - }); - - return $q.all(result); - }; - - return LocatingObjectDecorator; - } -); - diff --git a/platform/entanglement/src/services/LocationService.js b/platform/entanglement/src/services/LocationService.js deleted file mode 100644 index 58b2d4901a..0000000000 --- a/platform/entanglement/src/services/LocationService.js +++ /dev/null @@ -1,90 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -/** - * This bundle implements actions which control the location of objects - * (move, copy, link.) - * @namespace platform/entanglement - */ -define( - function () { - - /** - * The LocationService allows for easily prompting the user for a - * location in the root tree. - * @constructor - * @memberof platform/entanglement - */ - function LocationService(dialogService) { - return { - /** Prompt the user to select a location. Returns a promise - * that is resolved with a domainObject representing the - * location selected by the user. - * - * @param {string} title - title of location dialog - * @param {string} label - label for location input field - * @param {function} validate - function that validates - * selections. - * @param {domainObject} initialLocation - tree location to - * display at start - * @returns {Promise} promise for a domain object. - * @memberof platform/entanglement.LocationService# - */ - getLocationFromUser: function (title, label, validate, initialLocation) { - var formStructure, - formState; - - formStructure = { - sections: [ - { - name: 'Location', - cssClass: "grows", - rows: [ - { - name: label, - control: "locator", - validate: validate, - key: 'location' - } - ] - } - ], - name: title - }; - - formState = { - location: initialLocation - }; - - return dialogService - .getUserInput(formStructure, formState) - .then(function (userFormState) { - return userFormState.location; - }); - } - }; - } - - return LocationService; - } -); - diff --git a/platform/entanglement/test/ControlledPromise.js b/platform/entanglement/test/ControlledPromise.js deleted file mode 100644 index ff2a0b1f15..0000000000 --- a/platform/entanglement/test/ControlledPromise.js +++ /dev/null @@ -1,97 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 instrumented promise implementation for better control of promises - * during tests. - * - */ - function ControlledPromise() { - this.resolveHandlers = []; - this.rejectHandlers = []; - spyOn(this, 'then').and.callThrough(); - } - - /** - * Resolve the promise, passing the supplied value to all resolve - * handlers. - */ - ControlledPromise.prototype.resolve = function (value) { - this.resolveHandlers.forEach(function (handler) { - handler(value); - }); - }; - - /** - * Reject the promise, passing the supplied value to all rejection - * handlers. - */ - ControlledPromise.prototype.reject = function (value) { - this.rejectHandlers.forEach(function (handler) { - handler(value); - }); - }; - - /** - * Standard promise.then, returns a promise that support chaining. - * TODO: Need to support resolve/reject handlers that return promises. - */ - ControlledPromise.prototype.then = function (onResolve, onReject) { - var returnPromise = new ControlledPromise(); - - if (onResolve) { - this.resolveHandlers.push(function (resolveWith) { - var chainResult = onResolve(resolveWith); - if (chainResult && chainResult.then) { - // chainResult is a promise, resolve when it resolves. - chainResult.then(function (pipedResult) { - return returnPromise.resolve(pipedResult); - }); - } else { - returnPromise.resolve(chainResult); - } - }); - } - - if (onReject) { - this.rejectHandlers.push(function (rejectWith) { - var chainResult = onReject(rejectWith); - if (chainResult && chainResult.then) { - chainResult.then(function (pipedResult) { - returnPromise.reject(pipedResult); - }); - } else { - returnPromise.reject(chainResult); - } - }); - } - - return returnPromise; - }; - - return ControlledPromise; - - } -); diff --git a/platform/entanglement/test/DomainObjectFactory.js b/platform/entanglement/test/DomainObjectFactory.js deleted file mode 100644 index 569b74a811..0000000000 --- a/platform/entanglement/test/DomainObjectFactory.js +++ /dev/null @@ -1,160 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * @typedef DomainObjectConfig - * @type {object} - * @property {string} [name] a name for the underlying jasmine spy - * object mockDomainObject. Used as - * @property {string} [id] initial id value for the domainOBject. - * @property {object} [model] initial values for the object's model. - * @property {object} [capabilities] an object containing - * capability definitions. - */ - - var configObjectProps = ['model', 'capabilities']; - - /** - * Internal function for ensuring an object is an instance of a - * DomainObjectConfig. - */ - function ensureValidConfigObject(config) { - if (!config || !config.hasOwnProperty) { - config = {}; - } - - if (!config.name) { - config.name = 'domainObject'; - } - - configObjectProps.forEach(function (prop) { - if (!config[prop] || !config[prop].hasOwnProperty) { - config[prop] = {}; - } - }); - - return config; - } - - /** - * Defines a factory function which takes a `config` object and returns - * a mock domainObject. The config object is an easy way to provide - * initial properties for the domainObject-- they can be changed at any - * time by directly modifying the domainObject's properties. - * - * @param {Object} [config] initial configuration for a domain object. - * @returns {Object} mockDomainObject - */ - function domainObjectFactory(config) { - config = ensureValidConfigObject(config); - - var domainObject = jasmine.createSpyObj(config.name, [ - 'getId', - 'getModel', - 'getCapability', - 'hasCapability', - 'useCapability' - ]); - - domainObject.model = JSON.parse(JSON.stringify(config.model)); - domainObject.capabilities = config.capabilities; - domainObject.id = config.id; - - /** - * getId: Returns `domainObject.id`. - * - * @returns {string} id - */ - domainObject.getId.and.callFake(function () { - return domainObject.id; - }); - - /** - * getModel: Returns `domainObject.model`. - * - * @returns {object} model - */ - domainObject.getModel.and.callFake(function () { - return domainObject.model; - }); - - /** - * getCapability: returns a `capability` object defined in - * domainObject.capabilities. Returns undefined if capability - * does not exist. - * - * @param {string} capability name of the capability to return. - * @returns {*} capability object - */ - domainObject.getCapability.and.callFake(function (capability) { - if (Object.prototype.hasOwnProperty.call(config.capabilities, capability)) { - return config.capabilities[capability]; - } - }); - - /** - * hasCapability: return true if domainObject.capabilities has a - * property named `capability`, otherwise returns false. - * - * @param {string} capability name of the capability to test for - * existence of. - * @returns {boolean} - */ - domainObject.hasCapability.and.callFake(function (capability) { - return Object.prototype.hasOwnProperty.call(config.capabilities, capability); - }); - - /** - * useCapability: find a capability in domainObject.capabilities - * and call that capabilities' invoke method. If the capability - * does not have an invoke method, will throw an error. - * - * @param {string} capability name of a capability to invoke. - * @param {...*} params to pass to the capability's `invoke` method. - * @returns {*} result whatever was returned by `invoke`. - */ - domainObject.useCapability.and.callFake(function (capability) { - if (Object.prototype.hasOwnProperty.call(config.capabilities, capability)) { - if (!config.capabilities[capability].invoke) { - throw new Error( - capability + ' missing invoke function.' - ); - } - - var passThroughArgs = [].slice.call(arguments, 1); - - return config - .capabilities[capability] - .invoke - .apply(null, passThroughArgs); - } - }); - - return domainObject; - } - - return domainObjectFactory; - } -); diff --git a/platform/entanglement/test/actions/AbstractComposeActionSpec.js b/platform/entanglement/test/actions/AbstractComposeActionSpec.js deleted file mode 100644 index 8fa168afc1..0000000000 --- a/platform/entanglement/test/actions/AbstractComposeActionSpec.js +++ /dev/null @@ -1,227 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/AbstractComposeAction', - '../services/MockCopyService', - '../DomainObjectFactory' - ], - function (AbstractComposeAction, MockCopyService, domainObjectFactory) { - - describe("Move/copy/link Actions", function () { - - var action, - policyService, - locationService, - locationServicePromise, - composeService, - context, - selectedObject, - selectedObjectContextCapability, - currentParent, - newParent; - - beforeEach(function () { - policyService = jasmine.createSpyObj( - 'policyService', - ['allow'] - ); - - selectedObjectContextCapability = jasmine.createSpyObj( - 'selectedObjectContextCapability', - [ - 'getParent' - ] - ); - - selectedObject = domainObjectFactory({ - name: 'selectedObject', - model: { - name: 'selectedObject' - }, - capabilities: { - context: selectedObjectContextCapability - } - }); - - currentParent = domainObjectFactory({ - name: 'currentParent' - }); - - selectedObjectContextCapability - .getParent - .and.returnValue(currentParent); - - newParent = domainObjectFactory({ - name: 'newParent' - }); - - locationService = jasmine.createSpyObj( - 'locationService', - [ - 'getLocationFromUser' - ] - ); - - locationServicePromise = jasmine.createSpyObj( - 'locationServicePromise', - [ - 'then' - ] - ); - - policyService.allow.and.returnValue(true); - - locationService - .getLocationFromUser - .and.returnValue(locationServicePromise); - - composeService = new MockCopyService(); - }); - - it("are only applicable to domain objects with a context", function () { - var noContextObject = domainObjectFactory({ - name: 'selectedObject', - model: { name: 'selectedObject' }, - capabilities: {} - }); - - expect(AbstractComposeAction.appliesTo({ - selectedObject: selectedObject - })).toBe(true); - expect(AbstractComposeAction.appliesTo({ - domainObject: selectedObject - })).toBe(true); - - expect(AbstractComposeAction.appliesTo({ - selectedObject: noContextObject - })).toBe(false); - expect(AbstractComposeAction.appliesTo({ - domainObject: noContextObject - })).toBe(false); - }); - - describe("with context from context-action", function () { - beforeEach(function () { - context = { - domainObject: selectedObject - }; - - action = new AbstractComposeAction( - policyService, - locationService, - composeService, - context, - "Compose" - ); - }); - - it("initializes happily", function () { - expect(action).toBeDefined(); - }); - - describe("when performed it", function () { - beforeEach(function () { - action.perform(); - }); - - it("prompts for location", function () { - expect(locationService.getLocationFromUser) - .toHaveBeenCalledWith( - "Compose selectedObject To a New Location", - "Compose To", - jasmine.any(Function), - currentParent - ); - }); - - it("waits for location and handles cancellation by user", function () { - expect(locationServicePromise.then) - .toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function)); - }); - - it("copies object to selected location", function () { - locationServicePromise - .then - .calls.mostRecent() - .args[0](newParent); - - expect(composeService.perform) - .toHaveBeenCalledWith(selectedObject, newParent); - }); - - describe("provides a validator which", function () { - var validator; - - beforeEach(function () { - validator = locationService.getLocationFromUser - .calls.mostRecent().args[2]; - composeService.validate.and.returnValue(true); - policyService.allow.and.returnValue(true); - }); - - it("is sensitive to policy", function () { - expect(validator()).toBe(true); - policyService.allow.and.returnValue(false); - expect(validator()).toBe(false); - }); - - it("is sensitive to service-specific validation", function () { - expect(validator()).toBe(true); - composeService.validate.and.returnValue(false); - expect(validator()).toBe(false); - }); - - }); - }); - }); - - describe("with context from drag-drop", function () { - beforeEach(function () { - context = { - selectedObject: selectedObject, - domainObject: newParent - }; - - action = new AbstractComposeAction( - policyService, - locationService, - composeService, - context, - "Compose" - ); - }); - - it("initializes happily", function () { - expect(action).toBeDefined(); - }); - - it("performs copy immediately", function () { - action.perform(); - expect(composeService.perform) - .toHaveBeenCalledWith(selectedObject, newParent); - }); - }); - }); - } -); diff --git a/platform/entanglement/test/actions/SetPrimaryLocationActionSpec.js b/platform/entanglement/test/actions/SetPrimaryLocationActionSpec.js deleted file mode 100644 index d4980c6215..0000000000 --- a/platform/entanglement/test/actions/SetPrimaryLocationActionSpec.js +++ /dev/null @@ -1,88 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/SetPrimaryLocationAction', - '../DomainObjectFactory' - ], - function (SetPrimaryLocation, domainObjectFactory) { - - describe("The 'set primary location' action", function () { - var testContext, - testModel, - testId, - mockLocationCapability, - openmct; - - beforeEach(function () { - openmct = { - objects: { - isPersistable: jasmine.createSpy('isPersistable') - } - }; - testId = "some-id"; - testModel = { name: "some name" }; - - mockLocationCapability = jasmine.createSpyObj( - 'location', - ['setPrimaryLocation', 'getContextualLocation'] - ); - - openmct.objects.isPersistable.and.returnValue(true); - mockLocationCapability.getContextualLocation.and.returnValue(testId); - - testContext = { - domainObject: domainObjectFactory({ - capabilities: { - location: mockLocationCapability - }, - model: testModel - }) - }; - }); - - it("is applicable to objects with no location specified", function () { - expect(SetPrimaryLocation.appliesTo(testContext, undefined, openmct)) - .toBe(true); - testContext.domainObject.getModel.and.returnValue({ - location: "something", - name: "some name" - }); - expect(SetPrimaryLocation.appliesTo(testContext, undefined, openmct)) - .toBe(false); - }); - - it("checks object persistability", function () { - SetPrimaryLocation.appliesTo(testContext, undefined, openmct); - expect(openmct.objects.isPersistable).toHaveBeenCalled(); - }); - - it("sets the location contextually when performed", function () { - new SetPrimaryLocation(testContext).perform(); - expect(mockLocationCapability.setPrimaryLocation) - .toHaveBeenCalledWith(testId); - }); - - }); - } -); diff --git a/platform/entanglement/test/capabilities/LocationCapabilitySpec.js b/platform/entanglement/test/capabilities/LocationCapabilitySpec.js deleted file mode 100644 index 343f033626..0000000000 --- a/platform/entanglement/test/capabilities/LocationCapabilitySpec.js +++ /dev/null @@ -1,163 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/LocationCapability', - '../DomainObjectFactory', - '../ControlledPromise' - ], - function (LocationCapability, domainObjectFactory, ControlledPromise) { - - describe("LocationCapability", function () { - - describe("instantiated with domain object", function () { - var locationCapability, - mutationPromise, - mockQ, - mockInjector, - mockObjectService, - domainObject; - - beforeEach(function () { - domainObject = domainObjectFactory({ - id: "testObject", - capabilities: { - context: { - getParent: function () { - return domainObjectFactory({id: 'root'}); - } - }, - mutation: jasmine.createSpyObj( - 'mutationCapability', - ['invoke'] - ) - } - }); - - mockQ = jasmine.createSpyObj("$q", ["when"]); - mockInjector = jasmine.createSpyObj("$injector", ["get"]); - mockObjectService = - jasmine.createSpyObj("objectService", ["getObjects"]); - - mutationPromise = new ControlledPromise(); - domainObject.capabilities.mutation.invoke.and.callFake( - function (mutator) { - return mutationPromise.then(function () { - mutator(domainObject.model); - }); - } - ); - - locationCapability = new LocationCapability( - mockQ, - mockInjector, - domainObject - ); - }); - - it("returns contextual location", function () { - expect(locationCapability.getContextualLocation()) - .toBe('root'); - }); - - it("knows when the object is an original", function () { - domainObject.model.location = 'root'; - expect(locationCapability.isOriginal()).toBe(true); - expect(locationCapability.isLink()).toBe(false); - }); - - it("knows when the object is a link.", function () { - domainObject.model.location = 'different-root'; - expect(locationCapability.isLink()).toBe(true); - expect(locationCapability.isOriginal()).toBe(false); - }); - - it("can mutate location", function () { - var result = locationCapability - .setPrimaryLocation('root'), - whenComplete = jasmine.createSpy('whenComplete'); - - result.then(whenComplete); - - expect(domainObject.model.location).not.toBeDefined(); - mutationPromise.resolve(); - expect(domainObject.model.location).toBe('root'); - - expect(whenComplete).toHaveBeenCalled(); - }); - - describe("when used to load an original instance", function () { - var objectPromise, - qPromise, - originalObjects, - mockCallback; - - function resolvePromises() { - if (mockQ.when.calls.count() > 0) { - qPromise.resolve(mockQ.when.calls.mostRecent().args[0]); - } - - if (mockObjectService.getObjects.calls.count() > 0) { - objectPromise.resolve(originalObjects); - } - } - - beforeEach(function () { - objectPromise = new ControlledPromise(); - qPromise = new ControlledPromise(); - originalObjects = { - testObject: domainObjectFactory() - }; - - mockInjector.get.and.callFake(function (key) { - return key === 'objectService' && mockObjectService; - }); - mockObjectService.getObjects.and.returnValue(objectPromise); - mockQ.when.and.returnValue(qPromise); - - mockCallback = jasmine.createSpy('callback'); - }); - - it("provides originals directly", function () { - domainObject.model.location = 'root'; - locationCapability.getOriginal().then(mockCallback); - expect(mockCallback).not.toHaveBeenCalled(); - resolvePromises(); - expect(mockCallback) - .toHaveBeenCalledWith(domainObject); - }); - - it("loads from the object service for links", function () { - domainObject.model.location = 'some-other-root'; - locationCapability.getOriginal().then(mockCallback); - expect(mockCallback).not.toHaveBeenCalled(); - resolvePromises(); - expect(mockCallback) - .toHaveBeenCalledWith(originalObjects.testObject); - }); - }); - - }); - }); - } -); diff --git a/platform/entanglement/test/policies/CopyPolicySpec.js b/platform/entanglement/test/policies/CopyPolicySpec.js deleted file mode 100644 index c53ef6cf09..0000000000 --- a/platform/entanglement/test/policies/CopyPolicySpec.js +++ /dev/null @@ -1,92 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define([ - '../../src/policies/CopyPolicy', - '../DomainObjectFactory' -], function (CopyPolicy, domainObjectFactory) { - - describe("CopyPolicy", function () { - var testMetadata, - testContext, - mockDomainObject, - mockType, - mockAction, - policy; - - beforeEach(function () { - mockType = - jasmine.createSpyObj('type', ['hasFeature']); - - testMetadata = {}; - - mockDomainObject = domainObjectFactory({ - capabilities: { type: mockType } - }); - - mockType.hasFeature.and.callFake(function (feature) { - return feature === 'creation'; - }); - - mockAction = jasmine.createSpyObj('action', ['getMetadata']); - mockAction.getMetadata.and.returnValue(testMetadata); - - testContext = { domainObject: mockDomainObject }; - - policy = new CopyPolicy(); - }); - - describe("for copy actions", function () { - beforeEach(function () { - testMetadata.key = 'copy'; - }); - - describe("when an object is non-creatable", function () { - beforeEach(function () { - mockType.hasFeature.and.returnValue(false); - }); - - it("disallows the action", function () { - expect(policy.allow(mockAction, testContext)).toBe(false); - }); - }); - - describe("when an object is creatable", function () { - it("allows the action", function () { - expect(policy.allow(mockAction, testContext)).toBe(true); - }); - }); - }); - - describe("for other actions", function () { - beforeEach(function () { - testMetadata.key = 'foo'; - }); - - it("simply allows the action", function () { - expect(policy.allow(mockAction, testContext)).toBe(true); - mockType.hasFeature.and.returnValue(false); - expect(policy.allow(mockAction, testContext)).toBe(true); - }); - }); - }); -}); diff --git a/platform/entanglement/test/policies/CrossSpacePolicySpec.js b/platform/entanglement/test/policies/CrossSpacePolicySpec.js deleted file mode 100644 index 1e7d86d59a..0000000000 --- a/platform/entanglement/test/policies/CrossSpacePolicySpec.js +++ /dev/null @@ -1,117 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define( - [ - '../../src/policies/CrossSpacePolicy', - '../DomainObjectFactory' - ], - function (CrossSpacePolicy, domainObjectFactory) { - - describe("CrossSpacePolicy", function () { - var mockAction, - testActionMetadata, - sameSpaceContext, - crossSpaceContext, - policy; - - function makeObject(space) { - var mockPersistence = jasmine.createSpyObj( - 'persistence', - ['getSpace'] - ); - mockPersistence.getSpace.and.returnValue(space); - - return domainObjectFactory({ - id: space + ":foo", - model: {}, - capabilities: { persistence: mockPersistence } - }); - } - - beforeEach(function () { - testActionMetadata = {}; - - // Policy should only call passive methods, so - // only define those in mocks. - mockAction = jasmine.createSpyObj( - 'action', - ['getMetadata'] - ); - mockAction.getMetadata.and.returnValue(testActionMetadata); - - sameSpaceContext = { - domainObject: makeObject('a'), - selectedObject: makeObject('a') - }; - crossSpaceContext = { - domainObject: makeObject('a'), - selectedObject: makeObject('b') - }; - - policy = new CrossSpacePolicy(); - }); - - describe("for move actions", function () { - beforeEach(function () { - testActionMetadata.key = 'move'; - }); - - it("allows same-space changes", function () { - expect(policy.allow(mockAction, sameSpaceContext)) - .toBe(true); - }); - - it("disallows cross-space changes", function () { - expect(policy.allow(mockAction, crossSpaceContext)) - .toBe(false); - }); - - it("allows actions with no selectedObject", function () { - expect(policy.allow(mockAction, { - domainObject: makeObject('a') - })).toBe(true); - }); - }); - - describe("for other actions", function () { - beforeEach(function () { - testActionMetadata.key = "some-other-action"; - }); - - it("allows same-space and cross-space changes", function () { - expect(policy.allow(mockAction, crossSpaceContext)) - .toBe(true); - expect(policy.allow(mockAction, sameSpaceContext)) - .toBe(true); - }); - - it("allows actions with no selectedObject", function () { - expect(policy.allow(mockAction, { - domainObject: makeObject('a') - })).toBe(true); - }); - }); - - }); - } -); diff --git a/platform/entanglement/test/services/CopyServiceSpec.js b/platform/entanglement/test/services/CopyServiceSpec.js deleted file mode 100644 index 3ebad9d191..0000000000 --- a/platform/entanglement/test/services/CopyServiceSpec.js +++ /dev/null @@ -1,479 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/CopyService', - '../DomainObjectFactory' - ], - function (CopyService, domainObjectFactory) { - - function synchronousPromise(value) { - if (value && value.then) { - return value; - } - - var promise = { - then: function (callback) { - return synchronousPromise(callback(value)); - } - }; - spyOn(promise, 'then').and.callThrough(); - - return promise; - } - - xdescribe("CopyService", function () { - var policyService; - - beforeEach(function () { - policyService = jasmine.createSpyObj( - 'policyService', - ['allow'] - ); - }); - - describe("validate", function () { - - var copyService, - object, - parentCandidate, - validate; - - beforeEach(function () { - copyService = new CopyService( - null, - policyService - ); - object = domainObjectFactory({ - name: 'object', - capabilities: { - type: { type: 'object' } - } - }); - parentCandidate = domainObjectFactory({ - name: 'parentCandidate', - capabilities: { - type: { type: 'parentCandidate' } - } - }); - validate = function () { - return copyService.validate(object, parentCandidate); - }; - }); - - it("does not allow invalid parentCandidate", function () { - parentCandidate = undefined; - expect(validate()).toBe(false); - parentCandidate = {}; - expect(validate()).toBe(false); - }); - - it("does not allow copying into source object", function () { - object.id = parentCandidate.id = 'abc'; - expect(validate()).toBe(false); - }); - - describe("defers to policyService", function () { - beforeEach(function () { - object.id = 'a'; - parentCandidate.id = 'b'; - }); - - it("calls policy service with correct args", function () { - validate(); - expect(policyService.allow).toHaveBeenCalledWith( - "composition", - parentCandidate, - object - ); - }); - - it("and returns false", function () { - policyService.allow.and.returnValue(false); - expect(validate()).toBe(false); - }); - - it("and returns true", function () { - policyService.allow.and.returnValue(true); - expect(validate()).toBe(true); - }); - }); - }); - - describe("perform", function () { - - var mockQ, - mockDeferred, - copyService, - object, - newParent, - copyResult, - copyFinished, - persistObjectPromise, - persistenceCapability, - instantiationCapability, - compositionCapability, - locationCapability, - resolvedValue; - - beforeEach(function () { - policyService.allow.and.returnValue(true); - - persistObjectPromise = synchronousPromise(undefined); - - instantiationCapability = jasmine.createSpyObj( - "instantiation", - ["invoke"] - ); - - persistenceCapability = jasmine.createSpyObj( - "persistenceCapability", - ["persist", "getSpace"] - ); - persistenceCapability.persist.and.returnValue(persistObjectPromise); - - compositionCapability = jasmine.createSpyObj( - 'compositionCapability', - ['invoke', 'add'] - ); - compositionCapability.add.and.callFake(synchronousPromise); - - locationCapability = jasmine.createSpyObj( - 'locationCapability', - ['isLink'] - ); - locationCapability.isLink.and.returnValue(false); - - mockDeferred = jasmine.createSpyObj( - 'mockDeferred', - ['notify', 'resolve', 'reject'] - ); - mockDeferred.notify.and.callFake(function () {}); - mockDeferred.resolve.and.callFake(function (value) { - resolvedValue = value; - }); - mockDeferred.promise = { - then: function (callback) { - return synchronousPromise(callback(resolvedValue)); - } - }; - - mockQ = jasmine.createSpyObj( - 'mockQ', - ['when', 'all', 'reject', 'defer'] - ); - mockQ.reject.and.returnValue(synchronousPromise(undefined)); - mockQ.when.and.callFake(synchronousPromise); - mockQ.all.and.callFake(function (promises) { - var result = {}; - Object.keys(promises).forEach(function (k) { - promises[k].then(function (v) { - result[k] = v; - }); - }); - - return synchronousPromise(result); - }); - mockQ.defer.and.returnValue(mockDeferred); - - }); - - describe("on domain object without composition", function () { - beforeEach(function () { - var objectCopy; - - newParent = domainObjectFactory({ - name: 'newParent', - id: '456', - model: { - composition: [] - }, - capabilities: { - instantiation: instantiationCapability, - persistence: persistenceCapability, - composition: compositionCapability - } - }); - - object = domainObjectFactory({ - name: 'object', - id: 'abc', - model: { - name: 'some object', - location: '456', - someOtherAttribute: 'some other value', - embeddedObjectAttribute: { - name: 'Some embedded object' - } - }, - capabilities: { - persistence: persistenceCapability - } - }); - - objectCopy = domainObjectFactory({ - name: 'object', - id: 'abc.copy.fdgdfgdf', - capabilities: { - persistence: persistenceCapability, - location: locationCapability - } - }); - - instantiationCapability.invoke.and.callFake( - function (model) { - objectCopy.model = model; - - return objectCopy; - } - ); - - copyService = new CopyService(mockQ, policyService); - copyResult = copyService.perform(object, newParent); - copyFinished = jasmine.createSpy('copyFinished'); - copyResult.then(copyFinished); - }); - - it("uses persistence capability", function () { - expect(persistenceCapability.persist) - .toHaveBeenCalled(); - }); - - it("deep clones object model", function () { - var newModel = copyFinished.calls.all()[0].args[0].getModel(); - expect(newModel).toEqual(object.model); - expect(newModel).not.toBe(object.model); - }); - - it("returns a promise", function () { - expect(copyResult).toBeDefined(); - expect(copyFinished).toHaveBeenCalled(); - }); - - }); - - describe("on domainObject with composition", function () { - var childObject, - objectClone, - childObjectClone; - - beforeEach(function () { - var invocationCount = 0, - objectClones; - - instantiationCapability.invoke.and.callFake( - function (model) { - var cloneToReturn = objectClones[invocationCount++]; - cloneToReturn.model = model; - - return cloneToReturn; - } - ); - - newParent = domainObjectFactory({ - name: 'newParent', - id: '456', - model: { - composition: [] - }, - capabilities: { - instantiation: instantiationCapability, - persistence: persistenceCapability, - composition: compositionCapability - } - }); - - childObject = domainObjectFactory({ - name: 'childObject', - id: 'def', - model: { - name: 'a child object', - location: 'abc' - }, - capabilities: { - persistence: persistenceCapability, - location: locationCapability - } - }); - - childObjectClone = domainObjectFactory({ - name: 'childObject', - id: 'def.clone', - capabilities: { - persistence: persistenceCapability, - location: locationCapability - } - }); - - compositionCapability - .invoke - .and.returnValue(synchronousPromise([childObject])); - - object = domainObjectFactory({ - name: 'some object', - id: 'abc', - model: { - name: 'some object', - composition: ['def'], - location: 'testLocation' - }, - capabilities: { - instantiation: instantiationCapability, - composition: compositionCapability, - location: locationCapability, - persistence: persistenceCapability - } - }); - - objectClone = domainObjectFactory({ - name: 'some object', - id: 'abc.clone', - capabilities: { - instantiation: instantiationCapability, - composition: compositionCapability, - location: locationCapability, - persistence: persistenceCapability - } - }); - - objectClones = [objectClone, childObjectClone]; - - copyService = new CopyService(mockQ, policyService); - }); - - describe("the cloning process", function () { - beforeEach(function () { - copyResult = copyService.perform(object, newParent); - copyFinished = jasmine.createSpy('copyFinished'); - copyResult.then(copyFinished); - }); - - it("returns a promise", function () { - expect(copyResult.then).toBeDefined(); - expect(copyFinished).toHaveBeenCalled(); - }); - - it("returns a promise", function () { - expect(copyResult.then).toBeDefined(); - expect(copyFinished).toHaveBeenCalled(); - }); - - it ("correctly locates cloned objects", function () { - expect(childObjectClone.getModel().location).toEqual(objectClone.getId()); - }); - }); - - describe("when cloning non-creatable objects", function () { - beforeEach(function () { - policyService.allow.and.callFake(function (category) { - //Return false for 'creation' policy - return category !== 'creation'; - }); - - copyResult = copyService.perform(object, newParent); - copyFinished = jasmine.createSpy('copyFinished'); - copyResult.then(copyFinished); - }); - it ("creates link instead of clone", function () { - var copiedObject = copyFinished.calls.all()[0].args[0]; - expect(copiedObject).toBe(object); - expect(compositionCapability.add) - .toHaveBeenCalledWith(copiedObject); - }); - }); - - describe("when provided a filtering function", function () { - beforeEach(function () { - copyFinished = jasmine.createSpy('copyFinished'); - }); - - function accept() { - return true; - } - - function reject() { - return false; - } - - it("does not create new instances of objects " - + "rejected by the filter", function () { - copyService.perform(object, newParent, reject) - .then(copyFinished); - expect(copyFinished.calls.mostRecent().args[0]) - .toBe(object); - }); - - it("does create new instances of objects " - + "accepted by the filter", function () { - copyService.perform(object, newParent, accept) - .then(copyFinished); - expect(copyFinished.calls.mostRecent().args[0]) - .not.toBe(object); - }); - }); - }); - - describe("on invalid inputs", function () { - beforeEach(function () { - object = domainObjectFactory({ - name: 'object', - capabilities: { - type: { type: 'object' }, - location: locationCapability, - persistence: persistenceCapability - } - }); - - newParent = domainObjectFactory({ - name: 'parentCandidate', - capabilities: { - type: { type: 'parentCandidate' }, - instantiation: instantiationCapability, - composition: compositionCapability, - persistence: persistenceCapability - } - }); - - instantiationCapability.invoke.and.returnValue(object); - }); - - it("throws an error", function () { - var service = - new CopyService(mockQ, policyService); - - function perform() { - service.perform(object, newParent); - } - - spyOn(service, "validate"); - service.validate.and.returnValue(true); - expect(perform).not.toThrow(); - service.validate.and.returnValue(false); - expect(perform).toThrow(); - }); - }); - - }); - }); - } -); diff --git a/platform/entanglement/test/services/CopyTaskSpec.js b/platform/entanglement/test/services/CopyTaskSpec.js deleted file mode 100644 index 20a464d5ad..0000000000 --- a/platform/entanglement/test/services/CopyTaskSpec.js +++ /dev/null @@ -1,267 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/CopyTask', - '../DomainObjectFactory' - ], - function (CopyTask, domainObjectFactory) { - - var ID_A = "some-string-with-vaguely-uuidish-uniqueness", - ID_B = "some-other-similarly-unique-string"; - - function synchronousPromise(value) { - return (value && value.then) ? value : { - then: function (callback) { - return synchronousPromise(callback(value)); - } - }; - } - - describe("CopyTask", function () { - var mockDomainObject, - mockParentObject, - mockFilter, - mockQ, - mockDeferred, - testModel, - counter, - cloneIds, - task; - - function makeMockCapabilities(childIds) { - var mockCapabilities = { - persistence: jasmine.createSpyObj( - 'persistence', - ['persist'] - ), - composition: jasmine.createSpyObj( - 'composition', - ['add', 'invoke'] - ), - instantiation: jasmine.createSpyObj( - 'instantiation', - ['instantiate', 'invoke'] - ) - }, - mockChildren = (childIds || []).map(function (id) { - return domainObjectFactory({ - id: id, - capabilities: makeMockCapabilities([]), - model: { originalId: id } - }); - }); - - mockCapabilities.persistence.persist - .and.returnValue(synchronousPromise(true)); - mockCapabilities.composition.add.and.callFake(function (obj) { - return synchronousPromise(obj); - }); - mockCapabilities.composition.invoke - .and.returnValue(synchronousPromise(mockChildren)); - mockCapabilities.instantiation.invoke - .and.callFake(function (model) { - var id = "some-id-" + counter; - cloneIds[model.originalId] = id; - counter += 1; - - return domainObjectFactory({ - id: id, - model: model, - capabilities: makeMockCapabilities() - }); - }); - - return mockCapabilities; - } - - beforeEach(function () { - counter = 0; - cloneIds = {}; - - testModel = { - composition: [ID_A, ID_B], - someObj: {}, - someArr: [ID_A, ID_B], - objArr: [{"id": ID_A}, {"id": ID_B}], - singleElementArr: [ID_A] - }; - testModel.someObj[ID_A] = "some value"; - testModel.someObj.someProperty = ID_B; - - mockDomainObject = domainObjectFactory({ - capabilities: makeMockCapabilities(testModel.composition), - model: testModel - }); - mockParentObject = domainObjectFactory({ - capabilities: makeMockCapabilities() - }); - mockFilter = jasmine.createSpy('filter'); - mockQ = jasmine.createSpyObj('$q', ['when', 'defer', 'all']); - mockDeferred = jasmine.createSpyObj( - 'deferred', - ['notify', 'resolve', 'reject'] - ); - - mockFilter.and.returnValue(true); - - mockQ.when.and.callFake(synchronousPromise); - mockQ.defer.and.returnValue(mockDeferred); - mockQ.all.and.callFake(function (promises) { - return synchronousPromise(promises.map(function (promise) { - var value; - promise.then(function (v) { - value = v; - }); - - return value; - })); - }); - - mockDeferred.resolve.and.callFake(function (value) { - mockDeferred.promise = synchronousPromise(value); - }); - - }); - - describe("produces models which", function () { - var model; - - beforeEach(function () { - task = new CopyTask( - mockDomainObject, - mockParentObject, - mockFilter, - mockQ - ); - - task.perform().then(function (clone) { - model = clone.getModel(); - }); - }); - - it("contain rewritten identifiers in arrays", function () { - expect(model.someArr) - .toEqual(testModel.someArr.map(function (id) { - return cloneIds[id]; - })); - }); - - it("contain rewritten identifiers in properties", function () { - expect(model.someObj.someProperty) - .toEqual(cloneIds[testModel.someObj.someProperty]); - }); - - it("contain rewritten identifiers in property names", function () { - expect(model.someObj[cloneIds[ID_A]]) - .toEqual(testModel.someObj[ID_A]); - }); - - it("contain rewritten identifiers in single-element arrays", function () { - expect(model.singleElementArr) - .toEqual(testModel.singleElementArr.map(function (id) { - return cloneIds[id]; - })); - }); - }); - - describe("copies object trees with multiple references to the" - + " same object", function () { - var mockDomainObjectB, - mockComposingObject, - composingObjectModel, - domainObjectClone, - domainObjectBClone; - - beforeEach(function () { - mockDomainObjectB = domainObjectFactory({ - capabilities: makeMockCapabilities(testModel.composition), - model: testModel - }); - composingObjectModel = { - name: 'mockComposingObject', - composition: [mockDomainObject.getId(), mockDomainObjectB.getId()] - }; - mockComposingObject = domainObjectFactory({ - capabilities: makeMockCapabilities(composingObjectModel.composition), - model: composingObjectModel - }); - - mockComposingObject.capabilities.composition.invoke.and.returnValue([mockDomainObject, mockDomainObjectB]); - task = new CopyTask( - mockComposingObject, - mockParentObject, - mockFilter, - mockQ - ); - - task.perform(); - domainObjectClone = task.clones[2]; - domainObjectBClone = task.clones[5]; - }); - - /** - * mockDomainObject and mockDomainObjectB have the same - * model with references to children ID_A and ID_B. Expect - * that after duplication the references should differ - * because they are each now referencing different child - * objects. This tests the issue reported in #428 - */ - it(" and correctly updates child identifiers in models ", function () { - var childA_ID = task.clones[0].getId(), - childB_ID = task.clones[1].getId(), - childC_ID = task.clones[3].getId(), - childD_ID = task.clones[4].getId(); - - expect(domainObjectClone.model.someArr[0]).not.toBe(domainObjectBClone.model.someArr[0]); - expect(domainObjectClone.model.someArr[0]).toBe(childA_ID); - expect(domainObjectBClone.model.someArr[0]).toBe(childC_ID); - expect(domainObjectClone.model.someArr[1]).not.toBe(domainObjectBClone.model.someArr[1]); - expect(domainObjectClone.model.someArr[1]).toBe(childB_ID); - expect(domainObjectBClone.model.someArr[1]).toBe(childD_ID); - expect(domainObjectClone.model.someObj.someProperty).not.toBe(domainObjectBClone.model.someObj.someProperty); - expect(domainObjectClone.model.someObj.someProperty).toBe(childB_ID); - expect(domainObjectBClone.model.someObj.someProperty).toBe(childD_ID); - - }); - - /** - * This a bug found in testathon when testing issue #428 - */ - it(" and correctly updates child identifiers in object" - + " arrays within models ", function () { - var childA_ID = task.clones[0].getId(), - childB_ID = task.clones[1].getId(); - - expect(domainObjectClone.model.objArr[0].id).not.toBe(ID_A); - expect(domainObjectClone.model.objArr[0].id).toBe(childA_ID); - expect(domainObjectClone.model.objArr[1].id).not.toBe(ID_B); - expect(domainObjectClone.model.objArr[1].id).toBe(childB_ID); - - }); - }); - - }); - - } -); diff --git a/platform/entanglement/test/services/LocatingCreationDecoratorSpec.js b/platform/entanglement/test/services/LocatingCreationDecoratorSpec.js deleted file mode 100644 index 0506a7bf21..0000000000 --- a/platform/entanglement/test/services/LocatingCreationDecoratorSpec.js +++ /dev/null @@ -1,76 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/LocatingCreationDecorator' - ], - function (LocatingCreationDecorator) { - - describe("LocatingCreationDecorator", function () { - var mockCreationService, - mockPromise, - mockParent, - decorator; - - beforeEach(function () { - mockCreationService = jasmine.createSpyObj( - 'creationService', - ['createObject'] - ); - mockPromise = jasmine.createSpyObj( - 'promise', - ['then'] - ); - mockParent = jasmine.createSpyObj( - 'domainObject', - ['getCapability', 'getId', 'getModel', 'hasCapability', 'useCapability'] - ); - mockCreationService.createObject.and.returnValue(mockPromise); - mockParent.getId.and.returnValue('test-id'); - decorator = new LocatingCreationDecorator(mockCreationService); - }); - - it("delegates to its decorated service", function () { - expect(decorator.createObject( - { someKey: "some value" }, - mockParent - )).toEqual(mockPromise); // promise returned by decoratee - }); - - it("adds a location property", function () { - decorator.createObject( - { someKey: "some value" }, - mockParent - ); - expect(mockCreationService.createObject).toHaveBeenCalledWith( - { - someKey: "some value", - location: "test-id" // Parent's identifier - }, - mockParent - ); - }); - - }); - } -); diff --git a/platform/entanglement/test/services/LocatingObjectDecoratorSpec.js b/platform/entanglement/test/services/LocatingObjectDecoratorSpec.js deleted file mode 100644 index 40bf52a578..0000000000 --- a/platform/entanglement/test/services/LocatingObjectDecoratorSpec.js +++ /dev/null @@ -1,131 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/LocatingObjectDecorator', - '../../../core/src/capabilities/ContextualDomainObject' - ], - function (LocatingObjectDecorator, ContextualDomainObject) { - - describe("LocatingObjectDecorator", function () { - var mockQ, - mockLog, - mockObjectService, - mockCallback, - testObjects, - testModels, - decorator; - - function testPromise(v) { - return (v || {}).then ? v : { - then: function (callback) { - return testPromise(callback(v)); - } - }; - } - - beforeEach(function () { - // A <- B <- C - // D <-> E, to verify cycle detection - testModels = { - a: { name: "A" }, - b: { - name: "B", - location: "a" - }, - c: { - name: "C", - location: "b" - }, - d: { - name: "D", - location: "e" - }, - e: { - name: "E", - location: "d" - } - }; - testObjects = {}; - - mockQ = jasmine.createSpyObj("$q", ["when", "all"]); - mockLog = - jasmine.createSpyObj("$log", ["error", "warn", "info", "debug"]); - mockObjectService = - jasmine.createSpyObj("objectService", ["getObjects"]); - - mockQ.when.and.callFake(testPromise); - mockQ.all.and.callFake(function (promises) { - var result = {}; - Object.keys(promises).forEach(function (k) { - promises[k].then(function (v) { - result[k] = v; - }); - }); - - return testPromise(result); - }); - - mockObjectService.getObjects.and.returnValue(testPromise(testObjects)); - - mockCallback = jasmine.createSpy("callback"); - - Object.keys(testModels).forEach(function (id) { - testObjects[id] = jasmine.createSpyObj( - "domainObject-" + id, - ["getId", "getModel", "getCapability"] - ); - testObjects[id].getId.and.returnValue(id); - testObjects[id].getModel.and.returnValue(testModels[id]); - }); - - decorator = new LocatingObjectDecorator( - mockQ, - mockLog, - mockObjectService - ); - }); - - it("contextualizes domain objects", function () { - decorator.getObjects(['b', 'c']).then(mockCallback); - expect(mockCallback).toHaveBeenCalled(); - - var callbackObj = mockCallback.calls.mostRecent().args[0]; - expect(testObjects.b.getCapability('context')).not.toBeDefined(); - expect(testObjects.c.getCapability('context')).not.toBeDefined(); - expect(callbackObj.b.getCapability('context')).toBeDefined(); - expect(callbackObj.c.getCapability('context')).toBeDefined(); - }); - - it("warns on cycle detection", function () { - // Base case, no cycle, no warning - decorator.getObjects(['a', 'b', 'c']); - expect(mockLog.warn).not.toHaveBeenCalled(); - - decorator.getObjects(['e']); - expect(mockLog.warn).toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/entanglement/test/services/LocationServiceSpec.js b/platform/entanglement/test/services/LocationServiceSpec.js deleted file mode 100644 index 35b20599a0..0000000000 --- a/platform/entanglement/test/services/LocationServiceSpec.js +++ /dev/null @@ -1,151 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/LocationService' - ], - function (LocationService) { - - describe("LocationService", function () { - var dialogService, - locationService, - dialogServicePromise, - chainedPromise; - - beforeEach(function () { - dialogService = jasmine.createSpyObj( - 'dialogService', - ['getUserInput'] - ); - dialogServicePromise = jasmine.createSpyObj( - 'dialogServicePromise', - ['then'] - ); - chainedPromise = jasmine.createSpyObj( - 'chainedPromise', - ['then'] - ); - dialogServicePromise.then.and.returnValue(chainedPromise); - dialogService.getUserInput.and.returnValue(dialogServicePromise); - locationService = new LocationService(dialogService); - }); - - describe("getLocationFromUser", function () { - var title, - label, - validate, - initialLocation, - locationResult, - formStructure, - formState; - - beforeEach(function () { - title = "Get a location to do something"; - label = "a location"; - validate = function () { - return true; - }; - - initialLocation = { key: "a key" }; - locationResult = locationService.getLocationFromUser( - title, - label, - validate, - initialLocation - ); - formStructure = dialogService - .getUserInput - .calls.mostRecent() - .args[0]; - formState = dialogService - .getUserInput - .calls.mostRecent() - .args[1]; - }); - - it("calls through to dialogService", function () { - expect(dialogService.getUserInput).toHaveBeenCalledWith( - jasmine.any(Object), - jasmine.any(Object) - ); - expect(formStructure.name).toBe(title); - }); - - it("returns a promise", function () { - expect(locationResult.then).toBeDefined(); - }); - - describe("formStructure", function () { - var locationSection, - inputRow; - - beforeEach(function () { - locationSection = formStructure.sections[0]; - inputRow = locationSection.rows[0]; - }); - - it("has a location section", function () { - expect(locationSection).toBeDefined(); - expect(locationSection.name).toBe('Location'); - }); - - it("has a input row", function () { - expect(inputRow.control).toBe('locator'); - expect(inputRow.key).toBe('location'); - expect(inputRow.name).toBe(label); - expect(inputRow.validate).toBe(validate); - }); - }); - - describe("formState", function () { - it("has an initial location", function () { - expect(formState.location).toBe(initialLocation); - }); - }); - - describe("resolution of dialog service promise", function () { - var resolution, - resolver, - dialogResult, - selectedLocation; - - beforeEach(function () { - resolver = - dialogServicePromise.then.calls.mostRecent().args[0]; - - selectedLocation = { key: "i'm a location key" }; - dialogResult = { - location: selectedLocation - }; - - resolution = resolver(dialogResult); - }); - - it("returns selectedLocation", function () { - expect(resolution).toBe(selectedLocation); - }); - }); - }); - }); - } -); diff --git a/platform/entanglement/test/services/MockCopyService.js b/platform/entanglement/test/services/MockCopyService.js deleted file mode 100644 index a2640f4ed6..0000000000 --- a/platform/entanglement/test/services/MockCopyService.js +++ /dev/null @@ -1,96 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * MockCopyService provides the same interface as the copyService, - * returning promises where it would normally do so. At it's core, - * it is a jasmine spy object, but it also tracks the promises it - * returns and provides shortcut methods for resolving those promises - * synchronously. - * - * Usage: - * - * ```javascript - * var copyService = new MockCopyService(); - * - * // validate is a standard jasmine spy. - * copyService.validate.and.returnValue(true); - * var isValid = copyService.validate(object, parentCandidate); - * expect(isValid).toBe(true); - * - * // perform returns promises and tracks them. - * var whenCopied = jasmine.createSpy('whenCopied'); - * copyService.perform(object, parentObject).then(whenCopied); - * expect(whenCopied).not.toHaveBeenCalled(); - * copyService.perform.calls.mostRecent().resolve('someArg'); - * expect(whenCopied).toHaveBeenCalledWith('someArg'); - * ``` - */ - function MockCopyService() { - // track most recent call of a function, - // perform automatically returns - var mockCopyService = jasmine.createSpyObj( - 'MockCopyService', - [ - 'validate', - 'perform' - ] - ); - - mockCopyService.perform.and.callFake(() => { - var performPromise, - callExtensions, - spy; - - performPromise = jasmine.createSpyObj( - 'performPromise', - ['then'] - ); - - callExtensions = { - promise: performPromise, - resolve: function (resolveWith) { - performPromise.then.calls.all().forEach(function (call) { - call.args[0](resolveWith); - }); - } - }; - - spy = mockCopyService.perform; - - Object.keys(callExtensions).forEach(function (key) { - spy.calls.mostRecent()[key] = callExtensions[key]; - spy.calls.all()[spy.calls.count() - 1][key] = callExtensions[key]; - }); - - return performPromise; - }); - - return mockCopyService; - } - - return MockCopyService; - } -); diff --git a/platform/entanglement/test/services/MockLinkService.js b/platform/entanglement/test/services/MockLinkService.js deleted file mode 100644 index 27d3801c3c..0000000000 --- a/platform/entanglement/test/services/MockLinkService.js +++ /dev/null @@ -1,86 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - [ - '../ControlledPromise' - ], - function (ControlledPromise) { - - /** - * MockLinkService provides the same interface as the linkService, - * returning promises where it would normally do so. At it's core, - * it is a jasmine spy object, but it also tracks the promises it - * returns and provides shortcut methods for resolving those promises - * synchronously. - * - * Usage: - * - * ```javascript - * var linkService = new MockLinkService(); - * - * // validate is a standard jasmine spy. - * linkService.validate.and.returnValue(true); - * var isValid = linkService.validate(object, parentObject); - * expect(isValid).toBe(true); - * - * // perform returns promises and tracks them. - * var whenLinked = jasmine.createSpy('whenLinked'); - * linkService.perform(object, parentObject).then(whenLinked); - * expect(whenLinked).not.toHaveBeenCalled(); - * linkService.perform.calls.mostRecent().promise.resolve('someArg'); - * expect(whenLinked).toHaveBeenCalledWith('someArg'); - * ``` - */ - function MockLinkService() { - // track most recent call of a function, - // perform automatically returns - var mockLinkService = jasmine.createSpyObj( - 'MockLinkService', - [ - 'validate', - 'perform' - ] - ); - - mockLinkService.perform.and.callFake(object => { - var performPromise = new ControlledPromise(); - - mockLinkService.perform.calls.mostRecent().promise = performPromise; - mockLinkService.perform.calls.all()[mockLinkService.perform.calls.count() - 1].promise = - performPromise; - - return performPromise.then(function (overrideObject) { - if (overrideObject) { - return overrideObject; - } - - return object; - }); - }); - - return mockLinkService; - } - - return MockLinkService; - } -); diff --git a/platform/exporters/ExportService.js b/platform/exporters/ExportService.js deleted file mode 100644 index 9dd49dd012..0000000000 --- a/platform/exporters/ExportService.js +++ /dev/null @@ -1,92 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * @namespace platform/exporters - */ -define(['csv'], function (CSV) { - - /** - * Callback used to initiate saving files from the export service; - * typical implementation is - * [FileSaver.js](https://github.com/eligrey/FileSaver.js/). - * @callback platform/exporters.ExportService~saveAs - * @param {Blob} blob the contents of the file to export - * @param {string} filename the name of the file to export - */ - - /** - * The `exportService` provides a means to initiate downloads of - * structured data in the CSV format. - * @param {platform/exporters.ExportService~saveAs} saveAs function - * used to initiate saving files - * @constructor - * @memberof platform/exporters - */ - function ExportService(saveAs) { - this.saveAs = saveAs; - } - - /** - * Export a set of data as comma-separated values. Triggers a download - * using the function provided when the ExportService was instantiated. - * - * @param {Object[]} rows an array of objects containing key-value pairs, - * where keys are header names, and values are values - * @param {ExportOptions} [options] additional parameters for the file - * export - */ - ExportService.prototype.exportCSV = function (rows, options) { - var headers = (options && options.headers) - || (Object.keys((rows[0] || {})).sort()), - filename = (options && options.filename) || "export.csv", - csvText = new CSV(rows, { header: headers }).encode(), - blob = new Blob([csvText], { type: "text/csv" }); - this.saveAs(blob, filename); - }; - - /** - * Export an object as a JSON file. Triggers a download using the function - * provided when the ExportService was instantiated. - * - * @param {Object} obj an object to be exported as JSON - * @param {ExportOptions} [options] additional parameters for the file - * export - */ - ExportService.prototype.exportJSON = function (obj, options) { - var filename = (options && options.filename) || "test-export.json"; - var jsonText = JSON.stringify(obj); - var blob = new Blob([jsonText], {type: "application/json"}); - this.saveAs(blob, filename); - }; - /** - * Additional parameters for file export. - * @typedef ExportOptions - * @property {string} filename the name of the file to write - * @property {string[]} headers column header names, both as they - * should appear in the output and as they should be - * used to look up values from the data set. Defaults - * to the keys in the first object in the data set. - */ - - return ExportService; -}); diff --git a/platform/exporters/ExportServiceSpec.js b/platform/exporters/ExportServiceSpec.js deleted file mode 100644 index ca06e74c86..0000000000 --- a/platform/exporters/ExportServiceSpec.js +++ /dev/null @@ -1,159 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ["./ExportService", "csv"], - function (ExportService, CSV) { - - describe("ExportService", function () { - var mockSaveAs, - testRows, - csvContents, - readCSVPromise, - exportService; - - beforeEach(function () { - var resolveFunction; - csvContents = undefined; - testRows = [ - { - a: 1, - b: 2, - c: 3 - }, - { - a: 4, - b: 5, - c: 6 - }, - { - a: 7, - b: 8, - c: 9 - } - ]; - mockSaveAs = jasmine.createSpy('saveAs'); - readCSVPromise = new Promise(function (resolve) { - resolveFunction = resolve; - }); - mockSaveAs.and.callFake(function (blob) { - var reader = new FileReader(); - reader.onloadend = function () { - csvContents = new CSV(reader.result).parse(); - resolveFunction(); - }; - - reader.readAsText(blob); - }); - exportService = new ExportService(mockSaveAs); - }); - - describe("#exportCSV(rows)", function () { - beforeEach(function () { - exportService.exportCSV(testRows); - - return readCSVPromise; - }); - - it("triggers saving of a file", function () { - expect(mockSaveAs).toHaveBeenCalledWith( - jasmine.any(Blob), - jasmine.any(String) - ); - }); - - it("includes headers from the data set", function () { - expect(csvContents[0]) - .toEqual(Object.keys(testRows[0]).sort()); - }); - - it("includes data from the data set", function () { - var headers = csvContents[0], - expectedData = testRows.map(function (row) { - return headers.map(function (key) { - return String(row[key]); - }); - }); - // Everything after header should be data - expect(csvContents.slice(1)).toEqual(expectedData); - }); - }); - - describe("#exportCSV(rows, options.headers)", function () { - var testHeaders; - - beforeEach(function () { - testHeaders = ['a', 'b']; - exportService - .exportCSV(testRows, { headers: testHeaders }); - - return readCSVPromise; - }); - - it("triggers saving of a file", function () { - expect(mockSaveAs).toHaveBeenCalledWith( - jasmine.any(Blob), - jasmine.any(String) - ); - }); - - it("includes only the specified headers", function () { - expect(csvContents[0]) - .toEqual(testHeaders); - expect(csvContents[0]) - .not.toEqual(Object.keys(testRows[0]).sort()); - }); - - it("includes a subset data from the data set", function () { - var headers = testHeaders, - expectedData = testRows.map(function (row) { - return headers.map(function (key) { - return String(row[key]); - }); - }); - expect(csvContents.slice(1)).toEqual(expectedData); - }); - }); - - describe("#exportCSV(rows, options.filename)", function () { - var testFilename; - - beforeEach(function () { - testFilename = "some-test-filename.csv"; - exportService - .exportCSV(testRows, { filename: testFilename }); - - return readCSVPromise; - }); - - it("saves a file with the specified name", function () { - expect(mockSaveAs).toHaveBeenCalledWith( - jasmine.any(Blob), - testFilename - ); - }); - }); - - }); - - } -); diff --git a/platform/exporters/bundle.js b/platform/exporters/bundle.js deleted file mode 100644 index 2ab4b449aa..0000000000 --- a/platform/exporters/bundle.js +++ /dev/null @@ -1,65 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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([ - "./ExportService", - "saveAs" -], function (ExportService, saveAs) { - - return { - name: "platform/exporters", - definition: { - extensions: { - services: [ - { - key: "exportService", - implementation: function () { - return new ExportService(saveAs.saveAs); - } - } - ], - licenses: [ - { - "name": "CSV.js", - "version": "3.6.4", - "author": "Kash Nouroozi", - "description": "Encoder for CSV (comma separated values) export", - "website": "https://github.com/knrz/CSV.js", - "copyright": "Copyright (c) 2014 Kash Nouroozi", - "license": "license-mit", - "link": "https://github.com/knrz/CSV.js/blob/3.6.4/LICENSE" - }, - { - "name": "FileSaver.js", - "version": "0.0.2", - "author": "Eli Grey", - "description": "File download initiator (for file exports)", - "website": "https://github.com/eligrey/FileSaver.js/", - "copyright": "Copyright © 2015 Eli Grey.", - "license": "license-mit", - "link": "https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md" - } - ] - } - } - }; -}); diff --git a/platform/features/README.md b/platform/features/README.md deleted file mode 100644 index c839461c4d..0000000000 --- a/platform/features/README.md +++ /dev/null @@ -1,3 +0,0 @@ -This directory contains bundles which represent specific user-facing -features of Open MCT, such as plots and other visualizations. -Bundles in this directory should be effectively optional. diff --git a/platform/features/pages/bundle.js b/platform/features/pages/bundle.js deleted file mode 100644 index 516db4ed7f..0000000000 --- a/platform/features/pages/bundle.js +++ /dev/null @@ -1,77 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/EmbeddedPageController", - "./res/iframe.html" -], function ( - EmbeddedPageController, - iframeTemplate -) { - - return { - name: "platform/features/pages", - definition: { - "extensions": { - "types": [ - { - "key": "example.page", - "name": "Web Page", - "cssClass": "icon-page", - "description": "Embed a web page or web-based image in a resizeable window component. Can be added to Display Layouts. Note that the URL being embedded must allow iframing.", - "priority": 50, - "features": [ - "creation" - ], - "properties": [ - { - "key": "url", - "name": "URL", - "control": "textfield", - "required": true, - "cssClass": "l-input-lg" - } - ] - } - ], - "views": [ - { - "template": iframeTemplate, - "name": "Page", - "type": "example.page", - "key": "example.page", - "editable": false - } - ], - "controllers": [ - { - "key": "EmbeddedPageController", - "implementation": EmbeddedPageController, - "depends": [ - "$sce" - ] - } - ] - } - } - }; -}); diff --git a/platform/features/static-markup/bundle.js b/platform/features/static-markup/bundle.js deleted file mode 100644 index 564481fb23..0000000000 --- a/platform/features/static-markup/bundle.js +++ /dev/null @@ -1,56 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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([ - - "./res/markup.html" -], function ( - markupTemplate -) { - - return { - name: "platform/features/static-markup", - definition: { - "extensions": { - "types": [ - { - "key": "static.markup", - "name": "Static Markup", - "cssClass": "icon-pencil", - "description": "Static markup sandbox", - "features": [ - "creation" - ] - } - ], - "views": [ - { - "template": markupTemplate, - "name": "Static Markup", - "type": "static.markup", - "key": "static.markup" - } - ] - } - } - }; -}); diff --git a/platform/features/static-markup/res/markup.html b/platform/features/static-markup/res/markup.html deleted file mode 100644 index 72d3c9c44e..0000000000 --- a/platform/features/static-markup/res/markup.html +++ /dev/null @@ -1,24 +0,0 @@ -

      Static Markup Sandbox

      - -

      Plot limits

      -
      -
      -
      -
      -
      -
      -
      -
      - -

      Animation

      -
      This should pulse
      diff --git a/platform/framework/README.md b/platform/framework/README.md deleted file mode 100644 index 5b5fbc8bc8..0000000000 --- a/platform/framework/README.md +++ /dev/null @@ -1,192 +0,0 @@ -Framework-level components for Open MCT. This is Angular and Require, -with an extra layer to mediate between them and act as an extension -mechanism to allow plug-ins to be introduced declaratively. - -# Usage - -This section needs to be written. For now, refer to implementation notes and -examples in `example/builtins`, `example/extensions`, and `example/composite`. - -## Circular dependencies - -The framework layer (like Angular itself) does not support circular -dependencies among extensions. Generally, circular dependencies can be -avoided by refactoring; for instance, a dependency-less intermediary can be -added by two parties which depend upon one another, and both can depend upon -this intermediary while one abandons its dependency to the other (the -intermediary must then provide the functionality that was needed in the -abandoned dependency.) - -In some cases this refactoring is non-obvious or ineffective (for instance, -when a service component depends upon the whole.) In these cases, Angular's -`$injector` may be used to break the declaration-time dependency, by allowing -retrieval of the dependency at use-time instead. (This is essentially the -same solution as above, where `$injector` acts as an application-global -generalized intermediary.) - -# Implementation Notes - -The framework layer is responsible for performing a four-stage initialization -process. These stages are: - -1. __Loading definitions.__ JSON declarations are loaded for all bundles which - will constitute the application, and wrapped in a useful API for subsequent - stages. _Sources in `src/load`_ -2. __Resolving extensions.__ Any scripts which provide implementations for - extensions exposed by bundles are loaded, using Require. - _Sources in `src/resolve`_ -3. __Registering extensions.__ Resolved extensions are registered with Angular, - such that they can be used by the application at run-time. This stage - includes both registration of Angular built-ins (directives, controllers, - routes, constants, and services) as well as registration of non-Angular - extensions. _Sources in `src/register`_ -4. __Bootstrapping.__ JSON declarations are loaded for all bundles which - will constitute the application, and wrapped in a useful API for subsequent - stages. _Sources in `src/bootstrap`_ - -Additionally, the framework layer takes responsibility for initializing -other application state. Currently this simply means adding Promise to the -global namespace if it is not defined. - -## Load stage - -Using Angular's `$http`, the list of installed bundles is loaded from -`bundles.json`; then, each bundle's declaration (its path + `bundle.json`) -is loaded. These are wrapped by `Bundle` objects, and the extensions they -expose are wrapped by `Extension` objects; this is only to provide a -useful API for subsequent stages. - -A bundle is a set of related extensions; an extension is an individual -unit of the application that is meant to be used by other pieces of the -application. - -## Resolution stage - -Some, but not all, individual extensions have corresponding scripts. -These are referred to by the `implementation` field in their extension -definition. The implementation name should not include the bundle path, -or the name of the source folder; these will be pre-pended by the framework -during this stage. The implementation name should include a `.js` extension. - -Bundles may utilize third-party libraries, and may wish to expose these such -that other bundles may use them. Require JS may need special configuration -to recognize and utilize third-party libraries, and when exposing a -third-party library it may be desirable to do so under a short name -(to avoid long relative paths.) Such configuration is performed during the -resolution stage, immediately before implementations are loaded. Any -`configuration` properties from a bundle's definition (`bundle.json`) will -be used to perform this configuration; these `configuration` should take -the same form as needed to populate a -[`require.config`](http://requirejs.org/docs/api.html#config) call. -At present, only `shim` and `paths` options are supported; any `paths` will -be prepended with the bundle's library path (the bundle's `lib` folder, by -default; this directory name can be overridden by specifying a `libraries` -property in `bundles.json`.) - -An extension is resolved by loading its implementing script, if one has been -declared. If none is declared, the extension's raw definition is used -instead. To ensure that extensions look similar regardless of whether or -not an implementation is present, all key-value pairs from the definition -are copied to the loaded implementation (if one has been loaded.) - -## Registration stage - -Following implementation resolution, extensions are registered by Angular. -How this registration occurs depends on whether or not there is built in -support for the category of extension being registered. - -* For _built-in_ extension types (recognized by Angular), these are - registered with the application module. These categories are `directives`, - `controllers`, `services`, `constants`, and `routes`. -* For _composite services_, extensions of category `components` are passed - to the service compositor, which builds up a dependency graph among - the components such that their fully-wired whole is exposed as a single - service. -* For _general extensions_, the resolved extensions are assembled into a - list, with Angular-level dependencies are declared, and the full set - is exposed as a single Angular "service." - -### Priority order - -Within each category, registration occurs in priority order. An extension's -priority may be specified as a `priority` property in its extension -definition; this may be a number, or a symbolic string. Extensions are -registered in reverse numeric order (highest-priority first), and symbolic -strings are mapped to the numeric values as follows: - -* `fallback`: Negative infinity. Used for extensions that are not intended - for use (that is, they are meant to be overridden) but are present as an - option of last resort. -* `default`: -100. Used for extensions that are expected to be overridden, but - need a useful default. -* `none`: 0. Also used if no priority is specified, or if an unknown or - malformed priority is specified. -* `optional`: 100. Used for extensions that are meant to be used, but may be - overridden. -* `preferred`: 1000. Used for extensions that are specifically intended to - be used, but still may be overridden in principle. -* `mandatory`: Positive infinity. Used when an extension should definitely - not be overridden. - -These symbolic names are chosen to reflect usage where many extensions may -satisfy a given usage, but only one may be used; in this case, as a -convention it should be the lowest-ordered (highest-priority) extensions -available. In other cases, a full set (or multi-element subset) of -extensions may be desired, with a specific ordering; in these cases, it -is preferable to specify priority numerically when declaring extensions, -and to understand that extensions will be sorted according to these -conventions when using them. - -### Composite services - -Composite services are assumed to follow a provider-aggregator-decorator -pattern where: - -* _Providers_ have dependencies as usual, and expose the API associated - with the service they compose. Providers are full service implementations - in-and-of-themselves. -* _Aggregators_ have dependencies as usual plus one additional dependency, - which will be satisfied by the array of all providers registered of - that type of service. Implementations are assumed to include an extra - argument (after what they declare in `depends`) to receive this array. - Aggregators make multiple providers appear as one. -* _Decorators_ have dependencies as usual plus one additional dependency, - which will be satisfied by either an aggregator (if one is present), - the latest provider (if no aggregator is present), or another decorator - (if multiple decorators are present.) As with aggregators, an additional - argument should be accepted by the implementation to receive this. - Decorators modify or augment the behavior of a service, but do not - provide its core functionality. -* All of the above must be declared with a `provides` property, which - indicates which type of service they compose. Providers will only be - paired with aggregators of matching types, and so on. The value of - this property is also the name of the service that is ultimately - registered with Angular to represent the composite service as a whole. - -The service compositor handles this in five steps: - -1. All providers are registered. -2. Arrays of providers are registered. -3. All aggregators are registered (with dependencies to the arrays - registered in the previous step.) -4. All decorators are registered (with dependencies on the most recent - components of matching types.) -5. Full composite services are registered (essentially aliasing back - to the latest component registered of a given type.) - -Throughout these steps, components are registered with Angular using -generated names like `typeService[decorator#11]`. It is technically possible -to reference these dependencies elsewhere but that is not the intent. -Rather, the resulting composed service should be referred to as -`typeService` (or, more generally, the value matched from the `provides` -field of the paired service components.) - -### General extensions - -Similar to composite services, each individual general extension gets -registered using a generated name, like `types[extension#0]`. These are -not intended to be referenced directly; instead, they are declared -dependencies of the full list of general extensions of a given category. -This list of extensions is registered with a square-brackets suffix, -like `types[]`; this _is_ intended to be declared as a dependency by -non-framework code. diff --git a/platform/framework/bundle.js b/platform/framework/bundle.js deleted file mode 100644 index fdd3c89ebb..0000000000 --- a/platform/framework/bundle.js +++ /dev/null @@ -1,107 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - return { - name: "platform/framework", - definition: { - "name": "Open MCT Framework Component", - "description": "Framework layer for Open MCT; interprets bundle definitions and serves as an intermediary between Require and Angular", - "libraries": "lib", - "configuration": { - "paths": { - "angular": "angular.min" - }, - "shim": { - "angular": { - "exports": "angular" - } - } - }, - "extensions": { - "licenses": [ - { - "name": "Blanket.js", - "version": "1.1.5", - "description": "Code coverage measurement and reporting", - "author": "Alex Seville", - "website": "http://blanketjs.org/", - "copyright": "Copyright(c) 2013 Alex Seville", - "license": "license-mit", - "link": "http://opensource.org/licenses/MIT" - }, - { - "name": "Jasmine", - "version": "1.3.1", - "description": "Unit testing", - "author": "Pivotal Labs", - "website": "http://jasmine.github.io/", - "copyright": "Copyright(c) 2008-2011 Pivotal Labs", - "license": "license-mit", - "link": "http://opensource.org/licenses/MIT" - }, - { - "name": "RequireJS", - "version": "2.1.22", - "description": "Script loader", - "author": "The Dojo Foundation", - "website": "http://requirejs.org/", - "copyright": "Copyright(c) 2010-2015, The Dojo Foundation", - "license": "license-mit", - "link": "https://github.com/jrburke/requirejs/blob/master/LICENSE" - }, - { - "name": "AngularJS", - "version": "1.4.4", - "description": "Client-side web application framework", - "author": "Google", - "website": "http://angularjs.org/", - "copyright": "Copyright(c) 2010-2015 Google, Inc. http://angularjs.org", - "license": "license-mit", - "link": "https://github.com/angular/angular.js/blob/v1.4.4/LICENSE" - }, - { - "name": "Angular-Route", - "version": "1.4.4", - "description": "Client-side view routing", - "author": "Google", - "website": "http://angularjs.org/", - "copyright": "Copyright(c) 2010-2015 Google, Inc. http://angularjs.org", - "license": "license-mit", - "link": "https://github.com/angular/angular.js/blob/v1.4.4/LICENSE" - }, - { - "name": "ES6-Promise", - "version": "3.0.2", - "description": "Promise polyfill for pre-ECMAScript 6 browsers", - "author": "Yehuda Katz, Tom Dale, Stefan Penner and contributors", - "website": "https://github.com/jakearchibald/es6-promise", - "copyright": "Copyright(c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors", - "license": "license-mit", - "link": "https://github.com/jakearchibald/es6-promise/blob/master/LICENSE" - } - ] - } - } - }; -}); diff --git a/platform/framework/src/Constants.js b/platform/framework/src/Constants.js deleted file mode 100644 index f4e84b0bf0..0000000000 --- a/platform/framework/src/Constants.js +++ /dev/null @@ -1,48 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * Constants used by the framework layer. - */ -define({ - MODULE_NAME: "OpenMCTWeb", - BUNDLE_FILE: "bundle.json", - SEPARATOR: "/", - EXTENSION_SUFFIX: "[]", - DEFAULT_BUNDLE: { - "sources": "src", - "resources": "res", - "libraries": "lib", - "tests": "test", - "configuration": {}, - "extensions": {} - }, - PRIORITY_LEVELS: { - "fallback": Number.NEGATIVE_INFINITY, - "default": -100, - "none": 0, - "optional": 100, - "preferred": 1000, - "mandatory": Number.POSITIVE_INFINITY - }, - DEFAULT_PRIORITY: 0 -}); diff --git a/platform/framework/src/FrameworkInitializer.js b/platform/framework/src/FrameworkInitializer.js deleted file mode 100644 index 08e41f7dbb..0000000000 --- a/platform/framework/src/FrameworkInitializer.js +++ /dev/null @@ -1,73 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 FrameworkInitializer. Created by vwoeltje on 11/3/14. - */ -define( - [], - function () { - - /** - * Responsible for managing the four stages of framework - * initialization: - * - * * Loading bundle metadata (JSON files) - * * Resolving extension implementations with Require - * * Registering extensions with Angular - * * Bootstrapping the Angular application. - * - * @memberof platform/framework - * @constructor - * @param {platform/framework.BundleLoader} loader - * @param {platform/framework.BundleResolver} resolver - * @param {platform/framework.ExtensionRegistrar} registrar - * @param {platform/framework.ApplicationBootstrapper} bootstrapper - */ - function FrameworkInitializer(loader, resolver, registrar, bootstrapper) { - this.loader = loader; - this.resolver = resolver; - this.registrar = registrar; - this.bootstrapper = bootstrapper; - } - - function bind(method, thisArg) { - return function () { - return method.apply(thisArg, arguments); - }; - } - - /** - * Run the application defined by this set of bundles. - * @param bundleList - * @returns {*} - */ - FrameworkInitializer.prototype.runApplication = function () { - return this.loader.loadBundles([]) - .then(bind(this.resolver.resolveBundles, this.resolver)) - .then(bind(this.registrar.registerExtensions, this.registrar)) - .then(bind(this.bootstrapper.bootstrap, this.bootstrapper)); - }; - - return FrameworkInitializer; - } -); diff --git a/platform/framework/src/FrameworkLayer.js b/platform/framework/src/FrameworkLayer.js deleted file mode 100644 index b44337edc4..0000000000 --- a/platform/framework/src/FrameworkLayer.js +++ /dev/null @@ -1,104 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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([ - './Constants', - './FrameworkInitializer', - './LogLevel', - './load/BundleLoader', - './resolve/ImplementationLoader', - './resolve/ExtensionResolver', - './resolve/BundleResolver', - './register/CustomRegistrars', - './register/ExtensionRegistrar', - './register/ExtensionSorter', - './bootstrap/ApplicationBootstrapper' -], function ( - Constants, - FrameworkInitializer, - LogLevel, - BundleLoader, - ImplementationLoader, - ExtensionResolver, - BundleResolver, - CustomRegistrars, - ExtensionRegistrar, - ExtensionSorter, - ApplicationBootstrapper -) { - - function FrameworkLayer($http, $log) { - this.$http = $http; - this.$log = $log; - } - - FrameworkLayer.prototype.initializeApplication = function ( - angular, - openmct, - logLevel - ) { - var $http = this.$http, - $log = this.$log, - app = angular.module(Constants.MODULE_NAME, ["ngRoute"]), - loader = new BundleLoader($http, $log, openmct.legacyRegistry), - resolver = new BundleResolver( - new ExtensionResolver( - new ImplementationLoader({}), - $log - ), - $log - ), - registrar = new ExtensionRegistrar( - app, - new CustomRegistrars(app, $log), - new ExtensionSorter($log), - $log - ), - bootstrapper = new ApplicationBootstrapper( - angular, - openmct.element, - $log - ), - initializer = new FrameworkInitializer( - loader, - resolver, - registrar, - bootstrapper - ); - - // Override of angular1.6 ! hashPrefix - app.config(['$locationProvider', function ($locationProvider) { - $locationProvider.hashPrefix(''); - }]); - - // Apply logging levels; this must be done now, before the - // first log statement. - new LogLevel(logLevel).configure(app, $log); - - // Initialize the application - $log.info("Initializing application."); - - return initializer.runApplication(); - }; - - return FrameworkLayer; -}); diff --git a/platform/framework/src/LogLevel.js b/platform/framework/src/LogLevel.js deleted file mode 100644 index 13da83e335..0000000000 --- a/platform/framework/src/LogLevel.js +++ /dev/null @@ -1,100 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - // Log levels; note that these must be in order of - // most-important-first for LogLevel to function correctly - // as implemented. - var LOG_LEVELS = [ - 'error', - 'warn', - 'info', - 'log', - 'debug' - ]; - - // No-op, to replace undesired log levels with - function NOOP() {} - - /** - * Handles enforcement of logging at different levels, specified - * at load time. The provided level should be one of "error", - * "warn", "info", "log", or "debug"; otherwise, "warn" is used - * as a default. Only log messages of levels equal to or greater - * than the specified level will be passed to console. - * - * @memberof platform/framework - * @constructor - * @param {string} level the logging level - */ - function LogLevel(level) { - // Find the numeric level associated with the string - this.index = LOG_LEVELS.indexOf(level); - - // Default to 'warn' level if unspecified - if (this.index < 0) { - this.index = 1; - } - } - - /** - * Configure logging to suppress log output if it is - * not of an appropriate level. Both the Angular app - * being initialized and a reference to `$log` should be - * passed; the former is used to configure application - * logging, while the latter is needed to apply the - * same configuration during framework initialization - * (since the framework also logs.) - * - * @param app the Angular app to configure - * @param $log Angular's $log (also configured) - * @memberof platform/framework.LogLevel# - */ - LogLevel.prototype.configure = function (app, $log) { - var index = this.index; - - // Replace logging methods with no-ops, if they are - // not of an appropriate level. - function decorate(log) { - LOG_LEVELS.forEach(function (m, i) { - // Determine applicability based on index - // (since levels are in descending order) - if (i > index) { - log[m] = NOOP; - } - }); - } - - decorate($log); - app.decorator('$log', ['$delegate', function ($delegate) { - decorate($delegate); - - return $delegate; - }]); - }; - - return LogLevel; - } -); diff --git a/platform/framework/src/Main.js b/platform/framework/src/Main.js deleted file mode 100644 index fd861e9ab5..0000000000 --- a/platform/framework/src/Main.js +++ /dev/null @@ -1,60 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * Implements the framework layer, which handles the loading of bundles - * and the wiring-together of the extensions they expose. - * @namespace platform/framework - */ -define( - [ - './FrameworkLayer', - 'angular', - 'angular-route' - ], - function ( - FrameworkLayer, - angular - ) { - - function Main() { - } - - Main.prototype.run = function (openmct) { - // Get a reference to Angular's injector, so we can get $http and $log - // services, which are useful to the framework layer. - var injector = angular.injector(['ng']); - - // Look up log level from query string - function logLevel() { - var match = /[?&]log=([a-z]+)/.exec(window.location.search); - - return match ? match[1] : ""; - } - - return injector.instantiate(['$http', '$log', FrameworkLayer]) - .initializeApplication(angular, openmct, logLevel()); - }; - - return Main; - } -); diff --git a/platform/framework/src/bootstrap/ApplicationBootstrapper.js b/platform/framework/src/bootstrap/ApplicationBootstrapper.js deleted file mode 100644 index 2984ef28d8..0000000000 --- a/platform/framework/src/bootstrap/ApplicationBootstrapper.js +++ /dev/null @@ -1,70 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 Bootstrapper. Created by vwoeltje on 11/4/14. - * - * The bootstrapper is responsible - */ -define( - [], - function () { - - /** - * The application bootstrapper is responsible for issuing the - * bootstrap call to Angular. This would normally not be needed - * with an appropriately-placed ng-app directive, but the - * framework needs to wait until all extensions have been loaded - * and registered. - * - * @memberof platform/framework - * @constructor - */ - function ApplicationBootstrapper(angular, document, $log) { - this.angular = angular; - this.document = document; - this.$log = $log; - } - - /** - * Bootstrap the application. - * - * @param {angular.Module} app the Angular application to - * bootstrap - */ - ApplicationBootstrapper.prototype.bootstrap = function (app) { - var angular = this.angular, - document = this.document, - $log = this.$log; - - return new Promise(function (resolve, reject) { - $log.info("Bootstrapping application " + (app || {}).name); - angular.element(document).ready(function () { - angular.bootstrap(document, [app.name], { strictDi: true }); - resolve(angular); - }); - }); - }; - - return ApplicationBootstrapper; - } -); diff --git a/platform/framework/src/load/Bundle.js b/platform/framework/src/load/Bundle.js deleted file mode 100644 index 5b7c177e65..0000000000 --- a/platform/framework/src/load/Bundle.js +++ /dev/null @@ -1,207 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['../Constants', './Extension'], - function (Constants, Extension) { - - /** - * A bundle's plain JSON definition. - * - * @name BundleDefinition - * @property {string} name the human-readable name of this bundle - * @property {string} sources the name of the directory which - * contains source code used by this bundle - * @property {string} resources the name of the directory which - * contains resource files used by this bundle - * @property {Object.} [extensions={}] - * all extensions exposed by this bundle - * @constructor - * @memberof platform/framework - */ - - /** - * Instantiate a new reference to a bundle, based on its human-readable - * definition. - * - * @param {string} path the path to the directory containing - * this bundle - * @param {BundleDefinition} bundleDefinition - * @returns {{getDefinition: Function}} - * @constructor - */ - function Bundle(path, bundleDefinition) { - // Start with defaults - var definition = Object.create(Constants.DEFAULT_BUNDLE), - logName = path; - - // Override defaults with specifics from bundle definition - Object.keys(bundleDefinition).forEach(function (k) { - definition[k] = bundleDefinition[k]; - }); - - // Record path to bundle in definition - definition.path = path; - - // Build up the log-friendly name for this bundle - if (definition.key || definition.name) { - logName += "("; - logName += definition.key || ""; - logName += (definition.key && definition.name) ? " " : ""; - logName += definition.name || ""; - logName += ")"; - } - - this.path = path; - this.definition = definition; - this.logName = logName; - } - - // Utility function for resolving paths in this bundle - Bundle.prototype.resolvePath = function (elements) { - var path = this.path; - - return [path].concat(elements || []).join(Constants.SEPARATOR); - }; - - /** - * Get the path to this bundle. - * @returns {string} path to this bundle; - */ - Bundle.prototype.getPath = function () { - return this.path; - }; - - /** - * Get the path to this bundle's source folder. If an - * argument is provided, the path will be to the source - * file within the bundle's source file. - * - * @param {string} [sourceFile] optionally, give a path to - * a specific source file in the bundle. - * @returns {string} path to the source folder (or to the - * source file within it) - */ - Bundle.prototype.getSourcePath = function (sourceFile) { - var subpath = sourceFile - ? [this.definition.sources, sourceFile] - : [this.definition.sources]; - - return this.resolvePath(subpath); - }; - - /** - * Get the path to this bundle's resource folder. If an - * argument is provided, the path will be to the resource - * file within the bundle's resource file. - * - * @param {string} [resourceFile] optionally, give a path to - * a specific resource file in the bundle. - * @returns {string} path to the resource folder (or to the - * resource file within it) - */ - Bundle.prototype.getResourcePath = function (resourceFile) { - var subpath = resourceFile - ? [this.definition.resources, resourceFile] - : [this.definition.resources]; - - return this.resolvePath(subpath); - }; - - /** - * Get the path to this bundle's library folder. If an - * argument is provided, the path will be to the library - * file within the bundle's resource file. - * - * @param {string} [libraryFile] optionally, give a path to - * a specific library file in the bundle. - * @returns {string} path to the resource folder (or to the - * resource file within it) - */ - Bundle.prototype.getLibraryPath = function (libraryFile) { - var subpath = libraryFile - ? [this.definition.libraries, libraryFile] - : [this.definition.libraries]; - - return this.resolvePath(subpath); - }; - - /** - * Get library configuration for this bundle. This is read - * from the bundle's definition; if the bundle is well-formed, - * it will resemble a require.config object. - * @returns {object} library configuration - */ - Bundle.prototype.getConfiguration = function () { - return this.definition.configuration || {}; - }; - - /** - * Get a log-friendly name for this bundle; this will - * include both the key (machine-readable name for this - * bundle) and the name (human-readable name for this - * bundle.) - * @returns {string} log-friendly name for this bundle - */ - Bundle.prototype.getLogName = function () { - return this.logName; - }; - - /** - * Get all extensions exposed by this bundle of a given - * category. - * - * @param {string} category name of the extension category - * @returns {Array} extension definitions of that category - */ - Bundle.prototype.getExtensions = function (category) { - var extensions = this.definition.extensions[category] || [], - self = this; - - return extensions.map(function objectify(extDefinition) { - return new Extension(self, category, extDefinition); - }); - }; - - /** - * Get a list of all extension categories exposed by this bundle. - * - * @returns {string[]} the extension categories - */ - Bundle.prototype.getExtensionCategories = function () { - return Object.keys(this.definition.extensions); - }; - - /** - * Get the plain definition of this bundle, as read from - * its JSON declaration. - * - * @returns {platform/framework.BundleDefinition} the raw - * definition of this bundle - */ - Bundle.prototype.getDefinition = function () { - return this.definition; - }; - - return Bundle; - } -); diff --git a/platform/framework/src/load/BundleLoader.js b/platform/framework/src/load/BundleLoader.js deleted file mode 100644 index ed872f7752..0000000000 --- a/platform/framework/src/load/BundleLoader.js +++ /dev/null @@ -1,160 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 BundleLoader.js. Created by vwoeltje on 10/31/14. - */ -define( - ['../Constants', './Bundle'], - function (Constants, Bundle) { - - var INVALID_ARGUMENT_MESSAGE = "Malformed loadBundles argument; " - + "expected string or array", - BAD_CONTENTS_PREFIX = "Invalid bundle contents for ", - LOAD_ERROR_PREFIX = "Failed to load bundle "; - - /** - * Loads bundle definitions and wraps them in interfaces which are - * useful to the framework. This provides the base information which - * will be used by later phases of framework layer initialization. - * - * @memberof platform/framework - * @constructor - * @param $http Angular's HTTP requester - * @param $log Angular's logging service - */ - function BundleLoader($http, $log, legacyRegistry) { - this.$http = $http; - this.$log = $log; - this.legacyRegistry = legacyRegistry; - } - - /** - * Load a group of bundles, to be used to constitute the - * application by later framework initialization phases. - * - * @param {string|string[]} an array of bundle names to load, or - * the name of a JSON file containing that array - * @returns {Promise.} a promise for the loaded bundles - */ - BundleLoader.prototype.loadBundles = function (bundles) { - var $http = this.$http, - $log = this.$log, - legacyRegistry = this.legacyRegistry; - - // Utility function; load contents of JSON file using $http - function getJSON(file) { - return $http.get(file).then(function (response) { - return response.data; - }); - } - - // Remove bundles which failed to load properly. - // These should have been logged when loaded by - // loadBundleDefinition, so at this point they are safe - // to discard. - function filterBundles(array) { - return array.filter(function (x) { - return x !== undefined; - }); - } - - // Load a definition for a bundle - function loadBundleDefinition(bundlePath) { - return getJSON(bundlePath + "/" + Constants.BUNDLE_FILE).then( - function (x) { - if (x === null || typeof x !== 'object') { - $log.warn(BAD_CONTENTS_PREFIX + bundlePath); - - return undefined; - } - - return x; - }, - function () { - $log.warn(LOAD_ERROR_PREFIX + bundlePath); - - return undefined; - } - ); - } - - // Load an individual bundle, as a Bundle object. - // Returns undefined if the definition could not be loaded. - function loadBundle(bundlePath) { - if (legacyRegistry.contains(bundlePath)) { - return Promise.resolve(new Bundle( - bundlePath, - legacyRegistry.get(bundlePath) - )); - } - - return loadBundleDefinition(bundlePath).then(function (definition) { - return definition && (new Bundle(bundlePath, definition)); - }); - } - - // Used to filter out redundant bundles - function unique(element, index, array) { - return array.indexOf(element) === index; - } - - // Load all named bundles from the array, returned as an array - // of Bundle objects. - function loadBundlesFromArray(bundleArray) { - var bundlePromises = legacyRegistry.list() - .concat(bundleArray) - .filter(unique) - .map(loadBundle); - - return Promise.all(bundlePromises) - .then(filterBundles); - } - - // Load all bundles named in the referenced file. The file is - // presumed to be a JSON file - function loadBundlesFromFile(listFile) { - function handleError(err) { - $log.info([ - "No external bundles loaded;", - "could not load bundle listing in", - listFile, - "due to error", - err.status, - err.statusText - ].join(' ')); - - return loadBundlesFromArray([]); - } - - return getJSON(listFile) - .then(loadBundlesFromArray, handleError); - } - - return Array.isArray(bundles) ? loadBundlesFromArray(bundles) - : (typeof bundles === 'string') ? loadBundlesFromFile(bundles) - : Promise.reject(new Error(INVALID_ARGUMENT_MESSAGE)); - }; - - return BundleLoader; - } -); diff --git a/platform/framework/src/load/Extension.js b/platform/framework/src/load/Extension.js deleted file mode 100644 index ed1d0e3fc6..0000000000 --- a/platform/framework/src/load/Extension.js +++ /dev/null @@ -1,190 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 extension's plain JSON definition. - * - * @name ExtensionDefinition - * @property {string} [key] the machine-readable identifier for this - * extension - * @property {string} [implementation] the path to the AMD module - * which implements this extension; this path is relative - * to the containing bundle's source folder. - * @property {string[]} [depends=[]] the dependencies needed by this - * extension; these are strings as shall be passed to - * Angular's dependency resolution mechanism. - * @constructor - * @memberof platform/framework - */ - - /** - * Instantiate a new extension based on its definition. This serves - * primarily as a wrapper around the extension's definition to expose - * a useful interface. - * - * An extension - * - * @param {Bundle} bundle the bundle which exposed this extension - * @param {string} category the type of extension being exposed - * @param {ExtensionDefinition} definition the plain definition of - * this extension - * @constructor - */ - function Extension(bundle, category, definition) { - var logName = category, - extensionDefinition = {}; - - // Build up the log-friendly name for this bundle - if (definition.key || definition.name) { - logName += "("; - logName += definition.key || ""; - logName += (definition.key && definition.name) ? " " : ""; - logName += definition.name || ""; - logName += ")"; - } - - logName += " from " + bundle.getLogName(); - - // Copy over definition. This allows us to attach the bundle - // definition without modifying the original definition object. - Object.keys(definition).forEach(function (k) { - extensionDefinition[k] = definition[k]; - }); - - // Attach bundle metadata - extensionDefinition.bundle = bundle.getDefinition(); - - this.logName = logName; - this.bundle = bundle; - this.category = category; - this.definition = definition; - this.extensionDefinition = extensionDefinition; - } - - /** - * Get the machine-readable identifier for this extension. - * - * @returns {string} the identifier for this extension - */ - Extension.prototype.getKey = function () { - return this.definition.key || "undefined"; - }; - - /** - * Get the bundle which declared this extension. - * - * @returns {Bundle} the declaring bundle - */ - Extension.prototype.getBundle = function () { - return this.bundle; - }; - - /** - * Get the category into which this extension falls. - * (e.g. "directives") - * - * @returns {string} the extension category - */ - Extension.prototype.getCategory = function () { - return this.category; - }; - - /** - * Check whether or not this extension should have an - * associated implementation module which may need to - * be loaded. - * - * @returns {boolean} true if an implementation separate - * from this definition should also be loaded - */ - Extension.prototype.hasImplementation = function () { - return this.definition.implementation !== undefined; - }; - - /** - * Get the path to the AMD module which implements this - * extension. Will return undefined if there is no - * implementation associated with this extension. - * - * @returns {string} path to implementation, or undefined - */ - Extension.prototype.getImplementationPath = function () { - return (this.hasImplementation() && !this.hasImplementationValue()) - ? this.bundle.getSourcePath(this.definition.implementation) - : undefined; - }; - - /** - * Check if an extension has an actual implementation value - * (and not just a path to an implementation) defined. - * @returns {function} the constructor for this extension instance - */ - Extension.prototype.getImplementationValue = function () { - return typeof this.definition.implementation === 'function' - ? this.definition.implementation - : undefined; - }; - - /** - * Check if an extension has an actual implementation value - * (and not just a path to an implementation) defined. - * @returns {boolean} true if a value is available - */ - Extension.prototype.hasImplementationValue = function () { - return typeof this.definition.implementation === 'function'; - }; - - /** - * Get a log-friendly name for this extension; this will - * include both the key (machine-readable name for this - * extension) and the name (human-readable name for this - * extension.) - * - * @returns {string} log-friendly name for this extension - */ - Extension.prototype.getLogName = function () { - return this.logName; - }; - - /** - * Get the plain definition of the extension. - * - * Note that this definition will have an additional "bundle" - * field which points back to the bundle which defined the - * extension, as a convenience. - * - * @returns {ExtensionDefinition} the plain definition of - * this extension, as read from the bundle - * declaration. - */ - Extension.prototype.getDefinition = function () { - return this.extensionDefinition; - }; - - return Extension; - - } -); diff --git a/platform/framework/src/register/CustomRegistrars.js b/platform/framework/src/register/CustomRegistrars.js deleted file mode 100644 index cbb3b788fa..0000000000 --- a/platform/framework/src/register/CustomRegistrars.js +++ /dev/null @@ -1,248 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ -/* eslint-disable no-invalid-this */ - -/** - * Module defining CustomRegistrars. Created by vwoeltje on 11/3/14. - */ -define( - ['../Constants', './ServiceCompositor'], - function (Constants, ServiceCompositor) { - /*jshint validthis:true */ - - /** - * Handles registration of a few specific extension types that are - * understood natively by Angular. This includes services and - * directives. - * @memberof platform/framework - * @constructor - */ - function CustomRegistrars(app, $log) { - this.app = app; - this.$log = $log; - this.registered = {}; // Track registered keys by extension - } - - // Utility; bind a function to a "this" pointer - function bind(fn, thisArg) { - return function () { - return fn.apply(thisArg, arguments); - }; - } - - // Used to create custom registration functions which map to - // named methods on Angular modules, which follow the normal - // app.method(key, [ deps..., function ]) pattern. - function customRegistrar(angularFunction) { - return function (extension, index) { - var app = this.app, - $log = this.$log, - key = extension.key, - dependencies = extension.depends || [], - registered = this.registered[angularFunction] || {}; - - this.registered[angularFunction] = registered; - - if (!key) { - $log.warn([ - "Cannot register ", - angularFunction, - " ", - index, - ", no key specified. ", - JSON.stringify(extension) - ].join("")); - } else if (registered[key]) { - $log.debug([ - "Already registered ", - angularFunction, - " with key ", - key, - "; skipping." - ].join("")); - } else { - $log.info([ - "Registering ", - angularFunction, - ": ", - key - ].join("")); - registered[key] = true; - app[angularFunction]( - key, - dependencies.concat([extension]) - ); - } - }; - } - - function registerConstant(extension) { - var app = this.app, - $log = this.$log, - key = extension.key, - value = extension.value; - - if (typeof key === "string" && value !== undefined) { - $log.info([ - "Registering constant: ", - key, - " with value ", - value - ].join("")); - app.constant(key, value); - } else { - $log.warn([ - "Cannot register constant ", - key, - " with value ", - value - ].join("")); - } - - } - - // Custom registration function for extensions of category "runs" - function registerRun(extension) { - var app = this.app, - $log = this.$log; - - if (typeof extension === 'function') { - // Prepend dependencies, and schedule to run - app.run((extension.depends || []).concat([extension])); - } else { - // If it's not a function, no implementation was given - $log.warn([ - "Cannot register run extension from ", - (extension.bundle || {}).path, - "; no implementation." - ].join("")); - } - } - - // Custom registration function for extensions of category "route" - function registerRoute(extension) { - var app = this.app, - $log = this.$log, - route = Object.create(extension); - - // Adjust path for bundle - if (route.templateUrl) { - route.templateUrl = [ - route.bundle.path, - route.bundle.resources, - route.templateUrl - ].join(Constants.SEPARATOR); - } - - // Log the registration - $log.info("Registering route: " + (route.key || route.when)); - - // Register the route with Angular - app.config(['$routeProvider', function ($routeProvider) { - if (route.when) { - $routeProvider.when(route.when, route); - } else { - $routeProvider.otherwise(route); - } - }]); - } - - // Handle service compositing - function registerComponents(components) { - var app = this.app, - $log = this.$log; - - return new ServiceCompositor(app, $log) - .registerCompositeServices(components); - } - - // Utility; create a function which converts another function - // (which acts on single objects) to one which acts upon arrays. - function mapUpon(func) { - return function (array) { - return array.map(bind(func, this)); - }; - } - - // More like key-value pairs than methods; key is the - // name of the extension category to be handled, and the value - // is the function which handles it. - - /** - * Register constant values. - * @param {Array} extensions the resolved extensions - */ - CustomRegistrars.prototype.constants = - mapUpon(registerConstant); - - /** - * Register Angular routes. - * @param {Array} extensions the resolved extensions - */ - CustomRegistrars.prototype.routes = - mapUpon(registerRoute); - - /** - * Register Angular directives. - * @param {Array} extensions the resolved extensions - */ - CustomRegistrars.prototype.directives = - mapUpon(customRegistrar("directive")); - - /** - * Register Angular controllers. - * @param {Array} extensions the resolved extensions - */ - CustomRegistrars.prototype.controllers = - mapUpon(customRegistrar("controller")); - - /** - * Register Angular services. - * @param {Array} extensions the resolved extensions - */ - CustomRegistrars.prototype.services = - mapUpon(customRegistrar("service")); - - /** - * Register Angular filters. - * @param {Array} extensions the resolved extensions - */ - CustomRegistrars.prototype.filters = - mapUpon(customRegistrar("filter")); - - /** - * Register functions which will run after bootstrapping. - * @param {Array} extensions the resolved extensions - */ - CustomRegistrars.prototype.runs = - mapUpon(registerRun); - - /** - * Register components of composite services. - * @param {Array} extensions the resolved extensions - */ - CustomRegistrars.prototype.components = - registerComponents; - - return CustomRegistrars; - } -); diff --git a/platform/framework/src/register/ExtensionRegistrar.js b/platform/framework/src/register/ExtensionRegistrar.js deleted file mode 100644 index 8f05cad5a4..0000000000 --- a/platform/framework/src/register/ExtensionRegistrar.js +++ /dev/null @@ -1,232 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ExtensionRegistrar. Created by vwoeltje on 11/3/14. - */ -define( - ['../Constants', './PartialConstructor'], - function (Constants, PartialConstructor) { - - /** - * Responsible for registering extensions with Angular. - * - * @memberof platform/framework - * @constructor - * @param {angular.Module} the Angular application with which - * extensions should be registered - * @param {Object.} customRegistrars an object - * containing custom registration functions, primarily for - * Angular built-ins. - * @param {ExtensionSorter} sorter the sorter which will impose - * priority ordering upon extensions - * @param {*} $log Angular's logging service - */ - function ExtensionRegistrar(app, customRegistrars, sorter, $log) { - // Track which extension categories have already been registered. - // Exceptions will be thrown if the same extension category is - // registered twice. - this.registeredCategories = {}; - this.customRegistrars = customRegistrars || {}; - this.app = app; - this.sorter = sorter; - this.$log = $log; - } - - /** - * Register a group of resolved extensions with the Angular - * module managed by this registrar. - * - * For convenient chaining (particularly from the framework - * initializer's perspective), this returns the Angular - * module with which extensions were registered. - * - * @param {Object.} extensionGroup an object - * containing key-value pairs, where keys are extension - * categories and values are arrays of resolved - * extensions - * @returns {angular.Module} the application module with - * which extensions were registered - */ - ExtensionRegistrar.prototype.registerExtensions = function (extensionGroup) { - var registeredCategories = this.registeredCategories, - customRegistrars = this.customRegistrars, - app = this.app, - sorter = this.sorter, - $log = this.$log; - - // Used to build unique identifiers for individual extensions, - // so that these can be registered separately with Angular - function identify(category, extension, index) { - var name = extension.key - ? ("extension-" + extension.key + "#" + index) - : ("extension#" + index); - - return category + "[" + name + "]"; - } - - // Echo arguments; used to represent groups of non-built-in - // extensions as a single dependency. - function echo() { - return Array.prototype.slice.call(arguments); - } - - // Always return a static value; used to represent plain - // metadata as a single dependency in Angular. - function staticFunction(value) { - return function () { - return value; - }; - } - - // Utility function; create the second argument for Angular's - // .service service registration method (an array containing - // both dependencies and a factory method for the service.) - function makeServiceArgument(category, extension) { - var dependencies = extension.depends || [], - factory = (typeof extension === 'function') - ? new PartialConstructor(extension) - : staticFunction(extension); - - return dependencies.concat([factory]); - } - - // Register extension arrays with Angular under an appropriately - // suffixed name, e.g. "types[]" - function registerExtensionArraysForCategory(category, names) { - var name = category + Constants.EXTENSION_SUFFIX; - app.factory(name, names.concat([echo])); - } - - function registerExtensionsForCategory(category, extensions) { - var names = []; - - function registerExtension(extension, index) { - var name = identify(category, extension, index); - - // Track individual extension names as-registered - names.push(name); - - app.factory( - name, - makeServiceArgument(category, extension) - ); - } - - if (registeredCategories[category]) { - $log.warn([ - "Tried to register extensions for category ", - category, - " more than once. Ignoring all but first set." - ].join("")); - } else { - // Register all extensions. Use custom registration - // code for services, directives, etc; otherwise, - // just register them under generic names. - if (customRegistrars[category]) { - customRegistrars[category](extensions); - } else { - extensions.forEach(registerExtension); - registerExtensionArraysForCategory(category, names); - } - - registeredCategories[category] = true; - - return true; - } - } - - // Check if a declared dependency looks like a dependency on - // an extension category (e.g. is suffixed by []) - function isExtensionDependency(dependency) { - var index = dependency.indexOf( - Constants.EXTENSION_SUFFIX, - dependency.length - Constants.EXTENSION_SUFFIX.length - ); - - return index !== -1; - } - - // Examine a group of resolved dependencies to determine - // which extension categories still need to be satisfied. - function findEmptyExtensionDependencies(extGroup) { - var needed = {}, - categories = Object.keys(extGroup), - allExtensions = []; - - // Build up an array of all extensions - categories.forEach(function (category) { - allExtensions = - allExtensions.concat(extGroup[category]); - }); - - // Track all extension dependencies exposed therefrom - allExtensions.forEach(function (extension) { - (extension.depends || []).filter( - isExtensionDependency - ).forEach(function (dependency) { - needed[dependency] = true; - }); - }); - - // Remove categories which have been provided - categories.forEach(function (category) { - var dependency = category + Constants.EXTENSION_SUFFIX; - delete needed[dependency]; - }); - - return Object.keys(needed); - } - - // Register any extension categories that are depended-upon but - // have not been declared anywhere; such dependencies are then - // satisfied by an empty array, instead of not at all. - function registerEmptyDependencies(extGroup) { - findEmptyExtensionDependencies(extGroup) - .forEach(function (name) { - $log.info("Registering empty extension category " + name); - app.factory(name, [staticFunction([])]); - }); - } - - // Announce we're entering a new phase - $log.info("Registering extensions..."); - - // Register all declared extensions by category - Object.keys(extensionGroup).forEach(function (category) { - registerExtensionsForCategory( - category, - sorter.sort(extensionGroup[category]) - ); - }); - - // Also handle categories which are needed but not declared - registerEmptyDependencies(extensionGroup); - - // Return the application to which these extensions - // have been registered - return app; - }; - - return ExtensionRegistrar; - } -); diff --git a/platform/framework/src/register/ExtensionSorter.js b/platform/framework/src/register/ExtensionSorter.js deleted file mode 100644 index 6ba7cce49c..0000000000 --- a/platform/framework/src/register/ExtensionSorter.js +++ /dev/null @@ -1,118 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ["../Constants"], - function (Constants) { - - /** - * Responsible for applying priority order to extensions in a - * given category. This will sort in reverse order of the numeric - * priority given for extensions in the `priority` priority (such - * that large values are registered first.) Extensions may also - * specify symbolic properties as strings (instead of numbers), - * which will be looked up from the table `Constants.PRIORITY_LEVELS`. - * @param $log Angular's logging service - * @memberof platform/framework - * @constructor - */ - function ExtensionSorter($log) { - this.$log = $log; - } - - /** - * Sort extensions according to priority. - * - * @param {object[]} extensions array of resolved extensions - * @returns {object[]} the same extensions, in priority order - */ - ExtensionSorter.prototype.sort = function (extensions) { - var $log = this.$log; - - // Handle unknown or malformed priorities specified by extensions - function unrecognizedPriority(extension) { - // Issue a warning - $log.warn([ - "Unrecognized priority '", - (extension || {}).priority, - "' specified for extension from ", - ((extension || {}).bundle || {}).path, - "; defaulting to ", - Constants.DEFAULT_PRIORITY - ].join('')); - - // Provide a return value (default priority) to make this - // useful in an expression. - return Constants.DEFAULT_PRIORITY; - } - - function getPriority(extension) { - var priority = - (extension || {}).priority || Constants.DEFAULT_PRIORITY; - - // If it's a symbolic priority, look it up - if (typeof priority === 'string') { - priority = Constants.PRIORITY_LEVELS[priority]; - } - - // Should be a number; otherwise, issue a warning and - // fall back to default priority level. - return (typeof priority === 'number') - ? priority : unrecognizedPriority(extension); - } - - // Attach a numeric priority to an extension; this is done in - // one pass outside of the comparator, mainly because getPriority - // may log warnings, and we only want this to happen once - // (instead of the many times that might occur during a sort.) - function prioritize(extension, index) { - return { - // The extension itself, for later unwrapping - extension: extension, - // The index, to provide a stable sort (see compare) - index: index, - // The numeric priority of the extension - priority: getPriority(extension) - }; - } - - // Unwrap the original extension - // (for use after ordering has been applied) - function deprioritize(prioritized) { - return prioritized.extension; - } - - // Compare two prioritized extensions - function compare(a, b) { - // Reverse order by numeric priority; or, original order. - return (b.priority - a.priority) || (a.index - b.index); - } - - return (extensions || []) - .map(prioritize) - .sort(compare) - .map(deprioritize); - }; - - return ExtensionSorter; - } -); diff --git a/platform/framework/src/register/PartialConstructor.js b/platform/framework/src/register/PartialConstructor.js deleted file mode 100644 index c7f9f34a32..0000000000 --- a/platform/framework/src/register/PartialConstructor.js +++ /dev/null @@ -1,78 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 PartialConstructor. Created by vwoeltje on 11/3/14. - */ -define( - [], - function () { - - /** - * A partial constructor is used to instantiate objects in two - * stages: - * - * * First, dependencies injected from Angular - * * Second, arguments passed at run-time - * - * This allows extensions to accept both their Angular-injected - * dependencies and their per-instance attributes all in one - * constructor invocation. User code for these extensions then - * does not see the Angular dependency arguments; they may - * instantiate instances of these extensions by passing only - * those per-instance arguments. - * - * @memberof platform/framework - * @constructor - */ - function PartialConstructor(Constructor) { - - function OuterConstructor() { // Bind services - var dependencies = Array.prototype.slice.call(arguments); - - function InnerConstructor() { // Bind everything else - var other = Array.prototype.slice.call(arguments), - instance = Object.create(Constructor.prototype); - - // Mimic "new" behavior with apply. - instance = Constructor.apply( - instance, - dependencies.concat(other) - ) || instance; - - return instance; - } - - // Copy properties from original constructor - Object.keys(Constructor).forEach(function (k) { - InnerConstructor[k] = Constructor[k]; - }); - - return InnerConstructor; - } - - return OuterConstructor; - } - - return PartialConstructor; - } -); diff --git a/platform/framework/src/register/ServiceCompositor.js b/platform/framework/src/register/ServiceCompositor.js deleted file mode 100644 index 59e9b6440f..0000000000 --- a/platform/framework/src/register/ServiceCompositor.js +++ /dev/null @@ -1,257 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ServiceCompositor. Created by vwoeltje on 11/5/14. - */ -define( - [], - function () { - - /** - * Handles service compositing; that is, building up services - * from provider, aggregator, and decorator components. - * - * @memberof platform/framework - * @constructor - */ - function ServiceCompositor(app, $log) { - this.latest = {}; - this.providerLists = {}; // Track latest services registered - this.app = app; - this.$log = $log; - } - - /** - * Register composite services with Angular. This will build - * up a dependency hierarchy between providers, aggregators, - * and/or decorators, such that a dependency upon the service - * type they expose shall be satisfied by their fully-wired - * whole. - * - * Note that this method assumes that a complete set of - * components shall be provided. Multiple calls to this - * method may not behave as expected. - * - * @param {Array} components extensions of category component - */ - ServiceCompositor.prototype.registerCompositeServices = function (components) { - var latest = this.latest, - providerLists = this.providerLists, - app = this.app, - $log = this.$log; - - // Log a warning; defaults to "no service provided by" - function warn(extension, category, message) { - var msg = message || "No service provided by"; - $log.warn([ - msg, - " ", - category, - " ", - extension.key, - " from bundle ", - (extension.bundle || { path: "unknown bundle" }).path, - "; skipping." - ].join("")); - } - - //Log an info: defaults to "no service provide by" - function info(extension, category, message) { - var msg = message || "No service provided by"; - $log.info([ - msg, - " ", - category, - " ", - extension.key, - " from bundle ", - (extension.bundle || { path: "unknown bundle" }).path, - "; skipping." - ].join("")); - } - - // Echo arguments; used to represent groups of non-built-in - // extensions as a single dependency. - function echoMany() { - return Array.prototype.slice.call(arguments); - } - - // Echo arguments; used to represent groups of non-built-in - // extensions as a single dependency. - function echoSingle(value) { - return value; - } - - // Generates utility functions to match types (one of - // provider, aggregator, or decorator) of component. Used - // to filter down to specific types, which are handled - // in order. - function hasType(type) { - return function (extension) { - return extension.type === type; - }; - } - - // Make a unique name for a service component. - function makeName(category, service, index) { - return [ - service, - "[", - category, - "#", - index, - "]" - ].join(""); - } - - // Register a specific provider instance with Angular, and - // record its name for subsequent stages. - function registerProvider(provider, index) { - var service = provider.provides, - dependencies = provider.depends || [], - name = makeName("provider", service, index); - - if (!service) { - return warn(provider, "provider"); - } - - providerLists[service] = providerLists[service] || []; - providerLists[service].push(name); - - // This provider is the latest candidate for resolving - // the composite service. - latest[service] = name; - - app.service(name, dependencies.concat([provider])); - - $log.info("Registering provider for " + service); - } - - // Register an array of providers as a single dependency; - // aggregators will then depend upon this to consume all - // aggregated providers as a single dependency. - function registerProviderSets() { - Object.keys(providerLists).forEach(function (service) { - var name = makeName("provider", service, "*"), - list = providerLists[service]; - - $log.info([ - "Compositing", - list.length, - "providers for", - service - ].join(" ")); - - app.service(name, list.concat([echoMany])); - }); - } - - // Registers an aggregator via Angular, including both - // its declared dependencies and the additional, implicit - // dependency upon the array of all providers. - function registerAggregator(aggregator, index) { - var service = aggregator.provides, - dependencies = aggregator.depends || [], - providerSetName = makeName("provider", service, "*"), - name = makeName("aggregator", service, index); - - if (!service) { - return info(aggregator, "aggregator"); - } - - // Aggregators need other services to aggregate, otherwise they - // do nothing. - if (!latest[service]) { - return info( - aggregator, - "aggregator", - "No services to aggregate for" - ); - } - - dependencies = dependencies.concat([providerSetName]); - latest[service] = name; - - app.service(name, dependencies.concat([aggregator])); - } - - // Registers a decorator via Angular, including its implicit - // dependency on the latest service component which has come - // before it. - function registerDecorator(decorator, index) { - var service = decorator.provides, - dependencies = decorator.depends || [], - name = makeName("decorator", service, index); - - if (!service) { - return warn(decorator, "decorator"); - } - - // Decorators need other services to decorate, otherwise they - // do nothing. - if (!latest[service]) { - return warn( - decorator, - "decorator", - "No services to decorate for" - ); - } - - dependencies = dependencies.concat([latest[service]]); - latest[service] = name; - - app.service(name, dependencies.concat([decorator])); - } - - // Alias the latest services of various types back to the - // more general service declaration. - function registerLatest() { - Object.keys(latest).forEach(function (service) { - app.service(service, [latest[service], echoSingle]); - }); - } - - // Register composite services in phases: - // * Register providers - // * Register aggregators (which use providers) - // * Register decorators (which use anything) - // Then, register the latest candidate as a plain service. - function registerComposites(providers, aggregators, decorators) { - providers.forEach(registerProvider); - registerProviderSets(); - aggregators.forEach(registerAggregator); - decorators.forEach(registerDecorator); - registerLatest(); - } - - // Initial point of entry; split into three component types. - registerComposites( - components.filter(hasType("provider")), - components.filter(hasType("aggregator")), - components.filter(hasType("decorator")) - ); - }; - - return ServiceCompositor; - } -); diff --git a/platform/framework/src/resolve/BundleResolver.js b/platform/framework/src/resolve/BundleResolver.js deleted file mode 100644 index ce02f9e9f7..0000000000 --- a/platform/framework/src/resolve/BundleResolver.js +++ /dev/null @@ -1,125 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 BundleResolver. Created by vwoeltje on 11/4/14. - */ -define( - [], - function () { - - /** - * Responsible for the extension resolution phase of framework - * initialization. During this phase, any scripts implementing - * extensions provided by bundles are loaded. - * - * @memberof platform/framework - * @constructor - */ - function BundleResolver(extensionResolver, $log) { - this.extensionResolver = extensionResolver; - this.$log = $log; - } - - /** - * Resolve all extensions exposed by these bundles. - * - * @param {Bundle[]} bundles the bundles to resolve - * @returns {Promise.>} an promise - * for an object containing - * key-value pairs, where keys are extension - * categories and values are arrays of resolved - * extensions belonging to those categories - */ - BundleResolver.prototype.resolveBundles = function (bundles) { - var extensionResolver = this.extensionResolver, - $log = this.$log; - - /* - * Merge resolved bundles (where each is expressed as an - * object containing key-value pairs, where keys are extension - * categories and values are arrays of resolved extensions) - * into one large object containing resolved extensions from - * all bundles (in the same form.) - * - * @param {Object.|Array} resolvedBundles - * @returns {Object.} - * @memberof platform/framework.BundleResolver# - */ - function mergeResolvedBundles(resolvedBundles) { - var result = {}; - - resolvedBundles.forEach(function (resolved) { - Object.keys(resolved).forEach(function (k) { - result[k] = (result[k] || []).concat(resolved[k]); - }); - }); - - return result; - } - - // Resolve a bundle; resolve all extensions, and return - // the resolved extensions in an object in the format described - // for mergeResolvedBundles above - function resolveBundle(bundle) { - var categories = bundle.getExtensionCategories(), - result = {}; - - function resolveExtension(extension) { - var category = extension.getCategory(); - - function push(resolved) { - result[category].push(resolved); - } - - return extensionResolver.resolve(extension).then(push); - } - - function resolveCategory(category) { - result[category] = []; - - return Promise.all( - bundle.getExtensions(category).map(resolveExtension) - ); - } - - function giveResult() { - return result; - } - - // Log the large-scale task - $log.info( - "Resolving extensions for bundle " + bundle.getLogName() - ); - - return Promise.all(categories.map(resolveCategory)) - .then(giveResult); - } - - // Then, resolve all extension implementations. - return Promise.all(bundles.map(resolveBundle)) - .then(mergeResolvedBundles); - }; - - return BundleResolver; - } -); diff --git a/platform/framework/src/resolve/ExtensionResolver.js b/platform/framework/src/resolve/ExtensionResolver.js deleted file mode 100644 index 5994c654b5..0000000000 --- a/platform/framework/src/resolve/ExtensionResolver.js +++ /dev/null @@ -1,147 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ExtensionResolver. Created by vwoeltje on 11/3/14. - */ -define( - [], - function () { - - /** - * An ExtensionResolver is responsible for loading any implementation - * modules associated with specific extensions. - * - * @param {ImplementationLoader} loader used to load implementations - * @param {*} $log Angular's logging service - * @memberof platform/framework - * @constructor - */ - function ExtensionResolver(loader, $log) { - this.loader = loader; - this.$log = $log; - } - - /** - * Resolve the provided extension; this will give a promise - * for the extension's implementation, if one has been - * specified, or for the plain definition of the extension - * otherwise. The plain definition will also be given - * if the implementation fails to load for some reason. - * - * All key-value pairs from the extension definition - * will additionally be attached to any loaded implementation. - * - * @param {Extension} extension the extension to resolve - * @returns {Promise} a promise for the resolved extension - */ - ExtensionResolver.prototype.resolve = function (extension) { - var loader = this.loader, - $log = this.$log; - - function loadImplementation(ext) { - var implPromise = ext.hasImplementationValue() - ? Promise.resolve(ext.getImplementationValue()) - : loader.load(ext.getImplementationPath()), - definition = ext.getDefinition(); - - // Wrap a constructor function (to avoid modifying the original) - function constructorFor(impl) { - function Constructor() { - return impl.apply(this, arguments); - } - - Constructor.prototype = impl.prototype; - - return Constructor; - } - - // Attach values from the object definition to the - // loaded implementation. - function attachDefinition(impl) { - var result = (typeof impl === 'function') - ? constructorFor(impl) - : Object.create(impl); - - // Copy over static properties - Object.keys(impl).forEach(function (k) { - result[k] = impl[k]; - }); - - // Copy over definition - Object.keys(definition).forEach(function (k) { - if (result[k] === undefined) { - result[k] = definition[k]; - } - }); - result.definition = definition; - - // Log that this load was successful - $log.info("Resolved " + ext.getLogName()); - - return result; - } - - // Log any errors in loading the implementation, and - // return the plain extension definition instead. - function handleError(err) { - // Build up a log message from parts - var message = [ - "Could not load implementation for extension ", - ext.getLogName(), - " due to ", - err.message - ].join(""); - - // Log that the extension was not loaded - $log.warn(message); - - return ext.getDefinition(); - } - - if (!ext.hasImplementationValue()) { - // Log that loading has begun - $log.info([ - "Loading implementation ", - ext.getImplementationPath(), - " for extension ", - ext.getLogName() - ].join("")); - } - - return implPromise.then(attachDefinition, handleError); - } - - // Log that loading has begun - $log.info([ - "Resolving extension ", - extension.getLogName() - ].join("")); - - return extension.hasImplementation() - ? loadImplementation(extension) - : Promise.resolve(extension.getDefinition()); - }; - - return ExtensionResolver; - } -); diff --git a/platform/framework/src/resolve/ImplementationLoader.js b/platform/framework/src/resolve/ImplementationLoader.js deleted file mode 100644 index 3344a6ed0f..0000000000 --- a/platform/framework/src/resolve/ImplementationLoader.js +++ /dev/null @@ -1,64 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ImplementationLoader. Created by vwoeltje on 11/3/14. - */ -define( - [], - function () { - - /** - * Responsible for loading extension implementations - * (AMD modules.) Acts as a wrapper around RequireJS to - * provide a promise-like API. - * @memberof platform/framework - * @constructor - * @param {*} require RequireJS, or an object with similar API - * @param {*} $log Angular's logging service - */ - function ImplementationLoader(require) { - this.require = require; - } - - /** - * Load an extension's implementation; or, equivalently, - * load an AMD module. This is fundamentally similar - * to a call to RequireJS, except that the result is - * wrapped in a promise. The promise will be fulfilled - * with the loaded module, or rejected with the error - * reported by Require. - * - * @param {string} path the path to the module to load - * @returns {Promise} a promise for the specified module. - */ - ImplementationLoader.prototype.load = function loadModule(path) { - var require = this.require; - - return new Promise(function (fulfill, reject) { - require([path], fulfill, reject); - }); - }; - - return ImplementationLoader; - } -); diff --git a/platform/framework/test/FrameworkInitializerSpec.js b/platform/framework/test/FrameworkInitializerSpec.js deleted file mode 100644 index 55d55514d0..0000000000 --- a/platform/framework/test/FrameworkInitializerSpec.js +++ /dev/null @@ -1,60 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * FrameworkInitializerSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../src/FrameworkInitializer"], - function (FrameworkInitializer) { - - describe("The framework initializer", function () { - var initializer; - - function appender(name) { - return function (value) { - return Promise.resolve(value.concat([name])); - }; - } - - beforeEach(function () { - initializer = new FrameworkInitializer( - { loadBundles: appender("loader") }, - { resolveBundles: appender("resolver") }, - { registerExtensions: appender("registrar") }, - { bootstrap: appender("bootstrapper")} - ); - }); - - // Really just delegates work, can only verify the - // order of calls. - it("calls injected stages in order", function () { - return initializer.runApplication([]).then(function (result) { - expect(result).toEqual( - ["loader", "resolver", "registrar", "bootstrapper"] - ); - }); - }); - - }); - } -); diff --git a/platform/framework/test/LogLevelSpec.js b/platform/framework/test/LogLevelSpec.js deleted file mode 100644 index 4e5af24ecb..0000000000 --- a/platform/framework/test/LogLevelSpec.js +++ /dev/null @@ -1,98 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/LogLevel'], - function (LogLevel) { - - var LOG_METHODS = [ - 'error', - 'warn', - 'info', - 'log', - 'debug' - ]; - - describe("The logging level handler", function () { - var mockLog, - mockApp, - mockDelegate, - mockMethods; - - function logAll(v) { - LOG_METHODS.forEach(function (m) { - mockLog[m](v); - mockDelegate[m](v); - }); - } - - function expectCalls(calls, v) { - LOG_METHODS.forEach(function (m) { - if (calls.indexOf(m) > -1) { - expect(mockMethods[m]).toHaveBeenCalledWith(v); - } else { - expect(mockMethods[m]).not.toHaveBeenCalledWith(v); - } - }); - } - - beforeEach(function () { - mockMethods = jasmine.createSpyObj("levels", LOG_METHODS); - mockLog = jasmine.createSpyObj('$log', LOG_METHODS); - mockApp = jasmine.createSpyObj('app', ['config', 'decorator']); - mockDelegate = jasmine.createSpyObj('$delegate', LOG_METHODS); - - LOG_METHODS.forEach(function (m) { - mockLog[m].and.callFake(mockMethods[m]); - mockDelegate[m].and.callFake(mockMethods[m]); - }); - - mockApp.decorator.and.callFake(function (key, decoration) { - // We only expect $log to be decorated - if (key === '$log' && decoration[0] === '$delegate') { - decoration[1](mockDelegate); - } - }); - }); - - it("defaults to 'warn' level", function () { - new LogLevel("garbage").configure(mockApp, mockLog); - logAll("test"); - expectCalls(['error', 'warn'], 'test'); - }); - - LOG_METHODS.forEach(function (m, i) { - it("supports log level '" + m + "'", function () { - // Note: This is sensitive to ordering of LOG_METHODS, - // which needs to be highest-level-first above. - var expected = LOG_METHODS.slice(0, i + 1), - message = "test " + m; - - new LogLevel(m).configure(mockApp, mockLog); - logAll(message); - expectCalls(expected, message); - }); - }); - - }); - } -); diff --git a/platform/framework/test/bootstrap/ApplicationBootstrapperSpec.js b/platform/framework/test/bootstrap/ApplicationBootstrapperSpec.js deleted file mode 100644 index 8b2eebbdb7..0000000000 --- a/platform/framework/test/bootstrap/ApplicationBootstrapperSpec.js +++ /dev/null @@ -1,108 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ApplicationBootstrapperSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/bootstrap/ApplicationBootstrapper"], - function (ApplicationBootstrapper) { - - describe("The application bootstrapper", function () { - // Test support variables - var bootstrapper, - captured, - mockAngular, - mockDocument, - mockLog, - mockApp; - - // Used to capture arguments to mocks - function capture() { - var names = Array.prototype.slice.apply(arguments, []); - - return function () { - var values = arguments; - names.forEach(function (name, index) { - captured[name] = values[index]; - }); - }; - } - - // Set up the mocks before each run - beforeEach(function () { - captured = {}; - - mockAngular = { - element: function (selector) { - captured.selector = selector; - - return { ready: capture("callback") }; - }, - bootstrap: capture("element", "appNames") - }; - - mockDocument = "I am just a value."; - - mockLog = { info: capture("info") }; - - mockApp = { name: "MockApp" }; - - bootstrapper = new ApplicationBootstrapper( - mockAngular, - mockDocument, - mockLog - ); - - bootstrapper.bootstrap(mockApp); - }); - - // The tests. - - it("waits for the provided document element to be ready", function () { - // Should have provided Angular a selector... - expect(captured.selector).toBe(mockDocument); - // ...and called ready on the response. - expect(captured.callback).toBeDefined(); - }); - - it("issues a bootstrap call once ready", function () { - // Verify precondition; bootstrap not called - expect(captured.element).toBeUndefined(); - expect(captured.appNames).toBeUndefined(); - - // Call the "ready" function - captured.callback(); - - // Verify that bootstrap was called - expect(captured.element).toBe(mockDocument); - expect(captured.appNames).toEqual([mockApp.name]); - }); - - it("logs that the bootstrap phase has been reached", function () { - expect(captured.info).toBeDefined(); - expect(typeof captured.info).toEqual('string'); - }); - - }); - } -); diff --git a/platform/framework/test/load/BundleLoaderSpec.js b/platform/framework/test/load/BundleLoaderSpec.js deleted file mode 100644 index 51085f796b..0000000000 --- a/platform/framework/test/load/BundleLoaderSpec.js +++ /dev/null @@ -1,122 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * BundleLoaderSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/load/BundleLoader"], - function (BundleLoader) { - - describe("The bundle loader", function () { - var loader, - mockHttp, - mockLog, - mockRegistry, - testBundles; - - beforeEach(function () { - testBundles = { - "bundles.json": ["bundle/a", "bundle/b"], - "bundle/a/bundle.json": {"someValue": 6}, - "bundle/b/bundle.json": {"someValue": 7} - }; - - mockHttp = jasmine.createSpyObj("$http", ["get"]); - mockLog = jasmine.createSpyObj("$log", ["error", "warn", "info", "debug"]); - mockRegistry = jasmine.createSpyObj( - 'legacyRegistry', - ['list', 'contains', 'get'] - ); - mockRegistry.list.and.returnValue([]); - mockRegistry.contains.and.returnValue(false); - loader = new BundleLoader(mockHttp, mockLog, mockRegistry); - }); - - it("accepts a JSON file name and loads all bundles", function () { - // Set up; return named bundles - mockHttp.get.and.returnValue(Promise.resolve({ data: [] })); - - // Call load bundles - return loader.loadBundles("test-filename.json").then(function (bundles) { - // Should have loaded the file via $http - expect(mockHttp.get).toHaveBeenCalledWith("test-filename.json"); - - // Should have gotten an empty bundle list - expect(bundles).toEqual([]); - }); - }); - - it("accepts a list of bundle paths", function () { - // Set up; return named bundles - mockHttp.get.and.callFake(function (name) { - return Promise.resolve({data: testBundles[name]}); - }); - - // Call load bundles - return loader.loadBundles(["bundle/a", "bundle/b"]).then(function (bundles) { - // Should have gotten back two bundles - expect(bundles.length).toEqual(2); - - // They should have the values we expect; don't care about order, - // some map/reduce the summation. - expect(bundles.map(function (call) { - return call.getDefinition().someValue; - }).reduce(function (a, b) { - return a + b; - }, 0)).toEqual(13); - }); - }); - - it("warns about, then ignores, missing bundle declarations", function () { - // File-not-found - mockHttp.get.and.returnValue(Promise.reject(new Error("test error"))); - - // Try and load - return loader.loadBundles(["some/bundle"]).then(function (bundles) { - // Should have gotten zero bundles - expect(bundles.length).toEqual(0); - - // They should have the values we expect; don't care about order, - // some map/reduce the summation. - expect(mockLog.warn).toHaveBeenCalled(); - }); - }); - - it("warns about, then ignores, malformed bundle declarations", function () { - // File-not-found - mockHttp.get.and.returnValue(Promise.resolve(["I am not a valid bundle."])); - - // Try and load - return loader.loadBundles(["some/bundle"]).then(function (bundles) { - // Should have gotten zero bundle - expect(bundles.length).toEqual(0); - - // They should have the values we expect; don't care about order, - // some map/reduce the summation. - expect(mockLog.warn).toHaveBeenCalled(); - }); - }); - - }); - } -); diff --git a/platform/framework/test/load/BundleSpec.js b/platform/framework/test/load/BundleSpec.js deleted file mode 100644 index e299acaa11..0000000000 --- a/platform/framework/test/load/BundleSpec.js +++ /dev/null @@ -1,98 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * BundleSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/load/Bundle", "../../src/Constants"], - function (Bundle, Constants) { // Verify against constants, too - - describe("A bundle", function () { - var PATH = "some/path", - KEY = "someKey"; - - it("reports its path", function () { - expect(new Bundle(PATH, {}).getPath()).toEqual(PATH); - }); - - it("reports its source path", function () { - expect(new Bundle(PATH, { "sources": "test-src" }).getSourcePath()).toEqual( - PATH + Constants.SEPARATOR + "test-src" - ); - }); - - it("reports the default source path if none is configured", function () { - expect(new Bundle(PATH, {}).getSourcePath()).toEqual( - PATH + Constants.SEPARATOR + Constants.DEFAULT_BUNDLE.sources - ); - }); - - it("reports its resource path", function () { - expect(new Bundle(PATH, { "resources": "test-res" }).getResourcePath()).toEqual( - PATH + Constants.SEPARATOR + "test-res" - ); - }); - - it("reports the default resource path if none is configured", function () { - expect(new Bundle(PATH, {}).getResourcePath()).toEqual( - PATH + Constants.SEPARATOR + Constants.DEFAULT_BUNDLE.resources - ); - }); - - it("has a log-friendly name for the bundle which includes its key and path", function () { - // Use indexof to look for the bundle's key - var logName = new Bundle(PATH, { key: KEY }).getLogName(); - expect(logName.indexOf(KEY)).not.toEqual(-1); - expect(logName.indexOf(PATH)).not.toEqual(-1); - }); - - it("reports all declared extension categories", function () { - var bundle = new Bundle(PATH, { - extensions: { - things: [], - tests: [], - foos: [] - } - }); - - expect(bundle.getExtensionCategories().sort()).toEqual( - ["foos", "tests", "things"] - ); - }); - - it("reports all extensions that have been declared", function () { - var bundle = new Bundle(PATH, { - extensions: { things: [{}, {}, {}] } - }); - expect(bundle.getExtensions("things").length).toEqual(3); - }); - - it("reports an empty list for extensions that have not been declared", function () { - var bundle = new Bundle(PATH, { - extensions: { things: [{}, {}, {}] } - }); - expect(bundle.getExtensions("stuffs").length).toEqual(0); - }); - }); - } -); diff --git a/platform/framework/test/load/ExtensionSpec.js b/platform/framework/test/load/ExtensionSpec.js deleted file mode 100644 index 18bbb08717..0000000000 --- a/platform/framework/test/load/ExtensionSpec.js +++ /dev/null @@ -1,107 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ExtensionSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/load/Extension", "../../src/load/Bundle"], - function (Extension, Bundle) { - - describe("An extension", function () { - var bundle; - - beforeEach(function () { - bundle = new Bundle("test/bundle", {}); - }); - - it("reports its key", function () { - expect(new Extension(bundle, "tests", { key: "testKey"}).getKey()) - .toEqual("testKey"); - }); - - it("reports some key, even if non is defined", function () { - expect(new Extension(bundle, "tests", {}).getKey()).toBeDefined(); - }); - - it("allows retrieval of its declaring bundle", function () { - expect(new Extension(bundle, "tests", {}).getBundle()).toBe(bundle); - }); - - it("reports its category", function () { - expect(new Extension(bundle, "tests", {}).getCategory()) - .toEqual("tests"); - expect(new Extension(bundle, "otherThings", {}).getCategory()) - .toEqual("otherThings"); - }); - - it("provides a check to see if an implementation is associated with the extension", function () { - expect(new Extension(bundle, "tests", {}).hasImplementation()) - .toBeFalsy(); - expect(new Extension(bundle, "tests", { implementation: "Something.js" }).hasImplementation()) - .toBeTruthy(); - }); - - it("provides a full path to an implementation, if present", function () { - expect(new Extension(bundle, "tests", { implementation: "Something.js" }).getImplementationPath()) - .toEqual("test/bundle/src/Something.js"); - }); - - it("does not define an implementation path if there is no implementation", function () { - expect(new Extension(bundle, "tests", {}).getImplementationPath()) - .toBeUndefined(); - }); - - it("provides a log-friendly name which contains the extension key", function () { - var logName = - new Extension(bundle, "tests", { key: "testKey"}).getLogName(); - expect(logName.indexOf("testKey")).not.toEqual(-1); - }); - - it("allows its definition to be retrieved", function () { - var definition = { - key: "someKey", - implementation: "SomeImplementation.js" - }, - reported = new Extension(bundle, "tests", definition).getDefinition(); - - // Bundle is added, so we can't do a normal toEqual; check that - // all keys are still there, though. - Object.keys(definition).forEach(function (k) { - expect(reported[k]).toEqual(definition[k]); - }); - }); - - it("includes the bundle in its definition", function () { - // Bundle is needed by some registrars in the the registration phase, - // so make sure it gets attached to the definition. - var definition = { - key: "someKey", - implementation: "SomeImplementation.js" - }, - reported = new Extension(bundle, "tests", definition).getDefinition(); - - expect(reported.bundle).toEqual(bundle.getDefinition()); - }); - }); - } -); diff --git a/platform/framework/test/register/CustomRegistrarsSpec.js b/platform/framework/test/register/CustomRegistrarsSpec.js deleted file mode 100644 index 60f47ff628..0000000000 --- a/platform/framework/test/register/CustomRegistrarsSpec.js +++ /dev/null @@ -1,198 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * CustomRegistrarsSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/register/CustomRegistrars"], - function (CustomRegistrars) { - - describe("Custom registrars", function () { - var mockLog, - mockApp, - customRegistrars; - - // Set up mock test dependencies - beforeEach(function () { - mockApp = jasmine.createSpyObj("app", [ - "controller", - "directive", - "service", - "constant", - "config", - "run" - ]); - - mockLog = jasmine.createSpyObj("$log", [ - "error", - "warn", - "info", - "debug" - ]); - - customRegistrars = new CustomRegistrars(mockApp, mockLog); - }); - - it("has custom registrars for Angular built-ins", function () { - expect(customRegistrars.directives).toBeTruthy(); - expect(customRegistrars.controllers).toBeTruthy(); - expect(customRegistrars.services).toBeTruthy(); - expect(customRegistrars.routes).toBeTruthy(); - expect(customRegistrars.constants).toBeTruthy(); - expect(customRegistrars.runs).toBeTruthy(); - }); - - it("invokes built-in functions on the app", function () { - // Verify preconditions, invoke, expect to have been called - expect(mockApp.directive.calls.count()).toEqual(0); - customRegistrars.directives([{ key: "a" }, { key: "b" }, { key: "c" }]); - expect(mockApp.directive.calls.count()).toEqual(3); - - expect(mockApp.controller.calls.count()).toEqual(0); - customRegistrars.controllers([{ key: "a" }, { key: "b" }, { key: "c" }]); - expect(mockApp.controller.calls.count()).toEqual(3); - - expect(mockApp.service.calls.count()).toEqual(0); - customRegistrars.services([{ key: "a" }, { key: "b" }, { key: "c" }]); - expect(mockApp.service.calls.count()).toEqual(3); - - expect(mockApp.constant.calls.count()).toEqual(0); - customRegistrars.constants([{ - key: "a", - value: "b" - }, { - key: "b", - value: "c" - }, { - key: "c", - value: "d" - }]); - expect(mockApp.constant.calls.count()).toEqual(3); - - expect(mockApp.run.calls.count()).toEqual(0); - customRegistrars.runs([jasmine.createSpy("a"), jasmine.createSpy("a"), jasmine.createSpy("a")]); - expect(mockApp.run.calls.count()).toEqual(3); - - }); - - it("warns when keys are not defined, then skips", function () { - // Verify preconditions, invoke, expect to have been called - expect(mockApp.directive.calls.count()).toEqual(0); - customRegistrars.directives([{ key: "a" }, { }, { key: "c" }]); - expect(mockApp.directive.calls.count()).toEqual(2); - expect(mockLog.warn.calls.count()).toEqual(1); - - expect(mockApp.controller.calls.count()).toEqual(0); - customRegistrars.controllers([{ }, { }, { key: "c" }]); - expect(mockApp.controller.calls.count()).toEqual(1); - expect(mockLog.warn.calls.count()).toEqual(3); - - expect(mockApp.service.calls.count()).toEqual(0); - customRegistrars.services([{ }, { }, { }]); - expect(mockApp.service.calls.count()).toEqual(0); - expect(mockLog.warn.calls.count()).toEqual(6); - - expect(mockApp.constant.calls.count()).toEqual(0); - customRegistrars.constants([{ }, { }, { }]); - expect(mockApp.constant.calls.count()).toEqual(0); - expect(mockLog.warn.calls.count()).toEqual(9); - - // Notably, keys are not needed for run calls - }); - - it("does not re-register duplicate keys", function () { - // Verify preconditions, invoke, expect to have been called - expect(mockApp.directive.calls.count()).toEqual(0); - customRegistrars.directives([{ key: "a" }, { key: "a" }]); - expect(mockApp.directive.calls.count()).toEqual(1); - - expect(mockApp.controller.calls.count()).toEqual(0); - customRegistrars.controllers([{ key: "c" }, { key: "c" }, { key: "c" }]); - expect(mockApp.controller.calls.count()).toEqual(1); - - expect(mockApp.service.calls.count()).toEqual(0); - customRegistrars.services([{ key: "b" }, { key: "b" }]); - expect(mockApp.service.calls.count()).toEqual(1); - - // None of this should have warned, this is all - // nominal behavior - expect(mockLog.warn.calls.count()).toEqual(0); - }); - - it("allows routes to be registered", function () { - var mockRouteProvider = jasmine.createSpyObj( - "$routeProvider", - ["when", "otherwise"] - ), - bundle = { - path: "test/bundle", - resources: "res" - }, - routes = [ - { - when: "foo", - templateUrl: "templates/test.html", - bundle: bundle - }, - { - templateUrl: "templates/default.html", - bundle: bundle - } - ]; - - customRegistrars.routes(routes); - - // Give it the route provider based on its config call - mockApp.config.calls.all().forEach(function (call) { - // Invoke the provided callback - call.args[0][1](mockRouteProvider); - }); - - // The "when" clause should have been mapped to the when method... - expect(mockRouteProvider.when).toHaveBeenCalled(); - expect(mockRouteProvider.when.calls.mostRecent().args[0]).toEqual("foo"); - expect(mockRouteProvider.when.calls.mostRecent().args[1].templateUrl) - .toEqual("test/bundle/res/templates/test.html"); - - // ...while the other should have been treated as a default route - expect(mockRouteProvider.otherwise).toHaveBeenCalled(); - expect(mockRouteProvider.otherwise.calls.mostRecent().args[0].templateUrl) - .toEqual("test/bundle/res/templates/default.html"); - }); - - it("accepts components for service compositing", function () { - // Most relevant code will be exercised in service compositor spec - expect(customRegistrars.components).toBeTruthy(); - customRegistrars.components([]); - }); - - it("warns if no implementation is provided for runs", function () { - // Verify precondition - expect(mockLog.warn).not.toHaveBeenCalled(); - customRegistrars.runs([{ something: "that is not a function"}]); - expect(mockLog.warn).toHaveBeenCalledWith(jasmine.any(String)); - expect(mockApp.run).not.toHaveBeenCalled(); - }); - }); - } -); diff --git a/platform/framework/test/register/ExtensionRegistrarSpec.js b/platform/framework/test/register/ExtensionRegistrarSpec.js deleted file mode 100644 index f6d0715b67..0000000000 --- a/platform/framework/test/register/ExtensionRegistrarSpec.js +++ /dev/null @@ -1,119 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ExtensionRegistrarSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/register/ExtensionRegistrar"], - function (ExtensionRegistrar) { - - describe("The extension registrar", function () { - var mockApp, - mockLog, - mockSorter, - customRegistrars, - registrar; - - beforeEach(function () { - mockApp = jasmine.createSpyObj("app", ["factory"]); - mockLog = jasmine.createSpyObj("$log", ["error", "warn", "debug", "info"]); - mockSorter = jasmine.createSpyObj("sorter", ["sort"]); - customRegistrars = {}; - - mockSorter.sort.and.callFake(function (v) { - return v; - }); - - registrar = new ExtensionRegistrar( - mockApp, - customRegistrars, - mockSorter, - mockLog - ); - }); - - it("registers extensions using the factory", function () { - registrar.registerExtensions({ things: [{}] }); - expect(mockApp.factory).toHaveBeenCalled(); - }); - - it("registers extensions with square brackets, as arrays", function () { - var callbacks = {}; - mockApp.factory.and.callFake(function (name, value) { - callbacks[name] = value[value.length - 1]; - }); - registrar.registerExtensions({ things: [{}] }); - expect(callbacks["things[]"]).toBeDefined(); - - // Verify dependency echo behavior - expect(callbacks["things[]"]("a", "b", "c")).toEqual(["a", "b", "c"]); - }); - - it("warns if multiple registrations are made for the same category of extension", function () { - registrar.registerExtensions({ things: [{}] }); - expect(mockLog.warn).not.toHaveBeenCalled(); - registrar.registerExtensions({ things: [{}] }); - expect(mockLog.warn).toHaveBeenCalled(); - }); - - it("registers empty extension categories when they are needed", function () { - var lengths = {}; - mockApp.factory.and.callFake(function (name, value) { - lengths[name] = value.length; - }); - // Nobody has registered tests[], but it looks like an extension dependency, - // so register it as an empty array. - registrar.registerExtensions({ things: [{ depends: ["tests[]", "other"] }] }); - expect(lengths["tests[]"]).toEqual(1); - expect(lengths.other).toBeUndefined(); - }); - - it("invokes custom registrars (not app.factory) when available", function () { - customRegistrars.things = jasmine.createSpy("things"); - registrar.registerExtensions({ things: [{}] }); - expect(mockApp.factory).not.toHaveBeenCalled(); - expect(customRegistrars.things).toHaveBeenCalled(); - }); - - it("sorts extensions before registering", function () { - // Some extension definitions to sort - var a = { a: 'a' }, b = { b: 'b' }, c = { c: 'c' }; - - // Fake sorting; just reverse the array - mockSorter.sort.and.callFake(function (v) { - return v.reverse(); - }); - - // Register the extensions - registrar.registerExtensions({ things: [a, b, c] }); - - // Verify registration interactions occurred in reverse-order - [c, b, a].forEach(function (extension, index) { - expect(mockApp.factory.calls.all()[index].args[1][0]()) - .toEqual(extension); - }); - }); - - }); - } -); diff --git a/platform/framework/test/register/ExtensionSorterSpec.js b/platform/framework/test/register/ExtensionSorterSpec.js deleted file mode 100644 index 597de1d436..0000000000 --- a/platform/framework/test/register/ExtensionSorterSpec.js +++ /dev/null @@ -1,69 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/register/ExtensionSorter"], - function (ExtensionSorter) { - - describe("The extension sorter", function () { - var mockLog, - sorter; - - beforeEach(function () { - mockLog = jasmine.createSpyObj( - "$log", - ["error", "warn", "debug", "info"] - ); - - sorter = new ExtensionSorter(mockLog); - }); - - it("sorts extensions in priority order", function () { - var a = { priority: 10 }, - b = {}, - c = { priority: 'mandatory' }; // Should be +Inf - expect(sorter.sort([a, b, c])).toEqual([c, a, b]); - }); - - it("warns about unrecognized priorities", function () { - var a = { priority: 10 }, - b = {}, - c = { priority: 'mandatory' }, // Should be +Inf - d = { priority: 'GARBAGE-TEXT' }, - e = { priority: { mal: "formed"} }, - f = { priority: 3 }; - - // Sorting should use default order (note we assume - // a stable sort here as well) - expect(sorter.sort( - [a, b, c, d, e, f] - )).toEqual( - [c, a, f, b, d, e] - ); - - // Should have been warned exactly twice (for d & e) - expect(mockLog.warn.calls.count()).toEqual(2); - }); - - }); - } -); diff --git a/platform/framework/test/register/PartialConstructorSpec.js b/platform/framework/test/register/PartialConstructorSpec.js deleted file mode 100644 index 9d0b343e38..0000000000 --- a/platform/framework/test/register/PartialConstructorSpec.js +++ /dev/null @@ -1,97 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * PartialConstructorSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/register/PartialConstructor"], - function (PartialConstructor) { - - describe("A partial constructor", function () { - var result, - PartializedConstructor; - - function RegularConstructor(a, b, c, d) { - result = { - a: a, - b: b, - c: c, - d: d - }; - - return result; - } - - function ThisStyleConstructor(x, y, z) { - this.message = [x, y, z].join(" "); - } - - RegularConstructor.someProperty = "test property"; - - beforeEach(function () { - result = undefined; - PartializedConstructor = new PartialConstructor(RegularConstructor); - }); - - it("splits a constructor call into two stages", function () { - var RemainingConstructor = new PartializedConstructor("test"), - instance; - // first call should not have hit constructor - expect(result).toBeUndefined(); - - // Call again - instance = new RemainingConstructor(1, 2, 3); - expect(result).toEqual({ - a: "test", - b: 1, - c: 2, - d: 3 - }); - - // Should have returned the constructor's value - expect(instance).toEqual(result); - }); - - it("handles this-style constructors", function () { - var Partialized = new PartialConstructor(ThisStyleConstructor), - Remaining = new Partialized("this"), - instance = new Remaining("is", "correct"); - - // We should have everything we put in "this", and we - // should still pass an instanceof test.g - expect(instance.message).toEqual("this is correct"); - expect(instance).toEqual(new ThisStyleConstructor("this", "is", "correct")); - expect(instance instanceof ThisStyleConstructor).toBeTruthy(); - }); - - it("retains static properties after partialization", function () { - // This string should appear after invoking the partialized - // constructor, such that the resulting inner constructor - // exposes these as if we were looking at the original - // RegularConstructor. - expect(new PartializedConstructor().someProperty).toEqual("test property"); - }); - - }); - } -); diff --git a/platform/framework/test/register/ServiceCompositorSpec.js b/platform/framework/test/register/ServiceCompositorSpec.js deleted file mode 100644 index a0ee5bc8c7..0000000000 --- a/platform/framework/test/register/ServiceCompositorSpec.js +++ /dev/null @@ -1,258 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ServiceCompositorSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/register/ServiceCompositor"], - function (ServiceCompositor) { - - describe("The service compositor", function () { - var registered, - mockApp, - mockLog, - compositor; - - beforeEach(function () { - registered = {}; - - mockApp = jasmine.createSpyObj("app", ["service"]); - mockLog = jasmine.createSpyObj("$log", ["error", "warn", "info", "debug"]); - - mockApp.service.and.callFake(function (name, value) { - var factory = value[value.length - 1]; - - registered[name] = { - depends: value.slice(0, value.length - 1), - callback: value[value.length - 1] - }; - - // Track what name it was registered under - factory.registeredName = name; - }); - - compositor = new ServiceCompositor(mockApp, mockLog); - }); - - it("allows composite services to be registered", function () { - compositor.registerCompositeServices([ - { - type: "provider", - provides: "testService" - } - ]); - - expect(mockApp.service).toHaveBeenCalled(); - }); - - it("allows composite services to be registered", function () { - // Prepare components that look like resolved extensions - var components, name; - function MyDecorator() { - return {}; - } - - function MyOtherDecorator() { - return {}; - } - - function MyProvider() { - return {}; - } - - function MyOtherProvider() { - return {}; - } - - function MyAggregator() { - return {}; - } - - components = [ - MyDecorator, - MyProvider, - MyAggregator, - MyOtherDecorator, - MyOtherProvider - ]; - - MyDecorator.type = "decorator"; - MyOtherDecorator.type = "decorator"; - MyProvider.type = "provider"; - MyOtherProvider.type = "provider"; - MyAggregator.type = "aggregator"; - components.forEach(function (c) { - c.provides = "testService"; - }); - - // Add some test dependencies, to check prepending - MyOtherDecorator.depends = ["someOtherService"]; - MyAggregator.depends = ["tests[]"]; - - // Register! - compositor.registerCompositeServices(components); - - expect(mockApp.service).toHaveBeenCalled(); - - // Verify some interesting spots on dependency graph - expect(registered.testService.depends).toEqual([ - MyOtherDecorator.registeredName - ]); - expect(registered[MyOtherDecorator.registeredName].depends).toEqual([ - "someOtherService", - MyDecorator.registeredName - ]); - expect(registered[MyAggregator.registeredName].depends.length).toEqual(2); - // Get the name of the group of providers - name = registered[MyAggregator.registeredName].depends[1]; - // ...it should depend on both providers - expect(registered[name].depends).toEqual([ - MyProvider.registeredName, - MyOtherProvider.registeredName - ]); - }); - - it("allows registered composite services to be instantiated", function () { - // Prepare components that look like resolved extensions - var components, name; - function MyProvider() { - return {}; - } - - function MyOtherProvider() { - return {}; - } - - function MyAggregator() { - return {}; - } - - components = [MyProvider, MyAggregator, MyOtherProvider]; - - MyProvider.type = "provider"; - MyOtherProvider.type = "provider"; - MyAggregator.type = "aggregator"; - components.forEach(function (c) { - c.provides = "testService"; - }); - - // Register! - compositor.registerCompositeServices(components); - - expect(mockApp.service).toHaveBeenCalled(); - - // Test service should just be a reflecting dependency; - // it will depend upon (then return) the aggregator. - expect(registered.testService.callback("hello")).toEqual("hello"); - - // The aggregated provider dependencies should be similar, - // except they should reflect back the array of arguments. - // Get the name of the group of providers - name = registered[MyAggregator.registeredName].depends[0]; - // ...it should depend on both providers - expect(registered[name].callback(1, 2, "hello")).toEqual([1, 2, "hello"]); - - }); - - it("warns and skips components with no service type", function () { - // Prepare components that look like resolved extensions - var components; - function MyProvider() { - return {}; - } - - function MyDecorator() { - return {}; - } - - function MyAggregator() { - return {}; - } - - components = [MyProvider, MyAggregator, MyDecorator]; - - MyProvider.type = "provider"; - MyDecorator.type = "decorator"; - MyAggregator.type = "aggregator"; - - // Notably, we don't do - // components.forEach(function (c) { c.provides = "testService"; }); - - // Try to register... - compositor.registerCompositeServices(components); - - // Nothing should have gotten registered - expect(mockApp.service).not.toHaveBeenCalled(); - - // Should have gotten one warning for each skipped component - expect(mockLog.warn.calls.count()).toEqual(2); - expect(mockLog.info.calls.count()).toEqual(1); - }); - - it("warns about and skips aggregators with zero providers", function () { - // Prepare components that look like resolved extensions - var components; - function MyAggregator() { - return {}; - } - - components = [MyAggregator]; - - MyAggregator.type = "aggregator"; - MyAggregator.provides = "testService"; - - // Try to register... - compositor.registerCompositeServices(components); - - // Nothing should have gotten registered - expect(mockApp.service).not.toHaveBeenCalled(); - - // Should have gotten a warning - expect(mockLog.info).toHaveBeenCalled(); - }); - - it("warns about and skips decorators with nothing to decorate", function () { - // Prepare components that look like resolved extensions - var components; - function MyDecorator() { - return {}; - } - - components = [MyDecorator]; - - MyDecorator.type = "decorator"; - MyDecorator.provides = "testService"; - - // Try to register... - compositor.registerCompositeServices(components); - - // Nothing should have gotten registered - expect(mockApp.service).not.toHaveBeenCalled(); - - // Should have gotten a warning - expect(mockLog.warn).toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/framework/test/resolve/BundleResolverSpec.js b/platform/framework/test/resolve/BundleResolverSpec.js deleted file mode 100644 index 916916922f..0000000000 --- a/platform/framework/test/resolve/BundleResolverSpec.js +++ /dev/null @@ -1,71 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * BundleResolverSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/resolve/BundleResolver", "../../src/load/Bundle"], - function (BundleResolver, Bundle) { - - describe("The bundle resolver", function () { - var mockExtensionResolver, - mockLog, - resolver; - - beforeEach(function () { - mockExtensionResolver = jasmine.createSpyObj( - "extensionResolver", - ["resolve"] - ); - mockLog = jasmine.createSpyObj( - "$log", - ["error", "warn", "info", "debug"] - ); - - mockExtensionResolver.resolve.and.returnValue(Promise.resolve("a")); - - resolver = new BundleResolver( - mockExtensionResolver, - mockLog - ); - }); - - it("invokes the extension resolver for all bundle extensions", function () { - return resolver.resolveBundles([ - new Bundle("x", { extensions: { tests: [{}, {}, {}] } }), - new Bundle("y", { - extensions: { - tests: [{}, {}], - others: [{}, {}] - } - }), - new Bundle("z", { extensions: { others: [{}] } }) - ]).then(function (result) { - expect(result.tests).toEqual(["a", "a", "a", "a", "a"]); - expect(result.others).toEqual(["a", "a", "a"]); - }); - }); - - }); - } -); diff --git a/platform/framework/test/resolve/ExtensionResolverSpec.js b/platform/framework/test/resolve/ExtensionResolverSpec.js deleted file mode 100644 index e01119c6cc..0000000000 --- a/platform/framework/test/resolve/ExtensionResolverSpec.js +++ /dev/null @@ -1,114 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ExtensionResolverSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/resolve/ExtensionResolver", "../../src/load/Bundle"], - function (ExtensionResolver, Bundle) { - - describe("", function () { - var mockLoader, - mockLog, - resolver; - - // Test implementation, to load from the mock loader - function Constructor() { - return { someKey: "some value" }; - } - - Constructor.someProperty = "some static value"; - - beforeEach(function () { - mockLoader = jasmine.createSpyObj("loader", ["load"]); - - mockLog = jasmine.createSpyObj( - "$log", - ["error", "warn", "info", "debug"] - ); - - mockLoader.load.and.returnValue(Promise.resolve(Constructor)); - - resolver = new ExtensionResolver(mockLoader, mockLog); - }); - - it("requests implementations from the implementation loader", function () { - var bundle = new Bundle("w", { - sources: "x", - extensions: { tests: [{ implementation: "y/z.js" }] } - }), - extension = bundle.getExtensions("tests")[0]; - - return resolver.resolve(extension).then(function (result) { - // Verify that the right file was requested - expect(mockLoader.load).toHaveBeenCalledWith("w/x/y/z.js"); - - // We should have resolved to the constructor from above - expect(typeof result).toEqual('function'); - expect(result().someKey).toEqual("some value"); - }); - }); - - it("issues a warning and defaults to plain definition if load fails", function () { - var bundle = new Bundle("w", { - sources: "x", - extensions: { - tests: [{ - someOtherKey: "some other value", - implementation: "y/z.js" - }] - } - }), - extension = bundle.getExtensions("tests")[0]; - - mockLoader.load.and.returnValue(Promise.reject(new Error("test error"))); - - return resolver.resolve(extension).then(function (result) { - // Should have gotten a warning - expect(mockLog.warn).toHaveBeenCalled(); - // We should have resolved to the plain definition from above - expect(typeof result).not.toEqual('function'); - expect(result.someOtherKey).toEqual("some other value"); - }); - }); - - it("ensures implementation properties are exposed", function () { - var bundle = new Bundle("w", { - sources: "x", - extensions: { tests: [{ implementation: "y/z.js" }] } - }), - extension = bundle.getExtensions("tests")[0]; - - return resolver.resolve(extension).then(function (result) { - // Verify that the right file was requested - expect(mockLoader.load).toHaveBeenCalledWith("w/x/y/z.js"); - // We should have resolved to the constructor from above - expect(typeof result).toEqual('function'); - expect(result().someKey).toEqual("some value"); - expect(result.someProperty).toEqual("some static value"); - }); - }); - - }); - } -); diff --git a/platform/framework/test/resolve/ImplementationLoaderSpec.js b/platform/framework/test/resolve/ImplementationLoaderSpec.js deleted file mode 100644 index c28a18a7ac..0000000000 --- a/platform/framework/test/resolve/ImplementationLoaderSpec.js +++ /dev/null @@ -1,88 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * ImplementationLoaderSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../../src/resolve/ImplementationLoader"], - function (ImplementationLoader) { - - describe("The implementation loader", function () { - var required, - loader; - - function mockRequire(names, fulfill, reject) { - required = { - names: names, - fulfill: fulfill, - reject: reject - }; - } - - beforeEach(function () { - required = undefined; - loader = new ImplementationLoader(mockRequire); - }); - - it("passes script names to require", function () { - loader.load("xyz.js"); - expect(required.names).toEqual(["xyz.js"]); - }); - - it("wraps require results in a Promise that can resolve", function () { - // Load and get the result - var promise = loader.load("xyz.js").then(function (result) { - expect(result).toEqual("test result"); - }); - - required.fulfill("test result"); - - return promise; - }); - - it("wraps require results in a Promise that can reject", function () { - var result, - rejection; - - // Load and get the result - var promise = loader.load("xyz.js").then( - function (v) { - result = v; - }, - function (v) { - rejection = v; - }); - - expect(result).toBeUndefined(); - - required.reject("test result"); - - return promise.then(function () { - expect(result).toBeUndefined(); - expect(rejection).toEqual("test result"); - }); - }); - - }); - } -); diff --git a/platform/identity/README.md b/platform/identity/README.md deleted file mode 100644 index 4df89f7368..0000000000 --- a/platform/identity/README.md +++ /dev/null @@ -1,2 +0,0 @@ -This bundle is responsible for introducing identity management features -and API to Open MCT. diff --git a/platform/identity/bundle.js b/platform/identity/bundle.js deleted file mode 100644 index c4b6d66e25..0000000000 --- a/platform/identity/bundle.js +++ /dev/null @@ -1,87 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/IdentityAggregator", - "./src/IdentityProvider", - "./src/IdentityCreationDecorator", - "./src/IdentityIndicator" -], function ( - IdentityAggregator, - IdentityProvider, - IdentityCreationDecorator, - IdentityIndicator -) { - - return { - name: "platform/identity", - definition: { - "extensions": { - "components": [ - { - "implementation": IdentityAggregator, - "type": "aggregator", - "provides": "identityService", - "depends": [ - "$q" - ] - }, - { - "implementation": IdentityProvider, - "type": "provider", - "provides": "identityService", - "depends": [ - "$q" - ], - "priority": "fallback" - }, - { - "type": "decorator", - "provides": "creationService", - "implementation": IdentityCreationDecorator, - "depends": [ - "identityService" - ] - } - ], - "indicators": [ - { - "implementation": IdentityIndicator, - "depends": [ - "identityService" - ] - } - ], - "types": [ - { - "properties": [ - { - "key": "creator", - "name": "Creator" - } - ] - } - ] - } - } - }; -}); diff --git a/platform/identity/src/IdentityAggregator.js b/platform/identity/src/IdentityAggregator.js deleted file mode 100644 index 9ddf7dfaf0..0000000000 --- a/platform/identity/src/IdentityAggregator.js +++ /dev/null @@ -1,91 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * Defines interfaces and common infrastructure for establishing - * a user's identity. - * @namespace platform/identity - */ -define( - function () { - - /** - * Provides information about the currently logged-in - * user, if available. - * - * @interface IdentityService - */ - - /** - * Get information about the current user. This returns a promise - * which will resolve to metadata about the user, or undefined if - * no information about the user is available. - * - * @method IdentityService#getUser - * @returns {Promise.} a promise for metadata about - * the current user - */ - - /** - * Metadata about a user. - * - * @typedef IdentityMetadata - * @property {string} name the user's human-readable name - * @property {string} key the user's machine-readable name - */ - - /** - * Aggregator for multiple identity services. Exposes the first - * defined identity provided by any provider, according to - * priority order. - * - * @constructor - * @implements {IdentityService} - * @memberof platform/identity - */ - function IdentityAggregator($q, providers) { - this.providers = providers; - this.$q = $q; - } - - function delegateGetUser(provider) { - return provider.getUser(); - } - - function identity(value) { - return value; - } - - function giveFirst(results) { - return results.filter(identity)[0]; - } - - IdentityAggregator.prototype.getUser = function () { - var $q = this.$q, - promises = this.providers.map(delegateGetUser); - - return $q.all(promises).then(giveFirst); - }; - - return IdentityAggregator; - } -); diff --git a/platform/identity/src/IdentityCreationDecorator.js b/platform/identity/src/IdentityCreationDecorator.js deleted file mode 100644 index 6038096db0..0000000000 --- a/platform/identity/src/IdentityCreationDecorator.js +++ /dev/null @@ -1,53 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Adds a `creator` property to newly-created domain objects. - * @constructor - * @augments {platform/commonUI/browse.CreationService} - * @memberof platform/entanglement - */ - function IdentityCreationDecorator(identityService, creationService) { - this.identityService = identityService; - this.creationService = creationService; - } - - IdentityCreationDecorator.prototype.createObject = function (model, parent) { - var creationService = this.creationService, - identityService = this.identityService; - - return identityService.getUser().then(function (user) { - if (user && user.key) { - model.creator = user.key; - } - - return creationService.createObject(model, parent); - }); - }; - - return IdentityCreationDecorator; - } -); - diff --git a/platform/identity/src/IdentityIndicator.js b/platform/identity/src/IdentityIndicator.js deleted file mode 100644 index 539ba5b9cc..0000000000 --- a/platform/identity/src/IdentityIndicator.js +++ /dev/null @@ -1,60 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 showing the currently logged-in user. - * @constructor - * @memberof platform/identity - * @implements {Indicator} - * @param {IdentityService} identityService the identity service - */ - function IdentityIndicator(identityService) { - // Track the current connection state - var self = this; - - identityService.getUser().then(function (user) { - if (user && user.key) { - self.text = user.name || user.key; - self.description = "Logged in as " + user.key; - } - }); - } - - IdentityIndicator.prototype.getCssClass = function () { - return this.text && "icon-person"; - }; - - IdentityIndicator.prototype.getText = function () { - return this.text; - }; - - IdentityIndicator.prototype.getDescription = function () { - return this.description; - }; - - return IdentityIndicator; - } -); diff --git a/platform/identity/src/IdentityProvider.js b/platform/identity/src/IdentityProvider.js deleted file mode 100644 index b0319bdee5..0000000000 --- a/platform/identity/src/IdentityProvider.js +++ /dev/null @@ -1,51 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * Defines interfaces and common infrastructure for establishing - * a user's identity. - * @namespace platform/identity - */ -define( - function () { - - /** - * Default implementation of an identity service. Provides an - * unknown user as an `undefined` value; this is present simply - * to ensure that there is always an `identityService` available - * for platform components to use. - * - * @constructor - * @implements {IdentityService} - * @memberof platform/identity - */ - function IdentityProvider($q) { - this.userPromise = $q.when(undefined); - } - - IdentityProvider.prototype.getUser = function () { - return this.userPromise; - }; - - return IdentityProvider; - } -); diff --git a/platform/identity/test/IdentityAggregatorSpec.js b/platform/identity/test/IdentityAggregatorSpec.js deleted file mode 100644 index 29b24bf003..0000000000 --- a/platform/identity/test/IdentityAggregatorSpec.js +++ /dev/null @@ -1,139 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/IdentityAggregator"], - function (IdentityAggregator) { - - describe("The identity aggregator", function () { - var mockProviders, - mockQ, - resolves, - testUsers, - aggregator; - - function resolveProviderPromises() { - ['a', 'b', 'c'].forEach(function (id, i) { - resolves[id](testUsers[i]); - }); - } - - beforeEach(function () { - testUsers = [ - { - key: "user0", - name: "User Zero" - }, - { - key: "user1", - name: "User One" - }, - { - key: "user2", - name: "User Two" - } - ]; - - resolves = {}; - - mockProviders = ['a', 'b', 'c'].map(function (id) { - var mockProvider = jasmine.createSpyObj( - 'provider-' + id, - ['getUser'] - ); - - mockProvider.getUser.and.returnValue(new Promise(function (r) { - resolves[id] = r; - })); - - return mockProvider; - }); - - mockQ = jasmine.createSpyObj('$q', ['all']); - mockQ.all.and.callFake(function (promises) { - return Promise.all(promises); - }); - - aggregator = new IdentityAggregator( - mockQ, - mockProviders - ); - }); - - it("delegates to the aggregated providers", function () { - // Verify precondition - mockProviders.forEach(function (p) { - expect(p.getUser).not.toHaveBeenCalled(); - }); - - aggregator.getUser(); - - mockProviders.forEach(function (p) { - expect(p.getUser).toHaveBeenCalled(); - }); - }); - - it("returns the first result when it is defined", function () { - var promise = aggregator.getUser(); - - resolveProviderPromises(); - - return promise.then(function (user) { - expect(user).toEqual(testUsers[0]); - }); - }); - - it("returns a later result when earlier results are undefined", function () { - testUsers[0] = undefined; - - var promise = aggregator.getUser(); - - resolveProviderPromises(); - - return promise.then(function (user) { - expect(user).toEqual(testUsers[1]); - }); - }); - - it("returns undefined when no providers expose users", function () { - testUsers = [undefined, undefined, undefined]; - - var promise = aggregator.getUser(); - - resolveProviderPromises(); - - return promise.then(function (user) { - expect(user).toBe(undefined); - }); - }); - - it("returns undefined when there are no providers", function () { - var promise = new IdentityAggregator(mockQ, []).getUser(); - - return promise.then(function (user) { - expect(user).toBe(undefined); - }); - }); - - }); - } -); diff --git a/platform/identity/test/IdentityCreationDecoratorSpec.js b/platform/identity/test/IdentityCreationDecoratorSpec.js deleted file mode 100644 index ac85d599e1..0000000000 --- a/platform/identity/test/IdentityCreationDecoratorSpec.js +++ /dev/null @@ -1,95 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/IdentityCreationDecorator' - ], - function (IdentityCreationDecorator) { - - describe("IdentityCreationDecorator", function () { - var mockIdentityService, - mockCreationService, - mockParent, - mockCreatedObject, - decorator; - - beforeEach(function () { - mockIdentityService = jasmine.createSpyObj( - 'identityService', - ['getUser'] - ); - mockCreationService = jasmine.createSpyObj( - 'creationService', - ['createObject'] - ); - mockParent = jasmine.createSpyObj( - 'parentObject', - ['getCapability', 'getId', 'getModel', 'hasCapability', 'useCapability'] - ); - mockCreatedObject = jasmine.createSpyObj( - 'domainObject', - ['getCapability', 'getId', 'getModel', 'hasCapability', 'useCapability'] - ); - mockCreationService.createObject - .and.returnValue(Promise.resolve(mockCreatedObject)); - mockIdentityService.getUser - .and.returnValue(Promise.resolve({ key: "test-user-id" })); - mockParent.getId.and.returnValue('test-id'); - decorator = new IdentityCreationDecorator( - mockIdentityService, - mockCreationService - ); - }); - - it("delegates to its decorated service when identity is available", function () { - var testModel = { someKey: "some value" }; - - return decorator.createObject(testModel, mockParent) - .then(function (object) { - expect(object).toEqual(mockCreatedObject); - }); - }); - - it("adds a creator property", function () { - var testModel = { someKey: "some value" }; - - return decorator.createObject(testModel, mockParent) - .then(function (object) { - expect(object) - .toEqual(mockCreatedObject); - - // Make sure arguments were delegated appropriately - expect(mockCreationService.createObject) - .toHaveBeenCalledWith( - { - someKey: "some value", - creator: "test-user-id" - }, - mockParent - ); - }); - }); - - }); - } -); diff --git a/platform/identity/test/IdentityIndicatorSpec.js b/platform/identity/test/IdentityIndicatorSpec.js deleted file mode 100644 index 75491fe0db..0000000000 --- a/platform/identity/test/IdentityIndicatorSpec.js +++ /dev/null @@ -1,70 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/IdentityIndicator"], - function (IdentityIndicator) { - - describe("The identity indicator", function () { - var mockPromise, - mockIdentityService, - indicator; - - beforeEach(function () { - mockPromise = jasmine.createSpyObj('promise', ['then']); - mockIdentityService = jasmine.createSpyObj( - 'identityService', - ['getUser'] - ); - - mockIdentityService.getUser.and.returnValue(mockPromise); - - indicator = new IdentityIndicator(mockIdentityService); - }); - - it("shows information about the current user", function () { - mockPromise.then.calls.mostRecent().args[0]({ - key: "testuserid", - name: "A User" - }); - expect(indicator.getCssClass()).toEqual("icon-person"); - expect(indicator.getText()).toEqual("A User"); - expect(indicator.getDescription().indexOf("testuserid")) - .not.toEqual(-1); - }); - - it("shows nothing while no user information is available", function () { - expect(indicator.getCssClass()).toBeUndefined(); - expect(indicator.getText()).toBeUndefined(); - expect(indicator.getDescription()).toBeUndefined(); - }); - - it("shows nothing when there is no identity information", function () { - mockPromise.then.calls.mostRecent().args[0](undefined); - expect(indicator.getCssClass()).toBeUndefined(); - expect(indicator.getText()).toBeUndefined(); - expect(indicator.getDescription()).toBeUndefined(); - }); - - }); - } -); diff --git a/platform/identity/test/IdentityProviderSpec.js b/platform/identity/test/IdentityProviderSpec.js deleted file mode 100644 index 745d9c3c8e..0000000000 --- a/platform/identity/test/IdentityProviderSpec.js +++ /dev/null @@ -1,49 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/IdentityProvider' - ], - function (IdentityProvider) { - - describe("IdentityProvider", function () { - var mockQ, provider; - - beforeEach(function () { - mockQ = jasmine.createSpyObj('$q', ['when']); - mockQ.when.and.callFake(function (v) { - return Promise.resolve(v); - }); - - provider = new IdentityProvider(mockQ); - }); - - it("provides an undefined user", function () { - return provider.getUser().then(function (user) { - expect(user).toBe(undefined); - }); - }); - - }); - } -); diff --git a/platform/persistence/README.md b/platform/persistence/README.md deleted file mode 100644 index e5ffbd156d..0000000000 --- a/platform/persistence/README.md +++ /dev/null @@ -1 +0,0 @@ -This directory contains bundles relating to the persistence of domain objects. diff --git a/platform/persistence/aggregator/bundle.js b/platform/persistence/aggregator/bundle.js deleted file mode 100644 index c50a94f59e..0000000000 --- a/platform/persistence/aggregator/bundle.js +++ /dev/null @@ -1,46 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PersistenceAggregator" -], function ( - PersistenceAggregator -) { - - return { - name: "platform/persistence/aggregator", - definition: { - "extensions": { - "components": [ - { - "provides": "persistenceService", - "type": "aggregator", - "depends": [ - "$q" - ], - "implementation": PersistenceAggregator - } - ] - } - } - }; -}); diff --git a/platform/persistence/aggregator/src/PersistenceAggregator.js b/platform/persistence/aggregator/src/PersistenceAggregator.js deleted file mode 100644 index 84a8768dd0..0000000000 --- a/platform/persistence/aggregator/src/PersistenceAggregator.js +++ /dev/null @@ -1,90 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - // Return values to use when a persistence space is unknown, - // and there is no appropriate provider to route to. - var METHOD_DEFAULTS = { - createObject: false, - readObject: undefined, - listObjects: [], - updateObject: false, - deleteObject: false - }; - - /** - * Aggregates multiple persistence providers, such that they can be - * utilized as if they were a single object. This is achieved by - * routing persistence calls to an appropriate provider; the space - * specified at call time is matched with the first provider (per - * priority order) which reports that it provides persistence for - * this space. - * - * @memberof platform/persistence/aggregator - * @constructor - * @implements {PersistenceService} - * @param $q Angular's $q, for promises - * @param {PersistenceService[]} providers the providers to aggregate - */ - function PersistenceAggregator($q, providers) { - var providerMap = {}; - - function addToMap(provider) { - return provider.listSpaces().then(function (spaces) { - spaces.forEach(function (space) { - providerMap[space] = providerMap[space] || provider; - }); - }); - } - - this.providerMapPromise = $q.all(providers.map(addToMap)) - .then(function () { - return providerMap; - }); - } - - PersistenceAggregator.prototype.listSpaces = function () { - return this.providerMapPromise.then(function (map) { - return Object.keys(map); - }); - }; - - Object.keys(METHOD_DEFAULTS).forEach(function (method) { - PersistenceAggregator.prototype[method] = function (space) { - var delegateArgs = Array.prototype.slice.apply(arguments, []); - - return this.providerMapPromise.then(function (map) { - var provider = map[space]; - - return provider - ? provider[method].apply(provider, delegateArgs) - : METHOD_DEFAULTS[method]; - }); - }; - }); - - return PersistenceAggregator; - } -); diff --git a/platform/persistence/aggregator/test/PersistenceAggregatorSpec.js b/platform/persistence/aggregator/test/PersistenceAggregatorSpec.js deleted file mode 100644 index 86a93a89ad..0000000000 --- a/platform/persistence/aggregator/test/PersistenceAggregatorSpec.js +++ /dev/null @@ -1,105 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PersistenceAggregator'], - function (PersistenceAggregator) { - - var PERSISTENCE_SERVICE_METHODS = [ - 'listSpaces', - 'listObjects', - 'createObject', - 'readObject', - 'updateObject', - 'deleteObject' - ], - WRAPPED_METHODS = PERSISTENCE_SERVICE_METHODS.filter(function (m) { - return m !== 'listSpaces'; - }); - - function fakePromise(value) { - return (value || {}).then ? value : { - then: function (callback) { - return fakePromise(callback(value)); - } - }; - } - - describe("PersistenceAggregator", function () { - var mockQ, - mockProviders, - mockCallback, - testSpaces, - aggregator; - - beforeEach(function () { - testSpaces = ['a', 'b', 'c']; - mockQ = jasmine.createSpyObj("$q", ['all']); - mockProviders = testSpaces.map(function (space) { - var mockProvider = jasmine.createSpyObj( - 'provider-' + space, - PERSISTENCE_SERVICE_METHODS - ); - PERSISTENCE_SERVICE_METHODS.forEach(function (m) { - mockProvider[m].and.returnValue(fakePromise(true)); - }); - mockProvider.listSpaces.and.returnValue(fakePromise([space])); - - return mockProvider; - }); - mockCallback = jasmine.createSpy(); - - mockQ.all.and.callFake(function (fakePromises) { - var result = []; - fakePromises.forEach(function (p) { - p.then(function (v) { - result.push(v); - }); - }); - - return fakePromise(result); - }); - - aggregator = new PersistenceAggregator(mockQ, mockProviders); - }); - - it("exposes spaces for all providers", function () { - aggregator.listSpaces().then(mockCallback); - expect(mockCallback).toHaveBeenCalledWith(testSpaces); - }); - - WRAPPED_METHODS.forEach(function (m) { - it("redirects " + m + " calls to an appropriate provider", function () { - testSpaces.forEach(function (space, index) { - var key = 'key-' + space, - value = 'val-' + space; - expect(aggregator[m](space, key, value)) - .toEqual(mockProviders[index][m]()); - expect(mockProviders[index][m]) - .toHaveBeenCalledWith(space, key, value); - }); - }); - }); - - }); - } -); diff --git a/platform/persistence/elastic/README.md b/platform/persistence/elastic/README.md deleted file mode 100644 index 413501d9ca..0000000000 --- a/platform/persistence/elastic/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Elasticsearch Persistence Provider -An adapter for using Elastic for persistence of user-created objects. The installation function takes the URL for an -Elasticsearch server as a parameter. - -## Installation -```js -openmct.install(openmct.plugins.Elasticsearch('http://localhost:9200')) -``` \ No newline at end of file diff --git a/platform/persistence/elastic/bundle.js b/platform/persistence/elastic/bundle.js deleted file mode 100644 index 89082d4707..0000000000 --- a/platform/persistence/elastic/bundle.js +++ /dev/null @@ -1,97 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/ElasticPersistenceProvider", - "./src/ElasticSearchProvider", - "./src/ElasticIndicator" -], function ( - ElasticPersistenceProvider, - ElasticSearchProvider, - ElasticIndicator -) { - - return { - name: "platform/persistence/elastic", - definition: { - "name": "ElasticSearch Persistence", - "description": "Adapter to read and write objects using an ElasticSearch instance.", - "extensions": { - "components": [ - { - "provides": "persistenceService", - "type": "provider", - "implementation": ElasticPersistenceProvider, - "depends": [ - "$http", - "$q", - "PERSISTENCE_SPACE", - "ELASTIC_ROOT", - "ELASTIC_PATH" - ] - }, - { - "provides": "searchService", - "type": "provider", - "implementation": ElasticSearchProvider, - "depends": [ - "$http", - "ELASTIC_ROOT" - ] - } - ], - "constants": [ - { - "key": "PERSISTENCE_SPACE", - "value": "mct" - }, - { - "key": "ELASTIC_ROOT", - "value": "http://localhost:9200", - "priority": "fallback" - }, - { - "key": "ELASTIC_PATH", - "value": "mct/_doc", - "priority": "fallback" - }, - { - "key": "ELASTIC_INDICATOR_INTERVAL", - "value": 15000, - "priority": "fallback" - } - ], - "indicators": [ - { - "implementation": ElasticIndicator, - "depends": [ - "$http", - "$interval", - "ELASTIC_ROOT", - "ELASTIC_INDICATOR_INTERVAL" - ] - } - ] - } - } - }; -}); diff --git a/platform/persistence/elastic/src/ElasticIndicator.js b/platform/persistence/elastic/src/ElasticIndicator.js deleted file mode 100644 index b2e1788e11..0000000000 --- a/platform/persistence/elastic/src/ElasticIndicator.js +++ /dev/null @@ -1,104 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - // Set of connection states; changing among these states will be - // reflected in the indicator's appearance. - // CONNECTED: Everything nominal, expect to be able to read/write. - // DISCONNECTED: HTTP failed; maybe misconfigured, disconnected. - // PENDING: Still trying to connect, and haven't failed yet. - var CONNECTED = { - text: "Connected", - glyphClass: "ok", - statusClass: "s-status-on", - description: "Connected to the domain object database." - }, - DISCONNECTED = { - text: "Disconnected", - glyphClass: "err", - statusClass: "s-status-caution", - description: "Unable to connect to the domain object database." - }, - PENDING = { - text: "Checking connection..." - }; - - /** - * Indicator for the current ElasticSearch connection. Polls - * ElasticSearch at a regular interval (defined by bundle constants) - * to ensure that the database is available. - * @constructor - * @memberof platform/persistence/elastic - * @implements {Indicator} - * @param $http Angular's $http service - * @param $interval Angular's $interval service - * @param {string} path the URL to poll for elasticsearch availability - * @param {number} interval the interval, in milliseconds, to poll at - */ - function ElasticIndicator($http, $interval, path, interval) { - // Track the current connection state - var self = this; - - this.state = PENDING; - - // Callback if the HTTP request to ElasticSearch fails - function handleError() { - self.state = DISCONNECTED; - } - - // Callback if the HTTP request succeeds. - function handleResponse() { - self.state = CONNECTED; - } - - // Try to connect to ElasticSearch, and update the indicator. - function updateIndicator() { - $http.get(path).then(handleResponse, handleError); - } - - // Update the indicator initially, and start polling. - updateIndicator(); - $interval(updateIndicator, interval, 0, false); - } - - ElasticIndicator.prototype.getCssClass = function () { - return "c-indicator--clickable icon-suitcase"; - }; - - ElasticIndicator.prototype.getGlyphClass = function () { - return this.state.glyphClass; - }; - - ElasticIndicator.prototype.getText = function () { - return this.state.text; - }; - - ElasticIndicator.prototype.getDescription = function () { - return this.state.description; - }; - - return ElasticIndicator; - } -); diff --git a/platform/persistence/elastic/src/ElasticPersistenceProvider.js b/platform/persistence/elastic/src/ElasticPersistenceProvider.js deleted file mode 100644 index c2cd534c53..0000000000 --- a/platform/persistence/elastic/src/ElasticPersistenceProvider.js +++ /dev/null @@ -1,168 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -/** - * This bundle implements a persistence service which uses ElasticSearch to - * store documents. - * @namespace platform/persistence/elastic - */ -define( - [], - function () { - - // JSLint doesn't like underscore-prefixed properties, - // so hide them here. - var SRC = "_source", - CONFLICT = 409, - SEQ_NO = "_seq_no", - PRIMARY_TERM = "_primary_term"; - - /** - * The ElasticPersistenceProvider reads and writes JSON documents - * (more specifically, domain object models) to/from an ElasticSearch - * instance. - * @memberof platform/persistence/elastic - * @constructor - * @implements {PersistenceService} - * @param $http Angular's $http service - * @param $interval Angular's $interval service - * @param {string} space the name of the persistence space being served - * @param {string} root the root of the path to ElasticSearch - * @param {string} path the path to domain objects within ElasticSearch - */ - function ElasticPersistenceProvider($http, $q, space, root, path) { - this.spaces = [space]; - this.revs = {}; - this.$http = $http; - this.$q = $q; - this.root = root; - this.path = path; - } - - // Issue a request using $http; get back the plain JS object - // from the expected JSON response - ElasticPersistenceProvider.prototype.request = function (subpath, method, value, params) { - return this.$http({ - method: method, - url: this.root + '/' + this.path + '/' + subpath, - params: params, - data: value - }).then(function (response) { - return response.data; - }, function (response) { - return (response || {}).data; - }); - }; - - // Shorthand methods for GET/PUT methods - ElasticPersistenceProvider.prototype.get = function (subpath) { - return this.request(subpath, "GET"); - }; - - ElasticPersistenceProvider.prototype.put = function (subpath, value, params) { - return this.request(subpath, "PUT", value, params); - }; - - ElasticPersistenceProvider.prototype.del = function (subpath) { - return this.request(subpath, "DELETE"); - }; - - // Handle an update error - ElasticPersistenceProvider.prototype.handleError = function (response, key) { - var error = new Error("Persistence error."), - $q = this.$q; - if ((response || {}).status === CONFLICT) { - error.key = "revision"; - - // Load the updated model, then reject the promise - return this.get(key).then(function (res) { - error.model = res[SRC]; - - return $q.reject(error); - }); - } - - // Reject the promise - return this.$q.reject(error); - }; - - // Get a domain object model out of ElasticSearch's response - ElasticPersistenceProvider.prototype.getModel = function (response) { - if (response && response[SRC]) { - this.revs[response[SEQ_NO]] = response[SEQ_NO]; - this.revs[response[PRIMARY_TERM]] = response[PRIMARY_TERM]; - - return response[SRC]; - } else { - return undefined; - } - }; - - // Check the response to a create/update/delete request; - // track the rev if it's valid, otherwise return false to - // indicate that the request failed. - ElasticPersistenceProvider.prototype.checkResponse = function (response, key) { - if (response && !response.error) { - this.revs[SEQ_NO] = response[SEQ_NO]; - this.revs[PRIMARY_TERM] = response[PRIMARY_TERM]; - - return response; - } else { - return this.handleError(response, key); - } - }; - - // Public API - ElasticPersistenceProvider.prototype.listSpaces = function () { - return this.$q.when(this.spaces); - }; - - ElasticPersistenceProvider.prototype.listObjects = function () { - // Not yet implemented - return this.$q.when([]); - }; - - ElasticPersistenceProvider.prototype.createObject = function (space, key, value) { - return this.put(key, value).then(this.checkResponse.bind(this)); - }; - - ElasticPersistenceProvider.prototype.readObject = function (space, key) { - return this.get(key).then(this.getModel.bind(this)); - }; - - ElasticPersistenceProvider.prototype.updateObject = function (space, key, value) { - var self = this; - function checkUpdate(response) { - return self.checkResponse(response, key); - } - - return this.put(key, value) - .then(checkUpdate); - }; - - ElasticPersistenceProvider.prototype.deleteObject = function (space, key) { - return this.del(key).then(this.checkResponse.bind(this)); - }; - - return ElasticPersistenceProvider; - } -); diff --git a/platform/persistence/elastic/src/ElasticSearchProvider.js b/platform/persistence/elastic/src/ElasticSearchProvider.js deleted file mode 100644 index a8be8e010b..0000000000 --- a/platform/persistence/elastic/src/ElasticSearchProvider.js +++ /dev/null @@ -1,142 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 ElasticSearchProvider. Created by shale on 07/16/2015. - */ -define([ - -], function ( - -) { - - var ID_PROPERTY = '_id', - SOURCE_PROPERTY = '_source', - SCORE_PROPERTY = '_score'; - - /** - * A search service which searches through domain objects in - * the filetree using ElasticSearch. - * - * @constructor - * @param $http Angular's $http service, for working with urls. - * @param ROOT the constant `ELASTIC_ROOT` which allows us to - * interact with ElasticSearch. - */ - function ElasticSearchProvider($http, ROOT) { - this.$http = $http; - this.root = ROOT; - } - - /** - * Search for domain objects using elasticsearch as a search provider. - * - * @param {String} searchTerm the term to search by. - * @param {Number} [maxResults] the max number of results to return. - * @returns {Promise} promise for a modelResults object. - */ - ElasticSearchProvider.prototype.query = function (searchTerm, maxResults) { - var searchUrl = this.root + '/_search/', - params = {}, - provider = this; - - searchTerm = this.cleanTerm(searchTerm); - searchTerm = this.fuzzyMatchUnquotedTerms(searchTerm); - - params.q = searchTerm; - params.size = maxResults; - - return this - .$http({ - method: "GET", - url: searchUrl, - params: params - }) - .then(function success(succesResponse) { - return provider.parseResponse(succesResponse); - }, function error() { - // Gracefully fail. - return { - hits: [], - total: 0 - }; - }); - }; - - /** - * Clean excess whitespace from a search term and return the cleaned - * version. - * - * @private - * @param {string} the search term to clean. - * @returns {string} search terms cleaned of excess whitespace. - */ - ElasticSearchProvider.prototype.cleanTerm = function (term) { - return term.trim().replace(/ +/g, ' '); - }; - - /** - * Add fuzzy matching markup to search terms that are not quoted. - * - * The following: - * hello welcome "to quoted village" have fun - * will become - * hello~ welcome~ "to quoted village" have~ fun~ - * - * @private - */ - ElasticSearchProvider.prototype.fuzzyMatchUnquotedTerms = function (query) { - var matchUnquotedSpaces = '\\s+(?=([^"]*"[^"]*")*[^"]*$)', - matcher = new RegExp(matchUnquotedSpaces, 'g'); - - return query - .replace(matcher, '~ ') - .replace(/$/, '~') - .replace(/"~+/, '"'); - }; - - /** - * Parse the response from ElasticSearch and convert it to a - * modelResults object. - * - * @private - * @param response a ES response object from $http - * @returns modelResults - */ - ElasticSearchProvider.prototype.parseResponse = function (response) { - var results = response.data.hits.hits, - searchResults = results.map(function (result) { - return { - id: result[ID_PROPERTY], - model: result[SOURCE_PROPERTY], - score: result[SCORE_PROPERTY] - }; - }); - - return { - hits: searchResults, - total: response.data.hits.total - }; - }; - - return ElasticSearchProvider; -}); diff --git a/platform/persistence/elastic/test/ElasticIndicatorSpec.js b/platform/persistence/elastic/test/ElasticIndicatorSpec.js deleted file mode 100644 index ecac1fe4d4..0000000000 --- a/platform/persistence/elastic/test/ElasticIndicatorSpec.js +++ /dev/null @@ -1,109 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/ElasticIndicator"], - function (ElasticIndicator) { - - xdescribe("The ElasticSearch status indicator", function () { - var mockHttp, - mockInterval, - testPath, - testInterval, - mockPromise, - indicator; - - beforeEach(function () { - mockHttp = jasmine.createSpyObj("$http", ["get"]); - mockInterval = jasmine.createSpy("$interval"); - mockPromise = jasmine.createSpyObj("promise", ["then"]); - testPath = "/test/path"; - testInterval = 12321; // Some number - - mockHttp.get.and.returnValue(mockPromise); - - indicator = new ElasticIndicator( - mockHttp, - mockInterval, - testPath, - testInterval - ); - }); - - it("polls for changes", function () { - expect(mockInterval).toHaveBeenCalledWith( - jasmine.any(Function), - testInterval, - 0, - false - ); - }); - - it("has a database icon", function () { - expect(indicator.getCssClass()).toEqual("icon-suitcase"); - }); - - it("consults the database at the configured path", function () { - expect(mockHttp.get).toHaveBeenCalledWith(testPath); - }); - - it("changes when the database connection is nominal", function () { - var initialText = indicator.getText(), - initialDescrption = indicator.getDescription(), - initialGlyphClass = indicator.getGlyphClass(); - - // Nominal just means getting back an object, without - // an error field. - mockPromise.then.calls.mostRecent().args[0]({ data: {} }); - - // Verify that these values changed; - // don't test for specific text. - expect(indicator.getText()).not.toEqual(initialText); - expect(indicator.getGlyphClass()).not.toEqual(initialGlyphClass); - expect(indicator.getDescription()).not.toEqual(initialDescrption); - - // Do check for specific class - expect(indicator.getGlyphClass()).toEqual("ok"); - }); - - it("changes when the server cannot be reached", function () { - var initialText = indicator.getText(), - initialDescrption = indicator.getDescription(), - initialGlyphClass = indicator.getGlyphClass(); - - // Nominal just means getting back an object, without - // an error field. - mockPromise.then.calls.mostRecent().args[1]({ data: {} }); - - // Verify that these values changed; - // don't test for specific text. - expect(indicator.getText()).not.toEqual(initialText); - expect(indicator.getGlyphClass()).not.toEqual(initialGlyphClass); - expect(indicator.getDescription()).not.toEqual(initialDescrption); - - // Do check for specific class - expect(indicator.getGlyphClass()).toEqual("err"); - }); - - }); - } -); diff --git a/platform/persistence/elastic/test/ElasticPersistenceProviderSpec.js b/platform/persistence/elastic/test/ElasticPersistenceProviderSpec.js deleted file mode 100644 index 2bc8708124..0000000000 --- a/platform/persistence/elastic/test/ElasticPersistenceProviderSpec.js +++ /dev/null @@ -1,253 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/ElasticPersistenceProvider"], - function (ElasticPersistenceProvider) { - - describe("The ElasticSearch persistence provider", function () { - var mockHttp, - mockQ, - testSpace = "testSpace", - testRoot = "/test", - testPath = "db", - capture, - provider; - - function mockPromise(value) { - return (value || {}).then ? value : { - then: function (callback) { - return mockPromise(callback(value)); - } - }; - } - - beforeEach(function () { - mockHttp = jasmine.createSpy("$http"); - mockQ = jasmine.createSpyObj("$q", ["when", "reject"]); - - mockQ.when.and.callFake(mockPromise); - mockQ.reject.and.callFake(function (value) { - return { - then: function (ignored, callback) { - return mockPromise(callback(value)); - } - }; - }); - - // Capture promise results - capture = jasmine.createSpy("capture"); - - provider = new ElasticPersistenceProvider( - mockHttp, - mockQ, - testSpace, - testRoot, - testPath - ); - }); - - it("reports available spaces", function () { - provider.listSpaces().then(capture); - expect(capture).toHaveBeenCalledWith([testSpace]); - }); - - // General pattern of tests below is to simulate ElasticSearch's - // response, verify that request looks like what ElasticSearch - // would expect, and finally verify that ElasticPersistenceProvider's - // return values match what is expected. - it("lists all available documents", function () { - // Not implemented yet - provider.listObjects().then(capture); - expect(capture).toHaveBeenCalledWith([]); - }); - - it("allows object creation", function () { - var model = { someKey: "some value" }; - mockHttp.and.returnValue(mockPromise({ - data: { - "_id": "abc", - "_seq_no": 1, - "_primary_term": 1 - } - })); - provider.createObject("testSpace", "abc", model).then(capture); - expect(mockHttp).toHaveBeenCalledWith({ - url: "/test/db/abc", - method: "PUT", - data: model, - params: undefined - }); - expect(capture.calls.mostRecent().args[0]).toBeTruthy(); - }); - - it("allows object models to be read back", function () { - var model = { someKey: "some value" }; - mockHttp.and.returnValue(mockPromise({ - data: { - "_id": "abc", - "_seq_no": 1, - "_primary_term": 1, - "_source": model - } - })); - provider.readObject("testSpace", "abc").then(capture); - expect(mockHttp).toHaveBeenCalledWith({ - url: "/test/db/abc", - method: "GET", - params: undefined, - data: undefined - }); - expect(capture).toHaveBeenCalledWith(model); - }); - - it("allows object update", function () { - var model = { someKey: "some value" }; - - // First do a read to populate rev tags... - mockHttp.and.returnValue(mockPromise({ - data: { - "_id": "abc", - "_source": {} - } - })); - provider.readObject("testSpace", "abc"); - - // Now perform an update - mockHttp.and.returnValue(mockPromise({ - data: { - "_id": "abc", - "_seq_no": 1, - "_source": {} - } - })); - provider.updateObject("testSpace", "abc", model).then(capture); - expect(mockHttp).toHaveBeenCalledWith({ - url: "/test/db/abc", - method: "PUT", - params: undefined, - data: model - }); - expect(capture.calls.mostRecent().args[0]).toBeTruthy(); - }); - - it("allows object deletion", function () { - // First do a read to populate rev tags... - mockHttp.and.returnValue(mockPromise({ - data: { - "_id": "abc", - "_source": {} - } - })); - provider.readObject("testSpace", "abc"); - - // Now perform an update - mockHttp.and.returnValue(mockPromise({ - data: { - "_id": "abc", - "_source": {} - } - })); - provider.deleteObject("testSpace", "abc", {}).then(capture); - expect(mockHttp).toHaveBeenCalledWith({ - url: "/test/db/abc", - method: "DELETE", - params: undefined, - data: undefined - }); - expect(capture.calls.mostRecent().args[0]).toBeTruthy(); - }); - - it("returns undefined when objects are not found", function () { - // Act like a 404 - mockHttp.and.returnValue({ - then: function (success, fail) { - return mockPromise(fail()); - } - }); - provider.readObject("testSpace", "abc").then(capture); - expect(capture).toHaveBeenCalledWith(undefined); - }); - - it("handles rejection due to _seq_no", function () { - var model = { someKey: "some value" }, - mockErrorCallback = jasmine.createSpy('error'); - - // First do a read to populate rev tags... - mockHttp.and.returnValue(mockPromise({ - data: { - "_id": "abc", - "_seq_no": 1, - "_source": {} - } - })); - provider.readObject("testSpace", "abc"); - - // Now perform an update - mockHttp.and.returnValue(mockPromise({ - data: { - "status": 409, - "error": "Revision error..." - } - })); - provider.updateObject("testSpace", "abc", model).then( - capture, - mockErrorCallback - ); - - expect(capture).not.toHaveBeenCalled(); - expect(mockErrorCallback).toHaveBeenCalled(); - }); - - it("handles rejection due to unknown reasons", function () { - var model = { someKey: "some value" }, - mockErrorCallback = jasmine.createSpy('error'); - - // First do a read to populate rev tags... - mockHttp.and.returnValue(mockPromise({ - data: { - "_id": "abc", - "_seq_no": 1, - "_source": {} - } - })); - provider.readObject("testSpace", "abc"); - - // Now perform an update - mockHttp.and.returnValue(mockPromise({ - data: { - "status": 410, - "error": "Revision error..." - } - })); - provider.updateObject("testSpace", "abc", model).then( - capture, - mockErrorCallback - ); - - expect(capture).not.toHaveBeenCalled(); - expect(mockErrorCallback).toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/persistence/elastic/test/ElasticSearchProviderSpec.js b/platform/persistence/elastic/test/ElasticSearchProviderSpec.js deleted file mode 100644 index c56e5f2ca5..0000000000 --- a/platform/persistence/elastic/test/ElasticSearchProviderSpec.js +++ /dev/null @@ -1,164 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * SearchSpec. Created by shale on 07/31/2015. - */ -define([ - '../src/ElasticSearchProvider' -], function ( - ElasticSearchProvider -) { - - describe('ElasticSearchProvider', function () { - var $http, - ROOT, - provider; - - beforeEach(function () { - $http = jasmine.createSpy('$http'); - ROOT = 'http://localhost:9200'; - - provider = new ElasticSearchProvider($http, ROOT); - }); - - describe('query', function () { - beforeEach(function () { - spyOn(provider, 'cleanTerm').and.returnValue('cleanedTerm'); - spyOn(provider, 'fuzzyMatchUnquotedTerms').and.returnValue('fuzzy'); - spyOn(provider, 'parseResponse').and.returnValue('parsedResponse'); - $http.and.returnValue(Promise.resolve({ - data: { - hits: { - hits: [] - } - } - })); - }); - - it('cleans terms and adds fuzzyness', function () { - return provider.query('hello', 10) - .then(() => { - expect(provider.cleanTerm).toHaveBeenCalledWith('hello'); - expect(provider.fuzzyMatchUnquotedTerms) - .toHaveBeenCalledWith('cleanedTerm'); - }); - }); - - it('calls through to $http', function () { - return provider.query('hello', 10).then(() => { - expect($http).toHaveBeenCalledWith({ - method: 'GET', - params: { - q: 'fuzzy', - size: 10 - }, - url: 'http://localhost:9200/_search/' - }); - }); - }); - - it('gracefully fails when http fails', function () { - $http.and.returnValue(Promise.reject()); - - return provider - .query('hello', 10) - .then(function (results) { - expect(results).toEqual({ - hits: [], - total: 0 - }); - }); - }); - - it('parses and returns when http succeeds', function () { - $http.and.returnValue(Promise.resolve('successResponse')); - - return provider - .query('hello', 10) - .then(function (results) { - expect(provider.parseResponse) - .toHaveBeenCalledWith('successResponse'); - expect(results).toBe('parsedResponse'); - }); - }); - }); - - it('can clean terms', function () { - expect(provider.cleanTerm(' asdhs ')).toBe('asdhs'); - expect(provider.cleanTerm(' and some words')) - .toBe('and some words'); - expect(provider.cleanTerm('Nice input')).toBe('Nice input'); - }); - - it('can create fuzzy term matchers', function () { - expect(provider.fuzzyMatchUnquotedTerms('pwr dvc 43')) - .toBe('pwr~ dvc~ 43~'); - - expect(provider.fuzzyMatchUnquotedTerms( - 'hello welcome "to quoted village" have fun' - )).toBe( - 'hello~ welcome~ "to quoted village" have~ fun~' - ); - }); - - it('can parse responses', function () { - var elasticSearchResponse = { - data: { - hits: { - total: 2, - hits: [ - { - '_id': 'hit1Id', - '_source': 'hit1Model', - '_score': 0.56 - }, - { - '_id': 'hit2Id', - '_source': 'hit2Model', - '_score': 0.34 - } - ] - } - } - }; - - expect(provider.parseResponse(elasticSearchResponse)) - .toEqual({ - hits: [ - { - id: 'hit1Id', - model: 'hit1Model', - score: 0.56 - }, - { - id: 'hit2Id', - model: 'hit2Model', - score: 0.34 - } - ], - total: 2 - }); - }); - }); - -}); diff --git a/platform/persistence/queue/README.md b/platform/persistence/queue/README.md deleted file mode 100644 index b64bba3c34..0000000000 --- a/platform/persistence/queue/README.md +++ /dev/null @@ -1,5 +0,0 @@ -This bundle provides an Overwrite/Cancel dialog when persisting -domain objects, if persistence fails. It is meant to be paired -with a persistence adapter which performs revision-checking -on update calls, in order to provide the user interface for -choosing between Overwrite and Cancel in that situation. diff --git a/platform/persistence/queue/bundle.js b/platform/persistence/queue/bundle.js deleted file mode 100644 index 33d3ab0c20..0000000000 --- a/platform/persistence/queue/bundle.js +++ /dev/null @@ -1,82 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/QueuingPersistenceCapabilityDecorator", - "./src/PersistenceQueue", - "./src/PersistenceFailureController", - "./res/templates/persistence-failure-dialog.html" -], function ( - QueuingPersistenceCapabilityDecorator, - PersistenceQueue, - PersistenceFailureController, - persistenceFailureDialogTemplate -) { - - return { - name: "platform/persistence/queue", - definition: { - "extensions": { - "components": [ - { - "type": "decorator", - "provides": "capabilityService", - "implementation": QueuingPersistenceCapabilityDecorator, - "depends": [ - "persistenceQueue" - ] - } - ], - "services": [ - { - "key": "persistenceQueue", - "implementation": PersistenceQueue, - "depends": [ - "$q", - "$timeout", - "dialogService", - "PERSISTENCE_QUEUE_DELAY" - ] - } - ], - "constants": [ - { - "key": "PERSISTENCE_QUEUE_DELAY", - "value": 5 - } - ], - "templates": [ - { - "key": "persistence-failure-dialog", - "template": persistenceFailureDialogTemplate - } - ], - "controllers": [ - { - "key": "PersistenceFailureController", - "implementation": PersistenceFailureController - } - ] - } - } - }; -}); diff --git a/platform/persistence/queue/res/templates/persistence-failure-dialog.html b/platform/persistence/queue/res/templates/persistence-failure-dialog.html deleted file mode 100644 index 7b3f53aa3b..0000000000 --- a/platform/persistence/queue/res/templates/persistence-failure-dialog.html +++ /dev/null @@ -1,52 +0,0 @@ - - - -
      - External changes have been made to the following objects: -
        -
      • - - - was modified at - {{controller.formatTimestamp(failure.error.model.modified)}} - by - {{controller.formatUsername(failure.error.model.modifier)}} -
      • -
      - You may overwrite these objects, or discard your changes to keep - the updates that were made externally. -
      - -
      - Changes to these objects could not be saved for unknown reasons: -
        -
      • - - -
      • -
      -
      - -
      diff --git a/platform/persistence/queue/src/PersistenceFailureConstants.js b/platform/persistence/queue/src/PersistenceFailureConstants.js deleted file mode 100644 index b38c6c7cf4..0000000000 --- a/platform/persistence/queue/src/PersistenceFailureConstants.js +++ /dev/null @@ -1,28 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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({ - REVISION_ERROR_KEY: "revision", - OVERWRITE_KEY: "overwrite", - TIMESTAMP_FORMAT: "YYYY-MM-DD HH:mm:ss\\Z", - UNKNOWN_USER: "unknown user" -}); diff --git a/platform/persistence/queue/src/PersistenceFailureController.js b/platform/persistence/queue/src/PersistenceFailureController.js deleted file mode 100644 index 51fc9f59dd..0000000000 --- a/platform/persistence/queue/src/PersistenceFailureController.js +++ /dev/null @@ -1,55 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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', './PersistenceFailureConstants'], - function (moment, Constants) { - - /** - * Controller to support the template to be shown in the - * dialog shown for persistence failures. - * @constructor - * @memberof platform/persistence/queue - */ - function PersistenceFailureController() { - } - - /** - * Format a timestamp for display in the dialog. - * @memberof platform/persistence/queue.PersistenceFailureController# - */ - PersistenceFailureController.prototype.formatTimestamp = function (timestamp) { - return moment.utc(timestamp) - .format(Constants.TIMESTAMP_FORMAT); - }; - - /** - * Format a user name for display in the dialog. - * @memberof platform/persistence/queue.PersistenceFailureController# - */ - PersistenceFailureController.prototype.formatUsername = function (username) { - return username || Constants.UNKNOWN_USER; - }; - - return PersistenceFailureController; - } -); diff --git a/platform/persistence/queue/src/PersistenceFailureDialog.js b/platform/persistence/queue/src/PersistenceFailureDialog.js deleted file mode 100644 index d69a8c8520..0000000000 --- a/platform/persistence/queue/src/PersistenceFailureDialog.js +++ /dev/null @@ -1,78 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['./PersistenceFailureConstants'], - function (PersistenceFailureConstants) { - - var OVERWRITE_CANCEL_OPTIONS = [ - { - name: "Overwrite", - key: PersistenceFailureConstants.OVERWRITE_KEY - }, - { - name: "Discard", - key: "cancel" - } - ], - OK_OPTIONS = [{ - name: "OK", - key: "ok" - }]; - - /** - * Populates a `dialogModel` to pass to `dialogService.getUserChoise` - * in order to choose between Overwrite and Cancel. - * @constructor - * @memberof platform/persistence/queue - */ - function PersistenceFailureDialog(failures) { - var revisionErrors = [], - otherErrors = []; - - // Place this failure into an appropriate group - function categorizeFailure(failure) { - // Check if the error is due to object revision - var isRevisionError = ((failure || {}).error || {}).key - === PersistenceFailureConstants.REVISION_ERROR_KEY; - // Push the failure into the appropriate group - (isRevisionError ? revisionErrors : otherErrors).push(failure); - } - - // Separate into revision errors, and other errors - failures.forEach(categorizeFailure); - - return { - title: "Save Error", - template: "persistence-failure-dialog", - model: { - revised: revisionErrors, - unrecoverable: otherErrors - }, - options: revisionErrors.length > 0 - ? OVERWRITE_CANCEL_OPTIONS : OK_OPTIONS - }; - } - - return PersistenceFailureDialog; - } -); diff --git a/platform/persistence/queue/src/PersistenceFailureHandler.js b/platform/persistence/queue/src/PersistenceFailureHandler.js deleted file mode 100644 index ca31026a68..0000000000 --- a/platform/persistence/queue/src/PersistenceFailureHandler.js +++ /dev/null @@ -1,69 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - ['./PersistenceFailureDialog', './PersistenceFailureConstants'], - function (PersistenceFailureDialog, PersistenceFailureConstants) { - - /** - * Handle failures to persist domain object models. - * @param $q Angular's `$q` - * @param {DialogService} dialogService the dialog service - * @constructor - * @memberof platform/persistence/queue - */ - function PersistenceFailureHandler($q, dialogService) { - this.$q = $q; - this.dialogService = dialogService; - } - - /** - * Discard failures - * @param {Array} failures persistence failures, as prepared - * by PersistenceQueueHandler - * @memberof platform/persistence/queue.PersistenceFailureHandler# - */ - PersistenceFailureHandler.prototype.handle = function handleFailures(failures) { - - var dialogModel = new PersistenceFailureDialog(failures), - revisionErrors = dialogModel.model.revised, - $q = this.$q; - - // Discard changes for a failed refresh - function discard(failure) { - var persistence = - failure.domainObject.getCapability('persistence'); - - return persistence.refresh(); - } - - // Discard changes associated with a failed save - function discardAll(failuresToDiscard) { - return $q.all(failuresToDiscard.map(discard)); - } - - return discardAll(revisionErrors); - }; - - return PersistenceFailureHandler; - } -); diff --git a/platform/persistence/queue/src/PersistenceQueue.js b/platform/persistence/queue/src/PersistenceQueue.js deleted file mode 100644 index fe8b143ee2..0000000000 --- a/platform/persistence/queue/src/PersistenceQueue.js +++ /dev/null @@ -1,76 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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( - [ - './PersistenceQueueImpl', - './PersistenceQueueHandler', - './PersistenceFailureHandler' - ], - function ( - PersistenceQueueImpl, - PersistenceQueueHandler, - PersistenceFailureHandler - ) { - - /** - * The PersistenceQueue is used by the QueuingPersistenceCapability - * to aggregate calls for object persistence. These are then issued - * in a group, such that if some or all are rejected, this result can - * be shown to the user (again, in a group.) - * - * This constructor is exposed as a service, but handles only the - * wiring of injected dependencies; behavior is implemented in the - * various component parts. - * - * @param $timeout Angular's $timeout - * @param {PersistenceQueueHandler} handler handles actual - * persistence when the queue is flushed - * @param {number} [DELAY] optional; delay in milliseconds between - * attempts to flush the queue - * @constructor - * @memberof platform/persistence/queue - */ - function PersistenceQueue( - $q, - $timeout, - dialogService, - PERSISTENCE_QUEUE_DELAY - ) { - // Wire up injected dependencies - return new PersistenceQueueImpl( - $q, - $timeout, - new PersistenceQueueHandler( - $q, - new PersistenceFailureHandler( - $q, - dialogService - ) - ), - PERSISTENCE_QUEUE_DELAY - ); - } - - return PersistenceQueue; - } -); diff --git a/platform/persistence/queue/src/PersistenceQueueHandler.js b/platform/persistence/queue/src/PersistenceQueueHandler.js deleted file mode 100644 index be7fc75561..0000000000 --- a/platform/persistence/queue/src/PersistenceQueueHandler.js +++ /dev/null @@ -1,115 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Handles actual persistence invocations for queued persistence - * attempts, in a group. Handling in a group in this manner - * also allows failure to be handled in a group (e.g. in a single - * summary dialog.) - * @param $q Angular's $q, for promises - * @param {PersistenceFailureHandler} handler to invoke in the event - * that a persistence attempt fails. - * @constructor - * @memberof platform/persistence/queue - */ - function PersistenceQueueHandler($q, failureHandler) { - this.$q = $q; - this.failureHandler = failureHandler; - } - - /** - * Invoke the persist method on the provided persistence - * capabilities. - * @param {Object.} persistences - * capabilities to invoke, in id->capability pairs. - * @param {Object.} domainObjects - * associated domain objects, in id->object pairs. - * @param {PersistenceQueue} queue the persistence queue, - * to requeue as necessary - * @memberof platform/persistence/queue.PersistenceQueueHandler# - */ - PersistenceQueueHandler.prototype.persist = function (persistences, domainObjects, queue) { - var ids = Object.keys(persistences), - $q = this.$q, - failureHandler = this.failureHandler; - - // Handle a group of persistence invocations - function persistGroup(groupIds, persistenceCaps, domainObjs, pQueue) { - var failures = []; - - // Try to persist a specific domain object - function tryPersist(id) { - // Look up its persistence capability from the provided - // id->persistence object. - var persistence = persistenceCaps[id], - domainObject = domainObjs[id]; - - // Put a domain object back in the queue - // (e.g. after Overwrite) - function requeue() { - return pQueue.put(domainObject, persistence); - } - - // Handle success - function succeed(value) { - return value; - } - - // Handle failure (build up a list of failures) - function fail(error) { - failures.push({ - id: id, - persistence: persistence, - domainObject: domainObject, - requeue: requeue, - error: error - }); - - return false; - } - - // Invoke the actual persistence capability, then - // note success or failures - return persistence.persist().then(succeed, fail); - } - - // Handle any failures from the full operation - function handleFailure(value) { - return failures.length > 0 - ? failureHandler.handle(failures) - : value; - } - - // Try to persist everything, then handle any failures - return $q.all(groupIds.map(tryPersist)).then(handleFailure); - } - - return persistGroup(ids, persistences, domainObjects, queue); - }; - - return PersistenceQueueHandler; - } -); diff --git a/platform/persistence/queue/src/PersistenceQueueImpl.js b/platform/persistence/queue/src/PersistenceQueueImpl.js deleted file mode 100644 index c818334683..0000000000 --- a/platform/persistence/queue/src/PersistenceQueueImpl.js +++ /dev/null @@ -1,149 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The PersistenceQueue is used by the QueuingPersistenceCapability - * to aggregrate calls for object persistence. These are then issued - * in a group, such that if some or all are rejected, this result can - * be shown to the user (again, in a group.) - * - * This implementation is separate out from PersistenceQueue, which - * handles the wiring of injected dependencies into an instance of - * this class. - * - * @param $timeout Angular's $timeout - * @param {PersistenceQueueHandler} handler handles actual - * persistence when the queue is flushed - * @param {number} [DELAY] optional; delay in milliseconds between - * attempts to flush the queue - * @constructor - * @memberof platform/persistence/queue - */ - function PersistenceQueueImpl($q, $timeout, handler, delay) { - - this.persistences = {}; - this.objects = {}; - this.lastObservedSize = 0; - this.activeDefer = $q.defer(); - - // If no delay is provided, use a default - this.delay = delay || 0; - this.handler = handler; - this.$timeout = $timeout; - this.$q = $q; - } - - // Schedule a flushing of the queue (that is, plan to flush - // all objects in the queue) - PersistenceQueueImpl.prototype.scheduleFlush = function () { - var self = this, - $timeout = this.$timeout, - $q = this.$q, - handler = this.handler; - - // Check if the queue's size has stopped increasing) - function quiescent() { - return Object.keys(self.persistences).length - === self.lastObservedSize; - } - - // Persist all queued objects - function flush() { - // Get a local reference to the active promise; - // this will be replaced with a promise for the next round - // of persistence calls, so we want to make sure we clear - // the correct one when this flush completes. - var flushingDefer = self.activeDefer; - - // Clear the active promise for a queue flush - function clearFlushPromise(value) { - self.flushPromise = undefined; - flushingDefer.resolve(value); - - return value; - } - - // Persist all queued objects - self.flushPromise = handler.persist( - self.persistences, - self.objects, - self - ).then(clearFlushPromise, clearFlushPromise); - - // Reset queue, etc. - self.persistences = {}; - self.objects = {}; - self.lastObservedSize = 0; - self.pendingTimeout = undefined; - self.activeDefer = $q.defer(); - } - - function maybeFlush() { - // Timeout fired, so clear it - self.pendingTimeout = undefined; - // Only flush when we've stopped receiving updates - if (quiescent()) { - flush(); - } else { - self.scheduleFlush(); - } - - // Update lastObservedSize to detect quiescence - self.lastObservedSize = Object.keys(self.persistences).length; - } - - // If we are already flushing the queue... - if (self.flushPromise) { - // Wait until that's over before considering a flush - self.flushPromise.then(maybeFlush); - } else { - // Otherwise, schedule a flush on a timeout (to give - // a window for other updates to get aggregated) - self.pendingTimeout = self.pendingTimeout - || $timeout(maybeFlush, self.delay, false); - } - - return self.activeDefer.promise; - }; - - /** - * Queue persistence of a domain object. - * @param {DomainObject} domainObject the domain object - * @param {PersistenceCapability} persistence the object's - * undecorated persistence capability - * @returns {Promise} a promise which will resolve upon persistence - */ - PersistenceQueueImpl.prototype.put = function (domainObject, persistence) { - var id = domainObject.getId(); - this.persistences[id] = persistence; - this.objects[id] = domainObject; - - return this.scheduleFlush(); - }; - - return PersistenceQueueImpl; - } -); diff --git a/platform/persistence/queue/src/QueuingPersistenceCapability.js b/platform/persistence/queue/src/QueuingPersistenceCapability.js deleted file mode 100644 index 70fb144ca4..0000000000 --- a/platform/persistence/queue/src/QueuingPersistenceCapability.js +++ /dev/null @@ -1,51 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The QueuingPersistenceCapability places `persist` calls in a queue - * to be handled in batches. - * @param {PersistenceQueue} queue of persistence calls - * @param {PersistenceCapability} persistence the wrapped persistence - * capability - * @param {DomainObject} domainObject the domain object which exposes - * the capability - * @constructor - * @memberof platform/persistence/queue - */ - function QueuingPersistenceCapability(queue, persistence, domainObject) { - var queuingPersistence = Object.create(persistence); - - // Override persist calls to queue them instead - queuingPersistence.persist = function () { - return queue.put(domainObject, persistence); - }; - - return queuingPersistence; - } - - return QueuingPersistenceCapability; - } -); diff --git a/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js b/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js deleted file mode 100644 index d351c95633..0000000000 --- a/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js +++ /dev/null @@ -1,86 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 decorates the persistence service to handle persistence - * in batches, and to provide notification of persistence errors in batches - * as well. - * @namespace platform/persistence/queue - */ -define( - ['./QueuingPersistenceCapability'], - function (QueuingPersistenceCapability) { - - /** - * Capability decorator. Adds queueing support to persistence - * capabilities for domain objects, such that persistence attempts - * will be handled in batches (allowing failure notification to - * also be presented in batches.) - * - * @memberof platform/persistence/queue - * @constructor - * @implements {CapabilityService} - * @param {platform/persistence/queue.PersistenceQueue} persistenceQueue - * @param {CapabilityService} the decorated capability service - */ - function QueuingPersistenceCapabilityDecorator( - persistenceQueue, - capabilityService - ) { - this.persistenceQueue = persistenceQueue; - this.capabilityService = capabilityService; - } - - QueuingPersistenceCapabilityDecorator.prototype.getCapabilities = function (model, id) { - var capabilityService = this.capabilityService, - persistenceQueue = this.persistenceQueue; - - function decoratePersistence(capabilities) { - var originalPersistence = capabilities.persistence; - if (originalPersistence) { - capabilities.persistence = function (domainObject) { - // Get/instantiate the original - var original = - (typeof originalPersistence === 'function') - ? originalPersistence(domainObject) - : originalPersistence; - - // Provide a decorated version - return new QueuingPersistenceCapability( - persistenceQueue, - original, - domainObject - ); - }; - } - - return capabilities; - } - - return decoratePersistence( - capabilityService.getCapabilities(model, id) - ); - }; - - return QueuingPersistenceCapabilityDecorator; - } -); diff --git a/platform/persistence/queue/test/PersistenceFailureConstantsSpec.js b/platform/persistence/queue/test/PersistenceFailureConstantsSpec.js deleted file mode 100644 index d02071fd6a..0000000000 --- a/platform/persistence/queue/test/PersistenceFailureConstantsSpec.js +++ /dev/null @@ -1,34 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PersistenceFailureConstants"], - function (PersistenceFailureConstants) { - - describe("Persistence failure constants", function () { - it("defines an overwrite key", function () { - expect(PersistenceFailureConstants.OVERWRITE_KEY) - .toEqual(jasmine.any(String)); - }); - }); - } -); diff --git a/platform/persistence/queue/test/PersistenceFailureControllerSpec.js b/platform/persistence/queue/test/PersistenceFailureControllerSpec.js deleted file mode 100644 index a3ae852303..0000000000 --- a/platform/persistence/queue/test/PersistenceFailureControllerSpec.js +++ /dev/null @@ -1,45 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PersistenceFailureController"], - function (PersistenceFailureController) { - - describe("The persistence failure controller", function () { - var controller; - - beforeEach(function () { - controller = new PersistenceFailureController(); - }); - - it("converts timestamps to human-readable dates", function () { - expect(controller.formatTimestamp(402514331000)) - .toEqual("1982-10-03 17:32:11Z"); - }); - - it("provides default user names", function () { - expect(controller.formatUsername(undefined)) - .toEqual(jasmine.any(String)); - }); - }); - } -); diff --git a/platform/persistence/queue/test/PersistenceFailureDialogSpec.js b/platform/persistence/queue/test/PersistenceFailureDialogSpec.js deleted file mode 100644 index 950a11fe3c..0000000000 --- a/platform/persistence/queue/test/PersistenceFailureDialogSpec.js +++ /dev/null @@ -1,71 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PersistenceFailureDialog", "../src/PersistenceFailureConstants"], - function (PersistenceFailureDialog, Constants) { - - describe("The persistence failure dialog", function () { - var testFailures, - dialog; - - beforeEach(function () { - testFailures = [ - { - error: { key: Constants.REVISION_ERROR_KEY }, - someKey: "abc" - }, - { - error: { key: "..." }, - someKey: "def" - }, - { - error: { key: Constants.REVISION_ERROR_KEY }, - someKey: "ghi" - }, - { - error: { key: Constants.REVISION_ERROR_KEY }, - someKey: "jkl" - }, - { - error: { key: "..." }, - someKey: "mno" - } - ]; - dialog = new PersistenceFailureDialog(testFailures); - }); - - it("categorizes failures", function () { - expect(dialog.model.revised).toEqual([ - testFailures[0], testFailures[2], testFailures[3] - ]); - expect(dialog.model.unrecoverable).toEqual([ - testFailures[1], testFailures[4] - ]); - }); - - it("provides an overwrite option", function () { - expect(dialog.options[0].key).toEqual(Constants.OVERWRITE_KEY); - }); - }); - } -); diff --git a/platform/persistence/queue/test/PersistenceFailureHandlerSpec.js b/platform/persistence/queue/test/PersistenceFailureHandlerSpec.js deleted file mode 100644 index 30a7a4efbf..0000000000 --- a/platform/persistence/queue/test/PersistenceFailureHandlerSpec.js +++ /dev/null @@ -1,82 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PersistenceFailureHandler", "../src/PersistenceFailureConstants"], - function (PersistenceFailureHandler, Constants) { - - describe("The persistence failure handler", function () { - var mockQ, - mockDialogService, - mockFailures, - mockPromise, - handler; - - function makeMockFailure(id, index) { - var mockFailure = jasmine.createSpyObj( - 'failure-' + id, - ['requeue'] - ), - mockPersistence = jasmine.createSpyObj( - 'persistence-' + id, - ['refresh', 'persist'] - ); - mockFailure.domainObject = jasmine.createSpyObj( - 'domainObject', - ['getCapability', 'useCapability', 'getModel'] - ); - mockFailure.domainObject.getCapability.and.callFake(function (c) { - return (c === 'persistence') && mockPersistence; - }); - mockFailure.domainObject.getModel.and.returnValue({ - id: id, - modified: index - }); - mockFailure.persistence = mockPersistence; - mockFailure.id = id; - mockFailure.error = { key: Constants.REVISION_ERROR_KEY }; - - return mockFailure; - } - - beforeEach(function () { - mockQ = jasmine.createSpyObj('$q', ['all', 'when']); - mockDialogService = jasmine.createSpyObj('dialogService', ['getUserChoice']); - mockFailures = ['a', 'b', 'c'].map(makeMockFailure); - mockPromise = jasmine.createSpyObj('promise', ['then']); - mockDialogService.getUserChoice.and.returnValue(mockPromise); - mockQ.all.and.returnValue(mockPromise); - mockPromise.then.and.returnValue(mockPromise); - handler = new PersistenceFailureHandler(mockQ, mockDialogService); - }); - - it("discards on handle", function () { - handler.handle(mockFailures); - mockFailures.forEach(function (mockFailure) { - expect(mockFailure.persistence.refresh).toHaveBeenCalled(); - expect(mockFailure.requeue).not.toHaveBeenCalled(); - expect(mockFailure.domainObject.useCapability).not.toHaveBeenCalled(); - }); - }); - }); - } -); diff --git a/platform/persistence/queue/test/PersistenceQueueHandlerSpec.js b/platform/persistence/queue/test/PersistenceQueueHandlerSpec.js deleted file mode 100644 index 28f2281cbb..0000000000 --- a/platform/persistence/queue/test/PersistenceQueueHandlerSpec.js +++ /dev/null @@ -1,136 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PersistenceQueueHandler"], - function (PersistenceQueueHandler) { - - var TEST_ERROR = { someKey: "some value" }; - - describe("The persistence queue handler", function () { - var mockQ, - mockFailureHandler, - mockPersistences, - mockDomainObjects, - mockQueue, - mockRejection, - handler; - - function asPromise(value) { - return (value || {}).then ? value : { - then: function (callback) { - return asPromise(callback(value)); - } - }; - } - - function makeMockPersistence(id) { - var mockPersistence = jasmine.createSpyObj( - 'persistence-' + id, - ['persist', 'refresh'] - ); - mockPersistence.persist.and.returnValue(asPromise(true)); - - return mockPersistence; - } - - function makeMockDomainObject(id) { - var mockDomainObject = jasmine.createSpyObj( - 'domainObject-' + id, - ['getId'] - ); - mockDomainObject.getId.and.returnValue(id); - - return mockDomainObject; - } - - beforeEach(function () { - mockQ = jasmine.createSpyObj('$q', ['all']); - mockFailureHandler = jasmine.createSpyObj('handler', ['handle']); - mockQueue = jasmine.createSpyObj('queue', ['put']); - mockPersistences = {}; - mockDomainObjects = {}; - ['a', 'b', 'c'].forEach(function (id) { - mockPersistences[id] = makeMockPersistence(id); - mockDomainObjects[id] = makeMockDomainObject(id); - }); - mockRejection = jasmine.createSpyObj('rejection', ['then']); - mockQ.all.and.returnValue(asPromise([])); - mockRejection.then.and.callFake(function (callback, fallback) { - return asPromise(fallback({ someKey: "some value" })); - }); - handler = new PersistenceQueueHandler(mockQ, mockFailureHandler); - }); - - it("invokes persistence on all members in the group", function () { - handler.persist(mockPersistences, mockDomainObjects, mockQueue); - expect(mockPersistences.a.persist).toHaveBeenCalled(); - expect(mockPersistences.b.persist).toHaveBeenCalled(); - expect(mockPersistences.c.persist).toHaveBeenCalled(); - // No failures in this group - expect(mockFailureHandler.handle).not.toHaveBeenCalled(); - }); - - it("handles failures that occur", function () { - mockPersistences.b.persist.and.returnValue(mockRejection); - mockPersistences.c.persist.and.returnValue(mockRejection); - handler.persist(mockPersistences, mockDomainObjects, mockQueue); - expect(mockFailureHandler.handle).toHaveBeenCalledWith([ - { - id: 'b', - persistence: mockPersistences.b, - domainObject: mockDomainObjects.b, - requeue: jasmine.any(Function), - error: TEST_ERROR - }, - { - id: 'c', - persistence: mockPersistences.c, - domainObject: mockDomainObjects.c, - requeue: jasmine.any(Function), - error: TEST_ERROR - } - ]); - }); - - it("provides a requeue method for failures", function () { - // This method is needed by PersistenceFailureHandler - // to allow requeuing of objects for persistence when - // Overwrite is chosen. - mockPersistences.b.persist.and.returnValue(mockRejection); - handler.persist(mockPersistences, mockDomainObjects, mockQueue); - - // Verify precondition - expect(mockQueue.put).not.toHaveBeenCalled(); - - // Invoke requeue - mockFailureHandler.handle.calls.mostRecent().args[0][0].requeue(); - - // Should have returned the object to the queue - expect(mockQueue.put).toHaveBeenCalledWith( - mockDomainObjects.b, - mockPersistences.b - ); - }); - }); - } -); diff --git a/platform/persistence/queue/test/PersistenceQueueImplSpec.js b/platform/persistence/queue/test/PersistenceQueueImplSpec.js deleted file mode 100644 index 260f24f42f..0000000000 --- a/platform/persistence/queue/test/PersistenceQueueImplSpec.js +++ /dev/null @@ -1,153 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PersistenceQueueImpl"], - function (PersistenceQueueImpl) { - - var TEST_DELAY = 42; - - describe("The implemented persistence queue", function () { - var mockQ, - mockTimeout, - mockHandler, - mockDeferred, - mockPromise, - queue; - - function makeMockDomainObject(id) { - var mockDomainObject = jasmine.createSpyObj( - 'domainObject-' + id, - ['getId'] - ); - mockDomainObject.getId.and.returnValue(id); - - return mockDomainObject; - } - - function makeMockPersistence(id) { - var mockPersistence = jasmine.createSpyObj( - 'persistence-' + id, - ['persist'] - ); - - return mockPersistence; - } - - beforeEach(function () { - mockQ = jasmine.createSpyObj('$q', ['when', 'defer']); - mockTimeout = jasmine.createSpy('$timeout'); - mockHandler = jasmine.createSpyObj('handler', ['persist']); - mockDeferred = jasmine.createSpyObj('deferred', ['resolve']); - mockDeferred.promise = jasmine.createSpyObj('promise', ['then']); - mockPromise = jasmine.createSpyObj('promise', ['then']); - mockQ.defer.and.returnValue(mockDeferred); - mockTimeout.and.returnValue({}); - mockHandler.persist.and.returnValue(mockPromise); - mockPromise.then.and.returnValue(mockPromise); - queue = new PersistenceQueueImpl( - mockQ, - mockTimeout, - mockHandler, - TEST_DELAY - ); - }); - - it("schedules a timeout to persist objects", function () { - expect(mockTimeout).not.toHaveBeenCalled(); - queue.put(makeMockDomainObject('a'), makeMockPersistence('a')); - expect(mockTimeout).toHaveBeenCalledWith( - jasmine.any(Function), - TEST_DELAY, - false - ); - }); - - it("does not schedule multiple timeouts for multiple objects", function () { - // Put three objects in without triggering the timeout; - // shouldn't schedule multiple timeouts - queue.put(makeMockDomainObject('a'), makeMockPersistence('a')); - queue.put(makeMockDomainObject('b'), makeMockPersistence('b')); - queue.put(makeMockDomainObject('c'), makeMockPersistence('c')); - expect(mockTimeout.calls.count()).toEqual(1); - }); - - it("returns a promise", function () { - expect(queue.put(makeMockDomainObject('a'), makeMockPersistence('a'))) - .toEqual(mockDeferred.promise); - }); - - it("waits for quiescence to proceed", function () { - // Keep adding objects to the queue between timeouts. - // Should keep scheduling timeouts instead of resolving. - queue.put(makeMockDomainObject('a'), makeMockPersistence('a')); - expect(mockTimeout.calls.count()).toEqual(1); - mockTimeout.calls.mostRecent().args[0](); - queue.put(makeMockDomainObject('b'), makeMockPersistence('b')); - expect(mockTimeout.calls.count()).toEqual(2); - mockTimeout.calls.mostRecent().args[0](); - queue.put(makeMockDomainObject('c'), makeMockPersistence('c')); - expect(mockTimeout.calls.count()).toEqual(3); - mockTimeout.calls.mostRecent().args[0](); - expect(mockHandler.persist).not.toHaveBeenCalled(); - }); - - it("persists upon quiescence", function () { - // Add objects to the queue, but fire two timeouts afterward - queue.put(makeMockDomainObject('a'), makeMockPersistence('a')); - queue.put(makeMockDomainObject('b'), makeMockPersistence('b')); - queue.put(makeMockDomainObject('c'), makeMockPersistence('c')); - mockTimeout.calls.mostRecent().args[0](); - mockTimeout.calls.mostRecent().args[0](); - expect(mockHandler.persist).toHaveBeenCalled(); - }); - - it("waits on an active flush, while flushing", function () { - // Persist some objects - queue.put(makeMockDomainObject('a'), makeMockPersistence('a')); - queue.put(makeMockDomainObject('b'), makeMockPersistence('b')); - mockTimeout.calls.mostRecent().args[0](); - mockTimeout.calls.mostRecent().args[0](); - expect(mockTimeout.calls.count()).toEqual(2); - // Adding a new object should not trigger a new timeout, - // because we haven't completed the previous flush - queue.put(makeMockDomainObject('c'), makeMockPersistence('c')); - expect(mockTimeout.calls.count()).toEqual(2); - }); - - it("clears the active flush after it has completed", function () { - // Persist some objects - queue.put(makeMockDomainObject('a'), makeMockPersistence('a')); - queue.put(makeMockDomainObject('b'), makeMockPersistence('b')); - mockTimeout.calls.mostRecent().args[0](); - mockTimeout.calls.mostRecent().args[0](); - expect(mockTimeout.calls.count()).toEqual(2); - // Resolve the promise from handler.persist - mockPromise.then.calls.all()[0].args[0](true); - // Adding a new object should now trigger a new timeout, - // because we have completed the previous flush - queue.put(makeMockDomainObject('c'), makeMockPersistence('c')); - expect(mockTimeout.calls.count()).toEqual(3); - }); - }); - } -); diff --git a/platform/persistence/queue/test/PersistenceQueueSpec.js b/platform/persistence/queue/test/PersistenceQueueSpec.js deleted file mode 100644 index dba5f6aa45..0000000000 --- a/platform/persistence/queue/test/PersistenceQueueSpec.js +++ /dev/null @@ -1,53 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PersistenceQueue"], - function (PersistenceQueue) { - - describe("The persistence queue", function () { - var mockQ, - mockTimeout, - mockDialogService, - queue; - - beforeEach(function () { - mockQ = jasmine.createSpyObj("$q", ['defer']); - mockTimeout = jasmine.createSpy("$timeout"); - mockDialogService = jasmine.createSpyObj( - 'dialogService', - ['getUserChoice'] - ); - queue = new PersistenceQueue(mockQ, mockTimeout, mockDialogService); - }); - - // PersistenceQueue is just responsible for handling injected - // dependencies and wiring the PersistenceQueueImpl and its - // handlers. Functionality is tested there, so our test here is - // minimal (get back expected interface, no exceptions) - it("provides a queue with a put method", function () { - expect(queue.put).toEqual(jasmine.any(Function)); - }); - - }); - } -); diff --git a/platform/persistence/queue/test/QueuingPersistenceCapabilityDecoratorSpec.js b/platform/persistence/queue/test/QueuingPersistenceCapabilityDecoratorSpec.js deleted file mode 100644 index 2dda92d533..0000000000 --- a/platform/persistence/queue/test/QueuingPersistenceCapabilityDecoratorSpec.js +++ /dev/null @@ -1,83 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/QueuingPersistenceCapabilityDecorator"], - function (QueuingPersistenceCapabilityDecorator) { - - describe("A queuing persistence capability decorator", function () { - var mockQueue, - mockCapabilityService, - mockPersistenceConstructor, - mockPersistence, - mockDomainObject, - testModel, - testId, - decorator; - - beforeEach(function () { - mockQueue = jasmine.createSpyObj('queue', ['put']); - mockCapabilityService = jasmine.createSpyObj( - 'capabilityService', - ['getCapabilities'] - ); - testModel = { someKey: "some value" }; - testId = 'someId'; - mockPersistence = jasmine.createSpyObj( - 'persistence', - ['persist', 'refresh'] - ); - mockPersistenceConstructor = jasmine.createSpy(); - mockDomainObject = jasmine.createSpyObj( - 'domainObject', - ['getId'] - ); - - mockCapabilityService.getCapabilities.and.returnValue({ - persistence: mockPersistenceConstructor - }); - mockPersistenceConstructor.and.returnValue(mockPersistence); - - decorator = new QueuingPersistenceCapabilityDecorator( - mockQueue, - mockCapabilityService - ); - }); - - // Here, we verify that the decorator wraps the calls it is expected - // to wrap; remaining responsibility belongs to - // QueuingPersistenceCapability itself, which has its own tests. - - it("delegates to its wrapped service", function () { - decorator.getCapabilities(testModel, testId); - expect(mockCapabilityService.getCapabilities) - .toHaveBeenCalledWith(testModel, testId); - }); - - it("wraps its persistence capability's constructor", function () { - decorator.getCapabilities(testModel).persistence(mockDomainObject); - expect(mockPersistenceConstructor).toHaveBeenCalledWith(mockDomainObject); - }); - - }); - } -); diff --git a/platform/persistence/queue/test/QueuingPersistenceCapabilitySpec.js b/platform/persistence/queue/test/QueuingPersistenceCapabilitySpec.js deleted file mode 100644 index b4edcd645d..0000000000 --- a/platform/persistence/queue/test/QueuingPersistenceCapabilitySpec.js +++ /dev/null @@ -1,64 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/QueuingPersistenceCapability"], - function (QueuingPersistenceCapability) { - - describe("A queuing persistence capability", function () { - var mockQueue, - mockPersistence, - mockDomainObject, - persistence; - - beforeEach(function () { - mockQueue = jasmine.createSpyObj('queue', ['put']); - mockPersistence = jasmine.createSpyObj( - 'persistence', - ['persist', 'refresh'] - ); - mockDomainObject = {}; - persistence = new QueuingPersistenceCapability( - mockQueue, - mockPersistence, - mockDomainObject - ); - }); - - it("puts a request for persistence into the queue on persist", function () { - // Verify precondition - expect(mockQueue.put).not.toHaveBeenCalled(); - // Invoke persistence - persistence.persist(); - // Should have queued - expect(mockQueue.put).toHaveBeenCalledWith( - mockDomainObject, - mockPersistence - ); - }); - - it("exposes other methods from the wrapped persistence capability", function () { - expect(persistence.refresh).toBe(mockPersistence.refresh); - }); - }); - } -); diff --git a/platform/policy/README.md b/platform/policy/README.md deleted file mode 100644 index 571782c174..0000000000 --- a/platform/policy/README.md +++ /dev/null @@ -1,93 +0,0 @@ -# Overview - -This bundle provides support for policy in Open MCT. Policy can be -used to limit the applicability of certain actions, or more broadly, -to provide an extension point for arbitrary decisions. - -# Services - -This bundle introduces the `policyService`, which may be consulted for -various decisions which are intended to be open for extension. - -The `policyService` has a single method, `allow`, which takes three -arguments and returns a boolean value (true if policy says this decision -should be allowed, false if not): - -* `category`: A string identifying which kind of decision is being made. - Typically, this will be a non-plural form of an extension type that is - being filtered down; for instance, to check whether or not a given - action should be returned by an `actionService`, one would use the - `action` category of extension. -* `candidate`: An object representing the thing which shall or shall not - be allowed. Usually, this will be an instance of an extension of the - category defined above. - * This does need to be the case; additional - policies which are not specific to any extension may also be defined - and consulted using unique `category` identifiers. In this case, the - type of the object delivered for the candidate may be unique to the - policy type. -* `context`: An object representing the context in which the decision is - occurring. Its contents are specific to each policy category. -* `callback`: Optional; a function to call if the policy decision is - rejected. This function will be called with the `message` string - (which may be undefined) of whichever individual policy caused the - operation to fail. - -_Design rationale_: Returning a boolean here limits the amount of -information that can be conveyed by a policy decision, but has the -benefit of simplicity. In MCT on the desktop, the policy service -returned a more complex object with both a boolean status and a string -message; the string message was used rarely (by only around 15% of -policy user code) and as such is made optional in the call itself here. - -_Design rationale_: Returning a boolean instead of a promise here implies -that policy decisions must occur synchronously. This limits the logic -which can be involved in a policy decision, but broadens its applicability; -policy is meant to be used by a variety of other services to separate out -a certain category of business logic, and a synchronous response means -that this capability may be utilized by both synchronous and asynchronous -services. Additionally, policies will often be used in loops (e.g. to filter -down a set of applicable actions) where latency will have the result of -harming the user experience (e.g. the user right-clicks and gets stuck -waiting for a bunch of policy decisions to complete before a menu showing -available actions can appear.) - -The `policyService` is a composite service; it may be modified by adding -decorators, aggregators, etc. - -## Service Components - -The policy service is most often used by decorators for other composite -services. For instance, this bundle contains a decorator for `actionService` -which filters down the applicable actions exposed by that service based -on policy. - -# Policy Categories - -This bundle introduces `action` as a policy category. Policies of this -category shall take action instances as their candidate argument, and -action contexts as their context argument. - -# Extensions - -This bundle introduces the `policies` category of extension. An extension -of this category should have both an implementation, as well as the following -metadata: - -* `category`: A string identifying which kind of policy decision this - effects. -* `message`: Optional; a human-readable string describing the policy - decision when it fails. - -An extension of this category must also have an implementation which -takes no arguments to its constructor and provides a single method, -`allow`, which takes two arguments, `candidate` and `context` (see -descriptions above under documentation for `actionService`) and returns -a boolean indicating whether or not it allows the policy decision. - -Policy decisions require consensus among all policies; that is, if a -single policy returns false, then the policy decision as a whole returns -false. As a consequence, policies should be written in a permissive -manner; that is, they should be designed to prohibit behavior under a -specific set of conditions (by returning false), and allow any behavior -which does not match those conditions (by returning true.) diff --git a/platform/policy/bundle.js b/platform/policy/bundle.js deleted file mode 100644 index acadc4ca2c..0000000000 --- a/platform/policy/bundle.js +++ /dev/null @@ -1,69 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PolicyActionDecorator", - "./src/PolicyViewDecorator", - "./src/PolicyProvider" -], function ( - PolicyActionDecorator, - PolicyViewDecorator, - PolicyProvider -) { - - return { - name: "platform/policy", - definition: { - "name": "Policy Service", - "description": "Provides support for extension-driven decisions.", - "sources": "src", - "extensions": { - "components": [ - { - "type": "decorator", - "provides": "actionService", - "implementation": PolicyActionDecorator, - "depends": [ - "policyService" - ] - }, - { - "type": "decorator", - "provides": "viewService", - "implementation": PolicyViewDecorator, - "depends": [ - "policyService" - ] - }, - { - "type": "provider", - "provides": "policyService", - "implementation": PolicyProvider, - "depends": [ - "policies[]" - ] - } - ] - } - } - }; -}); diff --git a/platform/policy/src/PolicyActionDecorator.js b/platform/policy/src/PolicyActionDecorator.js deleted file mode 100644 index 5be65cd178..0000000000 --- a/platform/policy/src/PolicyActionDecorator.js +++ /dev/null @@ -1,55 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Filters out actions based on policy. - * @param {PolicyService} policyService the service which provides - * policy decisions - * @param {ActionService} actionService the service to decorate - * @constructor - * @memberof platform/policy - * @implements {ActionService} - */ - function PolicyActionDecorator(policyService, actionService) { - this.policyService = policyService; - this.actionService = actionService; - } - - PolicyActionDecorator.prototype.getActions = function (context) { - var policyService = this.policyService; - - // Check if an action is allowed by policy. - function allow(action) { - return policyService.allow('action', action, context); - } - - // Look up actions, filter out the disallowed ones. - return this.actionService.getActions(context).filter(allow); - }; - - return PolicyActionDecorator; - } -); diff --git a/platform/policy/src/PolicyProvider.js b/platform/policy/src/PolicyProvider.js deleted file mode 100644 index c0f1091ecf..0000000000 --- a/platform/policy/src/PolicyProvider.js +++ /dev/null @@ -1,143 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -/** - * This bundle implements the policy service. - * @namespace platform/policy - */ -define( - [], - function () { - - /** - * A policy is a participant in decision-making policies. Policies - * are divided into categories (identified symbolically by strings); - * within a given category, every given policy-driven decision will - * occur by consulting all available policies and requiring their - * collective consent (that is, every individual policy has the - * power to reject the decision entirely.) - * - * @interface Policy - * @template C, X - */ - - /** - * Check if this policy allows the described decision. The types - * of the arguments expected here vary depending on policy category. - * - * @method Policy#allow - * @template C, X - * @param {C} candidate the thing to allow or disallow - * @param {X} context the context in which the decision occurs - * @returns {boolean} false if disallowed; otherwise, true - */ - - /** - * The `policyService` handles decisions about what things - * are and are not allowed in certain contexts. - * @interface PolicyService - */ - - /** - * Check whether or not a certain decision is allowed by - * policy. - * @param {string} category a machine-readable identifier - * for the kind of decision being made - * @param candidate the object about which the decision is - * being made - * @param context the context in which the decision occurs - * @param {Function} [callback] callback to invoke with a - * string message describing the reason a decision - * was disallowed (if its disallowed) - * @returns {boolean} true if the decision is allowed, - * otherwise false. - * @method PolicyService#allow - */ - - /** - * Provides an implementation of `policyService` which consults - * various policy extensions to determine whether or not a specific - * decision should be allowed. - * @memberof platform/policy - * @constructor - * @implements {PolicyService} - * @param {Policy[]} policies the policies to enforce - */ - function PolicyProvider(policies) { - var policyMap = {}; - - // Instantiate a policy. Mostly just a constructor call, but - // we also track the message (which was provided as metadata - // along with the constructor) so that we can expose this later. - function instantiate(Policy) { - var policy = Object.create(new Policy()); - policy.message = Policy.message; - - return policy; - } - - // Add a specific policy to the map for later lookup, - // according to its category. Note that policy extensions are - // provided as constructors, so they are instantiated here. - function addToMap(Policy) { - var category = (Policy || {}).category; - if (category) { - // Create a new list for that category if needed... - policyMap[category] = policyMap[category] || []; - // ...and put an instance of this policy in that list. - policyMap[category].push(instantiate(Policy)); - } - } - - // Populate the map for subsequent lookup - policies.forEach(addToMap); - this.policyMap = policyMap; - } - - PolicyProvider.prototype.allow = function (category, candidate, context, callback) { - var policyList = this.policyMap[category] || [], - i; - - // Iterate through policies. We do this instead of map or - // forEach so that we can return immediately if a policy - // chooses to disallow this decision. - for (i = 0; i < policyList.length; i += 1) { - // Consult the policy... - if (!policyList[i].allow(candidate, context)) { - // ...it disallowed, so pass its message to - // the callback (if any) - if (callback) { - callback(policyList[i].message); - } - - // And return the failed result. - return false; - } - } - - // No policy disallowed this decision. - return true; - }; - - return PolicyProvider; - } -); diff --git a/platform/policy/src/PolicyViewDecorator.js b/platform/policy/src/PolicyViewDecorator.js deleted file mode 100644 index ed6baee435..0000000000 --- a/platform/policy/src/PolicyViewDecorator.js +++ /dev/null @@ -1,55 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Filters out views based on policy. - * @param {PolicyService} policyService the service which provides - * policy decisions - * @param {ViewService} viewService the service to decorate - * @constructor - * @memberof platform/policy - * @implements {ViewService} - */ - function PolicyViewDecorator(policyService, viewService) { - this.policyService = policyService; - this.viewService = viewService; - } - - PolicyViewDecorator.prototype.getViews = function (domainObject) { - var policyService = this.policyService; - - // Check if an action is allowed by policy. - function allow(view) { - return policyService.allow('view', view, domainObject); - } - - // Look up actions, filter out the disallowed ones. - return this.viewService.getViews(domainObject).filter(allow); - }; - - return PolicyViewDecorator; - } -); diff --git a/platform/policy/test/PolicyActionDecoratorSpec.js b/platform/policy/test/PolicyActionDecoratorSpec.js deleted file mode 100644 index f61c701741..0000000000 --- a/platform/policy/test/PolicyActionDecoratorSpec.js +++ /dev/null @@ -1,98 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PolicyActionDecorator"], - function (PolicyActionDecorator) { - - describe("The policy action decorator", function () { - var mockPolicyService, - mockActionService, - testContext, - testActions, - decorator; - - beforeEach(function () { - mockPolicyService = jasmine.createSpyObj( - 'policyService', - ['allow'] - ); - mockActionService = jasmine.createSpyObj( - 'actionService', - ['getActions'] - ); - - // Content of actions should be irrelevant to this - // decorator, so just give it some objects to pass - // around. - testActions = [ - { someKey: "a" }, - { someKey: "b" }, - { someKey: "c" } - ]; - testContext = { someKey: "some value" }; - - mockActionService.getActions.and.returnValue(testActions); - mockPolicyService.allow.and.returnValue(true); - - decorator = new PolicyActionDecorator( - mockPolicyService, - mockActionService - ); - }); - - it("delegates to its decorated action service", function () { - decorator.getActions(testContext); - expect(mockActionService.getActions) - .toHaveBeenCalledWith(testContext); - }); - - it("provides actions from its decorated action service", function () { - // Mock policy service allows everything by default, - // so everything should be returned - expect(decorator.getActions(testContext)) - .toEqual(testActions); - }); - - it("consults the policy service for each candidate action", function () { - decorator.getActions(testContext); - testActions.forEach(function (testAction) { - expect(mockPolicyService.allow).toHaveBeenCalledWith( - 'action', - testAction, - testContext - ); - }); - }); - - it("filters out policy-disallowed actions", function () { - // Disallow the second action - mockPolicyService.allow.and.callFake(function (cat, candidate) { - return candidate.someKey !== 'b'; - }); - expect(decorator.getActions(testContext)) - .toEqual([testActions[0], testActions[2]]); - }); - - }); - } -); diff --git a/platform/policy/test/PolicyProviderSpec.js b/platform/policy/test/PolicyProviderSpec.js deleted file mode 100644 index 9a2fe6fdad..0000000000 --- a/platform/policy/test/PolicyProviderSpec.js +++ /dev/null @@ -1,128 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PolicyProvider"], - function (PolicyProvider) { - - describe("The policy provider", function () { - var testPolicies, - mockPolicies, - mockPolicyConstructors, - testCandidate, - testContext, - provider; - - beforeEach(function () { - testPolicies = [ - { - category: "a", - message: "some message", - result: true - }, - { - category: "a", - result: true - }, - { - category: "a", - result: true - }, - { - category: "b", - message: "some message", - result: true - }, - { - category: "b", - result: true - }, - { - category: "b", - result: true - } - ]; - mockPolicies = testPolicies.map(function (p) { - var mockPolicy = jasmine.createSpyObj("policy", ['allow']); - mockPolicy.allow.and.callFake(function () { - return p.result; - }); - - return mockPolicy; - }); - mockPolicyConstructors = testPolicies.map(function (p, i) { - var mockPolicyConstructor = jasmine.createSpy(); - mockPolicyConstructor.and.returnValue(mockPolicies[i]); - mockPolicyConstructor.message = p.message; - mockPolicyConstructor.category = p.category; - - return mockPolicyConstructor; - }); - - testCandidate = { someKey: "some value" }; - testContext = { someOtherKey: "some other value" }; - - provider = new PolicyProvider(mockPolicyConstructors); - }); - - it("has an allow method", function () { - expect(provider.allow).toEqual(jasmine.any(Function)); - }); - - it("consults all relevant policies", function () { - provider.allow("a", testCandidate, testContext); - expect(mockPolicies[0].allow) - .toHaveBeenCalledWith(testCandidate, testContext); - expect(mockPolicies[1].allow) - .toHaveBeenCalledWith(testCandidate, testContext); - expect(mockPolicies[2].allow) - .toHaveBeenCalledWith(testCandidate, testContext); - expect(mockPolicies[3].allow) - .not.toHaveBeenCalled(); - expect(mockPolicies[4].allow) - .not.toHaveBeenCalled(); - expect(mockPolicies[5].allow) - .not.toHaveBeenCalled(); - }); - - it("allows what all policies allow", function () { - expect(provider.allow("a", testCandidate, testContext)) - .toBeTruthy(); - }); - - it("disallows what any one policy disallows", function () { - testPolicies[1].result = false; - expect(provider.allow("a", testCandidate, testContext)) - .toBeFalsy(); - }); - - it("provides a message for policy failure, when available", function () { - var mockCallback = jasmine.createSpy(); - testPolicies[0].result = false; - expect(provider.allow("a", testCandidate, testContext, mockCallback)) - .toBeFalsy(); - expect(mockCallback).toHaveBeenCalledWith(testPolicies[0].message); - }); - - }); - } -); diff --git a/platform/policy/test/PolicyViewDecoratorSpec.js b/platform/policy/test/PolicyViewDecoratorSpec.js deleted file mode 100644 index d215c46dd7..0000000000 --- a/platform/policy/test/PolicyViewDecoratorSpec.js +++ /dev/null @@ -1,102 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/PolicyViewDecorator"], - function (PolicyViewDecorator) { - - describe("The policy view decorator", function () { - var mockPolicyService, - mockViewService, - mockDomainObject, - testViews, - decorator; - - beforeEach(function () { - mockPolicyService = jasmine.createSpyObj( - 'policyService', - ['allow'] - ); - mockViewService = jasmine.createSpyObj( - 'viewService', - ['getViews'] - ); - mockDomainObject = jasmine.createSpyObj( - 'domainObject', - ['getId'] - ); - - // Content of actions should be irrelevant to this - // decorator, so just give it some objects to pass - // around. - testViews = [ - { someKey: "a" }, - { someKey: "b" }, - { someKey: "c" } - ]; - - mockDomainObject.getId.and.returnValue('xyz'); - mockViewService.getViews.and.returnValue(testViews); - mockPolicyService.allow.and.returnValue(true); - - decorator = new PolicyViewDecorator( - mockPolicyService, - mockViewService - ); - }); - - it("delegates to its decorated view service", function () { - decorator.getViews(mockDomainObject); - expect(mockViewService.getViews) - .toHaveBeenCalledWith(mockDomainObject); - }); - - it("provides views from its decorated view service", function () { - // Mock policy service allows everything by default, - // so everything should be returned - expect(decorator.getViews(mockDomainObject)) - .toEqual(testViews); - }); - - it("consults the policy service for each candidate view", function () { - decorator.getViews(mockDomainObject); - testViews.forEach(function (testView) { - expect(mockPolicyService.allow).toHaveBeenCalledWith( - 'view', - testView, - mockDomainObject - ); - }); - }); - - it("filters out policy-disallowed views", function () { - // Disallow the second action - mockPolicyService.allow.and.callFake(function (cat, candidate) { - return candidate.someKey !== 'b'; - }); - expect(decorator.getViews(mockDomainObject)) - .toEqual([testViews[0], testViews[2]]); - }); - - }); - } -); diff --git a/platform/representation/README.md b/platform/representation/README.md deleted file mode 100644 index 493a04bd0a..0000000000 --- a/platform/representation/README.md +++ /dev/null @@ -1,120 +0,0 @@ -This bundle introduces the notion of "representations" to Open MCT, -primarily via an Angular directive, `mct-representation`. - -A representation is used to display domain objects as Angular templates. - -# Extension Categories - -This bundle introduces four new categories of extension: - -* `templates`: Reusable Angular templates. This category of extension is - present to support the `mct-include` directive, which in turn is present - to allow templates to be loaded from across bundles, without knowing - their path ahead of time. A template has the following fields: - * `key`: The machine-readable name which identifies this template, - matched against the value given to the `key` attribute of the - `mct-include` directive. - * `templateUrl`: The path to the relevant Angular template. This - path is relative to the bundle's resources directory. -* `representations`: Ways of representing a domain object. A representation - is defined with the following fields: - * `key`: The machine-readable name which identifies the representation. - * `templateUrl`: The path to the representation's Angular template. This - path is relative to the bundle's resources directory. - * `uses`: An array of capability names. Indicates that this representation - intends to use those capabilities of a domain object (via a - `useCapability` call), and expects to find the latest results of - that `useCapability` call in the scope of the presented template (under - the same name as the capability itself.) - * `gestures`: An array of keys identifying gestures which should be - available upon this representation. Examples of gestures include - "drag" (for representations that should act as draggable sources - for drag-drop operations) and "menu" (for representations which - should show a domain-object-specific context menu on right-click.) -* `views`: A view is a representation with a visible identity to the user - (e.g. something they can switch among in the view menu.) A view - supports the same fields as a representation, and additionally: - * `name`: The human-readable name of the view. - * `glyph`: A character to display as an icon for this view. - * `description`: The human-readable description of the view. -* `gestures`: A gesture is a user action which can be taken upon a - representation of a domain object. Gestures are described by: - * `key`: The machine-readable name used to look up the gesture. - * `implementation`: The class (relative to the bundle's sources - directory) which implements the gesture. This is instantiated once - per representation that uses the gesture. This class will - receive the jqLite-wrapped `mct-representation` element and the - domain object being represented as arguments, and should do any - necessary "wiring" (e.g. listening for events) during its - constructor call. This class may also expose an optional `destroy()` - method which should be called when the gesture should be removed, - to avoid memory leaks by way of unremoved listeners. - - -# Extensions - -## Directives - -* `mct-include`: Includes a template by symbolic key; used to augment the - capability of Angular's `ng-include`, which loads templates by path. - Takes three attributes as Angular expressions: - * `key`: The symbolic identifier of the template to load, matched - against keys defined in extensions of category `templates`. - Note that this is an Angular expression, so internal quotes - may be necessary (see documentation of `ng-include`, which has the same - "gotcha" for URLs.) - * `ng-model`: Optional (and not often used); a model which should appear - in the included template's scope, for it to modify. The specific - interpretation of this attribute will vary depending on the included - template. - * `parameters`: Optional (and not often used); as `ng-model`, except the - intent is to provide information about how to display the included - template (e.g. "title", "color"). The specific interpretation of - this attribute will vary depending on the included template. -* `mct-representation`: Similar to `mct-include`, except the template to - include is specifically a representation of a domain object. - * `key`: As used in `mct-include`, except it will refer to an extension - or category `representations` or of `views`. - * `mct-object`: An Angular expression; the domain object to be - represented. - * `parameters`: As defined for `mct-include`. - -### Examples - - - - - - - - -## Components - -* `gestureService`: A provider of type `gestureService` is included to - remove the need to depend on `gestures[]` directly; instead, the - gesture service can be used to add/remove gestures in groups. This is - present primarily for bundle-internal use (it is used by the - `mct-representation` directive) but it is exposed as a service component - for convenience. - -## Gestures - -In addition to introducing `gestures` as a category of extension, this bundle -introduces three specific gestures as "built in" options, listed by key: - -* `drag`: Representations with this gesture can serve as drag sources for - drag-drop domain object composition. -* `drop`: Representations with this gesture can serve as drop targets for - drag-drop domain object composition. - * When a drop occurs, an `mctDrop` event will be broadcast with two - arguments (in addition to Angular's event object): The domain object - identifier for the dropped object, and the position (with `x` and `y` - properties in pixels) of the drop, relative to the top-left of the - representation which features the drop gesture. -* `menu`: Representations with this gesture will provide a custom context - menu (instead of the browser default). - * It should be noted that this gesture does _not_ define the appearance - or functionality of this menu; rather, it simply adds a - representation of key `context-menu` to the document at an appropriate - location. This representation will be supplied by the commonUI bundle. diff --git a/platform/representation/bundle.js b/platform/representation/bundle.js deleted file mode 100644 index 3a8debd9c9..0000000000 --- a/platform/representation/bundle.js +++ /dev/null @@ -1,144 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/MCTInclude", - "./src/MCTRepresentation", - "./src/gestures/DragGesture", - "./src/gestures/DropGesture", - "./src/gestures/GestureProvider", - "./src/gestures/GestureRepresenter", - "./src/services/DndService", - "./src/TemplateLinker", - "./src/TemplatePrefetcher" -], function ( - MCTInclude, - MCTRepresentation, - DragGesture, - DropGesture, - GestureProvider, - GestureRepresenter, - DndService, - TemplateLinker, - TemplatePrefetcher -) { - - return { - name: "platform/representation", - definition: { - "extensions": { - "directives": [ - { - "key": "mctInclude", - "implementation": MCTInclude, - "depends": [ - "templates[]", - "templateLinker" - ] - }, - { - "key": "mctRepresentation", - "implementation": MCTRepresentation, - "depends": [ - "representations[]", - "views[]", - "representers[]", - "$q", - "templateLinker", - "$log" - ] - } - ], - "gestures": [ - { - "key": "drag", - "implementation": DragGesture, - "depends": [ - "$log", - "dndService" - ] - }, - { - "key": "drop", - "implementation": DropGesture, - "depends": [ - "dndService", - "$q" - ] - } - ], - "components": [ - { - "provides": "gestureService", - "type": "provider", - "implementation": GestureProvider, - "depends": [ - "gestures[]" - ] - } - ], - "representers": [ - { - "implementation": GestureRepresenter, - "depends": [ - "gestureService" - ] - } - ], - "services": [ - { - "key": "dndService", - "implementation": DndService, - "depends": [ - "$log" - ] - }, - { - "key": "templateLinker", - "implementation": TemplateLinker, - "depends": [ - "$templateRequest", - "$sce", - "$compile", - "$log" - ], - "comment": "For internal use by mct-include and mct-representation." - } - ], - "runs": [ - { - "priority": "mandatory", - "implementation": TemplatePrefetcher, - "depends": [ - "templateLinker", - "templates[]", - "views[]", - "representations[]", - "controls[]", - "containers[]" - ] - } - ] - } - } - }; -}); diff --git a/platform/representation/src/MCTInclude.js b/platform/representation/src/MCTInclude.js deleted file mode 100644 index dfb36343c9..0000000000 --- a/platform/representation/src/MCTInclude.js +++ /dev/null @@ -1,102 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 MCTInclude. Created by vwoeltje on 11/7/14. - */ -define( - [], - function () { - - /** - * Defines the mct-include directive. This acts like the - * ng-include directive, except it accepts a symbolic - * key which can be exposed by bundles, instead of requiring - * an explicit path. - * - * This directive uses two-way binding for three attributes: - * - * * `key`, matched against the key of a defined template extension - * in order to determine which actual template to include. - * * `ng-model`, populated as `ngModel` in the loaded template's - * scope; used for normal ng-model purposes (e.g. if the - * included template is meant to two-way bind to a data model.) - * * `parameters`, used to communicate display parameters to - * the included template (e.g. title.) The difference between - * `parameters` and `ngModel` is intent: Both are two-way - * bound, but `ngModel` is useful for data models (more like - * an output) and `parameters` is meant to be useful for - * display parameterization (more like an input.) - * - * @memberof platform/representation - * @constructor - * @param {TemplateDefinition[]} templates an array of - * template extensions - */ - function MCTInclude(templates, templateLinker) { - var templateMap = {}; - - function link(scope, element) { - var changeTemplate = templateLinker.link( - scope, - element, - scope.key && templateMap[scope.key] - ); - - scope.$watch('key', function (newKey, oldKey) { - if (newKey !== oldKey) { - changeTemplate(newKey && templateMap[newKey]); - } - }); - } - - // Prepopulate templateMap for easy look up by key - templates.forEach(function (template) { - var key = template.key; - // First found should win (priority ordering) - templateMap[key] = - templateMap[key] || template; - }); - - return { - // Only show at the element level - restrict: "E", - - // Use the included controller to populate scope - link: link, - - // May hide the element, so let other directives act first - priority: -1000, - - // Two-way bind key, ngModel, and parameters - scope: { - key: "=", - ngModel: "=", - parameters: "=" - } - }; - } - - return MCTInclude; - } -); - diff --git a/platform/representation/src/MCTRepresentation.js b/platform/representation/src/MCTRepresentation.js deleted file mode 100644 index b452e35983..0000000000 --- a/platform/representation/src/MCTRepresentation.js +++ /dev/null @@ -1,308 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -/** - * This bundle implements the directives for representing domain objects - * as Angular-managed HTML. - * @namespace platform/representation - */ -define( - [], - function () { - - /** - * Defines the mct-representation directive. This may be used to - * present domain objects as HTML (with event wiring), with the - * specific representation being mapped to a defined extension - * (as defined in either the `representation` category-of-extension, - * or the `views` category-of-extension.) - * - * This directive uses two-way binding for three attributes: - * - * * `key`, matched against the key of a defined template extension - * in order to determine which actual template to include. - * * `mct-object`, populated as `domainObject` in the loaded - * template's scope. This is the domain object being - * represented as HTML by this directive. - * * `parameters`, used to communicate display parameters to - * the included template (e.g. title.) - * - * @memberof platform/representation - * @constructor - * @param {RepresentationDefinition[]} representations an array of - * representation extensions - * @param {ViewDefinition[]} views an array of view extensions - */ - function MCTRepresentation(representations, views, representers, $q, templateLinker, $log) { - var representationMap = {}; - - // Assemble all representations and views - // The distinction between views and representations is - // not important here (view is-a representation) - representations.concat(views).forEach(function (representation) { - var key = representation.key; - - // Store the representation - representationMap[key] = representationMap[key] || []; - representationMap[representation.key].push(representation); - }); - - // Look up a matching representation for this domain object - function lookup(key, domainObject) { - var candidates = representationMap[key] || [], - type, - i; - // Filter candidates by object type - for (i = 0; i < candidates.length; i += 1) { - type = candidates[i].type; - if (!type || !domainObject - || domainObject.getCapability('type').instanceOf(type)) { - return candidates[i]; - } - } - } - - function link($scope, element, attrs) { - var activeRepresenters = representers.map(function (Representer) { - return new Representer($scope, element, attrs); - }), - toClear = [], // Properties to clear out of scope on change - counter = 0, - couldRepresent = false, - lastIdPath = [], - lastKey, - mutationListener, - changeTemplate = templateLinker.link($scope, element); - - // Populate scope with any capabilities indicated by the - // representation's extension definition - function refreshCapabilities() { - var domainObject = $scope.domainObject, - representation = lookup($scope.key, domainObject), - uses = ((representation || {}).uses || []), - myCounter = counter; - - if (mutationListener) { - mutationListener(); - mutationListener = undefined; - } - - if (domainObject) { - mutationListener = domainObject - .getCapability('mutation') - .listen(refreshCapabilities); - - // Update model - $scope.model = domainObject.getModel(); - - // Provide any of the capabilities requested - uses.forEach(function (used) { - $log.debug([ - "Requesting capability ", - used, - " for representation ", - $scope.key - ].join("")); - - $q.when( - domainObject.useCapability(used) - ).then(function (c) { - // Avoid clobbering capabilities from - // subsequent representations; - // Angular reuses scopes. - if (counter === myCounter) { - $scope[used] = c; - } - }); - }); - } - } - - // Destroy (deallocate any resources associated with) any - // active representers. - function destroyRepresenters() { - activeRepresenters.forEach(function (activeRepresenter) { - activeRepresenter.destroy(); - }); - } - - function unchanged(canRepresent, idPath, key) { - return (canRepresent === couldRepresent) - && (key === lastKey) - && (idPath.length === lastIdPath.length) - && idPath.every(function (id, i) { - return id === lastIdPath[i]; - }); - } - - function getIdPath(domainObject) { - if (!domainObject) { - return []; - } - - if (!domainObject.hasCapability('context')) { - return [domainObject.getId()]; - } - - return domainObject.getCapability('context') - .getPath().map(function (pathObject) { - return pathObject.getId(); - }); - } - - // General-purpose refresh mechanism; should set up the scope - // as appropriate for current representation key and - // domain object. - function refresh() { - var domainObject = $scope.domainObject, - representation = lookup($scope.key, domainObject), - uses = ((representation || {}).uses || []), - canRepresent = Boolean(representation && domainObject), - idPath = getIdPath(domainObject), - key = $scope.key; - - if (unchanged(canRepresent, idPath, key)) { - return; - } - - // Create an empty object named "representation", for this - // representation to store local variables into. - $scope.representation = {}; - - // Change templates (passing in undefined to clear - // if we don't have enough info to show a template.) - changeTemplate(canRepresent ? representation : undefined); - - // Any existing representers are no longer valid; release them. - destroyRepresenters(); - - // Log if a key was given, but no matching representation - // was found. - if (!representation && $scope.key) { - $log.warn("No representation found for " + $scope.key); - } - - // Clear out the scope from the last representation - toClear.forEach(function (property) { - delete $scope[property]; - }); - - // To allow simplified change detection next time around - couldRepresent = canRepresent; - lastIdPath = idPath; - lastKey = key; - - // Populate scope with fields associated with the current - // domain object (if one has been passed in) - if (canRepresent) { - // Track how many representations we've made in this scope, - // to ensure that the correct representations are matched to - // the correct object/key pairs. - counter += 1; - - // Initialize any capabilities - refreshCapabilities(); - - // Also provide the view configuration, - // for the specific view - $scope.configuration = - ($scope.model.configuration || {})[$scope.key] || {}; - - // Finally, wire up any additional behavior (such as - // gestures) associated with this representation. - activeRepresenters.forEach(function (representer) { - representer.represent(representation, domainObject); - }); - - // Track which properties we want to clear from scope - // next change object/key pair changes - toClear = uses.concat(['model']); - } - } - - // Update the representation when the key changes (e.g. if a - // different representation has been selected) - $scope.$watch("key", refresh); - - // Also update when the represented domain object changes - // (to a different object) - $scope.$watch("domainObject", refresh); - - // Make sure any resources allocated by representers also get - // released. - $scope.$on("$destroy", destroyRepresenters); - $scope.$on("$destroy", function () { - if (mutationListener) { - mutationListener(); - } - }); - - // Do one initial refresh, so that we don't need another - // digest iteration just to populate the scope. Failure to - // do this can result in unstable digest cycles, which - // Angular will detect, and throw an Error about. - refresh(); - } - - return { - // Only applicable at the element level - restrict: "E", - - // Handle Angular's linking step - link: link, - - // May hide the element, so let other directives act first - priority: -1000, - - // Two-way bind key and parameters, get the represented domain - // object as "mct-object" - scope: { - key: "=", - domainObject: "=mctObject", - ngModel: "=", - parameters: "=" - } - }; - } - - /** - * A representer participates in the process of instantiating a - * representation of a domain object. - * - * @interface Representer - * @augments {Destroyable} - */ - /** - * Set the current representation in use, and the domain - * object being represented. - * - * @method Representer#represent - * @param {RepresentationDefinition} representation the - * definition of the representation in use - * @param {DomainObject} domainObject the domain object - * being represented - */ - - return MCTRepresentation; - } -); - diff --git a/platform/representation/src/TemplateLinker.js b/platform/representation/src/TemplateLinker.js deleted file mode 100644 index 47ca56fa62..0000000000 --- a/platform/representation/src/TemplateLinker.js +++ /dev/null @@ -1,177 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The `templateLinker` service is intended for internal use by - * the `mct-include` and `mct-representation` directives. It is - * used to support common behavior of directives; specifically, - * loading templates and inserting them into a specified element, - * and/or removing that element from the DOM when there is no - * template to populate it with. - * - * @param {Function} $templateRequest Angular's `$templateRequest` - * service - * @param $sce Angular's `$sce` service - * @param {Function} $compile Angular's `$compile` service - * @param $log Angular's `$log` service - * @private - */ - function TemplateLinker($templateRequest, $sce, $compile, $log) { - this.$templateRequest = $templateRequest; - this.$sce = $sce; - this.$compile = $compile; - this.$log = $log; - } - - /** - * Load a template from the given URL. This request will be handled - * via `$templateRequest` to ensure caching et cetera. - * @param {string} the URL for the template - * @returns {Promise.} a promise for the HTML content of - * the template - */ - TemplateLinker.prototype.load = function (templateUrl) { - return this.$templateRequest( - this.$sce.trustAsResourceUrl(templateUrl), - false - ); - }; - - /** - * Get a path to a template from an extension definition fo - * a template, representation, or view. - * @param {TemplateDefinition} extensionDefinition the definition - * of the template/representation/view to resolve - */ - TemplateLinker.prototype.getPath = function (extensionDefinition) { - return [ - extensionDefinition.bundle.path, - extensionDefinition.bundle.resources, - extensionDefinition.templateUrl - ].join('/'); - }; - - /** - * Populate the given element with templates, within the given scope; - * intended to support the `link` function of the supported directives. - * - * @param {Scope} scope the Angular scope to use when rendering - * templates - * @param element the jqLite-wrapped element into which templates - * should be inserted - * @param {TemplateDefinition} extensionDefinition the definition - * of the template/representation/view to display initially - * @returns {Function} a function which can be called with a template's - * extension definition to switch templates, or `undefined` - * to remove. - */ - TemplateLinker.prototype.link = function (scope, element, ext) { - var activeElement = element, - activeTemplateUrl, - comment = this.$compile('')(scope), - activeScope, - self = this; - - function destroyScope() { - if (activeScope) { - activeScope.$destroy(); - activeScope = undefined; - } - } - - function removeElement() { - if (activeElement !== comment) { - destroyScope(); - activeElement.replaceWith(comment); - activeElement = comment; - } - } - - function addElement() { - if (activeElement !== element) { - activeElement.replaceWith(element); - activeElement = element; - activeElement.empty(); - } - } - - function populateElement(template) { - destroyScope(); - activeScope = scope.$new(false); - element.html(template); - self.$compile(element.contents())(activeScope); - } - - function showTemplate(template) { - addElement(); - populateElement(template); - activeTemplateUrl = undefined; - } - - function badTemplateUrl(templateUrl) { - self.$log.warn("Couldn't load template at " + templateUrl); - removeElement(); - } - - function changeTemplateUrl(templateUrl) { - if (templateUrl) { - destroyScope(); - addElement(); - self.load(templateUrl).then(function (template) { - // Avoid race conditions - if (templateUrl === activeTemplateUrl) { - populateElement(template); - } - }, function () { - badTemplateUrl(templateUrl); - }); - } else { - removeElement(); - } - - activeTemplateUrl = templateUrl; - } - - function changeTemplate(templateExt) { - templateExt = templateExt || {}; - if (templateExt.templateUrl) { - changeTemplateUrl(self.getPath(templateExt)); - } else if (templateExt.template) { - showTemplate(templateExt.template); - } else { - removeElement(); - } - } - - changeTemplate(ext); - - return changeTemplate; - }; - - return TemplateLinker; - } -); - diff --git a/platform/representation/src/TemplatePrefetcher.js b/platform/representation/src/TemplatePrefetcher.js deleted file mode 100644 index 172732ce36..0000000000 --- a/platform/representation/src/TemplatePrefetcher.js +++ /dev/null @@ -1,48 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Loads all templates when the application is started. - * @param {platform/representation.TemplateLinker} templateLinker - * the `templateLinker` service, used to load and cache - * template extensions - * @param {...Array.<{templateUrl: string}>} extensions arrays - * of template or template-like extensions - */ - function TemplatePrefetcher(templateLinker) { - Array.prototype.slice.apply(arguments, [1]) - .reduce(function (a, b) { - return a.concat(b); - }, []) - .forEach(function (ext) { - if (ext.templateUrl) { - templateLinker.load(templateLinker.getPath(ext)); - } - }); - } - - return TemplatePrefetcher; - } -); diff --git a/platform/representation/src/gestures/DragGesture.js b/platform/representation/src/gestures/DragGesture.js deleted file mode 100644 index 4c1d7c984e..0000000000 --- a/platform/representation/src/gestures/DragGesture.js +++ /dev/null @@ -1,119 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 DragGesture. Created by vwoeltje on 11/17/14. - */ -define( - ['./GestureConstants'], - function (GestureConstants) { - - /** - * Add event handlers to a representation such that it may be - * dragged as the source for drag-drop composition. - * - * @memberof platform/representation - * @constructor - * @implements {Gesture} - * @param $log Angular's logging service - * @param element the jqLite-wrapped element which should become - * draggable - * @param {DomainObject} domainObject the domain object which - * is represented; this will be passed on drop. - */ - function DragGesture($log, dndService, element, domainObject) { - function startDrag(e) { - var event = (e || {}).originalEvent || e; - - $log.debug("Initiating drag"); - - try { - // Set the data associated with the drag-drop operation - event.dataTransfer.effectAllowed = 'move'; - - // Support drop as plain-text (JSON); not used internally - event.dataTransfer.setData( - 'text/plain', - JSON.stringify({ - id: domainObject.getId(), - model: domainObject.getModel() - }) - ); - - // For internal use, pass the object's identifier as - // part of the drag - event.dataTransfer.setData( - GestureConstants.MCT_DRAG_TYPE, - domainObject.getId() - ); - - // Finally, also pass the id object instance via the - // dndService, allowing inspection during drag as well - // as retrieval of the original domain object. - dndService.setData( - GestureConstants.MCT_EXTENDED_DRAG_TYPE, - domainObject - ); - dndService.setData( - GestureConstants.MCT_DRAG_TYPE, - domainObject.getId() - ); - - } catch (err) { - // Exceptions at this point indicate that the browser - // do not fully support drag-and-drop (e.g. if - // dataTransfer is undefined) - $log.warn([ - "Could not initiate drag due to ", - err.message - ].join("")); - } - - } - - function endDrag() { - // Clear the drag data after the drag is complete - dndService.removeData(GestureConstants.MCT_DRAG_TYPE); - dndService.removeData(GestureConstants.MCT_EXTENDED_DRAG_TYPE); - } - - // Mark the element as draggable, and handle the dragstart event - $log.debug("Attaching drag gesture"); - element.attr('draggable', 'true'); - element.on('dragstart', startDrag); - element.on('dragend', endDrag); - - this.element = element; - this.startDragCallback = startDrag; - this.endDragCallback = endDrag; - } - - DragGesture.prototype.destroy = function () { - // Detach listener - this.element.removeAttr('draggable'); - this.element.off('dragstart', this.startDragCallback); - this.element.off('dragend', this.endDragCallback); - }; - - return DragGesture; - } -); diff --git a/platform/representation/src/gestures/DropGesture.js b/platform/representation/src/gestures/DropGesture.js deleted file mode 100644 index 4e670c633c..0000000000 --- a/platform/representation/src/gestures/DropGesture.js +++ /dev/null @@ -1,129 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 DropGesture. Created by vwoeltje on 11/17/14. - */ -define( - ['./GestureConstants'], - function (GestureConstants) { - - /** - * A DropGesture adds and maintains event handlers upon an element - * such that it may act as a drop target for drag-drop composition. - * - * @memberof platform/representation - * @constructor - * @param $q Angular's $q, for promise handling - * @param element the jqLite-wrapped representation element - * @param {DomainObject} domainObject the domain object whose - * composition should be modified as a result of the drop. - */ - function DropGesture(dndService, $q, element, domainObject) { - var actionCapability = domainObject.getCapability('action'), - action; // Action for the drop, when it occurs - - function broadcastDrop(id, event) { - // Find the relevant scope... - var rect, - scope = element.scope && element.scope(); - - if (scope && scope.$broadcast) { - // Get the representation's bounds, to convert - // drop position - rect = element[0].getBoundingClientRect(); - - // ...and broadcast the event. This allows specific - // views to have post-drop behavior which depends on - // drop position. - scope.$broadcast( - GestureConstants.MCT_DROP_EVENT, - id, - { - x: event.pageX - rect.left, - y: event.pageY - rect.top - } - ); - } - } - - function dragOver(e) { - var event = (e || {}).originalEvent || e, - selectedObject = dndService.getData( - GestureConstants.MCT_EXTENDED_DRAG_TYPE - ); - - if (selectedObject) { - // TODO: Vary this based on modifier keys - action = actionCapability.getActions({ - key: 'compose', - selectedObject: selectedObject - })[0]; - if (action) { - event.dataTransfer.dropEffect = 'move'; - - // Indicate that we will accept the drag - event.preventDefault(); // Required in Chrome? - - return false; - } - } - } - - function drop(e) { - var event = (e || {}).originalEvent || e, - id = event.dataTransfer.getData(GestureConstants.MCT_DRAG_TYPE); - - // Handle the drop; add the dropped identifier to the - // destination domain object's composition, and persist - // the change. - if (id) { - e.preventDefault(); - $q.when(action && action.perform()).then(function () { - broadcastDrop(id, event); - }); - - } - } - - // We can only handle drops if we have access to actions... - if (actionCapability) { - // Listen for dragover, to indicate we'll accept a drag - element.on('dragover', dragOver); - - // Listen for the drop itself - element.on('drop', drop); - } - - this.element = element; - this.dragOverCallback = dragOver; - this.dropCallback = drop; - } - - DropGesture.prototype.destroy = function () { - this.element.off('dragover', this.dragOverCallback); - this.element.off('drop', this.dropCallback); - }; - - return DropGesture; - } -); diff --git a/platform/representation/src/gestures/GestureConstants.js b/platform/representation/src/gestures/GestureConstants.js deleted file mode 100644 index 522fe7a479..0000000000 --- a/platform/representation/src/gestures/GestureConstants.js +++ /dev/null @@ -1,53 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * Constants used by domain object gestures. - * @class platform/representation.GestureConstants - */ -define({ - /** - * The string identifier for the data type used for drag-and-drop - * composition of domain objects. (e.g. in event.dataTransfer.setData - * calls.) - * @memberof platform/representation.GestureConstants - */ - MCT_DRAG_TYPE: 'mct-domain-object-id', - /** - * The string identifier for the data type used for drag-and-drop - * composition of domain objects, by object instance (passed through - * the dndService) - * @memberof platform/representation.GestureConstants - */ - MCT_EXTENDED_DRAG_TYPE: 'mct-domain-object', - /** - * An estimate for the dimensions of a context menu, used for - * positioning. - * @memberof platform/representation.GestureConstants - */ - MCT_MENU_DIMENSIONS: [170, 200], - /** - * Identifier for drop events. - * @memberof platform/representation.GestureConstants - */ - MCT_DROP_EVENT: 'mctDrop' -}); diff --git a/platform/representation/src/gestures/GestureProvider.js b/platform/representation/src/gestures/GestureProvider.js deleted file mode 100644 index 7b96378267..0000000000 --- a/platform/representation/src/gestures/GestureProvider.js +++ /dev/null @@ -1,133 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 GestureProvider. Created by vwoeltje on 11/22/14. - */ -define( - [], - function () { - - /** - * Handles the attachment of gestures (responses to DOM events, - * generally) to DOM elements which represent domain objects. - * - * @interface GestureService - */ - /** - * Attach a set of gestures (indicated by key) to a - * DOM element which represents a specific domain object. - * @method GestureService#attachGestures - * @param element the jqLite-wrapped DOM element which the - * user will interact with - * @param {DomainObject} domainObject the domain object which - * is represented by that element - * @param {string[]} gestureKeys an array of keys identifying - * which gestures should apply; these will be matched - * against the keys defined in the gestures' extension - * definitions - * @return {Destroyable} an object with a `destroy` - * method which can (and should) be used when - * gestures should no longer be applied to an element. - */ - - /** - * The GestureProvider exposes defined gestures. Gestures are used - * do describe and handle general-purpose interactions with the DOM - * that should be interpreted as interactions with domain objects, - * such as right-clicking to expose context menus. - * - * Gestures are defined individually as extensions of the - * `gestures` category. The gesture provider merely serves as an - * intermediary between these and the `mct-representation` directive - * where they are used. - * - * @memberof platform/representation - * @implements {GestureService} - * @constructor - * @param {Gesture[]} gestures an array of all gestures which are - * available as extensions - */ - function GestureProvider(gestures) { - var gestureMap = {}; - - // Assemble all gestures into a map, for easy look up - gestures.forEach(function (gesture) { - gestureMap[gesture.key] = gestureMap[gesture.key] || gesture; - }); - - this.gestureMap = gestureMap; - } - - function releaseGesture(gesture) { - // Invoke the gesture's "destroy" method (if there is one) - // to release any held resources and detach event handlers. - if (gesture && gesture.destroy) { - gesture.destroy(); - } - } - - GestureProvider.prototype.attachGestures = function attachGestures(element, domainObject, gestureKeys) { - // Look up the desired gestures, filter for applicability, - // and instantiate them. Maintain a reference to allow them - // to be destroyed as a group later. - var gestureMap = this.gestureMap, - attachedGestures = gestureKeys.map(function (key) { - return gestureMap[key]; - }).filter(function (Gesture) { - return Gesture !== undefined && (Gesture.appliesTo - ? Gesture.appliesTo(domainObject) - : true); - }).map(function (Gesture) { - return new Gesture(element, domainObject); - }); - - return { - destroy: function () { - // Just call all the individual "destroy" methods - attachedGestures.forEach(releaseGesture); - } - }; - }; - - /** - * A destroyable object may have resources allocated which require - * explicit release. - * - * @interface Destroyable - */ - /** - * Release any resources associated with this object. - * - * @method Destroyable#destroy - */ - - /** - * A gesture describes manners in which certain representations of - * domain objects may respond to DOM events upon those representations. - * @interface Gesture - * @augments Destroyable - */ - - return GestureProvider; - } -); diff --git a/platform/representation/src/gestures/GestureRepresenter.js b/platform/representation/src/gestures/GestureRepresenter.js deleted file mode 100644 index 4fd021b43e..0000000000 --- a/platform/representation/src/gestures/GestureRepresenter.js +++ /dev/null @@ -1,68 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * The GestureRepresenter is responsible for installing predefined - * gestures upon mct-representation instances. - * Gestures themselves are pulled from the gesture service; this - * simply wraps that behavior in a Representer interface, such that - * it may be included among other such Representers used to prepare - * specific representations. - * @param {GestureService} gestureService the service which provides - * gestures - * @param {Scope} scope the Angular scope for this representation - * @param element the JQLite-wrapped mct-representation element - * @constructor - * @implements {Representer} - * @memberof platform/representation - */ - function GestureRepresenter(gestureService, scope, element) { - this.gestureService = gestureService; - this.element = element; - } - - GestureRepresenter.prototype.represent = function represent(representation, domainObject) { - // Clear out any existing gestures - this.destroy(); - - // Attach gestures - by way of the service. - this.gestureHandle = this.gestureService.attachGestures( - this.element, - domainObject, - (representation || {}).gestures || [] - ); - }; - - GestureRepresenter.prototype.destroy = function () { - // Release any resources associated with these gestures - if (this.gestureHandle) { - this.gestureHandle.destroy(); - } - }; - - return GestureRepresenter; - } -); diff --git a/platform/representation/src/services/DndService.js b/platform/representation/src/services/DndService.js deleted file mode 100644 index a1cc7e9fef..0000000000 --- a/platform/representation/src/services/DndService.js +++ /dev/null @@ -1,73 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - /** - * Drag-and-drop service. - * Supplements HTML5 drag-and-drop support by: - * * Storing arbitrary JavaScript objects (not just strings.) - * * Allowing inspection of dragged objects during `dragover` events, - * etc. (which cannot be done in Chrome for security reasons) - * @memberof platform/representation - * @constructor - * @param $log Angular's $log service - */ - function DndService($log) { - var data = {}; - - return { - /** - * Set drag data associated with a given type. - * @param {string} key the type's identiifer - * @param {*} value the data being dragged - * @memberof platform/representation.DndService# - */ - setData: function (key, value) { - $log.debug("Setting drag data for " + key); - data[key] = value; - }, - /** - * Get drag data associated with a given type. - * @returns {*} the data being dragged - * @memberof platform/representation.DndService# - */ - getData: function (key) { - return data[key]; - }, - /** - * Remove data associated with active drags. - * @param {string} key the type to remove - * @memberof platform/representation.DndService# - */ - removeData: function (key) { - $log.debug("Clearing drag data for " + key); - delete data[key]; - } - }; - } - - return DndService; - } -); diff --git a/platform/representation/test/MCTIncludeSpec.js b/platform/representation/test/MCTIncludeSpec.js deleted file mode 100644 index 99f95e905e..0000000000 --- a/platform/representation/test/MCTIncludeSpec.js +++ /dev/null @@ -1,108 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * MCTIncudeSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../src/MCTInclude"], - function (MCTInclude) { - - describe("The mct-include directive", function () { - var testTemplates, - testUrls, - mockLinker, - mockScope, - mockElement, - mockChangeTemplate, - mctInclude; - - function fireWatch(expr, value) { - mockScope.$watch.calls.all().forEach(function (call) { - if (call.args[0] === expr) { - call.args[1](value); - } - }); - } - - beforeEach(function () { - testTemplates = [ - { - key: "abc", - bundle: { - path: "a", - resources: "b" - }, - templateUrl: "c/template.html" - }, - { - key: "xyz", - bundle: { - path: "x", - resources: "y" - }, - templateUrl: "z/template.html" - } - ]; - testUrls = {}; - testTemplates.forEach(function (t, i) { - testUrls[t.key] = "some URL " + String(i); - }); - mockLinker = jasmine.createSpyObj( - 'templateLinker', - ['link', 'getPath'] - ); - mockScope = jasmine.createSpyObj('$scope', ['$watch', '$on']); - mockElement = jasmine.createSpyObj('element', ['empty']); - mockChangeTemplate = jasmine.createSpy('changeTemplate'); - mockLinker.link.and.returnValue(mockChangeTemplate); - mockLinker.getPath.and.callFake(function (template) { - return testUrls[template.key]; - }); - mctInclude = new MCTInclude(testTemplates, mockLinker); - mctInclude.link(mockScope, mockElement, {}); - }); - - it("is restricted to elements", function () { - expect(mctInclude.restrict).toEqual("E"); - }); - - it("exposes templates via the templateLinker", function () { - expect(mockLinker.link) - .toHaveBeenCalledWith(mockScope, mockElement, undefined); - }); - - it("reads a template location from a scope's key variable", function () { - mockScope.key = 'abc'; - fireWatch('key', mockScope.key); - expect(mockChangeTemplate) - .toHaveBeenCalledWith(testTemplates[0]); - - mockScope.key = 'xyz'; - fireWatch('key', mockScope.key); - expect(mockChangeTemplate) - .toHaveBeenCalledWith(testTemplates[1]); - }); - - }); - } -); diff --git a/platform/representation/test/MCTRepresentationSpec.js b/platform/representation/test/MCTRepresentationSpec.js deleted file mode 100644 index c02e07d8d5..0000000000 --- a/platform/representation/test/MCTRepresentationSpec.js +++ /dev/null @@ -1,343 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ - -/** - * MCTRepresentationSpec. Created by vwoeltje on 11/6/14. - */ -define( - ["../src/MCTRepresentation"], - function (MCTRepresentation) { - - var JQLITE_FUNCTIONS = ["on", "off", "attr", "removeAttr"], - LOG_FUNCTIONS = ["error", "warn", "info", "debug"], - DOMAIN_OBJECT_METHODS = ["getId", "getModel", "getCapability", "hasCapability", "useCapability"]; - - describe("The mct-representation directive", function () { - var testRepresentations, - testViews, - testUrls, - mockRepresenters, - mockMutationCapability, - mockQ, - mockLinker, - mockLog, - mockChangeTemplate, - mockScope, - mockElement, - mockDomainObject, - testModel, - mctRepresentation; - - function mockPromise(value) { - return (value && value.then) ? value : { - then: function (callback) { - return mockPromise(callback(value)); - } - }; - } - - function fireWatch(expr, value) { - mockScope.$watch.calls.all().forEach(function (call) { - if (call.args[0] === expr) { - call.args[1](value); - } - }); - } - - beforeEach(function () { - testUrls = {}; - - testRepresentations = [ - { - key: "abc", - bundle: { - path: "a", - resources: "b" - }, - templateUrl: "c/template.html" - }, - { - key: "def", - bundle: { - path: "d", - resources: "e" - }, - templateUrl: "f/template.html", - uses: ["testCapability", "otherTestCapability"] - } - ]; - - testViews = [ - { - key: "uvw", - bundle: { - path: "u", - resources: "v" - }, - templateUrl: "w/template.html", - gestures: ["testGesture", "otherTestGesture"] - }, - { - key: "xyz", - bundle: { - path: "x", - resources: "y" - }, - templateUrl: "z/template.html" - } - ]; - - testModel = { someKey: "some value" }; - - testUrls = {}; - testViews.concat(testRepresentations).forEach(function (t, i) { - testUrls[t.key] = "some URL " + String(i); - }); - - mockRepresenters = ["A", "B"].map(function (name) { - var constructor = jasmine.createSpy("Representer" + name), - representer = jasmine.createSpyObj( - "representer" + name, - ["represent", "destroy"] - ); - constructor.and.returnValue(representer); - - return constructor; - }); - - mockQ = { when: mockPromise }; - mockLinker = jasmine.createSpyObj( - 'templateLinker', - ['link', 'getPath'] - ); - mockChangeTemplate = jasmine.createSpy('changeTemplate'); - mockLog = jasmine.createSpyObj("$log", LOG_FUNCTIONS); - - mockMutationCapability = - jasmine.createSpyObj("mutation", ["listen"]); - - mockScope = jasmine.createSpyObj("scope", ["$watch", "$on"]); - mockElement = jasmine.createSpyObj("element", JQLITE_FUNCTIONS); - mockDomainObject = jasmine.createSpyObj("domainObject", DOMAIN_OBJECT_METHODS); - - mockDomainObject.getModel.and.returnValue(testModel); - mockLinker.link.and.returnValue(mockChangeTemplate); - mockLinker.getPath.and.callFake(function (ext) { - return testUrls[ext.key]; - }); - - mockDomainObject.getCapability.and.callFake(function (c) { - return c === 'mutation' && mockMutationCapability; - }); - - mctRepresentation = new MCTRepresentation( - testRepresentations, - testViews, - mockRepresenters, - mockQ, - mockLinker, - mockLog - ); - mctRepresentation.link(mockScope, mockElement); - }); - - it("is restricted to elements", function () { - expect(mctRepresentation.restrict).toEqual("E"); - }); - - it("exposes templates via the templateLinker", function () { - expect(mockLinker.link) - .toHaveBeenCalledWith(mockScope, mockElement); - }); - - it("watches scope when linked", function () { - expect(mockScope.$watch).toHaveBeenCalledWith( - "key", - jasmine.any(Function) - ); - expect(mockScope.$watch).toHaveBeenCalledWith( - "domainObject", - jasmine.any(Function) - ); - }); - - it("recognizes keys for representations", function () { - mockScope.key = "abc"; - mockScope.domainObject = mockDomainObject; - - // Trigger the watch - fireWatch('key', mockScope.key); - fireWatch('domainObject', mockDomainObject); - - expect(mockChangeTemplate) - .toHaveBeenCalledWith(testRepresentations[0]); - }); - - it("recognizes keys for views", function () { - mockScope.key = "xyz"; - mockScope.domainObject = mockDomainObject; - - // Trigger the watches - fireWatch('key', mockScope.key); - fireWatch('domainObject', mockDomainObject); - - expect(mockChangeTemplate) - .toHaveBeenCalledWith(testViews[1]); - }); - - it("does not load templates until there is an object", function () { - mockScope.key = "xyz"; - - // Trigger the watch - fireWatch('key', mockScope.key); - - expect(mockChangeTemplate) - .not.toHaveBeenCalledWith(jasmine.any(Object)); - - mockScope.domainObject = mockDomainObject; - fireWatch('domainObject', mockDomainObject); - - expect(mockChangeTemplate) - .toHaveBeenCalledWith(jasmine.any(Object)); - }); - - it("loads declared capabilities", function () { - mockScope.key = "def"; - mockScope.domainObject = mockDomainObject; - - // Trigger the watch - mockScope.$watch.calls.all()[0].args[1](); - - expect(mockDomainObject.useCapability) - .toHaveBeenCalledWith("testCapability"); - expect(mockDomainObject.useCapability) - .toHaveBeenCalledWith("otherTestCapability"); - }); - - it("logs when no representation is available for a key", function () { - mockScope.key = "someUnknownThing"; - - // Verify precondition - expect(mockLog.warn).not.toHaveBeenCalled(); - - // Trigger the watch - mockScope.$watch.calls.all()[0].args[1](); - - // Should have gotten a warning - that's an unknown key - expect(mockLog.warn).toHaveBeenCalled(); - }); - - it("clears out obsolete properties from scope", function () { - mockScope.key = "def"; - mockScope.domainObject = mockDomainObject; - mockDomainObject.useCapability.and.returnValue("some value"); - - // Trigger the watch - mockScope.$watch.calls.all()[0].args[1](); - expect(mockScope.testCapability).toBeDefined(); - - // Change the view - mockScope.key = "xyz"; - - // Trigger the watch again; should clear capability from scope - mockScope.$watch.calls.all()[0].args[1](); - expect(mockScope.testCapability).toBeUndefined(); - }); - - describe("when a domain object has been observed", function () { - var mockContext, - mockContext2, - mockLink, - mockParent; - - beforeEach(function () { - mockContext = jasmine.createSpyObj('context', ['getPath']); - mockContext2 = jasmine.createSpyObj('context', ['getPath']); - mockLink = jasmine.createSpyObj( - 'linkedObject', - DOMAIN_OBJECT_METHODS - ); - mockParent = jasmine.createSpyObj( - 'parentObject', - DOMAIN_OBJECT_METHODS - ); - - mockDomainObject.getCapability.and.callFake(function (c) { - return { - context: mockContext, - mutation: mockMutationCapability - }[c]; - }); - mockLink.getCapability.and.callFake(function (c) { - return { - context: mockContext2, - mutation: mockMutationCapability - }[c]; - }); - mockDomainObject.hasCapability.and.callFake(function (c) { - return c === 'context'; - }); - mockLink.hasCapability.and.callFake(function (c) { - return c === 'context'; - }); - mockLink.getModel.and.returnValue({}); - - mockContext.getPath.and.returnValue([mockDomainObject]); - mockContext2.getPath.and.returnValue([mockParent, mockLink]); - - mockLink.getId.and.returnValue('test-id'); - mockDomainObject.getId.and.returnValue('test-id'); - - mockParent.getId.and.returnValue('parent-id'); - - mockScope.key = "abc"; - mockScope.domainObject = mockDomainObject; - - mockScope.$watch.calls.all()[0].args[1](); - }); - - it("listens for mutation of that object", function () { - expect(mockMutationCapability.listen) - .toHaveBeenCalledWith(jasmine.any(Function)); - }); - - it("detects subsequent changes among linked instances", function () { - var callCount = mockChangeTemplate.calls.count(); - - mockScope.domainObject = mockLink; - mockScope.$watch.calls.all()[0].args[1](); - - expect(mockChangeTemplate.calls.count()) - .toEqual(callCount + 1); - }); - - it("does not trigger excess template changes for same instances", function () { - var callCount = mockChangeTemplate.calls.count(); - mockScope.$watch.calls.all()[0].args[1](); - expect(mockChangeTemplate.calls.count()).toEqual(callCount); - }); - - }); - - }); - } -); diff --git a/platform/representation/test/TemplateLinkerSpec.js b/platform/representation/test/TemplateLinkerSpec.js deleted file mode 100644 index 947440430f..0000000000 --- a/platform/representation/test/TemplateLinkerSpec.js +++ /dev/null @@ -1,239 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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/TemplateLinker"], - function (TemplateLinker) { - - var JQLITE_METHODS = ['replaceWith', 'empty', 'html', 'contents'], - SCOPE_METHODS = ['$on', '$new', '$destroy']; - - describe("TemplateLinker", function () { - var mockTemplateRequest, - mockSce, - mockCompile, - mockLog, - mockScope, - mockElement, - mockTemplates, - mockElements, - mockContents, - mockNewScope, - mockPromise, - linker; - - function testExtension(path, res, templatePath) { - return { - bundle: { - path: path, - resources: res - }, - templateUrl: templatePath - }; - } - - beforeEach(function () { - mockTemplateRequest = jasmine.createSpy('$templateRequest'); - mockSce = jasmine.createSpyObj('$sce', ['trustAsResourceUrl']); - mockCompile = jasmine.createSpy('$compile'); - mockLog = jasmine.createSpyObj('$log', ['error', 'warn']); - mockScope = jasmine.createSpyObj('$scope', SCOPE_METHODS); - mockNewScope = jasmine.createSpyObj('$scope', SCOPE_METHODS); - mockElement = jasmine.createSpyObj('element', JQLITE_METHODS); - mockPromise = jasmine.createSpyObj('promise', ['then']); - mockTemplates = {}; - mockElements = {}; - mockContents = {}; - - mockTemplateRequest.and.returnValue(mockPromise); - mockCompile.and.callFake(function (toCompile) { - var html = typeof toCompile === 'string' - ? toCompile : toCompile.testHtml; - mockTemplates[html] = jasmine.createSpy('template'); - mockElements[html] = - jasmine.createSpyObj('templateEl', JQLITE_METHODS); - mockTemplates[html].and.returnValue(mockElements[html]); - - return mockTemplates[html]; - }); - mockSce.trustAsResourceUrl.and.callFake(function (url) { - return { trusted: url }; - }); - mockScope.$new.and.returnValue(mockNewScope); - mockElement.html.and.callFake(function (html) { - mockContents[html] = - jasmine.createSpyObj('contentsEl', JQLITE_METHODS); - mockContents[html].testHtml = html; - }); - mockElement.contents.and.callFake(function () { - return mockContents[ - mockElement.html.calls.mostRecent().args[0] - ]; - }); - - linker = new TemplateLinker( - mockTemplateRequest, - mockSce, - mockCompile, - mockLog - ); - }); - - it("resolves extension paths", function () { - var testExt = testExtension('a', 'b', 'c/d.html'); - expect(linker.getPath(testExt)).toEqual('a/b/c/d.html'); - }); - - describe("when linking elements", function () { - var changeTemplate, - commentElement; - - function findCommentElement() { - mockCompile.calls.all().forEach(function (call) { - var html = call.args[0]; - if (html.indexOf(" -
      diff --git a/src/adapter/views/LegacyViewProvider.js b/src/adapter/views/LegacyViewProvider.js deleted file mode 100644 index 1a1714c76c..0000000000 --- a/src/adapter/views/LegacyViewProvider.js +++ /dev/null @@ -1,141 +0,0 @@ -define([ - -], function ( - -) { - const DEFAULT_VIEW_PRIORITY = 100; - - const PRIORITY_LEVELS = { - "fallback": Number.NEGATIVE_INFINITY, - "default": -100, - "none": 0, - "optional": DEFAULT_VIEW_PRIORITY, - "preferred": 1000, - "mandatory": Number.POSITIVE_INFINITY - }; - - function LegacyViewProvider(legacyView, openmct, convertToLegacyObject) { - return { - key: legacyView.key, - name: legacyView.name, - cssClass: legacyView.cssClass, - description: legacyView.description, - canEdit: function () { - return legacyView.editable === true; - }, - canView: function (domainObject) { - if (!domainObject || !domainObject.identifier) { - return false; - } - - if (legacyView.type) { - return domainObject.type === legacyView.type; - } - - let legacyObject = convertToLegacyObject(domainObject); - if (legacyView.needs) { - let meetsNeeds = legacyView.needs.every(k => legacyObject.hasCapability(k)); - if (!meetsNeeds) { - return false; - } - } - - return openmct.$injector.get('policyService').allow( - 'view', legacyView, legacyObject - ); - }, - view: function (domainObject) { - let $rootScope = openmct.$injector.get('$rootScope'); - let templateLinker = openmct.$injector.get('templateLinker'); - let scope = $rootScope.$new(true); - let legacyObject = convertToLegacyObject(domainObject); - let isDestroyed = false; - let unlistenToStatus; - let element; - scope.domainObject = legacyObject; - scope.model = legacyObject.getModel(); - let child; - let parent; - - return { - show: function (container) { - parent = container; - child = document.createElement('div'); - parent.appendChild(child); - let statusCapability = legacyObject.getCapability('status'); - unlistenToStatus = statusCapability.listen((newStatus) => { - child.classList.remove('s-status-timeconductor-unsynced'); - - if (newStatus.includes('timeconductor-unsynced')) { - child.classList.add('s-status-timeconductor-unsynced'); - } - }); - - // TODO: implement "gestures" support ? - let uses = legacyView.uses || []; - let promises = []; - let results = uses.map(function (capabilityKey, i) { - let result = legacyObject.useCapability(capabilityKey); - if (result.then) { - promises.push(result.then(function (r) { - results[i] = r; - })); - } - - return result; - }); - - function link() { - if (isDestroyed) { - return; - } - - uses.forEach(function (key, i) { - scope[key] = results[i]; - }); - element = openmct.$angular.element(child); - templateLinker.link( - scope, - element, - legacyView - ); - child.classList.add('u-contents'); - } - - if (promises.length) { - Promise.all(promises) - .then(function () { - link(); - scope.$digest(); - }); - } else { - link(); - } - }, - onClearData() { - scope.$broadcast('clearData'); - }, - destroy: function () { - element.off(); - element.remove(); - scope.$destroy(); - element = null; - scope = null; - unlistenToStatus(); - } - }; - }, - priority: function () { - let priority = legacyView.priority || DEFAULT_VIEW_PRIORITY; - if (typeof priority === 'string') { - priority = PRIORITY_LEVELS[priority]; - } - - return priority; - } - }; - } - - return LegacyViewProvider; - -}); diff --git a/src/adapter/views/TypeInspectorViewProvider.js b/src/adapter/views/TypeInspectorViewProvider.js deleted file mode 100644 index f7c3c6bd9c..0000000000 --- a/src/adapter/views/TypeInspectorViewProvider.js +++ /dev/null @@ -1,98 +0,0 @@ -define([ - -], function ( - -) { - function TypeInspectorViewProvider(typeDefinition, openmct, convertToLegacyObject) { - let representation = openmct.$injector.get('representations[]') - .filter((r) => r.key === typeDefinition.inspector)[0]; - - return { - key: representation.key, - name: representation.name, - cssClass: representation.cssClass, - description: representation.description, - canView: function (selection) { - if (selection.length !== 1 || selection[0].length === 0) { - return false; - } - - let selectionContext = selection[0][0].context; - - if (!selectionContext.item) { - return false; - } - - return selectionContext.item.type === typeDefinition.key; - }, - view: function (selection) { - let domainObject = selection[0][0].context.item; - let $rootScope = openmct.$injector.get('$rootScope'); - let templateLinker = openmct.$injector.get('templateLinker'); - let scope = $rootScope.$new(true); - let legacyObject = convertToLegacyObject(domainObject); - let isDestroyed = false; - let element; - scope.domainObject = legacyObject; - scope.model = legacyObject.getModel(); - - return { - show: function (container) { - let child = document.createElement('div'); - container.appendChild(child); - // TODO: implement "gestures" support ? - let uses = representation.uses || []; - let promises = []; - let results = uses.map(function (capabilityKey, i) { - let result = legacyObject.useCapability(capabilityKey); - if (result.then) { - promises.push(result.then(function (r) { - results[i] = r; - })); - } - - return result; - }); - - function link() { - if (isDestroyed) { - return; - } - - uses.forEach(function (key, i) { - scope[key] = results[i]; - }); - element = openmct.$angular.element(child); - templateLinker.link( - scope, - element, - representation - ); - container.style.height = '100%'; - } - - if (promises.length) { - Promise.all(promises) - .then(function () { - link(); - scope.$digest(); - }); - } else { - link(); - } - }, - destroy: function () { - element.off(); - element.remove(); - scope.$destroy(); - element = null; - scope = null; - } - }; - } - }; - } - - return TypeInspectorViewProvider; - -}); diff --git a/src/adapter/views/installLegacyViews.js b/src/adapter/views/installLegacyViews.js deleted file mode 100644 index 86419a09c9..0000000000 --- a/src/adapter/views/installLegacyViews.js +++ /dev/null @@ -1,32 +0,0 @@ -define([ - './LegacyViewProvider', - './TypeInspectorViewProvider', - 'objectUtils' -], function ( - LegacyViewProvider, - TypeInspectorViewProvider, - objectUtils -) { - function installLegacyViews(openmct, legacyViews, instantiate) { - - function convertToLegacyObject(domainObject) { - let keyString = objectUtils.makeKeyString(domainObject.identifier); - let oldModel = objectUtils.toOldFormat(domainObject); - - return instantiate(oldModel, keyString); - } - - legacyViews.forEach(function (legacyView) { - openmct.objectViews.addProvider(new LegacyViewProvider(legacyView, openmct, convertToLegacyObject)); - }); - - let inspectorTypes = openmct.$injector.get('types[]') - .filter((t) => Object.prototype.hasOwnProperty.call(t, 'inspector')); - - inspectorTypes.forEach(function (typeDefinition) { - openmct.inspectorViews.addProvider(new TypeInspectorViewProvider(typeDefinition, openmct, convertToLegacyObject)); - }); - } - - return installLegacyViews; -}); diff --git a/src/end.frag b/src/end.frag deleted file mode 100644 index 9746cce6b8..0000000000 --- a/src/end.frag +++ /dev/null @@ -1,2 +0,0 @@ - return require('openmct'); -})); diff --git a/src/plugins/legacySupport/BundleRegistry.js b/src/plugins/legacySupport/BundleRegistry.js deleted file mode 100644 index 8229502397..0000000000 --- a/src/plugins/legacySupport/BundleRegistry.js +++ /dev/null @@ -1,78 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 () { - - function BundleRegistry() { - this.bundles = {}; - this.knownBundles = {}; - } - - BundleRegistry.prototype.register = function (path, definition) { - if (Object.prototype.hasOwnProperty.call(this.knownBundles, path)) { - throw new Error('Cannot register bundle with duplicate path', path); - } - - this.knownBundles[path] = definition; - }; - - BundleRegistry.prototype.enable = function (path) { - if (!this.knownBundles[path]) { - throw new Error('Unknown bundle ' + path); - } - - this.bundles[path] = this.knownBundles[path]; - }; - - BundleRegistry.prototype.disable = function (path) { - if (!this.bundles[path]) { - throw new Error('Tried to disable inactive bundle ' + path); - } - - delete this.bundles[path]; - }; - - BundleRegistry.prototype.contains = function (path) { - return Boolean(this.bundles[path]); - }; - - BundleRegistry.prototype.get = function (path) { - return this.bundles[path]; - }; - - BundleRegistry.prototype.list = function () { - return Object.keys(this.bundles); - }; - - BundleRegistry.prototype.remove = BundleRegistry.prototype.disable; - - BundleRegistry.prototype.delete = function (path) { - if (!this.knownBundles[path]) { - throw new Error('Cannot remove Unknown Bundle ' + path); - } - - delete this.bundles[path]; - delete this.knownBundles[path]; - }; - - return BundleRegistry; -}); diff --git a/src/plugins/legacySupport/BundleRegistrySpec.js b/src/plugins/legacySupport/BundleRegistrySpec.js deleted file mode 100644 index 9ad0bab6f8..0000000000 --- a/src/plugins/legacySupport/BundleRegistrySpec.js +++ /dev/null @@ -1,88 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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(['./BundleRegistry'], function (BundleRegistry) { - - describe("BundleRegistry", function () { - let testPath; - let bundleRegistry; - - beforeEach(function () { - testPath = 'some/bundle'; - bundleRegistry = new BundleRegistry(); - }); - - it("initially lists no bundles", function () { - expect(bundleRegistry.list()).toEqual([]); - }); - - it("initially contains no bundles", function () { - expect(bundleRegistry.contains(testPath)) - .toBe(false); - }); - - it("initially provides no bundles", function () { - expect(bundleRegistry.get(testPath)) - .toBeUndefined(); - }); - - describe("when a bundle has been registered", function () { - let testBundleDef; - - beforeEach(function () { - testBundleDef = { someKey: "some value" }; - bundleRegistry.register(testPath, testBundleDef); - bundleRegistry.enable(testPath); - }); - - it("lists registered bundles", function () { - expect(bundleRegistry.list()).toEqual([testPath]); - }); - - it("contains registered bundles", function () { - expect(bundleRegistry.contains(testPath)) - .toBe(true); - }); - - it("provides registered bundles", function () { - expect(bundleRegistry.get(testPath)) - .toBe(testBundleDef); - }); - - describe("and then removed", function () { - beforeEach(function () { - bundleRegistry.remove(testPath); - }); - - it("appears empty again", function () { - expect(bundleRegistry.list()).toEqual([]); - }); - - it("does not contain the removed bundle", function () { - expect(bundleRegistry.contains(testPath)) - .toBe(false); - }); - }); - }); - }); - -}); diff --git a/src/plugins/legacySupport/installDefaultBundles.js b/src/plugins/legacySupport/installDefaultBundles.js deleted file mode 100644 index 36875adefb..0000000000 --- a/src/plugins/legacySupport/installDefaultBundles.js +++ /dev/null @@ -1,100 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - *****************************************************************************/ -const DEFAULTS = [ - 'src/adapter', - 'platform/framework', - 'platform/core', - 'platform/representation', - 'platform/commonUI/browse', - 'platform/commonUI/edit', - 'platform/commonUI/dialog', - 'platform/commonUI/general', - 'platform/commonUI/inspect', - 'platform/commonUI/mobile', - 'platform/commonUI/notification', - 'platform/containment', - 'platform/exporters', - 'platform/telemetry', - 'platform/identity', - 'platform/persistence/aggregator', - 'platform/policy', - 'platform/entanglement', - 'platform/status', - 'platform/commonUI/regions' -]; - -define([ - '../../adapter/bundle', - '../../../example/export/bundle', - '../../../example/forms/bundle', - '../../../example/identity/bundle', - '../../../example/mobile/bundle', - '../../../example/msl/bundle', - '../../../example/notifications/bundle', - '../../../example/persistence/bundle', - '../../../example/policy/bundle', - '../../../example/profiling/bundle', - '../../../example/scratchpad/bundle', - '../../../example/styleguide/bundle', - '../../../platform/commonUI/browse/bundle', - '../../../platform/commonUI/dialog/bundle', - '../../../platform/commonUI/edit/bundle', - '../../../platform/commonUI/general/bundle', - '../../../platform/commonUI/inspect/bundle', - '../../../platform/commonUI/mobile/bundle', - '../../../platform/commonUI/notification/bundle', - '../../../platform/commonUI/regions/bundle', - '../../../platform/containment/bundle', - '../../../platform/core/bundle', - '../../../platform/entanglement/bundle', - '../../../platform/exporters/bundle', - '../../../platform/features/static-markup/bundle', - '../../../platform/framework/bundle', - '../../../platform/framework/src/load/Bundle', - '../../../platform/identity/bundle', - '../../../platform/persistence/aggregator/bundle', - '../../../platform/persistence/elastic/bundle', - '../../../platform/persistence/queue/bundle', - '../../../platform/policy/bundle', - '../../../platform/representation/bundle', - '../../../platform/status/bundle', - '../../../platform/telemetry/bundle' -], function () { - const LEGACY_BUNDLES = Array.from(arguments); - - return function installDefaultBundles(bundleRegistry) { - registerLegacyBundles(LEGACY_BUNDLES); - enableDefaultBundles(); - - function registerLegacyBundles(bundles) { - bundles.forEach((bundle, i) => { - bundleRegistry.register(bundle.name, bundle.definition); - }); - } - - function enableDefaultBundles() { - DEFAULTS.forEach(function (bundlePath) { - bundleRegistry.enable(bundlePath); - }); - } - }; -}); diff --git a/src/plugins/legacySupport/legacyRegistry.js b/src/plugins/legacySupport/legacyRegistry.js deleted file mode 100644 index 013dc82cc6..0000000000 --- a/src/plugins/legacySupport/legacyRegistry.js +++ /dev/null @@ -1,25 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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(['./BundleRegistry'], function (BundleRegistry) { - return new BundleRegistry(); -}); diff --git a/src/plugins/legacySupport/legacyRegistrySpec.js b/src/plugins/legacySupport/legacyRegistrySpec.js deleted file mode 100644 index 25eb6c69e6..0000000000 --- a/src/plugins/legacySupport/legacyRegistrySpec.js +++ /dev/null @@ -1,33 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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([ - './legacyRegistry', - './BundleRegistry' -], function (legacyRegistry, BundleRegistry) { - - describe("legacyRegistry", function () { - it("is a BundleRegistry", function () { - expect(legacyRegistry instanceof BundleRegistry).toBe(true); - }); - }); -}); diff --git a/src/plugins/legacySupport/plugin.js b/src/plugins/legacySupport/plugin.js deleted file mode 100644 index cf20ca1792..0000000000 --- a/src/plugins/legacySupport/plugin.js +++ /dev/null @@ -1,126 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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 installDefaultBundles from './installDefaultBundles'; -import BundleRegistry from './BundleRegistry'; -import Main from '../../../platform/framework/src/Main'; -import objectUtils from '../../api/objects/object-utils'; -import DomainObjectImpl from '../../../platform/core/src/objects/DomainObjectImpl'; -import ContextualDomainObject from '../../../platform/core/src/capabilities/ContextualDomainObject'; - -export default function LegacySupportPlugin() { - return function install(openmct) { - openmct.legacyBundle = { - extensions: { - services: [ - { - key: "openmct", - implementation: function ($injector) { - openmct.$injector = $injector; - - return openmct; - }, - depends: ['$injector'] - } - ] - } - }; - - openmct.legacyExtension = function (category, extension) { - this.legacyBundle.extensions[category] = - this.legacyBundle.extensions[category] || []; - this.legacyBundle.extensions[category].push(extension); - }.bind(openmct); - - /** - * Return a legacy object, for compatibility purposes only. This method - * will be deprecated and removed in the future. - * @private - */ - openmct.legacyObject = function (domainObject) { - let capabilityService = this.$injector.get('capabilityService'); - - function instantiate(model, keyString) { - const capabilities = capabilityService.getCapabilities(model, keyString); - model.id = keyString; - - return new DomainObjectImpl(keyString, model, capabilities); - } - - if (Array.isArray(domainObject)) { - // an array of domain objects. [object, ...ancestors] representing - // a single object with a given chain of ancestors. We instantiate - // as a single contextual domain object. - return domainObject - .map((o) => { - let keyString = objectUtils.makeKeyString(o.identifier); - let oldModel = objectUtils.toOldFormat(o); - - return instantiate(oldModel, keyString); - }) - .reverse() - .reduce((parent, child) => { - return new ContextualDomainObject(child, parent); - }); - - } else { - let keyString = objectUtils.makeKeyString(domainObject.identifier); - let oldModel = objectUtils.toOldFormat(domainObject); - - return instantiate(oldModel, keyString); - } - }.bind(openmct); - - openmct.legacyRegistry = new BundleRegistry(); - installDefaultBundles(openmct.legacyRegistry); - - const patchedStart = openmct.start.bind(openmct); - openmct.start = async () => { - openmct.legacyRegistry.register('adapter', openmct.legacyBundle); - openmct.legacyRegistry.enable('adapter'); - - openmct.legacyExtension('runs', { - depends: ['navigationService'], - implementation: function (navigationService) { - navigationService - .addListener(openmct.emit.bind(openmct, 'navigation')); - } - }); - - // TODO: remove with legacy types. - openmct.types.listKeys().forEach(function (typeKey) { - const type = openmct.types.get(typeKey); - const legacyDefinition = type.toLegacyDefinition(); - legacyDefinition.key = typeKey; - openmct.legacyExtension('types', legacyDefinition); - }); - - const main = new Main(); - const angularInstance = await main.run(openmct); - - openmct.$angular = angularInstance; - openmct.$injector.get('objectService'); - - return patchedStart(); - }; - - }; -} diff --git a/src/plugins/plugins.js b/src/plugins/plugins.js index 4755895aa6..4bab569c0f 100644 --- a/src/plugins/plugins.js +++ b/src/plugins/plugins.js @@ -77,9 +77,7 @@ define([ './timer/plugin', './userIndicator/plugin', '../../example/exampleUser/plugin', - './localStorage/plugin', - './legacySupport/plugin.js', - '../adapter/indicators/legacy-indicators-plugin' + './localStorage/plugin' ], function ( _, UTCTimeSystem, @@ -137,21 +135,9 @@ define([ Timer, UserIndicator, ExampleUser, - LocalStorage, - LegacySupportPlugin, - LegacyIndicatorsPlugin + LocalStorage ) { - const bundleMap = { - Elasticsearch: 'platform/persistence/elastic' - }; - - const plugins = _.mapValues(bundleMap, function (bundleName, pluginName) { - return function pluginConstructor() { - return function (openmct) { - openmct.legacyRegistry.enable(bundleName); - }; - }; - }); + const plugins = {}; plugins.example = {}; plugins.example.ExampleUser = ExampleUser.default; @@ -182,28 +168,6 @@ define([ plugins.CouchDB = CouchDBPlugin.default; - plugins.Elasticsearch = function (url) { - return function (openmct) { - if (url) { - const bundleName = "config/elastic"; - openmct.legacyRegistry.register(bundleName, { - "extensions": { - "constants": [ - { - "key": "ELASTIC_ROOT", - "value": url, - "priority": "mandatory" - } - ] - } - }); - openmct.legacyRegistry.enable(bundleName); - } - - openmct.legacyRegistry.enable(bundleMap.Elasticsearch); - }; - }; - plugins.ImageryPlugin = ImageryPlugin; plugins.Plot = PlotPlugin.default; plugins.Chart = ChartPlugin.default; @@ -249,8 +213,6 @@ define([ plugins.DeviceClassifier = DeviceClassifier.default; plugins.UserIndicator = UserIndicator.default; plugins.LocalStorage = LocalStorage.default; - plugins.LegacySupport = LegacySupportPlugin.default; - plugins.LegacyIndicators = LegacyIndicatorsPlugin; return plugins; }); diff --git a/src/plugins/timer/pluginSpec.js b/src/plugins/timer/pluginSpec.js index 1db9af21c4..b8660345ab 100644 --- a/src/plugins/timer/pluginSpec.js +++ b/src/plugins/timer/pluginSpec.js @@ -67,6 +67,10 @@ describe("Timer plugin:", () => { }); } + afterEach(() => { + return resetApplicationState(openmct); + }); + describe("should still work if it's in the old format", () => { let timerViewProvider; let timerView; @@ -96,6 +100,7 @@ describe("Timer plugin:", () => { timerViewProvider = applicableViews.find(viewProvider => viewProvider.key === 'timer.view'); spyOn(openmct.objects, 'get').and.returnValue(Promise.resolve(timerViewObject)); + spyOn(openmct.objects, 'save').and.returnValue(Promise.resolve(true)); mutableTimerObject = await openmct.objects.getMutable(timerViewObject.identifier); @@ -173,8 +178,6 @@ describe("Timer plugin:", () => { if (appHolder) { appHolder.remove(); } - - return resetApplicationState(openmct); }); it("has name as Timer", () => { diff --git a/src/start.frag b/src/start.frag deleted file mode 100644 index d53e580f9e..0000000000 --- a/src/start.frag +++ /dev/null @@ -1,45 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2022, 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. - * - * Open MCT https://nasa.github.io/openmct/ - * Version: @@version - * Built: @@timestamp - * Revision: @@revision - * Branch: @@branch - * - * @preserve - *****************************************************************************/ - -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.openmct = factory(); - } -}(this, function() { - var BUILD_CONSTANTS = { - version: "@@version", - timestamp: "@@timestamp", - revision: "@@revision", - branch: "@@branch" - };