mirror of
https://github.com/nasa/openmct.git
synced 2025-04-09 04:14:32 +00:00
Merge remote-tracking branch 'origin/open608' into open-master
This commit is contained in:
commit
51376fb38a
@ -11,6 +11,10 @@
|
||||
{
|
||||
"key": "action-button",
|
||||
"templateUrl": "templates/controls/action-button.html"
|
||||
},
|
||||
{
|
||||
"key": "indicator",
|
||||
"templateUrl": "templates/indicator.html"
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
@ -42,6 +46,11 @@
|
||||
"key": "ViewSwitcherController",
|
||||
"implementation": "ViewSwitcherController.js",
|
||||
"depends": [ "$scope" ]
|
||||
},
|
||||
{
|
||||
"key": "BottomBarController",
|
||||
"implementation": "BottomBarController.js",
|
||||
"depends": [ "indicators[]" ]
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
|
@ -1,13 +1,9 @@
|
||||
<div class='abs bottom-bar ue-bottom-bar'>
|
||||
<div class='abs bottom-bar ue-bottom-bar' ng-controller="BottomBarController as bar">
|
||||
<div id='status' class='status-holder abs'>
|
||||
<div id='status_data_flow' class='status block data-flow'>
|
||||
<span class='ui-symbol status-indicator ok'>.</span>
|
||||
<span class='label'>Connected</span>
|
||||
</div>
|
||||
<!--div id='status_data_connection' class='status block data-connection'>
|
||||
<span class='ui-symbol status-indicator caution'>D</span>
|
||||
<span class='label'>Connected CPU 0.1% / Mem 1.9%</span>
|
||||
</div-->
|
||||
<mct-include ng-repeat="indicator in bar.getIndicators()"
|
||||
ng-model="indicator.ngModel"
|
||||
key="indicator.template">
|
||||
</mct-include>
|
||||
</div>
|
||||
<!--mct-include key="'app-logo'"></mct-include-->
|
||||
</div>
|
18
platform/commonUI/general/res/templates/indicator.html
Normal file
18
platform/commonUI/general/res/templates/indicator.html
Normal file
@ -0,0 +1,18 @@
|
||||
<div class='status block'
|
||||
title="{{ngModel.getDescription()}}"
|
||||
ng-click='ngModel.configure()'
|
||||
ng-class='ngModel.getClass()'>
|
||||
<span class="ui-symbol status-indicator"
|
||||
ng-class='ngModel.getGlyphClass()'>
|
||||
{{ngModel.getGlyph()}}
|
||||
</span>
|
||||
<span class="label"
|
||||
ng-class='ngModel.getTextClass()'>
|
||||
{{ngModel.getText()}}
|
||||
</span>
|
||||
<a href=''
|
||||
class="ui-symbol"
|
||||
ng-if="ngModel.configure">
|
||||
G
|
||||
</a>
|
||||
</div>
|
40
platform/commonUI/general/src/BottomBarController.js
Normal file
40
platform/commonUI/general/src/BottomBarController.js
Normal file
@ -0,0 +1,40 @@
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Controller for the bottombar template. Exposes
|
||||
* available indicators (of extension category "indicators")
|
||||
* @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
|
||||
};
|
||||
}
|
||||
|
||||
indicators = indicators.map(present);
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get all indicators to display.
|
||||
* @returns {Indicator[]} all indicators
|
||||
* to display in the bottom bar.
|
||||
*/
|
||||
getIndicators: function () {
|
||||
return indicators;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return BottomBarController;
|
||||
}
|
||||
);
|
55
platform/commonUI/general/test/BottomBarControllerSpec.js
Normal file
55
platform/commonUI/general/test/BottomBarControllerSpec.js
Normal file
@ -0,0 +1,55 @@
|
||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
define(
|
||||
["../src/BottomBarController"],
|
||||
function (BottomBarController) {
|
||||
"use strict";
|
||||
|
||||
describe("The bottom bar controller", function () {
|
||||
var testIndicators,
|
||||
testIndicatorA,
|
||||
testIndicatorB,
|
||||
testIndicatorC,
|
||||
mockIndicator,
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockIndicator = jasmine.createSpyObj(
|
||||
"indicator",
|
||||
[ "getGlyph", "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,5 +1,6 @@
|
||||
[
|
||||
"ActionGroupController",
|
||||
"BottomBarController",
|
||||
"ClickAwayController",
|
||||
"ContextMenuController",
|
||||
"MCTContainer",
|
||||
|
@ -18,6 +18,21 @@
|
||||
{
|
||||
"key": "COUCHDB_PATH",
|
||||
"value": "/couch/openmct"
|
||||
},
|
||||
{
|
||||
"key": "COUCHDB_INDICATOR_INTERVAL",
|
||||
"value": 15000
|
||||
}
|
||||
],
|
||||
"indicators": [
|
||||
{
|
||||
"implementation": "CouchIndicator.js",
|
||||
"depends": [
|
||||
"$http",
|
||||
"$interval",
|
||||
"COUCHDB_PATH",
|
||||
"COUCHDB_INDICATOR_INTERVAL"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
103
platform/persistence/src/CouchIndicator.js
Normal file
103
platform/persistence/src/CouchIndicator.js
Normal file
@ -0,0 +1,103 @@
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
// Set of connection states; changing among these states will be
|
||||
// reflected in the indicator's appearance.
|
||||
// CONNECTED: Everything nominal, expect to be able to read/write.
|
||||
// DISCONNECTED: HTTP failed; maybe misconfigured, disconnected.
|
||||
// SEMICONNECTED: Connected to the database, but it reported an error.
|
||||
// PENDING: Still trying to connect, and haven't failed yet.
|
||||
var CONNECTED = {
|
||||
text: "Connected",
|
||||
glyphClass: "ok",
|
||||
description: "Connected to the domain object database."
|
||||
},
|
||||
DISCONNECTED = {
|
||||
text: "Disconnected",
|
||||
glyphClass: "err",
|
||||
description: "Unable to connect to the domain object database."
|
||||
},
|
||||
SEMICONNECTED = {
|
||||
text: "Unavailable",
|
||||
glyphClass: "caution",
|
||||
description: "Database does not exist or is unavailable."
|
||||
},
|
||||
PENDING = {
|
||||
text: "Checking connection..."
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicator for the current CouchDB connection. Polls CouchDB
|
||||
* at a regular interval (defined by bundle constants) to ensure
|
||||
* that the database is available.
|
||||
*/
|
||||
function CouchIndicator($http, $interval, PATH, INTERVAL) {
|
||||
// Track the current connection state
|
||||
var state = PENDING;
|
||||
|
||||
// Callback if the HTTP request to Couch fails
|
||||
function handleError(err) {
|
||||
state = DISCONNECTED;
|
||||
}
|
||||
|
||||
// Callback if the HTTP request succeeds. CouchDB may
|
||||
// report an error, so check for that.
|
||||
function handleResponse(response) {
|
||||
var data = response.data;
|
||||
state = data.error ? SEMICONNECTED : CONNECTED;
|
||||
}
|
||||
|
||||
// Try to connect to CouchDB, and update the indicator.
|
||||
function updateIndicator() {
|
||||
$http.get(PATH).then(handleResponse, handleError);
|
||||
}
|
||||
|
||||
// Update the indicator initially, and start polling.
|
||||
updateIndicator();
|
||||
$interval(updateIndicator, INTERVAL);
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get the glyph (single character used as an icon)
|
||||
* to display in this indicator. This will return "D",
|
||||
* which should appear as a database icon.
|
||||
* @returns {string} the character of the database icon
|
||||
*/
|
||||
getGlyph: function () {
|
||||
return "D";
|
||||
},
|
||||
/**
|
||||
* Get the name of the CSS class to apply to the glyph.
|
||||
* This is used to color the glyph to match its
|
||||
* state (one of ok, caution or err)
|
||||
* @returns {string} the CSS class to apply to this glyph
|
||||
*/
|
||||
getGlyphClass: function () {
|
||||
return state.glyphClass;
|
||||
},
|
||||
/**
|
||||
* Get the text that should appear in the indicator.
|
||||
* @returns {string} brief summary of connection status
|
||||
*/
|
||||
getText: function () {
|
||||
return state.text;
|
||||
},
|
||||
/**
|
||||
* Get a longer-form description of the current connection
|
||||
* space, suitable for display in a tooltip
|
||||
* @returns {string} longer summary of connection status
|
||||
*/
|
||||
getDescription: function () {
|
||||
return state.description;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
return CouchIndicator;
|
||||
}
|
||||
);
|
111
platform/persistence/test/CouchIndicatorSpec.js
Normal file
111
platform/persistence/test/CouchIndicatorSpec.js
Normal file
@ -0,0 +1,111 @@
|
||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
define(
|
||||
["../src/CouchIndicator"],
|
||||
function (CouchIndicator) {
|
||||
"use strict";
|
||||
|
||||
describe("The CouchDB status indicator", function () {
|
||||
var mockHttp,
|
||||
mockInterval,
|
||||
testPath,
|
||||
testInterval,
|
||||
mockPromise,
|
||||
indicator;
|
||||
|
||||
beforeEach(function () {
|
||||
mockHttp = jasmine.createSpyObj("$http", [ "get" ]);
|
||||
mockInterval = jasmine.createSpy("$interval");
|
||||
mockPromise = jasmine.createSpyObj("promise", [ "then" ]);
|
||||
testPath = "/test/path";
|
||||
testInterval = 12321; // Some number
|
||||
|
||||
mockHttp.get.andReturn(mockPromise);
|
||||
|
||||
indicator = new CouchIndicator(
|
||||
mockHttp,
|
||||
mockInterval,
|
||||
testPath,
|
||||
testInterval
|
||||
);
|
||||
});
|
||||
|
||||
it("polls for changes", function () {
|
||||
expect(mockInterval).toHaveBeenCalledWith(
|
||||
jasmine.any(Function),
|
||||
testInterval
|
||||
);
|
||||
});
|
||||
|
||||
it("has a database icon", function () {
|
||||
expect(indicator.getGlyph()).toEqual("D");
|
||||
});
|
||||
|
||||
it("consults the database at the configured path", function () {
|
||||
expect(mockHttp.get).toHaveBeenCalledWith(testPath);
|
||||
});
|
||||
|
||||
it("changes when the database connection is nominal", function () {
|
||||
var initialText = indicator.getText(),
|
||||
initialDescrption = indicator.getDescription(),
|
||||
initialGlyphClass = indicator.getGlyphClass();
|
||||
|
||||
// Nominal just means getting back an objeect, without
|
||||
// an error field.
|
||||
mockPromise.then.mostRecentCall.args[0]({ data: {} });
|
||||
|
||||
// Verify that these values changed;
|
||||
// don't test for specific text.
|
||||
expect(indicator.getText()).not.toEqual(initialText);
|
||||
expect(indicator.getGlyphClass()).not.toEqual(initialGlyphClass);
|
||||
expect(indicator.getDescription()).not.toEqual(initialDescrption);
|
||||
|
||||
// Do check for specific class
|
||||
expect(indicator.getGlyphClass()).toEqual("ok");
|
||||
});
|
||||
|
||||
it("changes when the server reports an error", function () {
|
||||
var initialText = indicator.getText(),
|
||||
initialDescrption = indicator.getDescription(),
|
||||
initialGlyphClass = indicator.getGlyphClass();
|
||||
|
||||
// Nominal just means getting back an objeect, with
|
||||
// an error field.
|
||||
mockPromise.then.mostRecentCall.args[0](
|
||||
{ data: { error: "Uh oh." } }
|
||||
);
|
||||
|
||||
// Verify that these values changed;
|
||||
// don't test for specific text.
|
||||
expect(indicator.getText()).not.toEqual(initialText);
|
||||
expect(indicator.getGlyphClass()).not.toEqual(initialGlyphClass);
|
||||
expect(indicator.getDescription()).not.toEqual(initialDescrption);
|
||||
|
||||
// Do check for specific class
|
||||
expect(indicator.getGlyphClass()).toEqual("caution");
|
||||
|
||||
});
|
||||
|
||||
it("changes when the server cannot be reached", function () {
|
||||
var initialText = indicator.getText(),
|
||||
initialDescrption = indicator.getDescription(),
|
||||
initialGlyphClass = indicator.getGlyphClass();
|
||||
|
||||
// Nominal just means getting back an objeect, without
|
||||
// an error field.
|
||||
mockPromise.then.mostRecentCall.args[1]({ data: {} });
|
||||
|
||||
// Verify that these values changed;
|
||||
// don't test for specific text.
|
||||
expect(indicator.getText()).not.toEqual(initialText);
|
||||
expect(indicator.getGlyphClass()).not.toEqual(initialGlyphClass);
|
||||
expect(indicator.getDescription()).not.toEqual(initialDescrption);
|
||||
|
||||
// Do check for specific class
|
||||
expect(indicator.getGlyphClass()).toEqual("err");
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
);
|
@ -1,4 +1,5 @@
|
||||
[
|
||||
"CouchDocument",
|
||||
"CouchIndicator",
|
||||
"CouchPersistenceProvider"
|
||||
]
|
Loading…
x
Reference in New Issue
Block a user