Compare commits

..

12 Commits

Author SHA1 Message Date
charlesh88
371d132bfc Missing/unknown item should appear visually distinct
- Remove unneeded in-progress CSS;
2019-07-01 14:37:17 -07:00
charlesh88
91904ec22d Missing/unknown item should appear visually distinct
- Add missing/unknown styling to browse-bar;
2019-07-01 13:29:02 -07:00
charlesh88
afaee9a483 Missing/unknown item should appear visually distinct
- Apply missing/unknown styling to tabs view;
- Augment `isUnknown` mixin to also target same element with class
icon*;
2019-07-01 13:21:59 -07:00
charlesh88
709e1eb10e Missing/unknown item should appear visually distinct
- 'no-frame' CSS class application only allowed if domainObject.type is
not unknown;
- Show telemetry-view label element if domainObject.type is unknown;
2019-07-01 12:42:43 -07:00
charlesh88
6740677652 Missing/unknown item should appear visually distinct
- Styling applied to telemetry views for type unknown;
2019-06-28 09:42:51 -07:00
charlesh88
ee7521915f Missing/unknown item should appear visually distinct
- New "isUnknown" sass mixin to consolidate styling;
- Refined styling for grid, list-item and object label views;
- Flex and Display Layout frame headers now style properly for
missing/unknown items;
- TODO: visual indication when header is hidden (alphanumerics, summary
widgets, frame hidden manually, etc.)
2019-06-26 16:41:55 -07:00
charlesh88
bc590081b3 Missing/unknown item should appear visually distinct
- Styling for grid and list-item views;
- Refactor of item hover approach to use filters rather than discrete
colors;
2019-06-26 09:52:13 -07:00
charlesh88
854ffb9153 Missing/unknown item should appear visually distinct
- Theme color added;
- Styling for tree items;
- Removed unused tree item hover styling;
2019-06-26 06:12:07 -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
59 changed files with 636 additions and 552 deletions

View File

@@ -1,6 +1,6 @@
<span class="h-indicator" ng-controller="DialogLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div class="c-indicator c-indicator--clickable icon-box-with-arrow s-status-available"><span class="label">
<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>

View File

@@ -1,6 +1,6 @@
<span class="h-indicator" ng-controller="NotificationLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div class="c-indicator c-indicator--clickable icon-bell s-status-available"><span class="label">
<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>

View File

@@ -87,7 +87,6 @@
openmct.install(openmct.plugins.Filters(['table', 'telemetry.plot.overlay']));
openmct.install(openmct.plugins.ObjectMigration());
openmct.install(openmct.plugins.GoToOriginalAction());
openmct.install(openmct.plugins.GlobalClearIndicator());
openmct.start();
</script>
</html>

View File

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

View File

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

View File

@@ -49,7 +49,7 @@ define(
};
ClockIndicator.prototype.getCssClass = function () {
return "t-indicator-clock icon-clock no-collapse c-indicator--not-clickable";
return "t-indicator-clock icon-clock no-collapse float-right";
};
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 "c-indicator--clickable icon-database " + this.state.statusClass;
return "icon-database " + this.state.statusClass;
};
CouchIndicator.prototype.getGlyphClass = function () {

View File

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

View File

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

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

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

View File

@@ -0,0 +1,77 @@
/*****************************************************************************
* 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 (selection) {
let component;
return {
show: function (element) {
component = new Vue({
provide: {
openmct
},
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"
@@ -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

@@ -22,7 +22,7 @@
<template>
<layout-frame :item="item"
:grid-size="gridSize"
:title="domainObject && domainObject.name"
:title="domainObject && domainObject.name + ': ' + domainObject.type"
@move="(gridDelta) => $emit('move', gridDelta)"
@endMove="() => $emit('endMove')">
<object-frame v-if="domainObject"

View File

@@ -23,12 +23,14 @@
<template>
<layout-frame :item="item"
:grid-size="gridSize"
:title="domainObject && domainObject.name + ': ' + domainObject.type"
:class="{'c-telemetry-view--unknown': domainObject.type.indexOf('unknown') !== -1}"
@move="(gridDelta) => $emit('move', gridDelta)"
@endMove="() => $emit('endMove')">
<div class="c-telemetry-view"
:style="styleObject"
v-if="domainObject">
<div v-if="showLabel"
<div v-if="showLabel || domainObject.type.indexOf('unknown') !== -1"
class="c-telemetry-view__label">
<div class="c-telemetry-view__label-text">{{ domainObject.name }}</div>
</div>
@@ -50,6 +52,21 @@
display: flex;
align-items: stretch;
&--unknown {
.c-telemetry-view__label-text {
@include isUnknown();
display: flex;
align-items: center;
&:before {
content: $glyph-icon-object-unknown;
font-family: symbolsfont;
font-style: normal;
display: inline-block;
margin-right: $interiorMarginSm;
}
}
}
> * {
// Label and value holders
flex: 1 1 auto;
@@ -79,6 +96,7 @@
<script>
import LayoutFrame from './LayoutFrame.vue'
import printj from 'printj'
const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5],
DEFAULT_POSITION = [1, 1];
@@ -143,6 +161,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() {
@@ -168,6 +190,9 @@
}
this.context.index = newIndex;
},
item(newItem) {
this.context.layoutItem = newItem;
}
},
methods: {
@@ -219,10 +244,14 @@
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);
}
},
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({
@@ -76,7 +78,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

@@ -1,6 +1,6 @@
<template>
<a class="l-grid-view__item c-grid-item"
:class="{ 'is-alias': item.isAlias === true }"
:class="{ 'is-alias': item.isAlias === true, 'c-grid-item--unknown': item.type.cssClass === undefined || item.type.cssClass.indexOf('unknown') !== -1 }"
:href="objectLink">
<div class="c-grid-item__type-icon"
:class="(item.type.cssClass != undefined) ? 'bg-' + item.type.cssClass : 'bg-icon-object-unknown'">
@@ -34,10 +34,13 @@
padding: $interiorMarginLg;
&__type-icon {
filter: $colorKeyFilter;
flex: 0 0 $gridItemMobile;
font-size: floor($gridItemMobile / 2);
margin-right: $interiorMarginLg;
&:before {
filter: $colorKeyFilter;
height: 100%;
}
}
&.is-alias {
@@ -48,6 +51,22 @@
}
}
&--unknown {
@include isUnknown();
/*[class*='__'] {
opacity: 0.7;
}
[class*='__name'],
[class*='__metadata'] {
font-style: italic;
}*/
[class*='__type-icon__glyph'] {
filter: $filterItemUnknown;
}
}
&__details {
display: flex;
flex-flow: column nowrap;
@@ -93,11 +112,10 @@
transition: background $transOutMs ease-in-out;
&:hover {
background: $colorItemBgHov;
transition: $transIn;
filter: $filterItemHoverFg;
//transition: $transIn;
.c-grid-item__type-icon {
filter: $colorKeyFilterHov;
transform: scale(1);
transition: $transInBounce;
}

View File

@@ -1,5 +1,5 @@
<template>
<div class="l-grid-view">
<div class="l-grid-view foo">
<grid-item v-for="(item, index) in items"
:key="index"
:item="item"
@@ -31,129 +31,6 @@
}
}
}
/******************************* GRID ITEMS */
.c-grid-item {
// Mobile-first
@include button($bg: $colorItemBg, $fg: $colorItemFg);
cursor: pointer;
display: flex;
padding: $interiorMarginLg;
&__type-icon {
filter: $colorKeyFilter;
flex: 0 0 $gridItemMobile;
font-size: floor($gridItemMobile / 2);
margin-right: $interiorMarginLg;
}
&.is-alias {
// Object is an alias to an original.
[class*='__type-icon'] {
@include isAlias();
color: $colorIconAliasForKeyFilter;
}
}
&__details {
display: flex;
flex-flow: column nowrap;
flex: 1 1 auto;
}
&__name {
@include ellipsize();
color: $colorItemFg;
font-size: 1.2em;
font-weight: 400;
margin-bottom: $interiorMarginSm;
}
&__metadata {
color: $colorItemFgDetails;
font-size: 0.9em;
body.mobile & {
[class*='__item-count'] {
&:before {
content: ' - ';
}
}
}
}
&__controls {
color: $colorItemFgDetails;
flex: 0 0 64px;
font-size: 1.2em;
display: flex;
align-items: center;
justify-content: flex-end;
> * + * {
margin-left: $interiorMargin;
}
}
body.desktop & {
$transOutMs: 300ms;
flex-flow: column nowrap;
transition: background $transOutMs ease-in-out;
&:hover {
background: $colorItemBgHov;
transition: $transIn;
.c-grid-item__type-icon {
filter: $colorKeyFilterHov;
transform: scale(1);
transition: $transInBounce;
}
}
> * {
margin: 0; // Reset from mobile
}
&__controls {
align-items: start;
flex: 0 0 auto;
order: 1;
.c-info-button,
.c-pointer-icon { display: none; }
}
&__type-icon {
flex: 1 1 auto;
font-size: floor($gridItemDesk / 3);
margin: $interiorMargin 22.5% $interiorMargin * 3 22.5%;
order: 2;
transform: scale(0.9);
transform-origin: center;
transition: all $transOutMs ease-in-out;
}
&__details {
flex: 0 0 auto;
justify-content: flex-end;
order: 3;
}
&__metadata {
display: flex;
&__type {
flex: 1 1 auto;
@include ellipsize();
}
&__item-count {
opacity: 0.7;
flex: 0 0 auto;
}
}
}
}
</style>
<script>

View File

@@ -1,6 +1,6 @@
<template>
<tr class="c-list-item"
:class="{ 'is-alias': item.isAlias === true }"
:class="{ 'is-alias': item.isAlias === true, 'c-list-item--unknown': item.type.cssClass === undefined || item.type.cssClass.indexOf('unknown') !== -1 }"
@click="navigate">
<td class="c-list-item__name">
<a :href="objectLink" ref="objectLink">
@@ -20,6 +20,7 @@
/******************************* LIST ITEM */
.c-list-item {
&__name a {
color: $colorItemFg;
display: flex;
> * + * { margin-left: $interiorMarginSm; }
@@ -53,6 +54,11 @@
}
}
}
&--unknown {
@include isUnknown();
filter: $filterItemUnknown;
}
}
</style>

View File

@@ -62,15 +62,16 @@
tbody tr {
background: $colorListItemBg;
transition: $transOut;
}
body.desktop & {
tbody tr {
transition: $transOut;
cursor: pointer;
&:hover {
background: $colorListItemBgHov;
background: $colorItemTreeHoverBg;
filter: $filterItemHoverFg;
transition: $transIn;
}
}

View File

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

View File

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

@@ -80,10 +80,6 @@ define([
'configuration.filters',
this.updateFiltersAndResubscribe.bind(this)
);
this.refresh = this.refresh.bind(this);
this.openmct.notifications.on('clear', this.refresh);
}
eventHelpers.extend(PlotController.prototype);
@@ -170,8 +166,6 @@ define([
if (this.filterObserver) {
this.filterObserver();
}
this.openmct.notifications.off('clear', this.refresh);
};
PlotController.prototype.loadMoreData = function (range, purge) {
@@ -269,12 +263,6 @@ define([
});
};
PlotController.prototype.refresh = function (updatedFilters) {
this.config.series.forEach(function (series) {
series.refresh();
});
};
/**
* Export view as JPG.
*/

View File

@@ -43,8 +43,7 @@ define([
'./LADTable/plugin',
'./filters/plugin',
'./objectMigration/plugin',
'./goToOriginalAction/plugin',
'./globalClearIndicator/plugin'
'./goToOriginalAction/plugin'
], function (
_,
UTCTimeSystem,
@@ -68,8 +67,7 @@ define([
LADTable,
Filters,
ObjectMigration,
GoToOriginalAction,
GlobalClearIndicator
GoToOriginalAction
) {
var bundleMap = {
LocalStorage: 'platform/persistence/local',
@@ -168,7 +166,6 @@ define([
plugins.Filters = Filters;
plugins.ObjectMigration = ObjectMigration.default;
plugins.GoToOriginalAction = GoToOriginalAction.default;
plugins.GlobalClearIndicator = GlobalClearIndicator;
return plugins;
});

View File

@@ -16,7 +16,10 @@
v-for="(tab,index) in tabsList"
:key="index"
:class="[
{'is-current': isCurrent(tab)},
{
'is-current': isCurrent(tab),
'c-tab--unknown': tab.type.definition.cssClass.indexOf('unknown') !== -1
},
tab.type.definition.cssClass
]"
@click="showTab(tab)">
@@ -29,7 +32,12 @@
:class="{'c-tabs-view__object-holder--hidden': !isCurrent(tab)}">
<div v-if="currentTab"
class="c-tabs-view__object-name l-browse-bar__object-name--w"
:class="currentTab.type.definition.cssClass">
:class="[
{
'c-tabs-view__object--unknown': tab.type.definition.cssClass.indexOf('unknown') !== -1
},
currentTab.type.definition.cssClass
]">
<div class="l-browse-bar__object-name">
{{currentTab.domainObject.name}}
</div>
@@ -102,6 +110,13 @@
width: 100%;
}
}
.c-tab,
.c-tabs-view__object {
&--unknown {
@include isUnknown();
}
}
</style>
<script>

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 {
@@ -62,7 +64,6 @@ define([
openmct.time.on('bounds', this.refreshData);
openmct.time.on('timeSystem', this.refreshData);
openmct.notifications.on('clear', this.refreshData);
}
initialize() {
@@ -95,8 +96,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);
@@ -106,7 +105,7 @@ define([
}
addTelemetryObject(telemetryObject) {
this.configuration.addColumnsForObject(telemetryObject, true);
this.addColumnsForObject(telemetryObject, true);
this.requestDataFor(telemetryObject);
this.subscribeTo(telemetryObject);
this.telemetryObjects.push(telemetryObject);
@@ -133,6 +132,13 @@ define([
this.emit('object-removed', objectIdentifier);
}
/**
* @private
*/
createRow(datum, columnMap, keyString, limitEvaluator) {
return new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator);
}
requestDataFor(telemetryObject) {
this.incrementOutstandingRequests();
let requestOptions = this.buildOptionsFromConfiguration(telemetryObject);
@@ -146,7 +152,7 @@ define([
let columnMap = this.getColumnMapForObject(keyString);
let limitEvaluator = this.openmct.telemetry.limitEvaluator(telemetryObject);
let telemetryRows = telemetryData.map(datum => new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
let telemetryRows = telemetryData.map(datum => this.createRow(datum, columnMap, keyString, limitEvaluator));
this.boundedRows.add(telemetryRows);
}).finally(() => {
this.decrementOutstandingRequests();
@@ -192,6 +198,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);
@@ -203,7 +222,7 @@ define([
if (!this.telemetryObjects.includes(telemetryObject)) {
return;
}
this.boundedRows.add(new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
this.boundedRows.add(this.createRow(datum, columnMap, keyString, limitEvaluator));
}, subscribeOptions);
}
@@ -241,7 +260,6 @@ define([
Object.keys(this.subscriptions).forEach(this.unsubscribe, this);
this.openmct.time.off('bounds', this.refreshData);
this.openmct.time.off('timeSystem', this.refreshData);
this.openmct.notifications.off('clear', this.refreshData);
if (this.filterObserver) {
this.filterObserver();
}

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

@@ -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() {

View File

@@ -22,12 +22,10 @@
define([
'./components/table.vue',
'../../exporters/CSVExporter',
'./TelemetryTable',
'vue'
], function (
TableComponent,
CSVExporter,
TelemetryTable,
Vue
) {
@@ -51,7 +49,6 @@ define([
return domainObject.type === 'table';
},
view(domainObject) {
let csvExporter = new CSVExporter.default();
let table = new TelemetryTable(domainObject, openmct);
let component;
return {
@@ -67,7 +64,6 @@ define([
},
provide: {
openmct,
csvExporter,
table
},
el: element,

View File

@@ -1,5 +1,5 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2019, United States Government
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
@@ -19,30 +19,26 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
'./components/globalClearIndicator.vue',
'vue'
], function (
GlobaClearIndicator,
Vue
) {
return function plugin() {
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);
};
};
});
<template>
<td>{{formattedValue}}</td>
</template>
<script>
export default {
inject: ['openmct'],
props: {
row: {
type: Object,
required: true
},
columnKey: {
type: String,
require: true
}
},
computed: {
formattedValue() {
return this.row.getFormattedValue(this.columnKey);
}
}
};
</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,12 +20,18 @@
* 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="rowClass">
<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]"
class="is-selectable"
@click="selectCell($event.currentTarget, key)"
:row="row"></component>
</tr>
</template>
@@ -33,13 +39,19 @@
</style>
<script>
import TableCell from './table-cell.vue';
export default {
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
}, {})
}
},
props: {
@@ -77,8 +89,25 @@ export default {
},
formatRow: function (row) {
this.formattedRow = row.getFormattedDatum(this.headers);
this.rowLimitClass = row.getRowLimitClass();
this.rowClass = row.getRowClass();
this.cellLimitClasses = row.getCellLimitClasses();
},
selectCell(element, 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();
}
},
// TODO: use computed properties
@@ -88,6 +117,9 @@ export default {
handler: 'formatRow',
deep: false
}
},
components: {
TableCell
}
}
</script>

View File

@@ -22,7 +22,8 @@
<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 :style="{ 'max-width': widthWithScroll, 'min-width': '150px'}"><slot></slot></div>
<div v-if="allowExport" 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">
@@ -40,7 +41,7 @@
:key="key"
:headerKey="key"
:headerIndex="headerIndex"
@sort="sortBy(key)"
@sort="allowSorting && sortBy(key)"
@resizeColumn="resizeColumn"
@dropTargetOffsetChanged="setDropTargetOffset"
@dropTargetActive="dropTargetActive"
@@ -279,6 +280,7 @@
import TelemetryTableRow from './table-row.vue';
import search from '../../../ui/components/search.vue';
import TableColumnHeader from './table-column-header.vue';
import CSVExporter from '../../../exporters/CSVExporter.js';
import _ from 'lodash';
const VISIBLE_ROW_COUNT = 100;
@@ -295,11 +297,23 @@ export default {
TableColumnHeader,
search
},
inject: ['table', 'openmct', 'csvExporter'],
inject: ['table', 'openmct'],
props: {
isEditing: {
type: Boolean,
default: false
},
allowExport: {
type: Boolean,
default: true
},
allowFiltering: {
'type': Boolean,
'default': true
},
allowSorting: {
'type': Boolean,
'default': true
}
},
data() {
@@ -611,12 +625,17 @@ export default {
scrollTop = this.scrollable.scrollTop;
}, RESIZE_POLL_INTERVAL);
},
clearRowsAndRerender() {
this.visibleRows = [];
this.$nextTick().then(this.updateVisibleRows);
}
},
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 +643,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 +669,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

@@ -108,6 +108,10 @@
a {
color: $colorAboutLink;
&:hover {
color: $colorAHov;
}
}
em {

View File

@@ -101,6 +101,8 @@ $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;
@@ -140,6 +142,8 @@ $browseFrameColor: pullForward($colorBodyBg, 10%);
$browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing
$browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4);
$filterItemHoverFg: brightness(1.2);
$filterItemUnknown: contrast(0);
/************************************************** EDITING */
$editUIColor: $uiColor; // Base color

View File

@@ -105,6 +105,8 @@ $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;
@@ -144,6 +146,8 @@ $browseFrameColor: pullForward($colorBodyBg, 10%);
$browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing
$browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4);
$filterItemHoverFg: brightness(1.2);
$filterItemUnknown: contrast(0);
/************************************************** EDITING */
$editUIColor: $uiColor; // Base color

View File

@@ -101,6 +101,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;
@@ -140,6 +142,8 @@ $browseFrameColor: pullForward($colorBodyBg, 10%);
$browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing
$browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4);
$filterItemHoverFg: brightness(0.9);
$filterItemUnknown: contrast(0);
/************************************************** EDITING */
$editUIColor: $uiColor; // Base color

View File

@@ -49,21 +49,6 @@ 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;
@@ -75,17 +60,29 @@ 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 {
@include hasMenu();
&:after {
content: $glyph-icon-arrow-down;
font-family: symbolsfont;
font-size: 0.7em;
margin-left: floor($interiorMarginSm * 0.8);
opacity: 0.5;
}
}
}
@@ -135,7 +132,7 @@ button {
/******************************************************** DISCLOSURE CONTROLS */
/********* Disclosure Button */
// Provides a downward arrow icon that when clicked displays additional options and/or info.
// Provides a downward arrow icon that when clicked displays a context menu
// Always placed AFTER an element
.c-disclosure-button {
@include cClickIcon();

View File

@@ -79,9 +79,6 @@ a {
color: $colorA;
cursor: pointer;
text-decoration: none;
&:hover {
color: $colorAHov;
}
}
body, html {

View File

@@ -782,10 +782,6 @@ mct-indicators mct-include {
display: contents;
}
/*
// MOVED TO INDICATORS.VUE
.ls-indicator {
$bg: rgba(white, 0.2) !important;
$hbg: $colorStatusBarBg;
@@ -863,7 +859,7 @@ mct-indicators mct-include {
border-radius: $br;
font-size: .6rem;
left: 0;
top: 140%;
bottom: 140%;
opacity: 0;
padding: $interiorMarginSm $interiorMargin;
position: absolute;
@@ -877,8 +873,8 @@ mct-indicators mct-include {
content: '';
display: block;
position: absolute;
bottom: 100%;
@include triangle('up', $size: 4px, $ratio: 1, $color: $hbg);
top: 100%;
@include triangle('down', $size: 4px, $ratio: 1, $color: $hbg);
}
}
@@ -898,8 +894,7 @@ mct-indicators mct-include {
}
}
/* Mobile */
// Hide the clock indicator when we're phone portrait
body.phone.portrait {
.ls-indicator.t-indicator-clock {
@@ -907,8 +902,6 @@ body.phone.portrait {
}
}
*/
/************************************************* DATETIME UI */
@mixin complexFieldHolder($myW) {
width: $myW + $interiorMargin;

View File

@@ -36,10 +36,14 @@
}
@mixin glyphBg($glyphUrl) {
background-image: $glyphUrl;
background-position: center;
background-size: contain;
background-repeat: no-repeat;
&:before {
content: '';
display: block;
background-image: $glyphUrl;
background-position: center;
background-size: contain;
background-repeat: no-repeat;
}
}
[class*="icon-"] {
@@ -97,6 +101,24 @@
}
}
@mixin isUnknown() {
// Common styles to be applied to tree items, object labels, grid and list item views
font-style: italic;
opacity: 0.7;
&[class*='icon']:before,
&[class*='icon']:after,
[class*='icon']:before,
[class*='icon']:after {
font-style: normal; // Prevent symbolsfont element from being italicized;
}
[class*='icon']:before {
// Target :before to avoid affecting alias indicator
filter: $filterItemUnknown;
}
}
@mixin bgDiagonalStripes($c: yellow, $a: 0.1, $d: 40px) {
background-image: linear-gradient(-45deg,
rgba($c, $a) 25%, transparent 25%,
@@ -420,9 +442,20 @@
}
}
@mixin cClickIconButtonLayout() {
@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
$pLR: 4px;
$pTB: 4px;
@include cControl();
background: none;
box-shadow: none;
cursor: pointer;
transition: $transOut;
border-radius: $controlCr;
padding: $pTB $pLR;
&:before,
@@ -431,20 +464,6 @@
// 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;
@@ -481,16 +500,6 @@
}
}
@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;

View File

@@ -127,7 +127,7 @@ tr {
.s-status-icon-ok:before { content: $glyph-icon-check; }
/*************************************************** INDICATOR COLORING */
.c-indicator {
.ls-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

@@ -25,8 +25,8 @@
// Do not include anything that renders to CSS!
@import "constants";
@import "constants-mobile.scss";
@import "constants-espresso"; // TEMP
//@import "constants-snow"; // TEMP
//@import "constants-espresso"; // TEMP
@import "constants-snow"; // TEMP
//@import "constants-maelstrom";
@import "mixins";
@import "animations";

View File

@@ -1,22 +0,0 @@
<template>
<div class="c-indicator no-collapse icon-clock c-current-datetime">
<span class="label">{{ currentDateTime }} UTC</span>
</div>
</template>
<script>
import moment from 'moment';
export default {
data() {
return {
currentDateTime: moment.utc().format('LTS')
}
},
mounted: function() {
setInterval(()=>{
this.currentDateTime = moment.utc().format('YYYY/MM/DD HH:mm:ss')
},100)
}
}
</script>

View File

@@ -22,11 +22,13 @@
<template>
<div class="c-so-view has-local-controls"
:class="{
'c-so-view--no-frame': !hasFrame,
'c-so-view--no-frame': !hasFrame && cssClass.indexOf('unknown') === -1,
'has-complex-content': complexContent
}">
<div class="c-so-view__header">
<div class="c-so-view__header__icon" :class="cssClass"></div>
<div class="c-so-view__header"
:class="{'c-so-view__header--unknown': cssClass.indexOf('unknown') !== -1}">
<div class="c-so-view__header__icon"
:class="cssClass"></div>
<div class="c-so-view__header__name">
{{ domainObject && domainObject.name }}
</div>
@@ -74,6 +76,10 @@
@include ellipsize();
flex: 0 1 auto;
}
&--unknown {
@include isUnknown();
}
}
&:not(.c-so-view--no-frame) {

View File

@@ -1,5 +1,6 @@
<template>
<a class="c-tree__item__label c-object-label"
:class="{'c-object-label--unknown': typeClass.indexOf('icon-object-unknown') !== -1}"
draggable="true"
@dragstart="dragStart"
@click="navigateOrPreview"
@@ -39,6 +40,10 @@
color: $colorItemTreeIcon;
width: $treeTypeIconW;
}
&--unknown {
@include isUnknown();
}
}
</style>

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

@@ -5,7 +5,12 @@
class="l-browse-bar__nav-to-parent-button c-icon-button c-icon-button--major icon-pointer-left"
@click="goToParent"></button>
<div class="l-browse-bar__object-name--w"
:class="type.cssClass">
:class="[
{
'l-browse-bar--unknown': type.cssClass.indexOf('unknown') !== -1
},
type.cssClass
]">
<span
class="l-browse-bar__object-name c-input-inline"
@blur="updateName"
@@ -316,5 +321,9 @@ const PLACEHOLDER_OBJECT = {};
&__object-name {
flex: 0 1 auto;
}
&--unknown {
@include isUnknown();
}
}
</style>

View File

@@ -4,9 +4,7 @@
}">
<div class="l-shell__head">
<CreateButton class="l-shell__create-button"></CreateButton>
<indicators class="l-shell__head-section l-shell__indicators"></indicators>
<notification-banner></notification-banner> <!-- TODO: MAKE SURE THIS PLACEMENT WORKS PROPERLY -->
<div class="l-shell__head-section l-shell__controls">
<div class="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">
@@ -17,8 +15,6 @@
</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">
@@ -48,6 +44,9 @@
<Inspector :isEditing="isEditing" ref="inspector"></Inspector>
</pane>
</multipane>
<div class="l-shell__status">
<StatusBar></StatusBar>
</div>
</div>
</template>
@@ -62,13 +61,11 @@
flex-flow: column nowrap;
overflow: hidden;
/* &__status {
min-width: 95%;
margin-right: 1%;
&__status {
background: $colorStatusBarBg;
color: $colorStatusBarFg;
padding: $interiorMarginSm;
}*/
}
&__pane-tree {
width: 40%;
@@ -166,25 +163,11 @@
align-items: center;
background: $colorHeadBg;
justify-content: space-between;
padding: $interiorMargin $interiorMargin + 2;
padding: $interiorMargin;
> [class*="__"] + [class*="__"] {
margin-left: $interiorMargin;
}
[class*='__collapse-button']:before {
content: $glyph-icon-arrow-down;
font-size: 1.1em;
}
&-section {
// Subdivides elements across the head
@include ellipsize();
border-right: 1px solid $colorInteriorBorder;
display: flex;
flex: 0 1 auto;
padding-right: $interiorMargin;
}
}
&__create-button,
@@ -192,11 +175,11 @@
flex: 0 0 auto;
}
&__create-button { margin-right: $interiorMarginLg; }
&__indicators {
flex: 1 1 auto;
[class*='indicator-clock'] { order: 99; }
&__controls {
flex: 1 1 100%;
display: flex;
justify-content: flex-end;
margin-right: 2.5%;
}
/******************************* MAIN AREA */
@@ -283,10 +266,9 @@
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;
@@ -327,10 +309,9 @@
multipane,
pane,
BrowseBar,
StatusBar,
Toolbar,
AppLogo,
Indicators,
NotificationBanner
AppLogo
},
mounted() {
this.openmct.editor.on('isEditing', (isEditing)=>{
@@ -375,9 +356,6 @@
}
this.hasToolbar = structure.length > 0;
},
toggleShellHead() {
return true;
}
}
}

View File

@@ -83,13 +83,7 @@
&:hover {
background: $colorItemTreeHoverBg;
.c-tree__item__type-icon:before {
color: $colorItemTreeIconHover;
}
.c-tree__item__name {
color: $colorItemTreeHoverFg;
}
> * { filter: $filterItemHoverFg; }
}
&.is-navigated-object,

View File

@@ -148,6 +148,21 @@
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,132 +17,10 @@
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";
.l-indicators {
display: flex;
align-items: center;
}
.c-indicator {
@include cClickIconButtonLayout();
&--clickable {
@include cClickIconButton();
@include hasMenu();
}
$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;
top: 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;
bottom: 100%;
@include triangle('up', $size: 4px, $ratio: 1, $color: $hbg);
}
}
}
&.float-right {
float: right;
}
}
/* Mobile */
// Hide the clock indicator when we're phone portrait
body.phone.portrait {
.c-indicator.t-indicator-clock {
display: none;
}
}
</style>
<script>
@@ -153,11 +31,10 @@
this.openmct.indicators.indicatorObjects.forEach((indicator) => {
// So that we can consistently position indicator elements,
// guarantee that they are wrapped in an element we control
// CH: fuck that...
// var wrapperNode = document.createElement('span');
// wrapperNode.className = 'u-contents';
// wrapperNode.appendChild(indicator.element);
this.$el.appendChild(indicator.element);
var wrapperNode = document.createElement('span');
wrapperNode.className = 'l-indicator';
wrapperNode.appendChild(indicator.element);
this.$el.appendChild(wrapperNode);
});
}
}

View File

@@ -0,0 +1,42 @@
<!--
Open MCT, Copyright (c) 2014-2018, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<template>
<span class="c-status">
<indicators></indicators>
<notification-banner></notification-banner>
</span>
</template>
<style lang="scss">
.c-status {
width: 100%;
}
</style>
<script>
import Indicators from './Indicators.vue';
import NotificationBanner from './NotificationBanner.vue';
export default {
components: {
Indicators,
NotificationBanner
}
}
</script>

View File

@@ -24,6 +24,7 @@ const webpackConfig = {
output: {
filename: '[name].js',
library: '[name]',
libraryTarget: 'umd',
path: path.resolve(__dirname, 'dist')
},
resolve: {
@@ -35,6 +36,7 @@ const webpackConfig = {
"bourbon": "bourbon.scss",
"vue": path.join(__dirname, "node_modules/vue/dist/vue.js"),
"d3-scale": path.join(__dirname, "node_modules/d3-scale/build/d3-scale.min.js"),
"printj": path.join(__dirname, "node_modules/printj/dist/printj.min.js"),
"styles": path.join(__dirname, "src/styles-new")
}
},