Compare commits

..

43 Commits

Author SHA1 Message Date
Pete Richards
720aaf151d [Plot] Remove x-axis tick ellipses
Remove ellipses from x-axis ticks and reversal of tick text.  This
allows PNG export to export ticks correctly instead of reversed.

Fixes #2177
2018-11-07 10:14:45 -08:00
Pete Richards
4bda4080d2 Consistent composition order (#2209)
* ensure composition loads in specified order

* Remove Modern JS to match current style guide
2018-11-07 10:07:57 -08:00
Pete Richards
e710cafb2c Mutate correct path for plot range (#2208)
Mutate correct path on object for axis range.  Fixes #2182.
2018-11-07 10:02:41 -08:00
Andrew Henry
e9643ad07f Added brief readmes for all plugins. (#2184) 2018-10-03 18:55:27 -07:00
Pete Richards
ca16892237 [cleanup] remove npm lodash (#2155)
remove npm lodash and unused scripts directory.  Removes usage of
lodash 3.10 in node files.
2018-08-31 12:04:16 -07:00
Pete Richards
a2b0d350d8 Merge pull request #2151 from nasa/update-d3-deps
Updated d3 dependency paths
2018-08-27 13:17:19 -07:00
Andrew Henry
534bdbae50 Updated d3 dependency paths 2018-08-27 10:19:39 -07:00
Andrew Henry
831873e7de Updated README to remove misleading references to instabilities in API. (#2150) 2018-08-21 10:38:12 -07:00
Pete Richards
622d246fdd Merge pull request #2129 from nasa/fixed-position-2125
[Fixed Position] Cannot add on objects when creating Fixed Position for the first time
2018-08-10 10:58:05 -07:00
Pete Richards
4a1ca9f299 Remove stray characters 2018-08-10 10:10:15 -07:00
Pete Richards
4e1de2678c Merge pull request #2134 from nasa/tables-2132
Change table row layout to use flex fixes #2132
2018-08-10 10:07:34 -07:00
Deep Tailor
33a4792531 do not show warning dialog when user moves an object from one location to another (#2142)
* dont show error dialog when user moves an object from one location to another

* add test for not showing blocking message on remove action

Fixes #2141
2018-08-10 10:06:40 -07:00
Pete Richards
37dd4856a6 Merge pull request #2145 from nasa/import-export-links
Fixes Import / Export to work correctly with links and contained objects.
2018-08-10 10:05:28 -07:00
Andrew Henry
6a9cf3389d Fixes #2144. Identifiers for objects and links now exported as identifier objects.
Use keystring as map key on import. Also removed redundant step to re-add imported objects to parent composition.
2018-08-10 07:09:59 -07:00
Deep Tailor
9582fb2b06 Merge pull request #2137 from nasa/prevent-plot-accidental-remove
[Plot] Update formDomainObject on mutate
2018-07-31 12:44:51 -07:00
Pete Richards
3c075b7ff2 [Plot] pass persisted config in constructor
When a plot series is constructed, it checks to see if should set a
default interpolation based on the persisted configuration.  However,
the persisted configuration wasn't available until after construction
which resulted in the default value always being set.

Pass the persisted configuration through the constructor to ensure the
plot series can make the right decision about defaults.

Fixes #2120.
2018-07-31 12:33:10 -07:00
Deep Tailor
081edfbd70 Merge pull request #2127 from nasa/plot-requests-2126
[Plot] Prevent duplicate query on bounds change
2018-07-31 12:32:57 -07:00
Pete Richards
04cc8f7aa2 [Plot] Update formDomainObject on mutate
When a new series is added to a plot, a plot series form controller
is instantiated and passed in a domain object via scope that it will
mutate upon changes.  If a mutation results in a composition add, then
the plot series form controller needs to get a version of the domain
object with the updated composition array, which it was not previously
doing.

This fixes #2120.
2018-07-31 12:03:49 -07:00
charlesh88
2da2395473 Change table row layout to use flex
Fixes #2132
- flex styles applied;
- CSS reorganized for better DRY;
- Set height on <tr> so that <td>'s won't collapse when
all cells of a row have empty values. This can occur when columns are
hidden in a Telemetry Table.
2018-07-27 18:04:06 -07:00
tobiasbrown
a1d206bfc3 [Remove] Add confirmation dialog (#1870)
* [Remove] Added confirmation dialog before the remove action is performed

Addresses #563
2018-07-27 13:54:41 -07:00
Deep Tailor
00ecd27bb3 fixes #2130
fix lingering event listener that was caused by function (setSelection) being stored in two different locations, causing pointer mis match
2018-07-26 12:21:10 -07:00
Deep Tailor
0fa4486dcf force a click on the fixed position element after initialize to initialise Fixed Position controller on the selection API 2018-07-25 16:31:31 -07:00
Pete Richards
ef9c6d5fed [Plot] Prevent duplicate query on bounds change
Bounds change triggers a clearing of plot history, which triggers
a user interaction change, which was triggering a second query.

This change sets a flag to prevent the requery from the user interaction on
bounds change.  This flag could potentially be reused elsewhere, e.g. if we
wanted to prevent requery when not utilizing a minmax data source.

fixes #2126
2018-07-25 11:44:14 -07:00
Pete Richards
15a75ac134 [Table] prevent forced reflow on scroll (#2117)
Prevent forcing a reflow during scroll events, improving scroll
performance.
2018-07-20 16:49:52 -07:00
Even Stensberg
cde3994979 [CI] Update circleCI to v2 (#1942)
* initial v2 config

t # This is a combination of 10 commits.

fix indent errs

fix indentations

run prepare manually

run prepare manually

remove indent

remove indent

remove indent

remove indent

remove indent

Misc

fix npm prepare

Install gulp

use gulp locally

use checkout

use old job

use old job

build-<test

build-<test

change

change

change

change

change

* add gulp as devdep

* local npm commands

* use node8

* cache bower components

* use npm to run checkstyle

* remove circlev1 config

* store artifacts

* clean up naming

fixes #1933
2018-07-20 16:00:13 -07:00
Deep Tailor
1a10c966e0 deprecated timeline (#2119)
* first release of deprecated timeline

* Better deprecation message and use unknown icon class

* Update deprecated-timeline-message.html

Added a period to end of sentence.

* remove unused files, and commented code - If we need timeline again we can recover from git

* Provide link to tracker in deprecation message
2018-07-20 15:45:30 -07:00
Deep Tailor
9288880e47 Add and Remove corresponding classes to capture higher contrast/print friendly png and jpg exports (#2088)
* add and remove corrensponding class to capture better images (wip)

* pass class through exportAsPng and exportAsJpg directly

* pass classname from stacked plots into exportImageService

* Adding additional export styles

Fixes #2088
- WIP

* WIP export styles

Fixes #2080
- Styling WIP;
- Moved styles into plots-main.scss;
- Change to how plot hashes are rendered;

* add class before clone, because adding it on clone was not rendering new css styles

* Export styles

Fixes #2080
- Code indenting cleaned up;
- Additional styles for export;
- Added hide effects for .h-local-controls and unsynced state;

* Apply class to cloned element only
2018-07-20 15:17:10 -07:00
Pete Richards
d2c5476cdd [Plot] Update limit variable name (#2124)
Update limit variable name in template so that styles are properly
applied when hovering over plot.  Fixes #2084.
2018-07-20 14:40:29 -07:00
Pete Richards
8d21d420ae Plot composition re-ordering support (#2120)
* [Plot] Allow 0 in plot y axis bounds

Allow 0 values in plot y axis bounds.  Also properly re-do validation
when changing from a bad value to the previously used good value.

Fixes https://github.com/nasa/openmct/issues/2082

* [Plot] separate config index from composition index

Locate the configuration index by checking identifiers instead of
relying on order of composition to match order of configuration.

Ensures that editing a plot after reordering composition does not
edit wrong object.

Fixes https://github.com/nasa/openmct/issues/2101

* [Plot] refactor form controllers, separate concerns

Refactor form controllers to simplify the plot options inspector.

Individual plot models each have a form controller which handles
three way binding between the scope, model, and domain object configuration.

Added support to linkFields for dynamic object paths so that mutations
always find the right object in the configuration instead of breaking
when indices change.

* support deferred init for sub-object selection

* Style fixes

* Remove assignment to window
2018-07-20 14:14:01 -07:00
Charles Hacskaylo
cc22fd4e9d Broaden selector to handle wrapped links/buttons (#2118)
Fixes #2116
- When buttons or links with icons are wrapped,
let the styling set margin and size properly;
2018-07-17 17:07:42 -07:00
Pete Richards
4a046b3eea Adapter consolidation & fix incorrect export to window (#2114)
* Merge adapter bundles

Merge adapter bundles into consistent location.

Update telemetry API to not incorrectly expose the format service
on window.

* openmct available on window for developers

* remove offending comma
2018-07-17 13:57:38 -07:00
Pete Richards
b0702ceff5 [Table] Check alarms for all values (#2115)
Check alarm status for all values, not just ranges.  This allows
limit evaluators to apply styling to additional columns if
desired by developers.
2018-07-17 13:55:35 -07:00
Deep Tailor
5af14cd3b9 [Notebook] Snapshot overlay - fixes issues #2098 #2102 #2108 #2110 (#2113)
* snapshot - when taking a snapshot of overlay, select object-holder vs the entire overlay. This fixes plots not being captured

* remove new Notebook entry from context menu - fixes issue #2098

* add licence information for Painterro - fixes issue #2108

* add watch for defaultSort - fixes issue 2102

* dont allow snapshot action from imagery

* fix checkstyle error
2018-07-17 11:30:01 -07:00
Charles Hacskaylo
d7eb4c17ca Added div element to force horz scroll in table body (#2111)
Fixes #2103
- Added div that is set to the calculated table width. When
filtering is such that no rows are present in the tbody
of the table, this element will still force a horizontal
scroll in that area, allowing the user to horz scroll the headers;
2018-07-16 15:25:02 -07:00
Andrew Henry
8c9fe2d36b [Tables] Address performance issues observed in testathon (#2112)
* Use datum key of 'utc' for timestamp

* Do not try to get column values for data that does not have those values

* Collapse current time system columns

* Noop parsing for numbers in LocalTimeFormat

* Do not attempt to provide data for columns that object does not have telemetry for. Fixes #2027
2018-07-16 15:23:34 -07:00
Andrew Henry
3246480f82 Indicators api (#1837)
* [API] Added Indicators API

* [Indicators] Converted Follow Indicator to new Indicators API

* [Indicators] Converted URL Indicator to new Indicators API

* [Indicators] Changes to some legacy indicators for compatibility with new Indicators API

* [Indicators] Addressed code review items from https://github.com/nasa/openmct/pull/1837

* Updated tests for URL Indicator

* Adding Indicator API spec

* Address linting issues

* Switched to direct DOM manipulation rather than template compilation to avoid an unnecessary extra holder element

* Updated documentation to reflect changes to API

* Indicators api styling (#2076)

Updated styling for Indicators

* Update API TOC

* Fix color of items w-mct-example areas of Style Guide

Fixes #1837

* Status class refactoring and cleanups

Fixes #1837
- Significant cleanups and name refactoring to allow more
concise selector definitions, with changes in js, html and scss files;
- Updates in Style Guide > Status page, with some content
reorganization and clarification;

* Corrected out of date API

* de-zeptoed Indicator API test spec

* Remove promise from URLIndicator

* Separated legacy indicators support

* Updated Indicator specs to Jasmine 3

* Fixed checkstyle and lint issues

* Moved legacy indicators support to adapter folder

* Various fixes for Indicators

Fixes #1837
- Added SASS constants for Indicator colors;
- Removed commented code;
- Removed unused indicator classes from _messages.scss
- Fixed missing s-status-on class;

* Significant revisions to Style Guide Indicators content

Fixes #1837
- Better documentation including recommendations;
- Better and more concrete examples;

* Style Guide example tweaks

Fixes #1837

* Refinement to Style Guide Status and Limits content

Fixes #1837
- More detail and clarification on Status and Limits;

* Cleanup code

Fixes #1837
- Remove commented styles;
- Line return refinements;
2018-07-16 15:21:38 -07:00
Deep Tailor
8055e050b6 Merge pull request #2109 from nasa/snapshot-2105
Fix for table overflow problem in html2canvas
2018-07-03 17:24:02 -07:00
charlesh88
b0f73fff0d Add overflow: auto when snapshotting table for Notebook
Fixes #2105
2018-07-03 16:57:26 -07:00
charlesh88
755cf21d3f Local control tweaks
Fixes #2094
- Adjust timing;
- Added hover effects for .s-notebook-entry;
2018-07-03 14:33:35 -07:00
charlesh88
95457a1981 View control fixes
Fixes #2094
- Add position: relative to .view-control main class;
- Add correct classes to markup;
- Fix Sum Widget field size while I was in there;
2018-07-03 14:25:39 -07:00
Deep Tailor
da0ed95662 Merge pull request #2097 from nasa/matching-historical-states
use correct duration for historical states
2018-07-03 12:47:15 -07:00
Charles Hacskaylo
c8919708bb Fixes for main search input (#2106)
* Fix for input width

* Margin added to right of c-search-btn-wrapper element

Fixes #2094
2018-07-03 12:36:24 -07:00
Pete Richards
cc5bfda730 use correct duration for historical states 2018-07-02 14:18:29 -07:00
259 changed files with 3176 additions and 16663 deletions

40
.circleci/config.yml Normal file
View File

@@ -0,0 +1,40 @@
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

117
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,7 +48,10 @@
- [The Time Conductor](#the-time-conductor)
- [Time Conductor Configuration](#time-conductor-configuration)
- [Example conductor configuration](#example-conductor-configuration)
- [Included Plugins](#included-plugins)
- [Indicators](#indicators)
- [The URL Status Indicator](#the-url-status-indicator)
- [Creating a Simple Indicator](#creating-a-simple-indicator)
- [Custom Indicators](#custom-indicators)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@@ -688,7 +691,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.
@@ -977,58 +980,68 @@ openmct.install(openmct.plugins.Conductor({
}));
```
## Included Plugins
## Indicators
Open MCT is packaged along with a few general-purpose plugins:
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.
* `openmct.plugins.Conductor` provides a user interface for working with time
within the application. If activated, configuration must be provided. This is
detailed in the section on [Time Conductor Configuration](#time-conductor-configuration).
* `openmct.plugins.CouchDB` is an adapter for using CouchDB for persistence
of user-created objects. This is a constructor that takes the URL for the
CouchDB database as a parameter, e.g.
```javascript
openmct.install(openmct.plugins.CouchDB('http://localhost:5984/openmct'))
```
* `openmct.plugins.Elasticsearch` is an adapter for using Elasticsearch for
persistence of user-created objects. This is a
constructor that takes the URL for the Elasticsearch instance as a
parameter. eg.
```javascript
openmct.install(openmct.plugins.CouchDB('http://localhost:9200'))
```
* `openmct.plugins.Espresso` and `openmct.plugins.Snow` are two different
themes (dark and light) available for Open MCT. Note that at least one
of these themes must be installed for Open MCT to appear correctly.
* `openmct.plugins.URLIndicatorPlugin` adds an indicator which shows the
availability of a URL with the following options:
- `url` : URL to indicate the status of
- `cssClass`: Icon to show in the status bar, defaults to `icon-database`, [list of all icons](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home?view=items)
- `interval`: Interval between checking the connection, defaults to `10000`
- `label` Name showing up as text in the status bar, defaults to url
```javascript
openmct.install(openmct.plugins.URLIndicatorPlugin({
url: 'http://google.com',
cssClass: 'check',
interval: 10000,
label: 'Google'
})
);
```
* `openmct.plugins.LocalStorage` provides persistence of user-created
objects in browser-local storage. This is particularly useful in
development environments.
* `openmct.plugins.MyItems` adds a top-level folder named "My Items"
when the application is first started, providing a place for a
user to store created items.
* `openmct.plugins.UTCTimeSystem` provides a default time system for Open MCT.
### The URL Status Indicator
Generally, you will want to either install these plugins, or install
different plugins that provide persistence and an initial folder
hierarchy.
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
the [documentation](./src/plugins/URLIndicatorPlugin) 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
openmct.install(openmct.plugins.LocalStorage());
openmct.install(openmct.plugins.MyItems());
``` 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
});
```

View File

@@ -20,14 +20,8 @@ API. Open MCT is also being refactored to minimize the dependencies that using
Open MCT imposes on developers, such as the current requirement to use
AngularJS.
This new API has not yet been heavily used and is likely to contain defects.
You can help by trying it out, and reporting any issues you encounter
using our GitHub issue tracker. Such issues may include bugs, suggestions,
missing documentation, or even just requests for help if you're having
trouble.
We want Open MCT to be as easy to use, install, run, and develop for as
possible, and your feedback will help us get there!
possible, and your feedback will help us get there! Feedback can be provided via [GitHub issues](https://github.com/nasa/openmct/issues), or by emailing us at [arc-dl-openmct@nasa.gov](mailto:arc-dl-openmct@nasa.gov).
## Building and Running Open MCT Locally

View File

@@ -1,27 +0,0 @@
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": "time",
"name": "Time",
"key": "utc",
"name": "Timestamp",
"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 += 5000;
start += duration;
}
return Promise.resolve(data);
};

View File

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

View File

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

View File

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

View File

@@ -1,9 +1,9 @@
<span class="status block" ng-controller="NotificationLaunchController">
<span class="h-indicator" ng-controller="NotificationLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<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> |
<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>
<a ng-click="newProgress()">Progress</a>
</span><span class="count"></span>
</span></div>
</span>

View File

@@ -58,7 +58,10 @@
position: relative;
}
.w-mct-example > div { margin-bottom: $interiorMarginLg; }
.w-mct-example {
color: #ccc;
> 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-limit"],
.w-mct-example div[class*="s-status"],
.w-mct-example div[class*="s-unsynced"],
.w-mct-example span[class*="s-status"],
.w-mct-example div[class*="s-limit"],
.w-mct-example span[class*="s-limit"] {
border-radius: 4px;
padding: 3px 7px;
border-radius: 3px;
padding: 2px 5px;
}
.w-mct-example table {
width: 100%;
@@ -36,65 +36,12 @@
<h1>Status Indication</h1>
<div class="l-section">
<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>
<h2>Status Classes</h2>
<div class="cols cols1-1">
<div class="col">
<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>
<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>
<ul>
<li>Color only</li>
<ul>
@@ -106,37 +53,175 @@
</ul>
<li>Color and icon</li>
<ul>
<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>
<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>
</ul>
</ul>
</div>
<mct-example><div class="s-status-warning-hi">WARNING HI</div>
<mct-example><!-- Color alone examples -->
<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>
<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>
<!-- 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>
</mct-example>
</div>
</div>
<div class="l-section">
<h2>Synchronization</h2>
<h2>Limit Classes</h2>
<div class="cols cols1-1">
<div class="col">
<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>
<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>
</div>
<mct-example><div class="s-unsynced">This element is unsynced</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>
</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>

View File

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

View File

@@ -31,7 +31,6 @@ var gulp = require('gulp'),
git = require('git-rev-sync'),
moment = require('moment'),
project = require('./package.json'),
_ = require('lodash'),
paths = {
main: 'openmct.js',
dist: 'dist',
@@ -140,7 +139,7 @@ gulp.task('checkstyle', function () {
var mkdirp = require('mkdirp');
var reportName = 'jscs-html-report.html';
var reportPath = path.resolve(paths.reports, 'checkstyle', reportName);
var moveReport = fs.rename.bind(fs, reportName, reportPath, _.noop);
var moveReport = fs.rename.bind(fs, reportName, reportPath, function () {});
mkdirp.sync(path.resolve(paths.reports, 'checkstyle'));
@@ -179,4 +178,4 @@ gulp.task('install', [ 'assets', 'scripts' ]);
gulp.task('verify', [ 'lint', 'test', 'checkstyle' ]);
gulp.task('build', [ 'verify', 'install' ]);
gulp.task('build', [ 'verify', 'install' ]);

View File

@@ -73,6 +73,7 @@
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

@@ -41,14 +41,14 @@ requirejs.config({
"lodash": "bower_components/lodash/lodash",
"d3-selection": "node_modules/d3-selection/dist/d3-selection.min",
"d3-scale": "node_modules/d3-scale/build/d3-scale.min",
"d3-axis": "node_modules/d3-axis/build/d3-axis.min",
"d3-array": "node_modules/d3-array/build/d3-array.min",
"d3-collection": "node_modules/d3-collection/build/d3-collection.min",
"d3-axis": "node_modules/d3-axis/dist/d3-axis.min",
"d3-array": "node_modules/d3-array/dist/d3-array.min",
"d3-collection": "node_modules/d3-collection/dist/d3-collection.min",
"d3-color": "node_modules/d3-color/build/d3-color.min",
"d3-format": "node_modules/d3-format/build/d3-format.min",
"d3-interpolate": "node_modules/d3-interpolate/build/d3-interpolate.min",
"d3-time": "node_modules/d3-time/build/d3-time.min",
"d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min",
"d3-time": "node_modules/d3-time/dist/d3-time.min",
"d3-time-format": "node_modules/d3-time-format/dist/d3-time-format.min",
"html2canvas": "node_modules/html2canvas/dist/html2canvas.min",
"painterro": "node_modules/painterro/build/painterro.min",
"printj": "node_modules/printj/dist/printj.min"

View File

@@ -1,7 +1,7 @@
{
"name": "openmct",
"version": "0.14.0-SNAPSHOT",
"description": "The Open MCT core platform",
"description": "The Open MCT core platform.",
"dependencies": {
"d3-array": "1.2.x",
"d3-axis": "1.0.x",
@@ -43,7 +43,6 @@
"karma-html-reporter": "^0.2.7",
"karma-jasmine": "^1.1.2",
"karma-requirejs": "^1.1.0",
"lodash": "^3.10.1",
"markdown-toc": "^0.11.7",
"marked": "^0.3.5",
"merge-stream": "^1.0.0",
@@ -59,6 +58,8 @@
"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,7 +32,6 @@ define([
"./src/actions/SaveAction",
"./src/actions/SaveAndStopEditingAction",
"./src/actions/SaveAsAction",
"./src/actions/SaveAsAndKeepEditingAction",
"./src/actions/CancelAction",
"./src/policies/EditActionPolicy",
"./src/policies/EditPersistableObjectsPolicy",
@@ -71,7 +70,6 @@ define([
SaveAction,
SaveAndStopEditingAction,
SaveAsAction,
SaveAsAndKeepEditingAction,
CancelAction,
EditActionPolicy,
EditPersistableObjectsPolicy,
@@ -190,6 +188,7 @@ define([
"name": "Remove",
"description": "Remove this object from its containing object.",
"depends": [
"dialogService",
"navigationService"
]
},
@@ -233,21 +232,6 @@ 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

@@ -23,111 +23,125 @@
/**
* Module defining RemoveAction. Created by vwoeltje on 11/17/14.
*/
define(
[],
function () {
define([
'./RemoveDialog'
], function (
RemoveDialog
) {
/**
* Construct an action which will remove the provided object manifestation.
* The object will be removed from its parent's composition; the parent
* is looked up via the "context" capability (so this will be the
* immediate ancestor by which this specific object was reached.)
*
* @param {DomainObject} object the object to be removed
* @param {ActionContext} context the context in which this action is performed
* @memberof platform/commonUI/edit
* @constructor
* @implements {Action}
/**
* Construct an action which will remove the provided object manifestation.
* The object will be removed from its parent's composition; the parent
* is looked up via the "context" capability (so this will be the
* immediate ancestor by which this specific object was reached.)
*
* @param {DialogService} dialogService a service which will show the dialog
* @param {NavigationService} navigationService a service that maintains the current navigation state
* @param {ActionContext} context the context in which this action is performed
* @memberof platform/commonUI/edit
* @constructor
* @implements {Action}
*/
function RemoveAction(dialogService, navigationService, context) {
this.domainObject = (context || {}).domainObject;
this.dialogService = dialogService;
this.navigationService = navigationService;
}
/**
* Perform this action.
*/
RemoveAction.prototype.perform = function (skipWarning) {
var dialog,
dialogService = this.dialogService,
domainObject = this.domainObject,
navigationService = this.navigationService;
/*
* Check whether an object ID matches the ID of the object being
* removed (used to filter a parent's composition to handle the
* removal.)
*/
function RemoveAction(navigationService, context) {
this.domainObject = (context || {}).domainObject;
this.navigationService = navigationService;
function isNotObject(otherObjectId) {
return otherObjectId !== domainObject.getId();
}
/**
* Perform this action.
* @return {Promise} a promise which will be
* fulfilled when the action has completed.
/*
* Mutate a parent object such that it no longer contains the object
* which is being removed.
*/
RemoveAction.prototype.perform = function () {
var navigationService = this.navigationService,
domainObject = this.domainObject;
/*
* Check whether an object ID matches the ID of the object being
* removed (used to filter a parent's composition to handle the
* removal.)
*/
function isNotObject(otherObjectId) {
return otherObjectId !== domainObject.getId();
}
function doMutate(model) {
model.composition = model.composition.filter(isNotObject);
}
/*
* Mutate a parent object such that it no longer contains the object
* which is being removed.
*/
function doMutate(model) {
model.composition = model.composition.filter(isNotObject);
}
/*
* Checks current object and ascendants of current
* object with object being removed, if the current
* object or any in the current object's path is being removed,
* navigate back to parent of removed object.
*/
function checkObjectNavigation(object, parentObject) {
// Traverse object starts at current location
var traverseObject = (navigationService).getNavigation(),
context;
/*
* Checks current object and ascendants of current
* object with object being removed, if the current
* object or any in the current object's path is being removed,
* navigate back to parent of removed object.
*/
function checkObjectNavigation(object, parentObject) {
// Traverse object starts at current location
var traverseObject = (navigationService).getNavigation(),
context;
// Stop when object is not defined (above ROOT)
while (traverseObject) {
// If object currently traversed to is object being removed
// navigate to parent of current object and then exit loop
if (traverseObject.getId() === object.getId()) {
navigationService.setNavigation(parentObject);
return;
}
// Traverses to parent of current object, moving
// up the ascendant path
context = traverseObject.getCapability('context');
traverseObject = context && context.getParent();
// Stop when object is not defined (above ROOT)
while (traverseObject) {
// If object currently traversed to is object being removed
// navigate to parent of current object and then exit loop
if (traverseObject.getId() === object.getId()) {
navigationService.setNavigation(parentObject);
return;
}
// Traverses to parent of current object, moving
// up the ascendant path
context = traverseObject.getCapability('context');
traverseObject = context && context.getParent();
}
}
/*
* Remove the object from its parent, as identified by its context
* capability. Based on object's location and selected object's location
* user may be navigated to existing parent object
*/
function removeFromContext(object) {
var contextCapability = object.getCapability('context'),
parent = contextCapability.getParent();
// If currently within path of removed object(s),
// navigates to existing object up tree
checkObjectNavigation(object, parent);
return parent.useCapability('mutation', doMutate);
}
if (skipWarning) {
removeFromContext(domainObject);
} else {
/*
* Remove the object from its parent, as identified by its context
* capability. Based on object's location and selected object's location
* user may be navigated to existing parent object
*/
function removeFromContext(object) {
var contextCapability = object.getCapability('context'),
parent = contextCapability.getParent();
* Pass in the function to remove the domain object so it can be
* associated with an 'OK' button press
*/
dialog = new RemoveDialog(dialogService, domainObject, removeFromContext);
dialog.show();
}
};
// If currently within path of removed object(s),
// navigates to existing object up tree
checkObjectNavigation(object, parent);
// Object needs to have a parent for Remove to be applicable
RemoveAction.appliesTo = function (context) {
var object = (context || {}).domainObject,
contextCapability = object && object.getCapability("context"),
parent = contextCapability && contextCapability.getParent(),
parentType = parent && parent.getCapability('type'),
parentCreatable = parentType && parentType.hasFeature('creation');
return parent.useCapability('mutation', doMutate);
}
// Only creatable types should be modifiable
return parent !== undefined &&
Array.isArray(parent.getModel().composition) &&
parentCreatable;
};
return removeFromContext(domainObject);
};
// Object needs to have a parent for Remove to be applicable
RemoveAction.appliesTo = function (context) {
var object = (context || {}).domainObject,
contextCapability = object && object.getCapability("context"),
parent = contextCapability && contextCapability.getParent(),
parentType = parent && parent.getCapability('type'),
parentCreatable = parentType && parentType.hasFeature('creation');
// Only creatable types should be modifiable
return parent !== undefined &&
Array.isArray(parent.getModel().composition) &&
parentCreatable;
};
return RemoveAction;
}
);
return RemoveAction;
});

View File

@@ -0,0 +1,77 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([], function () {
/**
* @callback removeCallback
* @param {DomainObject} domainObject the domain object to be removed
*/
/**
* Construct a new Remove dialog.
*
* @param {DialogService} dialogService the service that shows the dialog
* @param {DomainObject} domainObject the domain object to be removed
* @param {removeCallback} removeCallback callback that handles removal of the domain object
* @memberof platform/commonUI/edit
* @constructor
*/
function RemoveDialog(dialogService, domainObject, removeCallback) {
this.dialogService = dialogService;
this.domainObject = domainObject;
this.removeCallback = removeCallback;
}
/**
* Display a dialog to confirm the removal of a domain object.
*/
RemoveDialog.prototype.show = function () {
var dialog,
domainObject = this.domainObject,
removeCallback = this.removeCallback,
model = {
title: 'Remove ' + domainObject.getModel().name,
actionText: 'Warning! This action will permanently remove this object. Are you sure you want to continue?',
severity: 'alert',
primaryOption: {
label: 'OK',
callback: function () {
removeCallback(domainObject);
dialog.dismiss();
}
},
options: [
{
label: 'Cancel',
callback: function () {
dialog.dismiss();
}
}
]
};
dialog = this.dialogService.showBlockingMessage(model);
};
return RemoveDialog;
});

View File

@@ -1,85 +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(
["./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

@@ -25,50 +25,37 @@ define(
function (RemoveAction) {
describe("The Remove action", function () {
var mockQ,
mockNavigationService,
mockDomainObject,
mockParent,
mockChildObject,
mockGrandchildObject,
mockRootObject,
mockContext,
mockChildContext,
mockGrandchildContext,
mockRootContext,
mockMutation,
mockType,
var action,
actionContext,
model,
capabilities,
action;
function mockPromise(value) {
return {
then: function (callback) {
return mockPromise(callback(value));
}
};
}
mockContext,
mockDialogService,
mockDomainObject,
mockMutation,
mockNavigationService,
mockParent,
mockType,
model;
beforeEach(function () {
mockDomainObject = jasmine.createSpyObj(
"domainObject",
["getId", "getCapability"]
["getId", "getCapability", "getModel"]
);
mockChildObject = jasmine.createSpyObj(
"domainObject",
["getId", "getCapability"]
);
mockGrandchildObject = jasmine.createSpyObj(
"domainObject",
["getId", "getCapability"]
);
mockRootObject = jasmine.createSpyObj(
"domainObject",
["getId", "getCapability"]
);
mockQ = { when: mockPromise };
mockMutation = jasmine.createSpyObj("mutation", ["invoke"]);
mockType = jasmine.createSpyObj("type", ["hasFeature"]);
mockType.hasFeature.and.returnValue(true);
capabilities = {
mutation: mockMutation,
type: mockType
};
model = {
composition: ["a", "test", "b"]
};
mockParent = {
getModel: function () {
return model;
@@ -80,12 +67,12 @@ define(
return capabilities[k].invoke(v);
}
};
mockContext = jasmine.createSpyObj("context", ["getParent"]);
mockChildContext = jasmine.createSpyObj("context", ["getParent"]);
mockGrandchildContext = jasmine.createSpyObj("context", ["getParent"]);
mockRootContext = jasmine.createSpyObj("context", ["getParent"]);
mockMutation = jasmine.createSpyObj("mutation", ["invoke"]);
mockType = jasmine.createSpyObj("type", ["hasFeature"]);
mockDialogService = jasmine.createSpyObj(
"dialogService",
["showBlockingMessage"]
);
mockNavigationService = jasmine.createSpyObj(
"navigationService",
[
@@ -97,23 +84,19 @@ define(
);
mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
mockContext = jasmine.createSpyObj("context", ["getParent"]);
mockContext.getParent.and.returnValue(mockParent);
mockDomainObject.getId.and.returnValue("test");
mockDomainObject.getCapability.and.returnValue(mockContext);
mockDomainObject.getModel.and.returnValue({name: 'test object'});
mockContext.getParent.and.returnValue(mockParent);
mockType.hasFeature.and.returnValue(true);
capabilities = {
mutation: mockMutation,
type: mockType
};
model = {
composition: ["a", "test", "b"]
};
actionContext = { domainObject: mockDomainObject };
action = new RemoveAction(mockNavigationService, actionContext);
action = new RemoveAction(mockDialogService, mockNavigationService, actionContext);
});
it("only applies to objects with parents", function () {
@@ -127,83 +110,157 @@ define(
expect(mockType.hasFeature).toHaveBeenCalledWith('creation');
});
it("mutates the parent when performed", function () {
action.perform();
expect(mockMutation.invoke)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("changes composition from its mutation function", function () {
var mutator, result;
action.perform();
mutator = mockMutation.invoke.calls.mostRecent().args[0];
result = mutator(model);
// Should not have cancelled the mutation
expect(result).not.toBe(false);
// Simulate mutate's behavior (remove can either return a
// new model or modify this one in-place)
result = result || model;
// Should have removed "test" - that was our
// mock domain object's id.
expect(result.composition).toEqual(["a", "b"]);
});
it("removes parent of object currently navigated to", function () {
// Navigates to child object
mockNavigationService.getNavigation.and.returnValue(mockChildObject);
// Test is id of object being removed
// Child object has different id
mockDomainObject.getId.and.returnValue("test");
mockChildObject.getId.and.returnValue("not test");
// Sets context for the child and domainObject
mockDomainObject.getCapability.and.returnValue(mockContext);
mockChildObject.getCapability.and.returnValue(mockChildContext);
// Parents of child and domainObject are set
mockContext.getParent.and.returnValue(mockParent);
mockChildContext.getParent.and.returnValue(mockDomainObject);
mockType.hasFeature.and.returnValue(true);
it("shows a blocking message dialog", function () {
mockParent = jasmine.createSpyObj(
"parent",
["getModel", "getCapability", "useCapability"]
);
action.perform();
// Expects navigation to parent of domainObject (removed object)
expect(mockNavigationService.setNavigation).toHaveBeenCalledWith(mockParent);
expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
// Also check that no mutation happens at this point
expect(mockParent.useCapability).not.toHaveBeenCalledWith("mutation", jasmine.any(Function));
});
it("checks if removing object not in ascendent path (reaches ROOT)", function () {
// Navigates to grandchild of ROOT
mockNavigationService.getNavigation.and.returnValue(mockGrandchildObject);
it("does not show a blocking message dialog when true is passed to perform", function () {
mockParent = jasmine.createSpyObj(
"parent",
["getModel", "getCapability", "useCapability"]
);
// domainObject (grandparent) is set as ROOT, child and grandchild
// are set objects not being removed
mockDomainObject.getId.and.returnValue("test 1");
mockRootObject.getId.and.returnValue("ROOT");
mockChildObject.getId.and.returnValue("not test 2");
mockGrandchildObject.getId.and.returnValue("not test 3");
action.perform(true);
// Sets context for the grandchild, child, and domainObject
mockRootObject.getCapability.and.returnValue(mockRootContext);
mockChildObject.getCapability.and.returnValue(mockChildContext);
mockGrandchildObject.getCapability.and.returnValue(mockGrandchildContext);
// Parents of grandchild and child are set
mockChildContext.getParent.and.returnValue(mockRootObject);
mockGrandchildContext.getParent.and.returnValue(mockChildObject);
mockType.hasFeature.and.returnValue(true);
action.perform();
// Expects no navigation to occur
expect(mockNavigationService.setNavigation).not.toHaveBeenCalled();
expect(mockDialogService.showBlockingMessage).not.toHaveBeenCalled();
});
describe("after the remove callback is triggered", function () {
var mockChildContext,
mockChildObject,
mockDialogHandle,
mockGrandchildContext,
mockGrandchildObject,
mockRootContext,
mockRootObject;
beforeEach(function () {
mockChildObject = jasmine.createSpyObj(
"domainObject",
["getId", "getCapability"]
);
mockDialogHandle = jasmine.createSpyObj(
"dialogHandle",
["dismiss"]
);
mockGrandchildObject = jasmine.createSpyObj(
"domainObject",
["getId", "getCapability"]
);
mockRootObject = jasmine.createSpyObj(
"domainObject",
["getId", "getCapability"]
);
mockChildContext = jasmine.createSpyObj("context", ["getParent"]);
mockGrandchildContext = jasmine.createSpyObj("context", ["getParent"]);
mockRootContext = jasmine.createSpyObj("context", ["getParent"]);
mockDialogService.showBlockingMessage.and.returnValue(mockDialogHandle);
});
it("mutates the parent when performed", function () {
action.perform();
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
.primaryOption.callback();
expect(mockMutation.invoke)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("changes composition from its mutation function", function () {
var mutator, result;
action.perform();
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
.primaryOption.callback();
mutator = mockMutation.invoke.calls.mostRecent().args[0];
result = mutator(model);
// Should not have cancelled the mutation
expect(result).not.toBe(false);
// Simulate mutate's behavior (remove can either return a
// new model or modify this one in-place)
result = result || model;
// Should have removed "test" - that was our
// mock domain object's id.
expect(result.composition).toEqual(["a", "b"]);
});
it("removes parent of object currently navigated to", function () {
// Navigates to child object
mockNavigationService.getNavigation.and.returnValue(mockChildObject);
// Test is id of object being removed
// Child object has different id
mockDomainObject.getId.and.returnValue("test");
mockChildObject.getId.and.returnValue("not test");
// Sets context for the child and domainObject
mockDomainObject.getCapability.and.returnValue(mockContext);
mockChildObject.getCapability.and.returnValue(mockChildContext);
// Parents of child and domainObject are set
mockContext.getParent.and.returnValue(mockParent);
mockChildContext.getParent.and.returnValue(mockDomainObject);
mockType.hasFeature.and.returnValue(true);
action.perform();
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
.primaryOption.callback();
// Expects navigation to parent of domainObject (removed object)
expect(mockNavigationService.setNavigation).toHaveBeenCalledWith(mockParent);
});
it("checks if removing object not in ascendent path (reaches ROOT)", function () {
// Navigates to grandchild of ROOT
mockNavigationService.getNavigation.and.returnValue(mockGrandchildObject);
// domainObject (grandparent) is set as ROOT, child and grandchild
// are set objects not being removed
mockDomainObject.getId.and.returnValue("test 1");
mockRootObject.getId.and.returnValue("ROOT");
mockChildObject.getId.and.returnValue("not test 2");
mockGrandchildObject.getId.and.returnValue("not test 3");
// Sets context for the grandchild, child, and domainObject
mockRootObject.getCapability.and.returnValue(mockRootContext);
mockChildObject.getCapability.and.returnValue(mockChildContext);
mockGrandchildObject.getCapability.and.returnValue(mockGrandchildContext);
// Parents of grandchild and child are set
mockChildContext.getParent.and.returnValue(mockRootObject);
mockGrandchildContext.getParent.and.returnValue(mockChildObject);
mockType.hasFeature.and.returnValue(true);
action.perform();
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
.primaryOption.callback();
// Expects no navigation to occur
expect(mockNavigationService.setNavigation).not.toHaveBeenCalled();
});
});
});
}
);

View File

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

View File

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

View File

@@ -20,66 +20,120 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*************************************************** MIXINS */
@mixin formulateStatusColors($c) {
@mixin elementStatusColors($c) {
// Sets bg and icon colors for elements
background: rgba($c, 0.4) !important;
&:before { color: $c !important; }
}
/*************************************************** GENERAL */
.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);
background: rgba($c, 0.5) !important;
&:before {
content:'';
font-family: symbolsfont;
font-size: 0.8em;
margin-right: $interiorMarginSm;
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'] {
&:before {
content:'';
display: inline-block;
font-family: symbolsfont;
font-size: 0.8em;
}
}
/*************************************************** LIMITS */
.s-limit-yellow, .s-limit-yellow-icon {
@include formulateStatusColors($colorWarningLo);
[class*='s-limit'] {
&[class*='icon-'] {
&:before {
margin-right: $interiorMargin;
}
}
}
.s-limit-red, .s-limit-red-icon {
@include formulateStatusColors($colorWarningHi);
.s-limit-yellow, .s-limit-icon-yellow {
@include elementStatusColors($colorWarningLo);
}
.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; }
.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;
}
}
}
/*************************************************** STATUS */
.s-status-warning-hi, .s-status-warning-hi-icon { @include formulateStatusColors($colorWarningHi); }
.s-status-warning-lo, .s-status-warning-lo-icon { @include formulateStatusColors($colorWarningLo); }
.s-status-diagnostic, .s-status-diagnostic-icon { @include formulateStatusColors($colorDiagnostic); }
.s-status-info, .s-status-info-icon { @include formulateStatusColors($colorInfo); }
.s-status-ok, .s-status-ok-icon { @include formulateStatusColors($colorOk); }
[class*='s-status'] {
&[class*='icon-'] {
&:before {
margin-right: $interiorMargin;
}
}
}
.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-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-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,19 +133,11 @@
/******************************************************** 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
@@ -156,7 +148,7 @@ body.desktop .has-local-controls {
}
.local-controls-hidden {
@include trans-prop-nice($props: opacity, $dur: 1000ms);
@include trans-prop-nice($props: opacity, $dur: 500ms);
opacity: 0;
pointer-events: none;
}
@@ -211,6 +203,7 @@ 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

@@ -0,0 +1,147 @@
/*****************************************************************************
* 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: 30%;
$bgPb: 10%;
$bgPbD: 10%;
background-color: darken($bg, $bgPb);
color: $fg;
@@ -36,110 +36,6 @@
}
}
// Status coloring
.ok, .info {
.status-indicator {
color: $colorInfo;
}
}
.alert, .caution, .warning {
.status-indicator, .count {
color: $colorStatusAlert;
}
}
.error, .err {
.status-indicator, .count {
color: $colorStatusError;
}
}
.available {
.status-indicator, .count {
color: $colorStatusAvailable;
}
}
.subdued {
.status-indicator {
color: pullForward($colorStatusBarBg, 40%);
}
}
.status-block-holder {
// Applied to mct-include element
// Contains status.block elements
$transDelay: 1.5s;
$transSpeed: .25s;
display: inline-block;
&.clickable { cursor: pointer; }
&:not(.clickable) { cursor: default; }
&.no-icon .status.block {
.status-indicator {
display: none;
}
}
&.float-right {
float: right;
}
&:not(.no-collapse) .status.block {
.label {
// Max-width silliness is necessary for width transition
@include trans-prop-nice(max-width, $transSpeed, $transDelay);
overflow: hidden;
max-width: 0px;
}
&:hover {
.label {
@include trans-prop-nice(max-width, $transSpeed, 0s);
max-width: 600px;
width: auto;
}
.count {
@include trans-prop-nice(max-width, $transSpeed, 0s);
opacity: 0;
}
}
}
}
.status.block {
$transDelay: 1.5s;
$transSpeed: .25s;
color: $colorStatusDefault;
display: inline-block;
margin-right: $interiorMargin;
.status-indicator,
.label,
.count {
display: inline-block;
vertical-align: top;
}
.status-indicator {
background: none !important;
margin-right: $interiorMarginSm;
&[class*='s-status']:before {
font-size: 1em;
}
}
.count {
@include trans-prop-nice(opacity, $transSpeed, $transDelay);
font-weight: bold;
opacity: 1;
}
.s-button {
background: $colorStatusBtnBg;
padding: 0 $interiorMargin;
height: auto;
line-height: inherit;
}
}
/******************************************************************* MESSAGE BANNERS */
.message {
&.block {
@@ -289,7 +185,6 @@
> 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,18 +51,15 @@
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 */
@@ -74,7 +71,8 @@
position: absolute;
display: block;
font-size: 1.5em;
top: $interiorMarginSm; left: $interiorMarginSm;
top: $interiorMarginSm;
left: $interiorMarginSm;
}
}
@@ -105,71 +103,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%);
@@ -190,119 +188,191 @@
right: $interiorMargin;
}
.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%;
}
}
.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%;
}
}
/****************************** 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;
}
&.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;
}
}
}
}

View File

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

View File

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

View File

@@ -19,14 +19,9 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class='abs bottom-bar ue-bottom-bar mobile-disable-select' ng-controller="BottomBarController as bar">
<div class='abs bottom-bar l-ue-bottom-bar s-ue-bottom-bar mobile-disable-select'>
<div id='status' class='status-holder'>
<mct-include ng-repeat="indicator in bar.getIndicators()"
ng-model="indicator.ngModel"
key="indicator.template"
class="status-block-holder"
ng-class='indicator.ngModel.getGlyphClass()'>
</mct-include>
<mct-indicators></mct-indicators>
</div>
<mct-include key="'message-banner'"></mct-include>
<mct-include key="'about-logo'"></mct-include>

View File

@@ -1,59 +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 () {
/**
* 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

@@ -19,15 +19,22 @@
* 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 "constants-espresso";
@import "timeline-thematic";
define(
[],
function () {
function MCTIndicators(openmct) {
return {
restrict: "E",
link: function link(scope, element) {
openmct.indicators.indicatorElements
.forEach(function (indicatorElement) {
element.append(indicatorElement);
});
}
};
}
return MCTIndicators;
}
);

View File

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

View File

@@ -0,0 +1,7 @@
# Espresso Theme
Dark theme for the Open MCT user interface.
## Installation
```js
openmct.install(openmct.plugins.Espresso());
```

View File

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

View File

@@ -0,0 +1,7 @@
# Espresso Theme
A light colored theme for the Open MCT user interface.
## Installation
```js
openmct.install(openmct.plugins.Snow());
```

View File

@@ -3,6 +3,8 @@ $colorBodyBg: #fcfcfc;
$colorBodyFg: #666;
$colorGenBg: #fff;
$colorStatusBarBg: #000;
$colorStatusBarFg: #999;
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeySelectedBg: $colorKey;
$colorKeyFg: #fff;
@@ -72,7 +74,6 @@ $colorObjHdrTxt: $colorBodyFg;
$colorObjHdrIc: lighten($colorObjHdrTxt, 30%);
$colorTick: rgba(black, 0.2);
$colorSelectableSelectedPrimary: $colorKey;
//$colorSelectableSelectedSecondary: pushBack($colorSelectableSelectedPrimary, 20%);
$colorSelectableHov: rgba($colorBodyFg, 0.4);
// Menu colors
@@ -117,8 +118,7 @@ $colorStatusFg: #999;
$colorStatusDefault: #ccc;
$colorStatusInfo: #60ba7b;
$colorStatusAlert: #ffb66c;
$colorStatusError: #c96b68;
$colorStatusAvailable: $colorKey;
$colorStatusError: #da0004;
$colorStatusBtnBg: #666;
$colorProgressBarOuter: rgba(#000, 0.1);
$colorProgressBarAmt: #0a0;
@@ -127,6 +127,12 @@ $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;
@@ -177,7 +183,8 @@ $colorTabHeaderBorder: $colorBodyBg;
// Plot
$colorPlotBg: rgba(black, 0.05);
$colorPlotFg: $colorBodyFg;
$colorPlotHash: $colorTick;
$colorPlotHash: black;
$opacityPlotHash: 0.2;
$stylePlotHash: dashed;
$colorPlotAreaBorder: $colorInteriorBorder;
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);

View File

@@ -102,14 +102,14 @@ define(
* @returns {Action[]} an array of matching actions
* @memberof platform/core.ActionCapability#
*/
ActionCapability.prototype.perform = function (context) {
ActionCapability.prototype.perform = function (context, flag) {
// Alias to getActions(context)[0].perform, with a
// check for empty arrays.
var actions = this.getActions(context);
return this.$q.when(
(actions && actions.length > 0) ?
actions[0].perform() :
actions[0].perform(flag) :
undefined
);
};

View File

@@ -92,7 +92,7 @@ define(
.then(function () {
return object
.getCapability('action')
.perform('remove');
.perform('remove', true);
});
};

View File

@@ -224,10 +224,11 @@ define(
locationPromise.resolve();
});
it("removes object from parent", function () {
it("removes object from parent without user warning dialog", function () {
expect(actionCapability.perform)
.toHaveBeenCalledWith('remove');
.toHaveBeenCalledWith('remove', true);
});
});
});
@@ -244,9 +245,9 @@ define(
.toHaveBeenCalled();
});
it("removes object from parent", function () {
it("removes object from parent without user warning dialog", function () {
expect(actionCapability.perform)
.toHaveBeenCalledWith('remove');
.toHaveBeenCalledWith('remove', true);
});
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -87,7 +87,8 @@ define(
'setDisplayedValue',
'subscribeToObject',
'unsubscribe',
'updateView'
'updateView',
'setSelection'
].forEach(function (name) {
self[name] = self[name].bind(self);
});
@@ -224,7 +225,7 @@ define(
// Respond to external bounds changes
this.openmct.time.on("bounds", updateDisplayBounds);
this.openmct.selection.on('change', this.setSelection.bind(this));
this.openmct.selection.on('change', this.setSelection);
this.$element.on('click', this.bypassSelection.bind(this));
this.unlisten = this.openmct.objects.observe(this.newDomainObject, '*', function (obj) {
this.newDomainObject = JSON.parse(JSON.stringify(obj));
@@ -233,6 +234,9 @@ define(
this.updateElementPositions(this.newDomainObject.layoutGrid);
refreshElements();
//force a click, to initialize Fixed Position Controller on SelectionAPI
$element[0].click();
}
FixedController.prototype.updateElementPositions = function (layoutGrid) {

View File

@@ -0,0 +1,8 @@
# My Items plugin
Defines top-level folder named "My Items" to store user-created items. Enabled by default, this can be disabled in a
read-only deployment with no user-editable objects.
## Installation
```js
openmct.install(openmct.plugins.MyItems());
```

View File

@@ -58,7 +58,8 @@ define([
"model": {
"entries": [],
"composition": [],
"entryTypes": []
"entryTypes": [],
"defaultSort": "-createdOn"
},
"properties": [
{
@@ -236,7 +237,6 @@ 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": "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"
"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"
}
],
"capabilities": [

View File

@@ -144,6 +144,13 @@
}
}
.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
@@ -285,24 +292,3 @@ 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,10 +34,12 @@
}
.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 notebook-entry-delete">
<div class="holder flex-elem local-control local-controls-hidden 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,7 +185,18 @@ define(
NewEntryContextual.appliesTo = function (context) {
var domainObject = context.domainObject;
return !!(domainObject && domainObject.getModel().type !== 'notebook');
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 NewEntryContextual;

View File

@@ -42,7 +42,7 @@ define(
) {
$scope.entriesEl = $(document.body).find('.t-entries-list');
$scope.sortEntries = $scope.domainObject.getModel().defaultSort || "-createdOn";
$scope.sortEntries = $scope.domainObject.getModel().defaultSort;
$scope.showTime = "0";
$scope.editEntry = false;
$scope.entrySearch = '';
@@ -354,6 +354,11 @@ 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')[0] || $(document.body).find("[key='representation.selected.key']")[0],
var objectElement = $(document.body).find(".overlay .object-holder")[0] || $(document.body).find("[key='representation.selected.key']")[0],
takeSnapshot,
makeImg,
saveImg;

View File

@@ -35,28 +35,30 @@ mct-table {
}
.mct-table {
tr {
display: flex; // flex-flow defaults to row nowrap (which is what we want) so no need to define
height: 18px; // Needed when a row has empty values in its cells
align-items: stretch;
}
td, th {
box-sizing: border-box;
display: block;
flex: 1 0 auto;
white-space: nowrap;
}
thead {
display: block;
tr {
display: block;
white-space: nowrap;
th {
display: inline-block;
box-sizing: border-box;
}
}
}
tbody {
tr {
position: absolute;
white-space: nowrap;
display: block;
}
td {
white-space: nowrap;
overflow: hidden;
box-sizing: border-box;
display: inline-block;
}
}
}
@@ -65,3 +67,10 @@ 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,6 +59,10 @@
</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.timeColumns"
time-columns="[tableController.table.timeSystemColumnTitle]"
format-cell="formatCell"
enableFilter="true"
enableSort="true"

View File

@@ -0,0 +1,67 @@
/*****************************************************************************
* 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(
[],
function () {
['./TableColumn'],
function (TableColumn) {
/**
* Class that manages table metadata, state, and contents.
@@ -32,62 +32,31 @@ define(
*/
function TableConfiguration(domainObject, openmct) {
this.domainObject = domainObject;
this.columns = [];
this.openmct = openmct;
this.timeSystemColumn = undefined;
this.columns = [];
this.headers = new Set();
this.timeSystemColumnTitle = undefined;
}
/**
* Build column definitions based on supplied telemetry metadata
* Build column definition based on supplied telemetry metadata
* @param telemetryObject the telemetry producing object associated with this column
* @param metadata Metadata describing the domains and ranges available
* @returns {TableConfiguration} This object
*/
TableConfiguration.prototype.populateColumns = function (metadata) {
var self = this;
var telemetryApi = this.openmct.telemetry;
TableConfiguration.prototype.addColumn = function (telemetryObject, metadatum) {
var column = new TableColumn(this.openmct, telemetryObject, metadatum);
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;
}
});
});
if (column.isCurrentTimeSystem()) {
if (!this.timeSystemColumnTitle) {
this.timeSystemColumnTitle = column.title();
}
column.title(this.timeSystemColumnTitle);
}
return this;
};
/**
* 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);
});
this.columns.push(column);
this.headers.add(column.title());
};
/**
@@ -98,22 +67,32 @@ 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 (limitEvaluator, datum) {
return this.columns.reduce(function (rowObject, column, i) {
var columnTitle = column.getTitle() || 'Column ' + (i + 1),
columnValue = column.getValue(datum, limitEvaluator);
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) {
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)) {
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;
}
}
return rowObject;
}, {});
};
@@ -164,7 +143,7 @@ define(
* specifying whether the column is visible or not. Default to
* existing (persisted) configuration if available
*/
this.getHeaders().forEach(function (columnTitle) {
this.headers.forEach(function (columnTitle) {
configuration[columnTitle] =
typeof defaultConfig[columnTitle] === 'undefined' ? true :
defaultConfig[columnTitle];

View File

@@ -93,7 +93,9 @@ define(
// Calculate the new index of the last item in bounds
endIndex = _.sortedLastIndex(this.highBuffer, testValue, this.sortField);
added = this.highBuffer.splice(0, endIndex);
this.telemetry = this.telemetry.concat(added);
added.forEach(function (datum) {
this.telemetry.push(datum);
}.bind(this));
}
if (discarded && discarded.length > 0) {
@@ -132,6 +134,7 @@ define(
// bounds events, so no bounds checking necessary
if (this.sortField === undefined) {
this.telemetry.push(item);
return true;
}
@@ -153,7 +156,6 @@ 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,19 +262,26 @@ 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.scrollable[0].scrollTop <
(this.scrollable[0].scrollHeight - this.scrollable[0].offsetHeight) - 20) {
if (this.scrollWindow.top <
(this.scrollWindow.height - this.scrollWindow.offsetHeight) - 20) {
this.$scope.autoScroll = false;
} else {
this.$scope.autoScroll = true;
}
this.scrolling = false;
delete this.scrollWindow;
}.bind(this));
};
@@ -283,15 +290,14 @@ define(
* @private
*/
MCTTableController.prototype.firstVisible = function () {
var target = this.scrollable[0],
topScroll = target.scrollTop,
firstVisible;
var topScroll = this.scrollWindow ?
this.scrollWindow.top :
this.scrollable[0].scrollTop;
firstVisible = Math.floor(
return Math.floor(
(topScroll) / this.$scope.rowHeight
);
return firstVisible;
};
/**
@@ -299,16 +305,14 @@ define(
* @private
*/
MCTTableController.prototype.lastVisible = function () {
var target = this.scrollable[0],
topScroll = target.scrollTop,
bottomScroll = topScroll + target.offsetHeight,
lastVisible;
var bottomScroll = this.scrollWindow ?
this.scrollWindow.bottom :
this.scrollable[0].scrollTop + this.scrollable[0].offsetHeight;
lastVisible = Math.ceil(
return Math.ceil(
(bottomScroll) /
this.$scope.rowHeight
);
return lastVisible;
};
/**

View File

@@ -118,23 +118,18 @@ define(
* to sort by. By default will just match on key.
*
* @private
* @param {TimeSystem} timeSystem
*/
TelemetryTableController.prototype.sortByTimeSystem = function (timeSystem) {
TelemetryTableController.prototype.sortByTimeSystem = function () {
var scope = this.$scope;
var sortColumn;
scope.defaultSort = undefined;
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');
}
sortColumn = this.table.columns.filter(function (column) {
return column.isCurrentTimeSystem();
})[0];
if (sortColumn) {
scope.defaultSort = sortColumn.title();
this.telemetry.sort(sortColumn.title() + '.value');
}
};
@@ -172,9 +167,6 @@ define(
* @param rows
*/
TelemetryTableController.prototype.addRowsToTable = function (rows) {
rows.forEach(function (row) {
this.$scope.rows.push(row);
}, this);
this.$scope.$broadcast('add:rows', rows);
};
@@ -237,35 +229,21 @@ 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) {
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;
});
objects.forEach(function (object) {
var metadataValues = telemetryApi.getMetadata(object).values();
metadataValues.forEach(function (metadatum) {
this.table.addColumn(object, metadatum);
}.bind(this));
}.bind(this));
this.filterColumns();
// 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);
}
this.sortByTimeSystem();
}
return objects;
@@ -302,7 +280,7 @@ define(
/*
* Process a batch of historical data
*/
function processData(historicalData, index, limitEvaluator) {
function processData(object, historicalData, index, limitEvaluator) {
if (index >= historicalData.length) {
processedObjects++;
@@ -311,14 +289,13 @@ define(
}
} else {
rowData = rowData.concat(historicalData.slice(index, index + self.batchSize)
.map(self.table.getRowValues.bind(self.table, limitEvaluator)));
.map(self.table.getRowValues.bind(self.table, object, limitEvaluator)));
/*
Use timeout to yield process to other UI activities. On
return, process next batch
*/
self.timeoutHandle = self.$timeout(function () {
processData(historicalData, index + self.batchSize, limitEvaluator);
processData(object, historicalData, index + self.batchSize, limitEvaluator);
});
}
}
@@ -327,7 +304,7 @@ define(
// Only process the most recent request
if (requestTime === self.lastRequestTime) {
var limitEvaluator = openmct.telemetry.limitEvaluator(object);
processData(historicalData, 0, limitEvaluator);
processData(object, historicalData, 0, limitEvaluator);
} else {
resolve(rowData);
}
@@ -367,7 +344,6 @@ 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) {
@@ -377,7 +353,7 @@ define(
function newData(domainObject, datum) {
limitEvaluator = telemetryApi.limitEvaluator(domainObject);
added = telemetryCollection.add([table.getRowValues(limitEvaluator, datum)]);
telemetryCollection.add([table.getRowValues(domainObject, limitEvaluator, datum)]);
}
objects.forEach(function (object) {

View File

@@ -27,31 +27,52 @@ define(
function (Table) {
describe("A table", function () {
var mockDomainObject,
var mockTableObject,
mockTelemetryObject,
mockAPI,
mockTelemetryAPI,
table,
mockTimeAPI,
mockObjectsAPI,
mockModel;
beforeEach(function () {
mockDomainObject = jasmine.createSpyObj('domainObject',
mockTableObject = jasmine.createSpyObj('domainObject',
['getModel', 'useCapability', 'getCapability', 'hasCapability']
);
mockModel = {};
mockDomainObject.getModel.and.returnValue(mockModel);
mockDomainObject.getCapability.and.callFake(function (name) {
mockTableObject.getModel.and.returnValue(mockModel);
mockTableObject.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
telemetry: mockTelemetryAPI,
time: mockTimeAPI,
objects: mockObjectsAPI
};
mockTelemetryAPI.getValueFormatter.and.callFake(function (metadata) {
var formatter = jasmine.createSpyObj(
@@ -69,7 +90,7 @@ define(
return formatter;
});
table = new Table(mockDomainObject, mockAPI);
table = new Table(mockTableObject, mockAPI);
});
describe("Building columns from telemetry metadata", function () {
@@ -77,51 +98,57 @@ define(
{
name: 'Range 1',
key: 'range1',
source: 'range1',
hints: {
y: 1
range: 1
}
},
{
name: 'Range 2',
key: 'range2',
source: 'range2',
hints: {
y: 2
range: 2
}
},
{
name: 'Domain 1',
key: 'domain1',
source: 'domain1',
format: 'utc',
hints: {
x: 1
domain: 1
}
},
{
name: 'Domain 2',
key: 'domain2',
source: 'domain2',
format: 'utc',
hints: {
x: 2
domain: 2
}
}
];
beforeEach(function () {
table.populateColumns(metadata);
mockTimeAPI.timeSystem.and.returnValue({
key: 'domain1'
});
metadata.forEach(function (metadatum) {
table.addColumn(mockTelemetryObject, metadatum);
});
});
it("populates columns", function () {
expect(table.columns.length).toBe(4);
});
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("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("Provides a default configuration with all columns" +
@@ -169,11 +196,10 @@ define(
};
}
};
rowValues = table.getRowValues(limitEvaluator, datum);
rowValues = table.getRowValues(mockTelemetryObject, 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,7 +78,8 @@ define(
]);
mockObjectAPI = jasmine.createSpyObj("objectAPI", [
"observe"
"observe",
"makeKeyString"
]);
unobserve = jasmine.createSpy("unobserve");
mockObjectAPI.observe.and.returnValue(unobserve);
@@ -184,8 +185,7 @@ define(
var mockComposition,
mockTelemetryObject,
mockChildren,
unsubscribe,
done;
unsubscribe;
beforeEach(function () {
mockComposition = jasmine.createSpyObj("composition", [
@@ -207,8 +207,6 @@ 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 () {
@@ -292,40 +290,37 @@ define(
});
describe('populates table columns', function () {
var domainMetadata;
var allMetadata;
var mockTimeSystem;
var mockTimeSystem1;
var mockTimeSystem2;
beforeEach(function () {
domainMetadata = [{
key: "column1",
name: "Column 1",
hints: {}
}];
allMetadata = [{
key: "column1",
name: "Column 1",
hints: {}
hints: {
domain: 1
}
}, {
key: "column2",
name: "Column 2",
hints: {}
hints: {
domain: 2
}
}, {
key: "column3",
name: "Column 3",
hints: {}
}];
mockTimeSystem = {
mockTimeSystem1 = {
key: "column1"
};
mockTimeSystem2 = {
key: "column2"
};
mockTelemetryAPI.commonValuesForHints.and.callFake(function (metadata, hints) {
if (_.eq(hints, ["domain"])) {
return domainMetadata;
}
});
mockConductor.timeSystem.and.returnValue(mockTimeSystem1);
mockTelemetryAPI.getMetadata.and.returnValue({
values: function () {
@@ -345,9 +340,12 @@ 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 () {
@@ -403,25 +401,16 @@ 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.on.calls.all().forEach(function (call) {
if (call.args[0] === 'added') {
call.args[1](testRows);
}
});
controller.telemetry.add(testRows);
});
it("adds it to rows in scope", function () {
expect(mockScope.rows).toEqual(expectedRows);
it("Adds the rows to the MCTTable directive", function () {
expect(mockScope.$broadcast).toHaveBeenCalledWith("add:rows", testRows);
});
});
});

View File

@@ -21,597 +21,29 @@
*****************************************************************************/
define([
"./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",
"text!./res/templates/deprecated-timeline-message.html",
'legacyRegistry'
], function (
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,
deprecatedTimelineMessage,
legacyRegistry
) {
legacyRegistry.register("platform/features/timeline", {
"name": "Timelines",
"description": "Resources, templates, CSS, and code for Timelines.",
"resources": "res",
"extensions": {
"actions": [
legacyRegistry.register('platform/features/timeline', {
extensions: {
types: [
{
"key": "timeline.export",
"name": "Export Timeline as CSV",
"category": "contextual",
"implementation": ExportTimelineAsCSVAction,
"depends": [
"$log",
"exportService",
"notificationService",
"resources[]"
]
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
}
],
"constants": [
views: [
{
"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": "%"
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
}
]
}

View File

@@ -1,77 +0,0 @@
.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

@@ -1,42 +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.
*****************************************************************************/
// 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

@@ -1,42 +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.
*****************************************************************************/
// 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

@@ -1,63 +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.
*****************************************************************************/
@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

@@ -1,185 +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.
*****************************************************************************/
.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

@@ -1,333 +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.
*****************************************************************************/
//*************************************************************** 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

@@ -1,32 +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.
*****************************************************************************/
$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

@@ -1,32 +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.
*****************************************************************************/
$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

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

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

@@ -0,0 +1,10 @@
<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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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