Compare commits

..

1 Commits

Author SHA1 Message Date
Deep Tailor
3f8b4be7bd create a save-as-and-keep-editing action, and register with bundle 2018-07-02 13:48:37 -07:00
229 changed files with 16069 additions and 2631 deletions

View File

@@ -1,40 +0,0 @@
version: 2
jobs:
build:
docker:
- image: circleci/node:8-browsers
environment:
CHROME_BIN: "/usr/bin/google-chrome"
steps:
- checkout
- run:
name: Update npm
command: 'sudo npm install -g npm@latest'
- restore_cache:
key: dependency-cache-{{ checksum "package.json" }}-{{ checksum "bower.json" }}
- run:
name: Installing dependencies (npm install)
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package.json" }}-{{ checksum "bower.json" }}
paths:
- node_modules
- bower_components
- run:
name: npm run test
command: npm run test
- run:
name: npm run lint
command: npm run lint
- run:
name: npm run checkstyle
command: npm run checkstyle
- store_artifacts:
path: dist
prefix: dist
workflows:
version: 2
test:
jobs:
- build

88
API.md
View File

@@ -37,7 +37,7 @@
- [Time Systems and Bounds](#time-systems-and-bounds)
- [Defining and Registering Time Systems](#defining-and-registering-time-systems)
- [Getting and Setting the Active Time System](#getting-and-setting-the-active-time-system)
- [Time Bounds](#time-bounds)
- [Time Bounds](#time-bounds)
- [Clocks](#clocks)
- [Defining and registering clocks](#defining-and-registering-clocks)
- [Getting and setting active clock](#getting-and-setting-active-clock)
@@ -48,10 +48,6 @@
- [The Time Conductor](#the-time-conductor)
- [Time Conductor Configuration](#time-conductor-configuration)
- [Example conductor configuration](#example-conductor-configuration)
- [Indicators](#indicators)
- [The URL Status Indicator](#the-url-status-indicator)
- [Creating a Simple Indicator](#creating-a-simple-indicator)
- [Custom Indicators](#custom-indicators)
- [Included Plugins](#included-plugins)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@@ -692,7 +688,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.
@@ -981,72 +977,6 @@ 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.
Typically an indicator will display an icon (customizable with a CSS class) that will
reveal additional information when the mouse cursor is hovered over it.
### 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 Simple Indicator
A simple indicator with an icon and some text can be created and added with minimal code. An indicator
of this type exposes functions for customizing the text, icon, and style of the indicator.
eg.
``` javascript
var myIndicator = openmct.indicators.simpleIndicator();
myIndicator.text("Hello World!");
openmct.indicators.add(myIndicator);
```
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 simple providing a DOM element to place alongside other indicators.
``` javascript
var domNode = document.createElement('div');
domNode.innerText = new Date().toString();
setInterval(function () {
domNode.innerText = new Date().toString();
}, 1000);
openmct.indicators.add({
element: domNode
});
```
## Included Plugins
Open MCT is packaged along with a few general-purpose plugins:
@@ -1070,18 +1000,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.URLIndicator` adds an indicator which shows the
* `openmct.plugins.URLIndicatorPlugin` adds an indicator which shows the
availability of a URL with the following options:
- `url` : URL to indicate the status of
- `iconClass`: Icon to show in the status bar, defaults to `icon-database`, [list of all icons](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home?view=items)
- `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)
- `interval`: Interval between checking the connection, defaults to `10000`
- `label` Name showing up as text in the status bar, defaults to url
```javascript
openmct.install(openmct.plugins.URLIndicator({
url: 'http://localhost:8080',
iconClass: 'check',
interval: 10000,
label: 'Localhost'
openmct.install(openmct.plugins.URLIndicatorPlugin({
url: 'http://google.com',
cssClass: 'check',
interval: 10000,
label: 'Google'
})
);
```

27
circle.yml Normal file
View File

@@ -0,0 +1,27 @@
machine:
node:
version: 8.11.0
dependencies:
pre:
- npm install -g npm@latest
deployment:
production:
branch: master
commands:
- npm install canvas nomnoml
- ./build-docs.sh
openmctweb-staging-deux:
branch: mobile
heroku:
appname: openmctweb-staging-deux
test:
post:
- gulp lint
- gulp checkstyle
general:
branches:
ignore:
- gh-pages

View File

@@ -60,8 +60,8 @@ define([
"source": "eventGenerator",
"domains": [
{
"key": "utc",
"name": "Timestamp",
"key": "time",
"name": "Time",
"format": "utc"
}
],

View File

@@ -72,7 +72,7 @@ define([
var data = [];
while (start <= end && data.length < 5000) {
data.push(pointForTimestamp(start, duration, domainObject.name));
start += duration;
start += 5000;
}
return Promise.resolve(data);
};

View File

@@ -38,8 +38,7 @@ define([
"provides": "identityService",
"type": "provider",
"depends": [
"dialogService",
"$q"
"dialogService"
]
}
]

View File

@@ -55,37 +55,21 @@ define(
* @implements {IdentityService}
* @memberof platform/identity
*/
function ExampleIdentityProvider(dialogService, $q) {
this.dialogService = dialogService;
this.$q = $q;
function ExampleIdentityProvider(dialogService) {
// Handle rejected dialog messages by treating the
// current user as undefined.
function echo(v) { return v; }
function giveUndefined() { return undefined; }
this.returnUser = this.returnUser.bind(this);
this.returnUndefined = this.returnUndefined.bind(this);
this.userPromise =
dialogService.getUserInput(DIALOG_STRUCTURE, DEFAULT_IDENTITY)
.then(echo, giveUndefined);
}
ExampleIdentityProvider.prototype.getUser = function () {
if (this.user) {
return this.$q.when(this.user);
} else {
return this.dialogService.getUserInput(DIALOG_STRUCTURE, DEFAULT_IDENTITY)
.then(this.returnUser, this.returnUndefined);
}
return this.userPromise;
};
/**
* @private
*/
ExampleIdentityProvider.prototype.returnUser = function (user) {
return this.user = user;
}
/**
* @private
*/
ExampleIdentityProvider.prototype.returnUndefined = function () {
return undefined;
}
return ExampleIdentityProvider;
}
);

View File

@@ -1,9 +1,9 @@
<span class="h-indicator" ng-controller="DialogLaunchController">
<span class="status block" ng-controller="DialogLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div class="ls-indicator icon-box-with-arrow s-status-available"><span class="label">
<a ng-click="launchProgress(true)">Known</a>
<a ng-click="launchProgress(false)">Unknown</a>
<a ng-click="launchError()">Error</a>
<span class="status-indicator icon-box-with-arrow"></span><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></div>
</span><span class="count"></span>
</span>

View File

@@ -1,9 +1,9 @@
<span class="h-indicator" ng-controller="NotificationLaunchController">
<span class="status block" ng-controller="NotificationLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div class="ls-indicator icon-bell s-status-available"><span class="label">
<a ng-click="newInfo()">Success</a>
<a ng-click="newError()">Error</a>
<a ng-click="newAlert()">Alert</a>
<span class="status-indicator icon-bell"></span><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></div>
</span><span class="count"></span>
</span>

View File

@@ -58,10 +58,7 @@
position: relative;
}
.w-mct-example {
color: #ccc;
> div { margin-bottom: $interiorMarginLg; }
}
.w-mct-example > div { margin-bottom: $interiorMarginLg; }
code,
pre {

View File

@@ -20,12 +20,12 @@
at runtime from the About dialog for additional information.
-->
<style>
.w-mct-example div[class*="s-status"],
.w-mct-example span[class*="s-status"],
.w-mct-example div[class*="s-limit"],
.w-mct-example div[class*="s-status"],
.w-mct-example div[class*="s-unsynced"],
.w-mct-example span[class*="s-limit"] {
border-radius: 3px;
padding: 2px 5px;
border-radius: 4px;
padding: 3px 7px;
}
.w-mct-example table {
width: 100%;
@@ -36,12 +36,65 @@
<h1>Status Indication</h1>
<div class="l-section">
<h2>Status Classes</h2>
<h2>Overview</h2>
<p>Many elements in Open MCT need to articulate a dynamic status; Open MCT provides the following styles and conventions to handle this:</p>
<ul>
<li><strong>Limits</strong>: when telemetry values exceed minimum or maximum values, they can be violating limits. Limit styles include both color and iconography; color is used to indicate severity while icons are used to indicate direction, upper or lower.</li>
<li><strong>Status</strong>: Open MCT also provides a number or built-in Status styles allowing telemetry or other displayed information to be visually classified by type. Common uses for these classes are to visually denote event records.</li>
<li><strong>Synchronization</strong>: When the system is displaying real-time data, it is very important that displays clearly indicate when they are not doing so, such as when a plot if frozen while panning or zooming. Open MCT provides a style for this.</li>
</ul>
</div>
<div class="l-section">
<h2>Limits</h2>
<div class="cols cols1-1">
<div class="col">
<p>Status classes allow any block or inline-block element to be decorated in order to articulate a
status. Provided classes include color-only and color plus icon; custom icons can easily be
employed by using a color-only status class in combination with an <a class="link" href="#/browse/styleguide:home/glyphs?tc.mode=local&tc.timeSystem=utc&tc.startDelta=1800000&tc.endDelta=0&view=styleguide.glyphs">glyph</a>.</p>
<p>Limit CSS classes can be applied to any block or inline element. Open MCT limit classes set color and optionally an icon, but don't effect other properties. Yellow and red limit classes can be used as is, or allow the application of any custom icon available in Open MCT's glyphs library. &quot;Level&quot; limit classes - upper and lower - always use an icon in addition to a color; Open MCT doesn't support level limits without color.</p>
<ul>
<li>Color only</li>
<ul>
<li><code>s-limit-yellow</code>: A yellow limit.</li>
<li><code>s-limit-red</code>: A red limit.</li>
</ul>
<li>Color and icon</li>
<ul>
<li><code>s-limit-yellow-icon</code>: A yellow limit with icon.</li>
<li><code>s-limit-red-icon</code>: A red limit with icon.</li>
</ul>
<li>Upper and lower limit indicators. Must be used with a color limit class to be visible.</li>
<ul>
<li><code>s-limit-upr</code>: Upper limit.
</li>
<li><code>s-limit-lwr</code>: Lower limit.
</li>
</ul>
</ul>
</div>
<mct-example><div class="s-limit-yellow">Yellow limit</div>
<div class="s-limit-red">Red limit</div>
<div class="s-limit-yellow-icon">Yellow limit with icon</div>
<div class="s-limit-red-icon">Red limit with icon</div>
<div class="s-limit-yellow s-limit-lwr">Lower yellow limit</div>
<div class="s-limit-red s-limit-upr">Upper red limit</div>
<div class="s-limit-red icon-bell">Red Limit with a custom icon</div>
<div>Some text with an <span class="s-limit-yellow-icon">inline element</span> showing a yellow limit.</div>
<!-- Limits applied in a table -->
<table>
<tr class='header'><td>Name</td><td>Value 1</td><td>Value 2</td></tr>
<tr><td>ENG_PWR 4991</td><td>7.023</td><td class="s-limit-yellow s-limit-upr">70.23</td></tr>
<tr><td>ENG_PWR 4992</td><td>49.784</td><td class="s-limit-red s-limit-lwr">-121.22</td></tr>
<tr><td>ENG_PWR 4993</td><td class="s-limit-yellow icon-bell">0.451</td><td>1.007</td></tr>
</table>
</mct-example>
</div>
</div>
<div class="l-section">
<h2>Status</h2>
<div class="cols cols1-1">
<div class="col">
<p>Classes here can be applied to elements as needed.</p>
<ul>
<li>Color only</li>
<ul>
@@ -53,175 +106,37 @@
</ul>
<li>Color and icon</li>
<ul>
<li><code>s-status-icon-warning-hi</code></li>
<li><code>s-status-icon-warning-lo</code></li>
<li><code>s-status-icon-diagnostic</code></li>
<li><code>s-status-icon-info</code></li>
<li><code>s-status-icon-ok</code></li>
<li><code>s-status-warning-hi-icon</code></li>
<li><code>s-status-warning-lo-icon</code></li>
<li><code>s-status-diagnostic-icon</code></li>
<li><code>s-status-info-icon</code></li>
<li><code>s-status-ok-icon</code></li>
</ul>
</ul>
</div>
<mct-example><!-- Color alone examples -->
<div class="s-status-warning-hi">WARNING HI</div>
<mct-example><div class="s-status-warning-hi">WARNING HI</div>
<div class="s-status-warning-lo">WARNING LOW</div>
<div class="s-status-diagnostic">DIAGNOSTIC</div>
<div class="s-status-info">INFO</div>
<div class="s-status-ok">OK</div>
<!-- Color and icon examples -->
<div class="s-status-icon-warning-hi">WARNING HI with icon</div>
<div class="s-status-icon-warning-lo">WARNING LOW with icon</div>
<div class="s-status-icon-diagnostic">DIAGNOSTIC with icon</div>
<div class="s-status-icon-info">INFO with icon</div>
<div class="s-status-icon-ok">OK with icon</div>
<div class="s-status-warning-hi icon-alert-triangle">WARNING HI with custom icon</div>
<div>Some text with an <span class="s-status-icon-diagnostic">inline element</span> showing a Diagnostic status.</div>
<div class="s-status-warning-hi-icon">WARNING HI with icon</div>
<div class="s-status-warning-lo-icon">WARNING LOW with icon</div>
<div class="s-status-diagnostic-icon">DIAGNOSTIC with icon</div>
<div class="s-status-info-icon">INFO with icon</div>
<div class="s-status-ok-icon">OK with icon</div>
<div class="s-status-warning-hi icon-gear">WARNING HI with custom icon</div>
</mct-example>
</div>
</div>
<div class="l-section">
<h2>Limit Classes</h2>
<h2>Synchronization</h2>
<div class="cols cols1-1">
<div class="col">
<p>Limit classes are a specialized form of status, specifically meant to be applied to telemetry
displays to indicate that a limit threshold has been violated. Open MCT provides both severity
and direction classes; severity (yellow and red) can be used alone or in combination
with direction (upper or lower). Direction classes cannot be used on their own.</p>
<p>Like Status classes, Limits can be used as color-only, or color plus icon. Custom icons can
be applied in the same fashion as described above.</p>
<ul>
<li>Severity color alone</li>
<ul>
<li><code>s-limit-yellow</code>: A yellow limit.</li>
<li><code>s-limit-red</code>: A red limit.</li>
</ul>
<li>Severity color and icon</li>
<ul>
<li><code>s-limit-icon-yellow</code>: A yellow limit with icon.</li>
<li><code>s-limit-icon-red</code>: A red limit with icon.</li>
</ul>
<li>Direction indicators. MUST be used with a &quot;color alone&quot; limit class. See
examples for more.</li>
<ul>
<li><code>s-limit-upr</code>: Upper limit.</li>
<li><code>s-limit-lwr</code>: Lower limit.</li>
</ul>
</ul>
<p>When the system is operating in real-time streaming mode, it is important for views that display real-time data to clearly articulate when they are not, such as when a user zooms or pans a plot view, freezing that view. In that case, the CSS class <code>s-unsynced</code> should be applied to that view.</p>
</div>
<mct-example><!-- Color alone examples -->
<div class="s-limit-yellow">Yellow limit</div>
<div class="s-limit-red">Red limit</div>
<!-- Color and icon examples -->
<div class="s-limit-icon-yellow">Yellow limit with icon</div>
<div class="s-limit-icon-red">Red limit with icon</div>
<div class="s-limit-red icon-alert-rect">Red Limit with a custom icon</div>
<div>Some text with an <span class="s-limit-icon-yellow">inline element</span> showing a yellow limit.</div>
<!-- Severity and direction examples -->
<div class="s-limit-yellow s-limit-lwr">Lower yellow limit</div>
<div class="s-limit-red s-limit-upr">Upper red limit</div>
<!-- Limits applied in a table -->
<table>
<tr class='header'><td>Name</td><td>Value 1</td><td>Value 2</td></tr>
<tr><td>ENG_PWR 4991</td><td>7.023</td><td class="s-limit-yellow s-limit-upr">70.23</td></tr>
<tr><td>ENG_PWR 4992</td><td>49.784</td><td class="s-limit-red s-limit-lwr">-121.22</td></tr>
<tr><td>ENG_PWR 4993</td><td class="s-limit-yellow icon-alert-triangle">0.451</td><td>1.007</td></tr>
</table>
<mct-example><div class="s-unsynced">This element is unsynced</div>
</mct-example>
</div>
</div>
<div class="l-section">
<h2>Status Bar Indicators</h2>
<div class="cols cols1-1">
<div class="col">
<p>Indicators are small iconic notification elements that appear in the Status Bar area of
the application at the window's bottom. Indicators should be used to articulate the state of a
system and optionally provide gestures related to that system. They use a combination of icon and
color to identify themselves and articulate a state respectively.</p>
<h3>Recommendations</h3>
<ul>
<li><strong>Keep the icon consistent</strong>. The icon is the principal identifier of the system and is a valuable
recall aid for the user. Don't change the icon as a system's state changes, use color and
text for that purpose.</li>
<li><strong>Don't use the same icon more than once</strong>. Select meaningful and distinct icons so the user
will be able to quickly identify what they're looking for.</li>
</ul>
<h3>States</h3>
<ul>
<li><strong>Disabled</strong>: The system is not available to the user.</li>
<li><strong>Off / Available</strong>: The system is accessible to the user but is not currently
&quot;On&quot; or has not been configured. If the Indicator directly provides gestures
related to the system, such as opening a configuration dialog box, then use
&quot;Available&quot;; if the user must act elsewhere or the system isn't user-controllable,
use &quot;Off&quot;.</li>
<li><strong>On</strong>: The system is enabled or configured; it is having an effect on the larger application.</li>
<li><strong>Alert / Error</strong>: There has been a problem with the system. Generally, &quot;Alert&quot;
should be used to call attention to an issue that isn't critical, while &quot;Error&quot;
should be used to call attention to a problem that the user should really be aware of or do
something about.</li>
</ul>
<h3>Structure</h3>
<p>Indicators consist of a <code>.ls-indicator</code>
wrapper element with <code>.icon-*</code> classes for the type of thing they represent and
<code>.s-status-*</code> classes to articulate the current state. Title attributes should be used
to provide more verbose information about the thing and/or its status.</p>
<p>The wrapper encloses a <code>.label</code> element that is displayed on hover. This element should
include a brief statement of the current status, and can also include clickable elements
as <code>&lt;a&gt;</code> tags. An optional <code>.count</code> element can be included to display
information such as a number of messages.</p>
<p>Icon classes are as defined on the
<a class="link" href="#/browse/styleguide:home/glyphs?tc.mode=local&tc.timeSystem=utc&tc.startDelta=1800000&tc.endDelta=0&view=styleguide.glyphs">
Glyphs page</a>. Status classes applicable to Indicators are as follows:</p>
<ul>
<li><code>s-status-disabled</code></li>
<li><code>s-status-off</code></li>
<li><code>s-status-available</code></li>
<li><code>s-status-on</code></li>
<li><code>s-status-alert</code></li>
<li><code>s-status-error</code></li>
</ul>
</div>
<mct-example><div class="s-ue-bottom-bar status-holder s-status-bar">
<span class="ls-indicator icon-database s-status-disabled" title="The system is currently disabled.">
<span class="label">System not enabled.</span>
</span>
</div>
<div class="s-ue-bottom-bar status-holder s-status-bar">
<span class="ls-indicator icon-database s-status-available" title="Configure data connection.">
<span class="label">Data connection available
<a class="icon-gear">Configure</a>
</span>
</span>
</div>
<div class="s-ue-bottom-bar status-holder s-status-bar">
<span class="ls-indicator icon-database s-status-on" title="Data connected.">
<span class="label">Connected to Skynet
<a class="icon-gear">Change</a>
<a>Disconnect</a>
</span>
</span>
</div>
<div class="s-ue-bottom-bar status-holder s-status-bar">
<span class="ls-indicator icon-database s-status-alert" title="System is self-aware.">
<span class="label">Skynet at Turing Level 5</span>
</span>
<span class="ls-indicator icon-bell s-status-error" title="You have alerts.">
<span class="label">
<a class="icon-alert-triangle">View Alerts</a>
</span>
<span class="count">495</span>
</span>
</div>
</mct-example>
</div>
</div>
</div>
</div>

View File

@@ -54,7 +54,7 @@ define(
return "icon-object-unknown";
},
getText: function () {
return "" + latest;
return latest;
},
getDescription: function () {
return "";

View File

@@ -73,7 +73,6 @@
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
openmct.time.timeSystem('utc');
openmct.start();
window.openmct = openmct;
});
</script>
<link rel="stylesheet" href="platform/commonUI/general/res/css/startup-base.css">

View File

@@ -59,8 +59,6 @@
"start": "node app.js",
"test": "karma start --single-run",
"jshint": "jshint platform example",
"lint": "./node_modules/gulp/bin/gulp.js lint",
"checkstyle": "./node_modules/gulp/bin/gulp.js checkstyle",
"watch": "karma start",
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",
"otherdoc": "node docs/gendocs.js --in docs/src --out dist/docs --suppress-toc 'docs/src/index.md|docs/src/process/index.md'",

View File

@@ -32,6 +32,7 @@ define([
"./src/actions/SaveAction",
"./src/actions/SaveAndStopEditingAction",
"./src/actions/SaveAsAction",
"./src/actions/SaveAsAndKeepEditingAction",
"./src/actions/CancelAction",
"./src/policies/EditActionPolicy",
"./src/policies/EditPersistableObjectsPolicy",
@@ -70,6 +71,7 @@ define([
SaveAction,
SaveAndStopEditingAction,
SaveAsAction,
SaveAsAndKeepEditingAction,
CancelAction,
EditActionPolicy,
EditPersistableObjectsPolicy,
@@ -188,8 +190,7 @@ define([
"name": "Remove",
"description": "Remove this object from its containing object.",
"depends": [
"navigationService",
"dialogService"
"navigationService"
]
},
{
@@ -232,6 +233,21 @@ define([
],
"priority": "mandatory"
},
{
"key": "save-as-edit",
"category": "save",
"implementation": SaveAsAndKeepEditingAction,
"name": "Save As And Continue Editing...",
"cssClass": "icon-save labeled",
"description": "Save changes made to these objects, without leaving edit mode.",
"depends": [
"$injector",
"policyService",
"dialogService",
"copyService",
"notificationService"
]
},
{
"key": "cancel",
"category": "conclude-editing",

View File

@@ -39,12 +39,9 @@ define(
* @constructor
* @implements {Action}
*/
function RemoveAction(navigationService, dialogService, context) {
function RemoveAction(navigationService, context) {
this.domainObject = (context || {}).domainObject;
this.navigationService = navigationService;
this.dialogService = dialogService;
this.delete = this.delete.bind(this);
}
/**
@@ -52,7 +49,7 @@ define(
* @return {Promise} a promise which will be
* fulfilled when the action has completed.
*/
RemoveAction.prototype.delete = function () {
RemoveAction.prototype.perform = function () {
var navigationService = this.navigationService,
domainObject = this.domainObject;
/*
@@ -117,28 +114,6 @@ define(
return removeFromContext(domainObject);
};
RemoveAction.prototype.perform = function () {
var self = this;
var confirmationDialog = this.dialogService.showBlockingMessage({
severity: "error",
title: "Warning! This action will permanently remove this object. Are you sure you want to continue?",
minimized: true, // want the notification to be minimized initially (don't show banner)
options: [{
label: "OK",
callback: function () {
self.delete().then(function () {
confirmationDialog.dismiss();
});
}
},{
label: "Cancel",
callback: function () {
confirmationDialog.dismiss();
}
}]
});
};
// Object needs to have a parent for Remove to be applicable
RemoveAction.appliesTo = function (context) {
var object = (context || {}).domainObject,

View File

@@ -0,0 +1,85 @@
/*****************************************************************************
* 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(
["./SaveAsAction"],
function (SaveAsAction) {
/**
* The "Save As and Keep Editing" action performs a [Save As And Keep Editing action]{@link SaveAsAndKeepEditingAction}
* on the object under edit and keeps user in edit mode.
* @constructor
* @implements {Action}
* @memberof platform/commonUI/edit
*/
function SaveAsAndKeepEditingAction(
$injector,
policyService,
dialogService,
copyService,
notificationService,
context
) {
this.$injector = $injector;
this.policyService = policyService;
this.dialogService = dialogService;
this.copyService = copyService;
this.notificationService = notificationService;
this.context = context;
this.domainObject = (context || {}).domainObject;
}
/**
* Trigger a save operation and go back to edit mode.
*
* @memberof platform/commonUI/edit.SaveAsAndKeepEditingAction#
*/
SaveAsAndKeepEditingAction.prototype.perform = function () {
var saveAsAction = new SaveAsAction(
this.$injector,
this.policyService,
this.dialogService,
this.copyService,
this.notificationService,
this.context
);
function openEditor(object) {
if (object) {
object.getCapability('action').perform('edit');
}
}
return saveAsAction.save().then(openEditor);
};
/**
* Check if this action is applicable in a given context.
* This will ensure that a domain object is present in the context,
* and that this domain object is in Edit mode.
* @returns true if applicable
*/
SaveAsAndKeepEditingAction.appliesTo = SaveAsAction.appliesTo;
return SaveAsAndKeepEditingAction;
}
);

View File

@@ -128,14 +128,14 @@ define(
});
it("mutates the parent when performed", function () {
action.delete();
action.perform();
expect(mockMutation.invoke)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("changes composition from its mutation function", function () {
var mutator, result;
action.delete();
action.perform();
mutator = mockMutation.invoke.calls.mostRecent().args[0];
result = mutator(model);
@@ -170,7 +170,7 @@ define(
mockType.hasFeature.and.returnValue(true);
action.delete();
action.perform();
// Expects navigation to parent of domainObject (removed object)
expect(mockNavigationService.setNavigation).toHaveBeenCalledWith(mockParent);
@@ -198,7 +198,7 @@ define(
mockType.hasFeature.and.returnValue(true);
action.delete();
action.perform();
// Expects no navigation to occur
expect(mockNavigationService.setNavigation).not.toHaveBeenCalled();

View File

@@ -34,6 +34,7 @@ define([
"./src/controllers/ContextMenuController",
"./src/controllers/ClickAwayController",
"./src/controllers/ViewSwitcherController",
"./src/controllers/BottomBarController",
"./src/controllers/GetterSetterController",
"./src/controllers/SelectorController",
"./src/controllers/ObjectInspectorController",
@@ -48,14 +49,13 @@ define([
"./src/directives/MCTSplitPane",
"./src/directives/MCTSplitter",
"./src/directives/MCTTree",
"./src/directives/MCTIndicators",
"./src/directives/MCTPreview",
"./src/actions/MCTPreviewAction",
"./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/angular-indicator.html",
"text!./res/templates/indicator.html",
"text!./res/templates/message-banner.html",
"text!./res/templates/progress-bar.html",
"text!./res/templates/controls/time-controller.html",
@@ -87,6 +87,7 @@ define([
ContextMenuController,
ClickAwayController,
ViewSwitcherController,
BottomBarController,
GetterSetterController,
SelectorController,
ObjectInspectorController,
@@ -101,7 +102,6 @@ define([
MCTSplitPane,
MCTSplitter,
MCTTree,
MCTIndicators,
MCTPreview,
MCTPreviewAction,
ReverseFilter,
@@ -281,6 +281,13 @@ define([
"$timeout"
]
},
{
"key": "BottomBarController",
"implementation": BottomBarController,
"depends": [
"indicators[]"
]
},
{
"key": "GetterSetterController",
"implementation": GetterSetterController,
@@ -396,11 +403,6 @@ define([
"implementation": MCTTree,
"depends": ['gestureService', 'openmct']
},
{
"key": "mctIndicators",
"implementation": MCTIndicators,
"depends": ['openmct']
},
{
"key": "mctPreview",
"implementation": MCTPreview,

View File

@@ -42,7 +42,6 @@
@import "controls/lists";
@import "controls/menus";
@import "controls/messages";
@import "controls/indicators";
@import "mobile/controls/menus";
/********************************* FORMS */

View File

@@ -20,120 +20,66 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*************************************************** MIXINS */
@mixin elementStatusColors($c) {
@mixin formulateStatusColors($c) {
// Sets bg and icon colors for elements
background: rgba($c, 0.5) !important;
&:before {
color: $c !important;
}
background: rgba($c, 0.4) !important;
&:before { color: $c !important; }
}
@mixin indicatorStatusColors($c) {
&:before, .count {
color: $c;
}
}
/*************************************************** GENERAL */
.s-limit-upr,
.s-limit-lwr,
[class*='s-limit-icon'],
[class*='s-status-icon'] {
.s-limit-yellow,
.s-limit-red,
.s-limit-yellow-icon,
.s-limit-red-icon,
.s-status-warning-lo,
.s-status-warning-hi,
.s-status-diagnostic,
.s-status-command,
.s-status-info,
.s-status-ok,
.s-status-warning-lo-icon,
.s-status-warning-hi-icon,
.s-status-diagnostic-icon,
.s-status-command-icon,
.s-status-info-icon,
.s-status-ok-icon {
@include trans-prop-nice($props: background, $dur: 500ms);
&:before {
content:'';
display: inline-block;
font-family: symbolsfont;
font-size: 0.8em;
margin-right: $interiorMarginSm;
}
}
/*************************************************** LIMITS */
[class*='s-limit'] {
&[class*='icon-'] {
&:before {
margin-right: $interiorMargin;
}
}
.s-limit-yellow, .s-limit-yellow-icon {
@include formulateStatusColors($colorWarningLo);
}
.s-limit-yellow, .s-limit-icon-yellow {
@include elementStatusColors($colorWarningLo);
.s-limit-red, .s-limit-red-icon {
@include formulateStatusColors($colorWarningHi);
}
.s-limit-red, .s-limit-icon-red {
@include elementStatusColors($colorWarningHi);
}
.s-limit {
&-upr,
&-lwr {
&:before {
margin-right: $interiorMargin;
}
}
&-upr:before { content: $glyph-icon-arrow-double-up; }
&-lwr:before { content: $glyph-icon-arrow-double-down; }
&-icon-yellow,
&-icon-red {
&:before {
content: $glyph-icon-alert-triangle;
}
}
}
.s-limit-upr:before { content: $glyph-icon-arrow-double-up; }
.s-limit-lwr:before { content: $glyph-icon-arrow-double-down; }
.s-limit-yellow-icon:before,
.s-limit-red-icon:before { content: $glyph-icon-alert-triangle; }
/*************************************************** STATUS */
[class*='s-status'] {
&[class*='icon-'] {
&:before {
margin-right: $interiorMargin;
}
}
}
.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-icon-warning-hi { @include elementStatusColors($colorWarningHi); }
.s-status-warning-lo, .s-status-icon-warning-lo { @include elementStatusColors($colorWarningLo); }
.s-status-diagnostic, .s-status-icon-diagnostic { @include elementStatusColors($colorDiagnostic); }
.s-status-info, .s-status-icon-info { @include elementStatusColors($colorInfo); }
.s-status-ok, .s-status-icon-ok { @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; }
.s-status-diagnostic-icon:before { content: $glyph-icon-eye-open; }
.s-status-info-icon:before { content: $glyph-icon-info; }
.s-status-ok-icon:before { content: $glyph-icon-check; }
.s-status-icon-warning-hi:before { content: $glyph-icon-alert-triangle; }
.s-status-icon-warning-lo:before { content: $glyph-icon-alert-rect; }
.s-status-icon-diagnostic:before { content: $glyph-icon-eye-open; }
.s-status-icon-info:before { content: $glyph-icon-info; }
.s-status-icon-ok:before { content: $glyph-icon-check; }
/*************************************************** INDICATOR COLORING */
.ls-indicator {
&.s-status-info {
@include indicatorStatusColors($colorInfo);
}
&.s-status-disabled {
@include indicatorStatusColors($colorIndicatorDisabled);
}
&.s-status-available {
@include indicatorStatusColors($colorIndicatorAvailable);
}
&.s-status-on,
&.s-status-enabled {
@include indicatorStatusColors($colorIndicatorOn);
}
&.s-status-off {
@include indicatorStatusColors($colorIndicatorOff);
}
&.s-status-caution,
&.s-status-warning,
&.s-status-alert {
@include indicatorStatusColors($colorStatusAlert);
}
&.s-status-error {
@include indicatorStatusColors($colorStatusError);
}
}

View File

@@ -133,11 +133,19 @@
/******************************************************** LOCAL CONTROLS */
// Controls placed in proximity to or overlaid on components and views
.local-controls-persist {
}
.local-controls-hidden {
// Used within .has-local-controls, hidden by default
}
.local-controls-flyout {
}
body.desktop .has-local-controls {
// Helper class, provides hover ability to show local controls
@@ -148,7 +156,7 @@ body.desktop .has-local-controls {
}
.local-controls-hidden {
@include trans-prop-nice($props: opacity, $dur: 500ms);
@include trans-prop-nice($props: opacity, $dur: 1000ms);
opacity: 0;
pointer-events: none;
}
@@ -203,7 +211,6 @@ body.desktop .has-local-controls {
cursor: pointer;
height: 1em; width: 1em;
line-height: inherit;
position: relative;
&:before {
position: absolute;
@include trans-prop-nice(transform, 100ms);

View File

@@ -1,147 +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.
*****************************************************************************/
/* Indicators are generally only displayed in the ue-bottom-bar element of the main interface */
.h-indicator,
mct-indicators mct-include {
display: inline; // Fallback for display: contents
display: contents;
}
.ls-indicator {
$bg: rgba(white, 0.2) !important;
$hbg: $colorStatusBarBg;
$hshdw: rgba(white, 0.4) 0 0 3px;
$br: $controlCr;
$hoverYOffset: -35px;
background: transparent !important;
border-radius: $br;
display: inline-block;
position: relative;
padding: 1px $interiorMarginSm; // Use padding instead of margin to keep hover chatter to a minimum
&:before {
display: inline-block;
}
.label {
display: inline-block;
a,
button,
.s-button {
// Make <a> in label look like buttons
@include trans-prop-nice($props: all, $dur: 100ms);
background: transparent;
border: 1px solid rgba($colorStatusBarFg, 0.5);
border-radius: $br;
box-sizing: border-box;
color: inherit;
font-size: inherit;
height: auto;
line-height: normal;
padding: 0 2px;
&:hover {
background: $bg;
color: #fff;
}
}
[class*='icon-'] {
// If any elements within label include the class 'icon-*' then deal with their :before's
&:before {
font-size: 0.8em;
margin-right: $interiorMarginSm;
}
}
button { text-transform: uppercase !important; }
}
&.no-collapse {
display: flex;
flex-flow: row nowrap;
align-items: center;
> *,
&:before {
flex: 1 1 auto;
}
&:before {
margin-right: $interiorMarginSm;
}
}
&:not(.no-collapse) {
z-index: 0;
&:before {
margin-right: 0 !important;
}
.label {
transition: all 250ms ease-in 100ms;
background: $hbg;
border-radius: $br;
font-size: .6rem;
left: 0;
bottom: 140%;
opacity: 0;
padding: $interiorMarginSm $interiorMargin;
position: absolute;
transform-origin: 10px 100%;
transform: scale(0.0);
white-space: nowrap;
&:before {
// Infobubble-style arrow element
content: '';
display: block;
position: absolute;
top: 100%;
@include triangle('down', $size: 4px, $ratio: 1, $color: $hbg);
}
}
&:hover {
background: $bg;
z-index: 1;
.label {
opacity: 1;
transform: scale(1.0);
transition: all 100ms ease-out 0s;
}
}
}
&.float-right {
float: right;
}
}
/* Mobile */
// Hide the clock indicator when we're phone portrait
body.phone.portrait {
.ls-indicator.t-indicator-clock {
display: none;
}
}

View File

@@ -19,9 +19,9 @@
* 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: 10%;
$bgPb: 30%;
$bgPbD: 10%;
background-color: darken($bg, $bgPb);
color: $fg;
@@ -36,6 +36,110 @@
}
}
// 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 {
@@ -185,6 +289,7 @@
> div,
> span {
//@include test(red);
margin-bottom: $interiorMargin;
}

View File

@@ -33,8 +33,8 @@
display: flex;
flex-flow: column nowrap;
.gl-plot.child-frame {
mct-plot {
display: flex;
mct-plot {
display: flex;
flex: 1 1 auto;
height: 100%;
position: relative;
@@ -51,15 +51,18 @@
display: block;
}
}
}
.gl-plot {
color: $colorPlotFg;
color: $colorPlotFg;
display: flex;
font-size: 0.7rem;
position: relative;
width: 100%;
height: 100%;
font-size: 0.7rem;
position: relative;
width: 100%;
height: 100%;
min-height: $plotMinH;
/********************************************* AXIS AND DISPLAY AREA */
@@ -71,8 +74,7 @@
position: absolute;
display: block;
font-size: 1.5em;
top: $interiorMarginSm;
left: $interiorMarginSm;
top: $interiorMarginSm; left: $interiorMarginSm;
}
}
@@ -103,71 +105,71 @@
}
}
.gl-plot-axis-area {
position: absolute;
&.gl-plot-y {
top: nth($plotDisplayArea, 1);
right: auto;
bottom: nth($plotDisplayArea, 3);
left: 0;
width: $plotYBarW;
}
}
.gl-plot-axis-area {
position: absolute;
&.gl-plot-y {
top: nth($plotDisplayArea, 1);
right: auto;
bottom: nth($plotDisplayArea, 3);
left: 0;
width: $plotYBarW;
}
}
.gl-plot-coords {
box-sizing: border-box;
border-radius: $controlCr;
background: black;
color: lighten($colorBodyFg, 30%);
padding: 2px 5px;
position: absolute;
top: nth($plotDisplayArea,1) + $interiorMarginLg;
right: auto;
bottom: auto;
left: nth($plotDisplayArea,4) + $interiorMarginLg;
z-index: 10;
&:empty {
display: none;
}
}
.gl-plot-coords {
box-sizing: border-box;
border-radius: $controlCr;
background: black;
color: lighten($colorBodyFg, 30%);
padding: 2px 5px;
position: absolute;
top: nth($plotDisplayArea,1) + $interiorMarginLg;
right: auto;
bottom: auto;
left: nth($plotDisplayArea,4) + $interiorMarginLg;
z-index: 10;
&:empty {
display: none;
}
}
.gl-plot-label,
.l-plot-label {
color: $colorPlotLabelFg;
position: absolute;
text-align: center;
.gl-plot-label,
.l-plot-label {
color: $colorPlotLabelFg;
position: absolute;
text-align: center;
&.gl-plot-x-label,
&.l-plot-x-label {
top: auto;
right: 0;
bottom: 0;
left: 0;
height: auto;
}
&.gl-plot-x-label,
&.l-plot-x-label {
top: auto;
right: 0;
bottom: 0;
left: 0;
height: auto;
}
&.gl-plot-y-label,
&.l-plot-y-label {
$x: -50%;
$r: -90deg;
transform-origin: 50% 0;
transform: translateX($x) rotate($r);
display: inline-block;
margin-left: $interiorMargin; // Kick off the left edge
left: 0;
top: 50%;
white-space: nowrap;
}
}
&.gl-plot-y-label,
&.l-plot-y-label {
$x: -50%;
$r: -90deg;
transform-origin: 50% 0;
transform: translateX($x) rotate($r);
display: inline-block;
margin-left: $interiorMargin; // Kick off the left edge
left: 0;
top: 50%;
white-space: nowrap;
}
}
.gl-plot-x-options,
.gl-plot-x-options,
.gl-plot-y-options {
$h: 24px;
position: absolute;
height: $h;
min-height: $h;
$h: 24px;
position: absolute;
height: $h;
min-height: $h;
z-index: 2;
}
}
.gl-plot-x-options {
transform: translateX(-50%);
@@ -188,192 +190,119 @@
right: $interiorMargin;
}
.gl-plot-hash {
position: absolute;
opacity: $opacityPlotHash;
&.hash-v {
border-right: 1px $colorPlotHash $stylePlotHash;
height: 100%;
}
&.hash-h {
border-bottom: 1px $colorPlotHash $stylePlotHash;
width: 100%;
}
}
.gl-plot-hash {
position: absolute;
border: 0 $colorPlotHash $stylePlotHash;
&.hash-v {
border-right-width: 1px;
height: 100%;
}
&.hash-h {
border-bottom-width: 1px;
width: 100%;
}
}
/****************************** Limits and Out-of-Bounds data */
/****************************** Limits and Out-of-Bounds data */
.l-limit-bar,
.l-oob-data {
position: absolute;
left: 0;
right: 0;
width: auto;
}
.l-limit-bar,
.l-oob-data {
position: absolute;
left: 0;
right: 0;
width: auto;
}
.l-limit-bar {
// Limits in plot display area
@mixin limitBg($c) {
background: rgba($c, 0.2);
}
.l-limit-bar {
// Limits in plot display area
@mixin limitBg($c) {
background: rgba($c, 0.2);
}
height: auto;
z-index: 0;
&.s-limit-yellow {
@include limitBg($colorLimitYellowBg);
}
&.s-limit-red {
@include limitBg($colorLimitRedBg);
}
}
height: auto;
z-index: 0;
&.s-limit-yellow { @include limitBg($colorLimitYellowBg); }
&.s-limit-red { @include limitBg($colorLimitRedBg); }
}
.l-oob-data {
$c: #7748d6;
$a: 0.5;
$h: 10px;
@include absPosDefault();
pointer-events: none;
height: $h;
z-index: 1;
&.l-oob-data-up {
top: 0;
bottom: auto;
@include linearGlow(0deg, $c, $a);
}
&.l-oob-data-dwn {
bottom: 0;
top: auto;
@include linearGlow(180deg, $c, $a);
}
}
.l-oob-data {
$c: #7748d6;
$a: 0.5;
$h: 10px;
@include absPosDefault();
pointer-events: none;
height: $h;
z-index: 1;
&.l-oob-data-up {
top: 0;
bottom: auto;
@include linearGlow(0deg, $c, $a);
}
&.l-oob-data-dwn {
bottom: 0;
top: auto;
@include linearGlow(180deg, $c, $a);
}
}
}
.gl-plot-display-area,
.plot-display-area {
@if $colorPlotBg != none {
background-color: $colorPlotBg;
}
@if $colorPlotBg != none { background-color: $colorPlotBg; }
cursor: crosshair;
border: 1px solid $colorPlotAreaBorder;
}
.tick {
position: absolute;
border: 0 $colorPlotHash solid;
&.tick-x {
border-right-width: 1px;
height: 100%; // Assumption is that the tick will be in a holder that will set it's height;
}
position: absolute;
border: 0 $colorPlotHash solid;
&.tick-x {
border-right-width: 1px;
height: 100%; // Assumption is that the tick will be in a holder that will set it's height;
}
}
.gl-plot-tick,
.tick-label {
@include reverseEllipsis();
font-size: 0.7rem;
position: absolute;
&.gl-plot-x-tick-label,
&.tick-label-x {
right: auto;
bottom: auto;
left: auto;
height: auto;
width: 20%;
margin-left: -10%;
text-align: center;
}
&.gl-plot-y-tick-label,
&.tick-label-y {
top: auto;
height: 1em;
width: auto;
margin-bottom: -0.5em;
text-align: right;
}
font-size: 0.7rem;
position: absolute;
&.gl-plot-x-tick-label,
&.tick-label-x {
right: auto;
bottom: auto;
left: auto;
height: auto;
width: 20%;
margin-left: -10%;
text-align: center;
}
&.gl-plot-y-tick-label,
&.tick-label-y {
top: auto;
height: 1em;
width: auto;
margin-bottom: -0.5em;
text-align: right;
}
}
.gl-plot-tick {
&.gl-plot-x-tick-label {
top: $interiorMargin;
}
&.gl-plot-y-tick-label {
right: $interiorMargin;
left: $interiorMargin;
}
&.gl-plot-x-tick-label {
top: $interiorMargin;
}
&.gl-plot-y-tick-label {
right: $interiorMargin;
left: $interiorMargin;
}
}
.tick-label {
&.tick-label-x {
top: 0;
}
&.tick-label-y {
right: 0;
left: 0;
}
}
.export-plot {
$bg: white;
$fg: black;
$gry: #999;
background: $bg !important;
z-index: -10;
.l-view-section {
$m: $interiorMargin;
top: $m !important;
right: $m;
bottom: $m;
left: $m;
.s-status-timeconductor-unsynced .holder-plot {
.t-object-alert.t-alert-unsynced {
display: none;
}
}
}
.gl-plot-display-area {
background: none !important;
border-color: $gry !important;
.gl-plot-local-controls,
.h-local-controls {
opacity: 0;
}
}
.gl-plot {
color: $fg;
.gl-plot-hash {
opacity: 0.1;
border-color: $fg;
}
}
table {
thead {
border-bottom: none;
th {
background: #eee;
border-left-color: $bg;
color: #666;
}
tr {
border: none;
}
}
tbody {
tr {
border-top: 1px solid #ccc;
}
td {
color: $fg;
}
}
}
&.tick-label-x {
top: 0;
}
&.tick-label-y {
right: 0; left: 0;
}
}

View File

@@ -97,7 +97,6 @@ input.c-search__search-input {
box-shadow: none !important; // !important needed to override default for [input]
flex: 1 1 99%;
min-width: 10px;
width: 100%;
}
.c-search__search-menu-holder {
@@ -110,10 +109,6 @@ input.c-search__search-input {
.holder-search {
$iconWidth: 20px;
.c-search-btn-wrapper {
margin-right: $interiorMarginLg; // Fend off rights side from pane splitter control
}
.results-msg {
font-size: 0.8rem;
opacity: 0.6;

View File

@@ -47,18 +47,6 @@
}
}
.status-holder {
text-transform: uppercase;
}
.s-ue-bottom-bar {
background: $colorStatusBarBg;
color: $colorStatusBarFg;
cursor: default;
font-size: .7rem;
}
.user-environ {
height: 100%;
width: 100%;
@@ -93,17 +81,21 @@
}
}
.l-ue-bottom-bar {
$m: $interiorMarginSm;
@include absPosDefault(0, $overflow: visible);// New status bar design
.ue-bottom-bar {
@include absPosDefault(0);// New status bar design
top: auto;
height: $ueFooterH;
line-height: $ueFooterH - ($m * 2);
line-height: $ueFooterH - ($interiorMargin * 2);
background: $colorStatusBarBg;
color: lighten($colorBodyBg, 30%);
font-size: .7rem;
.status-holder {
box-sizing: border-box;
@include absPosDefault($m, $overflow: visible);
@include absPosDefault($interiorMargin);
@include ellipsize();
right: 120px;
z-index: 10;
text-transform: uppercase;
z-index: 1;
}
.app-logo {
background-position: right center;

View File

@@ -19,9 +19,14 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class='abs bottom-bar l-ue-bottom-bar s-ue-bottom-bar mobile-disable-select'>
<div class='abs bottom-bar ue-bottom-bar mobile-disable-select' ng-controller="BottomBarController as bar">
<div id='status' class='status-holder'>
<mct-indicators></mct-indicators>
<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>
<mct-include key="'message-banner'"></mct-include>
<mct-include key="'about-logo'"></mct-include>

View File

@@ -20,8 +20,14 @@
at runtime from the About dialog for additional information.
-->
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div class="ls-indicator {{ngModel.getCssClass()}}"
<div class='status block'
title="{{ngModel.getDescription()}}"
ng-click='ngModel.configure()'
ng-show="ngModel.getText().length > 0">
<span class="label">{{ngModel.getText()}}</span>
<span class="status-indicator {{ngModel.getCssClass()}}"></span><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>

View File

@@ -0,0 +1,59 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
[],
function () {
/**
* 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);
}
/**
* 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 BottomBarController;
}
);

View File

@@ -0,0 +1,76 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
["../../src/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);
});
});
}
);

View File

@@ -1,8 +1,9 @@
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div ng-show="notifications.length > 0" class="ls-indicator s-status-{{highest.severity}} icon-bell"
<a ng-click="showNotificationsList()" ng-show="notifications.length > 0" class="status block"
ng-class="highest.severity"
ng-controller="NotificationIndicatorController">
<span class="label">
<a ng-click="showNotificationsList()">
{{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></a>
<span class="status-indicator icon-bell"></span><span class="label">
{{notifications.length}} Notifications
</span><span class="count">{{notifications.length}}</span>
</div>
</a>

View File

@@ -3,8 +3,6 @@ $colorBodyBg: #333;
$colorBodyFg: #999;
$colorGenBg: #222;
$colorStatusBarBg: #000;
$colorStatusBarFg: #999;
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeySelectedBg: #005177;
$colorKeyFg: #fff;
@@ -57,7 +55,7 @@ $colorTransLucBg: #666; // Used as a visual blocking element over variable backg
// Foundation Colors
$colorAlt1: #ffc700;
$colorAlert: #ff9900;
$colorAlert: #ff3c00;
$colorWarningHi: #cc0000;
$colorWarningLo: #ff9900;
$colorDiagnostic: #a4b442;
@@ -74,6 +72,7 @@ $colorObjHdrTxt: $colorBodyFg;
$colorObjHdrIc: lighten($colorObjHdrTxt, 20%);
$colorTick: rgba(white, 0.2);
$colorSelectableSelectedPrimary: $colorKey;
//$colorSelectableSelectedSecondary: pushBack($colorSelectableSelectedPrimary, 20%);
$colorSelectableHov: rgba($colorBodyFg, 0.3);
// Menu colors
@@ -115,10 +114,11 @@ $colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
// Status colors, mainly used for messaging and item ancillary symbols
$colorStatusFg: #ccc;
$colorStatusDefault: #999;
$colorStatusDefault: #ccc;
$colorStatusInfo: $colorInfo;
$colorStatusAlert: $colorAlert;
$colorStatusError: #da0004;
$colorStatusError: #d4585c;
$colorStatusAvailable: $colorKey;
$colorStatusBtnBg: $colorBtnBg;
$colorProgressBarOuter: rgba(#000, 0.1);
$colorProgressBarAmt: $colorKey;
@@ -127,12 +127,6 @@ $progressBarStripeW: 20px;
$shdwStatusIc: rgba(black, 0.4) 0 1px 2px;
$animPausedPulseDur: 500ms;
// Indicator colors
$colorIndicatorAvailable: $colorKey;
$colorIndicatorDisabled: #444;
$colorIndicatorOn: $colorOk;
$colorIndicatorOff: #666;
// Selects
$colorSelectBg: $colorBtnBg;
$colorSelectFg: $colorBtnFg;
@@ -183,8 +177,7 @@ $colorTabHeaderBorder: $colorBodyBg;
// Plot
$colorPlotBg: rgba(black, 0.1);
$colorPlotFg: $colorBodyFg;
$colorPlotHash: white;
$opacityPlotHash: 0.2;
$colorPlotHash: $colorTick;
$stylePlotHash: dashed;
$colorPlotAreaBorder: $colorInteriorBorder;
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);

View File

@@ -3,8 +3,6 @@ $colorBodyBg: #fcfcfc;
$colorBodyFg: #666;
$colorGenBg: #fff;
$colorStatusBarBg: #000;
$colorStatusBarFg: #999;
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeySelectedBg: $colorKey;
$colorKeyFg: #fff;
@@ -74,6 +72,7 @@ $colorObjHdrTxt: $colorBodyFg;
$colorObjHdrIc: lighten($colorObjHdrTxt, 30%);
$colorTick: rgba(black, 0.2);
$colorSelectableSelectedPrimary: $colorKey;
//$colorSelectableSelectedSecondary: pushBack($colorSelectableSelectedPrimary, 20%);
$colorSelectableHov: rgba($colorBodyFg, 0.4);
// Menu colors
@@ -118,7 +117,8 @@ $colorStatusFg: #999;
$colorStatusDefault: #ccc;
$colorStatusInfo: #60ba7b;
$colorStatusAlert: #ffb66c;
$colorStatusError: #da0004;
$colorStatusError: #c96b68;
$colorStatusAvailable: $colorKey;
$colorStatusBtnBg: #666;
$colorProgressBarOuter: rgba(#000, 0.1);
$colorProgressBarAmt: #0a0;
@@ -127,12 +127,6 @@ $progressBarStripeW: 20px;
$shdwStatusIc: rgba(white, 0.8) 0 0px 5px;
$animPausedPulseDur: 1s;
// Indicator colors
$colorIndicatorAvailable: $colorKey;
$colorIndicatorDisabled: #444;
$colorIndicatorOn: $colorOk;
$colorIndicatorOff: #666;
// Selects
$colorSelectBg: $colorBtnBg;
$colorSelectFg: $colorBtnFg;
@@ -183,8 +177,7 @@ $colorTabHeaderBorder: $colorBodyBg;
// Plot
$colorPlotBg: rgba(black, 0.05);
$colorPlotFg: $colorBodyFg;
$colorPlotHash: black;
$opacityPlotHash: 0.2;
$colorPlotHash: $colorTick;
$stylePlotHash: dashed;
$colorPlotAreaBorder: $colorInteriorBorder;
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);

View File

@@ -55,6 +55,7 @@ define([
timerTemplate,
legacyRegistry
) {
legacyRegistry.register("platform/features/clock", {
"name": "Clocks/Timers",
"descriptions": "Domain objects for displaying current & relative times.",
@@ -85,6 +86,11 @@ define([
"CLOCK_INDICATOR_FORMAT"
],
"priority": "preferred"
},
{
"implementation": FollowIndicator,
"depends": ["timerService"],
"priority": "fallback"
}
],
"services": [
@@ -299,10 +305,6 @@ define([
}
}
],
"runs": [{
"implementation": FollowIndicator,
"depends": ["openmct", "timerService"]
}],
"licenses": [
{
"name": "moment-duration-format",

View File

@@ -45,11 +45,11 @@ define(
}
ClockIndicator.prototype.getGlyphClass = function () {
return "";
return "no-collapse float-right subdued";
};
ClockIndicator.prototype.getCssClass = function () {
return "t-indicator-clock icon-clock no-collapse float-right";
return "icon-clock";
};
ClockIndicator.prototype.getText = function () {

View File

@@ -1,5 +1,5 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2018, United States Government
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
@@ -20,32 +20,38 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([], function () {
define(
['moment'],
function (moment) {
var NO_TIMER = "No timer being followed";
/**
* Indicator that displays the active timer, as well as its
* current state.
* @memberof platform/features/clock
*/
return function installFollowIndicator(openmct, timerService) {
var indicator = openmct.indicators.simpleIndicator();
var timer = timerService.getTimer();
setIndicatorStatus(timer);
function setIndicatorStatus(newTimer) {
if (newTimer !== undefined) {
indicator.iconClass('icon-timer');
indicator.statusClass('s-status-on');
indicator.text('Following timer ' + newTimer.name);
} else {
indicator.iconClass('icon-timer');
indicator.statusClass('s-status-disabled');
indicator.text('No timer being followed');
}
/**
* Indicator that displays the active timer, as well as its
* current state.
* @implements {Indicator}
* @memberof platform/features/clock
*/
function FollowIndicator(timerService) {
this.timerService = timerService;
}
timerService.on('change', setIndicatorStatus);
FollowIndicator.prototype.getGlyphClass = function () {
return "";
};
openmct.indicators.add(indicator);
};
});
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;
}
);

View File

@@ -44,7 +44,7 @@ define(['EventEmitter'], function (EventEmitter) {
*/
TimerService.prototype.setTimer = function (timer) {
this.timer = timer;
this.emit('change', timer);
this.emit('change');
if (this.stopObserving) {
this.stopObserving();

View File

@@ -1,5 +1,5 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2018, United States Government
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
@@ -20,77 +20,39 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
"../../src/indicators/FollowIndicator",
"../../src/services/TimerService",
"../../../../../src/MCT",
'zepto'
], function (
FollowIndicator,
TimerService,
MCT,
$
) {
define(["../../src/indicators/FollowIndicator"], function (FollowIndicator) {
var TIMER_SERVICE_METHODS =
['setTimer', 'getTimer', 'clearTimer', 'on', 'off'];
describe("The timer-following indicator", function () {
var timerService;
var openmct;
var mockTimerService;
var indicator;
beforeEach(function () {
openmct = new MCT();
timerService = new TimerService(openmct);
spyOn(openmct.indicators, "add");
mockTimerService =
jasmine.createSpyObj('timerService', TIMER_SERVICE_METHODS);
indicator = new FollowIndicator(mockTimerService);
});
it("adds an indicator when installed", function () {
FollowIndicator(openmct, timerService);
expect(openmct.indicators.add).toHaveBeenCalled();
});
it("indicates that no timer is being followed", function () {
FollowIndicator(openmct, timerService);
var simpleIndicator = openmct.indicators.add.calls.mostRecent().args[0];
var element = simpleIndicator.element;
var text = $('.indicator-text', element).text().trim();
expect(text).toEqual('No timer being followed');
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));
});
describe("when a timer is set", function () {
var testObject;
var simpleIndicator;
beforeEach(function () {
testObject = {
identifier: {
namespace: 'namespace',
key: 'key'
},
name: "some timer!"
};
timerService.setTimer(testObject);
FollowIndicator(openmct, timerService);
simpleIndicator = openmct.indicators.add.calls.mostRecent().args[0];
testObject = { name: "some timer!" };
mockTimerService.getTimer.and.returnValue(testObject);
});
it("displays the timer's name", function () {
var element = simpleIndicator.element;
var text = $('.indicator-text', element).text().trim();
expect(text).toEqual('Following timer ' + testObject.name);
expect(indicator.getText().indexOf(testObject.name))
.not.toEqual(-1);
});
it("displays the timer's name when it changes", function () {
var secondTimer = {
identifier: {
namespace: 'namespace',
key: 'key2'
},
name: "Some other timer"
};
var element = simpleIndicator.element;
timerService.setTimer(secondTimer);
var text = $('.indicator-text', element).text().trim();
expect(text).toEqual('Following timer ' + secondTimer.name);
});
});
});
});

View File

@@ -58,8 +58,7 @@ define([
"model": {
"entries": [],
"composition": [],
"entryTypes": [],
"defaultSort": "-createdOn"
"entryTypes": []
},
"properties": [
{
@@ -237,6 +236,7 @@ define([
"cssClass": "icon-notebook labeled",
"description": "Add a new Notebook entry",
"category": [
"contextual",
"view-control"
],
"depends": [
@@ -252,13 +252,13 @@ define([
"licenses": [
{
"name": "painterro",
"version": "0.2.65",
"author": "Ivan Borshchov",
"description": "Painterro is JavaScript paint widget which allows editing images directly in a browser.",
"website": "https://github.com/ivictbor/painterro",
"copyright": "Copyright 2017 Ivan Borshchov",
"license": "MIT",
"link": "https://github.com/ivictbor/painterro/blob/master/LICENSE"
"version": "4.1.0",
"author": "Mike Bostock",
"description": "D3 (or D3.js) is a JavaScript library for visualizing data using web standards. D3 helps you bring data to life using SVG, Canvas and HTML. D3 combines powerful visualization and interaction techniques with a data-driven approach to DOM manipulation, giving you the full capabilities of modern browsers and the freedom to design the right visual interface for your data.",
"website": "https://d3js.org/",
"copyright": "Copyright 2010-2016 Mike Bostock",
"license": "BSD-3-Clause",
"link": "https://github.com/d3/d3/blob/master/LICENSE"
}
],
"capabilities": [

View File

@@ -144,13 +144,6 @@
}
}
.s-status-taking-snapshot,
.overlay.snapshot {
// Handle overflow-y issues with tables and html2canvas
.l-sticky-headers .l-tabular-body { overflow: auto; }
}
/********************************************* MOBILE */
body.mobile {
// Hide the start entry area, and disable ability to edit or delete an entry in mobile context
@@ -292,3 +285,24 @@ body.phone.portrait {
.overlay.l-dialog .abs.editor {
padding-right: 0;
}
/*
.overlay.l-dialog .outer-holder.annotation-dialog{
width: 90%;
height: 90%;
}
*/
/*
.snap-annotation-wrapper{
padding-top: 40px;
}
.t-console {
// Temp console-like reporting element
max-height: 200px;
box-sizing: border-box;
padding: 5px;
}
*/

View File

@@ -34,12 +34,10 @@
}
.s-notebook-entry {
transition: background-color 500ms ease-out;
background-color: rgba($colorBodyFg, 0.1);
border-radius: $basicCr;
&:hover {
transition: background-color 50ms ease-in;
background-color: rgba($colorBodyFg, 0.2);
}

View File

@@ -109,7 +109,7 @@
</div>
</div>
<!-- delete entry -->
<div class="holder flex-elem local-control local-controls-hidden notebook-entry-delete">
<div class="holder flex-elem local-control notebook-entry-delete">
<a class="s-icon-button icon-trash" id={{entry.id}} title="Delete Entry" ng-click="deleteEntry($event)"></a>
</div>
</li>

View File

@@ -185,18 +185,7 @@ define(
NewEntryContextual.appliesTo = function (context) {
var domainObject = context.domainObject;
if (domainObject) {
if (domainObject.getModel().type === 'Notebook') {
// do not allow in context of a notebook
return false;
} else if (domainObject.getModel().type.includes('imagery')) {
// do not allow in the context of an object with imagery
// (because of cross domain issue with snapshot)
return false;
}
}
return true;
return !!(domainObject && domainObject.getModel().type !== 'notebook');
};
return NewEntryContextual;

View File

@@ -42,7 +42,7 @@ define(
) {
$scope.entriesEl = $(document.body).find('.t-entries-list');
$scope.sortEntries = $scope.domainObject.getModel().defaultSort;
$scope.sortEntries = $scope.domainObject.getModel().defaultSort || "-createdOn";
$scope.showTime = "0";
$scope.editEntry = false;
$scope.entrySearch = '';
@@ -354,11 +354,6 @@ define(
$scope.$watchCollection("composition", refreshComp);
$scope.$watch('domainObject.getModel().defaultSort', function (newDefaultSort, oldDefaultSort) {
if (newDefaultSort !== oldDefaultSort) {
$scope.sortEntries = newDefaultSort;
}
});
$scope.$on('$destroy', function () {});

View File

@@ -25,7 +25,7 @@ define(['zepto'], function ($) {
var document = $document[0];
function link($scope, $element, $attrs) {
var objectElement = $(document.body).find(".overlay .object-holder")[0] || $(document.body).find("[key='representation.selected.key']")[0],
var objectElement = $(document.body).find('.overlay')[0] || $(document.body).find("[key='representation.selected.key']")[0],
takeSnapshot,
makeImg,
saveImg;

View File

@@ -65,10 +65,3 @@ mct-table {
margin-bottom: 3px;
}
}
.mct-table-scroll-forcer {
// Force horz scroll when needed; width set via JS
font-size: 0;
height: 1px; // Height 0 won't force scroll properly
position: relative;
}

View File

@@ -59,10 +59,6 @@
</tbody>
</table>
<div class="l-tabular-body t-scrolling vscroll--persist" mct-resize="resize()" mct-scroll-x="scroll.x">
<div class="mct-table-scroll-forcer"
ng-style="{
width: totalWidth
}"></div>
<table class="mct-table"
ng-style="{
height: totalHeight + 'px',

View File

@@ -3,7 +3,7 @@
<mct-table
headers="headers"
rows="rows"
time-columns="[tableController.table.timeSystemColumnTitle]"
time-columns="tableController.timeColumns"
format-cell="formatCell"
enableFilter="true"
enableSort="true"

View File

@@ -1,67 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(function () {
function TableColumn(openmct, telemetryObject, metadatum) {
this.openmct = openmct;
this.telemetryObject = telemetryObject;
this.metadatum = metadatum;
this.formatter = openmct.telemetry.getValueFormatter(metadatum);
this.titleValue = this.metadatum.name;
}
TableColumn.prototype.title = function (title) {
if (arguments.length > 0) {
this.titleValue = title;
}
return this.titleValue;
};
TableColumn.prototype.isCurrentTimeSystem = function () {
var isCurrentTimeSystem = this.metadatum.hints.hasOwnProperty('domain') &&
this.metadatum.key === this.openmct.time.timeSystem().key;
return isCurrentTimeSystem;
};
TableColumn.prototype.hasValue = function (telemetryObject, telemetryDatum) {
var keyStringForDatum = this.openmct.objects.makeKeyString(telemetryObject.identifier);
var keyStringForColumn = this.openmct.objects.makeKeyString(this.telemetryObject.identifier);
return keyStringForDatum === keyStringForColumn && telemetryDatum.hasOwnProperty(this.metadatum.source);
};
TableColumn.prototype.getValue = function (telemetryDatum, limitEvaluator) {
var alarm = limitEvaluator &&
limitEvaluator.evaluate(telemetryDatum, this.metadatum);
var value = {
text: this.formatter.format(telemetryDatum),
value: this.formatter.parse(telemetryDatum)
};
if (alarm) {
value.cssClass = alarm.cssClass;
}
return value;
};
return TableColumn;
});

View File

@@ -19,10 +19,10 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/* global Set */
define(
['./TableColumn'],
function (TableColumn) {
[],
function () {
/**
* Class that manages table metadata, state, and contents.
@@ -32,31 +32,62 @@ define(
*/
function TableConfiguration(domainObject, openmct) {
this.domainObject = domainObject;
this.openmct = openmct;
this.timeSystemColumn = undefined;
this.columns = [];
this.headers = new Set();
this.timeSystemColumnTitle = undefined;
this.openmct = openmct;
}
/**
* Build column definition based on supplied telemetry metadata
* @param telemetryObject the telemetry producing object associated with this column
* Build column definitions based on supplied telemetry metadata
* @param metadata Metadata describing the domains and ranges available
* @returns {TableConfiguration} This object
*/
TableConfiguration.prototype.addColumn = function (telemetryObject, metadatum) {
var column = new TableColumn(this.openmct, telemetryObject, metadatum);
TableConfiguration.prototype.populateColumns = function (metadata) {
var self = this;
var telemetryApi = this.openmct.telemetry;
if (column.isCurrentTimeSystem()) {
if (!this.timeSystemColumnTitle) {
this.timeSystemColumnTitle = column.title();
}
column.title(this.timeSystemColumnTitle);
this.columns = [];
if (metadata) {
metadata.forEach(function (metadatum) {
var formatter = telemetryApi.getValueFormatter(metadatum);
self.columns.push({
getKey: function () {
return metadatum.key;
},
getTitle: function () {
return metadatum.name;
},
getValue: function (telemetryDatum, limitEvaluator) {
var isValueColumn = !!(metadatum.hints.y || metadatum.hints.range);
var alarm = isValueColumn &&
limitEvaluator &&
limitEvaluator.evaluate(telemetryDatum, metadatum);
var value = {
text: formatter.format(telemetryDatum),
value: formatter.parse(telemetryDatum)
};
if (alarm) {
value.cssClass = alarm.cssClass;
}
return value;
}
});
});
}
return this;
};
this.columns.push(column);
this.headers.add(column.title());
/**
* Get a simple list of column titles
* @returns {Array} The titles of the columns
*/
TableConfiguration.prototype.getHeaders = function () {
return this.columns.map(function (column, i) {
return column.getTitle() || 'Column ' + (i + 1);
});
};
/**
@@ -67,32 +98,22 @@ define(
* @returns {Object} Key value pairs where the key is the column
* title, and the value is the formatted value from the provided datum.
*/
TableConfiguration.prototype.getRowValues = function (telemetryObject, limitEvaluator, datum) {
return this.columns.reduce(function (rowObject, column) {
var columnTitle = column.title();
var columnValue = {
text: '',
value: undefined
};
if (rowObject[columnTitle] === undefined) {
rowObject[columnTitle] = columnValue;
}
if (column.hasValue(telemetryObject, datum)) {
TableConfiguration.prototype.getRowValues = function (limitEvaluator, datum) {
return this.columns.reduce(function (rowObject, column, i) {
var columnTitle = column.getTitle() || 'Column ' + (i + 1),
columnValue = column.getValue(datum, limitEvaluator);
if (columnValue.text === undefined) {
columnValue.text = '';
}
// Don't replace something with nothing.
// This occurs when there are multiple columns with the same
// column title
if (rowObject[columnTitle].text === undefined ||
rowObject[columnTitle].text.length === 0) {
rowObject[columnTitle] = columnValue;
}
if (columnValue !== undefined && columnValue.text === undefined) {
columnValue.text = '';
}
// Don't replace something with nothing.
// This occurs when there are multiple columns with the same
// column title
if (rowObject[columnTitle] === undefined ||
rowObject[columnTitle].text === undefined ||
rowObject[columnTitle].text.length === 0) {
rowObject[columnTitle] = columnValue;
}
return rowObject;
}, {});
};
@@ -143,7 +164,7 @@ define(
* specifying whether the column is visible or not. Default to
* existing (persisted) configuration if available
*/
this.headers.forEach(function (columnTitle) {
this.getHeaders().forEach(function (columnTitle) {
configuration[columnTitle] =
typeof defaultConfig[columnTitle] === 'undefined' ? true :
defaultConfig[columnTitle];

View File

@@ -93,9 +93,7 @@ define(
// Calculate the new index of the last item in bounds
endIndex = _.sortedLastIndex(this.highBuffer, testValue, this.sortField);
added = this.highBuffer.splice(0, endIndex);
added.forEach(function (datum) {
this.telemetry.push(datum);
}.bind(this));
this.telemetry = this.telemetry.concat(added);
}
if (discarded && discarded.length > 0) {
@@ -134,7 +132,6 @@ define(
// bounds events, so no bounds checking necessary
if (this.sortField === undefined) {
this.telemetry.push(item);
return true;
}
@@ -156,6 +153,7 @@ define(
// If out of bounds low, disregard data
if (!boundsLow) {
// Going to check for duplicates. Bound the search problem to
// items around the given time. Use sortedIndex because it
// employs a binary search which is O(log n). Can use binary search

View File

@@ -262,26 +262,19 @@ define(
* @private
*/
MCTTableController.prototype.onScroll = function (event) {
this.scrollWindow = {
top: this.scrollable[0].scrollTop,
bottom: this.scrollable[0].scrollTop + this.scrollable[0].offsetHeight,
offsetHeight: this.scrollable[0].offsetHeight,
height: this.scrollable[0].scrollHeight
};
this.$window.requestAnimationFrame(function () {
this.setVisibleRows();
this.digest();
// If user scrolls away from bottom, disable auto-scroll.
// Auto-scroll will be re-enabled if user scrolls to bottom again.
if (this.scrollWindow.top <
(this.scrollWindow.height - this.scrollWindow.offsetHeight) - 20) {
if (this.scrollable[0].scrollTop <
(this.scrollable[0].scrollHeight - this.scrollable[0].offsetHeight) - 20) {
this.$scope.autoScroll = false;
} else {
this.$scope.autoScroll = true;
}
this.scrolling = false;
delete this.scrollWindow;
}.bind(this));
};
@@ -290,14 +283,15 @@ define(
* @private
*/
MCTTableController.prototype.firstVisible = function () {
var topScroll = this.scrollWindow ?
this.scrollWindow.top :
this.scrollable[0].scrollTop;
var target = this.scrollable[0],
topScroll = target.scrollTop,
firstVisible;
return Math.floor(
firstVisible = Math.floor(
(topScroll) / this.$scope.rowHeight
);
return firstVisible;
};
/**
@@ -305,14 +299,16 @@ define(
* @private
*/
MCTTableController.prototype.lastVisible = function () {
var bottomScroll = this.scrollWindow ?
this.scrollWindow.bottom :
this.scrollable[0].scrollTop + this.scrollable[0].offsetHeight;
var target = this.scrollable[0],
topScroll = target.scrollTop,
bottomScroll = topScroll + target.offsetHeight,
lastVisible;
return Math.ceil(
lastVisible = Math.ceil(
(bottomScroll) /
this.$scope.rowHeight
);
return lastVisible;
};
/**

View File

@@ -118,18 +118,23 @@ define(
* to sort by. By default will just match on key.
*
* @private
* @param {TimeSystem} timeSystem
*/
TelemetryTableController.prototype.sortByTimeSystem = function () {
TelemetryTableController.prototype.sortByTimeSystem = function (timeSystem) {
var scope = this.$scope;
var sortColumn;
scope.defaultSort = undefined;
sortColumn = this.table.columns.filter(function (column) {
return column.isCurrentTimeSystem();
})[0];
if (sortColumn) {
scope.defaultSort = sortColumn.title();
this.telemetry.sort(sortColumn.title() + '.value');
if (timeSystem !== undefined) {
this.table.columns.forEach(function (column) {
if (column.getKey() === timeSystem.key) {
sortColumn = column;
}
});
if (sortColumn) {
scope.defaultSort = sortColumn.getTitle();
this.telemetry.sort(sortColumn.getTitle() + '.value');
}
}
};
@@ -167,6 +172,9 @@ define(
* @param rows
*/
TelemetryTableController.prototype.addRowsToTable = function (rows) {
rows.forEach(function (row) {
this.$scope.rows.push(row);
}, this);
this.$scope.$broadcast('add:rows', rows);
};
@@ -229,21 +237,35 @@ define(
TelemetryTableController.prototype.loadColumns = function (objects) {
var telemetryApi = this.openmct.telemetry;
this.table = new TableConfiguration(this.$scope.domainObject,
this.openmct);
this.$scope.headers = [];
if (objects.length > 0) {
objects.forEach(function (object) {
var metadataValues = telemetryApi.getMetadata(object).values();
metadataValues.forEach(function (metadatum) {
this.table.addColumn(object, metadatum);
}.bind(this));
}.bind(this));
var allMetadata = objects.map(telemetryApi.getMetadata.bind(telemetryApi));
var allValueMetadata = _.flatten(allMetadata.map(
function getMetadataValues(metadata) {
return metadata.values();
}
));
this.table.populateColumns(allValueMetadata);
var domainColumns = telemetryApi.commonValuesForHints(allMetadata, ['domain']);
this.timeColumns = domainColumns.map(function (metadatum) {
return metadatum.name;
});
this.filterColumns();
this.sortByTimeSystem();
// Default to no sort on underlying telemetry collection. Sorting
// is necessary to do bounds filtering, but this is only possible
// if data matches selected time system
this.telemetry.sort(undefined);
var timeSystem = this.openmct.time.timeSystem();
if (timeSystem !== undefined) {
this.sortByTimeSystem(timeSystem);
}
}
return objects;
@@ -280,7 +302,7 @@ define(
/*
* Process a batch of historical data
*/
function processData(object, historicalData, index, limitEvaluator) {
function processData(historicalData, index, limitEvaluator) {
if (index >= historicalData.length) {
processedObjects++;
@@ -289,13 +311,14 @@ define(
}
} else {
rowData = rowData.concat(historicalData.slice(index, index + self.batchSize)
.map(self.table.getRowValues.bind(self.table, object, limitEvaluator)));
.map(self.table.getRowValues.bind(self.table, limitEvaluator)));
/*
Use timeout to yield process to other UI activities. On
return, process next batch
*/
self.timeoutHandle = self.$timeout(function () {
processData(object, historicalData, index + self.batchSize, limitEvaluator);
processData(historicalData, index + self.batchSize, limitEvaluator);
});
}
}
@@ -304,7 +327,7 @@ define(
// Only process the most recent request
if (requestTime === self.lastRequestTime) {
var limitEvaluator = openmct.telemetry.limitEvaluator(object);
processData(object, historicalData, 0, limitEvaluator);
processData(historicalData, 0, limitEvaluator);
} else {
resolve(rowData);
}
@@ -344,6 +367,7 @@ define(
var telemetryCollection = this.telemetry;
//Set table max length to avoid unbounded growth.
var limitEvaluator;
var added = false;
var table = this.table;
this.subscriptions.forEach(function (subscription) {
@@ -353,7 +377,7 @@ define(
function newData(domainObject, datum) {
limitEvaluator = telemetryApi.limitEvaluator(domainObject);
telemetryCollection.add([table.getRowValues(domainObject, limitEvaluator, datum)]);
added = telemetryCollection.add([table.getRowValues(limitEvaluator, datum)]);
}
objects.forEach(function (object) {

View File

@@ -27,52 +27,31 @@ define(
function (Table) {
describe("A table", function () {
var mockTableObject,
mockTelemetryObject,
var mockDomainObject,
mockAPI,
mockTelemetryAPI,
table,
mockTimeAPI,
mockObjectsAPI,
mockModel;
beforeEach(function () {
mockTableObject = jasmine.createSpyObj('domainObject',
mockDomainObject = jasmine.createSpyObj('domainObject',
['getModel', 'useCapability', 'getCapability', 'hasCapability']
);
mockModel = {};
mockTableObject.getModel.and.returnValue(mockModel);
mockTableObject.getCapability.and.callFake(function (name) {
mockDomainObject.getModel.and.returnValue(mockModel);
mockDomainObject.getCapability.and.callFake(function (name) {
return name === 'editor' && {
isEditContextRoot: function () {
return true;
}
};
});
mockTelemetryObject = {
identifier: {
namespace: 'mock',
key: 'domainObject'
}
};
mockTelemetryAPI = jasmine.createSpyObj('telemetryAPI', [
'getValueFormatter'
]);
mockTimeAPI = jasmine.createSpyObj('timeAPI', [
'timeSystem'
]);
mockObjectsAPI = jasmine.createSpyObj('objectsAPI', [
'makeKeyString'
]);
mockObjectsAPI.makeKeyString.and.callFake(function (identifier) {
return [identifier.namespace, identifier.key].join(':');
});
mockAPI = {
telemetry: mockTelemetryAPI,
time: mockTimeAPI,
objects: mockObjectsAPI
telemetry: mockTelemetryAPI
};
mockTelemetryAPI.getValueFormatter.and.callFake(function (metadata) {
var formatter = jasmine.createSpyObj(
@@ -90,7 +69,7 @@ define(
return formatter;
});
table = new Table(mockTableObject, mockAPI);
table = new Table(mockDomainObject, mockAPI);
});
describe("Building columns from telemetry metadata", function () {
@@ -98,57 +77,51 @@ define(
{
name: 'Range 1',
key: 'range1',
source: 'range1',
hints: {
range: 1
y: 1
}
},
{
name: 'Range 2',
key: 'range2',
source: 'range2',
hints: {
range: 2
y: 2
}
},
{
name: 'Domain 1',
key: 'domain1',
source: 'domain1',
format: 'utc',
hints: {
domain: 1
x: 1
}
},
{
name: 'Domain 2',
key: 'domain2',
source: 'domain2',
format: 'utc',
hints: {
domain: 2
x: 2
}
}
];
beforeEach(function () {
mockTimeAPI.timeSystem.and.returnValue({
key: 'domain1'
});
metadata.forEach(function (metadatum) {
table.addColumn(mockTelemetryObject, metadatum);
});
table.populateColumns(metadata);
});
it("populates columns", function () {
expect(table.columns.length).toBe(4);
});
it("Produces headers for each column based on metadata name", function () {
expect(table.headers.size).toBe(4);
Array.from(table.headers.values).forEach(function (header, i) {
expect(header).toEqual(metadata[i].name);
});
it("Produces headers for each column based on title", function () {
var headers,
firstColumn = table.columns[0];
spyOn(firstColumn, 'getTitle');
headers = table.getHeaders();
expect(headers.length).toBe(4);
expect(firstColumn.getTitle).toHaveBeenCalled();
});
it("Provides a default configuration with all columns" +
@@ -196,10 +169,11 @@ define(
};
}
};
rowValues = table.getRowValues(mockTelemetryObject, limitEvaluator, datum);
rowValues = table.getRowValues(limitEvaluator, datum);
});
it("Returns a value for every column", function () {
expect(rowValues['Range 1'].text).toBeDefined();
expect(rowValues['Range 1'].text).toEqual(10);
});

View File

@@ -78,8 +78,7 @@ define(
]);
mockObjectAPI = jasmine.createSpyObj("objectAPI", [
"observe",
"makeKeyString"
"observe"
]);
unobserve = jasmine.createSpy("unobserve");
mockObjectAPI.observe.and.returnValue(unobserve);
@@ -185,7 +184,8 @@ define(
var mockComposition,
mockTelemetryObject,
mockChildren,
unsubscribe;
unsubscribe,
done;
beforeEach(function () {
mockComposition = jasmine.createSpyObj("composition", [
@@ -207,6 +207,8 @@ define(
mockTelemetryAPI.isTelemetryObject.and.callFake(function (obj) {
return obj.identifier.key === mockTelemetryObject.identifier.key;
});
done = false;
});
it('fetches historical data for the time period specified by the conductor bounds', function () {
@@ -290,37 +292,40 @@ define(
});
describe('populates table columns', function () {
var domainMetadata;
var allMetadata;
var mockTimeSystem1;
var mockTimeSystem2;
var mockTimeSystem;
beforeEach(function () {
domainMetadata = [{
key: "column1",
name: "Column 1",
hints: {}
}];
allMetadata = [{
key: "column1",
name: "Column 1",
hints: {
domain: 1
}
hints: {}
}, {
key: "column2",
name: "Column 2",
hints: {
domain: 2
}
hints: {}
}, {
key: "column3",
name: "Column 3",
hints: {}
}];
mockTimeSystem1 = {
mockTimeSystem = {
key: "column1"
};
mockTimeSystem2 = {
key: "column2"
};
mockConductor.timeSystem.and.returnValue(mockTimeSystem1);
mockTelemetryAPI.commonValuesForHints.and.callFake(function (metadata, hints) {
if (_.eq(hints, ["domain"])) {
return domainMetadata;
}
});
mockTelemetryAPI.getMetadata.and.returnValue({
values: function () {
@@ -340,12 +345,9 @@ define(
});
it('and sorts by column matching time system', function () {
expect(mockScope.defaultSort).not.toEqual("Column 1");
controller.sortByTimeSystem(mockTimeSystem);
expect(mockScope.defaultSort).toEqual("Column 1");
mockConductor.timeSystem.and.returnValue(mockTimeSystem2);
controller.sortByTimeSystem();
expect(mockScope.defaultSort).toEqual("Column 2");
});
it('batches processing of rows for performance when receiving historical telemetry', function () {
@@ -401,16 +403,25 @@ define(
describe('when telemetry is added', function () {
var testRows;
var expectedRows;
beforeEach(function () {
testRows = [{ a: 0 }, { a: 1 }, { a: 2 }];
mockScope.rows = [{ a: -1 }];
expectedRows = mockScope.rows.concat(testRows);
spyOn(controller.telemetry, "on").and.callThrough();
controller.registerChangeListeners();
controller.telemetry.add(testRows);
controller.telemetry.on.calls.all().forEach(function (call) {
if (call.args[0] === 'added') {
call.args[1](testRows);
}
});
});
it("Adds the rows to the MCTTable directive", function () {
expect(mockScope.$broadcast).toHaveBeenCalledWith("add:rows", testRows);
it("adds it to rows in scope", function () {
expect(mockScope.rows).toEqual(expectedRows);
});
});
});

View File

@@ -21,29 +21,597 @@
*****************************************************************************/
define([
"text!./res/templates/deprecated-timeline-message.html",
"./src/actions/ExportTimelineAsCSVAction",
"./src/controllers/TimelineController",
"./src/controllers/TimelineGraphController",
"./src/controllers/TimelineDateTimeController",
"./src/controllers/TimelineZoomController",
"./src/controllers/TimelineTickController",
"./src/controllers/TimelineTableController",
"./src/controllers/TimelineGanttController",
"./src/controllers/TimelineTOIController",
"./src/controllers/ActivityModeValuesController",
"./src/capabilities/ActivityTimespanCapability",
"./src/capabilities/TimelineTimespanCapability",
"./src/capabilities/UtilizationCapability",
"./src/capabilities/GraphCapability",
"./src/capabilities/CostCapability",
"./src/directives/MCTSwimlaneDrop",
"./src/directives/MCTSwimlaneDrag",
"./src/directives/MCTResourceGraphDrop",
"./src/services/ObjectLoader",
"./src/chart/MCTTimelineChart",
"text!./res/templates/values.html",
"text!./res/templates/timeline.html",
"text!./res/templates/activity-gantt.html",
"text!./res/templates/tabular-swimlane-cols-tree.html",
"text!./res/templates/tabular-swimlane-cols-data.html",
"text!./res/templates/resource-graphs.html",
"text!./res/templates/resource-graph-labels.html",
"text!./res/templates/legend-item.html",
"text!./res/templates/ticks.html",
"text!./res/templates/controls/datetime.html",
'legacyRegistry'
], function (
deprecatedTimelineMessage,
ExportTimelineAsCSVAction,
TimelineController,
TimelineGraphController,
TimelineDateTimeController,
TimelineZoomController,
TimelineTickController,
TimelineTableController,
TimelineGanttController,
TimelineTOIController,
ActivityModeValuesController,
ActivityTimespanCapability,
TimelineTimespanCapability,
UtilizationCapability,
GraphCapability,
CostCapability,
MCTSwimlaneDrop,
MCTSwimlaneDrag,
MCTResourceGraphDrop,
ObjectLoader,
MCTTimelineChart,
valuesTemplate,
timelineTemplate,
activityGanttTemplate,
tabularSwimlaneColsTreeTemplate,
tabularSwimlaneColsDataTemplate,
resourceGraphsTemplate,
resourceGraphLabelsTemplate,
legendItemTemplate,
ticksTemplate,
datetimeTemplate,
legacyRegistry
) {
legacyRegistry.register('platform/features/timeline', {
extensions: {
types: [
legacyRegistry.register("platform/features/timeline", {
"name": "Timelines",
"description": "Resources, templates, CSS, and code for Timelines.",
"resources": "res",
"extensions": {
"actions": [
{
key: "timeline",
name: "Timeline",
description: "Timeline, Activity and Activity Mode objects have been deprecated and will no longer be supported. (07/18/2018)",
priority: 502
"key": "timeline.export",
"name": "Export Timeline as CSV",
"category": "contextual",
"implementation": ExportTimelineAsCSVAction,
"depends": [
"$log",
"exportService",
"notificationService",
"resources[]"
]
}
],
views: [
"constants": [
{
key: "timeline",
name: "Timeline",
type: "timeline",
description: "Timeline, Activity and Activity Mode objects have been deprecated and will no longer be supported. (07/18/2018)",
template: deprecatedTimelineMessage
"key": "TIMELINE_MINIMUM_DURATION",
"description": "The minimum duration to display in a timeline view (one hour.)",
"value": 3600000
},
{
"key": "TIMELINE_MAXIMUM_OFFSCREEN",
"description": "Maximum amount, in pixels, of a Gantt bar which may go off screen.",
"value": 1000
},
{
"key": "TIMELINE_ZOOM_CONFIGURATION",
"description": "Describes major tick sizes in milliseconds, and width in pixels.",
"value": {
"levels": [
1000,
2000,
5000,
10000,
20000,
30000,
60000,
120000,
300000,
600000,
1200000,
1800000,
3600000,
7200000,
14400000,
28800000,
43200000,
86400000,
86400000 * 2,
86400000 * 5,
86400000 * 10,
86400000 * 20,
86400000 * 30,
86400000 * 60,
86400000 * 120,
86400000 * 240,
86400000 * 365
],
"width": 200
}
}
],
"types": [
{
"key": "timeline",
"name": "Timeline",
"cssClass": "icon-timeline",
"description": "A time-oriented container that lets you enclose and organize other Timelines and Activities. The Timeline view provides both tabular and Gantt views as well as resource utilization graphing of Activities.",
"priority": 502,
"features": [
"creation"
],
"contains": [
"timeline",
"activity"
],
"properties": [
{
"name": "Start date/time",
"control": "timeline-datetime",
"required": true,
"property": [
"start"
],
"options": [
"SET"
]
},
{
"name": "Battery capacity (Watt-hours)",
"control": "textfield",
"required": false,
"conversion": "number",
"property": [
"capacity"
],
"pattern": "^-?\\d+(\\.\\d*)?$"
},
{
"name": "Battery starting SOC (%)",
"control": "textfield",
"required": false,
"conversion": "number",
"property": [
"startingSOC"
],
"pattern": "^([0-9](\\.\\d*)?|[1-9][0-9](\\.\\d*)?|100)%?$"
}
],
"model": {
"composition": [],
"start": {
"timestamp": 0
}
}
},
{
"key": "activity",
"name": "Activity",
"cssClass": "icon-activity",
"features": [
"creation"
],
"contains": [
"activity"
],
"description": "An event or process that starts and ends at a discrete datetime. Activities can be nested in other Activities, and can be added to Timelines. Activity Modes can be added to an Activity to define its resource utilization over time.",
"priority": 501,
"properties": [
{
"name": "Start date/time",
"control": "timeline-datetime",
"required": true,
"property": [
"start"
],
"options": [
"SET"
]
},
{
"name": "Duration",
"control": "duration",
"required": true,
"property": [
"duration"
]
}
],
"model": {
"composition": [],
"relationships": {
"modes": []
},
"start": {
"timestamp": 0
},
"duration": {
"timestamp": 0
}
}
},
{
"key": "mode",
"name": "Activity Mode",
"cssClass": "icon-activity-mode",
"features": [
"creation"
],
"description": "When a sub-system utilizes Power or Communications resources over time, you can define those values in an Activity Mode. Activity Modes can then be linked to Activities to allow resource utilization graphing and estimating in a Timeline.",
"priority": 500,
"model": {
"resources": {
"comms": 0,
"power": 0
}
},
"properties": [
{
"name": "Comms (Kbps)",
"control": "textfield",
"conversion": "number",
"pattern": "^-?\\d+(\\.\\d*)?$",
"property": [
"resources",
"comms"
]
},
{
"name": "Power (watts)",
"control": "textfield",
"conversion": "number",
"pattern": "^-?\\d+(\\.\\d*)?$",
"property": [
"resources",
"power"
]
}
]
}
],
"views": [
{
"key": "values",
"name": "Values",
"cssClass": "icon-activity-mode",
"template": valuesTemplate,
"type": "mode",
"uses": [
"cost"
],
"editable": false
},
{
"key": "timeline",
"name": "Timeline",
"cssClass": "icon-timeline",
"type": "timeline",
"description": "A time-oriented container that lets you enclose and organize other Timelines and Activities. The Timeline view provides both tabular and Gantt views as well as resource utilization graphing of Activities.",
"template": timelineTemplate,
"editable": true,
"toolbar": {
"sections": [
{
"items": [
{
"method": "add",
"control": "menu-button",
"text": "Add",
"options": [
{
"name": "Timeline",
"cssClass": "icon-timeline",
"key": "timeline"
},
{
"name": "Activity",
"cssClass": "icon-activity",
"key": "activity"
}
]
}
]
},
{
"items": [
{
"cssClass": "icon-plot-resource",
"description": "Graph Resource Utilization",
"control": "button",
"method": "toggleGraph"
},
{
"cssClass": "icon-activity-mode",
"control": "dialog-button",
"description": "Apply Activity Modes...",
"title": "Apply Activity Modes",
"dialog": {
"control": "selector",
"name": "Modes",
"type": "mode",
"layout": "controls-under"
},
"property": "modes"
},
{
"cssClass": "icon-chain-links",
"description": "Edit Activity Link",
"title": "Activity Link",
"control": "dialog-button",
"dialog": {
"control": "textfield",
"name": "Link",
"pattern": "^(ftp|https?)\\:\\/\\/\\w+(\\.\\w+)*(\\:\\d+)?(\\/\\S*)*$",
"cssClass": "l-input-lg"
},
"property": "link"
},
{
"cssClass": "icon-gear",
"description": "Edit Properties...",
"control": "button",
"method": "properties"
}
]
},
{
"items": [
{
"method": "remove",
"description": "Remove Item",
"control": "button",
"cssClass": "icon-trash"
}
]
}
]
}
}
],
"stylesheets": [
{
"stylesheetUrl": "css/timeline.css"
},
{
"stylesheetUrl": "css/timeline-espresso.css",
"theme": "espresso"
},
{
"stylesheetUrl": "css/timeline-snow.css",
"theme": "snow"
}
],
"representations": [
{
"key": "gantt",
"template": activityGanttTemplate,
"uses": [
"timespan",
"type"
]
}
],
"templates": [
{
"key": "timeline-tabular-swimlane-cols-tree",
"priority": "mandatory",
"template": tabularSwimlaneColsTreeTemplate
},
{
"key": "timeline-tabular-swimlane-cols-data",
"priority": "mandatory",
"template": tabularSwimlaneColsDataTemplate
},
{
"key": "timeline-resource-graphs",
"priority": "mandatory",
"template": resourceGraphsTemplate
},
{
"key": "timeline-resource-graph-labels",
"priority": "mandatory",
"template": resourceGraphLabelsTemplate
},
{
"key": "timeline-legend-item",
"priority": "mandatory",
"template": legendItemTemplate
},
{
"key": "timeline-ticks",
"priority": "mandatory",
"template": ticksTemplate
}
],
"controls": [
{
"key": "timeline-datetime",
"template": datetimeTemplate
},
{
"key": "duration",
"template": datetimeTemplate
}
],
"controllers": [
{
"key": "TimelineController",
"implementation": TimelineController,
"depends": [
"$scope",
"$q",
"objectLoader",
"TIMELINE_MINIMUM_DURATION"
]
},
{
"key": "TimelineGraphController",
"implementation": TimelineGraphController,
"depends": [
"$scope",
"resources[]"
]
},
{
"key": "TimelineDateTimeController",
"implementation": TimelineDateTimeController,
"depends": [
"$scope"
]
},
{
"key": "TimelineZoomController",
"implementation": TimelineZoomController,
"depends": [
"$scope",
"$window",
"TIMELINE_ZOOM_CONFIGURATION"
]
},
{
"key": "TimelineTickController",
"implementation": TimelineTickController
},
{
"key": "TimelineTableController",
"implementation": TimelineTableController
},
{
"key": "TimelineGanttController",
"implementation": TimelineGanttController,
"depends": [
"TIMELINE_MAXIMUM_OFFSCREEN"
]
},
{
"key": "TimelineTOIController",
"implementation": TimelineTOIController,
"depends": [
"openmct",
"timerService",
"$scope"
]
},
{
"key": "ActivityModeValuesController",
"implementation": ActivityModeValuesController,
"depends": [
"resources[]"
]
}
],
"capabilities": [
{
"key": "timespan",
"implementation": ActivityTimespanCapability,
"depends": [
"$q"
]
},
{
"key": "timespan",
"implementation": TimelineTimespanCapability,
"depends": [
"$q"
]
},
{
"key": "utilization",
"implementation": UtilizationCapability,
"depends": [
"$q"
]
},
{
"key": "graph",
"implementation": GraphCapability,
"depends": [
"$q"
]
},
{
"key": "cost",
"implementation": CostCapability
}
],
"directives": [
{
"key": "mctSwimlaneDrop",
"implementation": MCTSwimlaneDrop,
"depends": [
"dndService"
]
},
{
"key": "mctSwimlaneDrag",
"implementation": MCTSwimlaneDrag,
"depends": [
"dndService"
]
},
{
"key": "mctTimelineChart",
"implementation": MCTTimelineChart,
"depends": [
"$interval",
"$log"
]
},
{
"key": "mctResourceGraphDrop",
"implementation": MCTResourceGraphDrop,
"depends": [
"dndService"
]
}
],
"services": [
{
"key": "objectLoader",
"implementation": ObjectLoader,
"depends": [
"$q"
]
}
],
"resources": [
{
"key": "power",
"name": "Power",
"units": "watts"
},
{
"key": "comms",
"name": "Comms",
"units": "Kbps"
},
{
"key": "battery",
"name": "Battery State-of-Charge",
"units": "%"
}
]
}

View File

@@ -0,0 +1,77 @@
.l-timeline-gantt {
min-width: 2px;
overflow: hidden;
position: absolute;
top: $timelineSwimlaneGanttVM; bottom: $timelineSwimlaneGanttVM;
.bar {
@include ellipsize();
height: $activityBarH;
line-height: $activityBarH;
padding: 0 $interiorMargin;
span {
$iconW: 20px;
@include absPosDefault();
display: block;
&.s-activity-type {
right: auto; width: $iconW;
text-align: center;
&.timeline {
&:before {
content:"S";
}
}
&.activity {
&:before {
content:"A";
}
}
}
&.s-title {
overflow: hidden;
text-overflow: ellipsis;
left: $iconW;
}
&.duration {
left: auto;
opacity: 0.75;
right: 0;
text-align: right;
width: 60px;
}
&.handle {
top: 0;
bottom: 0;
height: auto;
width: 15px;
&.left {
right: auto;
}
&.middle {
right: 15px;
left: 15px;
width: auto;
}
&.right {
right: 0;
left: auto;
}
}
}
}
&.sm .bar span {
// Hide icon and label if width is too small
display: none;
}
}
.edit-mode .s-timeline-gantt,
.s-status-editing .s-timeline-gantt {
.handle {
cursor: col-resize;
&.mid {
cursor: ew-resize;
}
}
}

View File

@@ -0,0 +1,42 @@
/*****************************************************************************
* 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.
*****************************************************************************/
// General
$timelineHeaderColorBg: pullForward($colorBodyBg, 5%);
$timelineColorAlt1: pullForward($timelineHeaderColorBg, 10%);
$colorGanttBarBg: #5555aa;
$colorGanttBarFg: #fff;
$colorGanttBarSelectedBg: #ccc;
$colorGanttBarSelectedFg: #333;
$colorGanttBarTabularFgIcon: #8594ff;
// Swimlane colors
$colorDropTarg: rgba($colorGanttBarBg, 0.4);
$colorSwimlaneSelectedBg: #222;
$colorSwimlaneSelectedFg: #ccc;
$colorGanttToggle: $colorKey;
$shdwGanttBar: rgba(black, 0.4) 0 1px 3px;
// Resource graphs
$timelineResourceGraphBg: rgba(black, 0.2);
$timelineResourceGraphFg: $colorBodyFg;
$timelineResourceGraphLegendFg: $colorBodyFg;

View File

@@ -0,0 +1,42 @@
/*****************************************************************************
* 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.
*****************************************************************************/
// General
$timelineHeaderColorBg: pullForward($colorBodyBg, 5%);
$timelineColorAlt1: pullForward($timelineHeaderColorBg, 10%);
$colorGanttBarBg: #5555aa;
$colorGanttBarFg: #fff;
$colorGanttBarSelectedBg: $colorGanttBarBg;
$colorGanttBarSelectedFg: $colorGanttBarFg;
$colorGanttBarTabularFgIcon: #8594ff;
// Swimlane colors
$colorDropTarg: rgba($colorGanttBarBg, 0.4);
$colorSwimlaneSelectedBg: rgba($colorGanttBarBg, 0.25);
$colorSwimlaneSelectedFg: pullForward($colorBodyFg, 10%);
$colorGanttToggle: $colorKey;
$shdwGanttBar: rgba(black, 0.1) 0 1px 3px;
// Resource graphs
$timelineResourceGraphBg: $colorPlotBg;
$timelineResourceGraphFg: $colorBodyFg;
$timelineResourceGraphLegendFg: $colorBodyFg;

View File

@@ -0,0 +1,63 @@
/*****************************************************************************
* 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.
*****************************************************************************/
@mixin activityBg($bg, $gamma: 10) {
@include background-image(linear-gradient(lighten($bg, $gamma), $bg));
}
// Timeline constants
$activityBarH: 17px;
$timelinePaneLeftW: 30%;
$timelinePaneBtmH: 30%;
$timelineResourceGraphYLabelsMargin: 70px;
$timelineTopPaneHeaderH: 30px;
$timelineSwimlaneGanttVM: 2px; // The vertical space above and below the gantt bars
$timelineSwimlaneH: $activityBarH + ($timelineSwimlaneGanttVM * 2);
$timelineTopPaneHeaderElemMargin: $interiorMargin;
// Timeline Tabular constants
$timelineColIconW: 16px;
$timelineColResourcePlotW: $timelineColIconW;
$timelineColTitleW: 250px;
$timelineColDatetimeW: 110px;
$timelineColDurationW: 70px;
$timelineColActivityModesW: $timelineColTitleW;
$timelineColPadR: 50px;
$timelineTabularTitleW: $timelineColResourcePlotW + $timelineColTitleW;
$timelineTabularDataW: ($timelineColDatetimeW * 2) + $timelineColDurationW + $timelineColActivityModesW + $timelineColPadR;
// // Ported from legacy timelines SASS
$activitiesHolderM: 30px;
$scenarioTopPad: 25px;
$swimlaneVM: 2px;
$timelineVM: 10px;
$timelineBPad: $interiorMargin * 2;
$graphResourceSummaryH: 200px;
$graphResourceSummaryLegendH: 20px;
$scenarioTimelineSummaryH: 20px;
$scenarioTimelineSummaryHExpanded: $graphResourceSummaryH + 30px;
$scenarioPanZoomSliderH: 16px;
$scenarioTicksH: 7px;
$scenarioTickLabelsH: 10px;

View File

@@ -0,0 +1,185 @@
/*****************************************************************************
* 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.
*****************************************************************************/
.l-timeline-holder {
.l-timeline-pane {
&.t-pane-h {
&.l-timeline-resource-legend {
.l-legend-items {
color: $timelineResourceGraphLegendFg;
}
}
}
}
// Follow Line
.l-follow-line {
// TODO: move before and after into l-timeline-gantt so those only render in that pane
pointer-events: none;
position: absolute;
top: 0; bottom: 0;
width: 1px;
z-index: 9; // Just below .l-hover-btns-holder
}
}
.l-timeline-gantt {
.l-follow-line {
$d: 0.8rem;
top: $interiorMargin;
&:before,
&:after {
content: '';
display: block;
height: $d;
width: $d;
position: absolute;
top: 0;
transform: translateX(-50%);
}
&:before {
// Icon blocker
width: 2 * $d;
}
&:after {
// Icon
font-size: $d;
line-height: $d;
text-align: center;
}
}
}
.s-timeline-gantt {
.bar {
color: $colorGanttBarFg;
@include activityBg($colorGanttBarBg);
box-shadow: $shdwGanttBar;
.s-toggle {
color: $colorGanttToggle;
}
}
}
.s-timeline-tabular {
.l-header .l-cols {
.l-col {
border-left: 1px solid pullForward($timelineHeaderColorBg, 15%);
}
}
.l-pane-l {
// Left pane of the tabular area
.l-cols {
.t-object-label .t-item-icon {
color: pullForward($colorGanttBarBg, 10%);
}
}
}
}
.edit-mode .s-timeline-gantt,
.s-status-editing .s-timeline-gantt {
.bar {
&:hover {
@include background-image(linear-gradient(lighten($colorGanttBarBg, 20), lighten($colorGanttBarBg, 10)));
}
}
}
//*************************************************************** STYLING
.s-timeline {
font-size: 0.75rem;
.s-header {
background-color: $timelineHeaderColorBg;
}
.s-swimlane {
border-bottom: 1px solid pullForward($colorBodyBg, 10%);
line-height: $activityBarH + 2 + 1;
&.exceeded {
@include bgDiagonalStripes(#fff, 0.05, $timelineSwimlaneH + 1);
}
&.selected {
background-color: $colorSwimlaneSelectedBg;
color: $colorSwimlaneSelectedFg;
.s-timeline-gantt .bar {
@include activityBg($colorGanttBarSelectedBg, 10);
color: $colorGanttBarSelectedFg;
}
}
&.drop-into {
background-color: rgba($colorDropTarg, 0.7);
.s-timeline-gantt {
opacity: 0.7;
}
}
&.drop-after {
background-color: rgba(#000, 0.2);
border-bottom-color: rgba($colorDropTarg, 1.0);
}
}
.s-ticks {
@include bgTicks( $timelineColorAlt1);
}
.s-hover-btns-holder {
$bg: $timelineHeaderColorBg;
$l: 5%;
@include user-select(none);
@include background-image(linear-gradient(-90deg, rgba($bg, 1), rgba($bg, 1) 75%, rgba($bg, 0) 100%));
}
.l-timeline-resource-graph {
.l-graph {
background: $timelineResourceGraphBg;
}
.l-title {
color: $timelineResourceGraphFg;
}
}
.s-follow-line {
background: rgba($timeControllerToiLineColor, 0.5);
}
.s-timeline-gantt {
.s-follow-line {
&:after {
// Icon
color: $timeControllerToiLineColor;
content: $glyph-icon-timer;
font-family: symbolsfont;
text-shadow: $shdwItemText;
}
&:before {
// Blocker
$bg: $timelineHeaderColorBg;
$l: 30%;
@include background-image(linear-gradient(90deg, rgba($bg, 0), rgba($bg, 1) $l, rgba($bg, 1) 100% - $l, rgba($bg, 0)));
}
}
}
}

View File

@@ -0,0 +1,333 @@
/*****************************************************************************
* 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.
*****************************************************************************/
//*************************************************************** LAYOUT
.l-timeline-holder {
@include absPosDefault();
&.split-layout {
>.splitter {
// Top of splitter within Timelines should be 0
top: 0;
}
}
.l-header {
@include user-select(none);
cursor: default;
}
.l-timeline-pane {
@include absPosDefault();
&.drop-over {
background-color: lighten($colorEditAreaBg, 5%);
}
.l-width-control {
position: relative;
}
.l-swimlanes-holder {
@include absPosDefault();
top: $timelineTopPaneHeaderH + 1;
.l-col.l-plot-resource {
cursor: pointer;
}
}
// Overall layout
&.t-pane-h {
&.s-timeline-tabular .t-pane-v {
// Vertical panes within tabular area
@include absPosDefault();
&.l-tabular-l {
// Tree area with item title
right: auto; // Set this to auto and uncomment width below when additional tabular columns are added
width: $timelineTabularTitleW;
.l-swimlanes-holder {
bottom: $scrollbarTrackSize;
}
}
&.l-tabular-r {
// Start, end, duration, activity modes columns
@include scrollH(scroll);
left: $timelineTabularTitleW;
.l-width {
@include absPosDefault(0, visible);
min-width: $timelineTabularDataW;
width: 100%;
}
}
}
&.l-timeline-gantt {
.abs.l-timeline-gantt-header-w {
overflow: hidden;
height: $timelineTopPaneHeaderH;
}
.l-swimlanes-holder {
@include scrollV(scroll);
bottom: $scrollbarTrackSize;
}
}
&.l-timeline-resource-legend {
box-sizing: border-box;
padding: $interiorMargin 0;
white-space: nowrap;
.l-legend-items {
@include absPosDefault();
@include scrollV();
top: 25px;
}
.legend-item {
// Inherits from /platform/commonUI/general/res/sass/plots/_plots-main.scss
display: block;
margin-bottom: $interiorMarginSm;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.color-swatch {
vertical-align: baseline;
}
.title-label {
vertical-align: baseline;
}
}
}
&.l-timeline-resource-graph {
$m: $interiorMargin;
.l-graphs-holder {
@include absPosDefault();
bottom: $scrollbarTrackSize;
.l-graphs {
@include absPosDefault();
@include scrollV(scroll);
}
.l-graph-labels-holder {
@include absPosDefault();
overflow: hidden;
right: auto;
width: 400px;
}
}
.l-scroll-control {
@include absPosDefault();
overflow-x: scroll;
overflow-y: hidden;
top: auto; right: $scrollbarTrackSize;
height: $scrollbarTrackSize;
.l-width-control {
height: 10px; // Need to add height to force scrollbar to appear
}
}
.l-graph,
.l-graph-labels {
height: 80px;
margin-bottom: $interiorMarginSm;
position: relative;
}
.l-title {
@include ellipsize();
top: $m; left: $m;
position: absolute;
}
.l-graph {
width: 100%;
.l-graph-area {
canvas {
width: 100%;
height: 100%;
}
}
}
.l-graph-labels {
z-index: 10;
}
.l-graph-area {
@include absPosDefault();
top: 20px; bottom: 5px;
.l-labels-holder {
@include absPosDefault();
justify-content: space-between;
left: $m;
.t-resource-graph-tick-label {
font-size: 0.9em;
&.tick-label-y {
text-align: left;
}
}
}
}
}
}
&.l-pane-l {
right: auto;
min-width: 50px;
max-width: 90%;
width: $timelinePaneLeftW;
}
&.l-pane-r {
left: 0;
}
&.l-pane-top {
bottom: $timelinePaneBtmH;
}
&.l-pane-btm {
top: auto;
min-height: 20px;
max-height: 80%;
height: $timelinePaneBtmH;
}
}
.l-swimlane {
height: $timelineSwimlaneH;
position: relative;
}
// Header
.s-timeline-tabular .l-header,
.s-timeline-gantt .l-header {
@include absPosDefault(0, visible);
bottom: auto; height: $timelineTopPaneHeaderH;
.l-header-elem {
@include absPosDefault($timelineTopPaneHeaderElemMargin, visible);
display: block;
&.l-labels {
.l-label {
position: absolute;
width: 140px;
margin-left: -70px;
text-align: center;
}
}
}
}
.l-hover-btns-holder {
@include absPosDefault();
box-sizing: border-box;
height: $timelineTopPaneHeaderH;
left: auto;
padding: $interiorMargin $interiorMargin $interiorMargin $interiorMargin * 10;
text-align: right;
z-index: 10;
}
// Tabular Columns
.l-cols {
@include absPosDefault(0, visible);
text-wrap: none;
white-space: nowrap;
.l-col {
box-sizing: border-box;
@include ellipsize();
display: inline-block;
height: 100%;
padding: 0 $interiorMargin;
position: relative;
text-wrap: none;
white-space: nowrap;
&.l-col-icon {
width: $timelineColIconW;
text-align: center;
padding: 0;
}
&.l-plot-resource {
border-left: none !important;
padding-left: 0;
}
&.l-title {
width: $timelineColTitleW;
.rep-object-label {
border-radius: $basicCr;
display: inline-block;
padding: 0 $interiorMargin;
}
}
&.l-start,
&.l-end,
&.l-duration {
width: $timelineColDatetimeW;
}
&.l-activity-modes {
display: none; // Temp, until modes can be displayed
width: $timelineColActivityModesW;
}
}
}
.s-timeline-tabular {
.l-header .l-cols {
top: $timelineTopPaneHeaderElemMargin; bottom: $timelineTopPaneHeaderElemMargin;
}
.l-pane-l {
// Left pane of the tabular area
.l-cols {
left: $timelineTopPaneHeaderElemMargin;
}
}
}
// Ticks
.l-ticks,
.l-subticks {
@include absPosDefault();
top: auto; bottom: $interiorMarginSm;
}
.l-ticks {
height: 10px
}
.l-subticks {
height: 5px
}
}
.s-status-editing .l-title .rep-object-label[draggable="true"] {
@include transition(background-color, 0.25s);
cursor: pointer;
&:hover {
background-color: $colorItemTreeHoverBg;
}
}

View File

@@ -19,22 +19,15 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
$output-bourbon-deprecation-warnings: false;
@import "bourbon";
define(
[],
function () {
function MCTIndicators(openmct) {
return {
restrict: "E",
link: function link(scope, element) {
openmct.indicators.indicatorElements
.forEach(function (indicatorElement) {
element.append(indicatorElement);
});
}
};
}
@import "../../../../commonUI/general/res/sass/constants";
@import "../../../../commonUI/general/res/sass/mixins";
@import "../../../../commonUI/general/res/sass/glyphs";
@import "../../../../commonUI/themes/espresso/res/sass/constants";
@import "../../../../commonUI/themes/espresso/res/sass/mixins";
@import "constants";
@import "constants-espresso";
@import "timeline-thematic";
return MCTIndicators;
}
);

View File

@@ -0,0 +1,32 @@
/*****************************************************************************
* 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.
*****************************************************************************/
$output-bourbon-deprecation-warnings: false;
@import "bourbon";
@import "../../../../commonUI/general/res/sass/constants";
@import "../../../../commonUI/general/res/sass/mixins";
@import "../../../../commonUI/general/res/sass/glyphs";
@import "../../../../commonUI/themes/snow/res/sass/constants";
@import "../../../../commonUI/themes/snow/res/sass/mixins";
@import "constants";
@import "constants-snow";
@import "timeline-thematic";

View File

@@ -0,0 +1,32 @@
/*****************************************************************************
* 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.
*****************************************************************************/
$output-bourbon-deprecation-warnings: false;
@import "bourbon";
@import "../../../../commonUI/general/res/sass/constants";
@import "../../../../commonUI/general/res/sass/mixins";
@import "../../../../commonUI/general/res/sass/glyphs";
@import "../../../../commonUI/themes/espresso/res/sass/constants";
@import "../../../../commonUI/themes/espresso/res/sass/mixins";
@import "constants";
@import "activities";
@import "timelines";

View File

@@ -0,0 +1,38 @@
<!--
Open MCT, Copyright (c) 2009-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class="t-timeline-gantt l-timeline-gantt s-timeline-gantt"
ng-class="timespan ? { sm: gantt.width(timespan, parameters.scroll, parameters.toPixels) < 25 } : {}"
title="{{model.name}}"
ng-controller="TimelineGanttController as gantt"
ng-style="timespan ? {
left: gantt.left(timespan, parameters.scroll, parameters.toPixels) + 'px',
width: gantt.width(timespan, parameters.scroll, parameters.toPixels) + 'px'
} : {}">
<div class="bar">
<span class="s-activity-type {{type.getCssClass()}}"></span>
<span class="s-title">
{{model.name}}
</span>
</div>
</div>

View File

@@ -0,0 +1,83 @@
<!--
Open MCT, Copyright (c) 2009-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class='form-control complex datetime'>
<div class='field-hints'>
<span class='hint time sm'>Days</span>
<span class='hint time sm'>Hours</span>
<span class='hint time sm'>Minutes</span>
<span class='hint time sm'>Seconds</span>
<span class='hint' ng-if="structure.options.length > 0">Time System</span>
</div>
<ng-form name="mctControl">
<div class='fields' ng-controller="TimelineDateTimeController">
<span class='field control time sm'>
<input type='text'
name='days'
min='0'
max='9999'
integer
ng-pattern="/\d+/"
ng-model='datetime.days'/>
</span>
<span class='field control time sm'>
<input type='text'
name='hour'
maxlength='2'
min='0'
max='23'
integer
ng-pattern='/\d+/'
ng-model="datetime.hours"/>
</span>
<span class='field control time sm'>
<input type='text'
name='min'
maxlength='2'
min='0'
max='59'
integer
ng-pattern='/\d+/'
ng-model="datetime.minutes"
ng-required='true'/>
</span>
<span class='field control time sm'>
<input type='text'
name='sec'
maxlength='2'
min='0'
max='59'
integer
ng-pattern='/\d+/'
ng-model="datetime.seconds"
ng-required='true'/>
</span>
<span ng-if="structure.options.length > 0"
class='field control'>
SET
</span>
</div>
</ng-form>
</div>

View File

@@ -1,10 +0,0 @@
<div>
Timeline, Activity and Activity Mode objects have been deprecated and will no longer be supported.
</div>
<div>
Please open an issue in the
<a href="https://github.com/nasa/openmct/issues" target="_blank">
Open MCT Issue tracker
</a>
if you have any questions about the timeline plugin.
</div>

View File

@@ -0,0 +1,34 @@
<!--
Open MCT, Copyright (c) 2009-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<!-- TO-DO: make legend item color-swatch dynamic -->
<span
class="legend-item s-legend-item"
title="{{ngModel.path}}{{ngModel.domainObject.getModel().name}}"
>
<span class="color-swatch"
ng-style="{ 'background-color': ngModel.color() }">
</span>
<span class="title-label">
<span class="l-parent-path">{{ngModel.path}}</span>
<span class="l-leaf-title">{{ngModel.domainObject.getModel().name}}</span>
</span>
</span>

View File

@@ -0,0 +1,37 @@
<!--
Open MCT, Copyright (c) 2009-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class="l-title s-title">
{{parameters.title}}
</div>
<div class="l-graph-area">
<div class="l-labels-holder l-flex-col">
<div class="t-resource-graph-tick-label tick-label-y flex-elem">
{{parameters.high}}
</div>
<div class="t-resource-graph-tick-label tick-label-y flex-elem">
{{parameters.middle}}
</div>
<div class="t-resource-graph-tick-label tick-label-y flex-elem">
{{parameters.low}}
</div>
</div>
</div>

View File

@@ -0,0 +1,34 @@
<!--
Open MCT, Copyright (c) 2009-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<span ng-controller="TimelineGraphController as graphController">
<div class="t-graph l-graph" ng-repeat="graph in parameters.graphs">
<div class="l-graph-area l-canvas-holder">
<mct-timeline-chart draw="graph.drawingObject"></mct-timeline-chart>
</div>
<div class="t-graph-labels l-graph-labels">
<mct-include key="'timeline-resource-graph-labels'"
parameters="graphController.label(graph)"
ng-model="graph">
</mct-include>
</div>
</div>
</span>

View File

@@ -0,0 +1,37 @@
<!--
Open MCT, Copyright (c) 2009-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class="t-swimlane s-swimlane l-swimlane {{ngModel.activitystate}} {{ngModel.swimlanestate}}"
ng-class="{
exceeded: ngModel.exceeded(),
selected: ngModel.selected(swimlane),
'drop-into': ngModel.highlight(),
'drop-after': ngModel.highlightBottom()
}">
<div
class="l-cols"
ng-controller="TimelineTableController as tabularVal">
<span class="align-right l-col l-start">{{tabularVal.niceTime(ngModel.timespan().getStart())}}</span>
<span class="align-right l-col l-end">{{tabularVal.niceTime(ngModel.timespan().getEnd())}}</span>
<span class="align-right l-col l-duration">{{tabularVal.niceTime(ngModel.timespan().getDuration())}}</span>
<span class="l-col l-activity-modes"></span>
</div>
</div>

View File

@@ -0,0 +1,57 @@
<!--
Open MCT, Copyright (c) 2009-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class="t-swimlane s-swimlane l-swimlane {{ngModel.activitystate}} {{ngModel.swimlanestate}}"
mct-swimlane-drop="ngModel"
ng-class="{
exceeded: ngModel.exceeded(),
selected: ngModel.selected(swimlane),
'drop-into': ngModel.highlight(),
'drop-after': ngModel.highlightBottom()
}">
<div class="l-cols">
<span class="l-col l-col-icon l-plot-resource"
ng-click="ngModel.toggleGraph(); parameters.commit()"
title="Click to enable or disable inclusion in Resource Graphing">
<span class="icon-plot-resource s-toggle-icon"
ng-class="{ active: ngModel.graph() }">
</span>
</span>
<span class="l-col l-col-icon l-link">
<a class="icon-chain-links"
target="_blank"
ng-href="{{ngModel.link()}}"
ng-if="ngModel.link().length > 0"
title="{{ngModel.link()}}"
>
</a>
</span>
<span class="l-col l-title"
ng-click="ngModel.select()"
ng-style="{ 'margin-left': 15 * ngModel.depth + 'px' }">
<mct-representation key="'label'"
mct-object="ngModel.domainObject"
class="rep-object-label"
mct-swimlane-drag="ngModel">
</mct-representation>
</span>
</div>
</div>

View File

@@ -0,0 +1,39 @@
<!--
Open MCT, Copyright (c) 2009-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class="t-header l-header s-header"
ng-controller="TimelineTickController as tick"
ng-style="{ width: parameters.fullWidth + 'px' }">
<div class="l-header-elem t-labels l-labels">
<div class="t-label l-label s-label"
ng-repeat="label in tick.labels(parameters.start, parameters.width, parameters.step, parameters.toMillis)"
ng-style="{ left: label.left + 'px' }">
{{label.text}}
</div>
</div>
<div class="t-ticks l-ticks s-ticks"
ng-style="{ 'background-size': parameters.step + 'px 100%' }">
</div>
<div class="t-ticks s-ticks l-subticks"
ng-style="{ 'background-size': (parameters.step / 40) + 'px 100%' }">
</div>
</div>

View File

@@ -0,0 +1,223 @@
<!--
Open MCT, Copyright (c) 2009-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class="s-timeline l-timeline-holder split-layout vertical splitter-sm"
ng-click="$event.stopPropagation()"
ng-controller="TimelineController as timelineController">
<mct-split-pane anchor="left" class="abs" position="pane.x">
<!-- LEFT PANE: TABULAR AND RESOURCE LEGEND AREAS -->
<mct-split-pane anchor="bottom"
position="pane.y"
class="abs horizontal split-pane-component l-timeline-pane l-pane-l t-pane-v">
<!-- TOP PANE TABULAR AREA -->
<div class="split-pane-component s-timeline-tabular l-timeline-pane t-pane-h l-pane-top">
<!-- TABULAR LEFT FIXED AREA -->
<div class="t-pane-v l-pane-l l-tabular-l"
ng-if="true">
<div class="t-header l-header s-header">
<div class="l-cols">
<span title="Resource Graphing: click a row to toggle" class="l-col l-col-icon l-plot-resource icon-plot-resource"></span>
<span title="Activity Links" class="l-col l-col-icon l-col-link icon-chain-links"></span>
<span class="l-col l-title">Title</span>
</div>
</div>
<div class="t-swimlanes-holder l-swimlanes-holder"
mct-scroll-y="scroll.y">
<mct-include key="'timeline-tabular-swimlane-cols-tree'"
parameters="{ commit: commit }"
ng-repeat="swimlane in timelineController.swimlanes()"
ng-model="swimlane">
</mct-include>
</div>
</div>
<!-- TABULAR RIGHT HORZ SCROLLING AREA -->
<div class="t-pane-v l-pane-r l-tabular-r">
<div class="l-width">
<div class="t-header l-header s-header">
<div class="l-cols">
<span class="l-col l-start">Start</span>
<span class="l-col l-end">End</span>
<span class="l-col l-duration">Duration</span>
<span class="l-col l-activity-modes">Activity Modes</span>
</div>
</div>
<div class="t-swimlanes-holder l-swimlanes-holder"
mct-scroll-y="scroll.y">
<mct-include key="'timeline-tabular-swimlane-cols-data'"
ng-repeat="swimlane in timelineController.swimlanes()"
ng-model="swimlane">
</mct-include>
</div>
</div>
</div>
</div>
<!-- HORZ SPLITTER -->
<mct-splitter></mct-splitter>
<!-- BOTTOM PANE RESOURCE LEGEND -->
<div mct-resource-graph-drop
class="split-pane-component abs l-timeline-pane t-pane-h l-pane-btm s-timeline-resource-legend l-timeline-resource-legend">
<div class="l-title s-title">{{ngModel.title}}Resource Graph Legend</div>
<div class="l-legend-items legend">
<mct-include key="'timeline-legend-item'"
ng-repeat="swimlane in timelineController.swimlanes()"
ng-model="swimlane"
ng-show="swimlane.graph()">
</mct-include>
</div>
</div>
</mct-split-pane>
<!-- MAIN VERTICAL SPLITTER -->
<mct-splitter></mct-splitter>
<!-- RIGHT PANE: GANTT AND RESOURCE PLOTS -->
<span ng-controller="TimelineZoomController as zoomController" class="abs">
<span class="toi-control-holder temp" ng-controller="TimelineTOIController as toiController">
<mct-split-pane anchor="bottom"
position="pane.y"
class="abs split-pane-component l-timeline-pane l-pane-r t-pane-v">
<!-- TOP PANE GANTT BARS -->
<div class="split-pane-component l-timeline-pane t-pane-h l-pane-top t-timeline-gantt l-timeline-gantt s-timeline-gantt">
<div class="h-local-controls l-hover-btns-holder s-hover-btns-holder">
<a class="s-button icon-timer"
ng-click="scroll.follow = true"
ng-show="!toiController.isFollowing() && toiController.isActive()"
title="Follow time bounds">
</a>
<div class="l-btn-set">
<a class="s-button icon-reset"
ng-click="scroll.follow = false; zoomController.fit()"
ng-show="true"
title="Zoom to fit">
</a>
<a class="s-button icon-magnify-in"
ng-click="scroll.follow = false; zoomController.zoom(-1)"
ng-show="true"
title="Zoom in">
</a>
<a class="s-button icon-magnify-out"
ng-click="scroll.follow = false; zoomController.zoom(1)"
ng-show="true"
title="Zoom out">
</a>
</div>
</div>
<div style="overflow: hidden; position: absolute; left: 0; top: 0; right: 0; height: 30px;" mct-scroll-x="scroll.x">
<mct-include key="'timeline-ticks'"
parameters="{
fullWidth: zoomController.width(timelineController.end()),
start: scroll.x,
width: scroll.width,
step: zoomController.toPixels(zoomController.zoom()),
toMillis: zoomController.toMillis
}">
</mct-include>
</div>
<div ng-if="toiController.isActive()" class="l-follow-line s-follow-line"
ng-style="{ left: toiController.x() - scroll.x + 'px' }"></div>
<div class="t-swimlanes-holder l-swimlanes-holder"
mct-scroll-x="scroll.x"
mct-scroll-y="scroll.y">
<div class="l-width-control"
ng-style="{ width: zoomController.width(timelineController.end()) + 'px' }">
<div class="t-swimlane s-swimlane l-swimlane"
ng-repeat="swimlane in timelineController.swimlanes()"
ng-class="{
exceeded: swimlane.exceeded(),
selected: selection.selected(swimlane),
'drop-into': swimlane.highlight(),
'drop-after': swimlane.highlightBottom()
}"
ng-click="selection.select(swimlane)"
mct-swimlane-drop="swimlane">
<mct-representation key="'gantt'"
mct-object="swimlane.domainObject"
parameters="{
scroll: scroll,
toPixels: zoomController.toPixels
}">
</mct-representation>
<span ng-if="selection.selected(swimlane)">
<span ng-repeat="handle in timelineController.handles()"
ng-style="handle.style(zoomController)"
style="position: absolute; top: 0px; bottom: 0px;"
class="handle"
ng-class="{ start: $index === 0, mid: $index === 1, end: $index > 1 }"
mct-drag-down="handle.begin()"
mct-drag="handle.drag(delta[0], zoomController); timelineController.refresh()"
mct-drag-up="handle.finish()">
</span>
</span>
</div>
</div>
</div>
</div>
<!-- HORZ SPLITTER -->
<mct-splitter></mct-splitter>
<!-- BOTTOM PANE RESOURCE GRAPHS AND RIGHT PANE HORIZONTAL SCROLL CONTROL -->
<div class="split-pane-component l-timeline-resource-graph l-timeline-pane t-pane-h l-pane-btm">
<div class="l-graphs-holder"
mct-resize="scroll.width = bounds.width">
<div class="t-graphs l-graphs">
<mct-include key="'timeline-resource-graphs'"
parameters="{
origin: zoomController.toMillis(scroll.x),
duration: zoomController.toMillis(scroll.width),
graphs: timelineController.graphs()
}">
</mct-include>
</div>
<div ng-if="toiController.isActive()" class="l-follow-line s-follow-line"
ng-style="{ left: toiController.x() - scroll.x + 'px' }"></div>
</div>
<div mct-scroll-x="scroll.x"
class="t-pane-r-scroll-h-control l-scroll-control s-scroll-control">
<div class="l-width-control"
ng-style="{ width: zoomController.width(timelineController.end()) + 'px' }">
</div>
</div>
</div>
</mct-split-pane>
</span>
</span>
</mct-split-pane>
</div>

View File

@@ -0,0 +1,27 @@
<!--
Open MCT, Copyright (c) 2009-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<ul ng-controller="ActivityModeValuesController as controller" class="cols cols-2-ff properties">
<li ng-repeat="(key, value) in cost" class="l-row s-row">
<span class="col col-100px s-title">{{controller.metadata(key).name}}</span>
<span class="col s-value">{{value}} {{controller.metadata(key).units}}</span>
</li>
</ul>

View File

@@ -0,0 +1,31 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/**
* Defines constant values for use in timeline view.
*/
define({
// Pixel width of start/end handles
HANDLE_WIDTH: 32,
// Pixel tolerance for snapping behavior
SNAP_WIDTH: 16
});

View File

@@ -0,0 +1,76 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
[],
function () {
// Conversion factors from time units to milliseconds
var SECONDS = 1000,
MINUTES = SECONDS * 60,
HOURS = MINUTES * 60,
DAYS = HOURS * 24;
/**
* Formatters for durations shown in a timeline view.
* @constructor
*/
function TimelineFormatter() {
// Format a numeric value to a string with some number of digits
function formatValue(value, digits) {
var v = value.toString(10);
// Pad with zeroes
while (v.length < digits) {
v = "0" + v;
}
return v;
}
// Format duration to string
function formatDuration(duration) {
var days = Math.floor(duration / DAYS),
hours = Math.floor(duration / HOURS) % 24,
minutes = Math.floor(duration / MINUTES) % 60,
seconds = Math.floor(duration / SECONDS) % 60,
millis = Math.floor(duration) % 1000;
return formatValue(days, 3) + " " +
formatValue(hours, 2) + ":" +
formatValue(minutes, 2) + ":" +
formatValue(seconds, 2) + "." +
formatValue(millis, 3);
}
return {
/**
* Format the provided duration.
* @param {number} duration duration, in milliseconds
* @returns {string} displayable representation of duration
*/
format: formatDuration
};
}
return TimelineFormatter;
}
);

View File

@@ -0,0 +1,54 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([], function () {
/**
* A column containing references to other objects contained
* in a domain object's composition.
* @param {number} index the zero-based index of the composition
* element associated with this column
* @param idMap an object containing key value pairs, where keys
* are domain object identifiers and values are whatever
* should appear in CSV output in their place
* @constructor
* @implements {platform/features/timeline.TimelineCSVColumn}
*/
function CompositionColumn(index, idMap) {
this.index = index;
this.idMap = idMap;
}
CompositionColumn.prototype.name = function () {
return "Child " + (this.index + 1);
};
CompositionColumn.prototype.value = function (domainObject) {
var model = domainObject.getModel(),
composition = model.composition || [];
return composition.length > this.index ?
this.idMap[composition[this.index]] : "";
};
return CompositionColumn;
});

View File

@@ -0,0 +1,79 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(["./ExportTimelineAsCSVTask"], function (ExportTimelineAsCSVTask) {
/**
* Implements the "Export Timeline as CSV" action.
*
* @param exportService the service used to perform the CSV export
* @param notificationService the service used to show notifications
* @param {Array} resources an array of `resources` extensions
* @param context the Action's context
* @implements {Action}
* @constructor
* @memberof {platform/features/timeline}
*/
function ExportTimelineAsCSVAction(
$log,
exportService,
notificationService,
resources,
context
) {
this.$log = $log;
this.task = new ExportTimelineAsCSVTask(
exportService,
resources,
context.domainObject
);
this.notificationService = notificationService;
}
ExportTimelineAsCSVAction.prototype.perform = function () {
var notificationService = this.notificationService,
notification = notificationService.notify({
title: "Exporting CSV",
unknownProgress: true
}),
$log = this.$log;
return this.task.run()
.then(function () {
notification.dismiss();
})
.catch(function (err) {
$log.warn(err);
notification.dismiss();
notificationService.error("Error exporting CSV");
});
};
ExportTimelineAsCSVAction.appliesTo = function (context) {
return context.domainObject &&
context.domainObject.hasCapability('type') &&
context.domainObject.getCapability('type')
.instanceOf('timeline');
};
return ExportTimelineAsCSVAction;
});

View File

@@ -0,0 +1,71 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/**
* Module defining ExportTimelineAsCSVTask. Created by vwoeltje on 2/8/16.
*/
define([
"./TimelineTraverser",
"./TimelineColumnizer"
], function (TimelineTraverser, TimelineColumnizer) {
/**
* Runs (and coordinates) the preparation and export of CSV data
* for the "Export Timeline as CSV" action.
*
* @constructor
* @memberof {platform/features/timeline}
* @param exportService the service used to export as CSV
* @param resources the `resources` extension category
* @param {DomainObject} domainObject the timeline being exported
*/
function ExportTimelineAsCSVTask(exportService, resources, domainObject) {
this.domainObject = domainObject;
this.exportService = exportService;
this.resources = resources;
}
/**
* Run this CSV export task.
*
* @returns {Promise} a promise that will be resolved when the
* export has finished (or rejected if there are problems.)
*/
ExportTimelineAsCSVTask.prototype.run = function () {
var exportService = this.exportService;
var resources = this.resources;
function doExport(objects) {
var exporter = new TimelineColumnizer(objects, resources),
options = { headers: exporter.headers() };
return exporter.rows().then(function (rows) {
return exportService.exportCSV(rows, options);
});
}
return new TimelineTraverser(this.domainObject)
.buildObjectList()
.then(doExport);
};
return ExportTimelineAsCSVTask;
});

View File

@@ -0,0 +1,46 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([], function () {
/**
* A column showing identifying domain objects.
* @constructor
* @param idMap an object containing key value pairs, where keys
* are domain object identifiers and values are whatever
* should appear in CSV output in their place
* @implements {platform/features/timeline.TimelineCSVColumn}
*/
function IdColumn(idMap) {
this.idMap = idMap;
}
IdColumn.prototype.name = function () {
return "Index";
};
IdColumn.prototype.value = function (domainObject) {
return this.idMap[domainObject.getId()];
};
return IdColumn;
});

View File

@@ -0,0 +1,48 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([], function () {
/**
* A column reflecting properties from domain object metadata.
* @constructor
* @implements {platform/features/timeline.TimelineCSVColumn}
*/
function MetadataColumn(propertyName) {
this.propertyName = propertyName;
}
MetadataColumn.prototype.name = function () {
return this.propertyName;
};
MetadataColumn.prototype.value = function (domainObject) {
var properties = domainObject.useCapability('metadata'),
name = this.propertyName;
return properties.reduce(function (value, property) {
return property.name === name ?
property.value : value;
}, "");
};
return MetadataColumn;
});

View File

@@ -0,0 +1,52 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([], function () {
/**
* A column showing relationships to activity modes.
* @constructor
* @param {number} index the zero-based index of the composition
* element associated with this column
* @param idMap an object containing key value pairs, where keys
* are domain object identifiers and values are whatever
* should appear in CSV output in their place
* @implements {platform/features/timeline.TimelineCSVColumn}
*/
function ModeColumn(index, idMap) {
this.index = index;
this.idMap = idMap;
}
ModeColumn.prototype.name = function () {
return "Activity Mode " + (this.index + 1);
};
ModeColumn.prototype.value = function (domainObject) {
var model = domainObject.getModel(),
modes = (model.relationships || {}).modes || [];
return modes.length > this.index ?
this.idMap[modes[this.index]] : "";
};
return ModeColumn;
});

View File

@@ -0,0 +1,172 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
"./IdColumn",
"./ModeColumn",
"./CompositionColumn",
"./MetadataColumn",
"./TimespanColumn",
"./UtilizationColumn"
], function (
IdColumn,
ModeColumn,
CompositionColumn,
MetadataColumn,
TimespanColumn,
UtilizationColumn
) {
/**
* A description of how to populate a given column within a
* prepared table of domain object data, for CSV export.
* @interface platform/features/timeline.TimelineCSVColumn
*/
/**
* Get the value that belongs in this column for a given
* domain object.
* @memberof {platform/features/timeline.TimelineCSVColumn#}
* @method value
* @param {DomainObject} domainObject the domain object
* represented by this row
* @returns {string|Promise<string>} the value for this cell
*/
/**
* Get the name of this column, as belongs in a header.
* @memberof {platform/features/timeline.TimelineCSVColumn#}
* @method name
* @returns {string} the name of this column
*/
/**
* Handles conversion of a list of domain objects to a table
* representation appropriate for CSV export.
*
* @param {DomainObject[]} domainObjects the objects to include
* in the exported data
* @param {Array} resources an array of `resources` extensions
* @constructor
* @memberof {platform/features/timeline}
*/
function TimelineColumnizer(domainObjects, resources) {
var maxComposition = 0,
maxRelationships = 0,
columnNames = {},
columns = [],
foundTimespan = false,
idMap,
i;
function addMetadataProperty(property) {
var name = property.name;
if (!columnNames[name]) {
columnNames[name] = true;
columns.push(new MetadataColumn(name));
}
}
idMap = domainObjects.reduce(function (map, domainObject, index) {
map[domainObject.getId()] = index + 1;
return map;
}, {});
columns.push(new IdColumn(idMap));
domainObjects.forEach(function (domainObject) {
var model = domainObject.getModel(),
composition = model.composition,
relationships = model.relationships,
modes = relationships && relationships.modes,
metadataProperties = domainObject.useCapability('metadata');
if (composition) {
maxComposition = Math.max(maxComposition, composition.length);
}
if (modes) {
maxRelationships = Math.max(maxRelationships, modes.length);
}
if (domainObject.hasCapability('timespan')) {
foundTimespan = true;
}
if (metadataProperties) {
metadataProperties.forEach(addMetadataProperty);
}
});
if (foundTimespan) {
columns.push(new TimespanColumn(true));
columns.push(new TimespanColumn(false));
}
resources.forEach(function (resource) {
columns.push(new UtilizationColumn(resource));
});
for (i = 0; i < maxComposition; i += 1) {
columns.push(new CompositionColumn(i, idMap));
}
for (i = 0; i < maxRelationships; i += 1) {
columns.push(new ModeColumn(i, idMap));
}
this.domainObjects = domainObjects;
this.columns = columns;
}
/**
* Get a tabular representation of domain object data.
* Each row corresponds to a single object; each element
* in each row corresponds to a property designated by
* the `headers`, correlated by index.
* @returns {Promise.<string[][]>} domain object data
*/
TimelineColumnizer.prototype.rows = function () {
var columns = this.columns;
function toRow(domainObject) {
return Promise.all(columns.map(function (column) {
return column.value(domainObject);
}));
}
return Promise.all(this.domainObjects.map(toRow));
};
/**
* Get the column headers associated with this tabular
* representation of objects.
* @returns {string[]} column headers
*/
TimelineColumnizer.prototype.headers = function () {
return this.columns.map(function (column) {
return column.name();
});
};
return TimelineColumnizer;
});

View File

@@ -0,0 +1,83 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([], function () {
/**
* Builds a list of domain objects which should be included
* in the CSV export of a given timeline.
* @param {DomainObject} domainObject the object being exported
* @constructor
*/
function TimelineTraverser(domainObject) {
this.domainObject = domainObject;
}
/**
* Get a list of domain objects for CSV export.
* @returns {Promise.<DomainObject[]>} a list of domain objects
*/
TimelineTraverser.prototype.buildObjectList = function () {
var idSet = {},
objects = [];
function addObject(domainObject) {
var id = domainObject.getId(),
subtasks = [];
function addCompositionObjects() {
return domainObject.useCapability('composition')
.then(function (childObjects) {
return Promise.all(childObjects.map(addObject));
});
}
function addRelationships() {
var relationship = domainObject.getCapability('relationship');
relationship.getRelatedObjects('modes')
.then(function (modeObjects) {
return Promise.all(modeObjects.map(addObject));
});
}
if (!idSet[id]) {
idSet[id] = true;
objects.push(domainObject);
if (domainObject.hasCapability('composition')) {
subtasks.push(addCompositionObjects());
}
if (domainObject.hasCapability('relationship')) {
subtasks.push(addRelationships());
}
}
return Promise.all(subtasks);
}
return addObject(this.domainObject).then(function () {
return objects;
});
};
return TimelineTraverser;
});

View File

@@ -0,0 +1,53 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(['../TimelineFormatter'], function (TimelineFormatter) {
var FORMATTER = new TimelineFormatter();
/**
* A column showing start or end times associated with a domain object.
* @constructor
* @param {boolean} isStart true if this column refers to the object's
* start time; false if it refers to the object's end time
* @implements {platform/features/timeline.TimelineCSVColumn}
*/
function TimespanColumn(isStart) {
this.isStart = isStart;
}
TimespanColumn.prototype.name = function () {
return this.isStart ? "Start" : "End";
};
TimespanColumn.prototype.value = function (domainObject) {
var isStart = this.isStart;
return domainObject.hasCapability('timespan') ?
domainObject.useCapability('timespan').then(function (timespan) {
return FORMATTER.format(
isStart ? timespan.getStart() : timespan.getEnd()
);
}) : "";
};
return TimespanColumn;
});

View File

@@ -0,0 +1,72 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([], function () {
/**
* A column showing utilization costs associated with activities.
* @constructor
* @param {string} key the key for the particular cost
* @implements {platform/features/timeline.TimelineCSVColumn}
*/
function UtilizationColumn(resource) {
this.resource = resource;
}
UtilizationColumn.prototype.name = function () {
var units = {
"Kbps": "Kb",
"watts": "watt-seconds"
}[this.resource.units] || "unknown units";
return this.resource.name + " (" + units + ")";
};
UtilizationColumn.prototype.value = function (domainObject) {
var resource = this.resource;
function getCost(utilization) {
var seconds = (utilization.end - utilization.start) / 1000;
return seconds * utilization.value;
}
function getUtilizationValue(utilizations) {
utilizations = utilizations.filter(function (utilization) {
return utilization.key === resource.key;
});
if (utilizations.length === 0) {
return "";
}
return utilizations.map(getCost).reduce(function (a, b) {
return a + b;
}, 0);
}
return domainObject.hasCapability('utilization') ?
domainObject.getCapability('utilization').internal()
.then(getUtilizationValue) :
"";
};
return UtilizationColumn;
});

View File

@@ -0,0 +1,119 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
[],
function () {
/**
* Describes the time span of an activity object.
* @param model the activity's object model
*/
function ActivityTimespan(model, mutation) {
// Get the start time for this timeline
function getStart() {
return model.start.timestamp;
}
// Get the end time for this timeline
function getEnd() {
return model.start.timestamp + model.duration.timestamp;
}
// Get the duration of this timeline
function getDuration() {
return model.duration.timestamp;
}
// Get the epoch used by this timeline
function getEpoch() {
return model.start.epoch; // Surface elapsed time
}
// Set the start time associated with this object
function setStart(value) {
var end = getEnd();
mutation.mutate(function (m) {
m.start.timestamp = Math.max(value, 0);
// Update duration to keep end time
m.duration.timestamp = Math.max(end - value, 0);
}, model.modified);
}
// Set the duration associated with this object
function setDuration(value) {
mutation.mutate(function (m) {
m.duration.timestamp = Math.max(value, 0);
}, model.modified);
}
// Set the end time associated with this object
function setEnd(value) {
var start = getStart();
mutation.mutate(function (m) {
m.duration.timestamp = Math.max(value - start, 0);
}, model.modified);
}
return {
/**
* Get the start time, in milliseconds relative to the epoch.
* @returns {number} the start time
*/
getStart: getStart,
/**
* Get the duration, in milliseconds.
* @returns {number} the duration
*/
getDuration: getDuration,
/**
* Get the end time, in milliseconds relative to the epoch.
* @returns {number} the end time
*/
getEnd: getEnd,
/**
* Set the start time, in milliseconds relative to the epoch.
* @param {number} the new value
*/
setStart: setStart,
/**
* Set the duration, in milliseconds.
* @param {number} the new value
*/
setDuration: setDuration,
/**
* Set the end time, in milliseconds relative to the epoch.
* @param {number} the new value
*/
setEnd: setEnd,
/**
* Get a string identifying the reference epoch used for
* start and end times.
* @returns {string} the epoch
*/
getEpoch: getEpoch
};
}
return ActivityTimespan;
}
);

View File

@@ -0,0 +1,61 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
['./ActivityTimespan'],
function (ActivityTimespan) {
/**
* Implements the `timespan` capability for Activity objects.
*
* @constructor
* @param $q Angular's $q, for promise-handling
* @param {DomainObject} domainObject the Activity
*/
function ActivityTimespanCapability($q, domainObject) {
// Promise time span
function promiseTimeSpan() {
return $q.when(new ActivityTimespan(
domainObject.getModel(),
domainObject.getCapability('mutation')
));
}
return {
/**
* Get the time span (start, end, duration) of this activity.
* @returns {Promise.<ActivityTimespan>} the time span of
* this activity
*/
invoke: promiseTimeSpan
};
}
// Only applies to timeline objects
ActivityTimespanCapability.appliesTo = function (model) {
return model && (model.type === 'activity');
};
return ActivityTimespanCapability;
}
);

View File

@@ -0,0 +1,50 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
[],
function () {
/**
* Provides data to populate resource graphs associated
* with activities in a timeline view.
* This is a placeholder until WTD-918.
* @constructor
*/
function ActivityUtilization() {
return {
getPointCount: function () {
return 0;
},
getDomainValue: function () {
return 0;
},
getRangeValue: function () {
return 0;
}
};
}
return ActivityUtilization;
}
);

View File

@@ -0,0 +1,75 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
[],
function () {
/**
* Exposes costs associated with a subsystem mode.
* @constructor
*/
function CostCapability(domainObject) {
var model = domainObject.getModel();
return {
/**
* Get a list of resource types which have associated
* costs for this object. Returned values are machine-readable
* keys, and should be paired with external metadata for
* presentation (see category of extension `resources`).
* @returns {string[]} resource types
*/
resources: function () {
return Object.keys(model.resources || {}).sort();
},
/**
* Get the cost associated with a resource of an identified
* type (typically, one of the types reported from a
* `resources` call.)
* @param {string} key the resource type
* @returns {number} the associated cost
*/
cost: function (key) {
return (model.resources || {})[key] || 0;
},
/**
* Get an object containing key-value pairs describing
* resource utilization as described by this object.
* Keys are resource types; values are levels of associated
* resource utilization.
* @returns {object} resource utilizations
*/
invoke: function () {
return model.resources || {};
}
};
}
// Only applies to subsystem modes.
CostCapability.appliesTo = function (model) {
return (model || {}).type === 'mode';
};
return CostCapability;
}
);

View File

@@ -0,0 +1,152 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
[],
function () {
/**
* Provide points for a cumulative resource summary graph, using
* a provided instantaneous resource summary graph.
*
* @param {ResourceGraph} graph the resource graph
* @param {number} minimum the minimum allowable level
* @param {number} maximum the maximum allowable level
* @param {number} initial the initial state of the resource
* @param {number} rate the rate at which one unit of instantaneous
* utilization changes the available level in one unit
* of domain values (that is, per millisecond)
* @constructor
*/
function CumulativeGraph(graph, minimum, maximum, initial, rate) {
var values;
// Calculate the domain value at which a line starting at
// (domain, range) and proceeding with the specified slope
// will have the specified range value.
function intercept(domain, range, slope, value) {
// value = slope * (intercept - domain) + range
// value - range = slope * ...
// intercept - domain = (value - range) / slope
// intercept = domain + (value - range) / slope
return domain + (value - range) / slope;
}
// Initialize the data values
function initializeValues() {
var vals = [],
slope = 0,
i;
// Add a point (or points, if needed) reaching to the provided
// domain and/or range value
function addPoint(domain, range) {
var previous = vals[vals.length - 1],
delta = domain - previous.domain, // time delta
change = delta * slope * rate, // change
next = previous.range + change;
// Crop to minimum boundary...
if (next < minimum) {
vals.push({
domain: intercept(
previous.domain,
previous.range,
slope * rate,
minimum
),
range: minimum
});
next = minimum;
}
// ...and maximum boundary
if (next > maximum) {
vals.push({
domain: intercept(
previous.domain,
previous.range,
slope * rate,
maximum
),
range: maximum
});
next = maximum;
}
// Add the new data value
if (delta > 0) {
vals.push({ domain: domain, range: next });
}
slope = range;
}
vals.push({ domain: 0, range: initial });
for (i = 0; i < graph.getPointCount(); i += 1) {
addPoint(graph.getDomainValue(i), graph.getRangeValue(i));
}
return vals;
}
function convertToPercent(point) {
point.range = 100 *
(point.range - minimum) / (maximum - minimum);
}
// Calculate cumulative values...
values = initializeValues();
// ...and convert to percentages.
values.forEach(convertToPercent);
return {
/**
* Get the total number of points in this graph.
* @returns {number} the total number of points
*/
getPointCount: function () {
return values.length;
},
/**
* Get the domain value (timestamp) for a point in this graph.
* @returns {number} the domain value
*/
getDomainValue: function (index) {
return values[index].domain;
},
/**
* Get the range value (utilization level) for a point in
* this graph.
* @returns {number} the range value
*/
getRangeValue: function (index) {
return values[index].range;
}
};
}
return CumulativeGraph;
}
);

View File

@@ -0,0 +1,100 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
['./ResourceGraph', './CumulativeGraph'],
function (ResourceGraph, CumulativeGraph) {
/**
* Implements the `graph` capability for Timeline and
* Activity objects.
*
* @constructor
* @param {DomainObject} domainObject the Timeline or Activity
*/
function GraphCapability($q, domainObject) {
// Build graphs for this group of utilizations
function buildGraphs(utilizations) {
var utilizationMap = {},
result = {},
startingSOC;
// Bucket utilizations by type
utilizations.forEach(function (u) {
var k = u.key;
utilizationMap[k] = utilizationMap[k] || [];
utilizationMap[k].push(u);
});
// ...then convert to graphs
Object.keys(utilizationMap).forEach(function (k) {
result[k] = new ResourceGraph(utilizationMap[k]);
});
// Add battery state of charge
if (domainObject.getModel().type === 'timeline' &&
result.power &&
domainObject.getModel().capacity > 0) {
startingSOC = isNaN(parseFloat(domainObject.getModel().startingSOC)) ?
100 : parseFloat(domainObject.getModel().startingSOC);
result.battery = new CumulativeGraph(
result.power,
0,
domainObject.getModel().capacity, // Watts
(startingSOC / 100) * domainObject.getModel().capacity,
1 / 3600000 // millis-to-hour (since units are watt-hours)
);
}
return result;
}
return {
/**
* Get resource graphs associated with this object.
* This is given as a promise for key-value pairs,
* where keys are resource types and values are graph
* objects.
* @returns {Promise} a promise for resource graphs
*/
invoke: function () {
return $q.when(
domainObject.useCapability('utilization') || []
).then(buildGraphs);
}
};
}
// Only applies to timeline objects
GraphCapability.appliesTo = function (model) {
return model &&
((model.type === 'timeline') ||
(model.type === 'activity'));
};
return GraphCapability;
}
);

View File

@@ -0,0 +1,147 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
[],
function () {
// Utility function to copy an array, sorted by a specific field
function sort(array, field) {
return array.slice().sort(function (a, b) {
return a[field] - b[field];
});
}
/**
* Provides data to populate resource graphs associated
* with timelines and activities.
* @param {Array} utilizations resource utilizations
* @constructor
*/
function ResourceGraph(utilizations) {
// Overview of algorithm here:
// * Goal: Have a list of time/value pairs which represents
// points along a stepped chart of resource utilization.
// Each change (stepping up or down) should have two points,
// at the bottom and top of the step respectively.
// * Step 1: Prepare two lists of utilizations sorted by start
// and end times. The "starts" will become step-ups, the
// "ends" will become step-downs.
// * Step 2: Initialize empty arrays for results, and a variable
// for the current utilization level.
// * Step 3: While there are still start or end times to add...
// * Step 3a: Determine whether the next change should be a
// step-up (start) or step-down (end) based on which of the
// next start/end times comes next (note that starts and ends
// are both sorted, so we look at the head of the array.)
// * Step 3b: Pull the next start or end (per previous decision)
// and convert it to a time-delta pair, negating if it's an
// end time (to step down or "un-step")
// * Step 3c: Add a point at the new time and the current
// running total (first point in the step, before the change)
// then increment the running total and add a new point
// (second point in the step, after the change)
// * Step 4: Filter out unnecessary points (if two activities
// run up against each other, there will be a zero-duration
// spike if we don't filter out the extra points from their
// start/end times.)
//
var starts = sort(utilizations, "start"),
ends = sort(utilizations, "end"),
values = [],
running = 0;
// If there are sequences of points with the same timestamp,
// allow only the first and last.
function filterPoint(value, index, vals) {
// Allow the first or last point as a base case; aside from
// that, allow only points that have different timestamps
// from their predecessor or successor.
return (index === 0) || (index === vals.length - 1) ||
(value.domain !== vals[index - 1].domain) ||
(value.domain !== vals[index + 1].domain);
}
// Add a step up or down (Step 3c above)
function addDelta(time, delta) {
values.push({ domain: time, range: running });
running += delta;
values.push({ domain: time, range: running });
}
// Add a start time (Step 3b above)
function addStart() {
var next = starts.shift();
addDelta(next.start, next.value);
}
// Add an end time (Step 3b above)
function addEnd() {
var next = ends.shift();
addDelta(next.end, -next.value);
}
// Decide whether next step should correspond to a start or
// an end. (Step 3c above)
function pickStart() {
return ends.length < 1 ||
(starts.length > 0 && starts[0].start <= ends[0].end);
}
// Build up start/end arrays (step 3 above)
while (starts.length > 0 || ends.length > 0) {
(pickStart() ? addStart : addEnd)();
}
// Filter out excess points
values = values.filter(filterPoint);
return {
/**
* Get the total number of points in this graph.
* @returns {number} the total number of points
*/
getPointCount: function () {
return values.length;
},
/**
* Get the domain value (timestamp) for a point in this graph.
* @returns {number} the domain value
*/
getDomainValue: function (index) {
return values[index].domain;
},
/**
* Get the range value (utilization level) for a point in
* this graph.
* @returns {number} the range value
*/
getRangeValue: function (index) {
return values[index].range;
}
};
}
return ResourceGraph;
}
);

View File

@@ -0,0 +1,124 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
[],
function () {
/**
* Describes the time span of a timeline object.
* @param model the timeline's object model
* @param {Timespan[]} time spans of contained activities
*/
function TimelineTimespan(model, mutation, timespans) {
// Get the start time for this timeline
function getStart() {
return model.start.timestamp;
}
// Get the end time for another time span
function getTimespanEnd(timespan) {
return timespan.getEnd();
}
// Wrapper for Math.max; used for max-finding of end time
function max(a, b) {
return Math.max(a, b);
}
// Get the end time for this timeline
function getEnd() {
return timespans.map(getTimespanEnd).reduce(max, getStart());
}
// Get the duration of this timeline
function getDuration() {
return getEnd() - getStart();
}
// Set the start time associated with this object
function setStart(value) {
mutation.mutate(function (m) {
m.start.timestamp = Math.max(value, 0);
}, model.modified);
}
// Set the duration associated with this object
function setDuration() {
// No-op; duration is implicit
}
// Set the end time associated with this object
function setEnd() {
// No-op; end time is implicit
}
// Get the epoch used by this timeline
function getEpoch() {
return model.start.epoch;
}
return {
/**
* Get the start time, in milliseconds relative to the epoch.
* @returns {number} the start time
*/
getStart: getStart,
/**
* Get the duration, in milliseconds.
* @returns {number} the duration
*/
getDuration: getDuration,
/**
* Get the end time, in milliseconds relative to the epoch.
* @returns {number} the end time
*/
getEnd: getEnd,
/**
* Set the start time, in milliseconds relative to the epoch.
* @param {number} the new value
*/
setStart: setStart,
/**
* Set the duration, in milliseconds. Timeline durations are
* implicit, so this is actually a no-op
* @param {number} the new value
*/
setDuration: setDuration,
/**
* Set the end time, in milliseconds. Timeline end times are
* implicit, so this is actually a no-op.
* @param {number} the new value
*/
setEnd: setEnd,
/**
* Get a string identifying the reference epoch used for
* start and end times.
* @returns {string} the epoch
*/
getEpoch: getEpoch
};
}
return TimelineTimespan;
}
);

View File

@@ -0,0 +1,87 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
['./TimelineTimespan'],
function (TimelineTimespan) {
/**
* Implements the `timespan` capability for Timeline objects.
*
* @constructor
* @param $q Angular's $q, for promise-handling
* @param {DomainObject} domainObject the Timeline
*/
function TimelineTimespanCapability($q, domainObject) {
// Check if a capability is defin
// Look up a child object's time span
function lookupTimeSpan(childObject) {
return childObject.useCapability('timespan');
}
// Check if a child object exposes a time span
function hasTimeSpan(childObject) {
return childObject.hasCapability('timespan');
}
// Instantiate a time span bounding other time spans
function giveTimeSpan(timespans) {
return new TimelineTimespan(
domainObject.getModel(),
domainObject.getCapability('mutation'),
timespans
);
}
// Build a time span object that fits all children
function buildTimeSpan(childObjects) {
return $q.all(
childObjects.filter(hasTimeSpan).map(lookupTimeSpan)
).then(giveTimeSpan);
}
// Promise
function promiseTimeSpan() {
return domainObject.useCapability('composition')
.then(buildTimeSpan);
}
return {
/**
* Get the time span (start, end, duration) of this timeline.
* @returns {Promise.<TimelineTimespan>} the time span of
* this timeline
*/
invoke: promiseTimeSpan
};
}
// Only applies to timeline objects
TimelineTimespanCapability.appliesTo = function (model) {
return model && (model.type === 'timeline');
};
return TimelineTimespanCapability;
}
);

View File

@@ -0,0 +1,50 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
[],
function () {
/**
* Provides data to populate resource graphs associated
* with timelines in a timeline view.
* This is a placeholder until WTD-918.
* @constructor
*/
function TimelineUtilization() {
return {
getPointCount: function () {
return 1000;
},
getDomainValue: function (index) {
return 60000 * index;
},
getRangeValue: function (index) {
return Math.sin(index) * (index % 10);
}
};
}
return TimelineUtilization;
}
);

View File

@@ -0,0 +1,224 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
[],
function () {
/**
* Provide the resource utilization over time for a timeline
* or activity object. A utilization is presented as an object
* with four properties:
* * `key`: The resource being utilized.
* * `value`: The numeric utilization of that resource.
* * `start`: The start time of the resource's utilization.
* * `end`: The duration of this resource's utilization.
* * `epoch`: The epoch to which `start` is relative.
* @constructor
*/
function UtilizationCapability($q, domainObject) {
// Utility function for array reduction
function concatenate(a, b) {
return (a || []).concat(b || []);
}
// Check whether an element in an array looks unique (for below)
function unique(element, index, array) {
return (index === 0) || (array[index - 1] !== element);
}
// Utility function to ensure sorted array is all unique
function uniquify(array) {
return array.filter(unique);
}
// Utility function for sorting strings arrays
function sort(array) {
return array.sort();
}
// Combine into one big array
function flatten(arrayOfArrays) {
return arrayOfArrays.reduce(concatenate, []);
}
// Promise the objects contained by this timeline/activity
function promiseComposition() {
return $q.when(domainObject.useCapability('composition') || []);
}
// Promise all subsystem modes associated with this object
function promiseModes() {
var relationship = domainObject.getCapability('relationship'),
modes = relationship && relationship.getRelatedObjects('modes');
return $q.when(modes || []);
}
// Promise the utilization which results directly from this object
function promiseInternalUtilization() {
var utilizations = {};
// Record the cost of a given activity mode
function addUtilization(mode) {
var cost = mode.getCapability('cost');
if (cost) {
cost.resources().forEach(function (k) {
utilizations[k] = utilizations[k] || 0;
utilizations[k] += cost.cost(k);
});
}
}
// Record costs for these modes
function addUtilizations(modes) {
modes.forEach(addUtilization);
}
// Look up start/end times for this object
function lookupTimespan() {
return domainObject.useCapability('timespan');
}
// Provide the result
function giveResult(timespan) {
// Convert to utilization objects
return Object.keys(utilizations).sort().map(function (k) {
return {
key: k,
value: utilizations[k],
start: timespan.getStart(),
end: timespan.getEnd(),
epoch: timespan.getEpoch()
};
});
}
return promiseModes()
.then(addUtilizations)
.then(lookupTimespan)
.then(giveResult);
}
// Look up a specific object's resource utilization
function lookupUtilization(object) {
return object.useCapability('utilization');
}
// Look up a specific object's resource utilization keys
function lookupUtilizationResources(object) {
var utilization = object.getCapability('utilization');
return utilization && utilization.resources();
}
// Promise a consolidated list of resource utilizations
function mapUtilization(objects) {
return $q.all(objects.map(lookupUtilization))
.then(flatten);
}
// Promise a consolidated list of resource utilization keys
function mapUtilizationResources(objects) {
return $q.all(objects.map(lookupUtilizationResources))
.then(flatten);
}
// Promise utilization associated with contained objects
function promiseExternalUtilization() {
// Get the composition, then consolidate their utilizations
return promiseComposition().then(mapUtilization);
}
// Get resource keys for this mode
function getModeKeys(mode) {
var cost = mode.getCapability('cost');
return cost ? cost.resources() : [];
}
// Map the above (for use in below)
function mapModeKeys(modes) {
return modes.map(getModeKeys);
}
// Promise identifiers for resources associated with modes
function promiseInternalKeys() {
return promiseModes().then(mapModeKeys).then(flatten);
}
// Promise identifiers for resources associated with modes
function promiseExternalKeys() {
return promiseComposition().then(mapUtilizationResources);
}
// Promise identifiers for resources used
function promiseResourceKeys() {
return $q.all([
promiseInternalKeys(),
promiseExternalKeys()
]).then(flatten).then(sort).then(uniquify);
}
// Promise all utilization
function promiseAllUtilization() {
// Concatenate internal utilization (from activity modes)
// with external utilization (from subactivities)
return $q.all([
promiseInternalUtilization(),
promiseExternalUtilization()
]).then(flatten);
}
return {
/**
* Get the keys for resources associated with this object.
* @returns {Promise.<string[]>} a promise for resource identifiers
*/
resources: promiseResourceKeys,
/**
* Get the resource utilization associated with this object
* directly, not including any resource utilization associated
* with contained objects.
* @returns {Promise.<Array>}
*/
internal: promiseInternalUtilization,
/**
* Get the resource utilization associated with this
* object. Results are not sorted. This requires looking
* at contained objects, which in turn must happen
* asynchronously, so this returns a promise.
* @returns {Promise.<Array>} a promise for all resource
* utilizations
*/
invoke: promiseAllUtilization
};
}
// Only applies to timelines and activities
UtilizationCapability.appliesTo = function (model) {
return model &&
((model.type === 'timeline') ||
(model.type === 'activity'));
};
return UtilizationCapability;
}
);

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