Merge branch 'master' into data-dropout-fixes

This commit is contained in:
Andrew Henry 2020-07-16 11:55:02 -07:00 committed by GitHub
commit 3f60c3c0f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 400 additions and 189 deletions

3
.gitignore vendored
View File

@ -37,4 +37,7 @@ protractor/logs
# npm-debug log # npm-debug log
npm-debug.log npm-debug.log
# karma reports
report.*.json
package-lock.json package-lock.json

View File

@ -19,7 +19,13 @@
this source code distribution or the Licensing information page available this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<div class="c-object-label"> <div class="c-object-label"
<div class="c-object-label__type-icon {{type.getCssClass()}}" ng-class="{ 'l-icon-link':location.isLink() }"></div> ng-class="{ 'is-missing': model.status === 'missing' }"
>
<div class="c-object-label__type-icon {{type.getCssClass()}}"
ng-class="{ 'l-icon-link':location.isLink() }"
>
<span class="is-missing__indicator" title="This item is missing"></span>
</div>
<div class='c-object-label__name'>{{model.name}}</div> <div class='c-object-label__name'>{{model.name}}</div>
</div> </div>

View File

@ -31,10 +31,16 @@
<div <div
v-if="domainObject" v-if="domainObject"
class="c-telemetry-view" class="c-telemetry-view"
:class="styleClass" :class="{
styleClass,
'is-missing': domainObject.status === 'missing'
}"
:style="styleObject" :style="styleObject"
@contextmenu.prevent="showContextMenu" @contextmenu.prevent="showContextMenu"
> >
<div class="is-missing__indicator"
title="This item is missing"
></div>
<div <div
v-if="showLabel" v-if="showLabel"
class="c-telemetry-view__label" class="c-telemetry-view__label"

View File

@ -26,4 +26,14 @@
@include abs(); @include abs();
border: 1px solid transparent; border: 1px solid transparent;
} }
&.is-missing {
@include isMissing($absPos: true);
border: $borderMissing;
.is-missing__indicator {
top: 0;
left: 0;
}
}
} }

View File

@ -1,13 +1,18 @@
<template> <template>
<a <a
class="l-grid-view__item c-grid-item" class="l-grid-view__item c-grid-item"
:class="{ 'is-alias': item.isAlias === true }" :class="{
'is-alias': item.isAlias === true,
'is-missing': item.model.status === 'missing',
'c-grid-item--unknown': item.type.cssClass === undefined || item.type.cssClass.indexOf('unknown') !== -1
}"
:href="objectLink" :href="objectLink"
> >
<div <div
class="c-grid-item__type-icon" class="c-grid-item__type-icon"
:class="(item.type.cssClass != undefined) ? 'bg-' + item.type.cssClass : 'bg-icon-object-unknown'" :class="(item.type.cssClass != undefined) ? 'bg-' + item.type.cssClass : 'bg-icon-object-unknown'"
></div> >
</div>
<div class="c-grid-item__details"> <div class="c-grid-item__details">
<!-- Name and metadata --> <!-- Name and metadata -->
<div <div
@ -22,6 +27,9 @@
</div> </div>
</div> </div>
<div class="c-grid-item__controls"> <div class="c-grid-item__controls">
<div class="is-missing__indicator"
title="This item is missing"
></div>
<div <div
class="icon-people" class="icon-people"
title="Shared" title="Shared"

View File

@ -7,13 +7,19 @@
<td class="c-list-item__name"> <td class="c-list-item__name">
<a <a
ref="objectLink" ref="objectLink"
class="c-object-label"
:class="{ 'is-missing': item.model.status === 'missing' }"
:href="objectLink" :href="objectLink"
> >
<div <div
class="c-list-item__type-icon" class="c-object-label__type-icon c-list-item__type-icon"
:class="item.type.cssClass" :class="item.type.cssClass"
></div> >
<div class="c-list-item__name-value">{{ item.model.name }}</div> <span class="is-missing__indicator"
title="This item is missing"
></span>
</div>
<div class="c-object-label__name c-list-item__name">{{ item.model.name }}</div>
</a> </a>
</td> </td>
<td class="c-list-item__type"> <td class="c-list-item__type">

View File

@ -38,7 +38,15 @@
// Object is an alias to an original. // Object is an alias to an original.
[class*='__type-icon'] { [class*='__type-icon'] {
@include isAlias(); @include isAlias();
color: $colorIconAliasForKeyFilter; }
}
&.is-missing {
@include isMissing();
[class*='__type-icon'],
[class*='__details'] {
opacity: $opacityMissing;
} }
} }
@ -85,15 +93,14 @@
body.desktop & { body.desktop & {
$transOutMs: 300ms; $transOutMs: 300ms;
flex-flow: column nowrap; flex-flow: column nowrap;
transition: background $transOutMs ease-in-out; transition: $transOutMs ease-in-out;
&:hover { &:hover {
background: $colorItemBgHov; filter: $filterItemHoverFg;
transition: $transIn; transition: $transIn;
.c-grid-item__type-icon { .c-grid-item__type-icon {
filter: $colorKeyFilterHov; transform: scale(1.1);
transform: scale(1);
transition: $transInBounce; transition: $transInBounce;
} }
} }
@ -103,7 +110,7 @@
} }
&__controls { &__controls {
align-items: start; align-items: baseline;
flex: 0 0 auto; flex: 0 0 auto;
order: 1; order: 1;
.c-info-button, .c-info-button,
@ -115,7 +122,6 @@
font-size: floor($gridItemDesk / 3); font-size: floor($gridItemDesk / 3);
margin: $interiorMargin 22.5% $interiorMargin * 3 22.5%; margin: $interiorMargin 22.5% $interiorMargin * 3 22.5%;
order: 2; order: 2;
transform: scale(0.9);
transform-origin: center; transform-origin: center;
transition: all $transOutMs ease-in-out; transition: all $transOutMs ease-in-out;
} }

View File

@ -1,37 +1,17 @@
/******************************* LIST ITEM */ /******************************* LIST ITEM */
.c-list-item { .c-list-item {
&__name a {
display: flex;
> * + * { margin-left: $interiorMarginSm; }
}
&__type-icon { &__type-icon {
// Have to do it this way instead of using icon-* class, due to need to apply alias to the icon color: $colorItemTreeIcon;
color: $colorKey;
display: inline-block;
width: 1em;
margin-right:$interiorMarginSm;
} }
&__name-value { &__name {
@include ellipsize(); @include ellipsize();
} }
&.is-alias { &.is-alias {
// Object is an alias to an original. // Object is an alias to an original.
[class*='__type-icon'] { [class*='__type-icon'] {
&:after { @include isAlias();
color: $colorIconAlias;
content: $glyph-icon-link;
font-family: symbolsfont;
display: block;
position: absolute;
text-shadow: rgba(black, 0.5) 0 1px 2px;
top: auto; left: -1px; bottom: 1px; right: auto;
transform-origin: bottom left;
transform: scale(0.65);
}
} }
} }
} }

View File

@ -13,7 +13,8 @@
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background: $colorListItemBgHov; background: $colorItemTreeHoverBg;
filter: $filterHov;
transition: $transIn; transition: $transIn;
} }
} }

View File

@ -28,17 +28,22 @@
ng-click="legend.set('expanded', !legend.get('expanded'));"> ng-click="legend.set('expanded', !legend.get('expanded'));">
</div> </div>
<div class="c-plot-legend__wrapper"> <div class="c-plot-legend__wrapper"
ng-class="{ 'is-cursor-locked': !!lockHighlightPoint }">
<!-- COLLAPSED PLOT LEGEND --> <!-- COLLAPSED PLOT LEGEND -->
<div class="plot-wrapper-collapsed-legend" <div class="plot-wrapper-collapsed-legend"
ng-class="{'icon-cursor-lock': !!lockHighlightPoint}"> ng-class="{'is-cursor-locked': !!lockHighlightPoint }">
<div class="c-state-indicator__alert-cursor-lock icon-cursor-lock" title="Cursor is point locked. Click anywhere in the plot to unlock."></div>
<div class="plot-legend-item" <div class="plot-legend-item"
ng-repeat="series in series track by $index"> ng-class="{'is-missing': series.domainObject.status === 'missing'}"
ng-repeat="series in series track by $index"
>
<div class="plot-series-swatch-and-name"> <div class="plot-series-swatch-and-name">
<span class="plot-series-color-swatch" <span class="plot-series-color-swatch "
ng-style="{ 'background-color': series.get('color').asHexString() }"> ng-style="{ 'background-color': series.get('color').asHexString() }">
</span> </span>
<span class="is-missing__indicator" title="This item is missing"></span>
<span class="plot-series-name">{{ series.get('name') }}</span> <span class="plot-series-name">{{ series.get('name') }}</span>
</div> </div>
<div class="plot-series-value hover-value-enabled value-to-display-{{ legend.get('valueToShowWhenCollapsed') }} {{ series.closest.mctLimitState.cssClass }}" <div class="plot-series-value hover-value-enabled value-to-display-{{ legend.get('valueToShowWhenCollapsed') }} {{ series.closest.mctLimitState.cssClass }}"
@ -55,7 +60,10 @@
</div> </div>
<!-- EXPANDED PLOT LEGEND --> <!-- EXPANDED PLOT LEGEND -->
<div class="plot-wrapper-expanded-legend"> <div class="plot-wrapper-expanded-legend"
ng-class="{'is-cursor-locked': !!lockHighlightPoint }"
>
<div class="c-state-indicator__alert-cursor-lock--verbose icon-cursor-lock" title="Click anywhere in the plot to unlock."> Cursor locked to point</div>
<table> <table>
<thead> <thead>
<tr> <tr>
@ -76,12 +84,15 @@
</th> </th>
</tr> </tr>
</thead> </thead>
<tr ng-repeat="series in series" class="plot-legend-item"> <tr ng-repeat="series in series"
<td class="plot-series-swatch-and-name" class="plot-legend-item"
ng-class="{'icon-cursor-lock': !!lockHighlightPoint}"> ng-class="{'is-missing': series.domainObject.status === 'missing'}"
>
<td class="plot-series-swatch-and-name">
<span class="plot-series-color-swatch" <span class="plot-series-color-swatch"
ng-style="{ 'background-color': series.get('color').asHexString() }"> ng-style="{ 'background-color': series.get('color').asHexString() }">
</span> </span>
<span class="is-missing__indicator" title="This item is missing"></span>
<span class="plot-series-name">{{ series.get('name') }}</span> <span class="plot-series-name">{{ series.get('name') }}</span>
</td> </td>
@ -134,7 +145,7 @@
{{option.name}} {{option.name}}
</option> </option>
</select> </select>
<mct-ticks axis="yAxis"> <mct-ticks axis="yAxis">
<div ng-repeat="tick in ticks track by tick.value" <div ng-repeat="tick in ticks track by tick.value"

View File

@ -71,8 +71,6 @@ define([
this.listenTo(this.$canvas, 'mouseleave', this.untrackMousePosition, this); this.listenTo(this.$canvas, 'mouseleave', this.untrackMousePosition, this);
this.listenTo(this.$canvas, 'mousedown', this.onMouseDown, this); this.listenTo(this.$canvas, 'mousedown', this.onMouseDown, this);
this.listenTo(this.$canvas, 'wheel', this.wheelZoom, this); this.listenTo(this.$canvas, 'wheel', this.wheelZoom, this);
this.watchForMarquee();
}; };
MCTPlotController.prototype.initialize = function () { MCTPlotController.prototype.initialize = function () {
@ -83,11 +81,6 @@ define([
this.listenTo(this.$canvas, 'mousedown', this.onMouseDown, this); this.listenTo(this.$canvas, 'mousedown', this.onMouseDown, this);
this.listenTo(this.$canvas, 'wheel', this.wheelZoom, this); this.listenTo(this.$canvas, 'wheel', this.wheelZoom, this);
this.watchForMarquee();
this.listenTo(this.$window, 'keydown', this.toggleInteractionMode, this);
this.listenTo(this.$window, 'keyup', this.resetInteractionMode, this);
this.$scope.rectangles = []; this.$scope.rectangles = [];
this.$scope.tickWidth = 0; this.$scope.tickWidth = 0;
@ -243,12 +236,16 @@ define([
}; };
MCTPlotController.prototype.onMouseDown = function ($event) { MCTPlotController.prototype.onMouseDown = function ($event) {
// do not monitor drag events on browser context click
if (event.ctrlKey) {
return;
}
this.listenTo(this.$window, 'mouseup', this.onMouseUp, this); this.listenTo(this.$window, 'mouseup', this.onMouseUp, this);
this.listenTo(this.$window, 'mousemove', this.trackMousePosition, this); this.listenTo(this.$window, 'mousemove', this.trackMousePosition, this);
if (this.allowPan) { if (event.altKey) {
return this.startPan($event); return this.startPan($event);
} } else {
if (this.allowMarquee) {
return this.startMarquee($event); return this.startMarquee($event);
} }
}; };
@ -261,11 +258,11 @@ define([
this.$scope.lockHighlightPoint = !this.$scope.lockHighlightPoint; this.$scope.lockHighlightPoint = !this.$scope.lockHighlightPoint;
} }
if (this.allowPan) { if (this.pan) {
return this.endPan($event); return this.endPan($event);
} }
if (this.allowMarquee) { if (this.marquee) {
return this.endMarquee($event); return this.endMarquee($event);
} }
}; };
@ -289,6 +286,9 @@ define([
}; };
MCTPlotController.prototype.startMarquee = function ($event) { MCTPlotController.prototype.startMarquee = function ($event) {
this.$canvas.removeClass('plot-drag');
this.$canvas.addClass('plot-marquee');
this.trackMousePosition($event); this.trackMousePosition($event);
if (this.positionOverPlot) { if (this.positionOverPlot) {
this.freeze(); this.freeze();
@ -444,6 +444,9 @@ define([
}; };
MCTPlotController.prototype.startPan = function ($event) { MCTPlotController.prototype.startPan = function ($event) {
this.$canvas.addClass('plot-drag');
this.$canvas.removeClass('plot-marquee');
this.trackMousePosition($event); this.trackMousePosition($event);
this.freeze(); this.freeze();
this.pan = { this.pan = {
@ -486,32 +489,6 @@ define([
this.$scope.$emit('user:viewport:change:end'); this.$scope.$emit('user:viewport:change:end');
}; };
MCTPlotController.prototype.watchForMarquee = function () {
this.$canvas.removeClass('plot-drag');
this.$canvas.addClass('plot-marquee');
this.allowPan = false;
this.allowMarquee = true;
};
MCTPlotController.prototype.watchForPan = function () {
this.$canvas.addClass('plot-drag');
this.$canvas.removeClass('plot-marquee');
this.allowPan = true;
this.allowMarquee = false;
};
MCTPlotController.prototype.toggleInteractionMode = function (event) {
if (event.keyCode === 18) { // control key.
this.watchForPan();
}
};
MCTPlotController.prototype.resetInteractionMode = function (event) {
if (event.keyCode === 18) {
this.watchForMarquee();
}
};
MCTPlotController.prototype.freeze = function () { MCTPlotController.prototype.freeze = function () {
this.config.yAxis.set('frozen', true); this.config.yAxis.set('frozen', true);
this.config.xAxis.set('frozen', true); this.config.xAxis.set('frozen', true);

View File

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

View File

@ -3,7 +3,7 @@
<div <div
class="c-tabs-view__tabs-holder c-tabs" class="c-tabs-view__tabs-holder c-tabs"
:class="{ :class="{
'is-dragging': isDragging, 'is-dragging': isDragging && allowEditing,
'is-mouse-over': allowDrop 'is-mouse-over': allowDrop
}" }"
> >
@ -22,14 +22,21 @@
<button <button
v-for="(tab,index) in tabsList" v-for="(tab,index) in tabsList"
:key="index" :key="index"
class="c-tabs-view__tab c-tab" class="c-tabs-view__tab c-tab c-object-label"
:class="[ :class="{
{'is-current': isCurrent(tab)}, 'is-current': isCurrent(tab),
tab.type.definition.cssClass 'is-missing': tab.domainObject.status === 'missing'
]" }"
@click="showTab(tab, index)" @click="showTab(tab, index)"
> >
<span class="c-button__label">{{ tab.domainObject.name }}</span> <div class="c-object-label__type-icon"
:class="tab.type.definition.cssClass"
>
<span class="is-missing__indicator"
title="This item is missing"
></span>
</div>
<span class="c-button__label c-object-label__name">{{ tab.domainObject.name }}</span>
</button> </button>
</div> </div>
<div <div
@ -38,15 +45,6 @@
class="c-tabs-view__object-holder" class="c-tabs-view__object-holder"
:class="{'c-tabs-view__object-holder--hidden': !isCurrent(tab)}" :class="{'c-tabs-view__object-holder--hidden': !isCurrent(tab)}"
> >
<div
v-if="currentTab"
class="c-tabs-view__object-name c-object-label l-browse-bar__object-name--w"
:class="currentTab.type.definition.cssClass"
>
<div class="l-browse-bar__object-name c-object-label__name">
{{ currentTab.domainObject.name }}
</div>
</div>
<object-view <object-view
v-if="internalDomainObject.keep_alive ? currentTab : isCurrent(tab)" v-if="internalDomainObject.keep_alive ? currentTab : isCurrent(tab)"
class="c-tabs-view__object" class="c-tabs-view__object"
@ -58,6 +56,12 @@
<script> <script>
import ObjectView from '../../../ui/components/ObjectView.vue'; import ObjectView from '../../../ui/components/ObjectView.vue';
import {
getSearchParam,
setSearchParam,
deleteSearchParam
} from 'utils/openmctLocation';
var unknownObjectType = { var unknownObjectType = {
definition: { definition: {
@ -71,26 +75,45 @@ export default {
components: { components: {
ObjectView ObjectView
}, },
props: {
isEditing: {
type: Boolean,
required: true
}
},
data: function () { data: function () {
let keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
return { return {
internalDomainObject: this.domainObject, internalDomainObject: this.domainObject,
currentTab: {}, currentTab: {},
currentTabIndex: undefined,
tabsList: [], tabsList: [],
setCurrentTab: true, setCurrentTab: true,
isDragging: false, isDragging: false,
allowDrop: false allowDrop: false,
searchTabKey: `tabs.pos.${keyString}`
}; };
}, },
computed: {
allowEditing() {
return !this.internalDomainObject.locked && this.isEditing;
}
},
mounted() { mounted() {
if (this.composition) { if (this.composition) {
this.composition.on('add', this.addItem); this.composition.on('add', this.addItem);
this.composition.on('remove', this.removeItem); this.composition.on('remove', this.removeItem);
this.composition.on('reorder', this.onReorder); this.composition.on('reorder', this.onReorder);
this.composition.load().then(() => { this.composition.load().then(() => {
let currentTabIndex = this.domainObject.currentTabIndex; let currentTabIndexFromURL = getSearchParam(this.searchTabKey);
let currentTabIndexFromDomainObject = this.internalDomainObject.currentTabIndex;
if (currentTabIndex !== undefined && this.tabsList.length > currentTabIndex) { if (currentTabIndexFromURL !== null) {
this.currentTab = this.tabsList[currentTabIndex]; this.setCurrentTabByIndex(currentTabIndexFromURL);
} else if (currentTabIndexFromDomainObject !== undefined) {
this.setCurrentTabByIndex(currentTabIndexFromDomainObject);
this.storeCurrentTabIndexInURL(currentTabIndexFromDomainObject);
} }
}); });
} }
@ -100,20 +123,29 @@ export default {
document.addEventListener('dragstart', this.dragstart); document.addEventListener('dragstart', this.dragstart);
document.addEventListener('dragend', this.dragend); document.addEventListener('dragend', this.dragend);
}, },
beforeDestroy() {
this.persistCurrentTabIndex(this.currentTabIndex);
},
destroyed() { destroyed() {
this.composition.off('add', this.addItem); this.composition.off('add', this.addItem);
this.composition.off('remove', this.removeItem); this.composition.off('remove', this.removeItem);
this.composition.off('reorder', this.onReorder); this.composition.off('reorder', this.onReorder);
this.unsubscribe(); this.unsubscribe();
this.clearCurrentTabIndexFromURL();
document.removeEventListener('dragstart', this.dragstart); document.removeEventListener('dragstart', this.dragstart);
document.removeEventListener('dragend', this.dragend); document.removeEventListener('dragend', this.dragend);
}, },
methods:{ methods:{
setCurrentTabByIndex(index) {
if (this.tabsList[index]) {
this.currentTab = this.tabsList[index];
}
},
showTab(tab, index) { showTab(tab, index) {
if (index !== undefined) { if (index !== undefined) {
this.storeCurrentTabIndex(index); this.storeCurrentTabIndexInURL(index);
} }
this.currentTab = tab; this.currentTab = tab;
@ -133,6 +165,10 @@ export default {
this.setCurrentTab = false; this.setCurrentTab = false;
} }
}, },
reset() {
this.currentTab = {};
this.setCurrentTab = true;
},
removeItem(identifier) { removeItem(identifier) {
let pos = this.tabsList.findIndex(tab => let pos = this.tabsList.findIndex(tab =>
tab.domainObject.identifier.namespace === identifier.namespace && tab.domainObject.identifier.key === identifier.key tab.domainObject.identifier.namespace === identifier.namespace && tab.domainObject.identifier.key === identifier.key
@ -144,6 +180,10 @@ export default {
if (this.isCurrent(tabToBeRemoved)) { if (this.isCurrent(tabToBeRemoved)) {
this.showTab(this.tabsList[this.tabsList.length - 1], this.tabsList.length - 1); this.showTab(this.tabsList[this.tabsList.length - 1], this.tabsList.length - 1);
} }
if (!this.tabsList.length) {
this.reset();
}
}, },
onReorder(reorderPlan) { onReorder(reorderPlan) {
let oldTabs = this.tabsList.slice(); let oldTabs = this.tabsList.slice();
@ -154,7 +194,7 @@ export default {
}, },
onDrop(e) { onDrop(e) {
this.setCurrentTab = true; this.setCurrentTab = true;
this.storeCurrentTabIndex(this.tabsList.length); this.storeCurrentTabIndexInURL(this.tabsList.length);
}, },
dragstart(e) { dragstart(e) {
if (e.dataTransfer.types.includes('openmct/domain-object-path')) { if (e.dataTransfer.types.includes('openmct/domain-object-path')) {
@ -177,8 +217,19 @@ export default {
updateInternalDomainObject(domainObject) { updateInternalDomainObject(domainObject) {
this.internalDomainObject = domainObject; this.internalDomainObject = domainObject;
}, },
storeCurrentTabIndex(index) { persistCurrentTabIndex(index) {
this.openmct.objects.mutate(this.internalDomainObject, 'currentTabIndex', index); this.openmct.objects.mutate(this.internalDomainObject, 'currentTabIndex', index);
},
storeCurrentTabIndexInURL(index) {
let currentTabIndexInURL = getSearchParam(this.searchTabKey);
if (index !== currentTabIndexInURL) {
setSearchParam(this.searchTabKey, index);
this.currentTabIndex = index;
}
},
clearCurrentTabIndexFromURL() {
deleteSearchParam(this.searchTabKey);
} }
} }
} }

View File

@ -42,20 +42,28 @@ define([
let component; let component;
return { return {
show: function (element) { show: function (element, editMode) {
component = new Vue({ component = new Vue({
el: element, el: element,
components: { components: {
TabsComponent: TabsComponent.default TabsComponent: TabsComponent.default
}, },
data() {
return {
isEditing: editMode
};
},
provide: { provide: {
openmct, openmct,
domainObject, domainObject,
composition: openmct.composition.get(domainObject) composition: openmct.composition.get(domainObject)
}, },
template: '<tabs-component></tabs-component>' template: '<tabs-component :isEditing="isEditing"></tabs-component>'
}); });
}, },
onEditModeChange(editMode) {
component.isEditing = editMode;
},
destroy: function (element) { destroy: function (element) {
component.$destroy(); component.$destroy();
component = undefined; component = undefined;

View File

@ -151,6 +151,10 @@ $browseFrameColor: pullForward($colorBodyBg, 10%);
$browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing $browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing
$browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px; $browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4); $browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4);
$filterItemHoverFg: brightness(1.2) contrast(1.1);
$filterItemMissing: brightness(0.6) grayscale(1);
$opacityMissing: 0.5;
$borderMissing: 1px dashed $colorAlert !important;
/************************************************** EDITING */ /************************************************** EDITING */
$editUIColor: $uiColor; // Base color $editUIColor: $uiColor; // Base color

View File

@ -155,6 +155,10 @@ $browseFrameColor: pullForward($colorBodyBg, 10%);
$browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing $browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing
$browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px; $browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4); $browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4);
$filterItemHoverFg: brightness(1.2) contrast(1.1);
$filterItemMissing: contrast(0.2);
$opacityMissing: 0.5;
$borderMissing: 1px dashed $colorAlert !important;
/************************************************** EDITING */ /************************************************** EDITING */
$editUIColor: $uiColor; // Base color $editUIColor: $uiColor; // Base color

View File

@ -151,6 +151,10 @@ $browseFrameColor: pullForward($colorBodyBg, 10%);
$browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing $browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing
$browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px; $browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4); $browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4);
$filterItemHoverFg: brightness(0.9);
$filterItemMissing: contrast(0.2);
$opacityMissing: 0.4;
$borderMissing: 1px dashed $colorAlert !important;
/************************************************** EDITING */ /************************************************** EDITING */
$editUIColor: $uiColor; // Base color $editUIColor: $uiColor; // Base color

View File

@ -61,7 +61,7 @@ $plotXBarH: 35px;
$plotLegendH: 20px; $plotLegendH: 20px;
$plotLegendWidthCollapsed: 20%; $plotLegendWidthCollapsed: 20%;
$plotLegendWidthExpanded: 50%; $plotLegendWidthExpanded: 50%;
$plotSwatchD: 10px; $plotSwatchD: 12px;
$plotDisplayArea: (0, 0, $plotXBarH, $plotYBarW); // 1: Top, 2: right, 3: bottom, 4: left $plotDisplayArea: (0, 0, $plotXBarH, $plotYBarW); // 1: Top, 2: right, 3: bottom, 4: left
$plotMinH: 95px; $plotMinH: 95px;
$controlBarH: 25px; $controlBarH: 25px;

View File

@ -420,9 +420,7 @@ select {
margin: 1px 1px 0 0; margin: 1px 1px 0 0;
padding: $interiorMargin $interiorMarginLg; padding: $interiorMargin $interiorMarginLg;
white-space: nowrap; white-space: nowrap;
--notchSize: 7px; --notchSize: 7px;
clip-path: clip-path:
polygon( polygon(
0% 0%, 0% 0%,
@ -433,8 +431,12 @@ select {
0% 100% 0% 100%
); );
> * + * {
margin-left: $interiorMargin;
}
@include hover() { @include hover() {
background: $colorBtnBgHov; filter: $filterHov;
} }
&.is-current { &.is-current {

View File

@ -43,7 +43,9 @@ mct-plot {
.c-plot, .c-plot,
.gl-plot { .gl-plot {
.s-status-taking-snapshot & { overflow: hidden;
.s-status-taking-snapshot & {
.c-control-bar { .c-control-bar {
display: none; display: none;
} }
@ -51,6 +53,17 @@ mct-plot {
display: none; display: none;
} }
} }
/*********************** MISSING ITEM INDICATORS */
.is-missing__indicator {
display: none;
}
.is-missing {
@include isMissing();
.is-missing__indicator {
font-size: 0.8em;
}
}
} }
.c-plot { .c-plot {
@ -74,6 +87,7 @@ mct-plot {
display: flex; display: flex;
flex: 1 1 auto; flex: 1 1 auto;
flex-direction: column; flex-direction: column;
overflow: hidden;
} }
&--stacked { &--stacked {
@ -102,18 +116,17 @@ mct-plot {
} }
} }
.gl-plot { .gl-plot {
display: flex; display: flex;
position: relative; position: relative;
width: 100%; width: 100%;
height: 100%; height: 100%;
min-height: $plotMinH;
/*********************** AXIS AND DISPLAY AREA */ /*********************** AXIS AND DISPLAY AREA */
.plot-wrapper-axis-and-display-area { .plot-wrapper-axis-and-display-area {
position: relative; position: relative;
flex: 1 1 auto; flex: 1 1 auto;
min-height: $plotMinH;
} }
.gl-plot-wrapper-display-area-and-x-axis { .gl-plot-wrapper-display-area-and-x-axis {
@ -196,7 +209,6 @@ mct-plot {
left: 0; top: 0; right: auto; bottom: 0; left: 0; top: 0; right: auto; bottom: 0;
padding-left: 5px; padding-left: 5px;
text-orientation: mixed; text-orientation: mixed;
//overflow: hidden;
writing-mode: vertical-lr; writing-mode: vertical-lr;
&:before { &:before {
// Icon denoting configurability // Icon denoting configurability
@ -368,12 +380,6 @@ mct-plot {
z-index: -10; z-index: -10;
.l-view-section { .l-view-section {
//$m: $interiorMargin;
//top: $m !important;
//right: $m;
//bottom: $m;
//left: $m;
.s-status-timeconductor-unsynced .holder-plot { .s-status-timeconductor-unsynced .holder-plot {
.t-object-alert.t-alert-unsynced { .t-object-alert.t-alert-unsynced {
display: none; display: none;
@ -429,14 +435,18 @@ mct-plot {
/****************** _LEGEND.SCSS */ /****************** _LEGEND.SCSS */
.gl-plot-legend, .gl-plot-legend,
.c-plot-legend { .c-plot-legend {
overflow: hidden;
&__wrapper { &__wrapper {
// Holds view-control and both collapsed and expanded legends // Holds view-control and both collapsed and expanded legends
flex: 1 1 auto; flex: 1 1 auto;
overflow: auto; // Prevents collapsed legend from forcing scrollbars on higher parent containers height: 100%;
overflow: auto;
padding: 2px;
} }
&__view-control { &__view-control {
padding-top: 2px; padding-top: 4px;
margin-right: $interiorMarginSm; margin-right: $interiorMarginSm;
} }
@ -481,15 +491,21 @@ mct-plot {
/***************** GENERAL STYLES, ALL STATES */ /***************** GENERAL STYLES, ALL STATES */
.plot-legend-item { .plot-legend-item {
// General styles for legend items, both expanded and collapsed legend states // General styles for legend items, both expanded and collapsed legend states
> * + * {
margin-left: $interiorMarginSm;
}
.plot-series-color-swatch { .plot-series-color-swatch {
border-radius: $smallCr; border-radius: 30%; //$smallCr;
border: 1px solid $colorBodyBg; border: 1px solid $colorBodyBg;
display: inline-block; display: inline-block;
flex: 0 0 auto;
height: $plotSwatchD; height: $plotSwatchD;
width: $plotSwatchD; width: $plotSwatchD;
} }
.plot-series-name { .plot-series-name {
display: inline; display: inline;
@include ellipsize();
} }
.plot-series-value { .plot-series-value {
@ -497,6 +513,16 @@ mct-plot {
} }
} }
.plot-series-swatch-and-name {
display: flex;
flex: 0 1 auto;
align-items: center;
> * + * {
margin-left: $interiorMarginSm;
}
}
.plot-wrapper-expanded-legend { .plot-wrapper-expanded-legend {
flex: 1 1 auto; flex: 1 1 auto;
} }
@ -505,9 +531,6 @@ mct-plot {
&.plot-legend-collapsed .plot-wrapper-expanded-legend { display: none; } &.plot-legend-collapsed .plot-wrapper-expanded-legend { display: none; }
&.plot-legend-expanded .plot-wrapper-collapsed-legend { display: none; } &.plot-legend-expanded .plot-wrapper-collapsed-legend { display: none; }
&.plot-legend-collapsed .icon-cursor-lock::before { padding-right: 5px; }
&.plot-legend-expanded .icon-cursor-lock::before { padding-right: 5px; }
&.plot-legend-top .gl-plot-legend { margin-bottom: $interiorMargin; } &.plot-legend-top .gl-plot-legend { margin-bottom: $interiorMargin; }
&.plot-legend-bottom .gl-plot-legend { margin-top: $interiorMargin; } &.plot-legend-bottom .gl-plot-legend { margin-top: $interiorMargin; }
&.plot-legend-right .gl-plot-legend { margin-left: $interiorMargin; } &.plot-legend-right .gl-plot-legend { margin-left: $interiorMargin; }
@ -521,19 +544,13 @@ mct-plot {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: stretch; justify-content: stretch;
&:not(:first-child) {
margin-left: $interiorMarginLg;
}
.plot-series-swatch-and-name, .plot-series-swatch-and-name,
.plot-series-value { .plot-series-value {
@include ellipsize(); @include ellipsize();
flex: 1 1 auto; flex: 1 1 auto;
} }
.plot-series-swatch-and-name {
margin-right: $interiorMarginSm;
}
.plot-series-value { .plot-series-value {
text-align: left; text-align: left;
} }
@ -543,7 +560,7 @@ mct-plot {
/***************** GENERAL STYLES, EXPANDED */ /***************** GENERAL STYLES, EXPANDED */
&.plot-legend-expanded { &.plot-legend-expanded {
.gl-plot-legend { .gl-plot-legend {
// max-height: 70%; max-height: 70%;
} }
.plot-wrapper-expanded-legend { .plot-wrapper-expanded-legend {
@ -564,6 +581,11 @@ mct-plot {
display: flex; display: flex;
flex: 1 1 auto; flex: 1 1 auto;
overflow: hidden; overflow: hidden;
> .plot-legend-item + .plot-legend-item {
// Space between plot items
margin-left: $interiorMarginLg;
}
} }
} }
} }
@ -595,12 +617,17 @@ mct-plot {
min-width: 0; min-width: 0;
flex: 1 1 auto; flex: 1 1 auto;
overflow-y: auto; overflow-y: auto;
> * + * {
// Space between plot items
margin-top: $interiorMarginSm;
}
} }
.plot-legend-item { .plot-legend-item {
margin-bottom: 1px;
margin-left: 0; margin-left: 0;
flex-wrap: wrap; flex-wrap: nowrap;
.plot-series-swatch-and-name { .plot-series-swatch-and-name {
@include ellipsize();
flex: 0 1 auto; flex: 0 1 auto;
min-width: 20%; min-width: 20%;
} }
@ -654,3 +681,24 @@ mct-plot {
display: inline-block !important; display: inline-block !important;
} }
} }
/*********************** CURSOR LOCK INDICATOR */
[class*='c-state-indicator__alert-cursor-lock'] {
display: none;
}
[class*='is-cursor-locked'] {
background: rgba($colorInfo, 0.1);
[class*='c-state-indicator__alert-cursor-lock'] {
@include userSelectNone();
color: $colorInfo;
display: block;
margin-right: $interiorMarginSm;
&[class*='--verbose'] {
padding: $interiorMarginSm;
}
}
}

View File

@ -117,6 +117,30 @@
} }
} }
@mixin isMissing($absPos: false) {
// Common styles to be applied to tree items, object labels, grid and list item views
//opacity: 0.7;
//pointer-events: none; // Don't think we can do this, as disables title hover on icon element
.is-missing__indicator {
display: block;
text-shadow: $colorBodyBg 0 0 2px;
color: $colorAlert;
font-family: symbolsfont;
&:before {
content: $glyph-icon-alert-triangle;
}
}
@if $absPos {
.is-missing__indicator {
position: absolute;
z-index: 3;
}
}
}
@mixin bgDiagonalStripes($c: yellow, $a: 0.1, $d: 40px) { @mixin bgDiagonalStripes($c: yellow, $a: 0.1, $d: 40px) {
background-image: linear-gradient(-45deg, background-image: linear-gradient(-45deg,
rgba($c, $a) 25%, transparent 25%, rgba($c, $a) 25%, transparent 25%,

View File

@ -49,8 +49,6 @@ table {
td { td {
vertical-align: top; vertical-align: top;
} }
a { color: $colorBtnMajorBg; }
} }
.is-editing { .is-editing {

View File

@ -13,7 +13,6 @@
@import "../plugins/filters/components/filters-view.scss"; @import "../plugins/filters/components/filters-view.scss";
@import "../plugins/filters/components/global-filters.scss"; @import "../plugins/filters/components/global-filters.scss";
@import "../plugins/flexibleLayout/components/flexible-layout.scss"; @import "../plugins/flexibleLayout/components/flexible-layout.scss";
@import "../plugins/folderView/components/grid-item.scss";
@import "../plugins/folderView/components/grid-view.scss"; @import "../plugins/folderView/components/grid-view.scss";
@import "../plugins/folderView/components/list-item.scss"; @import "../plugins/folderView/components/list-item.scss";
@import "../plugins/folderView/components/list-view.scss"; @import "../plugins/folderView/components/list-view.scss";

View File

@ -24,13 +24,24 @@
class="c-so-view has-local-controls" class="c-so-view has-local-controls"
:class="{ :class="{
'c-so-view--no-frame': !hasFrame, 'c-so-view--no-frame': !hasFrame,
'has-complex-content': complexContent 'has-complex-content': complexContent,
'is-missing': domainObject.status === 'missing'
}" }"
> >
<div class="c-so-view__header"> <div class="c-so-view__header">
<div class="c-object-label" <div class="c-object-label"
:class="[cssClass, classList]" :class="{
classList,
'is-missing': domainObject.status === 'missing'
}"
> >
<div class="c-object-label__type-icon"
:class="cssClass"
>
<span class="is-missing__indicator"
title="This item is missing"
></span>
</div>
<div class="c-object-label__name"> <div class="c-object-label__name">
{{ domainObject && domainObject.name }} {{ domainObject && domainObject.name }}
</div> </div>
@ -46,6 +57,9 @@
@click="expand" @click="expand"
></button> ></button>
</div> </div>
<div class="is-missing__indicator"
title="This item is missing"
></div>
<object-view <object-view
ref="objectView" ref="objectView"
class="c-so-view__object-view" class="c-so-view__object-view"

View File

@ -1,7 +1,10 @@
<template> <template>
<a <a
class="c-tree__item__label c-object-label" class="c-tree__item__label c-object-label"
:class="classList" :class="{
classList,
'is-missing': observedObject.status === 'missing'
}"
draggable="true" draggable="true"
:href="objectLink" :href="objectLink"
@dragstart="dragStart" @dragstart="dragStart"
@ -10,8 +13,14 @@
<div <div
class="c-tree__item__type-icon c-object-label__type-icon" class="c-tree__item__type-icon c-object-label__type-icon"
:class="typeClass" :class="typeClass"
></div> >
<div class="c-tree__item__name c-object-label__name">{{ observedObject.name }}</div> <span class="is-missing__indicator"
title="This item is missing"
></span>
</div>
<div class="c-tree__item__name c-object-label__name">
{{ observedObject.name }}
</div>
</a> </a>
</template> </template>

View File

@ -301,7 +301,7 @@ export default {
objectPath= this.currentObjectPath || this.objectPath, objectPath= this.currentObjectPath || this.objectPath,
parentObject = objectPath[1]; parentObject = objectPath[1];
return [browseObject, parentObject, this.currentObject].every(object => !object.locked); return [browseObject, parentObject, this.currentObject].every(object => object && !object.locked);
} }
} }
} }

View File

@ -2,6 +2,10 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
&.is-missing {
border: $borderMissing;
}
/*************************** HEADER */ /*************************** HEADER */
&__header { &__header {
flex: 0 0 auto; flex: 0 0 auto;
@ -39,6 +43,15 @@
> .c-so-view__local-controls { > .c-so-view__local-controls {
top: $interiorMarginSm; right: $interiorMarginSm; top: $interiorMarginSm; right: $interiorMarginSm;
} }
&.is-missing {
@include isMissing($absPos: true);
.is-missing__indicator {
top: $interiorMargin;
left: $interiorMargin;
}
}
} }
&__local-controls { &__local-controls {

View File

@ -3,23 +3,38 @@
// Used mostly in trees and lists // Used mostly in trees and lists
display: flex; display: flex;
align-items: center; align-items: center;
flex: 0 1 auto; flex: 1 1 auto;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
> * + * { margin-left: $interiorMargin; }
&__name { &__name {
@include ellipsize(); @include ellipsize();
display: inline; display: inline;
} }
&__type-icon, &__type-icon {
&:before {
// Type icon. Must be an HTML entity to allow inclusion of alias indicator. // Type icon. Must be an HTML entity to allow inclusion of alias indicator.
display: block; display: block;
flex: 0 0 auto; flex: 0 0 auto;
font-size: 1.1em; font-size: 1.1em;
opacity: 0.6; //margin-right: $interiorMargin;
margin-right: $interiorMargin; }
&.is-missing {
@include isMissing($absPos: true);
[class*='__type-icon']:before,
[class*='__type-icon']:after{
opacity: $opacityMissing;
}
.is-missing__indicator {
right: -3px;
top: -3px;
transform: scale(0.7);
}
} }
} }
@ -27,6 +42,8 @@
border-radius: $controlCr; border-radius: $controlCr;
padding: $interiorMarginSm 1px; padding: $interiorMarginSm 1px;
> * + * { margin-left: $interiorMarginSm; }
&__name { &__name {
display: inline; display: inline;
width: 100%; width: 100%;

View File

@ -1,16 +1,24 @@
<template> <template>
<div class="c-inspector__header"> <div class="c-inspector__header">
<div v-if="!multiSelect && !singleSelectNonObject" <div v-if="!multiSelect"
class="c-inspector__selected-w c-object-label" class="c-inspector__selected-w c-object-label"
:class="typeCssClass" :class="{'is-missing': domainObject.status === 'missing' }"
> >
<span class="c-inspector__selected c-object-label__name">{{ item.name }}</span> <div class="c-object-label__type-icon"
</div> :class="typeCssClass"
<div v-if="singleSelectNonObject" >
class="c-inspector__selected-w c-object-label" <span class="is-missing__indicator"
:class="typeCssClass" title="This item is missing"
> ></span>
<span class="c-inspector__selected c-object-label__name c-inspector__selected--non-domain-object">Layout Object</span> </div>
<span v-if="!singleSelectNonObject"
class="c-inspector__selected c-object-label__name"
>{{ item.name }}</span>
<span v-if="singleSelectNonObject"
class="c-inspector__selected c-object-label__name c-inspector__selected--non-domain-object"
>Layout Object</span>
</div> </div>
<div v-if="multiSelect" <div v-if="multiSelect"
class="c-inspector__multiple-selected-w" class="c-inspector__multiple-selected-w"

View File

@ -8,8 +8,18 @@
></button> ></button>
<div <div
class="l-browse-bar__object-name--w c-object-label" class="l-browse-bar__object-name--w c-object-label"
:class="[ type.cssClass, classList ]" :class="{
classList,
'is-missing': domainObject.status === 'missing'
}"
> >
<div class="c-object-label__type-icon"
:class="type.cssClass"
>
<span class="is-missing__indicator"
title="This item is missing"
></span>
</div>
<span <span
class="l-browse-bar__object-name c-object-label__name c-input-inline" class="l-browse-bar__object-name c-object-label__name c-input-inline"
contenteditable contenteditable

View File

@ -354,9 +354,9 @@
@include headerFont(1.4em); @include headerFont(1.4em);
min-width: 0; min-width: 0;
&:before { .is-missing__indicator {
// Icon right: -5px !important;
margin-right: $interiorMargin; top: -4px !important;
} }
} }

View File

@ -52,12 +52,13 @@
padding: $interiorMarginSm $interiorMargin; padding: $interiorMarginSm $interiorMargin;
transition: background 150ms ease; transition: background 150ms ease;
&__type-icon {
color: $colorItemTreeIcon;
}
&:hover { &:hover {
background: $colorItemTreeHoverBg; background: $colorItemTreeHoverBg;
filter: $filterHov;
[class*="__name"] {
color: $colorItemTreeHoverFg;
}
} }
&.is-navigated-object, &.is-navigated-object,
@ -81,12 +82,6 @@
margin-left: $interiorMarginSm; margin-left: $interiorMarginSm;
} }
&:hover {
.c-tree__item__type-icon:before {
color: $colorItemTreeIconHover;
}
}
&.is-navigated-object, &.is-navigated-object,
&.is-selected { &.is-selected {
.c-tree__item__type-icon:before { .c-tree__item__type-icon:before {
@ -115,10 +110,6 @@
color: $colorItemTreeFg; color: $colorItemTreeFg;
} }
&__type-icon {
color: $colorItemTreeIcon;
}
&.is-alias { &.is-alias {
// Object is an alias to an original. // Object is an alias to an original.
[class*='__type-icon'] { [class*='__type-icon'] {