Compare commits

...

91 Commits

Author SHA1 Message Date
charlesh88
25ec6b6943 Cleanup maelstrom2-core
- Remove copied maelstrom-adapters plugin directory and refs
2019-08-12 16:12:41 -07:00
charlesh88
b628814f78 Remove copied maelstrom-adapters directory 2019-08-12 16:03:21 -07:00
charlesh88
a15ad6fc4c Maelstrom 2
- Updated composition export backup JSON file;
- Added MaelstromDictionary.js for backup;
2019-08-09 19:22:38 -07:00
charlesh88
767aa78b06 Maelstrom 2
- Added composition export backup JSON file to repo;
2019-08-09 16:45:42 -07:00
charlesh88
43b7efa775 Maelstrom 2 updated to latest TCR
- Merge, resolve conflicts;
- Added plugin installation in index.html for Gauge and Bignumbers;
- Fixed frame styling issues in theme-maelstrom.scss;
2019-08-09 16:44:22 -07:00
charlesh88
ac18548b42 Merge branch 'maelstrom2-core' of https://github.com/nasa/openmct into maelstrom2-core 2019-08-09 15:51:50 -07:00
charlesh88
ed3c226909 Maelstrom 2
- Add adapters
2019-08-09 15:49:57 -07:00
Andrew Henry
aafe524454 bumped version number 2019-08-06 10:36:51 -07:00
Andrew Henry
e84ade1752 Removed unnecessary extra formatting (#2438) 2019-07-31 15:18:46 -07:00
Deep Tailor
3b094e43e3 Plot y axis label fix (#2437)
* set yAxis label if none is set yet

* remove empty listener
2019-07-31 10:24:27 -07:00
Andrew Henry
e6a7b4ed6c Move table cell selection to table cell component (#2436) 2019-07-31 10:08:27 -07:00
Deep Tailor
97230bb21f Context-Menu for Tables (#2424)
* add context menu capability to table rows, add view switcher to preview

* add an option to limit context menu actions to the ones requested, and modify preview action to also include a view historical data action

* extend preview action into view historical data action

* add context menu to LAD Table

* add keys to context menu actions, allow tables to conditionally attach context menu handler

* working switch y axis label

* New vertical select element for Y axis configuration in plots

- CSS for vertically rotated selects for Y axis label selection;
- New theme constants;
- Removed themedSelect theme mixins;
- New SASS svgColorFromHex function;

* use keys in lad table context menu options

* show historical view context menu on alpha-numerics

* make reviewer requested changes

* pass contextual object path from object view down etc

* made reviewer requested changes: removed options object, pass in object path instead

* remove redundant function from LADRow.vue
2019-07-26 16:09:59 -07:00
Deep Tailor
768d99d928 Select, Mark and export selected table rows (#2420)
* first pass

* add a unmark all rows button

* enable shift click to select multiple rows

* support row selection backwards

* Styling for marked table rows

- CSS class applied;
- Export button label modified;

* working pause

* working multi select
tables are paused when user selects a row

* Layout improvements for table and control bar elements

- Table markup re-org'd;
- New .c-separator css class;
- Renamed .c-table__control-bar to .c-table-control-bar;
- Added label to Pause button;
- TODO: refine styling for table within frame in Layouts;

* Refined styling for c-button in an object frame

- More compact, better alignment, font sizing and padding;

* change logic to marking/selecting

* use command key to mark multiple

* Fixed regression errors in markup

* add isSelectable functionality

* make reviewer requested changes

* remove key from v-for in table.vue
2019-07-25 13:47:40 -07:00
Deep Tailor
c760190a29 Time conductor Improvement 625 (#2432)
* when utc based time systems are switched, the bounds will stay the same

* inline check for utcBased time systems
2019-07-25 10:08:57 -07:00
Andrew Henry
7fe4a77c43 Minor table refactoring (#2431)
* Refactor how tables process incoming data

* Fixed build in linux

* Added 'buttons' slot to tables

* Revert theme change
2019-07-22 15:08:42 -07:00
Charles Hacskaylo
8578d78c51 Fixes VISTA issue 635 scrolling messages overflow problem (#2428) 2019-07-12 10:52:16 -07:00
Deep Tailor
362e565a09 Global and Local Clear (#2418)
* first proto of global clear, working on tables

* global clear works on plots

* styling

* Status bar migration to top of layout, WIP

- Refine and remove legacy styles for Indicators;
- Significant cleanup in Indicator markup;
- Remove unnecessary wrapper component StatusBar.vue;
- Move collapse-button styles to a more general location in _controls
.scss;
- New hasMenu mixin to allow easier application of disclosure control
styling;

* Status bar migration to top of layout, WIP

- Refine styles and markup for Indicators;
- Better separation of styles for clickable and non-clickable
Indicators;

* Status bar migration to top of layout, WIP

- Added tracking style to indicator-template;
- Moved click action to button in label of globalClearIndicator;
- Removed unnecessary markup in Indicators.vue;
- Commented out __head collapse button for now in Layout.vue;

* Status Bar Migration WIP

- Significant progress styling Indicators and their hover bubbles;
- Pull back from clickable Indicators to hover approach;
- Better theme-based constants for Indicator menu-related colors;

* Status Bar Migration WIP

- Significant refactor of label element naming in multiple indicator
markup files;
- Refactor label-related CSS;
- Better class naming: no-collapse > no-minify;
- Refactor example *-launch files to use buttons instead of <a> tags;
- Significant progress on expanding shell head and button styling;

* Status Bar Migration WIP

- Cleanups, sanding on Indicator CSS;
- Added local storage retention for head expanded state;
- Adjust dark theme colors for $colorWarningHi for better legibility;
- Other minor tweaks and fixes;

* Status Bar Migration WIP

- Suppress background in Indicators;
- Restore Snow as default theme;

* add a local clear action, rename plugin

* objectViews extends eventemitter, table view provider provides an onClearData function that is called from ObjectView when clear event is emitted. TODO - support plots

* add support for plots via legacy view provider

* add test for clearDataAction

* remove focus from test file

* install the following plugins by default:
Import Export
Folder View
Tabs View
Flexible Layout
LAD Table
Go To Original Action

* update test to include plugin level tests

* remove focus from unit test
2019-07-11 16:40:26 -07:00
Pegah Sarram
9517c1f2cd [Filters] various bugs in telemetry table filters (#2425)
* Update the filters object properly when both checkboxes are deselected. Check composition before loading. Modify logic for mixed filters.

* Get compostion from the global context

* Use Set to store keyStrings

* Rename variables for clarity and add comment. Also add keystring to telemetryKeyStrings when an object is added.

* Use size to get the size of the set instead of length. Remove telemetry keystring from the configuration filters when object is removed from the composition and update the indicator label.
2019-07-02 16:17:15 -07:00
Pegah Sarram
262d35804d [Telemetry Table] Display applied filters (#2421)
* Display a list of filters that are applied to telemetry objects in a telemetry table.

* - Display 'Mixed' if filters have mixed values.
- Use table configuration domain object to get composition.

* Filter indicator styling WIP

- Markup, class names added;
- TODO: 'Mixed' and commas to be added via CSS, icon and bg coloring;

* Filter indicators styling

- CSS, markup;
- Added dynamic labeling and titling for mixed/non-mixed filter states;
- Theme colors defined and added;
- Added new filter icon glyphs for both 16px and 12px fonts;
- Revised/normalized font project and glyph file names;

* Filter indicators styling

- Adding missed Icomoon project file;

* Filter indicators styling

- Reverting mistakenly changed file;

* Filter indicators styling

- Minor fix to theme sass;
- Sync maelstrom theme;

* Fix indentation

* Set label and title to empty string initially.

* Keep the default snow.
2019-06-26 14:25:02 -07:00
Charles Hacskaylo
e0587bf0e7 Status styling (#2422)
- Primarily needed by VISTA Data Products table UI;
- Adds new styling for inline links with icons;
- Adds new status colors in theme files;
2019-06-25 17:02:23 -07:00
Andrew Henry
f1494fd285 Vista table sync (#2423)
* Working version of integrated tables

* Fixed bug with multi-composition in tables

* Changes to support tables from VISTA
2019-06-25 13:56:39 -07:00
Pegah Sarram
884aec8ea0 Alpha-numeric printf format (#2416)
* Implement an inspector view provider to display a component that allows setting printf format for alphanumeric items in a display layout.

* Display 'Mixed' in format input if items' formats in selection are different.

* Use lodash function to find index.

* Simplify code.

* Put the logic to disallow viewing the inspector view for multi-select in the inspector view provider as apposed to the inspector view component.
2019-06-14 13:33:15 -07:00
Deep Tailor
216f447578 Show error message when user tries to import an invalid object into another object (#2417)
* check composition policy before importing into parent

* use alert icon and improve message

* add a but in message

* change alert message to a more generic sentence:

* add a period
2019-06-10 15:17:43 -07:00
charlesh88
261e8e8759 Maelstrom 2 WIP
- Fixed layout tweaks for RPY plot;
- Added pulse to passenger notice in nominal mode;
2019-05-20 20:50:13 -07:00
charlesh88
cb6a8629d3 Maelstrom 2 WIP
- Tweaks;
- Styling for plot element in Attitude component;
2019-05-15 22:13:25 -07:00
charlesh88
9eead672d8 Maelstrom 2 WIP
- Added Bg Widget styling;
- Added pulse-fast class;
2019-05-04 01:20:32 -07:00
charlesh88
5da6b2c969 Maelstrom 2 WIP
- Major style refinements and additions;
- Added next-los to Dictionary;
2019-05-03 19:18:45 -07:00
charlesh88
4780cde3b5 Merge branch 'topic-core-refactor' into maelstrom2-core 2019-05-03 15:39:59 -07:00
charlesh88
1960215fc1 Maelstrom 2 WIP
- Styling for "EVRs" LAD wtable in Sys Ovw;
2019-04-28 22:42:33 -07:00
charlesh88
d06e3e12fc Merge latest TCR; add EVRs 1-5 to Maelstrom Dictionary 2019-04-28 22:41:21 -07:00
charlesh88
365998ad4f Maelstrom 2 core WIP
- Install maelstrom-adapters;
2019-04-28 14:57:40 -07:00
charlesh88
15cfa79106 Maelstrom 2 styling WIP
- Ring widgets styling;
- Minor admin;
2019-04-26 18:42:06 -07:00
charlesh88
6857e15a83 Radial Gauge
- Dial now doesn't break if current value if greater than high limit;
2019-04-26 18:41:14 -07:00
charlesh88
f1294f3e73 Maelstrom 2 WIP
- Event Time Str element styling;
2019-04-21 23:22:44 -07:00
charlesh88
d4a1f6eb35 Maelstrom 2 WIP
- Boost Phase component styles;
2019-04-19 16:11:45 -07:00
charlesh88
4c7fb0d3eb Maelstrom 2 WIP
- Much better pulse mixin;
- pulse-* styles defined;
- Layout, Time Conductor refinements;
2019-04-19 01:15:18 -07:00
charlesh88
b9017329cd Maelstrom2 WIP
- Hide s-selected border in browse mode;
- Refined timer styles;
2019-04-18 00:47:25 -07:00
charlesh88
b08834a53b Important enhancements to Gauge:
- Number of decimals and whether Min and Max values should be displayed
are now configurable properties;
2019-04-18 00:46:21 -07:00
charlesh88
eb7330522e Maelstrom2
- Timer styling
2019-04-17 01:16:22 -07:00
charlesh88
0c1cdf1d8e Merge branch 'misc-fixes-2' into maelstrom2-core 2019-04-17 00:21:21 -07:00
charlesh88
8dedf52910 Maelstrom2
- colors, styling WIP
- New _movie overrides scss file;
2019-04-17 00:15:39 -07:00
charlesh88
0420eac159 Cherry pick: Misc Fixes 2
- Better approach to title in layout frames;
- Removed unneeded !important attribs;
2019-04-16 23:33:47 -07:00
charlesh88
715e3419a0 Maelstrom2 styling
- Body font size enlarged;
- Alignment in __header__name fixed;
2019-04-16 22:21:17 -07:00
charlesh88
e6ab3ccf85 Misc Fixes 2
- Restore erroneous delete;
2019-04-16 22:03:56 -07:00
charlesh88
edf748d4a1 Misc Fixes 2
- Fix alignment issue in c-so-view__headers;
2019-04-16 22:01:36 -07:00
charlesh88
84ba444eb5 Merge latest TCR, resolve minor conflicts 2019-04-16 21:32:45 -07:00
charlesh88
6d9f3f1e3e Cherry pick merge from misc-ui-7 0908b43 2019-04-04 00:44:08 -07:00
charlesh88
ae32b902a7 Significant progress on Maelstrom 2 base styling
- New theme file;
- Mods to theme constants;
2019-04-04 00:25:41 -07:00
charlesh88
660bf805d0 Fix merge booboo in plugins.js 2019-04-02 22:54:24 -07:00
charlesh88
2f58ea9c1f Merge latest TCR, resolve minor conflicts 2019-04-02 22:36:35 -07:00
charlesh88
ba09a17b29 Get bignumbers object wired up
- Added subscription methods from gauge (thanks Deep!);
- JS now splits number into decimal and integer;
- Mod to integer SVG display to use lengthAdjust=spacingAndGlyphs;
2019-02-02 19:20:04 -08:00
charlesh88
5063fa1fb1 Set gauge initial value to 0 2019-02-02 19:17:54 -08:00
charlesh88
543b4dab4c Allow bignumbers object type to be editable. 2019-02-02 17:20:15 -08:00
Deep Tailor
ef310a8777 make gauge view editable 2019-02-02 17:11:02 -08:00
charlesh88
7d07a9e21f Delete out-of-date constants scss file 2019-02-02 16:42:54 -08:00
charlesh88
ada18faa98 Merge in latest TCR, fix conflicts 2019-02-02 16:39:45 -08:00
Deep Tailor
95d40aaeed add telemetry support with updating values 2018-11-27 16:12:55 -08:00
charlesh88
b59f5c70dc Rename Bigalpha to Bignumbers
- Tweak layout as well;
2018-11-22 20:32:38 -08:00
charlesh88
94e7351e22 Various
- Fixed config properties;
- Added method to zero pad values;
2018-11-22 16:32:16 -08:00
charlesh88
50ee7353b1 Back to original hero font; better char spacing
- Layout and char spacing tweaks;
- TODOs: change properties;
2018-11-21 23:50:00 -08:00
charlesh88
df524c4f48 Layout finessing for new hero font WIP
- Added Share Tech Mono font, change to use;
- Layout tweaks;
2018-11-21 15:10:46 -08:00
charlesh88
aa59692585 Element layout WIP 2018-11-20 23:16:18 -08:00
charlesh88
0bf82956ab Add new bigAlpha component 2018-11-20 22:15:47 -08:00
Deep Tailor
f102158ba0 add form with min, max, limit values when creating gauge 2018-11-12 09:41:12 -08:00
charlesh88
9a51bb71b9 Suppress background of frames in Layout 2018-11-10 23:54:25 -08:00
charlesh88
12b9aa75a3 Added object name as title of frame in LayoutItem 2018-11-10 23:50:16 -08:00
charlesh88
5bedfc2efd Merged in fixed baseline in symbols font from TCR 2018-11-10 22:42:58 -08:00
charlesh88
212d7c3eae Merge branch 'gauges' into maelstrom2-core 2018-11-10 22:35:45 -08:00
charlesh88
d7a3510f34 Fixed code issues in gaugeRadial 2018-11-10 22:35:19 -08:00
charlesh88
9cc44dcc4e Color tweaks, View Controls color refined 2018-11-10 00:16:02 -08:00
charlesh88
f42a5e19f0 Fixed symbols-font baselines; theme parity
- open-mct-symbols font baseline set to 0, better alignment;
- espresso and snow themes now aligned to approach in maelstrom2;
2018-11-09 22:42:25 -08:00
charlesh88
102cfc33c4 Merge latest TCR, resolve conflicts
- Mostly TCR wins, check for issues...
2018-11-09 22:11:24 -08:00
charlesh88
957c7102fe Merge latest TCR, resolve conflicts
- Mostly TCR wins, check for issues...
2018-11-09 22:06:20 -08:00
charlesh88
0519824109 Added todo 2018-11-08 00:07:10 -08:00
charlesh88
4380f88a08 Apply hero font to gauge
- Placing, sizing;
2018-11-08 00:05:28 -08:00
charlesh88
20d5db6e44 Change default Fixed Layout grid sizing 2018-11-07 23:58:59 -08:00
charlesh88
5978b8e19d Added new theme stylesheet
- Loads thematic fonts;
- Font mixins;
- Override styling for c-frame;
2018-11-07 23:58:26 -08:00
charlesh88
a0b71f92b8 Merge branch 'gauges' into maelstrom2-core 2018-11-07 22:38:27 -08:00
charlesh88
7c3f7ff384 Added description 2018-11-07 22:38:05 -08:00
charlesh88
6f2a567299 Merge in latest topic-core-refactor 2018-11-07 22:34:04 -08:00
charlesh88
746badd065 Merge in gauges branch 2018-11-07 22:30:58 -08:00
charlesh88
7d99877eb9 Fixed dial value SVG path to avoid visual overflow at 90 deg 2018-11-06 23:52:40 -08:00
charlesh88
3eac91a6d9 Added gauge icon 2018-11-06 23:31:02 -08:00
charlesh88
4d426580ae Gauge now a plugin 2018-11-06 22:48:24 -08:00
charlesh88
9270f02ca4 Merge branch 'topic-core-refactor' into gauges 2018-11-06 22:11:03 -08:00
charlesh88
815b1449f4 Merge branch 'topic-core-refactor' into gauges 2018-11-05 19:53:48 -08:00
charlesh88
0874ada4d2 Maths fixed!
TODO: clipping path shows a little sliver of dial at 90%;
2018-10-31 01:20:32 -07:00
charlesh88
03812437d3 Current value and ranges now SVG text
- Scales properly;
- Math enhancements;
- TODO: fix math when negative numbers involved;
2018-10-31 00:15:15 -07:00
charlesh88
2b8272cf05 Adding dynamic SVG text 2018-10-30 09:54:00 -07:00
charlesh88
71a2f27e0c Refined art, WIP 2018-10-26 09:39:47 -07:00
charlesh88
5460ca2009 Initial markup, CSS and code for radial gauge
- WIP!
2018-10-25 10:21:57 -07:00
108 changed files with 3776 additions and 755 deletions

View File

@@ -0,0 +1,487 @@
export default {
'telemetry': {
type: 'folder',
name: 'Maelstrom Telemetry',
type: 'folder',
location: 'ROOT',
composition: [
{
namespace: 'maelstrom',
key: 'velocity'
},{
namespace: 'maelstrom',
key: 'acceleration-ms-2'
},{
namespace: 'maelstrom',
key: 'acceleration-g'
},{
namespace: 'maelstrom',
key: 'distance'
},{
namespace: 'maelstrom',
key: 'distance-m'
},{
namespace: 'maelstrom',
key: 'roll'
},{
namespace: 'maelstrom',
key: 'pitch'
},{
namespace: 'maelstrom',
key: 'yaw'
},{
namespace: 'maelstrom',
key: 'event-index'
},{
namespace: 'maelstrom',
key: 'event-time-str'
},{
namespace: 'maelstrom',
key: 'ring'
},{
namespace: 'maelstrom',
key: 'next-los'
},{
namespace: 'maelstrom',
key: 'evr-1'
},{
namespace: 'maelstrom',
key: 'evr-2'
},{
namespace: 'maelstrom',
key: 'evr-3'
},{
namespace: 'maelstrom',
key: 'evr-4'
},{
namespace: 'maelstrom',
key: 'evr-5'
}
]
},
'velocity': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Velocity',
telemetry: {
values: [{
"key": "value",
"name": "Velocity",
"units": "ms",
"format": "float",
"source": "velocity",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'acceleration-ms-2': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Acceleration (ms^-2)',
telemetry: {
values: [{
"key": "value",
"name": "Acceleration",
"units": "ms^-2",
"format": "float",
"source": "acceleration-ms-2",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'acceleration-g': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Acceleration (G)',
telemetry: {
values: [{
"key": "value",
"name": "Acceleration",
"units": "ms^-2",
"format": "float",
"source": "acceleration-g",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'distance': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Distance (km)',
telemetry: {
values: [{
"key": "value",
"name": "Distance",
"units": "km",
"format": "float",
"source": "distance-km",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'distance-m': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Distance (m)',
telemetry: {
values: [{
"key": "value",
"name": "Distance Meters",
"units": "m",
"format": "float",
"source": "distance-m",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'roll': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Roll',
telemetry: {
values: [{
"key": "value",
"name": "Roll",
"units": "degrees",
"format": "float",
"source": "roll",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'pitch': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Pitch',
telemetry: {
values: [{
"key": "value",
"name": "Pitch",
"units": "degrees",
"format": "float",
"source": "pitch",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'yaw': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Yaw',
telemetry: {
values: [{
"key": "value",
"name": "Yaw",
"units": "degrees",
"format": "float",
"source": "yaw",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'event-index': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Event Index',
telemetry: {
values: [{
"key": "value",
"name": "Event Index",
"units": "i",
"format": "float",
"source": "event-index",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'event-time-str': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Event Time Str',
telemetry: {
values: [{
"key": "value",
"name": "Event Time Str",
"units": "",
"format": "string",
"source": "event-time-str",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'ring': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Ring',
telemetry: {
values: [{
"key": "value",
"name": "Ring",
"units": "",
"format": "int",
"source": "ring",
"hints": {
"range": 24
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'next-los': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Next LOS',
telemetry: {
values: [{
"key": "value",
"name": "Next LOS",
"units": "",
"format": "string",
"source": "next-los",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'evr-1': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'EVR 1',
telemetry: {
values: [{
"key": "value",
"name": "EVR-1",
"units": "",
"format": "string",
"source": "evr-1",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'evr-2': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'EVR 2',
telemetry: {
values: [{
"key": "value",
"name": "EVR-2",
"units": "",
"format": "string",
"source": "evr-2",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'evr-3': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'EVR 3',
telemetry: {
values: [{
"key": "value",
"name": "EVR-3",
"units": "",
"format": "string",
"source": "evr-3",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'evr-4': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'EVR 4',
telemetry: {
values: [{
"key": "value",
"name": "EVR-4",
"units": "",
"format": "string",
"source": "evr-4",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'evr-5': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'EVR 5',
telemetry: {
values: [{
"key": "value",
"name": "EVR-5",
"units": "",
"format": "string",
"source": "evr-5",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -99,10 +99,10 @@ define([
GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
return _.extend(
{},
domainObject.telemetry,
METADATA_BY_TYPE[domainObject.type]
);
{},
domainObject.telemetry,
METADATA_BY_TYPE[domainObject.type]
);
};
return GeneratorMetadataProvider;

View File

@@ -1,9 +1,9 @@
<span class="h-indicator" ng-controller="DialogLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div class="ls-indicator icon-box-with-arrow s-status-available"><span class="label">
<a ng-click="launchProgress(true)">Known</a>
<a ng-click="launchProgress(false)">Unknown</a>
<a ng-click="launchError()">Error</a>
<a ng-click="launchInfo()">Info</a>
<div class="c-indicator c-indicator--clickable icon-box-with-arrow s-status-available"><span class="label c-indicator__label">
<button ng-click="launchProgress(true)">Known</button>
<button ng-click="launchProgress(false)">Unknown</button>
<button ng-click="launchError()">Error</button>
<button ng-click="launchInfo()">Info</button>
</span></div>
</span>

View File

@@ -1,9 +1,9 @@
<span class="h-indicator" ng-controller="NotificationLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div class="ls-indicator icon-bell s-status-available"><span class="label">
<a ng-click="newInfo()">Success</a>
<a ng-click="newError()">Error</a>
<a ng-click="newAlert()">Alert</a>
<a ng-click="newProgress()">Progress</a>
<div class="c-indicator c-indicator--clickable icon-bell s-status-available"><span class="label c-indicator__label">
<button ng-click="newInfo()">Success</button>
<button ng-click="newError()">Error</button>
<button ng-click="newAlert()">Alert</button>
<button ng-click="newProgress()">Progress</button>
</span></div>
</span>

View File

@@ -45,12 +45,13 @@
].forEach(
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
);
openmct.install(openmct.plugins.Bignumbers());
openmct.install(openmct.plugins.Gauge());
openmct.install(openmct.plugins.MyItems());
openmct.install(openmct.plugins.LocalStorage());
openmct.install(openmct.plugins.Generator());
openmct.install(openmct.plugins.ExampleImagery());
openmct.install(openmct.plugins.UTCTimeSystem());
openmct.install(openmct.plugins.ImportExport());
openmct.install(openmct.plugins.AutoflowView({
type: "telemetry.panel"
}));
@@ -80,13 +81,9 @@
}));
openmct.install(openmct.plugins.SummaryWidget());
openmct.install(openmct.plugins.Notebook());
openmct.install(openmct.plugins.FolderView());
openmct.install(openmct.plugins.Tabs());
openmct.install(openmct.plugins.FlexibleLayout());
openmct.install(openmct.plugins.LADTable());
openmct.install(openmct.plugins.Filters(['table', 'telemetry.plot.overlay']));
openmct.install(openmct.plugins.ObjectMigration());
openmct.install(openmct.plugins.GoToOriginalAction());
openmct.install(openmct.plugins.ClearData(['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked']));
openmct.start();
</script>
</html>

View File

@@ -1,9 +1,10 @@
{
"name": "openmct",
"version": "0.14.0-SNAPSHOT",
"version": "1.0.0-beta",
"description": "The Open MCT core platform",
"dependencies": {},
"devDependencies": {
"acorn": "6.2.0",
"angular": "1.4.14",
"angular-route": "1.4.14",
"babel-eslint": "8.2.6",
@@ -55,7 +56,7 @@
"node-bourbon": "^4.2.3",
"node-sass": "^4.9.2",
"painterro": "^0.2.65",
"printj": "^1.1.0",
"printj": "^1.2.1",
"raw-loader": "^0.5.1",
"request": "^2.69.0",
"split": "^1.0.0",

View File

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

View File

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

View File

@@ -49,7 +49,7 @@ define(
};
ClockIndicator.prototype.getCssClass = function () {
return "t-indicator-clock icon-clock no-collapse float-right";
return "t-indicator-clock icon-clock no-minify c-indicator--not-clickable";
};
ClockIndicator.prototype.getText = function () {

View File

@@ -64,12 +64,30 @@ define(['zepto'], function ($) {
var tree = this.generateNewIdentifiers(objTree);
var rootId = tree.rootId;
var rootObj = this.instantiate(tree.openmct[rootId], rootId);
var newStyleParent = parent.useCapability('adapter');
var newStyleRootObj = rootObj.useCapability('adapter');
// Instantiate all objects in tree with their newly genereated ids,
// adding each to its rightful parent's composition
rootObj.getCapability("location").setPrimaryLocation(parent.getId());
this.deepInstantiate(rootObj, tree.openmct, []);
parent.getCapability("composition").add(rootObj);
if (this.openmct.composition.checkPolicy(newStyleParent, newStyleRootObj)) {
// Instantiate all objects in tree with their newly generated ids,
// adding each to its rightful parent's composition
rootObj.getCapability("location").setPrimaryLocation(parent.getId());
this.deepInstantiate(rootObj, tree.openmct, []);
parent.getCapability("composition").add(rootObj);
} else {
var dialog = this.openmct.overlays.dialog({
iconClass: 'alert',
message: "We're sorry, but you cannot import that object type into this object.",
buttons: [
{
label: "Ok",
emphasis: true,
callback: function () {
dialog.dismiss();
}
}
]
});
}
};
ImportAsJSONAction.prototype.deepInstantiate = function (parent, tree, seen) {

View File

@@ -100,7 +100,7 @@ define(
}
CouchIndicator.prototype.getCssClass = function () {
return "icon-database " + this.state.statusClass;
return "c-indicator--clickable icon-database " + this.state.statusClass;
};
CouchIndicator.prototype.getGlyphClass = function () {

View File

@@ -84,7 +84,7 @@ define(
}
ElasticIndicator.prototype.getCssClass = function () {
return "icon-database";
return "c-indicator--clickable icon-database";
};
ElasticIndicator.prototype.getGlyphClass = function () {
return this.state.glyphClass;

View File

@@ -41,7 +41,7 @@ define(
}
LocalStorageIndicator.prototype.getCssClass = function () {
return "icon-database s-status-caution";
return "c-indicator--clickable icon-database s-status-caution";
};
LocalStorageIndicator.prototype.getGlyphClass = function () {
return 'caution';

View File

@@ -246,12 +246,21 @@ define([
this.branding = BrandingAPI.default;
this.legacyRegistry = defaultRegistry;
// Plugin's that are installed by default
this.install(this.plugins.Plot());
this.install(this.plugins.TelemetryTable());
this.install(PreviewPlugin.default());
this.install(LegacyIndicatorsPlugin());
this.install(LicensesPlugin.default());
this.install(RemoveActionPlugin.default());
this.install(this.plugins.ImportExport());
this.install(this.plugins.FolderView());
this.install(this.plugins.Tabs());
this.install(this.plugins.FlexibleLayout());
this.install(this.plugins.LADTable());
this.install(this.plugins.GoToOriginalAction());
if (typeof BUILD_CONSTANTS !== 'undefined') {
this.install(buildInfoPlugin(BUILD_CONSTANTS));

View File

@@ -26,6 +26,7 @@ const OUTSIDE_EDIT_PATH_BLACKLIST = ["copy", "follow", "properties", "move", "li
export default class LegacyContextMenuAction {
constructor(openmct, LegacyAction) {
this.openmct = openmct;
this.key = LegacyAction.definition.key;
this.name = LegacyAction.definition.name;
this.description = LegacyAction.definition.description;
this.cssClass = LegacyAction.definition.cssClass;

View File

@@ -108,6 +108,9 @@ define([
link();
}
},
onClearData() {
scope.$broadcast('clearData');
},
destroy: function () {
element.off();
element.remove();

View File

@@ -25,7 +25,7 @@ define([
cssClass: representation.cssClass,
description: representation.description,
canView: function (selection) {
if (selection.length === 0 || selection[0].length === 0) {
if (selection.length !== 1 || selection[0].length === 0) {
return false;
}

View File

@@ -49,6 +49,9 @@ class ContextMenuAPI {
* a single sentence or short paragraph) of this kind of view
* @property {string} cssClass the CSS class to apply to labels for this
* view (to add icons, for instance)
* @property {string} key unique key to identify the context menu action
* (used in custom context menu eg table rows, to identify which actions to include)
* @property {boolean} hideInDefaultMenu optional flag to hide action from showing in the default context menu (tree item)
*/
/**
* @method appliesTo
@@ -72,12 +75,21 @@ class ContextMenuAPI {
/**
* @private
*/
_showContextMenuForObjectPath(objectPath, x, y) {
_showContextMenuForObjectPath(objectPath, x, y, actionsToBeIncluded) {
let applicableActions = this._allActions.filter((action) => {
if (action.appliesTo === undefined) {
return true;
if (actionsToBeIncluded) {
if (action.appliesTo === undefined && actionsToBeIncluded.includes(action.key)) {
return true;
}
return action.appliesTo(objectPath, actionsToBeIncluded) && actionsToBeIncluded.includes(action.key);
} else {
if (action.appliesTo === undefined) {
return true;
}
return action.appliesTo(objectPath) && !action.hideInDefaultMenu;
}
return action.appliesTo(objectPath);
});
if (this._activeContextMenu) {

View File

@@ -28,7 +28,7 @@ define(['zepto', './res/indicator-template.html'],
this.openmct = openmct;
this.element = $(indicatorTemplate)[0];
this.textElement = this.element.querySelector('.indicator-text');
this.textElement = this.element.querySelector('.js-indicator-text');
//Set defaults
this.text('New Indicator');

View File

@@ -1,3 +1,3 @@
<div class="ls-indicator" title="">
<span class="label indicator-text"></span>
<div class="c-indicator c-indicator--clickable c-indicator--simple" title="">
<span class="label js-indicator-text c-indicator__label"></span>
</div>

View File

@@ -93,7 +93,7 @@
&.message-severity-error:before {
@include legacyMessage();
content: $glyph-icon-alert-triangle;
color: $colorWarningLo;
color: $colorWarningHi;
}
// Messages in a list

View File

@@ -69,6 +69,7 @@
flex: 1 1 auto;
display: flex;
flex-direction: column;
overflow: hidden;
}
&__top-bar {

View File

@@ -38,7 +38,7 @@ define([
canEdit: function (domainObject) {
return domainObject.type === 'LadTableSet';
},
view: function (domainObject) {
view: function (domainObject, isEditing, objectPath) {
let component;
return {
@@ -49,7 +49,8 @@ define([
},
provide: {
openmct,
domainObject
domainObject,
objectPath
},
el: element,
template: '<lad-table-set></lad-table-set>'

View File

@@ -38,7 +38,7 @@ define([
canEdit: function (domainObject) {
return domainObject.type === 'LadTable';
},
view: function (domainObject) {
view: function (domainObject, isEditing, objectPath) {
let component;
return {
@@ -49,7 +49,8 @@ define([
},
provide: {
openmct,
domainObject
domainObject,
objectPath
},
el: element,
template: '<lad-table-component></lad-table-component>'

View File

@@ -1,3 +1,4 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
@@ -21,7 +22,7 @@
*****************************************************************************/
<template>
<tr>
<tr @contextmenu.prevent="showContextMenu">
<td>{{name}}</td>
<td>{{timestamp}}</td>
<td :class="valueClass">
@@ -35,15 +36,25 @@
</style>
<script>
const CONTEXT_MENU_ACTIONS = [
'viewHistoricalData',
'remove'
];
export default {
inject: ['openmct'],
inject: ['openmct', 'objectPath'],
props: ['domainObject'],
data() {
let currentObjectPath = this.objectPath.slice();
currentObjectPath.unshift(this.domainObject);
return {
name: this.domainObject.name,
timestamp: '---',
value: '---',
valueClass: ''
valueClass: '',
currentObjectPath
}
},
methods: {
@@ -73,11 +84,15 @@ export default {
.request(this.domainObject, {strategy: 'latest'})
.then((array) => this.updateValues(array[array.length - 1]));
},
showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
}
},
mounted() {
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
this.limitEvaluator = openmct
.telemetry

View File

@@ -44,7 +44,7 @@ import lodash from 'lodash';
import LadRow from './LADRow.vue';
export default {
inject: ['openmct', 'domainObject'],
inject: ['openmct', 'domainObject', 'objectPath'],
components: {
LadRow
},

View File

@@ -5,7 +5,7 @@
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* You may obtain a copy of the License atw
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software

View File

@@ -0,0 +1,71 @@
/*****************************************************************************
* 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([
'./components/bignumbers.vue',
'vue'
], function (
BignumbersComponent,
Vue
) {
function Bignumbers(openmct) {
return {
key: 'bignumbers',
name: 'Bignumbers',
cssClass: 'icon-telemetry',
canView: function (domainObject) {
return domainObject.type === 'bignumbers';
},
canEdit: function (domainObject) {
return domainObject.type === 'bignumbers';
},
view: function (domainObject) {
let component;
return {
show: function (element) {
component = new Vue({
components: {
BignumbersComponent: BignumbersComponent.default
},
provide: {
openmct,
domainObject,
composition: openmct.composition.get(domainObject)
},
el: element,
template: '<bignumbers-component></bignumbers-component>'
});
},
destroy: function (element) {
component.$destroy();
component = undefined;
}
};
},
priority: function () {
return 1;
}
};
}
return Bignumbers;
});

View File

@@ -0,0 +1,131 @@
<template>
<div class="c-bignumbers">
<svg class="c-bignumbers__int" viewBox="0 0 52 32">
<text textLength=100% lengthAdjust=spacingAndGlyphs x="0" y="32">{{ this.curValInt }}</text>
</svg>
<svg class="c-bignumbers__dec" viewBox="0 0 40 20">
<text textLength=100% lengthAdjust=spacing x="0" y="20">.{{ this.curValDec }}</text>
</svg>
<svg class="c-bignumbers__units" viewBox="0 0 45 11">
<text textLength=100% lengthAdjust=spacingAndGlyphs x="0" y="11">{{ this.units }}</text>
</svg>
</div>
</template>
<style lang="scss">
@import "~styles/sass-base";
.c-bignumbers {
$w1: 53%;
@include abs();
bottom: auto;
padding-bottom: 33%;
&__int,
&__dec,
&__units {
position: absolute;
fill: #fff;
}
&__int,
&__dec {
font-family: $heroFont;
}
&__int {
font-size: 51px;
opacity: 0.8;
width: $w1;
}
&__dec {
left: $w1;
font-size: 32px;
opacity: 0.4;
width: 100% - $w1;
}
&__units {
font-size: 9px;
font-family: $headerFont;
left: $w1;
bottom: 0;
opacity: 0.2;
width: 99% - $w1; // Font has different char spacing, so use reduced width
}
}
</style>
<script>
export default {
name: "bignumbers",
inject: ['openmct', 'domainObject', 'composition'],
data: function () {
let config = this.domainObject.configuration,
units = config.units;
console.log(config);
return {
curValInt: 0,
curValDec: 0,
units: units
}
},
methods: {
getInt: function(val, digits) {
// Extract integer portion of val and zero-pad it if its length < digits
return this.zeroPad(Math.floor(val), digits);
},
getDec: function(val, digits) {
// Extract decimal portion of val to the specified number of digits
return Number.parseFloat(val).toFixed(digits).split('.')[1];
},
zeroPad: function(val, length) {
// Zero pads an integer and returns it as a string
let s = Math.abs(val).toString();
if (s.length < length) {
for (let i = 0; i <= (length - s.length); i++) {
s = '0' + s;
}
}
if (val < 0) {
s = '-' + s;
}
return s;
},
updateValue(datum) {
let cv = this.formats[this.valueKey].format(datum);
this.curValInt = this.getInt(cv, 3);
this.curValDec = this.getDec(cv, 3);
},
subscribe(domainObject) {
this.metadata = this.openmct.telemetry.getMetadata(domainObject);
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
this.valueKey = this
.metadata
.valuesForHints(['range'])[0].key;
this.unsubscribe = this.openmct
.telemetry
.subscribe(domainObject, this.updateValue.bind(this), {});
this.openmct
.telemetry
.request(domainObject, {strategy: 'latest'})
.then((values) => values.forEach(this.updateValue));
}
},
computed: {
},
mounted() {
this.composition.on('add', this.subscribe);
this.composition.load();
},
destroyed() {
this.composition.off('add', this.subscribe);
this.unsubscribe();
}
}
</script>

View File

@@ -0,0 +1,58 @@
/*****************************************************************************
* 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([
'./bignumbers'
], function (
Bignumbers
) {
return function plugin() {
return function install(openmct) {
openmct.objectViews.addProvider(new Bignumbers(openmct));
openmct.types.addType('bignumbers', {
name: "Big Numbers",
creatable: true,
description: "Display the value of a telemetry element with units in a stylized numeric view.",
cssClass: 'icon-telemetry',
initialize(domainObject) {
domainObject.composition = [];
domainObject.configuration = {
units: ''
};
},
form: [
{
name: "Units",
control: "textfield",
cssClass: "",
key: "units",
property: [
"configuration",
"units"
]
}
]
});
};
};
});

View File

@@ -0,0 +1,39 @@
/*****************************************************************************
* 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.
*****************************************************************************/
export default class ClearDataAction {
constructor(openmct, appliesToObjects) {
this.name = 'Clear Data';
this.description = 'Clears current data for object, unsubscribes and resubscribes to data';
this._openmct = openmct;
this._appliesToObjects = appliesToObjects;
}
invoke(objectPath) {
this._openmct.objectViews.emit('clearData', objectPath[0]);
}
appliesTo(objectPath) {
let contextualDomainObject = objectPath[0];
return this._appliesToObjects.filter(type => contextualDomainObject.type === type).length;
}
}

View File

@@ -0,0 +1,18 @@
<template>
<div class="c-indicator c-indicator--clickable icon-session">
<span class="label c-indicator__label">
<button @click="globalClearEmit">Clear All Data</button>
</span>
</div>
</template>
<script>
export default {
inject: ['openmct'],
methods: {
globalClearEmit() {
this.openmct.objectViews.emit('clearData');
}
}
}
</script>

View File

@@ -0,0 +1,54 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2019, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
'./components/globalClearIndicator.vue',
'./clearDataAction',
'vue'
], function (
GlobaClearIndicator,
ClearDataAction,
Vue
) {
return function plugin(appliesToObjects) {
appliesToObjects = appliesToObjects || [];
return function install(openmct) {
let component = new Vue ({
provide: {
openmct
},
components: {
GlobalClearIndicator: GlobaClearIndicator.default
},
template: '<GlobalClearIndicator></GlobalClearIndicator>'
}),
indicator = {
element: component.$mount().$el
};
openmct.indicators.add(indicator);
openmct.contextMenu.registerAction(new ClearDataAction.default(openmct, appliesToObjects));
};
};
});

View File

@@ -0,0 +1,62 @@
/*****************************************************************************
* 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.
*****************************************************************************/
import ClearDataActionPlugin from '../plugin.js';
import ClearDataAction from '../clearDataAction.js';
describe('When the Clear Data Plugin is installed,', function () {
var mockObjectViews = jasmine.createSpyObj('objectViews', ['emit']),
mockIndicatorProvider = jasmine.createSpyObj('indicators', ['add']),
mockContextMenuProvider = jasmine.createSpyObj('contextMenu', ['registerAction']),
openmct = {
objectViews: mockObjectViews,
indicators: mockIndicatorProvider,
contextMenu: mockContextMenuProvider,
install: function (plugin) {
plugin(this);
}
},
mockObjectPath = [
{name: 'mockObject1'},
{name: 'mockObject2'}
];
it('Global Clear Indicator is installed', function () {
openmct.install(ClearDataActionPlugin([]));
expect(mockIndicatorProvider.add).toHaveBeenCalled();
});
it('Clear Data context menu action is installed', function () {
openmct.install(ClearDataActionPlugin([]));
expect(mockContextMenuProvider.registerAction).toHaveBeenCalled();
});
it('clear data action emits a clearData event when invoked', function () {
let action = new ClearDataAction(openmct);
action.invoke(mockObjectPath);
expect(mockObjectViews.emit).toHaveBeenCalledWith('clearData', mockObjectPath[0]);
});
});

View File

@@ -0,0 +1,78 @@
/*****************************************************************************
* 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([
'./components/AlphanumericFormatView.vue',
'vue'
], function (AlphanumericFormatView, Vue) {
function AlphanumericFormatViewProvider(openmct, options) {
function isTelemetryObject(selectionPath) {
let selectedObject = selectionPath[0].context.item;
let parentObject = selectionPath[1].context.item;
return parentObject &&
parentObject.type === 'layout' &&
selectedObject &&
openmct.telemetry.isTelemetryObject(selectedObject) &&
!options.showAsView.includes(selectedObject.type)
}
return {
key: 'alphanumeric-format',
name: 'Alphanumeric Format',
canView: function (selection) {
if (selection.length === 0 || selection[0].length === 1) {
return false;
}
return selection.every(isTelemetryObject);
},
view: function (domainObject, isEditing, objectPath) {
let component;
return {
show: function (element) {
component = new Vue({
provide: {
openmct,
objectPath
},
components: {
AlphanumericFormatView: AlphanumericFormatView.default
},
template: '<alphanumeric-format-view></alphanumeric-format-view>',
el: element
});
},
destroy: function () {
component.$destroy();
component = undefined;
}
}
},
priority: function () {
return 1;
}
}
}
return AlphanumericFormatViewProvider;
});

View File

@@ -0,0 +1,90 @@
/*****************************************************************************
* 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.
*****************************************************************************/
<template>
<div class="c-properties" v-if="isEditing">
<div class="c-properties__header">Alphanumeric Format</div>
<ul class="c-properties__section">
<li class="c-properties__row">
<div class="c-properties__label" title="Printf formatting for the selected telemetry">
<label for="telemetryPrintfFormat">Format</label>
</div>
<div class="c-properties__value">
<input id="telemetryPrintfFormat"
type="text"
@change="formatTelemetry"
:value="telemetryFormat"
:placeholder="nonMixedFormat ? '' : 'Mixed'"
>
</div>
</li>
</ul>
</div>
</template>
<script>
export default {
inject: ['openmct'],
data() {
let selectionPath = this.openmct.selection.get()[0];
return {
isEditing: this.openmct.editor.isEditing(),
telemetryFormat: undefined,
nonMixedFormat: false
}
},
methods: {
toggleEdit(isEditing) {
this.isEditing = isEditing;
},
formatTelemetry(event) {
let newFormat = event.currentTarget.value;
this.openmct.selection.get().forEach(selectionPath => {
selectionPath[0].context.updateTelemetryFormat(newFormat);
});
this.telemetryFormat = newFormat;
},
handleSelection(selection) {
if (selection.length === 0 || selection[0].length < 2) {
return;
}
let format = selection[0][0].context.layoutItem.format;
this.nonMixedFormat = selection.every(selectionPath => {
return selectionPath[0].context.layoutItem.format === format;
});
this.telemetryFormat = this.nonMixedFormat ? format : '';
}
},
mounted() {
this.openmct.editor.on('isEditing', this.toggleEdit);
this.openmct.selection.on('change', this.handleSelection);
this.handleSelection(this.openmct.selection.get());
},
destroyed() {
this.openmct.editor.off('isEditing', this.toggleEdit);
this.openmct.selection.off('change', this.handleSelection);
}
}
</script>

View File

@@ -48,7 +48,8 @@
:multiSelect="selectedLayoutItems.length > 1"
@move="move"
@endMove="endMove"
@endLineResize='endLineResize'>
@endLineResize='endLineResize'
@formatChanged='updateTelemetryFormat'>
</component>
<edit-marquee v-if='showMarquee'
:gridSize="gridSize"
@@ -201,7 +202,7 @@
return selectionPath && selectionPath.length > 1 && !singleSelectedLine;
}
},
inject: ['openmct', 'options'],
inject: ['openmct', 'options', 'objectPath'],
props: ['domainObject'],
components: components,
methods: {
@@ -557,6 +558,11 @@
this.layoutItems.splice(itemIndex, 1);
this.layoutItems.splice(newIndex, 0, items[itemIndex]);
}
},
updateTelemetryFormat(item, format) {
let index = _.findIndex(this.layoutItems, item);
item.format = format;
this.mutate(`configuration.items[${index}]`, item);
}
},
mounted() {

View File

@@ -27,7 +27,7 @@
@endMove="() => $emit('endMove')">
<object-frame v-if="domainObject"
:domain-object="domainObject"
:object-path="objectPath"
:object-path="currentObjectPath"
:has-frame="item.hasFrame"
:show-edit-view="false"
ref="objectFrame">
@@ -71,7 +71,7 @@
hasFrame: hasFrameByDefault(domainObject.type)
};
},
inject: ['openmct'],
inject: ['openmct', 'objectPath'],
props: {
item: Object,
gridSize: Array,
@@ -81,7 +81,7 @@
data() {
return {
domainObject: undefined,
objectPath: []
currentObjectPath: []
}
},
components: {
@@ -100,7 +100,7 @@
methods: {
setObject(domainObject) {
this.domainObject = domainObject;
this.objectPath = [this.domainObject].concat(this.openmct.router.path);
this.currentObjectPath = [this.domainObject].concat(this.objectPath.slice());
this.$nextTick(function () {
let childContext = this.$refs.objectFrame.getSelectionContext();
childContext.item = domainObject;

View File

@@ -27,7 +27,8 @@
@endMove="() => $emit('endMove')">
<div class="c-telemetry-view"
:style="styleObject"
v-if="domainObject">
v-if="domainObject"
@contextmenu.prevent="showContextMenu">
<div v-if="showLabel"
class="c-telemetry-view__label">
<div class="c-telemetry-view__label-text">{{ domainObject.name }}</div>
@@ -79,9 +80,11 @@
<script>
import LayoutFrame from './LayoutFrame.vue'
import printj from 'printj'
const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5],
DEFAULT_POSITION = [1, 1];
DEFAULT_POSITION = [1, 1],
CONTEXT_MENU_ACTIONS = ['viewHistoricalData'];
export default {
makeDefinition(openmct, gridSize, domainObject, position) {
@@ -102,7 +105,7 @@
size: "13px"
};
},
inject: ['openmct'],
inject: ['openmct', 'objectPath'],
props: {
item: Object,
gridSize: Array,
@@ -143,6 +146,10 @@
return;
}
if (this.item.format) {
return printj.sprintf(this.item.format, this.datum[this.valueMetadata.key]);
}
return this.valueFormatter && this.valueFormatter.format(this.datum);
},
telemetryClass() {
@@ -158,7 +165,8 @@
return {
datum: undefined,
formats: undefined,
domainObject: undefined
domainObject: undefined,
currentObjectPath: undefined
}
},
watch: {
@@ -168,6 +176,9 @@
}
this.context.index = newIndex;
},
item(newItem) {
this.context.layoutItem = newItem;
}
},
methods: {
@@ -210,19 +221,30 @@
},
setObject(domainObject) {
this.domainObject = domainObject;
this.keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
this.limitEvaluator = this.openmct.telemetry.limitEvaluator(this.domainObject);
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
this.requestHistoricalData();
this.subscribeToObject();
this.currentObjectPath = this.objectPath.slice();
this.currentObjectPath.unshift(this.domainObject);
this.context = {
item: domainObject,
layoutItem: this.item,
index: this.index
index: this.index,
updateTelemetryFormat: this.updateTelemetryFormat
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el, this.context, this.initSelect);
},
updateTelemetryFormat(format) {
this.$emit('formatChanged', this.item, format);
},
showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
}
},
mounted() {

View File

@@ -25,6 +25,8 @@ import Vue from 'vue'
import objectUtils from '../../api/objects/object-utils.js'
import DisplayLayoutType from './DisplayLayoutType.js'
import DisplayLayoutToolbar from './DisplayLayoutToolbar.js'
import AlphaNumericFormatViewProvider from './AlphanumericFormatViewProvider.js'
export default function DisplayLayoutPlugin(options) {
return function (openmct) {
openmct.objectViews.addProvider({
@@ -35,7 +37,7 @@ export default function DisplayLayoutPlugin(options) {
canEdit: function (domainObject) {
return domainObject.type === 'layout';
},
view: function (domainObject) {
view: function (domainObject, isEditing, objectPath) {
let component;
return {
show(container) {
@@ -47,13 +49,14 @@ export default function DisplayLayoutPlugin(options) {
provide: {
openmct,
objectUtils,
options
options,
objectPath
},
el: container,
data () {
return {
domainObject: domainObject
}
};
}
});
},
@@ -76,7 +79,8 @@ export default function DisplayLayoutPlugin(options) {
}
});
openmct.types.addType('layout', DisplayLayoutType());
openmct.toolbars.addProvider(new DisplayLayoutToolbar(openmct));
openmct.toolbars.addProvider(new DisplayLayoutToolbar(openmct, options));
openmct.inspectorViews.addProvider(new AlphaNumericFormatViewProvider(openmct, options));
openmct.composition.addPolicy((parent, child) => {
if (parent.type === 'layout' && child.type === 'folder') {
return false;

View File

@@ -63,7 +63,13 @@ export default {
if (filterValue && filterValue[comparator]) {
if (value === false) {
filterValue[comparator] = filterValue[comparator].filter(v => v !== valueName);
let filteredValueName = filterValue[comparator].filter(v => v !== valueName);
if (filteredValueName.length === 0) {
delete this.updatedFilters[key];
} else {
filterValue[comparator] = filteredValueName;
}
} else {
filterValue[comparator].push(valueName);
}
@@ -77,6 +83,14 @@ export default {
this.$emit('updateFilters', this.keyString, this.updatedFilters);
},
updateTextFilter(key, comparator, value) {
if (value.trim() === '') {
if (this.updatedFilters[key]) {
delete this.updatedFilters[key];
this.$emit('updateFilters', this.keyString, this.updatedFilters);
}
return;
}
if (!this.updatedFilters[key]) {
this.$set(this.updatedFilters, key, {});
this.$set(this.updatedFilters[key], comparator, '');

View File

@@ -59,14 +59,18 @@ export default {
removeChildren(identifier) {
let keyString = this.openmct.objects.makeKeyString(identifier);
this.$delete(this.children, keyString);
this.persistFilters(keyString);
delete this.persistedFilters[keyString];
this.mutateConfigurationFilters();
},
persistFilters(keyString, userSelects) {
this.persistedFilters[keyString] = userSelects;
this.openmct.objects.mutate(this.providedObject, 'configuration.filters', this.persistedFilters);
this.mutateConfigurationFilters();
},
updatePersistedFilters(filters) {
this.persistedFilters = filters;
},
mutateConfigurationFilters() {
this.openmct.objects.mutate(this.providedObject, 'configuration.filters', this.persistedFilters);
}
},
mounted(){

View File

@@ -0,0 +1,202 @@
<template>
<div class="c-gauge">
<div class="c-gauge__wrapper">
<svg class="c-gauge__range" viewBox="0 0 512 512">
<text class="c-gauge__curval" transform="translate(256 310)" text-anchor="middle">{{ this.curVal }}</text>
<text font-size="35" transform="translate(105 455) rotate(-45)"
v-if="displayMinMax">{{ this.rangeLow }}</text>
<text font-size="35" transform="translate(407 455) rotate(45)" text-anchor="end"
v-if="displayMinMax">{{ this.rangeHigh }}</text>
</svg>
<div class="c-dial">
<svg class="c-dial__bg" viewBox="0 0 512 512">
<g>
<path d="M256,0C114.6,0,0,114.6,0,256S114.6,512,256,512,512,397.4,512,256,397.4,0,256,0Zm0,412A156,156,0,1,1,412,256,155.9,155.9,0,0,1,256,412Z"/>
</g>
</svg>
<svg class="c-dial__limit" viewBox="0 0 512 512"
v-if="degLimit < 270"
:class="{
'c-limit-clip--90': this.degLimit > 90,
'c-limit-clip--180': this.degLimit >= 180
}">
<path d="M100,256A156,156,0,1,1,366.3,366.3L437,437a255.2,255.2,0,0,0,75-181C512,114.6,397.4,0,256,0S0,114.6,0,256A255.2,255.2,0,0,0,75,437l70.7-70.7A155.5,155.5,0,0,1,100,256Z"
:style="`transform: rotate(${this.degLimit}deg)`"/>
</svg>
<svg class="c-dial__value" viewBox="0 0 512 512"
v-if="this.degValue > 0"
:class="{
'c-dial-clip--90': this.degValue < 90,
'c-dial-clip--180': this.degValue >= 90 && this.degValue < 180
}">
<path d="M256,31A224.3,224.3,0,0,0,98.3,95.5l48.4,49.2a156,156,0,1,1-1,221.6L96.9,415.1A224.4,224.4,0,0,0,256,481c124.3,0,225-100.7,225-225S380.3,31,256,31Z"
:style="`transform: rotate(${this.degValue}deg)`"/>
</svg>
</div>
</div>
</div>
</template>
<style lang="scss">
@import "~styles/sass-base";
.c-gauge {
@include abs();
overflow: hidden;
&__wrapper {
position: absolute;
width: 100%;
padding-bottom: 100%;
overflow: hidden;
}
&__value {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
font-size: 3vw;
}
&__range {
$o: 21%;
position: absolute;
fill: rgba(#fff, 0.8);
}
&__curval {
font-family: $heroFont;
font-size: 170px;
}
}
.c-dial {
// Dial elements
@include abs();
clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 50%, 0 100%);
svg,
&__ticks,
&__bg,
&__limit,
&__value {
@include abs();
}
svg {
path {
transform-origin: center;
}
}
&__limit {
&.c-limit-clip--90 {
clip-path: polygon(0 0, 100% 0, 100% 100%);
}
&.c-limit-clip--180 {
clip-path: polygon(100% 0, 100% 100%, 0 100%);
}
path {
fill: rgba(orange, 0.4);
}
}
&__value {
&.c-dial-clip--90 {
clip-path: polygon(0 0, 50% 50%, 0 100%);
}
&.c-dial-clip--180 {
clip-path: polygon(0 0, 100% 0, 0 100%);
}
path {
fill: rgba(#fff, 0.8);
}
}
&__bg {
g {
fill: rgba(#fff, 0.1);
}
}
}
</style>
<script>
export default {
name: "gaugeRadial",
inject: ['openmct', 'domainObject', 'composition'],
data: function () {
let config = this.domainObject.configuration,
rangeLow = config.min,
rangeHigh = config.max,
displayMinMax = config.displayMinMax,
limit = config.limit,
decimals = config.decimals;
return {
rangeLow,
rangeHigh,
displayMinMax: displayMinMax.indexOf('Yes') !== -1,
limit1: limit,
decimals,
curVal: 0
}
},
methods: {
round: function(val, decimals) {
let precision = Math.pow(10, decimals);
return Math.round(val * precision)/precision;
},
valToPercent: function(vValue) {
// Don't let the current value exceed the high range, or the dial won't display right
if (vValue >= this.rangeHigh) { return 100; }
return ((vValue - this.rangeLow) / (this.rangeHigh - this.rangeLow)) * 100;
},
percentToDegrees: function(vPercent) {
return this.round((vPercent/100)*270, 2);
},
updateValue(datum) {
this.curVal = this.round(this.formats[this.valueKey].format(datum), this.decimals);
},
subscribe(domainObject) {
this.metadata = this.openmct.telemetry.getMetadata(domainObject);
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
this.valueKey = this
.metadata
.valuesForHints(['range'])[0].key;
this.unsubscribe = this.openmct
.telemetry
.subscribe(domainObject, this.updateValue.bind(this), {});
this.openmct
.telemetry
.request(domainObject, {strategy: 'latest'})
.then((values) => values.forEach(this.updateValue));
}
},
computed: {
degValue: function() {
return this.percentToDegrees(this.valToPercent(this.curVal));
},
degLimit: function() {
return this.percentToDegrees(this.valToPercent(this.limit1));
}
},
mounted() {
this.composition.on('add', this.subscribe);
this.composition.load();
},
destroyed() {
this.composition.off('add', this.subscribe);
this.unsubscribe();
}
}
</script>

View File

@@ -0,0 +1,71 @@
/*****************************************************************************
* 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([
'./components/gaugeRadial.vue',
'vue'
], function (
GaugeComponent,
Vue
) {
function Gauge(openmct) {
return {
key: 'gauge',
name: 'Gauge',
cssClass: 'icon-gauge',
canView: function (domainObject) {
return domainObject.type === 'gauge';
},
canEdit: function (domainObject) {
return domainObject.type === 'gauge';
},
view: function (domainObject) {
let component;
return {
show: function (element) {
component = new Vue({
components: {
GaugeComponent: GaugeComponent.default
},
provide: {
openmct,
domainObject,
composition: openmct.composition.get(domainObject)
},
el: element,
template: '<gauge-component></gauge-component>'
});
},
destroy: function (element) {
component.$destroy();
component = undefined;
}
};
},
priority: function () {
return 1;
}
};
}
return Gauge;
});

102
src/plugins/gauge/plugin.js Normal file
View File

@@ -0,0 +1,102 @@
/*****************************************************************************
* 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([
'./gauge'
], function (
Gauge
) {
return function plugin() {
return function install(openmct) {
openmct.objectViews.addProvider(new Gauge(openmct));
openmct.types.addType('gauge', {
name: "Gauge",
creatable: true,
description: "Graphically visualize a telemetry element's current value between a minimum and maximum.",
cssClass: 'icon-gauge',
initialize(domainObject) {
domainObject.composition = [];
domainObject.configuration = {
min: 0,
max: 100,
displayMinMax: 'Yes',
limit: 90,
decimals: 1
};
},
form: [
{
name: "Minimum Value",
control: "numberfield",
cssClass: "l-input-sm l-numeric",
key: "min",
property: [
"configuration",
"min"
]
},
{
name: "Maximum Value",
control: "numberfield",
cssClass: "l-input-sm l-numeric",
key: "max",
property: [
"configuration",
"max"
]
},
{
name: "Display Min/Max",
control: "textfield",
cssClass: "l-input-sm",
key: "displayMinMax",
property: [
"configuration",
"displayMinMax"
]
},
{
name: "Limit",
control: "numberfield",
cssClass: "l-input-sm l-numeric",
key: "min",
property: [
"configuration",
"limit"
]
},
{
name: "Decimals",
control: "numberfield",
cssClass: "l-input-sm l-numeric",
key: "decimals",
property: [
"configuration",
"decimals"
]
}
]
});
};
};
});

View File

@@ -23,6 +23,7 @@
export default class GoToOriginalAction {
constructor(openmct) {
this.name = 'Go To Original';
this.key = 'goToOriginal';
this.description = 'Go to the original unlinked instance of this object';
this._openmct = openmct;

View File

@@ -115,10 +115,22 @@
width: (tickWidth + 30) + 'px'
}">
<div class="gl-plot-label gl-plot-y-label">
<div class="gl-plot-label gl-plot-y-label" ng-if="!yKeyOptions">
{{ yAxis.get('label') }}
</div>
<div class="gl-plot-label gl-plot-y-label" ng-if="yKeyOptions.length > 1 && series.length === 1">
<select class="gl-plot-y-label__select"
ng-model="yAxisLabel" ng-change="plot.toggleYAxisLabel(yAxisLabel, yKeyOptions, series[0])">
<option ng-repeat="option in yKeyOptions"
value="{{option.name}}"
ng-selected="option.name === yAxisLabel">
{{option.name}}
</option>
</select>
</div>
<mct-ticks axis="yAxis">
<div ng-repeat="tick in ticks track by tick.text"
class="gl-plot-tick gl-plot-y-tick-label"

View File

@@ -377,6 +377,19 @@ define([
delete this.unsubscribe;
}
this.fetch();
},
/**
* Clears the plot series, unsubscribes and resubscribes
* @public
*/
refresh: function () {
this.reset();
if (this.unsubscribe) {
this.unsubscribe();
delete this.unsubscribe;
}
this.fetch();
}
});

View File

@@ -93,6 +93,8 @@ define([
this.$scope.series = this.config.series.models;
this.$scope.legend = this.config.legend;
this.$scope.yAxisLabel = this.config.yAxis.get('label');
this.cursorGuideVertical = this.$element[0].querySelector('.js-cursor-guide--v');
this.cursorGuideHorizontal = this.$element[0].querySelector('.js-cursor-guide--h');
this.cursorGuide = false;
@@ -103,9 +105,35 @@ define([
this.listenTo(this.$scope, 'plot:tickWidth', this.onTickWidthChange, this);
this.listenTo(this.$scope, 'plot:highlight:set', this.onPlotHighlightSet, this);
this.listenTo(this.$scope, 'plot:reinitializeCanvas', this.initCanvas, this);
this.listenTo(this.config.xAxis, 'change:displayRange', this.onXAxisChange, this);
this.listenTo(this.config.yAxis, 'change:displayRange', this.onYAxisChange, this);
this.setUpYAxisOptions();
};
MCTPlotController.prototype.setUpYAxisOptions = function () {
if (this.$scope.series.length === 1) {
let metadata = this.$scope.series[0].metadata;
this.$scope.yKeyOptions = metadata
.valuesForHints(['range'])
.map(function (o) {
return {
name: o.name,
key: o.key
};
});
// set yAxisLabel if none is set yet
if (this.$scope.yAxisLabel === 'none') {
let yKey = this.$scope.series[0].model.yKey,
yKeyModel = this.$scope.yKeyOptions.filter(o => o.key === yKey)[0];
this.$scope.yAxisLabel = yKeyModel.name;
}
} else {
this.$scope.yKeyOptions = undefined;
}
};
MCTPlotController.prototype.onXAxisChange = function (displayBounds) {
@@ -493,5 +521,13 @@ define([
this.cursorGuide = !this.cursorGuide;
};
MCTPlotController.prototype.toggleYAxisLabel = function (label, options, series) {
let yAxisObject = options.filter(o => o.name === label)[0];
if (yAxisObject) {
series.emit('change:yKey', yAxisObject.key);
}
};
return MCTPlotController;
});

View File

@@ -63,8 +63,11 @@ define([
$scope.pending = 0;
this.clearData = this.clearData.bind(this);
this.listenTo($scope, 'user:viewport:change:end', this.onUserViewportChangeEnd, this);
this.listenTo($scope, '$destroy', this.destroy, this);
this.listenTo($scope, 'clearData', this.clearData);
this.config = this.getConfig(this.$scope.domainObject);
this.listenTo(this.config.series, 'add', this.addSeries, this);
@@ -74,6 +77,7 @@ define([
this.followTimeConductor();
this.newStyleDomainObject = $scope.domainObject.useCapability('adapter');
this.keyString = this.openmct.objects.makeKeyString(this.newStyleDomainObject.identifier);
this.filterObserver = this.openmct.objects.observe(
this.newStyleDomainObject,
@@ -263,6 +267,12 @@ define([
});
};
PlotController.prototype.clearData = function () {
this.config.series.forEach(function (series) {
series.refresh();
});
};
/**
* Export view as JPG.
*/

View File

@@ -43,7 +43,10 @@ define([
'./LADTable/plugin',
'./filters/plugin',
'./objectMigration/plugin',
'./goToOriginalAction/plugin'
'./goToOriginalAction/plugin',
'./clearData/plugin',
'./gauge/plugin',
'./bignumbers/plugin'
], function (
_,
UTCTimeSystem,
@@ -67,7 +70,10 @@ define([
LADTable,
Filters,
ObjectMigration,
GoToOriginalAction
GoToOriginalAction,
ClearData,
Gauge,
Bignumbers
) {
var bundleMap = {
LocalStorage: 'platform/persistence/local',
@@ -99,7 +105,6 @@ define([
* to exclusively.
*/
plugins.AutoflowView = AutoflowPlugin;
plugins.Conductor = TimeConductorPlugin.default;
plugins.CouchDB = function (url) {
@@ -166,6 +171,9 @@ define([
plugins.Filters = Filters;
plugins.ObjectMigration = ObjectMigration.default;
plugins.GoToOriginalAction = GoToOriginalAction.default;
plugins.ClearData = ClearData;
plugins.Gauge = Gauge;
plugins.Bignumbers = Bignumbers;
return plugins;
});

View File

@@ -23,6 +23,7 @@
export default class RemoveAction {
constructor(openmct) {
this.name = 'Remove';
this.key = 'remove';
this.description = 'Remove this object from its containing object.';
this.cssClass = "icon-trash";

View File

@@ -37,7 +37,7 @@ define([
key: 'table-configuration',
name: 'Telemetry Table Configuration',
canView: function (selection) {
if (selection.length === 0 || selection[0].length === 0) {
if (selection.length !== 1 || selection[0].length === 0) {
return false;
}
let object = selection[0][0].context.item;

View File

@@ -26,6 +26,7 @@ define([
'./collections/BoundedTableRowCollection',
'./collections/FilteredTableRowCollection',
'./TelemetryTableRow',
'./TelemetryTableColumn',
'./TelemetryTableConfiguration'
], function (
EventEmitter,
@@ -33,6 +34,7 @@ define([
BoundedTableRowCollection,
FilteredTableRowCollection,
TelemetryTableRow,
TelemetryTableColumn,
TelemetryTableConfiguration
) {
class TelemetryTable extends EventEmitter {
@@ -47,6 +49,8 @@ define([
this.telemetryObjects = [];
this.outstandingRequests = 0;
this.configuration = new TelemetryTableConfiguration(domainObject, openmct);
this.paused = false;
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
this.addTelemetryObject = this.addTelemetryObject.bind(this);
this.removeTelemetryObject = this.removeTelemetryObject.bind(this);
@@ -94,8 +98,6 @@ define([
this.tableComposition.load().then((composition) => {
composition = composition.filter(this.isTelemetryObject);
this.configuration.addColumnsForAllObjects(composition);
composition.forEach(this.addTelemetryObject);
this.tableComposition.on('add', this.addTelemetryObject);
@@ -105,7 +107,7 @@ define([
}
addTelemetryObject(telemetryObject) {
this.configuration.addColumnsForObject(telemetryObject, true);
this.addColumnsForObject(telemetryObject, true);
this.requestDataFor(telemetryObject);
this.subscribeTo(telemetryObject);
this.telemetryObjects.push(telemetryObject);
@@ -144,14 +146,17 @@ define([
let keyString = this.openmct.objects.makeKeyString(telemetryObject.identifier);
let columnMap = this.getColumnMapForObject(keyString);
let limitEvaluator = this.openmct.telemetry.limitEvaluator(telemetryObject);
let telemetryRows = telemetryData.map(datum => new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
this.boundedRows.add(telemetryRows);
this.processHistoricalData(telemetryData, columnMap, keyString, limitEvaluator);
}).finally(() => {
this.decrementOutstandingRequests();
});
}
processHistoricalData(telemetryData, columnMap, keyString, limitEvaluator) {
let telemetryRows = telemetryData.map(datum => new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
this.boundedRows.add(telemetryRows);
}
/**
* @private
*/
@@ -191,6 +196,19 @@ define([
}, {});
}
addColumnsForObject(telemetryObject) {
let metadataValues = this.openmct.telemetry.getMetadata(telemetryObject).values();
metadataValues.forEach(metadatum => {
let column = this.createColumn(metadatum);
this.configuration.addSingleColumnForObject(telemetryObject, column);
});
}
createColumn(metadatum) {
return new TelemetryTableColumn(this.openmct, metadatum);
}
subscribeTo(telemetryObject) {
let subscribeOptions = this.buildOptionsFromConfiguration(telemetryObject);
let keyString = this.openmct.objects.makeKeyString(telemetryObject.identifier);
@@ -202,10 +220,17 @@ define([
if (!this.telemetryObjects.includes(telemetryObject)) {
return;
}
this.boundedRows.add(new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
if (!this.paused) {
this.processRealtimeDatum(datum, columnMap, keyString, limitEvaluator);
}
}, subscribeOptions);
}
processRealtimeDatum(datum, columnMap, keyString, limitEvaluator) {
this.boundedRows.add(new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
}
isTelemetryObject(domainObject) {
return domainObject.hasOwnProperty('telemetry');
}
@@ -234,12 +259,24 @@ define([
}
}
pause() {
this.paused = true;
this.boundedRows.unsubscribeFromBounds();
}
unpause() {
this.paused = false;
this.boundedRows.subscribeToBounds();
this.refreshData();
}
destroy() {
this.boundedRows.destroy();
this.filteredRows.destroy();
Object.keys(this.subscriptions).forEach(this.unsubscribe, this);
this.openmct.time.off('bounds', this.refreshData);
this.openmct.time.off('timeSystem', this.refreshData);
if (this.filterObserver) {
this.filterObserver();
}

View File

@@ -21,10 +21,11 @@
*****************************************************************************/
define(function () {
class TelemetryTableColumn {
constructor (openmct, metadatum) {
constructor (openmct, metadatum, options = {selectable: false}) {
this.metadatum = metadatum;
this.formatter = openmct.telemetry.getValueFormatter(metadatum);
this.titleValue = this.metadatum.name;
this.selectable = options.selectable;
}
getKey() {
@@ -55,8 +56,7 @@ define(function () {
return formattedValue;
}
}
};
}
return TelemetryTableColumn;
});

View File

@@ -22,9 +22,8 @@
define([
'lodash',
'EventEmitter',
'./TelemetryTableColumn'
], function (_, EventEmitter, TelemetryTableColumn) {
'EventEmitter'
], function (_, EventEmitter) {
class TelemetryTableConfiguration extends EventEmitter {
constructor(domainObject, openmct) {
@@ -34,7 +33,6 @@ define([
this.openmct = openmct;
this.columns = {};
this.addColumnsForObject = this.addColumnsForObject.bind(this);
this.removeColumnsForObject = this.removeColumnsForObject.bind(this);
this.objectMutated = this.objectMutated.bind(this);
//Make copy of configuration, otherwise change detection is impossible if shared instance is being modified.
@@ -48,6 +46,7 @@ define([
configuration.hiddenColumns = configuration.hiddenColumns || {};
configuration.columnWidths = configuration.columnWidths || {};
configuration.columnOrder = configuration.columnOrder || [];
configuration.cellFormat = configuration.cellFormat || {};
configuration.autosize = configuration.autosize === undefined ? true : configuration.autosize;
return configuration;
@@ -65,26 +64,18 @@ define([
//Synchronize domain object reference. Duplicate object otherwise change detection becomes impossible.
this.domainObject = object;
//Was it the configuration that changed?
if (!_.eq(object.configuration, this.oldConfiguration)) {
if (object.configuration !== undefined && !_.eq(object.configuration, this.oldConfiguration)) {
//Make copy of configuration, otherwise change detection is impossible if shared instance is being modified.
this.oldConfiguration = JSON.parse(JSON.stringify(this.getConfiguration()));
this.emit('change', object.configuration);
}
}
addColumnsForAllObjects(objects) {
objects.forEach(object => this.addColumnsForObject(object, false));
}
addColumnsForObject(telemetryObject) {
let metadataValues = this.openmct.telemetry.getMetadata(telemetryObject).values();
addSingleColumnForObject(telemetryObject, column, position) {
let objectKeyString = this.openmct.objects.makeKeyString(telemetryObject.identifier);
this.columns[objectKeyString] = [];
metadataValues.forEach(metadatum => {
let column = new TelemetryTableColumn(this.openmct, metadatum);
this.columns[objectKeyString].push(column);
});
this.columns[objectKeyString] = this.columns[objectKeyString] || [];
position = position || this.columns[objectKeyString].length;
this.columns[objectKeyString].splice(position, 0, column);
}
removeColumnsForObject(objectIdentifier) {

View File

@@ -29,7 +29,7 @@ define([], function () {
this.limitEvaluator = limitEvaluator;
this.objectKeyString = objectKeyString;
}
getFormattedDatum(headers) {
return Object.keys(headers).reduce((formattedDatum, columnKey) => {
formattedDatum[columnKey] = this.getFormattedValue(columnKey);
@@ -42,12 +42,19 @@ define([], function () {
return column && column.getFormattedValue(this.datum[key]);
}
getRowLimitClass() {
if (!this.rowLimitClass) {
getCellComponentName(key) {
let column = this.columns[key];
return column &&
column.getCellComponentName &&
column.getCellComponentName();
}
getRowClass() {
if (!this.rowClass) {
let limitEvaluation = this.limitEvaluator.evaluate(this.datum);
this.rowLimitClass = limitEvaluation && limitEvaluation.cssClass;
this.rowClass = limitEvaluation && limitEvaluation.cssClass;
}
return this.rowLimitClass;
return this.rowClass;
}
getCellLimitClasses() {
@@ -55,12 +62,16 @@ define([], function () {
this.cellLimitClasses = Object.values(this.columns).reduce((alarmStateMap, column) => {
let limitEvaluation = this.limitEvaluator.evaluate(this.datum, column.getMetadatum());
alarmStateMap[column.getKey()] = limitEvaluation && limitEvaluation.cssClass;
return alarmStateMap;
}, {});
}
return this.cellLimitClasses;
}
getContextMenuActions() {
return [];
}
}
/**
@@ -78,4 +89,4 @@ define([], function () {
}
return TelemetryTableRow;
});
});

View File

@@ -22,12 +22,10 @@
define([
'./components/table.vue',
'../../exporters/CSVExporter',
'./TelemetryTable',
'vue'
], function (
TableComponent,
CSVExporter,
TelemetryTable,
Vue
) {
@@ -50,8 +48,7 @@ define([
canEdit(domainObject) {
return domainObject.type === 'table';
},
view(domainObject) {
let csvExporter = new CSVExporter.default();
view(domainObject, isEditing, objectPath) {
let table = new TelemetryTable(domainObject, openmct);
let component;
return {
@@ -67,16 +64,19 @@ define([
},
provide: {
openmct,
csvExporter,
table
table,
objectPath
},
el: element,
template: '<table-component :isEditing="isEditing"></table-component>'
template: '<table-component :isEditing="isEditing" :enableMarking="true"></table-component>'
});
},
onEditModeChange(isEditing) {
component.isEditing = isEditing;
},
onClearData() {
table.refreshData();
},
destroy: function (element) {
component.$destroy();
component = undefined;

View File

@@ -43,7 +43,8 @@ define(
this.sortByTimeSystem(openmct.time.timeSystem());
this.lastBounds = openmct.time.bounds();
openmct.time.on('bounds', this.bounds);
this.subscribeToBounds();
}
addOne(item) {
@@ -140,9 +141,17 @@ define(
return this.parseTime(row.datum[this.sortOptions.key]);
}
destroy() {
unsubscribeFromBounds() {
this.openmct.time.off('bounds', this.bounds);
}
subscribeToBounds() {
this.openmct.time.on('bounds', this.bounds);
}
destroy() {
this.unsubscribeFromBounds();
}
}
return BoundedTableRowCollection;
});

View File

@@ -0,0 +1,176 @@
<template>
<div v-if="filterNames.length > 0"
:title=title
class="c-filter-indication"
:class="{ 'c-filter-indication--mixed': mixed }">
<span class="c-filter-indication__mixed">{{ label }}</span>
<span v-for="(name, index) in filterNames"
class="c-filter-indication__label">
{{ name }}
</span>
</div>
</template>
<style lang="scss">
@import "~styles/sass-base";
.c-filter-indication {
@include userSelectNone();
background: $colorFilterBg;
color: $colorFilterFg;
display: flex;
align-items: center;
font-size: 0.9em;
margin-top: $interiorMarginSm;
padding: 2px;
text-transform: uppercase;
&:before {
font-family: symbolsfont-12px;
content: $glyph-icon-filter;
display: block;
font-size: 12px;
margin-right: $interiorMarginSm;
}
&__mixed {
font-weight: bold;
margin-right: $interiorMarginSm;
}
&--mixed {
.c-filter-indication__mixed {
font-style: italic;
}
}
&__label {
+ .c-filter-indication__label {
&:before {
content: ',';
}
}
}
}
</style>
<script>
const FILTER_INDICATOR_LABEL = 'Filters:';
const FILTER_INDICATOR_LABEL_MIXED = 'Mixed Filters:';
const FILTER_INDICATOR_TITLE = 'Data filters are being applied to this view.';
const FILTER_INDICATOR_TITLE_MIXED = 'A mix of data filter values are being applied to this view.';
export default {
inject: ['openmct', 'table'],
data() {
return {
filterNames: [],
filteredTelemetry: {},
mixed: false,
label: '',
title: ''
}
},
methods: {
isTelemetryObject(domainObject) {
return domainObject.hasOwnProperty('telemetry');
},
setFilterNames() {
let names = [];
this.composition && this.composition.load().then((domainObjects) => {
domainObjects.forEach(telemetryObject => {
let keyString= this.openmct.objects.makeKeyString(telemetryObject.identifier);
let filters = this.filteredTelemetry[keyString];
this.telemetryKeyStrings.add(keyString);
if (filters !== undefined) {
let metadataValues = this.openmct.telemetry.getMetadata(telemetryObject).values();
Object.keys(filters).forEach(key => {
metadataValues.forEach(metadaum => {
if (key === metadaum.key) {
names.push(metadaum.name);
}
});
});
}
});
this.filterNames = Array.from(new Set(names));
});
},
handleConfigurationChanges(configuration) {
if (!_.eq(this.filteredTelemetry, configuration.filters)) {
this.updateFilters(configuration.filters || {});
}
},
checkFiltersForMixedValues() {
let valueToCompare = this.filteredTelemetry[Object.keys(this.filteredTelemetry)[0]];
let mixed = false;
Object.values(this.filteredTelemetry).forEach(value => {
if (!_.isEqual(valueToCompare, value)) {
mixed = true;
return;
}
});
// If the filtered telemetry is not mixed at this point, check the number of available objects
// with the number of filtered telemetry. If they are not equal, the filters must be mixed.
if (mixed === false && _.size(this.filteredTelemetry) !== this.telemetryKeyStrings.size) {
mixed = true;
}
this.mixed = mixed;
},
setLabels() {
if (this.mixed) {
this.label = FILTER_INDICATOR_LABEL_MIXED;
this.title = FILTER_INDICATOR_TITLE_MIXED;
} else {
this.label = FILTER_INDICATOR_LABEL;
this.title = FILTER_INDICATOR_TITLE;
}
},
updateFilters(filters) {
this.filteredTelemetry = JSON.parse(JSON.stringify(filters));
this.setFilterNames();
this.updateIndicatorLabel();
},
addChildren(child) {
let keyString = this.openmct.objects.makeKeyString(child.identifier);
this.telemetryKeyStrings.add(keyString);
this.updateIndicatorLabel();
},
removeChildren(identifier) {
let keyString = this.openmct.objects.makeKeyString(identifier);
this.telemetryKeyStrings.delete(keyString);
this.updateIndicatorLabel();
},
updateIndicatorLabel() {
this.checkFiltersForMixedValues();
this.setLabels();
}
},
mounted() {
let filters = this.table.configuration.getConfiguration().filters || {};
this.telemetryKeyStrings = new Set();
this.composition = this.openmct.composition.get(this.table.configuration.domainObject);
if (this.composition) {
this.composition.on('add', this.addChildren);
this.composition.on('remove', this.removeChildren);
}
this.table.configuration.on('change', this.handleConfigurationChanges);
this.updateFilters(filters);
},
destroyed() {
this.table.configuration.off('change', this.handleConfigurationChanges);
if (this.composition) {
this.composition.off('add', this.addChildren);
this.composition.off('remove', this.removeChildren);
}
}
}
</script>

View File

@@ -0,0 +1,71 @@
/*****************************************************************************
* 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.
*****************************************************************************/
<template>
<td @click="selectCell($event.currentTarget, columnKey)" :title="formattedValue">{{formattedValue}}</td>
</template>
<script>
export default {
inject: ['openmct'],
props: {
row: {
type: Object,
required: true
},
columnKey: {
type: String,
require: true
},
objectPath: {
type: Array,
require: false
}
},
methods: {
selectCell(element, columnKey) {
if (this.isSelectable) {
this.openmct.selection.select([{
element: element,
context: {
type: 'table-cell',
row: this.row.objectKeyString,
column: columnKey
}
},{
element: this.openmct.layout.$refs.browseObject.$el,
context: {
item: this.objectPath[0]
}
}], false);
event.stopPropagation();
}
},
},
computed: {
formattedValue() {
return this.row.getFormattedValue(this.columnKey);
},
isSelectable() {
return this.row.columns[this.columnKey].selectable;
}
}
};
</script>

View File

@@ -23,6 +23,8 @@
</style>
<script>
import TelemetryTableColumn from '../TelemetryTableColumn';
export default {
inject: ['tableConfiguration', 'openmct'],
data() {
@@ -43,7 +45,7 @@ export default {
this.tableConfiguration.updateConfiguration(this.configuration);
},
addObject(domainObject) {
this.tableConfiguration.addColumnsForObject(domainObject, true);
this.addColumnsForObject(domainObject, true);
this.updateHeaders(this.tableConfiguration.getAllHeaders());
},
removeObject(objectIdentifier) {
@@ -56,6 +58,17 @@ export default {
toggleAutosize() {
this.configuration.autosize = !this.configuration.autosize;
this.tableConfiguration.updateConfiguration(this.configuration);
},
addColumnsForAllObjects(objects) {
objects.forEach(object => this.addColumnsForObject(object, false));
},
addColumnsForObject(telemetryObject) {
let metadataValues = this.openmct.telemetry.getMetadata(telemetryObject).values();
metadataValues.forEach(metadatum => {
let column = new TelemetryTableColumn(this.openmct, metadatum);
this.tableConfiguration.addSingleColumnForObject(telemetryObject, column);
});
}
},
mounted() {
@@ -65,7 +78,7 @@ export default {
compositionCollection.load()
.then((composition) => {
this.tableConfiguration.addColumnsForAllObjects(composition);
this.addColumnsForAllObjects(composition);
this.updateHeaders(this.tableConfiguration.getAllHeaders());
compositionCollection.on('add', this.addObject);

View File

@@ -20,26 +20,55 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<tr :style="{ top: rowTop }" :class="rowLimitClass">
<td v-for="(title, key) in headers"
<tr :style="{ top: rowTop }"
class="noselect"
:class="[
rowClass,
{'is-selected': marked}
]"
v-on="listeners">
<component v-for="(title, key) in headers"
:key="key"
:is="componentList[key]"
:columnKey="key"
:style="columnWidths[key] === undefined ? {} : { width: columnWidths[key] + 'px', 'max-width': columnWidths[key] + 'px'}"
:title="formattedRow[key]"
:class="cellLimitClasses[key]">{{formattedRow[key]}}</td>
:class="[cellLimitClasses[key], selectableColumns[key] ? 'is-selectable' : '']"
:objectPath="objectPath"
:row="row">
</component>
</tr>
</template>
<style>
.noselect {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome and Opera */
}
</style>
<script>
import TableCell from './table-cell.vue';
export default {
inject: ['openmct', 'objectPath'],
data: function () {
return {
rowTop: (this.rowOffset + this.rowIndex) * this.rowHeight + 'px',
formattedRow: this.row.getFormattedDatum(this.headers),
rowLimitClass: this.row.getRowLimitClass(),
cellLimitClasses: this.row.getCellLimitClasses()
rowClass: this.row.getRowClass(),
cellLimitClasses: this.row.getCellLimitClasses(),
componentList: Object.keys(this.headers).reduce((components, header) => {
components[header] = this.row.getCellComponentName(header) || 'table-cell';
return components
}, {}),
selectableColumns : Object.keys(this.row.columns).reduce((selectable, columnKeys) => {
selectable[columnKeys] = this.row.columns[columnKeys].selectable;
return selectable;
}, {})
}
},
props: {
@@ -55,6 +84,10 @@ export default {
type: Object,
required: true
},
objectPath: {
type: Array,
required: false
},
rowIndex: {
type: Number,
required: false,
@@ -69,6 +102,11 @@ export default {
type: Number,
required: false,
default: 0
},
marked: {
type: Boolean,
required: false,
default: false
}
},
methods: {
@@ -76,9 +114,54 @@ export default {
this.rowTop = (rowOffset + this.rowIndex) * this.rowHeight + 'px';
},
formatRow: function (row) {
this.formattedRow = row.getFormattedDatum(this.headers);
this.rowLimitClass = row.getRowLimitClass();
this.rowClass = row.getRowClass();
this.cellLimitClasses = row.getCellLimitClasses();
},
markRow: function (event) {
let keyCtrlModifier = false;
if (event.ctrlKey || event.metaKey) {
keyCtrlModifier = true;
}
if (event.shiftKey) {
this.$emit('markMultipleConcurrent', this.rowIndex);
} else {
if (this.marked) {
this.$emit('unmark', this.rowIndex, keyCtrlModifier);
} else {
this.$emit('mark', this.rowIndex, keyCtrlModifier);
}
}
},
selectCell(element, columnKey) {
if (this.selectableColumns[columnKey]) {
//TODO: This is a hack. Cannot get parent this way.
this.openmct.selection.select([{
element: element,
context: {
type: 'table-cell',
row: this.row.objectKeyString,
column: columnKey
}
},{
element: this.openmct.layout.$refs.browseObject.$el,
context: {
item: this.openmct.router.path[0]
}
}], false);
event.stopPropagation();
}
},
showContextMenu: function (event) {
event.preventDefault();
this.openmct.objects.get(this.row.objectKeyString).then((domainObject) => {
let contextualObjectPath = this.objectPath.slice();
contextualObjectPath.unshift(domainObject);
this.openmct.contextMenu._showContextMenuForObjectPath(contextualObjectPath, event.x, event.y, this.row.getContextMenuActions());
});
}
},
// TODO: use computed properties
@@ -88,6 +171,22 @@ export default {
handler: 'formatRow',
deep: false
}
},
components: {
TableCell
},
computed: {
listeners() {
let listenersObject = {
click: this.markRow
}
if (this.row.getContextMenuActions().length) {
listenersObject.contextmenu = this.showContextMenu;
}
return listenersObject;
}
}
}
</script>

View File

@@ -20,92 +20,135 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="c-table c-telemetry-table c-table--filterable c-table--sortable has-control-bar"
:class="{'loading': loading}">
<div class="c-table__control-bar c-control-bar">
<div class="c-table-wrapper">
<div class="c-table-control-bar c-control-bar">
<button class="c-button icon-download labeled"
v-on:click="exportAsCSV()"
title="Export This View's Data">
<span class="c-button__label">Export As CSV</span>
v-if="allowExport"
v-on:click="exportAllDataAsCSV()"
title="Export This View's Data">
<span class="c-button__label">Export Table Data</span>
</button>
<button class="c-button icon-download labeled"
v-if="allowExport"
v-show="markedRows.length"
v-on:click="exportMarkedDataAsCSV()"
title="Export Marked Rows As CSV">
<span class="c-button__label">Export Marked Rows</span>
</button>
<button class="c-button icon-x labeled"
v-show="markedRows.length"
v-on:click="unmarkAllRows()"
title="Unmark All Rows">
<span class="c-button__label">Unmark All Rows</span>
</button>
<div v-if="enableMarking"
class="c-separator">
</div>
<button v-if="enableMarking"
class="c-button icon-pause pause-play labeled"
:class=" paused ? 'icon-play is-paused' : 'icon-pause'"
v-on:click="togglePauseByButton()"
:title="paused ? 'Continue Data Flow' : 'Pause Data Flow'">
<span class="c-button__label">
{{paused ? 'Play' : 'Pause'}}
</span>
</button>
<slot name="buttons"></slot>
</div>
<div v-if="isDropTargetActive" class="c-telemetry-table__drop-target" :style="dropTargetStyle"></div>
<!-- Headers table -->
<div class="c-telemetry-table__headers-w js-table__headers-w" ref="headersTable" :style="{ 'max-width': widthWithScroll}">
<table class="c-table__headers c-telemetry-table__headers">
<thead>
<tr class="c-telemetry-table__headers__labels">
<table-column-header
v-for="(title, key, headerIndex) in headers"
:key="key"
:headerKey="key"
:headerIndex="headerIndex"
@sort="sortBy(key)"
@resizeColumn="resizeColumn"
@dropTargetOffsetChanged="setDropTargetOffset"
@dropTargetActive="dropTargetActive"
@reorderColumn="reorderColumn"
@resizeColumnEnd="updateConfiguredColumnWidths"
:columnWidth="columnWidths[key]"
:sortOptions="sortOptions"
:isEditing="isEditing"
><span class="c-telemetry-table__headers__label">{{title}}</span>
</table-column-header>
</tr>
<tr class="c-telemetry-table__headers__filter">
<table-column-header
v-for="(title, key, headerIndex) in headers"
:key="key"
:headerKey="key"
:headerIndex="headerIndex"
@resizeColumn="resizeColumn"
@dropTargetOffsetChanged="setDropTargetOffset"
@dropTargetActive="dropTargetActive"
@reorderColumn="reorderColumn"
@resizeColumnEnd="updateConfiguredColumnWidths"
:columnWidth="columnWidths[key]"
:isEditing="isEditing"
>
<search class="c-table__search"
v-model="filters[key]"
v-on:input="filterChanged(key)"
v-on:clear="clearFilter(key)" />
</table-column-header>
</tr>
</thead>
<div class="c-table c-telemetry-table c-table--filterable c-table--sortable has-control-bar"
:class="{
'loading': loading,
'paused' : paused
}">
<div :style="{ 'max-width': widthWithScroll, 'min-width': '150px'}"><slot></slot></div>
<div v-if="isDropTargetActive" class="c-telemetry-table__drop-target" :style="dropTargetStyle"></div>
<!-- Headers table -->
<div class="c-telemetry-table__headers-w js-table__headers-w" ref="headersTable" :style="{ 'max-width': widthWithScroll}">
<table class="c-table__headers c-telemetry-table__headers">
<thead>
<tr class="c-telemetry-table__headers__labels">
<table-column-header
v-for="(title, key, headerIndex) in headers"
:key="key"
:headerKey="key"
:headerIndex="headerIndex"
@sort="allowSorting && sortBy(key)"
@resizeColumn="resizeColumn"
@dropTargetOffsetChanged="setDropTargetOffset"
@dropTargetActive="dropTargetActive"
@reorderColumn="reorderColumn"
@resizeColumnEnd="updateConfiguredColumnWidths"
:columnWidth="columnWidths[key]"
:sortOptions="sortOptions"
:isEditing="isEditing"
><span class="c-telemetry-table__headers__label">{{title}}</span>
</table-column-header>
</tr>
<tr class="c-telemetry-table__headers__filter">
<table-column-header
v-for="(title, key, headerIndex) in headers"
:key="key"
:headerKey="key"
:headerIndex="headerIndex"
@resizeColumn="resizeColumn"
@dropTargetOffsetChanged="setDropTargetOffset"
@dropTargetActive="dropTargetActive"
@reorderColumn="reorderColumn"
@resizeColumnEnd="updateConfiguredColumnWidths"
:columnWidth="columnWidths[key]"
:isEditing="isEditing"
>
<search class="c-table__search"
v-model="filters[key]"
v-on:input="filterChanged(key)"
v-on:clear="clearFilter(key)" />
</table-column-header>
</tr>
</thead>
</table>
</div>
<!-- Content table -->
<div class="c-table__body-w c-telemetry-table__body-w js-telemetry-table__body-w" @scroll="scroll" :style="{ 'max-width': widthWithScroll}">
<div class="c-telemetry-table__scroll-forcer" :style="{ width: totalWidth + 'px' }"></div>
<table class="c-table__body c-telemetry-table__body js-telemetry-table__content"
:style="{ height: totalHeight + 'px'}">
<tbody>
<telemetry-table-row v-for="(row, rowIndex) in visibleRows"
:headers="headers"
:columnWidths="columnWidths"
:rowIndex="rowIndex"
:objectPath="objectPath"
:rowOffset="rowOffset"
:rowHeight="rowHeight"
:row="row"
:marked="row.marked"
@mark="markRow"
@unmark="unmarkRow"
@markMultipleConcurrent="markMultipleConcurrentRows">
</telemetry-table-row>
</tbody>
</table>
</div>
<!-- Sizing table -->
<table class="c-telemetry-table__sizing js-telemetry-table__sizing" :style="sizingTableWidth">
<tr>
<template v-for="(title, key) in headers">
<th :key="key" :style="{ width: configuredColumnWidths[key] + 'px', 'max-width': configuredColumnWidths[key] + 'px'}">{{title}}</th>
</template>
</tr>
<telemetry-table-row v-for="(sizingRowData, objectKeyString) in sizingRows"
:key="objectKeyString"
:headers="headers"
:columnWidths="configuredColumnWidths"
:row="sizingRowData">
</telemetry-table-row>
</table>
<telemetry-filter-indicator></telemetry-filter-indicator>
</div>
<!-- Content table -->
<div class="c-table__body-w c-telemetry-table__body-w js-telemetry-table__body-w" @scroll="scroll" :style="{ 'max-width': widthWithScroll}">
<div class="c-telemetry-table__scroll-forcer" :style="{ width: totalWidth + 'px' }"></div>
<table class="c-table__body c-telemetry-table__body js-telemetry-table__content"
:style="{ height: totalHeight + 'px'}">
<tbody>
<telemetry-table-row v-for="(row, rowIndex) in visibleRows"
:headers="headers"
:columnWidths="columnWidths"
:rowIndex="rowIndex"
:rowOffset="rowOffset"
:rowHeight="rowHeight"
:row="row">
</telemetry-table-row>
</tbody>
</table>
</div>
<!-- Sizing table -->
<table class="c-telemetry-table__sizing js-telemetry-table__sizing" :style="sizingTableWidth">
<tr>
<template v-for="(title, key) in headers">
<th :key="key" :style="{ width: configuredColumnWidths[key] + 'px', 'max-width': configuredColumnWidths[key] + 'px'}">{{title}}</th>
</template>
</tr>
<telemetry-table-row v-for="(sizingRowData, objectKeyString) in sizingRows"
:headers="headers"
:columnWidths="configuredColumnWidths"
:row="sizingRowData">
</telemetry-table-row>
</table>
</div>
</div><!-- closes c-table-wrapper -->
</template>
<style lang="scss">
@@ -131,7 +174,7 @@
display: block;
flex: 1 0 auto;
width: 100px;
vertical-align: middle; // This is crucial to hiding f**king 4px height injected by browser by default
vertical-align: middle; // This is crucial to hiding 4px height injected by browser by default
}
td {
@@ -216,6 +259,10 @@
align-items: stretch;
position: absolute;
height: 18px; // Needed when a row has empty values in its cells
&.is-selected {
background-color: $colorSelectedBg;
}
}
td {
@@ -266,6 +313,10 @@
}
}
.paused {
border: 1px solid #ff9900;
}
/******************************* LEGACY */
.s-status-taking-snapshot,
.overlay.snapshot {
@@ -279,6 +330,8 @@
import TelemetryTableRow from './table-row.vue';
import search from '../../../ui/components/search.vue';
import TableColumnHeader from './table-column-header.vue';
import TelemetryFilterIndicator from './TelemetryFilterIndicator.vue';
import CSVExporter from '../../../exporters/CSVExporter.js';
import _ from 'lodash';
const VISIBLE_ROW_COUNT = 100;
@@ -293,13 +346,30 @@ export default {
components: {
TelemetryTableRow,
TableColumnHeader,
search
search,
TelemetryFilterIndicator
},
inject: ['table', 'openmct', 'csvExporter'],
inject: ['table', 'openmct', 'objectPath'],
props: {
isEditing: {
type: Boolean,
default: false
},
allowExport: {
type: Boolean,
default: true
},
allowFiltering: {
'type': Boolean,
'default': true
},
allowSorting: {
'type': Boolean,
'default': true
},
enableMarking: {
type: Boolean,
default: false
}
},
data() {
@@ -328,7 +398,10 @@ export default {
dropOffsetLeft: undefined,
isDropTargetActive: false,
isAutosizeEnabled: configuration.autosize,
scrollW: 0
scrollW: 0,
markCounter: 0,
paused: false,
markedRows: []
}
},
computed: {
@@ -514,15 +587,27 @@ export default {
// which causes subsequent scroll to use an out of date height.
this.contentTable.style.height = this.totalHeight + 'px';
},
exportAsCSV() {
exportAsCSV(data) {
const headerKeys = Object.keys(this.headers);
const justTheData = this.table.filteredRows.getRows()
.map(row => row.getFormattedDatum(this.headers));
this.csvExporter.export(justTheData, {
this.csvExporter.export(data, {
filename: this.table.domainObject.name + '.csv',
headers: headerKeys
});
},
exportAllDataAsCSV() {
const justTheData = this.table.filteredRows.getRows()
.map(row => row.getFormattedDatum(this.headers));
this.exportAsCSV(justTheData);
},
exportMarkedDataAsCSV() {
const data = this.table.filteredRows.getRows()
.filter(row => row.marked === true)
.map(row => row.getFormattedDatum(this.headers));
this.exportAsCSV(data);
},
outstandingRequests(loading) {
this.loading = loading;
},
@@ -611,12 +696,114 @@ export default {
scrollTop = this.scrollable.scrollTop;
}, RESIZE_POLL_INTERVAL);
},
clearRowsAndRerender() {
this.visibleRows = [];
this.$nextTick().then(this.updateVisibleRows);
},
pause(pausedByButton) {
if (pausedByButton) {
this.pausedByButton = true;
}
this.paused = true;
this.table.pause();
},
unpause(unpausedByButton) {
if (unpausedByButton) {
this.paused = false;
this.table.unpause();
this.markedRows = [];
this.pausedByButton = false;
} else {
if (!this.pausedByButton) {
this.paused = false;
this.table.unpause();
this.markedRows = [];
}
}
},
togglePauseByButton() {
if (this.paused) {
this.unpause(true);
} else {
this.pause(true);
}
},
undoMarkedRows(unpause) {
this.markedRows.forEach(r => r.marked = false);
this.markedRows = [];
},
unmarkRow(rowIndex) {
this.undoMarkedRows();
this.unpause();
},
markRow(rowIndex, keyModifier) {
if (!this.enableMarking) {
return;
}
let insertMethod = 'unshift';
if (this.markedRows.length && !keyModifier) {
this.undoMarkedRows();
insertMethod = 'push';
}
let markedRow = this.visibleRows[rowIndex];
this.$set(markedRow, 'marked', true);
this.pause();
this.markedRows[insertMethod](markedRow);
},
unmarkAllRows(skipUnpause) {
this.markedRows.forEach(row => row.marked = false);
this.markedRows = [];
this.unpause();
},
markMultipleConcurrentRows(rowIndex) {
if (!this.enableMarking) {
return;
}
if (!this.markedRows.length) {
this.markRow(rowIndex);
} else {
if (this.markedRows.length > 1) {
this.markedRows.forEach((r,i) => {
if (i !== 0) {
r.marked = false;
}
});
this.markedRows.splice(1);
}
let lastRowToBeMarked = this.visibleRows[rowIndex];
let allRows = this.table.filteredRows.getRows(),
firstRowIndex = allRows.indexOf(this.markedRows[0]),
lastRowIndex = allRows.indexOf(lastRowToBeMarked);
//supports backward selection
if (lastRowIndex < firstRowIndex) {
let temp = lastRowIndex;
lastRowIndex = firstRowIndex;
firstRowIndex = temp - 1;
}
for (var i = firstRowIndex + 1; i <= lastRowIndex; i++) {
let row = allRows[i];
row.marked = true;
this.markedRows.push(row);
}
}
}
},
created() {
this.filterChanged = _.debounce(this.filterChanged, 500);
},
mounted() {
this.csvExporter = new CSVExporter();
this.rowsAdded = _.throttle(this.rowsAdded, 200);
this.rowsRemoved = _.throttle(this.rowsRemoved, 200);
this.scroll = _.throttle(this.scroll, 100);
@@ -624,6 +811,7 @@ export default {
this.table.on('object-added', this.addObject);
this.table.on('object-removed', this.removeObject);
this.table.on('outstanding-requests', this.outstandingRequests);
this.table.on('refresh', this.clearRowsAndRerender);
this.table.filteredRows.on('add', this.rowsAdded);
this.table.filteredRows.on('remove', this.rowsRemoved);
@@ -649,6 +837,7 @@ export default {
this.table.off('object-added', this.addObject);
this.table.off('object-removed', this.removeObject);
this.table.off('outstanding-requests', this.outstandingRequests);
this.table.off('refresh', this.clearRowsAndRerender);
this.table.filteredRows.off('add', this.rowsAdded);
this.table.filteredRows.off('remove', this.rowsRemoved);

View File

@@ -1,6 +0,0 @@
<tr :style="{ top: rowTop }" :class="rowLimitClass">
<td v-for="(title, key, headerIndex) in headers"
:style="{ width: columnWidths[headerIndex], 'max-width': columnWidths[headerIndex]}"
:title="formattedRow[key]"
:class="cellLimitClasses[key]">{{formattedRow[key]}}</td>
</tr>

View File

@@ -167,6 +167,7 @@ export default {
this.xAxis.scale(this.xScale);
this.xAxis.tickFormat(utcMultiTimeFormat);
this.axisElement.call(this.xAxis);
this.setScale();
},
getActiveFormatter() {
let timeSystem = this.openmct.time.timeSystem();

View File

@@ -60,7 +60,6 @@ export default {
.filter(menuOption => menuOption.clock === (clock && clock.key))
.map(menuOption => JSON.parse(JSON.stringify(this.openmct.time.timeSystems.get(menuOption.timeSystem))));
},
setTimeSystemFromView(timeSystem) {
if (timeSystem.key !== this.selectedTimeSystem.key) {
let activeClock = this.openmct.time.clock();
@@ -69,7 +68,15 @@ export default {
timeSystem: timeSystem.key
});
if (activeClock === undefined) {
this.openmct.time.timeSystem(timeSystem.key, configuration.bounds);
let bounds;
if (this.selectedTimeSystem.isUTCBased && timeSystem.isUTCBased) {
bounds = this.openmct.time.bounds();
} else {
bounds = configuration.bounds;
}
this.openmct.time.timeSystem(timeSystem.key, bounds);
} else {
this.openmct.time.timeSystem(timeSystem.key);
this.openmct.time.clockOffsets(configuration.clockOffsets);

View File

@@ -70,9 +70,6 @@ $colorBodyFgEm: #fff;
$colorGenBg: #222;
$colorHeadBg: #262626;
$colorHeadFg: $colorBodyFg;
$colorStatusBarBg: $colorHeadBg;
$colorStatusBarFg: $colorBodyFg;
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeyFg: #fff;
$colorKeyHov: #26d8ff;
@@ -101,10 +98,12 @@ $colorStatusAlertFilter: invert(78%) sepia(26%) saturate(1160%) hue-rotate(324de
$colorStatusError: #da0004;
$colorStatusErrorFilter: invert(10%) sepia(96%) saturate(4360%) hue-rotate(351deg) brightness(111%) contrast(115%);
$colorStatusBtnBg: #666; // Where is this used?
$colorStatusPartialBg: #3f5e8b;
$colorStatusCompleteBg: #457638;
$colorAlert: #ff3c00;
$colorAlertFg: #fff;
$colorWarningHi: #990000;
$colorWarningHiFg: #FF9594;
$colorWarningHi: #ff0000;
$colorWarningHiFg: #ffdad0;
$colorWarningLo: #ff9900;
$colorWarningLoFg: #523400;
$colorDiagnostic: #a4b442;
@@ -115,6 +114,8 @@ $colorInfo: #2294a2;
$colorInfoFg: #fff;
$colorOk: #33cc33;
$colorOkFg: #fff;
$colorFilterBg: #44449c;
$colorFilterFg: #8984e9;
// States
$colorPausedBg: #ff9900;
@@ -210,6 +211,10 @@ $btnStdH: 24px;
$colorCursorGuide: rgba(white, 0.6);
$shdwCursorGuide: rgba(black, 0.4) 0 0 2px;
$colorLocalControlOvrBg: rgba($colorBodyBg, 0.8);
$colorSelectBg: $colorBtnBg; // This must be a solid color, not a gradient, due to usage of SVG bg in selects
$colorSelectFg: $colorBtnFg;
$colorSelectArw: lighten($colorBtnBg, 20%);
$shdwSelect: rgba(black, 0.5) 0 0.5px 3px;
// Menus
$colorMenuBg: pullForward($colorBodyBg, 15%);
@@ -277,6 +282,11 @@ $colorIndicatorAvailable: $colorKey;
$colorIndicatorDisabled: #555555;
$colorIndicatorOn: $colorOk;
$colorIndicatorOff: #777777;
$colorIndicatorBgHov: rgba($colorHeadFg, 0.1);
$colorIndicatorMenuBg: $colorHeadBg;
$colorIndicatorMenuBgShdw: rgba(white, 0.6) 0 0 6px;
$colorIndicatorMenuFg: $colorHeadFg;
$colorIndicatorMenuFgHov: pullForward($colorHeadFg, 10%);
// Staleness
$colorTelemFresh: pullForward($colorBodyFg, 20%);
@@ -419,7 +429,3 @@ $createBtnTextTransform: uppercase;
background: linear-gradient(pullForward($c, 5%), $c);
box-shadow: rgba(black, 0.5) 0 0.5px 2px;
}
@mixin themedSelect($bg: $colorBtnBg, $fg: $colorBtnFg) {
@include cSelect(linear-gradient(lighten($bg, 5%), $bg), $fg, lighten($bg, 20%), rgba(black, 0.5) 0 0.5px 3px);
}

View File

@@ -36,9 +36,10 @@ $bodyFont: 'Chakra Petch', sans-serif;
@mixin headerFont($size: 1em) {
font-family: $headerFont;
font-size: $size * 0.8; // This font is comparatively large, so reduce it a bit
font-size: $size;
line-height: $size;
text-transform: uppercase;
word-spacing: 0.25em;
word-spacing: 0.4em;
}
@mixin bodyFont($size: 1em) {
@@ -68,14 +69,14 @@ $shdwBtns: rgba(black, 0.2) 0 1px 2px;
$shdwBtnsOverlay: rgba(black, 0.5) 0 1px 5px;
// Base colors
$colorBodyBg: #393939;
$colorBodyBg: #000000;
$colorBodyFg: #ccc;
$colorBodyFgEm: #fff;
$colorGenBg: #222;
$colorHeadBg: #262626;
$colorHeadBg: transparent;
$colorHeadFg: $colorBodyFg;
$colorStatusBarBg: $colorHeadBg;
$colorStatusBarFg: $colorBodyFg;
$colorStatusBarFg: rgba(white, 0.5);
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeyFg: #fff;
@@ -105,10 +106,12 @@ $colorStatusAlertFilter: invert(78%) sepia(26%) saturate(1160%) hue-rotate(324de
$colorStatusError: #da0004;
$colorStatusErrorFilter: invert(10%) sepia(96%) saturate(4360%) hue-rotate(351deg) brightness(111%) contrast(115%);
$colorStatusBtnBg: #666; // Where is this used?
$colorStatusPartialBg: #3f5e8b;
$colorStatusCompleteBg: #457638;
$colorAlert: #ff3c00;
$colorAlertFg: #fff;
$colorWarningHi: #990000;
$colorWarningHiFg: #FF9594;
$colorWarningHi: #ff0000;
$colorWarningHiFg: #ffdad0;
$colorWarningLo: #ff9900;
$colorWarningLoFg: #523400;
$colorDiagnostic: #a4b442;
@@ -119,6 +122,8 @@ $colorInfo: #2294a2;
$colorInfoFg: #fff;
$colorOk: #33cc33;
$colorOkFg: #fff;
$colorFilterBg: #44449c;
$colorFilterFg: #8984e9;
// States
$colorPausedBg: #ff9900;
@@ -184,7 +189,7 @@ $colorIconAliasForKeyFilter: #aaa;
$colorTabsHolderBg: rgba(black, 0.2);
// Buttons and Controls
$colorBtnBg: pullForward($colorBodyBg, 10%);
$colorBtnBg: pullForward($colorBodyBg, 30%);
$colorBtnBgHov: pullForward($colorBtnBg, 10%);
$colorBtnFg: pullForward($colorBodyFg, 10%);
$colorBtnReverseFg: pullForward($colorBtnFg, 10%);
@@ -214,6 +219,10 @@ $btnStdH: 24px;
$colorCursorGuide: rgba(white, 0.6);
$shdwCursorGuide: rgba(black, 0.4) 0 0 2px;
$colorLocalControlOvrBg: rgba($colorBodyBg, 0.8);
$colorSelectBg: $colorBtnBg; // This must be a solid color, not a gradient, due to usage of SVG bg in selects
$colorSelectFg: $colorBtnFg;
$colorSelectArw: lighten($colorBtnBg, 20%);
$shdwSelect: rgba(black, 0.5) 0 0.5px 3px;
// Menus
$colorMenuBg: pullForward($colorBodyBg, 15%);
@@ -281,6 +290,11 @@ $colorIndicatorAvailable: $colorKey;
$colorIndicatorDisabled: #555555;
$colorIndicatorOn: $colorOk;
$colorIndicatorOff: #777777;
$colorIndicatorBgHov: rgba($colorHeadFg, 0.1);
$colorIndicatorMenuBg: $colorHeadBg;
$colorIndicatorMenuBgShdw: rgba(white, 0.6) 0 0 6px;
$colorIndicatorMenuFg: $colorHeadFg;
$colorIndicatorMenuFgHov: pullForward($colorHeadFg, 10%);
// Staleness
$colorTelemFresh: pullForward($colorBodyFg, 20%);
@@ -424,10 +438,6 @@ $createBtnTextTransform: uppercase;
box-shadow: rgba(black, 0.5) 0 0.5px 2px;
}
@mixin themedSelect($bg: $colorBtnBg, $fg: $colorBtnFg) {
@include cSelect(linear-gradient(lighten($bg, 5%), $bg), $fg, lighten($bg, 20%), rgba(black, 0.5) 0 0.5px 3px);
}
/**************************************************** OVERRIDES */
.c-frame {
&:not(.no-frame) {

View File

@@ -42,6 +42,31 @@ $bodyFont: $heroFont;
font-size: $size;
}
// FONTS
@import url('https://fonts.googleapis.com/css?family=Chakra+Petch:400,600,700|Michroma|Teko:400,700');
$heroFont: "Helvetica Neue", Helvetica, Arial, sans-serif;
$headerFont: $heroFont;
$bodyFont: $heroFont;
@mixin heroFont($size: 1em) {
$mult: 1;
font-family: $heroFont;
font-size: $size * $mult;
}
@mixin headerFont($size: 1em) {
$mult: 1;
font-family: $headerFont;
font-size: $size * $mult;
}
@mixin bodyFont($size: 1em) {
$mult: 1;
font-family: $bodyFont;
font-size: $size * $mult;
}
// Functions
@function buttonBg($c: $colorBtnBg) {
@return $c;
@@ -70,9 +95,6 @@ $colorBodyFgEm: #333;
$colorGenBg: #fff;
$colorHeadBg: #eee;
$colorHeadFg: $colorBodyFg;
$colorStatusBarBg: #000;
$colorStatusBarFg: #999;
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeyFg: #fff;
$colorKeyHov: #00c0f6;
@@ -101,6 +123,8 @@ $colorStatusAlertFilter: invert(89%) sepia(26%) saturate(5035%) hue-rotate(316de
$colorStatusError: #da0004;
$colorStatusErrorFilter: invert(8%) sepia(96%) saturate(4511%) hue-rotate(352deg) brightness(136%) contrast(114%);
$colorStatusBtnBg: #666; // Where is this used?
$colorStatusPartialBg: #c9d6ff;
$colorStatusCompleteBg: #a4e4b4;
$colorAlert: #ff3c00;
$colorAlertFg: #fff;
$colorWarningHi: #990000;
@@ -115,6 +139,8 @@ $colorInfo: #2294a2;
$colorInfoFg: #fff;
$colorOk: #33cc33;
$colorOkFg: #fff;
$colorFilterBg: #a29fe2;
$colorFilterFg: #fff;
// States
$colorPausedBg: #ff9900;
@@ -210,6 +236,10 @@ $btnStdH: 24px;
$colorCursorGuide: rgba(black, 0.6);
$shdwCursorGuide: rgba(white, 0.4) 0 0 2px;
$colorLocalControlOvrBg: rgba($colorBodyFg, 0.8);
$colorSelectBg: $colorBtnBg; // This must be a solid color, not a gradient, due to usage of SVG bg in selects
$colorSelectFg: $colorBtnFg;
$colorSelectArw: lighten($colorBtnBg, 20%);
$shdwSelect: none;
// Menus
$colorMenuBg: pushBack($colorBodyBg, 10%);
@@ -277,6 +307,11 @@ $colorIndicatorAvailable: $colorKey;
$colorIndicatorDisabled: #444;
$colorIndicatorOn: $colorOk;
$colorIndicatorOff: #666;
$colorIndicatorBgHov: rgba($colorHeadFg, 0.1);
$colorIndicatorMenuBg: white;
$colorIndicatorMenuBgShdw: rgba(black, 0.6) 0 0 6px;
$colorIndicatorMenuFg: $colorHeadFg;
$colorIndicatorMenuFgHov: pullForward($colorHeadFg, 10%);
// Staleness
$colorTelemFresh: pullForward($colorBodyFg, 20%);
@@ -418,7 +453,3 @@ $createBtnTextTransform: uppercase;
@mixin themedButton($c: $colorBtnBg) {
background: $c;
}
@mixin themedSelect($bg: $colorBtnBg, $fg: $colorBtnFg) {
@include cSelect($bg, $fg, lighten($bg, 20%), none);
}

View File

@@ -141,6 +141,8 @@ $glyph-icon-grid: '\e922';
$glyph-icon-grippy-ew: '\e923';
$glyph-icon-columns: '\e924';
$glyph-icon-rows: '\e925';
$glyph-icon-filter: '\e926';
$glyph-icon-filter-outline: '\e927';
$glyph-icon-arrows-right-left: '\ea00';
$glyph-icon-arrows-up-down: '\ea01';
$glyph-icon-bullet: '\ea02';

View File

@@ -49,6 +49,21 @@ button {
}
}
&[class*='__collapse-button'] {
box-shadow: none;
background: $splitterBtnColorBg;
color: $splitterBtnColorFg;
border-radius: $smallCr;
font-size: 6px;
line-height: 90%;
padding: 3px 15px;
@include hover() {
background: $colorBtnBgHov;
color: $colorBtnFgHov;
}
}
&.is-active {
background: $colorBtnActiveBg;
color: $colorBtnActiveFg;
@@ -60,23 +75,23 @@ button {
}
}
/********* Icon Buttons */
/********* Icon Buttons and Links */
.c-click-icon {
@include cClickIcon();
}
.c-click-link {
// A clickable element, typically inline, with an icon and label
@include cControl();
cursor: pointer;
}
.c-icon-button,
.c-click-swatch {
@include cClickIconButton();
&--menu {
&:after {
content: $glyph-icon-arrow-down;
font-family: symbolsfont;
font-size: 0.7em;
margin-left: floor($interiorMarginSm * 0.8);
opacity: 0.5;
}
@include hasMenu();
}
}
@@ -126,7 +141,7 @@ button {
/******************************************************** DISCLOSURE CONTROLS */
/********* Disclosure Button */
// Provides a downward arrow icon that when clicked displays a context menu
// Provides a downward arrow icon that when clicked displays additional options and/or info.
// Always placed AFTER an element
.c-disclosure-button {
@include cClickIcon();
@@ -264,7 +279,10 @@ input[type=number]::-webkit-outer-spin-button {
// SELECTS
select {
@include appearanceNone();
@include themedSelect();
background-color: $colorSelectBg;
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10'%3e%3cpath fill='%23#{svgColorFromHex($colorSelectArw)}' d='M5 5l5-5H0z'/%3e%3c/svg%3e");
color: $colorSelectFg;
box-shadow: $shdwSelect;
background-repeat: no-repeat, no-repeat;
background-position: right .4em top 80%, 0 0;
border: none;
@@ -585,15 +603,15 @@ select {
margin-right: $m;
}
.c-separator {
@include cToolbarSeparator();
}
.c-toolbar {
> * + * {
margin-left: 2px;
}
&__button {
}
&__separator {
@include cToolbarSeparator();
}

View File

@@ -30,10 +30,10 @@
}
@font-face {
// Use https://icomoon.io/app with icomoon-project-openmct-symbols-12px.json to generate font files
// Use https://icomoon.io/app with icomoon-project-Open-MCT-Symbols-12px.json to generate font files
font-family: 'symbolsfont-12px';
src: url('./fonts/openmct-symbols-12px.woff') format('woff'),
url('./fonts/openmct-symbols-12px.ttf') format('truetype');
src: url('./fonts/Open-MCT-Symbols-12px.woff') format('woff'),
url('./fonts/Open-MCT-Symbols-12px.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
@@ -77,6 +77,8 @@
.icon-grippy-ew { @include glyphBefore($glyph-icon-grippy-ew); }
.icon-columns { @include glyphBefore($glyph-icon-columns); }
.icon-rows { @include glyphBefore($glyph-icon-rows); }
.icon-filter { @include glyphBefore($glyph-icon-filter); }
.icon-filter-outline { @include glyphBefore($glyph-icon-filter-outline); }
.icon-arrows-right-left { @include glyphBefore($glyph-icon-arrows-right-left); }
.icon-arrows-up-down { @include glyphBefore($glyph-icon-arrows-up-down); }
.icon-bullet { @include glyphBefore($glyph-icon-bullet); }
@@ -164,6 +166,8 @@
/************************** 12 PX CLASSES */
// TODO: sync with 16px redo as of 10/25/18
.icon-filter-12px { @include glyphBefore($glyph-icon-filter,'symbolsfont-12px'); }
.icon-filter-outline-12px { @include glyphBefore($glyph-icon-filter-outline,'symbolsfont-12px'); }
.icon-crosshair-12px { @include glyphBefore($glyph-icon-crosshair,'symbolsfont-12px'); }
.icon-folder-12px { @include glyphBefore($glyph-icon-folder,'symbolsfont-12px'); }
.icon-list-view-12px { @include glyphBefore($glyph-icon-list-view,'symbolsfont-12px'); }

View File

@@ -161,8 +161,7 @@ mct-plot {
height: auto;
}
&.gl-plot-y-label,
&.l-plot-y-label {
&.gl-plot-y-label {
$x: -50%;
$r: -90deg;
transform-origin: 50% 0;
@@ -172,6 +171,12 @@ mct-plot {
left: 0;
top: 50%;
white-space: nowrap;
select {
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10'%3e%3cpath fill='%23#{svgColorFromHex($colorSelectArw)}' d='M0 5l5 5V0L0 5z'/%3e%3c/svg%3e");
background-position: left .4em top 50%, 0 0;
padding: 1px $interiorMargin 1px 20px;
}
}
}

View File

@@ -782,126 +782,6 @@ mct-indicators mct-include {
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
text-transform: uppercase;
&:before {
display: inline-block;
}
.label {
// Hover bubbles that appear when hovering on an Indicator
display: inline-block;
a,
button,
s-button,
.c-button {
// Make <a> in label look like buttons
transition: $transIn;
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;
}
}
}
&.no-collapse {
display: flex;
flex-flow: row nowrap;
align-items: center;
> *,
&:before {
flex: 1 1 auto;
}
&:before {
margin-right: $interiorMarginSm;
}
}
&:not(.no-collapse) {
&: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;
z-index: 50;
&:before {
// Infobubble-style arrow element
content: '';
display: block;
position: absolute;
top: 100%;
@include triangle('down', $size: 4px, $ratio: 1, $color: $hbg);
}
}
@include hover() {
background: $bg;
.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;
}
}
/************************************************* DATETIME UI */
@mixin complexFieldHolder($myW) {
width: $myW + $interiorMargin;

View File

@@ -50,14 +50,14 @@
}
/************************** EFFECTS */
@mixin pulse($animName: pulse, $dur: 500ms, $iteration: infinite, $opacity0: 0.5, $opacity100: 1) {
@keyframes pulse {
0% { opacity: $opacity0; }
100% { opacity: $opacity100; }
@mixin pulse($animName: 'pulse', $dur: 500ms, $iteration: infinite, $prop: opacity, $val0: 0, $val100: 1, $direction: alternate) {
@keyframes #{$animName} {
0% { #{$prop}: $val0; }
100% { #{$prop}: $val100; }
}
animation-name: $animName;
animation-duration: $dur;
animation-direction: alternate;
animation-direction: $direction;
animation-iteration-count: $iteration;
animation-timing-function: ease-in-out;
}
@@ -420,20 +420,9 @@
}
}
@mixin cClickIconButton() {
// A clickable element that just includes the icon
// Background is displayed on hover
// Padding is included to facilitate a bigger hit area
// Make the icon bigger relative to its container
@mixin cClickIconButtonLayout() {
$pLR: 4px;
$pTB: 4px;
@include cControl();
background: none;
box-shadow: none;
cursor: pointer;
transition: $transOut;
border-radius: $controlCr;
padding: $pTB $pLR;
&:before,
@@ -442,6 +431,20 @@
// Needed for c-togglebutton.
font-size: 1.25em;
}
}
@mixin cClickIconButton() {
// A clickable element that just includes the icon
// Background is displayed on hover
// Padding is included to facilitate a bigger hit area
// Make the icon bigger relative to its container
@include cControl();
@include cClickIconButtonLayout();
background: none;
box-shadow: none;
cursor: pointer;
transition: $transOut;
border-radius: $controlCr;
@include hover() {
transition: $transIn;
@@ -478,6 +481,16 @@
}
}
@mixin hasMenu() {
&:after {
content: $glyph-icon-arrow-down;
font-family: symbolsfont;
font-size: 0.7em;
margin-left: floor($interiorMarginSm * 0.8);
opacity: 0.5;
}
}
@mixin cSelect($bg, $fg, $arwClr, $shdw) {
$svgArwClr: str-slice(inspect($arwClr), 2, str-length(inspect($arwClr))); // Remove initial # in color value
background: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10'%3e%3cpath fill='%23#{$svgArwClr}' d='M5 5l5-5H0z'/%3e%3c/svg%3e"), $bg;
@@ -572,6 +585,11 @@
}
}
@function svgColorFromHex($hexColor) {
// Remove initial # in color value
@return str-slice(inspect($hexColor), 2, str-length(inspect($hexColor)));
}
@mixin test($c: deeppink, $a: 0.3) {
background: rgba($c, $a) !important;
background-color: rgba($c, $a) !important;

View File

@@ -0,0 +1,447 @@
/**************************************************** CONSTANTS, MIXINS */
$bgKey: #222632;
$redKeyBg: #990000;
$redKeyBrdr: #ff0000;
$redKeyFg: rgba(white, 0.8);
$ylwKeyBg: #cc6b36;
$ylwKeyBrdr: #ffbf1a;
$ylwKeyFg: rgba(white, 0.8);
@mixin widgetOk() {
background-color: #bbb !important;
border-color: #fff !important;
color: #333 !important;
}
@mixin widgetRed() {
background-color: $redKeyBg !important;
border-color: $redKeyBrdr !important;
color: $redKeyFg !important;
}
@mixin widgetYellow() {
$c: $ylwKeyFg;
background-color: $ylwKeyBg !important;
border-color: $ylwKeyBrdr !important;
color: $ylwKeyFg !important;
}
/**************************************************** OVERRIDES */
body {
font-size: 1em;
}
.c-telemetry-view__value {
justify-content: center;
&[class*='is-limit'] {
background: transparent !important;
color: inherit !important;
&:before { display: none; }
}
}
/**************************************************** CONVENIENCE */
.u-inspectable[s-selected] {
border: none !important;
}
.c-table.c-telemetry-table {
font-size: 0.7em;
}
.widget-rule-content .t-rule-message-input {
width: 100%;
}
/**************************************************** TIME CONDUCTOR */
.c-conductor {
&__controls {
display: none !important;
}
&:hover {
.c-conductor__controls { display: flex !important; }
}
[class*='__label'] {
display: none;
}
&__end-fixed {
display: none;
}
&__end-delta {
&:after {
content: '';
display: block;
background: url('../ui/layout/assets/images/logo-app.svg') center no-repeat;
background-size: contain;
width: 100px;
height: 24px;
}
}
&-input {
input {
&.c-input--datetime,
&.c-input--hrs-min-sec {
color: $colorTime;
width: 200px;
}
&.c-input--hrs-min-sec {
width: 80px;
}
}
}
}
/**************************************************** MAIN LAYOUT */
.l-shell {
&:not(.is-editing) {
.l-shell__head,
.l-shell__main-view-browse-bar {
background: none !important;
height: $interiorMargin;
overflow: hidden;
padding: 0 !important;
position: absolute;
width: 30%;
z-index: 100;
* { opacity: 0; }
&:hover {
background: #666 !important;
height: auto;
overflow: visible;
padding: $interiorMargin !important;
* { opacity: 1; }
}
}
.l-shell__pane-main .l-pane__contents > * + * {
margin-top: 0;
}
.l-shell__main-container {
margin-top: 0 !important;
}
}
.l-shell__main-view-browse-bar {
top: -3px; right: 0;
}
&__main > .l-pane {
padding-left: $interiorMargin !important;
padding-right: $interiorMargin !important;
}
&__status { display: none !important; }
}
.l-pane {
&__contents {
overflow: visible !important;
}
&--collapsed {
$d: 5px;
flex-basis: $d !important;
min-width: $d !important;
min-height: $d !important;
.l-pane__label {
display: none !important;
}
.l-pane__collapse-button {
&:before { display: none !important; }
}
}
}
/**************************************************** STYLING BY TITLE */
*[title*='font-euro'] {
@include headerFont();
}
*[title*='key-widget'] {
font-size: 24px;
}
*[title*='alert-red'] {
.c-sw__icon {
color: red !important;
}
}
*[title*='alert-yellow'] {
.c-sw__icon {
color: $ylwKeyBg !important;
}
}
*[title*='widget-ok'] {
@include widgetOk();
}
*[title*='widget-yellow'] {
@include widgetYellow();
}
*[title*='widget-red'] {
@include widgetRed();
}
*[title*='pulse-slow'] {
@include pulse($animName: pulseSlow, $dur: 1000ms, $prop: filter, $val0: brightness(1.2), $val100: brightness(0.6), $direction: normal);
.c-sw__icon {
@include pulse($animName: pulseWarningIcon, $dur: 500ms, $prop: opacity, $val0: 0.1, $val100: 1, $direction: normal);
}
}
*[title*='pulse-fast'] {
@include pulse($animName: pulseSlow, $dur: 250ms, $prop: filter, $val0: brightness(1.5), $val100: brightness(0.9), $direction: normal);
}
*[title*='pulse-warning'] {
@include pulse($animName: pulseWarning, $dur: 1500ms, $prop: filter, $val0: brightness(1.2), $val100: brightness(0.7), $direction: normal);
}
*[title*='Bg Widget'] {
// Widgets that provide a flashing red bg for components
.c-summary-widget {
$b: 5px;
border: none !important;
border-radius: $b * 4;
&[title*='widget-yellow'] {
opacity: 0.3;
box-shadow: $ylwKeyBg 0px 0px $b $b;
}
&[title*='widget-red'] {
opacity: 0.4;
box-shadow: $redKeyBg 0px 0px $b $b;
}
}
}
/**************************************************** SECTIONS */
/************* SYS OVW WIDGETS */
*[title*='Sys Ovw'] {
*[title*='Widget'] {
font-size: 1.4em;
}
*[title*='sys-ok'] {
@include widgetOk();
}
*[title*='post-ring'] {
@include widgetRed();
}
}
/************* ATTITUDE */
*[title*='Attitude'] {
*[title*='RPY'] {
background: black;
padding: 3px;
border-radius: 5px;
.l-control-bar {
display: none;
}
.l-view-section {
top: 0;
}
.gl-plot-axis-area.gl-plot-y {
width: 22px !important;
}
.gl-plot-wrapper-display-area-and-x-axis {
left: 24px !important;
}
}
}
/************* VELOCITY COMPONENT */
*[title*='-not-attained'] {
@include widgetRed();
}
/************* ACCELERATION COMPONENT */
/************* BOOST PHASE WIDGETS */
*[title*='boost-phase-widget'] {
.c-summary-widget {
border-width: 2px;
padding: 5px 0;
&:before,
&:after {
content: '';
display: block;
position: absolute;
}
}
}
*[title*='boost-phase-widget-left'] {
.c-summary-widget {
$c: #999;
align-items: start;
background: rgba($c, 0.1) !important;
border-left: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
&:before,
&:after {
top: 25px; right: 0; bottom: 3%; left: 40%;
}
&:before {
@include bgStripes($c: $c, $a: 0.1, $bgsize: 20px, $angle: 0deg);
}
&:after {
@include bgStripes($c: $c, $a: 0.1, $bgsize: 63px, $angle: 0deg);
}
}
}
*[title*='boost-phase-widget-right'] {
.c-summary-widget {
$c: #555;
border-right: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
&:before {
//background: deeppink;
@include bgTicks($c: $c, $repeatDir: 'y');
background-size: 100% 45px;
top: 0px; right: 0; bottom: 0; left: 2px;
}
}
}
*[title*='Boost Phase Ring Widgets'] {
*[title*='Ring Widget'] {
//filter: saturate(0.7);
}
*[title*='ring-ok'] {
@include widgetOk();
}
*[title*='bad-ring'] {
@include widgetRed();
}
*[title*='post-ring'] {
@include widgetYellow();
}
}
/************* BOTTOM SYSTEM WIDGETS */
*[title*='system-widget'] {
background: $bgKey !important;
border-width: 2px !important;
justify-content: left !important;
.c-sw__icon {
$m: $interiorMarginSm;
position: absolute;
bottom: $m;
right: $m;
}
}
*[title*="Bottom System Widgets"] {
transform: translateY(-2px);
}
*[title*='system-widget--hero'] {
// Current "tab" in interface
border-top-left-radius: 0;
border-top-right-radius: 0;
border-top: none;
}
*[title*='system-widget--subtle'] {
opacity: 0.7;
}
/**************************************************** INDIVIDUAL ELEMENTS */
/************* PASSENGER NOTICE */
*[title*='passenger-notice'] {
font-size: 1.4em;
.c-sw__icon {
font-size: 2.1em;
margin-right: $interiorMarginLg;
}
}
*[title*='pulse-passenger-notice--nominal'] {
@include pulse($animName: pulseNominal, $dur: 1000ms, $prop: filter, $val0: brightness(1.4), $val100:brightness(1.0), $direction: alternate);
}
*[title*='pulse-passenger-notice--warning'] {
@include pulse($animName: pulseWarning, $dur: 750ms, $prop: background-color, $val0: #aa0000, $val100: #340000, $direction: normal);
}
*[title*='Main Console'] {
$r: $basicCr;
background: $bgKey;
border-radius: $r;
border-bottom: 2px solid rgb(102,102,102);
}
*[title*='Event Time Str'] {
@include heroFont(1.2em);
line-height: .8em;
}
*[title*="Sys Ovw LAD Table"] {
.c-lad-table {
tr {
background-color: black;
color: rgba(white, 0.3);
display: block;
font-weight: bold;
align-items: center;
height: 41px;
border-radius: 5px;
font-size: 0.75em;
margin-bottom: 4px;
overflow: hidden;
padding: 3px;
text-transform: uppercase;
}
thead,
tr td:nth-child(1),
tr td:nth-child(2) {
display: none;
}
td {
display: block;
width: auto;
white-space: normal;
}
}
}

View File

@@ -61,7 +61,7 @@
}
@mixin indicatorStatusColors($c) {
&:before, .count {
&:before, .c-indicator__count {
color: $c;
}
}
@@ -127,7 +127,7 @@ tr {
.s-status-icon-ok:before { content: $glyph-icon-check; }
/*************************************************** INDICATOR COLORING */
.ls-indicator {
.c-indicator {
&.s-status-info {
@include indicatorStatusColors($colorInfo);
}
@@ -159,3 +159,16 @@ tr {
@include indicatorStatusColors($colorStatusError);
}
}
.s-status {
&--partial {
// Partially completed things, such as a file downloading or process that's running
background-color: $colorStatusPartialBg;
}
&--complete {
// Completed things, such as a file downloaded or process that's finished
background-color: $colorStatusCompleteBg;
}
}

View File

@@ -76,23 +76,43 @@ div.c-table {
height: 100%;
}
.c-table-wrapper {
// Wraps .c-control-bar and .c-table
@include abs();
overflow: hidden;
display: flex;
flex-direction: column;
> .c-table {
height: auto;
flex: 1 1 auto;
}
> * + * {
margin-top: $interiorMarginSm;
}
}
.c-table-control-bar {
display: flex;
flex: 0 0 auto;
> * + * {
margin-left: $interiorMarginSm;
}
}
.c-table {
// Can be used by any type of table, scrolling, LAD, etc.
$min-w: 50px;
width: 100%;
&__control-bar,
&__headers-w {
flex: 0 0 auto;
}
/******************************* ELEMENTS */
&__control-bar {
margin-bottom: $interiorMarginSm;
}
thead tr,
&.c-table__headers {
background: $colorTabHeaderBg;

View File

@@ -34,3 +34,5 @@
@import "legacy";
@import "legacy-plots";
@import "legacy-messages";
@import "theme-maelstrom";
@import "movie-maelstrom";

View File

@@ -1,19 +1,35 @@
{
"metadata": {
"name": "openmct-symbols-12px",
"name": "Open MCT Symbols 12px",
"lastOpened": 0,
"created": 1527031065005
"created": 1561483556329
},
"iconSets": [
{
"selection": [
{
"order": 12,
"id": 10,
"name": "icon12-filter",
"prevSize": 12,
"code": 59686,
"tempChar": ""
},
{
"order": 14,
"id": 11,
"name": "icon12-filter-outline",
"prevSize": 12,
"code": 59687,
"tempChar": ""
},
{
"order": 9,
"id": 6,
"name": "icon12-crosshair",
"prevSize": 12,
"code": 59696,
"tempChar": ""
"tempChar": ""
},
{
"order": 11,
@@ -21,7 +37,7 @@
"name": "icon12-grippy",
"prevSize": 12,
"code": 59697,
"tempChar": ""
"tempChar": ""
},
{
"order": 10,
@@ -29,7 +45,7 @@
"name": "icon12-list-view",
"prevSize": 12,
"code": 921666,
"tempChar": ""
"tempChar": ""
},
{
"order": 6,
@@ -37,14 +53,14 @@
"prevSize": 12,
"code": 921865,
"name": "icon12-folder",
"tempChar": ""
"tempChar": ""
}
],
"id": 0,
"metadata": {
"name": "openmct-symbols-12px",
"name": "Open MCT Symbols 12px",
"importSize": {
"width": 279,
"width": 384,
"height": 384
},
"designer": "Charles Hacskaylo"
@@ -52,6 +68,28 @@
"height": 1024,
"prevSize": 12,
"icons": [
{
"id": 10,
"paths": [
"M853.333 0h-682.667c-94.135 0.302-170.364 76.532-170.667 170.638l-0 0.029v682.667c0.302 94.135 76.532 170.364 170.638 170.667l0.029 0h256v-341.333l-341.333-341.333h853.333l-341.333 341.333 1.067 341.333h254.933c94.135-0.302 170.364-76.532 170.667-170.638l0-0.029v-682.667c-0.302-94.135-76.532-170.364-170.638-170.667l-0.029-0z"
],
"attrs": [],
"grid": 0,
"tags": [
"icon12-filter"
]
},
{
"id": 11,
"paths": [
"M853.333 0h-682.667c-94.135 0.302-170.364 76.532-170.667 170.638l-0 0.029v682.667c0.302 94.135 76.532 170.364 170.638 170.667l0.029 0h682.667c94.135-0.302 170.364-76.532 170.667-170.638l0-0.029v-682.667c-0.302-94.135-76.532-170.364-170.638-170.667l-0.029-0zM170.933 853.333h-0.267v-512l256 256v256zM853.067 853.333h-255.2l-0.533-256 256-256v511.733zM853.333 341.333h-682.667v-170.4h682.667z"
],
"attrs": [],
"grid": 0,
"tags": [
"icon12-filter-outline"
]
},
{
"id": 6,
"paths": [
@@ -60,26 +98,11 @@
"M597.333 768h-170.667v256h170.667v-256z",
"M256 426.667h-256v170.667h256v-170.667z"
],
"attrs": [
{},
{},
{},
{}
],
"isMulticolor": false,
"isMulticolor2": false,
"attrs": [],
"grid": 0,
"tags": [
"icon12-crosshair"
],
"colorPermutations": {
"1161751": [
{},
{},
{},
{}
]
}
]
},
{
"id": 8,
@@ -95,39 +118,12 @@
"M744.773 511.867c0 51.458-41.715 93.173-93.173 93.173s-93.173-41.715-93.173-93.173c0-51.458 41.715-93.173 93.173-93.173s93.173 41.715 93.173 93.173z",
"M744.773 791.36c0 51.458-41.715 93.173-93.173 93.173s-93.173-41.715-93.173-93.173c0-51.458 41.715-93.173 93.173-93.173s93.173 41.715 93.173 93.173z"
],
"attrs": [
{},
{},
{},
{},
{},
{},
{},
{},
{},
{}
],
"attrs": [],
"width": 745,
"isMulticolor": false,
"isMulticolor2": false,
"grid": 0,
"tags": [
"icon12-grippy"
],
"colorPermutations": {
"1161751": [
{},
{},
{},
{},
{},
{},
{},
{},
{},
{}
]
}
]
},
{
"id": 7,
@@ -136,24 +132,11 @@
"M0 426.667h1024v170.667h-1024v-170.667z",
"M0 853.333h1024v170.667h-1024v-170.667z"
],
"attrs": [
{},
{},
{}
],
"isMulticolor": false,
"isMulticolor2": false,
"attrs": [],
"grid": 0,
"tags": [
"icon12-list-view"
],
"colorPermutations": {
"1161751": [
{},
{},
{}
]
}
]
},
{
"id": 3,
@@ -162,40 +145,14 @@
"M85.333 426.667h853.333c47.128 0 85.333 38.205 85.333 85.333v426.667c0 47.128-38.205 85.333-85.333 85.333h-853.333c-47.128 0-85.333-38.205-85.333-85.333v-426.667c0-47.128 38.205-85.333 85.333-85.333z"
],
"attrs": [],
"isMulticolor": false,
"grid": 0,
"tags": [
"icon12-folder"
],
"colorPermutations": {
"1161751": [
{
"f": 0
},
{
"f": 0
}
]
}
]
}
],
"invisible": false,
"colorThemes": [
[
[
0,
0,
0,
1
],
[
0,
161,
75,
1
]
]
],
"colorThemes": [],
"colorThemeIdx": 0
}
],
@@ -206,9 +163,9 @@
"showQuickUse2": true,
"showSVGs": true,
"fontPref": {
"prefix": "icon-",
"prefix": "openmct-symbols-",
"metadata": {
"fontFamily": "openmct-symbols-12px",
"fontFamily": "Open-MCT-Symbols-12px",
"majorVersion": 1,
"minorVersion": 0
},
@@ -217,7 +174,12 @@
"baseline": 6.25,
"whitespace": 50
},
"embed": false
"embed": false,
"noie8": true,
"ie7": false,
"showMetadata": false,
"includeMetadata": false,
"showMetrics": true
},
"imagePref": {
"prefix": "icon-",

View File

@@ -1,8 +1,8 @@
{
"metadata": {
"name": "Open MCT Symbols",
"name": "Open MCT Symbols 16px",
"lastOpened": 0,
"created": 1541830438012
"created": 1561482854927
},
"iconSets": [
{
@@ -317,13 +317,29 @@
"code": 59685,
"tempChar": ""
},
{
"order": 161,
"id": 142,
"name": "icon-filter",
"prevSize": 32,
"code": 59686,
"tempChar": ""
},
{
"order": 162,
"id": 141,
"name": "icon-filter-outline",
"prevSize": 32,
"code": 59687,
"tempChar": ""
},
{
"order": 27,
"id": 105,
"name": "icon-arrows-right-left",
"prevSize": 32,
"code": 59904,
"tempChar": ""
"tempChar": ""
},
{
"order": 26,
@@ -331,7 +347,7 @@
"name": "icon-arrows-up-down",
"prevSize": 32,
"code": 59905,
"tempChar": ""
"tempChar": ""
},
{
"order": 68,
@@ -339,7 +355,7 @@
"name": "icon-bullet",
"prevSize": 32,
"code": 59906,
"tempChar": ""
"tempChar": ""
},
{
"order": 150,
@@ -347,7 +363,7 @@
"prevSize": 32,
"code": 59907,
"name": "icon-calendar",
"tempChar": ""
"tempChar": ""
},
{
"order": 45,
@@ -355,7 +371,7 @@
"name": "icon-chain-links",
"prevSize": 32,
"code": 59908,
"tempChar": ""
"tempChar": ""
},
{
"order": 73,
@@ -363,7 +379,7 @@
"name": "icon-download",
"prevSize": 32,
"code": 59909,
"tempChar": ""
"tempChar": ""
},
{
"order": 39,
@@ -371,7 +387,7 @@
"name": "icon-duplicate",
"prevSize": 32,
"code": 59910,
"tempChar": ""
"tempChar": ""
},
{
"order": 50,
@@ -379,7 +395,7 @@
"name": "icon-folder-new",
"prevSize": 32,
"code": 59911,
"tempChar": ""
"tempChar": ""
},
{
"order": 138,
@@ -387,7 +403,7 @@
"name": "icon-fullscreen-collapse",
"prevSize": 32,
"code": 59912,
"tempChar": ""
"tempChar": ""
},
{
"order": 139,
@@ -395,7 +411,7 @@
"name": "icon-fullscreen-expand",
"prevSize": 32,
"code": 59913,
"tempChar": ""
"tempChar": ""
},
{
"order": 122,
@@ -403,7 +419,7 @@
"name": "icon-layers",
"prevSize": 32,
"code": 59914,
"tempChar": ""
"tempChar": ""
},
{
"order": 151,
@@ -411,7 +427,7 @@
"name": "icon-line-horz",
"prevSize": 32,
"code": 59915,
"tempChar": ""
"tempChar": ""
},
{
"order": 100,
@@ -419,7 +435,7 @@
"name": "icon-magnify",
"prevSize": 32,
"code": 59916,
"tempChar": ""
"tempChar": ""
},
{
"order": 99,
@@ -427,7 +443,7 @@
"name": "icon-magnify-in",
"prevSize": 32,
"code": 59917,
"tempChar": ""
"tempChar": ""
},
{
"order": 101,
@@ -435,7 +451,7 @@
"name": "icon-magnify-out-v2",
"prevSize": 32,
"code": 59918,
"tempChar": ""
"tempChar": ""
},
{
"order": 103,
@@ -443,7 +459,7 @@
"name": "icon-menu",
"prevSize": 32,
"code": 59919,
"tempChar": ""
"tempChar": ""
},
{
"order": 124,
@@ -451,7 +467,7 @@
"name": "icon-move",
"prevSize": 32,
"code": 59920,
"tempChar": ""
"tempChar": ""
},
{
"order": 7,
@@ -459,7 +475,7 @@
"name": "icon-new-window",
"prevSize": 32,
"code": 59921,
"tempChar": ""
"tempChar": ""
},
{
"order": 63,
@@ -467,7 +483,7 @@
"name": "icon-paint-bucket-v2",
"prevSize": 32,
"code": 59922,
"tempChar": ""
"tempChar": ""
},
{
"order": 15,
@@ -475,7 +491,7 @@
"name": "icon-pencil",
"prevSize": 32,
"code": 59923,
"tempChar": ""
"tempChar": ""
},
{
"order": 54,
@@ -483,7 +499,7 @@
"name": "icon-pencil-edit-in-place",
"prevSize": 32,
"code": 59924,
"tempChar": ""
"tempChar": ""
},
{
"order": 40,
@@ -491,7 +507,7 @@
"name": "icon-play",
"prevSize": 32,
"code": 59925,
"tempChar": ""
"tempChar": ""
},
{
"order": 125,
@@ -499,7 +515,7 @@
"name": "icon-pause",
"prevSize": 32,
"code": 59926,
"tempChar": ""
"tempChar": ""
},
{
"order": 119,
@@ -507,7 +523,7 @@
"name": "icon-plot-resource",
"prevSize": 32,
"code": 59927,
"tempChar": ""
"tempChar": ""
},
{
"order": 48,
@@ -515,7 +531,7 @@
"name": "icon-pointer-left",
"prevSize": 32,
"code": 59928,
"tempChar": ""
"tempChar": ""
},
{
"order": 47,
@@ -523,7 +539,7 @@
"name": "icon-pointer-right",
"prevSize": 32,
"code": 59929,
"tempChar": ""
"tempChar": ""
},
{
"order": 85,
@@ -531,7 +547,7 @@
"name": "icon-refresh",
"prevSize": 32,
"code": 59930,
"tempChar": ""
"tempChar": ""
},
{
"order": 55,
@@ -539,7 +555,7 @@
"name": "icon-save",
"prevSize": 32,
"code": 59931,
"tempChar": ""
"tempChar": ""
},
{
"order": 56,
@@ -547,7 +563,7 @@
"name": "icon-save-as",
"prevSize": 32,
"code": 59932,
"tempChar": ""
"tempChar": ""
},
{
"order": 58,
@@ -555,7 +571,7 @@
"name": "icon-sine",
"prevSize": 32,
"code": 59933,
"tempChar": ""
"tempChar": ""
},
{
"order": 113,
@@ -563,7 +579,7 @@
"name": "icon-font",
"prevSize": 32,
"code": 59934,
"tempChar": ""
"tempChar": ""
},
{
"order": 41,
@@ -571,7 +587,7 @@
"name": "icon-thumbs-strip",
"prevSize": 32,
"code": 59935,
"tempChar": ""
"tempChar": ""
},
{
"order": 146,
@@ -579,7 +595,7 @@
"name": "icon-two-parts-both",
"prevSize": 32,
"code": 59936,
"tempChar": ""
"tempChar": ""
},
{
"order": 145,
@@ -587,7 +603,7 @@
"name": "icon-two-parts-one-only",
"prevSize": 32,
"code": 59937,
"tempChar": ""
"tempChar": ""
},
{
"order": 82,
@@ -595,7 +611,7 @@
"name": "icon-resync",
"prevSize": 32,
"code": 59938,
"tempChar": ""
"tempChar": ""
},
{
"order": 86,
@@ -603,7 +619,7 @@
"name": "icon-reset",
"prevSize": 32,
"code": 59939,
"tempChar": ""
"tempChar": ""
},
{
"order": 61,
@@ -611,7 +627,7 @@
"name": "icon-x-in-circle",
"prevSize": 32,
"code": 59940,
"tempChar": ""
"tempChar": ""
},
{
"order": 84,
@@ -619,7 +635,7 @@
"name": "icon-brightness",
"prevSize": 32,
"code": 59941,
"tempChar": ""
"tempChar": ""
},
{
"order": 83,
@@ -627,7 +643,7 @@
"name": "icon-contrast",
"prevSize": 32,
"code": 59942,
"tempChar": ""
"tempChar": ""
},
{
"order": 87,
@@ -635,7 +651,7 @@
"name": "icon-expand",
"prevSize": 32,
"code": 59943,
"tempChar": ""
"tempChar": ""
},
{
"order": 89,
@@ -643,7 +659,7 @@
"name": "icon-list-view",
"prevSize": 32,
"code": 59944,
"tempChar": ""
"tempChar": ""
},
{
"order": 133,
@@ -651,7 +667,7 @@
"name": "icon-grid-snap-to",
"prevSize": 32,
"code": 59945,
"tempChar": ""
"tempChar": ""
},
{
"order": 132,
@@ -659,7 +675,7 @@
"name": "icon-grid-snap-no",
"prevSize": 32,
"code": 59946,
"tempChar": ""
"tempChar": ""
},
{
"order": 94,
@@ -667,7 +683,7 @@
"name": "icon-frame-show",
"prevSize": 32,
"code": 59947,
"tempChar": ""
"tempChar": ""
},
{
"order": 95,
@@ -675,7 +691,7 @@
"name": "icon-frame-hide",
"prevSize": 32,
"code": 59948,
"tempChar": ""
"tempChar": ""
},
{
"order": 97,
@@ -683,7 +699,7 @@
"name": "icon-import",
"prevSize": 32,
"code": 59949,
"tempChar": ""
"tempChar": ""
},
{
"order": 96,
@@ -691,7 +707,7 @@
"name": "icon-export",
"prevSize": 32,
"code": 59950,
"tempChar": ""
"tempChar": ""
},
{
"order": 114,
@@ -699,7 +715,7 @@
"name": "icon-font-size",
"prevSize": 32,
"code": 59951,
"tempChar": ""
"tempChar": ""
},
{
"order": 144,
@@ -707,7 +723,7 @@
"name": "icon-activity",
"prevSize": 32,
"code": 60160,
"tempChar": ""
"tempChar": ""
},
{
"order": 104,
@@ -715,7 +731,7 @@
"name": "icon-activity-mode",
"prevSize": 32,
"code": 60161,
"tempChar": ""
"tempChar": ""
},
{
"order": 137,
@@ -723,7 +739,7 @@
"name": "icon-autoflow-tabular",
"prevSize": 32,
"code": 60162,
"tempChar": ""
"tempChar": ""
},
{
"order": 115,
@@ -731,7 +747,7 @@
"name": "icon-clock",
"prevSize": 32,
"code": 60163,
"tempChar": ""
"tempChar": ""
},
{
"order": 2,
@@ -739,7 +755,7 @@
"name": "icon-database",
"prevSize": 32,
"code": 60164,
"tempChar": ""
"tempChar": ""
},
{
"order": 3,
@@ -747,7 +763,7 @@
"name": "icon-database-query",
"prevSize": 32,
"code": 60165,
"tempChar": ""
"tempChar": ""
},
{
"order": 67,
@@ -755,7 +771,7 @@
"name": "icon-dataset",
"prevSize": 32,
"code": 60166,
"tempChar": ""
"tempChar": ""
},
{
"order": 59,
@@ -763,7 +779,7 @@
"name": "icon-datatable",
"prevSize": 32,
"code": 60167,
"tempChar": ""
"tempChar": ""
},
{
"order": 136,
@@ -771,7 +787,7 @@
"name": "icon-dictionary",
"prevSize": 32,
"code": 60168,
"tempChar": ""
"tempChar": ""
},
{
"order": 51,
@@ -779,7 +795,7 @@
"name": "icon-folder",
"prevSize": 32,
"code": 60169,
"tempChar": ""
"tempChar": ""
},
{
"order": 147,
@@ -787,7 +803,7 @@
"name": "icon-image",
"prevSize": 32,
"code": 60170,
"tempChar": ""
"tempChar": ""
},
{
"order": 4,
@@ -795,7 +811,7 @@
"name": "icon-layout",
"prevSize": 32,
"code": 60171,
"tempChar": ""
"tempChar": ""
},
{
"order": 24,
@@ -803,7 +819,7 @@
"name": "icon-object",
"prevSize": 32,
"code": 60172,
"tempChar": ""
"tempChar": ""
},
{
"order": 52,
@@ -811,7 +827,7 @@
"name": "icon-object-unknown",
"prevSize": 32,
"code": 60173,
"tempChar": ""
"tempChar": ""
},
{
"order": 105,
@@ -819,7 +835,7 @@
"name": "icon-packet",
"prevSize": 32,
"code": 60174,
"tempChar": ""
"tempChar": ""
},
{
"order": 126,
@@ -827,7 +843,7 @@
"name": "icon-page",
"prevSize": 32,
"code": 60175,
"tempChar": ""
"tempChar": ""
},
{
"order": 130,
@@ -835,7 +851,7 @@
"name": "icon-plot-overlay",
"prevSize": 32,
"code": 60176,
"tempChar": ""
"tempChar": ""
},
{
"order": 80,
@@ -843,7 +859,7 @@
"name": "icon-plot-stacked",
"prevSize": 32,
"code": 60177,
"tempChar": ""
"tempChar": ""
},
{
"order": 134,
@@ -851,7 +867,7 @@
"name": "icon-session",
"prevSize": 32,
"code": 60178,
"tempChar": ""
"tempChar": ""
},
{
"order": 109,
@@ -859,7 +875,7 @@
"name": "icon-tabular",
"prevSize": 32,
"code": 60179,
"tempChar": ""
"tempChar": ""
},
{
"order": 107,
@@ -867,7 +883,7 @@
"name": "icon-tabular-lad",
"prevSize": 32,
"code": 60180,
"tempChar": ""
"tempChar": ""
},
{
"order": 106,
@@ -875,7 +891,7 @@
"name": "icon-tabular-lad-set",
"prevSize": 32,
"code": 60181,
"tempChar": ""
"tempChar": ""
},
{
"order": 70,
@@ -883,7 +899,7 @@
"name": "icon-tabular-realtime",
"prevSize": 32,
"code": 60182,
"tempChar": ""
"tempChar": ""
},
{
"order": 60,
@@ -891,7 +907,7 @@
"name": "icon-tabular-scrolling",
"prevSize": 32,
"code": 60183,
"tempChar": ""
"tempChar": ""
},
{
"order": 131,
@@ -899,7 +915,7 @@
"name": "icon-telemetry",
"prevSize": 32,
"code": 60184,
"tempChar": ""
"tempChar": ""
},
{
"order": 108,
@@ -907,7 +923,7 @@
"name": "icon-timeline",
"prevSize": 32,
"code": 60185,
"tempChar": ""
"tempChar": ""
},
{
"order": 81,
@@ -915,7 +931,7 @@
"name": "icon-timer",
"prevSize": 32,
"code": 60186,
"tempChar": ""
"tempChar": ""
},
{
"order": 69,
@@ -923,7 +939,7 @@
"name": "icon-topic",
"prevSize": 32,
"code": 60187,
"tempChar": ""
"tempChar": ""
},
{
"order": 79,
@@ -931,7 +947,7 @@
"name": "icon-box-with-dashed-lines-v2",
"prevSize": 32,
"code": 60188,
"tempChar": ""
"tempChar": ""
},
{
"order": 90,
@@ -939,7 +955,7 @@
"name": "icon-summary-widget",
"prevSize": 32,
"code": 60189,
"tempChar": ""
"tempChar": ""
},
{
"order": 92,
@@ -947,7 +963,7 @@
"name": "icon-notebook",
"prevSize": 32,
"code": 60190,
"tempChar": ""
"tempChar": ""
},
{
"order": 118,
@@ -955,7 +971,7 @@
"name": "icon-tabs-view",
"prevSize": 32,
"code": 60191,
"tempChar": ""
"tempChar": ""
},
{
"order": 117,
@@ -963,7 +979,7 @@
"name": "icon-flexible-layout",
"prevSize": 32,
"code": 60192,
"tempChar": ""
"tempChar": ""
},
{
"order": 152,
@@ -971,7 +987,7 @@
"name": "icon-generator-sine",
"prevSize": 32,
"code": 60193,
"tempChar": ""
"tempChar": ""
},
{
"order": 153,
@@ -979,7 +995,7 @@
"name": "icon-generator-event",
"prevSize": 32,
"code": 60194,
"tempChar": ""
"tempChar": ""
},
{
"order": 160,
@@ -987,7 +1003,7 @@
"name": "icon-gauge",
"prevSize": 32,
"code": 60195,
"tempChar": ""
"tempChar": ""
}
],
"id": 0,
@@ -1602,6 +1618,46 @@
]
}
},
{
"id": 142,
"paths": [
"M896 0h-768c-70.601 0.227-127.773 57.399-128 127.978l-0 0.022v768c0.227 70.601 57.399 127.773 127.978 128l0.022 0h256v-512l-192-192h640l-192 192v512h256c70.601-0.227 127.773-57.399 128-127.978l0-0.022v-768c-0.227-70.601-57.399-127.773-127.978-128l-0.022-0z"
],
"attrs": [
{}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 1,
"tags": [
"icon-filter"
],
"colorPermutations": {
"11841841841": [
{}
]
}
},
{
"id": 141,
"paths": [
"M896 0h-768c-70.601 0.227-127.773 57.399-128 127.978l-0 0.022v768c0.227 70.601 57.399 127.773 127.978 128l0.022 0h768c70.601-0.227 127.773-57.399 128-127.978l0-0.022v-768c-0.227-70.601-57.399-127.773-127.978-128l-0.022-0zM896 895.8h-256v-383.8l192-192h-640l192 192v384h-256v-767.8h768z"
],
"attrs": [
{}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 1,
"tags": [
"icon-filter-outline"
],
"colorPermutations": {
"11841841841": [
{}
]
}
},
{
"id": 105,
"paths": [

Binary file not shown.

Binary file not shown.

BIN
src/styles-new/fonts/Open-MCT-Symbols-16px.ttf Executable file → Normal file

Binary file not shown.

BIN
src/styles-new/fonts/Open-MCT-Symbols-16px.woff Executable file → Normal file

Binary file not shown.

View File

@@ -26,7 +26,7 @@
@import "constants";
@import "constants-mobile.scss";
//@import "constants-espresso"; // TEMP
@import "constants-snow"; // TEMP
//@import "constants-maelstrom";
//@import "constants-snow"; // TEMP
@import "constants-maelstrom";
@import "mixins";
@import "animations";

View File

@@ -0,0 +1,19 @@
/************* FRAMES */
.c-so-view {
&__header {
transform: translateY(3px);
}
&__header__name {
transform: translateY(-2px);
}
&:not(.c-so-view--no-frame) {
$bc: #666;
$bLR: 3px solid transparent;
$br: 20px;
background: none !important;
border: none !important;
padding: 0 !important;
}
}

View File

@@ -44,7 +44,8 @@
class="c-so-view__object-view"
ref="objectView"
:object="domainObject"
:show-edit-view="showEditView">
:show-edit-view="showEditView"
:object-path="objectPath">
</object-view>
</div>
</template>
@@ -123,7 +124,12 @@
.c-click-icon,
.c-button {
// Shrink buttons a bit when they appear in a frame
font-size: 0.8em;
align-items: baseline;
font-size: 0.85em;
padding: 3px 5px;
&:before {
font-size: 0.8em;
}
}
}
</style>

View File

@@ -9,7 +9,8 @@ export default {
props: {
view: String,
object: Object,
showEditView: Boolean
showEditView: Boolean,
objectPath: Array
},
destroyed() {
this.clear();
@@ -61,6 +62,8 @@ export default {
if (this.composition) {
this.composition._destroy();
}
this.openmct.objectViews.off('clearData', this.clearData);
},
invokeEditModeHandler(editMode) {
this.currentView.onEditModeChange(editMode);
@@ -89,17 +92,19 @@ export default {
return;
}
let objectPath = this.currentObjectPath || this.objectPath;
if (provider.edit && this.showEditView) {
if (this.openmct.editor.isEditing()) {
this.currentView = provider.edit(this.currentObject);
this.currentView = provider.edit(this.currentObject, true, objectPath);
} else {
this.currentView = provider.view(this.currentObject, false);
this.currentView = provider.view(this.currentObject, false, objectPath);
}
this.openmct.editor.on('isEditing', this.toggleEditView);
this.releaseEditModeHandler = () => this.openmct.editor.off('isEditing', this.toggleEditView);
} else {
this.currentView = provider.view(this.currentObject, this.openmct.editor.isEditing());
this.currentView = provider.view(this.currentObject, this.openmct.editor.isEditing(), objectPath);
if (this.currentView.onEditModeChange) {
this.openmct.editor.on('isEditing', this.invokeEditModeHandler);
@@ -112,8 +117,10 @@ export default {
this.removeSelectable = openmct.selection.selectable(
this.$el, this.getSelectionContext(), true);
}
this.openmct.objectViews.on('clearData', this.clearData);
},
show(object, viewKey, immediatelySelect) {
show(object, viewKey, immediatelySelect, currentObjectPath) {
if (this.unlisten) {
this.unlisten();
}
@@ -128,6 +135,11 @@ export default {
}
this.currentObject = object;
if (currentObjectPath) {
this.currentObjectPath = currentObjectPath;
}
this.unlisten = this.openmct.objects.observe(this.currentObject, '*', (mutatedObject) => {
this.currentObject = mutatedObject;
});
@@ -187,6 +199,22 @@ export default {
getComposableDomainObject(event) {
let serializedDomainObject = event.dataTransfer.getData('openmct/composable-domain-object');
return JSON.parse(serializedDomainObject);
},
clearData(domainObject) {
if (domainObject) {
let clearKeyString = this.openmct.objects.makeKeyString(domainObject.identifier),
currentObjectKeyString = this.openmct.objects.makeKeyString(this.currentObject.identifier);
if (clearKeyString === currentObjectKeyString) {
if (this.currentView.onClearData) {
this.currentView.onClearData();
}
}
} else {
if (this.currentView.onClearData) {
this.currentView.onClearData();
}
}
}
}
}

View File

@@ -25,10 +25,6 @@ import _ from 'lodash';
},
methods: {
updateSelection(selection) {
if (_.isEqual(this.selection, selection)) {
return;
}
this.selection = selection;
if (this.selectedViews) {
@@ -38,10 +34,6 @@ import _ from 'lodash';
this.$el.innerHTML = '';
}
if (selection.length > 1) {
return;
}
this.selectedViews = this.openmct.inspectorViews.get(selection);
this.selectedViews.forEach(selectedView => {
let viewContainer = document.createElement('div');

View File

@@ -19,28 +19,11 @@
</div>
<div class="l-browse-bar__end">
<div class="l-browse-bar__view-switcher c-ctrl-wrapper c-ctrl-wrapper--menus-left"
v-if="views.length > 1">
<button class="c-button--menu"
:class="currentView.cssClass"
title="Switch view type"
@click.stop="toggleViewMenu">
<span class="c-button__label">
{{ currentView.name }}
</span>
</button>
<div class="c-menu" v-show="showViewMenu">
<ul>
<li v-for="(view, index) in views"
@click="setView(view)"
:key="index"
:class="view.cssClass"
:title="view.name">
{{ view.name }}
</li>
</ul>
</div>
</div>
<view-switcher
:currentView="currentView"
:views="views"
@setView="setView">
</view-switcher>
<!-- Action buttons -->
<div class="l-browse-bar__actions">
<button v-if="notebookEnabled"
@@ -77,14 +60,15 @@
<script>
import NotebookSnapshot from '../utils/notebook-snapshot';
import ViewSwitcher from './ViewSwitcher.vue';
const PLACEHOLDER_OBJECT = {};
export default {
inject: ['openmct'],
components: {
ViewSwitcher
},
methods: {
toggleViewMenu() {
this.showViewMenu = !this.showViewMenu;
},
toggleSaveMenu() {
this.showSaveMenu = !this.showSaveMenu;
},

View File

@@ -2,9 +2,15 @@
<div class="l-shell" :class="{
'is-editing': isEditing
}">
<div class="l-shell__head">
<div class="l-shell__head" :class="{
'l-shell__head--expanded': headExpanded,
'l-shell__head--minify-indicators': !headExpanded
}">
<CreateButton class="l-shell__create-button"></CreateButton>
<div class="l-shell__controls">
<indicators class="l-shell__head-section l-shell__indicators">
</indicators>
<notification-banner></notification-banner>
<div class="l-shell__head-section l-shell__controls">
<button class="c-icon-button c-icon-button--major icon-new-window" title="Open in a new browser tab"
@click="openInNewTab"
target="_blank">
@@ -15,6 +21,8 @@
</button>
</div>
<app-logo></app-logo>
<button class="l-shell__head__collapse-button c-button"
@click="toggleShellHead"></button>
</div>
<multipane class="l-shell__main"
type="horizontal">
@@ -44,9 +52,6 @@
<Inspector :isEditing="isEditing" ref="inspector"></Inspector>
</pane>
</multipane>
<div class="l-shell__status">
<StatusBar></StatusBar>
</div>
</div>
</template>
@@ -61,12 +66,6 @@
flex-flow: column nowrap;
overflow: hidden;
&__status {
background: $colorStatusBarBg;
color: $colorStatusBarFg;
padding: $interiorMarginSm;
}
&__pane-tree {
width: 40%;
@@ -160,14 +159,52 @@
}
&__head {
align-items: center;
align-items: stretch;
background: $colorHeadBg;
justify-content: space-between;
padding: $interiorMargin;
padding: $interiorMargin $interiorMargin + 2;
> [class*="__"] + [class*="__"] {
margin-left: $interiorMargin;
}
[class*='__head__collapse-button'] {
align-self: start;
$p: 6px;
padding-left: $p !important;
padding-right: $p !important;
&:before {
content: $glyph-icon-arrow-down;
font-size: 1.1em;
}
}
&-section {
// Subdivides elements across the head
display: flex;
flex: 0 1 auto;
padding: 0 $interiorMargin;
}
&--expanded {
.c-indicator__label {
transition: none !important;
}
[class*='__head__collapse-button'] {
&:before {
transform: rotate(180deg);
}
}
}
}
&__controls {
$brdr: 1px solid $colorInteriorBorder;
border-right: $brdr;
border-left: $brdr;
align-items: start;
}
&__create-button,
@@ -175,11 +212,17 @@
flex: 0 0 auto;
}
&__controls {
flex: 1 1 100%;
display: flex;
justify-content: flex-end;
margin-right: 2.5%;
&__create-button { margin-right: $interiorMarginLg; }
&__indicators {
//@include test();
flex: 1 1 auto;
flex-wrap: wrap;
[class*='indicator-clock'] { order: 90; }
.c-indicator .label {
font-size: 0.9em;
}
}
/******************************* MAIN AREA */
@@ -266,9 +309,10 @@
import multipane from './multipane.vue';
import pane from './pane.vue';
import BrowseBar from './BrowseBar.vue';
import StatusBar from './status-bar/StatusBar.vue';
import Toolbar from '../toolbar/Toolbar.vue';
import AppLogo from './AppLogo.vue';
import Indicators from './status-bar/Indicators.vue';
import NotificationBanner from './status-bar/NotificationBanner.vue';
var enterFullScreen = () => {
var docElm = document.documentElement;
@@ -309,9 +353,10 @@
multipane,
pane,
BrowseBar,
StatusBar,
Toolbar,
AppLogo
AppLogo,
Indicators,
NotificationBanner
},
mounted() {
this.openmct.editor.on('isEditing', (isEditing)=>{
@@ -321,11 +366,18 @@
this.openmct.selection.on('change', this.toggleHasToolbar);
},
data: function () {
let storedHeadProps = window.localStorage.getItem('openmct-shell-head');
let headExpanded = true;
if (storedHeadProps) {
headExpanded = JSON.parse(storedHeadProps).expanded;
}
return {
fullScreen: false,
conductorComponent: undefined,
isEditing: false,
hasToolbar: false
hasToolbar: false,
headExpanded
}
},
computed: {
@@ -334,6 +386,18 @@
}
},
methods: {
toggleShellHead() {
this.headExpanded = !this.headExpanded;
window.localStorage.setItem(
'openmct-shell-head',
JSON.stringify(
{
expanded: this.headExpanded
}
)
);
},
fullScreenToggle() {
if (this.fullScreen) {
this.fullScreen = false;

View File

@@ -0,0 +1,55 @@
<template>
<div class="l-browse-bar__view-switcher c-ctrl-wrapper c-ctrl-wrapper--menus-left"
v-if="views.length > 1">
<button class="c-button--menu"
:class="currentView.cssClass"
title="Switch view type"
@click.stop="toggleViewMenu">
<span class="c-button__label">
{{ currentView.name }}
</span>
</button>
<div class="c-menu" v-show="showViewMenu">
<ul>
<li v-for="(view, index) in views"
@click="setView(view)"
:key="index"
:class="view.cssClass"
:title="view.name">
{{ view.name }}
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: [
'currentView',
'views'
],
data() {
return {
showViewMenu: false
}
},
methods: {
setView(view) {
this.$emit('setView', view);
},
toggleViewMenu() {
this.showViewMenu = !this.showViewMenu;
},
hideViewMenu() {
this.showViewMenu = false;
}
},
mounted() {
document.addEventListener('click', this.hideViewMenu);
},
destroyed() {
document.removeEventListener('click', this.hideViewMenu);
}
}
</script>

View File

@@ -148,21 +148,6 @@
font-size: floor(12px * .9);
}
&__collapse-button {
box-shadow: none;
background: $splitterBtnColorBg;
color: $splitterBtnColorFg;
border-radius: $smallCr;
font-size: 6px;
line-height: 90%;
padding: 3px 15px;
@include hover() {
background: $colorBtnBgHov;
color: $colorBtnFgHov;
}
}
&__label {
// Name of the pane
@include ellipsize();

View File

@@ -17,10 +17,137 @@
at runtime from the About dialog for additional information.
-->
<template>
<span id='status' class='status-holder'></span>
</template>
<style lang="scss">
@import "~styles/sass-base";
.c-indicator {
@include cControl();
@include cClickIconButtonLayout();
button { text-transform: uppercase; }
background: none !important;
border-radius: $controlCr;
overflow: visible;
position: relative;
text-transform: uppercase;
&.no-minify {
// For items that cannot be minified
display: flex;
flex-flow: row nowrap;
align-items: center;
> *,
&:before {
flex: 1 1 auto;
}
&:before {
margin-right: $interiorMarginSm;
}
}
&:not(.no-minify) {
&:before {
margin-right: 0 !important;
}
}
}
.c-indicator__label {
// Label element. Appears as a hover bubble element when Indicators are minified;
// Appears as an inline element when not.
display: inline-block;
transition:none;
white-space: nowrap;
a,
button,
s-button,
.c-button {
// Make <a> in label look like buttons
transition: $transIn;
background: transparent;
border: 1px solid rgba($colorIndicatorMenuFg, 0.5);
border-radius: $controlCr;
box-sizing: border-box;
color: inherit;
font-size: inherit;
height: auto;
line-height: normal;
padding: 0 2px;
&:hover {
background: rgba($colorIndicatorMenuFg, 0.1);
border-color: rgba($colorIndicatorMenuFg, 0.75);
color: $colorIndicatorMenuFgHov;
}
}
[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;
}
}
}
.c-indicator__count {
display: none; // Only displays when Indicator is minified, see below
}
[class*='minify-indicators'] {
// All styles for minified Indicators should go in here
.c-indicator:not(.no-minify) {
@include hover() {
background: $colorIndicatorBgHov;
.c-indicator__label {
box-shadow: $colorIndicatorMenuBgShdw;
transform: scale(1.0);
transition: transform 100ms ease-out 100ms;
}
}
.c-indicator__label {
transition: transform 250ms ease-in 200ms;
background: $colorIndicatorMenuBg;
color: $colorIndicatorMenuFg;
border-radius: $controlCr;
left: 0;
top: 130%;
padding: $interiorMargin $interiorMargin;
position: absolute;
transform-origin: 10px 0;
transform: scale(0.0);
overflow: visible;
z-index: 50;
&:before {
// Infobubble-style arrow element
content: '';
display: block;
position: absolute;
bottom: 100%;
@include triangle('up', $size: 4px, $ratio: 1, $color: $colorIndicatorMenuBg);
}
}
.c-indicator__count {
display: inline-block;
margin-left: $interiorMarginSm;
}
}
}
/* Mobile */
// Hide the clock indicator when we're phone portrait
body.phone.portrait {
.c-indicator.t-indicator-clock {
display: none;
}
}
</style>
<script>
@@ -29,12 +156,7 @@
mounted() {
this.openmct.indicators.indicatorObjects.forEach((indicator) => {
// So that we can consistently position indicator elements,
// guarantee that they are wrapped in an element we control
var wrapperNode = document.createElement('span');
wrapperNode.className = 'l-indicator';
wrapperNode.appendChild(indicator.element);
this.$el.appendChild(wrapperNode);
this.$el.appendChild(indicator.element);
});
}
}

View File

@@ -57,20 +57,19 @@
.c-message-banner {
$closeBtnSize: 7px;
$m: 1px;
border-radius: $controlCr;
@include statusBannerColors($colorStatusDefault, $colorStatusFg);
cursor: pointer;
display: flex;
align-items: center;
left: 50%;
top: 50%;
max-width: 50%;
padding: $interiorMargin $interiorMargin $interiorMargin $interiorMarginLg;
max-height: 25px;
padding: $interiorMarginSm $interiorMargin $interiorMarginSm $interiorMarginLg;
position: absolute;
transform: translateX(-50%);
bottom: $m;
transform: translate(-50%, -50%);
z-index: 2;
> * + * {

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