Compare commits
	
		
			13 Commits
		
	
	
		
			ui-various
			...
			style-guid
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					91263b0f6d | ||
| 
						 | 
					c458666173 | ||
| 
						 | 
					e21906d1fd | ||
| 
						 | 
					f2193495ec | ||
| 
						 | 
					dd05f29210 | ||
| 
						 | 
					b35be0c559 | ||
| 
						 | 
					9e6a2de585 | ||
| 
						 | 
					c7392db6f5 | ||
| 
						 | 
					6ee4740f5f | ||
| 
						 | 
					74401ed2de | ||
| 
						 | 
					c4fd3bc997 | ||
| 
						 | 
					55bac65cad | ||
| 
						 | 
					ed327f5211 | 
							
								
								
									
										108
									
								
								API.md
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								API.md
									
									
									
									
									
								
							@@ -567,7 +567,7 @@ openmct.time.timeSystem(utcTimeSystem, bounds);
 | 
			
		||||
Setting the active time system will trigger a [`'timeSystem'`](#time-events) 
 | 
			
		||||
event.  If you supplied bounds, a [`'bounds'`](#time-events) event will be triggered afterwards with your newly supplied bounds.
 | 
			
		||||
 | 
			
		||||
### Time Bounds
 | 
			
		||||
#### Time Bounds
 | 
			
		||||
 | 
			
		||||
The TimeAPI provides a getter/setter for querying and setting time bounds. Time 
 | 
			
		||||
bounds are simply an object with a `start` and an end `end` attribute.
 | 
			
		||||
@@ -591,7 +591,7 @@ openmct.time.bounds({start: now - ONE_HOUR, now);
 | 
			
		||||
To respond to bounds change events, listen for the [`'bounds'`](#time-events)
 | 
			
		||||
event.
 | 
			
		||||
 | 
			
		||||
## Clocks
 | 
			
		||||
### Clocks
 | 
			
		||||
 | 
			
		||||
The Time API can be set to follow a clock source which will cause the bounds
 | 
			
		||||
to be updated automatically whenever the clock source "ticks". A clock is simply
 | 
			
		||||
@@ -610,7 +610,7 @@ be defined to tick on some remote timing source.
 | 
			
		||||
The values provided by clocks are simple `number`s, which are interpreted in the
 | 
			
		||||
context of the active [Time System](#defining-and-registering-time-systems).
 | 
			
		||||
 | 
			
		||||
### Defining and registering clocks
 | 
			
		||||
#### Defining and registering clocks
 | 
			
		||||
 | 
			
		||||
A clock is an object that defines certain required metadata and functions:
 | 
			
		||||
 | 
			
		||||
@@ -724,7 +724,7 @@ __Note:__ Setting the clock offsets will trigger an immediate bounds change, as
 | 
			
		||||
new bounds will be calculated based on the `currentValue()` of the active clock. 
 | 
			
		||||
Clock offsets are only relevant when a clock source is active.
 | 
			
		||||
 | 
			
		||||
## Time Events
 | 
			
		||||
### Time Events
 | 
			
		||||
 | 
			
		||||
The Time API is a standard event emitter; you can register callbacks for events using the `on` method and remove callbacks for events with the `off` method.
 | 
			
		||||
 | 
			
		||||
@@ -766,7 +766,7 @@ The events emitted by the Time API are:
 | 
			
		||||
  * `clockOffsets`: The new [clock offsets](#clock-offsets).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## The Time Conductor
 | 
			
		||||
### The Time Conductor
 | 
			
		||||
 | 
			
		||||
The Time Conductor provides a user interface for managing time bounds in Open 
 | 
			
		||||
MCT. It allows a user to select from configured time systems and clocks, and to set bounds and clock offsets.
 | 
			
		||||
@@ -856,6 +856,90 @@ openmct.install(openmct.plugins.Conductor({
 | 
			
		||||
}));
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Indicators
 | 
			
		||||
 | 
			
		||||
Indicators are small widgets that reside at the bottom of the screen and are visible from 
 | 
			
		||||
every screen in Open MCT. They can be used to convey system state using an icon and text.
 | 
			
		||||
Indicators tend to be collapsed to an icon by default (though this behavior can be customized 
 | 
			
		||||
by defining a [custom indicator](#custom-indicators)), and hovering over them will reveal 
 | 
			
		||||
text providing more information.
 | 
			
		||||
 | 
			
		||||
### The URL Status Indicator
 | 
			
		||||
 | 
			
		||||
A common use case for indicators is to convey the state of some external system such as a 
 | 
			
		||||
persistence backend or HTTP server. So long as this system is accessible via http request, 
 | 
			
		||||
Open MCT provides a general purpose indicator to show whether the server is available and 
 | 
			
		||||
returing a 2xx status code. The URL Status Indicator is made available as a default plugin. See
 | 
			
		||||
[Included Plugins](#included-plugins) below for details on how to install and configure the 
 | 
			
		||||
URL Status Indicator.
 | 
			
		||||
 | 
			
		||||
### Creating a New Indicator
 | 
			
		||||
 | 
			
		||||
A new indicator can be created with a simple API call, eg.
 | 
			
		||||
 | 
			
		||||
``` javascript
 | 
			
		||||
var myIndicator = openmct.indicators.create();
 | 
			
		||||
myIndicator.text("Hello World!");
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This will create a new indicator and add it to the bottom of the screen in Open MCT.
 | 
			
		||||
By default, the indicator will appear as an information icon. Hovering over the icon will
 | 
			
		||||
reveal the text set via the call to `.text()`. The Indicator object returned by the API 
 | 
			
		||||
call exposes a number of functions for customizing the content and appearance of the indicator:
 | 
			
		||||
 | 
			
		||||
* `.text([text])`: Gets or sets the text shown when the user hovers over the indicator.
 | 
			
		||||
Accepts an __optional__ `string` argument that, if provided, will be used to set the text. 
 | 
			
		||||
Hovering over the indicator will expand it to its full size, revealing this text alongside 
 | 
			
		||||
the icon. Returns the currently set text as a `string`.
 | 
			
		||||
* `.description([description])`: Gets or sets the indicator's description. Accepts an 
 | 
			
		||||
__optional__ `string` argument that, if provided, will be used to set the text. The description 
 | 
			
		||||
allows for more detail to be provided in a tooltip when the user hovers over the indicator. 
 | 
			
		||||
Returns the currently set text as a `string`.
 | 
			
		||||
* `.iconClass([className])`: Gets or sets the CSS class used to define the icon. Accepts an __optional__ 
 | 
			
		||||
`string` parameter to be used to set the class applied to the indicator. Any of 
 | 
			
		||||
[the built-in glyphs](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home/glyphs?view=styleguide.glyphs) 
 | 
			
		||||
may be used here, or a custom CSS class can be provided. Returns the currently defined CSS 
 | 
			
		||||
class as a `string`.
 | 
			
		||||
* `.statusClass([className])`: Gets or sets the CSS class used to determine status. Accepts an __optional __
 | 
			
		||||
`string` parameter to be used to set a status class applied to the indicator. May be used to apply 
 | 
			
		||||
different colors to indicate status.
 | 
			
		||||
 | 
			
		||||
### Custom Indicators
 | 
			
		||||
 | 
			
		||||
A completely custom indicator can be added by registering a factory function that produces 
 | 
			
		||||
a DOM element for your custom indicator. eg.
 | 
			
		||||
 | 
			
		||||
``` javascript
 | 
			
		||||
openmct.indicators.create(function () {
 | 
			
		||||
    var domNode = document.createElement('div');
 | 
			
		||||
    domNode.innerText = new Date().toString();
 | 
			
		||||
    setInterval(function () {
 | 
			
		||||
        domNode.innerText = new Date().toString();
 | 
			
		||||
    }, 1000);
 | 
			
		||||
    return domNode;
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Priority
 | 
			
		||||
 | 
			
		||||
When creating a new indicator or defining a custom indicator, a `number` can optionally be 
 | 
			
		||||
provided that will determine the order that the indicator appears on the screen. An indicator 
 | 
			
		||||
with a higher `priority` number will be shown to the left of indicators with lower 
 | 
			
		||||
priority numbers. The lowest possible `priority` (and the default value if no `priority` is specified) 
 | 
			
		||||
is `Number.NEGATIVE_INFINTY`, and the highest possible priority is `Number.POSITIVE_INFINITY`.
 | 
			
		||||
 | 
			
		||||
eg.
 | 
			
		||||
``` javascript
 | 
			
		||||
var myIndicator = openmct.indicators.create(1);
 | 
			
		||||
myIndicator.text("I'm on the left!");
 | 
			
		||||
 | 
			
		||||
openmct.indicators.create(0, function () {
 | 
			
		||||
    var domNode = document.createElement('div');
 | 
			
		||||
    domNode.innerText = "I'm on the right!";
 | 
			
		||||
    return domNode;
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Included Plugins
 | 
			
		||||
 | 
			
		||||
Open MCT is packaged along with a few general-purpose plugins:
 | 
			
		||||
@@ -879,18 +963,18 @@ openmct.install(openmct.plugins.CouchDB('http://localhost:9200'))
 | 
			
		||||
* `openmct.plugins.Espresso` and `openmct.plugins.Snow` are two different
 | 
			
		||||
  themes (dark and light) available for Open MCT. Note that at least one
 | 
			
		||||
  of these themes must be installed for Open MCT to appear correctly.
 | 
			
		||||
* `openmct.plugins.URLIndicatorPlugin` adds an indicator which shows the
 | 
			
		||||
* `openmct.plugins.URLIndicator` adds an indicator which shows the
 | 
			
		||||
availability of a URL with the following options: 
 | 
			
		||||
  - `url` : URL to indicate the status of
 | 
			
		||||
  - `cssClass`: Icon to show in the status bar, defaults to `icon-database`, [list of all icons](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home?view=items)
 | 
			
		||||
  - `iconClass`: Icon to show in the status bar, defaults to `icon-database`, [list of all icons](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home?view=items)
 | 
			
		||||
  - `interval`: Interval between checking the connection, defaults to `10000`
 | 
			
		||||
  - `label` Name showing up as text in the status bar, defaults to url
 | 
			
		||||
```javascript
 | 
			
		||||
openmct.install(openmct.plugins.URLIndicatorPlugin({
 | 
			
		||||
  url: 'http://google.com',
 | 
			
		||||
  cssClass: 'check',
 | 
			
		||||
  interval: 10000,
 | 
			
		||||
  label: 'Google'
 | 
			
		||||
openmct.install(openmct.plugins.URLIndicator({
 | 
			
		||||
  url: 'http://localhost:8080',
 | 
			
		||||
    iconClass: 'check',
 | 
			
		||||
    interval: 10000,
 | 
			
		||||
    label: 'Localhost'
 | 
			
		||||
 })
 | 
			
		||||
);
 | 
			
		||||
```
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,8 @@ define([
 | 
			
		||||
                    "provides": "identityService",
 | 
			
		||||
                    "type": "provider",
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "dialogService"
 | 
			
		||||
                        "dialogService",
 | 
			
		||||
                        "$q"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
 
 | 
			
		||||
@@ -55,21 +55,37 @@ define(
 | 
			
		||||
         * @implements {IdentityService}
 | 
			
		||||
         * @memberof platform/identity
 | 
			
		||||
         */
 | 
			
		||||
        function ExampleIdentityProvider(dialogService) {
 | 
			
		||||
            // Handle rejected dialog messages by treating the
 | 
			
		||||
            // current user as undefined.
 | 
			
		||||
            function echo(v) { return v; }
 | 
			
		||||
            function giveUndefined() { return undefined; }
 | 
			
		||||
        function ExampleIdentityProvider(dialogService, $q) {
 | 
			
		||||
            this.dialogService = dialogService;
 | 
			
		||||
            this.$q = $q;
 | 
			
		||||
 | 
			
		||||
            this.userPromise =
 | 
			
		||||
                dialogService.getUserInput(DIALOG_STRUCTURE, DEFAULT_IDENTITY)
 | 
			
		||||
                    .then(echo, giveUndefined);
 | 
			
		||||
            this.returnUser = this.returnUser.bind(this);
 | 
			
		||||
            this.returnUndefined = this.returnUndefined.bind(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ExampleIdentityProvider.prototype.getUser = function () {
 | 
			
		||||
            return this.userPromise;
 | 
			
		||||
            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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
<span class="status block" ng-controller="DialogLaunchController">
 | 
			
		||||
<span class="l-indicator s-indicator icon-box-with-arrow" ng-controller="DialogLaunchController">
 | 
			
		||||
    <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
 | 
			
		||||
    <span class="status-indicator icon-box-with-arrow"></span><span class="label">
 | 
			
		||||
    <span class="label">
 | 
			
		||||
        <a ng-click="launchProgress(true)">Known</a> |
 | 
			
		||||
        <a ng-click="launchProgress(false)">Unknown</a> |
 | 
			
		||||
        <a ng-click="launchError()">Error</a> |
 | 
			
		||||
        <a ng-click="launchInfo()">Info</a>
 | 
			
		||||
    </span><span class="count"></span>
 | 
			
		||||
    </span>
 | 
			
		||||
</span>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
<span class="status block" ng-controller="NotificationLaunchController">
 | 
			
		||||
<span class="l-indicator s-indicator icon-bell" ng-controller="NotificationLaunchController">
 | 
			
		||||
    <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
 | 
			
		||||
    <span class="status-indicator icon-bell"></span><span class="label">
 | 
			
		||||
    <span class="label">
 | 
			
		||||
        <a ng-click="newInfo()">Success</a> |
 | 
			
		||||
        <a ng-click="newError()">Error</a> |
 | 
			
		||||
        <a ng-click="newAlert()">Alert</a> |
 | 
			
		||||
        <a ng-click="newProgress()">Progress</a>
 | 
			
		||||
    </span><span class="count"></span>
 | 
			
		||||
    </span>
 | 
			
		||||
</span>
 | 
			
		||||
 
 | 
			
		||||
@@ -129,6 +129,44 @@
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="l-section">
 | 
			
		||||
        <h2>Status Bar Indicators</h2>
 | 
			
		||||
        <div class="cols cols1-1">
 | 
			
		||||
            <div class="col">
 | 
			
		||||
                <p>Indicators content goes here.</p>
 | 
			
		||||
            </div>
 | 
			
		||||
<mct-example><div class="status-holder s-status-bar">
 | 
			
		||||
<span class="status-block-holder">
 | 
			
		||||
    <span class="l-indicator s-indicator">
 | 
			
		||||
        <span class="status-indicator icon-bell"></span>
 | 
			
		||||
        <span class="label">Collapsible Indicator</span>
 | 
			
		||||
    </span>
 | 
			
		||||
</span>
 | 
			
		||||
<span class="status-block-holder no-collapse caution">
 | 
			
		||||
    <span class="l-indicator s-indicator">
 | 
			
		||||
        <span class="status-indicator icon-bell"></span>
 | 
			
		||||
        <span class="label">No collapse</span>
 | 
			
		||||
    </span>
 | 
			
		||||
</span>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="status-holder s-status-bar">
 | 
			
		||||
<span class="status-block-holder">
 | 
			
		||||
    <span class="l-indicator s-indicator">
 | 
			
		||||
        <span class="status-indicator icon-bell"></span>
 | 
			
		||||
        <span class="label">Collapsible Indicator</span>
 | 
			
		||||
    </span>
 | 
			
		||||
</span>
 | 
			
		||||
    <span class="status-block-holder">
 | 
			
		||||
    <span class="status block s-status-info icon-info">
 | 
			
		||||
        <span class="label">No collapse</span>
 | 
			
		||||
    </span>
 | 
			
		||||
</span>
 | 
			
		||||
</div>
 | 
			
		||||
</mct-example>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <div class="l-section">
 | 
			
		||||
        <h2>Synchronization</h2>
 | 
			
		||||
        <div class="cols cols1-1">
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ define(
 | 
			
		||||
                    return "icon-object-unknown";
 | 
			
		||||
                },
 | 
			
		||||
                getText: function () {
 | 
			
		||||
                    return latest;
 | 
			
		||||
                    return "" + latest;
 | 
			
		||||
                },
 | 
			
		||||
                getDescription: function () {
 | 
			
		||||
                    return "";
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,6 @@ define([
 | 
			
		||||
    "./src/controllers/ContextMenuController",
 | 
			
		||||
    "./src/controllers/ClickAwayController",
 | 
			
		||||
    "./src/controllers/ViewSwitcherController",
 | 
			
		||||
    "./src/controllers/BottomBarController",
 | 
			
		||||
    "./src/controllers/GetterSetterController",
 | 
			
		||||
    "./src/controllers/SelectorController",
 | 
			
		||||
    "./src/controllers/ObjectInspectorController",
 | 
			
		||||
@@ -49,11 +48,12 @@ define([
 | 
			
		||||
    "./src/directives/MCTSplitPane",
 | 
			
		||||
    "./src/directives/MCTSplitter",
 | 
			
		||||
    "./src/directives/MCTTree",
 | 
			
		||||
    "./src/directives/MCTIndicators",
 | 
			
		||||
    "./src/filters/ReverseFilter",
 | 
			
		||||
    "text!./res/templates/bottombar.html",
 | 
			
		||||
    "text!./res/templates/controls/action-button.html",
 | 
			
		||||
    "text!./res/templates/controls/input-filter.html",
 | 
			
		||||
    "text!./res/templates/indicator.html",
 | 
			
		||||
    "text!./res/templates/angular-indicator.html",
 | 
			
		||||
    "text!./res/templates/message-banner.html",
 | 
			
		||||
    "text!./res/templates/progress-bar.html",
 | 
			
		||||
    "text!./res/templates/controls/time-controller.html",
 | 
			
		||||
@@ -84,7 +84,6 @@ define([
 | 
			
		||||
    ContextMenuController,
 | 
			
		||||
    ClickAwayController,
 | 
			
		||||
    ViewSwitcherController,
 | 
			
		||||
    BottomBarController,
 | 
			
		||||
    GetterSetterController,
 | 
			
		||||
    SelectorController,
 | 
			
		||||
    ObjectInspectorController,
 | 
			
		||||
@@ -99,6 +98,7 @@ define([
 | 
			
		||||
    MCTSplitPane,
 | 
			
		||||
    MCTSplitter,
 | 
			
		||||
    MCTTree,
 | 
			
		||||
    MCTIndicators,
 | 
			
		||||
    ReverseFilter,
 | 
			
		||||
    bottombarTemplate,
 | 
			
		||||
    actionButtonTemplate,
 | 
			
		||||
@@ -275,13 +275,6 @@ define([
 | 
			
		||||
                        "$timeout"
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "BottomBarController",
 | 
			
		||||
                    "implementation": BottomBarController,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "indicators[]"
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "GetterSetterController",
 | 
			
		||||
                    "implementation": GetterSetterController,
 | 
			
		||||
@@ -395,6 +388,11 @@ define([
 | 
			
		||||
                    "key": "mctTree",
 | 
			
		||||
                    "implementation": MCTTree,
 | 
			
		||||
                    "depends": ['gestureService']
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "mctIndicators",
 | 
			
		||||
                    "implementation": MCTIndicators,
 | 
			
		||||
                    "depends": ['openmct']
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "constants": [
 | 
			
		||||
 
 | 
			
		||||
@@ -42,6 +42,7 @@
 | 
			
		||||
@import "controls/lists";
 | 
			
		||||
@import "controls/menus";
 | 
			
		||||
@import "controls/messages";
 | 
			
		||||
@import "controls/indicators";
 | 
			
		||||
@import "mobile/controls/menus";
 | 
			
		||||
 | 
			
		||||
/********************************* FORMS */
 | 
			
		||||
 
 | 
			
		||||
@@ -20,13 +20,15 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*************************************************** MIXINS */
 | 
			
		||||
@mixin formulateStatusColors($c) {
 | 
			
		||||
@mixin elementStatusColors($c) {
 | 
			
		||||
    // Sets bg and icon colors for elements
 | 
			
		||||
    background: rgba($c, 0.4) !important;
 | 
			
		||||
    &:before { color: $c !important; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@mixin indicatorStatusColors($c) {
 | 
			
		||||
    &:before, .count { color: $c; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*************************************************** GENERAL */
 | 
			
		||||
.s-limit-yellow,
 | 
			
		||||
@@ -54,14 +56,13 @@
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*************************************************** LIMITS */
 | 
			
		||||
.s-limit-yellow, .s-limit-yellow-icon {
 | 
			
		||||
    @include formulateStatusColors($colorWarningLo);
 | 
			
		||||
    @include elementStatusColors($colorWarningLo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.s-limit-red, .s-limit-red-icon {
 | 
			
		||||
    @include formulateStatusColors($colorWarningHi);
 | 
			
		||||
    @include elementStatusColors($colorWarningHi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.s-limit-upr:before { content: $glyph-icon-arrow-double-up; }
 | 
			
		||||
@@ -70,11 +71,11 @@
 | 
			
		||||
.s-limit-red-icon:before { content: $glyph-icon-alert-triangle; }
 | 
			
		||||
 | 
			
		||||
/*************************************************** STATUS */
 | 
			
		||||
.s-status-warning-hi, .s-status-warning-hi-icon {  @include formulateStatusColors($colorWarningHi); }
 | 
			
		||||
.s-status-warning-lo, .s-status-warning-lo-icon {  @include formulateStatusColors($colorWarningLo); }
 | 
			
		||||
.s-status-diagnostic, .s-status-diagnostic-icon {  @include formulateStatusColors($colorDiagnostic); }
 | 
			
		||||
.s-status-info, .s-status-info-icon {  @include formulateStatusColors($colorInfo); }
 | 
			
		||||
.s-status-ok, .s-status-ok-icon {  @include formulateStatusColors($colorOk); }
 | 
			
		||||
.s-status-warning-hi, .s-status-warning-hi-icon {  @include elementStatusColors($colorWarningHi); }
 | 
			
		||||
.s-status-warning-lo, .s-status-warning-lo-icon {  @include elementStatusColors($colorWarningLo); }
 | 
			
		||||
.s-status-diagnostic, .s-status-diagnostic-icon {  @include elementStatusColors($colorDiagnostic); }
 | 
			
		||||
.s-status-info, .s-status-info-icon {  @include elementStatusColors($colorInfo); }
 | 
			
		||||
.s-status-ok, .s-status-ok-icon {  @include elementStatusColors($colorOk); }
 | 
			
		||||
 | 
			
		||||
.s-status-warning-hi-icon:before { content: $glyph-icon-alert-triangle; }
 | 
			
		||||
.s-status-warning-lo-icon:before { content: $glyph-icon-alert-rect; }
 | 
			
		||||
@@ -82,4 +83,25 @@
 | 
			
		||||
.s-status-info-icon:before { content: $glyph-icon-info; }
 | 
			
		||||
.s-status-ok-icon:before { content: $glyph-icon-check; }
 | 
			
		||||
 | 
			
		||||
/*************************************************** INDICATORS */
 | 
			
		||||
.s-indicator-status-info {
 | 
			
		||||
    @include indicatorStatusColors($colorInfo);
 | 
			
		||||
}
 | 
			
		||||
.s-indicator-status-ok {
 | 
			
		||||
    @include indicatorStatusColors($colorOk);
 | 
			
		||||
}
 | 
			
		||||
.s-indicator-status-caution, .s-indicator-status-warning, .s-indicator-status-alert {
 | 
			
		||||
    @include indicatorStatusColors($colorStatusAlert);
 | 
			
		||||
}
 | 
			
		||||
.s-indicator-status-error, .s-indicator-status-err {
 | 
			
		||||
    @include indicatorStatusColors($colorStatusError);
 | 
			
		||||
}
 | 
			
		||||
.s-indicator-status-available {
 | 
			
		||||
    @include indicatorStatusColors($colorStatusAvailable);
 | 
			
		||||
}
 | 
			
		||||
.s-indicator-status-subdued {
 | 
			
		||||
    opacity: 0.7;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										99
									
								
								platform/commonUI/general/res/sass/controls/_indicators.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								platform/commonUI/general/res/sass/controls/_indicators.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/* Indicators are generally only displayed in the ue-bottom-bar element of the main interface */
 | 
			
		||||
 | 
			
		||||
.l-indicator {
 | 
			
		||||
    $transDelayHover: 1.5s;
 | 
			
		||||
    $transDelayWhileExpanded: 2.5s;
 | 
			
		||||
    $transSpeed: .25s;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    margin-right: $interiorMarginSm;
 | 
			
		||||
 | 
			
		||||
    &:before {
 | 
			
		||||
        // Icon
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        opacity: 0.85;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .label,
 | 
			
		||||
    .count {
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        vertical-align: top;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.float-right {
 | 
			
		||||
        float: right;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.no-icon {
 | 
			
		||||
        &:before {
 | 
			
		||||
            display: none;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:not(.no-collapse) {
 | 
			
		||||
        .label {
 | 
			
		||||
            // Max-width silliness is necessary for width transition
 | 
			
		||||
            @include trans-prop-nice((max-width, margin-right), $transSpeed, $transDelayWhileExpanded);
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
            margin-right: 0;
 | 
			
		||||
            max-width: 0px;
 | 
			
		||||
            white-space: nowrap;
 | 
			
		||||
        }
 | 
			
		||||
        &:hover {
 | 
			
		||||
            &:before {
 | 
			
		||||
                opacity: 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .label {
 | 
			
		||||
                @include trans-prop-nice((max-width, margin-right), 0s);
 | 
			
		||||
                margin-right: $interiorMargin;
 | 
			
		||||
                max-width: 600px;
 | 
			
		||||
                width: auto;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .count {
 | 
			
		||||
                @include trans-prop-nice(max-width, 0s);
 | 
			
		||||
                opacity: 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .count {
 | 
			
		||||
        @include trans-prop-nice(opacity, $transSpeed, $transDelayWhileExpanded);
 | 
			
		||||
        font-weight: bold;
 | 
			
		||||
        opacity: 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .s-button {
 | 
			
		||||
        background: $colorStatusBtnBg;
 | 
			
		||||
        padding: 0 $interiorMargin;
 | 
			
		||||
        height: auto;
 | 
			
		||||
        line-height: inherit;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.s-indicator {
 | 
			
		||||
    color: $colorStatusDefault;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -19,7 +19,7 @@
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/******************************************************************* STATUS BLOCK ELEMS */
 | 
			
		||||
 | 
			
		||||
@mixin statusBannerColors($bg, $fg: $colorStatusFg) {
 | 
			
		||||
	$bgPb: 30%;
 | 
			
		||||
	$bgPbD: 10%;
 | 
			
		||||
@@ -36,110 +36,6 @@
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Status coloring
 | 
			
		||||
.ok, .info {
 | 
			
		||||
    .status-indicator {
 | 
			
		||||
        color: $colorInfo;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.alert, .caution, .warning {
 | 
			
		||||
    .status-indicator, .count {
 | 
			
		||||
        color: $colorStatusAlert;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.error, .err {
 | 
			
		||||
    .status-indicator, .count {
 | 
			
		||||
        color: $colorStatusError;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.available {
 | 
			
		||||
    .status-indicator, .count {
 | 
			
		||||
        color: $colorStatusAvailable;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.subdued {
 | 
			
		||||
    .status-indicator {
 | 
			
		||||
        color: pullForward($colorStatusBarBg, 40%);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.status-block-holder {
 | 
			
		||||
    // Applied to mct-include element
 | 
			
		||||
    // Contains status.block elements
 | 
			
		||||
    $transDelay: 1.5s;
 | 
			
		||||
    $transSpeed: .25s;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    &.clickable { cursor: pointer; }
 | 
			
		||||
    &:not(.clickable) { cursor: default; }
 | 
			
		||||
    &.no-icon .status.block {
 | 
			
		||||
        .status-indicator {
 | 
			
		||||
            display: none;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    &.float-right {
 | 
			
		||||
        float: right;
 | 
			
		||||
    }
 | 
			
		||||
    &:not(.no-collapse) .status.block {
 | 
			
		||||
        .label {
 | 
			
		||||
            // Max-width silliness is necessary for width transition
 | 
			
		||||
            @include trans-prop-nice(max-width, $transSpeed, $transDelay);
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
            max-width: 0px;
 | 
			
		||||
        }
 | 
			
		||||
        &:hover {
 | 
			
		||||
            .label {
 | 
			
		||||
                @include trans-prop-nice(max-width, $transSpeed, 0s);
 | 
			
		||||
                max-width: 600px;
 | 
			
		||||
                width: auto;
 | 
			
		||||
            }
 | 
			
		||||
            .count {
 | 
			
		||||
                @include trans-prop-nice(max-width, $transSpeed, 0s);
 | 
			
		||||
                opacity: 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.status.block {
 | 
			
		||||
    $transDelay: 1.5s;
 | 
			
		||||
    $transSpeed: .25s;
 | 
			
		||||
	color: $colorStatusDefault;
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
	margin-right: $interiorMargin;
 | 
			
		||||
	.status-indicator,
 | 
			
		||||
	.label,
 | 
			
		||||
	.count {
 | 
			
		||||
		display: inline-block;
 | 
			
		||||
		vertical-align: top;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.status-indicator {
 | 
			
		||||
        background: none !important;
 | 
			
		||||
		margin-right: $interiorMarginSm;
 | 
			
		||||
        &[class*='s-status']:before {
 | 
			
		||||
            font-size: 1em;
 | 
			
		||||
        }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.count {
 | 
			
		||||
		@include trans-prop-nice(opacity, $transSpeed, $transDelay);
 | 
			
		||||
		font-weight: bold;
 | 
			
		||||
		opacity: 1;
 | 
			
		||||
	}
 | 
			
		||||
    .s-button {
 | 
			
		||||
        background: $colorStatusBtnBg;
 | 
			
		||||
        padding: 0 $interiorMargin;
 | 
			
		||||
        height: auto;
 | 
			
		||||
        line-height: inherit;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************************* MESSAGE BANNERS */
 | 
			
		||||
.message {
 | 
			
		||||
	&.block {
 | 
			
		||||
 
 | 
			
		||||
@@ -81,16 +81,14 @@
 | 
			
		||||
        @include absPosDefault(0);// New status bar design
 | 
			
		||||
        top: auto;
 | 
			
		||||
        height: $ueFooterH;
 | 
			
		||||
        line-height: $ueFooterH - ($interiorMargin * 2);
 | 
			
		||||
        background: $colorStatusBarBg;
 | 
			
		||||
        color: lighten($colorBodyBg, 30%);
 | 
			
		||||
        font-size: .7rem;
 | 
			
		||||
        .status-holder {
 | 
			
		||||
 | 
			
		||||
        mct-indicators { display: block; }
 | 
			
		||||
        
 | 
			
		||||
        .indicator-holder {
 | 
			
		||||
            box-sizing: border-box;
 | 
			
		||||
            @include absPosDefault($interiorMargin);
 | 
			
		||||
            @include ellipsize();
 | 
			
		||||
            right: 120px;
 | 
			
		||||
            text-transform: uppercase;
 | 
			
		||||
            z-index: 1;
 | 
			
		||||
        }
 | 
			
		||||
        .app-logo {
 | 
			
		||||
@@ -105,6 +103,14 @@
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.s-status-bar {
 | 
			
		||||
    background: $colorStatusBarBg;
 | 
			
		||||
    color: lighten($colorBodyBg, 30%);
 | 
			
		||||
    font-size: .7rem;
 | 
			
		||||
    line-height: $ueFooterH - ($interiorMargin * 2);
 | 
			
		||||
    text-transform: uppercase;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.edit-mode {
 | 
			
		||||
    // Old edit mode
 | 
			
		||||
    .split-layout {
 | 
			
		||||
 
 | 
			
		||||
@@ -20,14 +20,12 @@
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
 | 
			
		||||
<div class='status block'
 | 
			
		||||
<div class='l-indicator s-indicator s-indicator-status-{{ngModel.getGlyphClass()}}'
 | 
			
		||||
	 title="{{ngModel.getDescription()}}"
 | 
			
		||||
	 ng-click='ngModel.configure()'
 | 
			
		||||
	 ng-show="ngModel.getText().length > 0">
 | 
			
		||||
	<span class="status-indicator {{ngModel.getCssClass()}}"></span><span class="label"
 | 
			
		||||
		  ng-class='ngModel.getTextClass()'>
 | 
			
		||||
	 ng-show="ngModel.getText().length > 0"
 | 
			
		||||
     ng-class="ngModel.getCssClass()">
 | 
			
		||||
	<span class="label" ng-class='ngModel.getTextClass()'>
 | 
			
		||||
		{{ngModel.getText()}}
 | 
			
		||||
        <a class="s-button icon-gear" ng-if="ngModel.configure"></a>
 | 
			
		||||
	</span><span class="count">
 | 
			
		||||
	</span>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -19,14 +19,9 @@
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<div class='abs bottom-bar ue-bottom-bar mobile-disable-select' ng-controller="BottomBarController as bar">
 | 
			
		||||
    <div id='status' class='status-holder'>
 | 
			
		||||
        <mct-include ng-repeat="indicator in bar.getIndicators()"
 | 
			
		||||
                     ng-model="indicator.ngModel"
 | 
			
		||||
                     key="indicator.template"
 | 
			
		||||
                     class="status-block-holder"
 | 
			
		||||
                     ng-class='indicator.ngModel.getGlyphClass()'>
 | 
			
		||||
        </mct-include>
 | 
			
		||||
<div class='abs bottom-bar ue-bottom-bar s-status-bar mobile-disable-select'>
 | 
			
		||||
    <div id='status' class='indicator-holder'>
 | 
			
		||||
        <mct-indicators></mct-indicators>
 | 
			
		||||
    </div>
 | 
			
		||||
    <mct-include key="'message-banner'"></mct-include>
 | 
			
		||||
    <mct-include key="'about-logo'"></mct-include>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
@@ -23,37 +23,20 @@
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Controller for the bottombar template. Exposes
 | 
			
		||||
         * available indicators (of extension category "indicators")
 | 
			
		||||
         * @memberof platform/commonUI/general
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function BottomBarController(indicators) {
 | 
			
		||||
            // Utility function used to make indicators presentable
 | 
			
		||||
            // for display.
 | 
			
		||||
            function present(Indicator) {
 | 
			
		||||
                return {
 | 
			
		||||
                    template: Indicator.template || "indicator",
 | 
			
		||||
                    ngModel: typeof Indicator === 'function' ?
 | 
			
		||||
                            new Indicator() : Indicator
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.indicators = indicators.map(present);
 | 
			
		||||
        function MCTIndicators(openmct) {
 | 
			
		||||
            return {
 | 
			
		||||
                restrict: "E",
 | 
			
		||||
                link: function link(scope, element) {
 | 
			
		||||
                    openmct.indicators.allIndicatorElements().then(function (elements) {
 | 
			
		||||
                        elements.forEach(function (indicatorElement) {
 | 
			
		||||
                            element.append(indicatorElement);
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get all indicators to display.
 | 
			
		||||
         * @returns {Indicator[]} all indicators
 | 
			
		||||
         *          to display in the bottom bar.
 | 
			
		||||
         * @memberof platform/commonUI/general.BottomBarController#
 | 
			
		||||
         */
 | 
			
		||||
        BottomBarController.prototype.getIndicators = function () {
 | 
			
		||||
            return this.indicators;
 | 
			
		||||
        };
 | 
			
		||||
        return MCTIndicators;
 | 
			
		||||
 | 
			
		||||
        return BottomBarController;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,76 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (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/BottomBarController"],
 | 
			
		||||
    function (BottomBarController) {
 | 
			
		||||
 | 
			
		||||
        describe("The bottom bar controller", function () {
 | 
			
		||||
            var testIndicators,
 | 
			
		||||
                testIndicatorA,
 | 
			
		||||
                testIndicatorB,
 | 
			
		||||
                testIndicatorC,
 | 
			
		||||
                mockIndicator,
 | 
			
		||||
                controller;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockIndicator = jasmine.createSpyObj(
 | 
			
		||||
                    "indicator",
 | 
			
		||||
                    ["getGlyph", "getCssClass", "getText"]
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                testIndicatorA = {};
 | 
			
		||||
                testIndicatorB = function () {
 | 
			
		||||
                    return mockIndicator;
 | 
			
		||||
                };
 | 
			
		||||
                testIndicatorC = { template: "someTemplate" };
 | 
			
		||||
 | 
			
		||||
                testIndicators = [
 | 
			
		||||
                    testIndicatorA,
 | 
			
		||||
                    testIndicatorB,
 | 
			
		||||
                    testIndicatorC
 | 
			
		||||
                ];
 | 
			
		||||
 | 
			
		||||
                controller = new BottomBarController(testIndicators);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("exposes one indicator description per extension", function () {
 | 
			
		||||
                expect(controller.getIndicators().length)
 | 
			
		||||
                    .toEqual(testIndicators.length);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("uses template field provided, or its own default", function () {
 | 
			
		||||
                // "indicator" is the default;
 | 
			
		||||
                // only testIndicatorC overrides this.
 | 
			
		||||
                var indicators = controller.getIndicators();
 | 
			
		||||
                expect(indicators[0].template).toEqual("indicator");
 | 
			
		||||
                expect(indicators[1].template).toEqual("indicator");
 | 
			
		||||
                expect(indicators[2].template).toEqual("someTemplate");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("instantiates indicators given as constructors", function () {
 | 
			
		||||
                // testIndicatorB constructs to mockIndicator
 | 
			
		||||
                expect(controller.getIndicators()[1].ngModel).toBe(mockIndicator);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,9 +1,7 @@
 | 
			
		||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
 | 
			
		||||
<a ng-click="showNotificationsList()" ng-show="notifications.length > 0" class="status block"
 | 
			
		||||
      ng-class="highest.severity"
 | 
			
		||||
<a ng-click="showNotificationsList()" ng-show="notifications.length > 0" class="l-indicator s-indicator s-indicator-status-{{highest.severity}} icon-bell"
 | 
			
		||||
      ng-controller="NotificationIndicatorController">
 | 
			
		||||
    <span class="status-indicator icon-bell"></span><span class="label">
 | 
			
		||||
      {{notifications.length}} Notifications
 | 
			
		||||
    <span class="label">
 | 
			
		||||
        {{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span>
 | 
			
		||||
    </span><span class="count">{{notifications.length}}</span>
 | 
			
		||||
 | 
			
		||||
</a>
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ $colorTransLucBg: #666; // Used as a visual blocking element over variable backg
 | 
			
		||||
 | 
			
		||||
// Foundation Colors
 | 
			
		||||
$colorAlt1: #ffc700;
 | 
			
		||||
$colorAlert: #ff3c00;
 | 
			
		||||
$colorAlert: #ff6600;
 | 
			
		||||
$colorWarningHi: #cc0000;
 | 
			
		||||
$colorWarningLo: #ff9900;
 | 
			
		||||
$colorDiagnostic: #a4b442;
 | 
			
		||||
@@ -114,10 +114,10 @@ $colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
 | 
			
		||||
 | 
			
		||||
// Status colors, mainly used for messaging and item ancillary symbols
 | 
			
		||||
$colorStatusFg: #ccc;
 | 
			
		||||
$colorStatusDefault: #ccc;
 | 
			
		||||
$colorStatusDefault: #999;
 | 
			
		||||
$colorStatusInfo: $colorInfo;
 | 
			
		||||
$colorStatusAlert: $colorAlert;
 | 
			
		||||
$colorStatusError: #d4585c;
 | 
			
		||||
$colorStatusError: #ff3300;
 | 
			
		||||
$colorStatusAvailable: $colorKey;
 | 
			
		||||
$colorStatusBtnBg: $colorBtnBg;
 | 
			
		||||
$colorProgressBarOuter: rgba(#000, 0.1);
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,6 @@ define([
 | 
			
		||||
    timerTemplate,
 | 
			
		||||
    legacyRegistry
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    legacyRegistry.register("platform/features/clock", {
 | 
			
		||||
        "name": "Clocks/Timers",
 | 
			
		||||
        "descriptions": "Domain objects for displaying current & relative times.",
 | 
			
		||||
@@ -86,11 +85,6 @@ define([
 | 
			
		||||
                        "CLOCK_INDICATOR_FORMAT"
 | 
			
		||||
                    ],
 | 
			
		||||
                    "priority": "preferred"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "implementation": FollowIndicator,
 | 
			
		||||
                    "depends": ["timerService"],
 | 
			
		||||
                    "priority": "fallback"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "services": [
 | 
			
		||||
@@ -305,6 +299,10 @@ define([
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "runs": [{
 | 
			
		||||
                "implementation": FollowIndicator,
 | 
			
		||||
                "depends": ["openmct", "timerService"]
 | 
			
		||||
            }],
 | 
			
		||||
            "licenses": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "moment-duration-format",
 | 
			
		||||
 
 | 
			
		||||
@@ -45,11 +45,11 @@ define(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ClockIndicator.prototype.getGlyphClass = function () {
 | 
			
		||||
            return "no-collapse float-right subdued";
 | 
			
		||||
            return "subdued";
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ClockIndicator.prototype.getCssClass = function () {
 | 
			
		||||
            return "icon-clock";
 | 
			
		||||
            return "icon-clock no-collapse float-right";
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ClockIndicator.prototype.getText = function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2009-2016, United States Government
 | 
			
		||||
 * Open MCT, Copyright (c) 2009-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
@@ -20,38 +20,32 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ['moment'],
 | 
			
		||||
    function (moment) {
 | 
			
		||||
        var NO_TIMER = "No timer being followed";
 | 
			
		||||
define([], function () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Indicator that displays the active timer, as well as its
 | 
			
		||||
         * current state.
 | 
			
		||||
         * @implements {Indicator}
 | 
			
		||||
         * @memberof platform/features/clock
 | 
			
		||||
         */
 | 
			
		||||
        function FollowIndicator(timerService) {
 | 
			
		||||
            this.timerService = timerService;
 | 
			
		||||
    /**
 | 
			
		||||
     * Indicator that displays the active timer, as well as its
 | 
			
		||||
     * current state.
 | 
			
		||||
     * @memberof platform/features/clock
 | 
			
		||||
     */
 | 
			
		||||
    return function installFollowIndicator(openmct, timerService) {
 | 
			
		||||
        var indicator = openmct.indicators.simpleIndicator();
 | 
			
		||||
        var timer = timerService.getTimer();
 | 
			
		||||
        setIndicatorStatus(timer);
 | 
			
		||||
 | 
			
		||||
        function setIndicatorStatus(newTimer) {
 | 
			
		||||
            if (newTimer !== undefined) {
 | 
			
		||||
                indicator.iconClass('icon-timer');
 | 
			
		||||
                indicator.statusClass('s-status-ok');
 | 
			
		||||
                indicator.text('Following timer ' + newTimer.name);
 | 
			
		||||
            } else {
 | 
			
		||||
                indicator.iconClass('icon-timer');
 | 
			
		||||
                indicator.statusClass('');
 | 
			
		||||
                indicator.text('No timer being followed');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        FollowIndicator.prototype.getGlyphClass = function () {
 | 
			
		||||
            return "";
 | 
			
		||||
        };
 | 
			
		||||
        timerService.on('change', setIndicatorStatus);
 | 
			
		||||
 | 
			
		||||
        FollowIndicator.prototype.getCssClass = function () {
 | 
			
		||||
            return (this.timerService.getTimer()) ? "icon-timer s-status-ok" : "icon-timer";
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        FollowIndicator.prototype.getText = function () {
 | 
			
		||||
            var timer = this.timerService.getTimer();
 | 
			
		||||
            return timer ? ('Following timer ' + timer.name) : NO_TIMER;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        FollowIndicator.prototype.getDescription = function () {
 | 
			
		||||
            return "";
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return FollowIndicator;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
        openmct.indicators.add(indicator);
 | 
			
		||||
    };
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ define(['EventEmitter'], function (EventEmitter) {
 | 
			
		||||
     */
 | 
			
		||||
    TimerService.prototype.setTimer = function (timer) {
 | 
			
		||||
        this.timer = timer;
 | 
			
		||||
        this.emit('change');
 | 
			
		||||
        this.emit('change', timer);
 | 
			
		||||
 | 
			
		||||
        if (this.stopObserving) {
 | 
			
		||||
            this.stopObserving();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2009-2016, United States Government
 | 
			
		||||
 * Open MCT, Copyright (c) 2009-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
@@ -20,39 +20,77 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(["../../src/indicators/FollowIndicator"], function (FollowIndicator) {
 | 
			
		||||
    var TIMER_SERVICE_METHODS =
 | 
			
		||||
        ['setTimer', 'getTimer', 'clearTimer', 'on', 'off'];
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    "../../src/indicators/FollowIndicator",
 | 
			
		||||
    "../../src/services/TimerService",
 | 
			
		||||
    "../../../../../src/MCT",
 | 
			
		||||
    'zepto'
 | 
			
		||||
], function (
 | 
			
		||||
    FollowIndicator,
 | 
			
		||||
    TimerService,
 | 
			
		||||
    MCT,
 | 
			
		||||
    $
 | 
			
		||||
) {
 | 
			
		||||
    describe("The timer-following indicator", function () {
 | 
			
		||||
        var mockTimerService;
 | 
			
		||||
        var indicator;
 | 
			
		||||
        var timerService;
 | 
			
		||||
        var openmct;
 | 
			
		||||
 | 
			
		||||
        beforeEach(function () {
 | 
			
		||||
            mockTimerService =
 | 
			
		||||
                jasmine.createSpyObj('timerService', TIMER_SERVICE_METHODS);
 | 
			
		||||
            indicator = new FollowIndicator(mockTimerService);
 | 
			
		||||
            openmct = new MCT();
 | 
			
		||||
            timerService = new TimerService(openmct);
 | 
			
		||||
            spyOn(openmct.indicators, "add");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it("implements the Indicator interface", function () {
 | 
			
		||||
            expect(indicator.getGlyphClass()).toEqual(jasmine.any(String));
 | 
			
		||||
            expect(indicator.getCssClass()).toEqual(jasmine.any(String));
 | 
			
		||||
            expect(indicator.getText()).toEqual(jasmine.any(String));
 | 
			
		||||
            expect(indicator.getDescription()).toEqual(jasmine.any(String));
 | 
			
		||||
        it("adds an indicator when installed", function () {
 | 
			
		||||
            FollowIndicator(openmct, timerService);
 | 
			
		||||
            expect(openmct.indicators.add).toHaveBeenCalled();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it("indicates that no timer is being followed", function () {
 | 
			
		||||
            FollowIndicator(openmct, timerService);
 | 
			
		||||
            var simpleIndicator = openmct.indicators.add.mostRecentCall.args[0];
 | 
			
		||||
            var element = simpleIndicator.element;
 | 
			
		||||
            var text = $('.indicator-text', element).text().trim();
 | 
			
		||||
            expect(text).toEqual('No timer being followed');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe("when a timer is set", function () {
 | 
			
		||||
            var testObject;
 | 
			
		||||
            var simpleIndicator;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                testObject = { name: "some timer!" };
 | 
			
		||||
                mockTimerService.getTimer.andReturn(testObject);
 | 
			
		||||
                testObject = {
 | 
			
		||||
                    identifier: {
 | 
			
		||||
                        namespace: 'namespace',
 | 
			
		||||
                        key: 'key'
 | 
			
		||||
                    },
 | 
			
		||||
                    name: "some timer!"
 | 
			
		||||
                };
 | 
			
		||||
                timerService.setTimer(testObject);
 | 
			
		||||
                FollowIndicator(openmct, timerService);
 | 
			
		||||
                simpleIndicator = openmct.indicators.add.mostRecentCall.args[0];
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("displays the timer's name", function () {
 | 
			
		||||
                expect(indicator.getText().indexOf(testObject.name))
 | 
			
		||||
                    .not.toEqual(-1);
 | 
			
		||||
                var element = simpleIndicator.element;
 | 
			
		||||
                var text = $('.indicator-text', element).text().trim();
 | 
			
		||||
                expect(text).toEqual('Following timer ' + testObject.name);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("displays the timer's name when it changes", function () {
 | 
			
		||||
                var secondTimer = {
 | 
			
		||||
                    identifier: {
 | 
			
		||||
                        namespace: 'namespace',
 | 
			
		||||
                        key: 'key2'
 | 
			
		||||
                    },
 | 
			
		||||
                    name: "Some other timer"
 | 
			
		||||
                };
 | 
			
		||||
                var element = simpleIndicator.element;
 | 
			
		||||
                timerService.setTimer(secondTimer);
 | 
			
		||||
                var text = $('.indicator-text', element).text().trim();
 | 
			
		||||
                expect(text).toEqual('Following timer ' + secondTimer.name);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								src/MCT.js
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/MCT.js
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
@@ -194,6 +194,15 @@ define([
 | 
			
		||||
         */
 | 
			
		||||
        this.telemetry = new api.TelemetryAPI(this);
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * An interface for creating new indicators and changing them dynamically.
 | 
			
		||||
         *
 | 
			
		||||
         * @type {module:openmct.IndicatorAPI}
 | 
			
		||||
         * @memberof module:openmct.MCT#
 | 
			
		||||
         * @name indicators
 | 
			
		||||
         */
 | 
			
		||||
        this.indicators = new api.IndicatorAPI(this);
 | 
			
		||||
 | 
			
		||||
        this.Dialog = api.Dialog;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,8 @@ define([
 | 
			
		||||
    './types/TypeRegistry',
 | 
			
		||||
    './ui/Dialog',
 | 
			
		||||
    './ui/GestureAPI',
 | 
			
		||||
    './telemetry/TelemetryAPI'
 | 
			
		||||
    './telemetry/TelemetryAPI',
 | 
			
		||||
    './indicators/IndicatorAPI'
 | 
			
		||||
], function (
 | 
			
		||||
    TimeAPI,
 | 
			
		||||
    ObjectAPI,
 | 
			
		||||
@@ -35,7 +36,8 @@ define([
 | 
			
		||||
    TypeRegistry,
 | 
			
		||||
    Dialog,
 | 
			
		||||
    GestureAPI,
 | 
			
		||||
    TelemetryAPI
 | 
			
		||||
    TelemetryAPI,
 | 
			
		||||
    IndicatorAPI
 | 
			
		||||
) {
 | 
			
		||||
    return {
 | 
			
		||||
        TimeAPI: TimeAPI,
 | 
			
		||||
@@ -44,6 +46,7 @@ define([
 | 
			
		||||
        Dialog: Dialog,
 | 
			
		||||
        TypeRegistry: TypeRegistry,
 | 
			
		||||
        GestureAPI: GestureAPI,
 | 
			
		||||
        TelemetryAPI: TelemetryAPI
 | 
			
		||||
        TelemetryAPI: TelemetryAPI,
 | 
			
		||||
        IndicatorAPI: IndicatorAPI
 | 
			
		||||
    };
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										129
									
								
								src/api/indicators/IndicatorAPI.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								src/api/indicators/IndicatorAPI.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,129 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
define([
 | 
			
		||||
    './SimpleIndicator',
 | 
			
		||||
    '../../../platform/framework/src/Constants',
 | 
			
		||||
    'lodash'
 | 
			
		||||
], function (
 | 
			
		||||
    SimpleIndicator,
 | 
			
		||||
    Constants,
 | 
			
		||||
    _
 | 
			
		||||
) {
 | 
			
		||||
    /* jshint validthis: true */
 | 
			
		||||
    var LEGACY_INDICATOR_TEMPLATE =
 | 
			
		||||
        '<mct-include ' +
 | 
			
		||||
        '   ng-model="indicator" ' +
 | 
			
		||||
        '   key="template" ' +
 | 
			
		||||
        ' </mct-include>';
 | 
			
		||||
 | 
			
		||||
    function IndicatorAPI(openmct) {
 | 
			
		||||
        this.openmct = openmct;
 | 
			
		||||
        this.indicatorElements = [];
 | 
			
		||||
        this.promiseForAllElements =
 | 
			
		||||
            fetchLegacyIndicators.call(this)
 | 
			
		||||
            .then(addLegacyIndicators.bind(this))
 | 
			
		||||
            .then(resolveWithAllIndicatorElements.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    IndicatorAPI.prototype.simpleIndicator = function () {
 | 
			
		||||
        return new SimpleIndicator(this.openmct);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Accepts an indicator object, which is a simple object
 | 
			
		||||
     * with a single attribute, 'element' which has an HTMLElement
 | 
			
		||||
     * as its value.
 | 
			
		||||
     *
 | 
			
		||||
     * We provide .simpleIndicator() as a convenience function
 | 
			
		||||
     * which will create a default Open MCT indicator that can
 | 
			
		||||
     * be passed to .add(indicator). This indicator also exposes
 | 
			
		||||
     * functions for changing its appearance to support customization
 | 
			
		||||
     * and dynamic behavior.
 | 
			
		||||
     *
 | 
			
		||||
     * Eg.
 | 
			
		||||
     * var myIndicator = openmct.indicators.simpleIndicator();
 | 
			
		||||
     * openmct.indicators.add(myIndicator);
 | 
			
		||||
     *
 | 
			
		||||
     * myIndicator.text("Hello World!");
 | 
			
		||||
     * myIndicator.iconClass("icon-info");
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    IndicatorAPI.prototype.add = function (indicator) {
 | 
			
		||||
        // So that we can consistently position indicator elements,
 | 
			
		||||
        // guarantee that they are wrapped in an element we control
 | 
			
		||||
        var wrapperNode = document.createElement('div');
 | 
			
		||||
        wrapperNode.className = 'l-indicator s-indicator';
 | 
			
		||||
        wrapperNode.appendChild(indicator.element);
 | 
			
		||||
        this.indicatorElements.push(wrapperNode);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    IndicatorAPI.prototype.allIndicatorElements = function () {
 | 
			
		||||
        return this.promiseForAllElements;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    function fetchLegacyIndicators() {
 | 
			
		||||
        return new Promise(function (resolve) {
 | 
			
		||||
            this.openmct.legacyExtension('runs', {
 | 
			
		||||
                depends: ['indicators[]'],
 | 
			
		||||
                implementation: resolve
 | 
			
		||||
            });
 | 
			
		||||
        }.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function addLegacyIndicators(legacyIndicators) {
 | 
			
		||||
        legacyIndicators.forEach(function (legacyIndicatorDef) {
 | 
			
		||||
            var legacyIndicator = initializeIfNeeded(legacyIndicatorDef);
 | 
			
		||||
            var legacyIndicatorElement = buildLegacyIndicator(this.openmct, legacyIndicator, legacyIndicatorDef.template);
 | 
			
		||||
            this.indicatorElements.push(legacyIndicatorElement);
 | 
			
		||||
        }.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function initializeIfNeeded(LegacyIndicatorDef) {
 | 
			
		||||
        var legacyIndicator;
 | 
			
		||||
        if (typeof LegacyIndicatorDef === 'function') {
 | 
			
		||||
            legacyIndicator = new LegacyIndicatorDef();
 | 
			
		||||
        } else {
 | 
			
		||||
            legacyIndicator = LegacyIndicatorDef;
 | 
			
		||||
        }
 | 
			
		||||
        return legacyIndicator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function buildLegacyIndicator(openmct, legacyIndicator, template) {
 | 
			
		||||
        var $compile = openmct.$injector.get('$compile');
 | 
			
		||||
        var $rootScope = openmct.$injector.get('$rootScope');
 | 
			
		||||
        var scope = $rootScope.$new(true);
 | 
			
		||||
        scope.indicator = legacyIndicator;
 | 
			
		||||
        scope.template = template || 'indicator';
 | 
			
		||||
 | 
			
		||||
        return $compile(LEGACY_INDICATOR_TEMPLATE)(scope)[0];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function resolveWithAllIndicatorElements() {
 | 
			
		||||
        return this.indicatorElements;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return IndicatorAPI;
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										214
									
								
								src/api/indicators/IndicatorAPISpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								src/api/indicators/IndicatorAPISpec.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,214 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [
 | 
			
		||||
        "../../MCT",
 | 
			
		||||
        "../../../platform/commonUI/general/src/directives/MCTIndicators",
 | 
			
		||||
        "zepto"
 | 
			
		||||
    ],
 | 
			
		||||
    function (
 | 
			
		||||
        MCT,
 | 
			
		||||
        MCTIndicators,
 | 
			
		||||
        $
 | 
			
		||||
    ) {
 | 
			
		||||
        describe("The Indicator API", function () {
 | 
			
		||||
            var openmct;
 | 
			
		||||
            var directive;
 | 
			
		||||
            var holderElement;
 | 
			
		||||
            var legacyExtensionFunction = MCT.prototype.legacyExtension;
 | 
			
		||||
            var legacyIndicatorsResolved = false;
 | 
			
		||||
            var legacyIndicatorsCallback;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockLegacyExtensionFunction();
 | 
			
		||||
 | 
			
		||||
                openmct = new MCT();
 | 
			
		||||
                directive = new MCTIndicators(openmct);
 | 
			
		||||
                holderElement = document.createElement('div');
 | 
			
		||||
 | 
			
		||||
                mockAngularComponents();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            afterEach(function () {
 | 
			
		||||
                MCT.prototype.legacyExtension = legacyExtensionFunction;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("Displays any legacy indicators ", function () {
 | 
			
		||||
                var legacyIndicators = [{},{},{},{}];
 | 
			
		||||
 | 
			
		||||
                mockLegacyIndicatorsWith(legacyIndicators);
 | 
			
		||||
 | 
			
		||||
                renderIndicators();
 | 
			
		||||
 | 
			
		||||
                waitsFor(legacyIndicatorsToResolve, 1000);
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    expectIndicatorsShownToBe(legacyIndicators.length);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("If legacy indicator is defined as a constructor function, executes function ", function () {
 | 
			
		||||
                var mockConstructorFunction = jasmine.createSpy('mockIndicatorConstructor');
 | 
			
		||||
                var legacyIndicators = [{}, mockConstructorFunction];
 | 
			
		||||
 | 
			
		||||
                mockConstructorFunction.andReturn({});
 | 
			
		||||
                mockLegacyIndicatorsWith(legacyIndicators);
 | 
			
		||||
                renderIndicators();
 | 
			
		||||
 | 
			
		||||
                waitsFor(legacyIndicatorsToResolve, 1000);
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    expectIndicatorsShownToBe(legacyIndicators.length);
 | 
			
		||||
                    expect(mockConstructorFunction).toHaveBeenCalled();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            describe("The simple indicator", function () {
 | 
			
		||||
                var simpleIndicator;
 | 
			
		||||
 | 
			
		||||
                beforeEach(function () {
 | 
			
		||||
                    simpleIndicator = openmct.indicators.simpleIndicator();
 | 
			
		||||
                    mockLegacyIndicatorsWith([]);
 | 
			
		||||
                    openmct.indicators.add(simpleIndicator);
 | 
			
		||||
                    renderIndicators();
 | 
			
		||||
                });
 | 
			
		||||
                it("applies the set icon class", function () {
 | 
			
		||||
                    simpleIndicator.iconClass('testIconClass');
 | 
			
		||||
 | 
			
		||||
                    waitsFor(legacyIndicatorsToResolve);
 | 
			
		||||
                    runs(function () {
 | 
			
		||||
                        expect(getIconElement().hasClass('testIconClass')).toBe(true);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
                it("applies the set status class", function () {
 | 
			
		||||
                    simpleIndicator.statusClass('testStatusClass');
 | 
			
		||||
 | 
			
		||||
                    waitsFor(legacyIndicatorsToResolve);
 | 
			
		||||
                    runs(function () {
 | 
			
		||||
                        expect(getIconElement().hasClass('testStatusClass')).toBe(true);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
                it("displays the set text", function () {
 | 
			
		||||
                    simpleIndicator.text('some test text');
 | 
			
		||||
 | 
			
		||||
                    waitsFor(legacyIndicatorsToResolve);
 | 
			
		||||
                    runs(function () {
 | 
			
		||||
                        expect(getTextElement().text().trim()).toEqual('some test text');
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
                it("sets the indicator's title", function () {
 | 
			
		||||
                    simpleIndicator.description('a test description');
 | 
			
		||||
 | 
			
		||||
                    waitsFor(legacyIndicatorsToResolve);
 | 
			
		||||
                    runs(function () {
 | 
			
		||||
                        expect(getIndicatorElement().attr('title')).toEqual('a test description');
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it("Hides indicator text if no text is set", function () {
 | 
			
		||||
                    simpleIndicator.text('');
 | 
			
		||||
 | 
			
		||||
                    waitsFor(legacyIndicatorsToResolve);
 | 
			
		||||
                    runs(function () {
 | 
			
		||||
                        expect(getIndicatorElement().hasClass('hidden')).toBe(true);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("Supports registration of a completely custom indicator", function () {
 | 
			
		||||
                var customIndicator = $('<div class="customIndicator">A custom indicator</div>')[0];
 | 
			
		||||
                mockLegacyIndicatorsWith([]);
 | 
			
		||||
                openmct.indicators.add({element: customIndicator});
 | 
			
		||||
                renderIndicators();
 | 
			
		||||
 | 
			
		||||
                waitsFor(legacyIndicatorsToResolve);
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    expect($('.customIndicator', holderElement).text().trim()).toEqual('A custom indicator');
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            function mockLegacyExtensionFunction() {
 | 
			
		||||
                spyOn(MCT.prototype, "legacyExtension");
 | 
			
		||||
                MCT.prototype.legacyExtension.andCallFake(function (extensionName, definition) {
 | 
			
		||||
                    if (extensionName === 'runs') {
 | 
			
		||||
                        legacyIndicatorsCallback = definition.implementation;
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function mockAngularComponents() {
 | 
			
		||||
                var mockInjector = jasmine.createSpyObj('$injector', ['get']);
 | 
			
		||||
                var mockCompile = jasmine.createSpy('$compile');
 | 
			
		||||
                var mockRootScope = jasmine.createSpyObj('rootScope', ['$new']);
 | 
			
		||||
                var mockScope = {};
 | 
			
		||||
 | 
			
		||||
                mockRootScope.$new.andReturn(mockScope);
 | 
			
		||||
                mockInjector.get.andCallFake(function (service) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        '$compile': mockCompile,
 | 
			
		||||
                        '$rootScope': mockRootScope
 | 
			
		||||
                    }[service];
 | 
			
		||||
                });
 | 
			
		||||
                openmct.$injector = mockInjector;
 | 
			
		||||
                mockCompile.andCallFake(function () {
 | 
			
		||||
                    return function () {
 | 
			
		||||
                        return $('<div></div>');
 | 
			
		||||
                    };
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function renderIndicators() {
 | 
			
		||||
                directive.link({}, holderElement);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function mockLegacyIndicatorsWith(legacyIndicators) {
 | 
			
		||||
                legacyIndicatorsResolved = false;
 | 
			
		||||
 | 
			
		||||
                openmct.indicators.allIndicatorElements().then(function () {
 | 
			
		||||
                    legacyIndicatorsResolved = true;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                legacyIndicatorsCallback(legacyIndicators);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function legacyIndicatorsToResolve() {
 | 
			
		||||
                return legacyIndicatorsResolved;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function expectIndicatorsShownToBe(number) {
 | 
			
		||||
                expect(holderElement.children.length).toBe(number);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function getIconElement() {
 | 
			
		||||
                return $('.indicator-icon', holderElement);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function getIndicatorElement() {
 | 
			
		||||
                return $('.status', holderElement);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function getTextElement() {
 | 
			
		||||
                return $('.indicator-text', holderElement);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
							
								
								
									
										100
									
								
								src/api/indicators/SimpleIndicator.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/api/indicators/SimpleIndicator.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(['text!./res/indicator-template.html'],
 | 
			
		||||
    function (indicatorTemplate) {
 | 
			
		||||
        var DEFAULT_ICON_CLASS = 'icon-info';
 | 
			
		||||
 | 
			
		||||
        function SimpleIndicator(openmct) {
 | 
			
		||||
            this.openmct = openmct;
 | 
			
		||||
            this.textValue = 'New Indicator';
 | 
			
		||||
            this.descriptionValue = 'A simple indicator';
 | 
			
		||||
            this.iconClassValue = DEFAULT_ICON_CLASS;
 | 
			
		||||
            this.statusClassValue = '';
 | 
			
		||||
 | 
			
		||||
            // We need to remove this element
 | 
			
		||||
            this.element = document.createElement('div');
 | 
			
		||||
            this.element.className = 'status-block-holder';
 | 
			
		||||
 | 
			
		||||
            SimpleIndicator.defaultDisplayFunction.call(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SimpleIndicator.prototype.text = function (text) {
 | 
			
		||||
            if (text !== undefined && text !== this.textValue) {
 | 
			
		||||
                this.textValue = text;
 | 
			
		||||
                SimpleIndicator.defaultDisplayFunction.call(this);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return this.textValue;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        SimpleIndicator.prototype.description = function (description) {
 | 
			
		||||
            if (description !== undefined && description !== this.descriptionValue) {
 | 
			
		||||
                this.descriptionValue = description;
 | 
			
		||||
                SimpleIndicator.defaultDisplayFunction.call(this);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return this.descriptionValue;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        SimpleIndicator.prototype.iconClass = function (iconClass) {
 | 
			
		||||
            if (iconClass !== undefined && iconClass !== this.iconClassValue) {
 | 
			
		||||
                this.iconClassValue = iconClass;
 | 
			
		||||
                SimpleIndicator.defaultDisplayFunction.call(this);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return this.iconClassValue;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        SimpleIndicator.prototype.statusClass = function (statusClass) {
 | 
			
		||||
            if (statusClass !== undefined && statusClass !== this.statusClassValue) {
 | 
			
		||||
                this.statusClassValue = statusClass;
 | 
			
		||||
                SimpleIndicator.defaultDisplayFunction.call(this);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return this.statusClassValue;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        function hideOrShowText(text) {
 | 
			
		||||
            if (text && text.length > 0) {
 | 
			
		||||
                return '';
 | 
			
		||||
            } else {
 | 
			
		||||
                return 'hidden';
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SimpleIndicator.defaultDisplayFunction = function () {
 | 
			
		||||
            var html = indicatorTemplate
 | 
			
		||||
                .replace('{{indicator.text}}', this.text())
 | 
			
		||||
                .replace('{{indicator.iconClass}}', this.iconClass())
 | 
			
		||||
                .replace('{{indicator.statusClass}}', this.statusClass())
 | 
			
		||||
                .replace('{{indicator.description}}', this.description())
 | 
			
		||||
                .replace('{{hideOrShowText}}', hideOrShowText(this.text()));
 | 
			
		||||
 | 
			
		||||
            this.element.innerHTML = html;
 | 
			
		||||
 | 
			
		||||
            return this.element;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return SimpleIndicator;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										24
									
								
								src/api/indicators/res/indicator-template.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/api/indicators/res/indicator-template.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
<!--
 | 
			
		||||
 Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 Administration. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 You may obtain a copy of the License at
 | 
			
		||||
 http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 | 
			
		||||
 Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 License for the specific language governing permissions and limitations
 | 
			
		||||
 under the License.
 | 
			
		||||
 | 
			
		||||
 Open MCT includes source code licensed under additional open source
 | 
			
		||||
 licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<span class="{{hideOrShowText}} {{indicator.iconClass}} {{indicator.statusClass}}" title="{{indicator.description}}">
 | 
			
		||||
    <span class="label indicator-text">{{indicator.text}}</span>
 | 
			
		||||
</span>
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2016, United States Government
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
@@ -21,8 +21,8 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
    ['zepto'],
 | 
			
		||||
    function ($) {
 | 
			
		||||
 | 
			
		||||
        // Set of connection states; changing among these states will be
 | 
			
		||||
        // reflected in the indicator's appearance.
 | 
			
		||||
@@ -30,68 +30,86 @@ define(
 | 
			
		||||
        // DISCONNECTED: HTTP failed; maybe misconfigured, disconnected.
 | 
			
		||||
        // PENDING: Still trying to connect, and haven't failed yet.
 | 
			
		||||
        var CONNECTED = {
 | 
			
		||||
                glyphClass: "ok"
 | 
			
		||||
                statusClass: "s-status-ok"
 | 
			
		||||
            },
 | 
			
		||||
            PENDING = {
 | 
			
		||||
                glyphClass: 'caution'
 | 
			
		||||
                statusClass: "s-status-warning-lo"
 | 
			
		||||
            },
 | 
			
		||||
            DISCONNECTED = {
 | 
			
		||||
                glyphClass: "err"
 | 
			
		||||
                statusClass: "s-status-warning-hi"
 | 
			
		||||
            };
 | 
			
		||||
        function URLIndicator($http, $interval) {
 | 
			
		||||
            var self = this;
 | 
			
		||||
            this.cssClass = this.options.cssClass ? this.options.cssClass : "icon-database";
 | 
			
		||||
            this.URLpath = this.options.url;
 | 
			
		||||
            this.label = this.options.label ? this.options.label : this.options.url;
 | 
			
		||||
            this.interval = this.options.interval || 10000;
 | 
			
		||||
            this.state = PENDING;
 | 
			
		||||
        function URLIndicator(options, openmct, simpleIndicator) {
 | 
			
		||||
            this.bindMethods();
 | 
			
		||||
            this.count = 0;
 | 
			
		||||
 | 
			
		||||
            function handleError(e) {
 | 
			
		||||
                self.state = DISCONNECTED;
 | 
			
		||||
            }
 | 
			
		||||
            function handleResponse() {
 | 
			
		||||
                self.state = CONNECTED;
 | 
			
		||||
            }
 | 
			
		||||
            function updateIndicator() {
 | 
			
		||||
                $http.get(self.URLpath).then(handleResponse, handleError);
 | 
			
		||||
            }
 | 
			
		||||
            updateIndicator();
 | 
			
		||||
            $interval(updateIndicator, self.interval, 0, false);
 | 
			
		||||
            this.indicator = simpleIndicator;
 | 
			
		||||
            this.setDefaultsFromOptions(options);
 | 
			
		||||
            this.setIndicatorToState(PENDING);
 | 
			
		||||
 | 
			
		||||
            this.fetchUrl();
 | 
			
		||||
            setInterval(this.fetchUrl, this.interval);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        URLIndicator.prototype.getCssClass = function () {
 | 
			
		||||
            return this.cssClass;
 | 
			
		||||
        };
 | 
			
		||||
        URLIndicator.prototype.getGlyphClass = function () {
 | 
			
		||||
            return this.state.glyphClass;
 | 
			
		||||
        };
 | 
			
		||||
        URLIndicator.prototype.getText = function () {
 | 
			
		||||
            switch (this.state) {
 | 
			
		||||
        URLIndicator.prototype.setIndicatorToState = function (state) {
 | 
			
		||||
            switch (state) {
 | 
			
		||||
                case CONNECTED: {
 | 
			
		||||
                    return this.label + " is connected";
 | 
			
		||||
                    this.indicator.text(this.label + " is connected");
 | 
			
		||||
                    this.indicator.description(this.label + " is online, checking status every " + this.interval + " milliseconds.");
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case PENDING: {
 | 
			
		||||
                    return "Checking status of " + this.label + " please stand by...";
 | 
			
		||||
                    this.indicator.text("Checking status of " + this.label + " please stand by...");
 | 
			
		||||
                    this.indicator.description("Checking status of " + this.label + " please stand by...");
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case DISCONNECTED: {
 | 
			
		||||
                    return this.label + " is offline";
 | 
			
		||||
                    this.indicator.text(this.label + " is offline");
 | 
			
		||||
                    this.indicator.description(this.label + " is offline, checking status every " + this.interval + " milliseconds");
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.indicator.statusClass(state.statusClass);
 | 
			
		||||
        };
 | 
			
		||||
        URLIndicator.prototype.getDescription = function () {
 | 
			
		||||
            switch (this.state) {
 | 
			
		||||
                case CONNECTED: {
 | 
			
		||||
                    return this.label + " is online, checking status every " +
 | 
			
		||||
                    this.interval + " milliseconds.";
 | 
			
		||||
                }
 | 
			
		||||
                case PENDING: {
 | 
			
		||||
                    return "Checking status of " + this.label + " please stand by...";
 | 
			
		||||
                }
 | 
			
		||||
                case DISCONNECTED: {
 | 
			
		||||
                    return this.label + " is offline, checking status every " +
 | 
			
		||||
                    this.interval + " milliseconds";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        URLIndicator.prototype.fetchUrl = function () {
 | 
			
		||||
            this.get(this.URLpath)
 | 
			
		||||
                .then(this.handleSuccess)
 | 
			
		||||
                .catch(this.handleError);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        URLIndicator.prototype.get = function (url) {
 | 
			
		||||
            return new Promise(function (resolve, reject) {
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                    type: 'GET',
 | 
			
		||||
                    url: url,
 | 
			
		||||
                    success: resolve,
 | 
			
		||||
                    error: reject
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        URLIndicator.prototype.handleError = function (e) {
 | 
			
		||||
            this.setIndicatorToState(DISCONNECTED);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        URLIndicator.prototype.handleSuccess = function () {
 | 
			
		||||
            this.setIndicatorToState(CONNECTED);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        URLIndicator.prototype.setDefaultsFromOptions = function (options) {
 | 
			
		||||
            this.URLpath = options.url;
 | 
			
		||||
            this.label = options.label || options.url;
 | 
			
		||||
            this.interval = options.interval || 10000;
 | 
			
		||||
            this.indicator.iconClass(options.iconClass || 'icon-connectivity');
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        URLIndicator.prototype.bindMethods = function () {
 | 
			
		||||
            this.fetchUrl = this.fetchUrl.bind(this);
 | 
			
		||||
            this.handleSuccess = this.handleSuccess.bind(this);
 | 
			
		||||
            this.handleError = this.handleError.bind(this);
 | 
			
		||||
            this.setIndicatorToState = this.setIndicatorToState.bind(this);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return URLIndicator;
 | 
			
		||||
    });
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +1,35 @@
 | 
			
		||||
define(
 | 
			
		||||
  [
 | 
			
		||||
    './URLIndicator'
 | 
			
		||||
  ],
 | 
			
		||||
  function URLIndicatorPlugin(URLIndicator) {
 | 
			
		||||
    return function (opts) {
 | 
			
		||||
        // Wrap the plugin in a function so we can apply the arguments.
 | 
			
		||||
        function URLIndicatorWrapper() {
 | 
			
		||||
            this.options = opts;
 | 
			
		||||
            URLIndicator.apply(this, arguments);
 | 
			
		||||
        }
 | 
			
		||||
        URLIndicatorWrapper.prototype = Object.create(URLIndicator.prototype);
 | 
			
		||||
        return function install(openmct) {
 | 
			
		||||
            openmct.legacyExtension('indicators', {
 | 
			
		||||
                  "implementation": URLIndicatorWrapper,
 | 
			
		||||
                  "depends": ["$http", "$interval"]
 | 
			
		||||
              });
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
define(['./URLIndicator'],
 | 
			
		||||
    function URLIndicatorPlugin(URLIndicator) {
 | 
			
		||||
        return function (opts) {
 | 
			
		||||
            return function install(openmct) {
 | 
			
		||||
                var simpleIndicator = openmct.indicators.simpleIndicator();
 | 
			
		||||
                var urlIndicator = new URLIndicator(opts, openmct, simpleIndicator);
 | 
			
		||||
 | 
			
		||||
                openmct.indicators.add(simpleIndicator);
 | 
			
		||||
 | 
			
		||||
                return urlIndicator;
 | 
			
		||||
            };
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
});
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2016, United States Government
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
@@ -21,138 +21,167 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ["./URLIndicator"],
 | 
			
		||||
    function (URLIndicator) {
 | 
			
		||||
 | 
			
		||||
    [
 | 
			
		||||
        "./URLIndicator",
 | 
			
		||||
        "./URLIndicatorPlugin",
 | 
			
		||||
        "../../MCT",
 | 
			
		||||
        "zepto"
 | 
			
		||||
    ],
 | 
			
		||||
    function (
 | 
			
		||||
        URLIndicator,
 | 
			
		||||
        URLIndicatorPlugin,
 | 
			
		||||
        MCT,
 | 
			
		||||
        $
 | 
			
		||||
    ) {
 | 
			
		||||
        var defaultPrototypeFunction = URLIndicator.prototype.get;
 | 
			
		||||
        describe("The URLIndicator", function () {
 | 
			
		||||
            var mockHttp,
 | 
			
		||||
                mockInterval,
 | 
			
		||||
                mockPromise,
 | 
			
		||||
                opts,
 | 
			
		||||
                Indicator,
 | 
			
		||||
                indicatorWrapper;
 | 
			
		||||
            var openmct;
 | 
			
		||||
            var indicatorElement;
 | 
			
		||||
            var urlIndicator;
 | 
			
		||||
            var mockHttpRequestFunction;
 | 
			
		||||
            var returned;
 | 
			
		||||
            var options;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockHttp = jasmine.createSpyObj("$http", ["get"]);
 | 
			
		||||
                mockInterval = jasmine.createSpy("$interval");
 | 
			
		||||
                mockPromise = jasmine.createSpyObj("promise", ["then"]);
 | 
			
		||||
                opts = {
 | 
			
		||||
                    url: "http://localhost:8080",
 | 
			
		||||
                    interval: 1337 //some number
 | 
			
		||||
                };
 | 
			
		||||
                mockHttp.get.andReturn(mockPromise);
 | 
			
		||||
                Indicator = function () {
 | 
			
		||||
                    this.options = opts;
 | 
			
		||||
                    URLIndicator.call(this, mockHttp, mockInterval);
 | 
			
		||||
                };
 | 
			
		||||
                Indicator.prototype = Object.create(URLIndicator.prototype);
 | 
			
		||||
                indicatorWrapper = new Indicator();
 | 
			
		||||
            });
 | 
			
		||||
            it("polls for changes", function () {
 | 
			
		||||
                expect(mockInterval).toHaveBeenCalledWith(
 | 
			
		||||
                    jasmine.any(Function),
 | 
			
		||||
                    opts.interval,
 | 
			
		||||
                    0,
 | 
			
		||||
                    false
 | 
			
		||||
                );
 | 
			
		||||
                returned = false;
 | 
			
		||||
                jasmine.Clock.useMock();
 | 
			
		||||
                openmct = new MCT();
 | 
			
		||||
                spyOn(openmct.indicators, 'add');
 | 
			
		||||
 | 
			
		||||
                mockHttpRequest();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("has a database cssClass as default", function () {
 | 
			
		||||
                expect(indicatorWrapper.getCssClass()).toEqual("icon-database");
 | 
			
		||||
            afterEach(function () {
 | 
			
		||||
                URLIndicator.prototype.get = defaultPrototypeFunction;
 | 
			
		||||
                jasmine.Clock.reset();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("consults the url with the path supplied", function () {
 | 
			
		||||
                expect(mockHttp.get).toHaveBeenCalledWith(opts.url);
 | 
			
		||||
            describe("on initialization", function () {
 | 
			
		||||
                describe("with default options", function () {
 | 
			
		||||
                    beforeEach(function () {
 | 
			
		||||
                        options = {
 | 
			
		||||
                            url: "someURL"
 | 
			
		||||
                        };
 | 
			
		||||
                        urlIndicator = URLIndicatorPlugin(options)(openmct);
 | 
			
		||||
                        indicatorElement = openmct.indicators.add.mostRecentCall.args[0].element;
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    it("has a default icon class if none supplied", function () {
 | 
			
		||||
                        var iconElement = getIconElement();
 | 
			
		||||
                        expect(iconElement.hasClass('icon-connectivity')).toBe(true);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    it("defaults to the URL if no label supplied", function () {
 | 
			
		||||
                        var textElement = getTextElement();
 | 
			
		||||
                        expect(textElement.text().indexOf(options.url) >= 0).toBe(true);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                describe("with custom options", function () {
 | 
			
		||||
                    beforeEach(function () {
 | 
			
		||||
                        options = {
 | 
			
		||||
                            url: "customURL",
 | 
			
		||||
                            interval: 1814,
 | 
			
		||||
                            iconClass: "iconClass-checked",
 | 
			
		||||
                            label: "custom label"
 | 
			
		||||
                        };
 | 
			
		||||
                        urlIndicator = URLIndicatorPlugin(options)(openmct);
 | 
			
		||||
                        indicatorElement = openmct.indicators.add.mostRecentCall.args[0].element;
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    it("uses the custom iconClass", function () {
 | 
			
		||||
                        var iconElement = getIconElement();
 | 
			
		||||
                        expect(iconElement.hasClass('iconClass-checked')).toBe(true);
 | 
			
		||||
                    });
 | 
			
		||||
                    it("uses custom interval", function () {
 | 
			
		||||
                        expect(mockHttpRequestFunction.calls.length).toEqual(1);
 | 
			
		||||
                        jasmine.Clock.tick(1);
 | 
			
		||||
                        expect(mockHttpRequestFunction.calls.length).toEqual(1);
 | 
			
		||||
                        mockInterval(options.interval + 1);
 | 
			
		||||
                        expect(mockHttpRequestFunction.calls.length).toEqual(2);
 | 
			
		||||
                    });
 | 
			
		||||
                    it("uses custom label if supplied in initialization", function () {
 | 
			
		||||
                        var textElement = getTextElement();
 | 
			
		||||
                        expect(textElement.text().indexOf(options.label) >= 0).toBe(true);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("changes when the database connection is nominal", function () {
 | 
			
		||||
                var initialText = indicatorWrapper.getText(),
 | 
			
		||||
                    initialDescrption = indicatorWrapper.getDescription(),
 | 
			
		||||
                    initialGlyphClass = indicatorWrapper.getGlyphClass();
 | 
			
		||||
            describe("when running", function () {
 | 
			
		||||
                beforeEach(function () {
 | 
			
		||||
                    options = {
 | 
			
		||||
                        url: "someURL",
 | 
			
		||||
                        interval: 100
 | 
			
		||||
                    };
 | 
			
		||||
                    urlIndicator = URLIndicatorPlugin(options)(openmct);
 | 
			
		||||
                    indicatorElement = openmct.indicators.add.mostRecentCall.args[0].element;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Nominal just means getting back an object, without
 | 
			
		||||
                // an error field.
 | 
			
		||||
                mockPromise.then.mostRecentCall.args[0]({ data: {} });
 | 
			
		||||
                it("requests the provided URL", function () {
 | 
			
		||||
                    mockInterval(options.interval + 1);
 | 
			
		||||
                    expect(mockHttpRequestFunction).toHaveBeenCalledWith(options.url);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Verify that these values changed;
 | 
			
		||||
                // don't test for specific text.
 | 
			
		||||
                expect(indicatorWrapper.getText()).not.toEqual(initialText);
 | 
			
		||||
                expect(indicatorWrapper.getGlyphClass()).not.toEqual(initialGlyphClass);
 | 
			
		||||
                expect(indicatorWrapper.getDescription()).not.toEqual(initialDescrption);
 | 
			
		||||
                it("indicates success if connection is nominal", function () {
 | 
			
		||||
                    mockSuccess();
 | 
			
		||||
                    mockInterval(options.interval + 1);
 | 
			
		||||
 | 
			
		||||
                // Do check for specific class
 | 
			
		||||
                expect(indicatorWrapper.getGlyphClass()).toEqual("ok");
 | 
			
		||||
                    waitsFor(httpRequestReturned);
 | 
			
		||||
                    runs(function () {
 | 
			
		||||
                        var iconElement = getIconElement();
 | 
			
		||||
                        expect(iconElement.hasClass('s-status-ok')).toBe(true);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it("indicates an error when the server cannot be reached", function () {
 | 
			
		||||
                    mockError();
 | 
			
		||||
                    mockInterval(options.interval + 1);
 | 
			
		||||
 | 
			
		||||
                    waitsFor(httpRequestReturned);
 | 
			
		||||
                    runs(function () {
 | 
			
		||||
                        var iconElement = getIconElement();
 | 
			
		||||
                        expect(iconElement.hasClass('s-status-warning-hi')).toBe(true);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("changes when the server cannot be reached", function () {
 | 
			
		||||
                var initialText = indicatorWrapper.getText(),
 | 
			
		||||
                    initialDescrption = indicatorWrapper.getDescription(),
 | 
			
		||||
                    initialGlyphClass = indicatorWrapper.getGlyphClass();
 | 
			
		||||
            function mockHttpRequest() {
 | 
			
		||||
                mockHttpRequestFunction = jasmine.createSpy('get');
 | 
			
		||||
                URLIndicator.prototype.get = mockHttpRequestFunction;
 | 
			
		||||
                mockSuccess();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
                // Nominal just means getting back an object, without
 | 
			
		||||
                // an error field.
 | 
			
		||||
                mockPromise.then.mostRecentCall.args[1]({ data: {} });
 | 
			
		||||
            function mockSuccess() {
 | 
			
		||||
                mockHttpRequestFunction
 | 
			
		||||
                    .andReturn(Promise.resolve().then(function () {
 | 
			
		||||
                        returned = true;
 | 
			
		||||
                    }));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
                // Verify that these values changed;
 | 
			
		||||
                // don't test for specific text.
 | 
			
		||||
                expect(indicatorWrapper.getText()).not.toEqual(initialText);
 | 
			
		||||
                expect(indicatorWrapper.getGlyphClass()).not.toEqual(initialGlyphClass);
 | 
			
		||||
                expect(indicatorWrapper.getDescription()).not.toEqual(initialDescrption);
 | 
			
		||||
            function mockError() {
 | 
			
		||||
                mockHttpRequestFunction
 | 
			
		||||
                    .andReturn(Promise.reject().then(function () {
 | 
			
		||||
                        returned = true;
 | 
			
		||||
                        //Throw error to ensure chained catch is invoked
 | 
			
		||||
                        throw undefined;
 | 
			
		||||
                    }));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
                // Do check for specific class
 | 
			
		||||
                expect(indicatorWrapper.getGlyphClass()).toEqual("err");
 | 
			
		||||
            });
 | 
			
		||||
            it("has a customized cssClass if supplied in initialization", function () {
 | 
			
		||||
                opts = {
 | 
			
		||||
                    url: "http://localhost:8080",
 | 
			
		||||
                    cssClass: "cssClass-checked",
 | 
			
		||||
                    interval: 10000
 | 
			
		||||
                };
 | 
			
		||||
                indicatorWrapper = new Indicator();
 | 
			
		||||
                expect(indicatorWrapper.getCssClass()).toEqual("cssClass-checked");
 | 
			
		||||
            });
 | 
			
		||||
            it("has a customized interval if supplied in initialization", function () {
 | 
			
		||||
                opts = {
 | 
			
		||||
                    url: "http://localhost:8080",
 | 
			
		||||
                    interval: 1814
 | 
			
		||||
                };
 | 
			
		||||
                indicatorWrapper = new Indicator();
 | 
			
		||||
                expect(mockInterval).toHaveBeenCalledWith(
 | 
			
		||||
                    jasmine.any(Function),
 | 
			
		||||
                    1814,
 | 
			
		||||
                    0,
 | 
			
		||||
                    false
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it("has a custom label if supplied in initialization", function () {
 | 
			
		||||
                opts = {
 | 
			
		||||
                    url: "http://localhost:8080",
 | 
			
		||||
                    label: "Localhost"
 | 
			
		||||
                };
 | 
			
		||||
                indicatorWrapper = new Indicator();
 | 
			
		||||
                expect(indicatorWrapper.getText()).toEqual("Checking status of Localhost please stand by...");
 | 
			
		||||
            });
 | 
			
		||||
            it("has a default label if not supplied in initialization", function () {
 | 
			
		||||
                opts = {
 | 
			
		||||
                    url: "http://localhost:8080"
 | 
			
		||||
                };
 | 
			
		||||
                indicatorWrapper = new Indicator();
 | 
			
		||||
                expect(indicatorWrapper.getText()).toEqual(
 | 
			
		||||
                  "Checking status of http://localhost:8080 please stand by..."
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it("has a default interval if not supplied in initialization", function () {
 | 
			
		||||
                opts = {
 | 
			
		||||
                    url: "http://localhost:8080"
 | 
			
		||||
                };
 | 
			
		||||
                indicatorWrapper = new Indicator();
 | 
			
		||||
                expect(mockInterval).toHaveBeenCalledWith(
 | 
			
		||||
                    jasmine.any(Function),
 | 
			
		||||
                    10000,
 | 
			
		||||
                    0,
 | 
			
		||||
                    false
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            function httpRequestReturned() {
 | 
			
		||||
                return returned;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function mockInterval(interval) {
 | 
			
		||||
                jasmine.Clock.tick(interval);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function getIconElement() {
 | 
			
		||||
                return $('.indicator-icon', indicatorElement);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function getTextElement() {
 | 
			
		||||
                return $('.indicator-text', indicatorElement);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
@@ -128,7 +128,7 @@ define([
 | 
			
		||||
    plugins.ExampleImagery = ExampleImagery;
 | 
			
		||||
    plugins.SummaryWidget = SummaryWidget;
 | 
			
		||||
    plugins.TelemetryMean = TelemetryMean;
 | 
			
		||||
    plugins.URLIndicatorPlugin = URLIndicatorPlugin;
 | 
			
		||||
    plugins.URLIndicator = URLIndicatorPlugin;
 | 
			
		||||
 | 
			
		||||
    return plugins;
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user