Apply condition sets to drawing objects in a layout + Static styling for objects. (#2767)

* Hardcoded prototype - conditional styles for display layout or generator domain objects only.
Needs Architectural review

* Updates to ConditionalStylesView

* Adds background colors list

* Show conditional styles for subObjectViews and telemetryViews

* Uses telemetry provider to determine which style is active
Removes hardcoded conditionSet work used for prototype

* Fixes failing test

* Add default styles to conditionalStyles when a condition set is added to the domain object.

* Use EventEmitter alias instead of eventEmitter3 in imports
Change variable name for better readability and clarity
Remove unused code

* Change StyleRuleManager to accept conditionStyle objects instead of domainObjects

* Uses a map for conditional styles instead of a list in order to improve performance

* Use in-built api to check for identifier equality
Pass missing arguments

* Removes unnecessary object get call.

* Conditionals styling WIP

- Tweaks for layout/overflow issues;
- Better header alignment;
- Much better approach to "accordion" spacing;

* Adds conditional styles for drawing objects

* Fixes small bugs while adding or removing nested conditional styling

* Removes hard coded conditionSetIdentifier

* Fixes small conditionManager bug

* WIP - Adds condition set selection dialog

* WIP - Add condition set

* Styling for tree dialog in selector

- New `.c-selector` class;
- Markup added to tree-item.vue to fix missing `c-object-label` wrapper;

* Adds image url to styles inspector view

* Adds highlight for selected conditionSet in selection dialog.

* Conditionals Inspector styling WIP

- Simplified Inspector markup;
- Refined `.c-inspector` layout strategy;
- Refined `.l-multipane` classes for better layout and scroll handling;
- TODOs: styling for 'styles' section; unit test, find regressions, fix;

* Read-only mode changes for the styles inspector

* Adds basic styling for styles inspector view

* Removes unused code

* Displays condition set name

* Display description for conditions

* Conditionals Inspector styling WIP

- Add new ObjectName component to Inspector;
- Add supporting styles;

* Conditionals Inspector styling WIP

- Refactor for better usage of c-object-label;
- Refactor `c-properties` classes to `c-inspect-properties`;

* Conditionals Inspector styling WIP

- Introduce `c-inspect-styles` class;
- Markup refined in ConditionalStylesView.vue;

* Conditionals Inspector styling WIP

- Fix unintended regression in `c-object-label`;

* Makes inspector view tabs sticky.
Shows errors if either telemetry or conditions are missing
Refresh conditionStyles when styles inspector is loaded to show new conditions that might be added to the conditionSet

* Conditionals styling WIP

- Added title to Condition Set selector dialog;

* Conditionals styling WIP

- CSS and markup changes;

* Conditionals styling WIP

- Markup changes;

* Componentize conditional style editor, condition description and condition error

* Conditionals styling WIP

- Conditional styling elements in Inspector, significant refinements;
- Condition description formatting;
- Significant markup simplification in StyleEditor.vue;
- Moved `.c-inspect-styles` into conditional-styles.scss;

* Conditionals styling WIP

- Added menu positioning css;

* Conditionals styling WIP

- Display images in StyleEditor `c-style-thumb` element;

* Use the condition description component to show the condition description in condition set views

* Conditionals styling WIP

- New `u-alert` and `u-error` classes and mixin;
- New $colorError theme constants;

* Conditionals styling WIP

- Fixed background: cover or c-style-thumbs;

* Conditionals styling WIP

- Add navigate-or-preview functionality to attached Condition Set used
for conditional styling (thank you Deep!);
- Better theme-compliant box-shadowing on c-style-thumb;
- Added default color property to cClickIcon SCSS mixin;

* Fixes ConditionDescription and ConditionErrors views

* Allow static styles for domain Objects and display layout items

* Consolidate handling of 'none' style to the object styles mixin

* Adds visibility option to child items

* Conditionals styling WIP

- Add `is-style-invisible` class;
- Better color approach for table headers to support domain object
styling;

* Change visibility to isInvisible class

* Fixes visibility for object views and telemetry views

* Fixes selection of condition set from tree view

* Conditionals styling WIP

- Added new $glyph-icon-eye-disabled font symbol and related class;
- Modded glyphs used for visibility toggle button;
- Modded StyleEditor thumb preview to reflect visibility setting;
- Tweaked `is-style-invisible` opacity property;
- Code cleanup;

* Conditionals styling WIP

- Display disabled toolbar for Inspector styles in Browse mode;
- Better approach to 'is-style-invisible' `c-style-thumb` with new
bgCheckerboard mixin;
- Moved `$controlDisabledOpacity` into a theme constant;
- Refined spacing in Inspector grid;

* Fixes linting issues

* Fixes telemetry metadata name

* criterion descriptions is now an array of strings

* Fixes spacing

* Removes commented out code.

* Remove v-if

Co-authored-by: charlesh88 <charlesh88@gmail.com>
This commit is contained in:
Shefali Joshi 2020-03-24 13:09:21 -07:00 committed by GitHub
parent 2c1b4b4cfc
commit 57a68a24de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 1840 additions and 680 deletions

View File

@ -23,18 +23,24 @@
import EventEmitter from 'EventEmitter';
export default class StyleRuleManager extends EventEmitter {
constructor(conditionalStyleConfiguration, openmct) {
constructor(styleConfiguration, openmct, callback) {
super();
this.openmct = openmct;
if (conditionalStyleConfiguration && conditionalStyleConfiguration.conditionSetIdentifier) {
this.initialize(conditionalStyleConfiguration);
this.subscribeToConditionSet();
this.callback = callback;
if (styleConfiguration) {
this.initialize(styleConfiguration);
if (styleConfiguration.conditionSetIdentifier) {
this.subscribeToConditionSet();
} else {
this.applyStaticStyle();
}
}
}
initialize(conditionalStyleConfiguration) {
this.conditionSetIdentifier = conditionalStyleConfiguration.conditionSetIdentifier;
this.updateConditionStylesMap(conditionalStyleConfiguration.styles || []);
initialize(styleConfiguration) {
this.conditionSetIdentifier = styleConfiguration.conditionSetIdentifier;
this.staticStyle = styleConfiguration.staticStyle;
this.updateConditionStylesMap(styleConfiguration.styles || []);
}
subscribeToConditionSet() {
@ -46,13 +52,14 @@ export default class StyleRuleManager extends EventEmitter {
});
}
updateConditionalStyleConfig(conditionalStyleConfiguration) {
if (!conditionalStyleConfiguration || !conditionalStyleConfiguration.conditionSetIdentifier) {
updateObjectStyleConfig(styleConfiguration) {
if (!styleConfiguration || !styleConfiguration.conditionSetIdentifier) {
this.initialize(styleConfiguration || {});
this.destroy();
} else {
let isNewConditionSet = !this.conditionSetIdentifier ||
this.openmct.objects.areIdsEqual(this.conditionSetIdentifier, conditionalStyleConfiguration.conditionSetIdentifier);
this.initialize(conditionalStyleConfiguration);
this.openmct.objects.areIdsEqual(this.conditionSetIdentifier, styleConfiguration.conditionSetIdentifier);
this.initialize(styleConfiguration);
//Only resubscribe if the conditionSet has changed.
if (isNewConditionSet) {
this.subscribeToConditionSet();
@ -63,7 +70,11 @@ export default class StyleRuleManager extends EventEmitter {
updateConditionStylesMap(conditionStyles) {
let conditionStyleMap = {};
conditionStyles.forEach((conditionStyle) => {
conditionStyleMap[conditionStyle.conditionId] = conditionStyle.style;
if (conditionStyle.conditionId) {
conditionStyleMap[conditionStyle.conditionId] = conditionStyle.style;
} else {
conditionStyleMap.static = conditionStyle.style;
}
});
this.conditionalStyleMap = conditionStyleMap;
}
@ -74,26 +85,33 @@ export default class StyleRuleManager extends EventEmitter {
if (foundStyle !== this.currentStyle) {
this.currentStyle = foundStyle;
}
this.updateDomainObjectStyle();
} else {
if (this.currentStyle !== this.defaultStyle) {
this.currentStyle = this.defaultStyle;
}
this.applyStaticStyle();
}
this.updateDomainObjectStyle();
}
updateDomainObjectStyle() {
this.emit('conditionalStyleUpdated', this.currentStyle)
if (this.callback) {
this.callback(Object.assign({}, this.currentStyle));
}
}
applyStaticStyle() {
if (this.staticStyle) {
this.currentStyle = this.staticStyle.style;
} else {
if (this.currentStyle) {
Object.keys(this.currentStyle).forEach(key => {
this.currentStyle[key] = 'transparent';
});
}
}
this.updateDomainObjectStyle();
}
destroy() {
if (this.currentStyle) {
Object.keys(this.currentStyle).forEach(key => {
this.currentStyle[key] = 'inherit';
});
}
this.updateDomainObjectStyle();
this.applyStaticStyle();
if (this.stopProvidingTelemetry) {
this.stopProvidingTelemetry();
}

View File

@ -42,28 +42,15 @@
<span class="c-condition__name">{{ condition.configuration.name }}</span>
<!-- TODO: description should be derived from criteria -->
<span v-if="condition.isDefault"
class="c-condition__summary"
>
When all else fails
</span>
<span v-else
class="c-condition__summary"
>
<span class="c-condition__summary">
<template v-if="!canEvaluateCriteria">
Define criteria
</template>
<template v-else>
When
<span v-for="(criterion, index) in condition.configuration.criteria"
:key="index"
>
{{ getRule(criterion, index) }}
<template v-if="!isLastCriterion">
{{ getConjunction }}
</template>
</span>
</template>
<span v-else>
<condition-description :show-label="false"
:condition="condition"
/>
</span>
</span>
<div class="c-condition__buttons">
@ -179,40 +166,23 @@
Output: {{ condition.configuration.output }}
</span>
</div>
<div v-if="condition.isDefault"
class="c-condition__summary"
>
When all else fails
</div>
<div v-else
class="c-condition__summary"
>
<template v-if="!canEvaluateCriteria">
Define criteria
</template>
<template v-else>
When
<span v-for="(criterion, index) in condition.configuration.criteria"
:key="index"
>
{{ getRule(criterion, index) }}
<template v-if="!isLastCriterion">
{{ getConjunction }}
</template>
</span>
</template>
<div class="c-condition__summary">
<condition-description :show-label="false"
:condition="condition"
/>
</div>
</div>
</template>
<script>
import Criterion from './Criterion.vue';
import { OPERATIONS } from '../utils/operations';
import ConditionDescription from "./ConditionDescription.vue";
export default {
inject: ['openmct'],
components: {
Criterion
Criterion,
ConditionDescription
},
props: {
condition: {
@ -246,19 +216,17 @@ export default {
computed: {
canEvaluateCriteria: function () {
let criteria = this.condition.configuration.criteria;
let lastCriterion = criteria[criteria.length - 1];
if (lastCriterion.telemetry &&
lastCriterion.operation &&
(lastCriterion.input.length ||
lastCriterion.operation === 'isDefined' ||
lastCriterion.operation === 'isUndefined')) {
return true;
} else {
return false;
if (criteria.length) {
let lastCriterion = criteria[criteria.length - 1];
if (lastCriterion.telemetry &&
lastCriterion.operation &&
(lastCriterion.input.length ||
lastCriterion.operation === 'isDefined' ||
lastCriterion.operation === 'isUndefined')) {
return true;
}
}
},
getConjunction: function () {
return this.condition.configuration.trigger === 'all' ? 'and' : 'or';
return false;
}
},
destroyed() {
@ -268,20 +236,6 @@ export default {
this.setOutputSelection();
},
methods: {
getRule(criterion, index) {
return `${criterion.telemetry.name} ${criterion.telemetry.fieldName} ${this.findDescription(criterion.operation, criterion.input)}`;
},
isLastCriterion(index) {
return index === this.condition.configuration.criteria.length - 1;
},
findDescription(operation, values) {
for (let i=0, ii= OPERATIONS.length; i < ii; i++) {
if (operation === OPERATIONS[i].name) {
return OPERATIONS[i].getDescription(values);
}
}
return null;
},
setOutputSelection() {
let conditionOutput = this.condition.configuration.output;
if (conditionOutput) {

View File

@ -0,0 +1,123 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2020, 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-style__condition-desc">
<span v-if="showLabel && condition"
class="c-style__condition-desc__name c-condition__name"
>
{{ condition.configuration.name }}
</span>
<span v-for="(criterionDescription, index) in criterionDescriptions"
:key="criterionDescription"
class="c-style__condition-desc__text"
>
<template v-if="!index">When</template>
{{ criterionDescription }}
<template v-if="index < (criterionDescriptions.length-1)">{{ triggerDescription }}</template>
</span>
</div>
</template>
<script>
import { TRIGGER } from "@/plugins/condition/utils/constants";
import { OPERATIONS } from "@/plugins/condition/utils/operations";
export default {
name: 'ConditionDescription',
inject: [
'openmct'
],
props: {
showLabel: {
type: Boolean,
default: false
},
condition: {
type: Object,
default() {
return undefined;
}
}
},
data() {
return {
criterionDescriptions: [],
triggerDescription: ''
}
},
watch: {
condition: {
handler(val) {
this.getConditionDescription();
},
deep: true
}
},
mounted() {
this.getConditionDescription();
},
methods: {
getConditionDescription() {
if (this.condition) {
this.triggerDescription = this.condition.configuration.trigger === TRIGGER.ANY ? ' or ' : ' and ';
this.criterionDescriptions = [];
this.condition.configuration.criteria.forEach((criterion, index) => {
this.getCriterionDescription(criterion, index);
});
if (this.condition.isDefault) {
this.criterionDescriptions.splice(0, 0, 'all else fails');
}
} else {
this.criterionDescriptions = [];
}
},
getCriterionDescription(criterion, index) {
this.openmct.objects.get(criterion.telemetry).then((telemetryObject) => {
if (telemetryObject.type === 'unknown') {
let description = `Unknown ${criterion.metadata} ${this.getOperatorText(criterion.operation, criterion.input)}`;
this.criterionDescriptions.splice(index, 0, description);
} else {
let metadataValue = criterion.metadata;
if (criterion.metadata) {
this.telemetryMetadata = this.openmct.telemetry.getMetadata(telemetryObject);
const metadataObj = this.telemetryMetadata.valueMetadatas.find((metadata) => metadata.key === criterion.metadata);
if (metadataObj && metadataObj.name) {
metadataValue = metadataObj.name;
}
}
let description = `${telemetryObject.name} ${metadataValue} ${this.getOperatorText(criterion.operation, criterion.input)}`;
if (this.criterionDescriptions[index]) {
this.criterionDescriptions[index] = description;
} else {
this.criterionDescriptions.splice(index, 0, description);
}
}
});
},
getOperatorText(operationName, values) {
const found = OPERATIONS.find((operation) => operation.name === operationName);
return found ? found.getDescription(values) : '';
}
}
}
</script>

View File

@ -0,0 +1,80 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2020, 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 v-if="conditionErrors.length"
class="c-condition__errors"
>
<div v-for="(error, index) in conditionErrors"
:key="index"
class="u-alert u-alert--block u-alert--with-icon"
>{{ error.message.errorText }} {{ error.additionalInfo }}
</div>
</div>
</template>
<script>
import { ERROR } from "@/plugins/condition/utils/constants";
export default {
name: 'ConditionError',
inject: [
'openmct'
],
props: {
condition: {
type: Object,
default() {
return undefined;
}
}
},
data() {
return {
conditionErrors: []
}
},
mounted() {
this.getConditionErrors();
},
methods: {
getConditionErrors() {
if (this.condition) {
this.condition.configuration.criteria.forEach((criterion, index) => {
this.getCriterionErrors(criterion, index);
});
}
},
getCriterionErrors(criterion, index) {
this.openmct.objects.get(criterion.telemetry).then((telemetryObject) => {
if (telemetryObject.type === 'unknown') {
this.conditionErrors.push({
message: ERROR.TELEMETRY_NOT_FOUND,
additionalInfo: criterion.telemetry ? `Key: ${this.openmct.objects.makeKeyString(criterion.telemetry)}` : ''
});
}
});
}
}
}
</script>

View File

@ -163,7 +163,6 @@ export default {
if (ev) {this.clearInputs()}
if (this.criterion.telemetry) {
this.openmct.objects.get(this.criterion.telemetry).then((telemetryObject) => {
this.criterion.telemetry.name = telemetryObject.name;
this.telemetryMetadata = this.openmct.telemetry.getMetadata(telemetryObject);
this.telemetryMetadataOptions = this.telemetryMetadata.values();
this.updateOperations();
@ -175,7 +174,6 @@ export default {
},
updateOperations(ev) {
if (ev) {
this.criterion.telemetry.fieldName = ev.target.options[ev.target.selectedIndex].text;
this.clearInputs()
}
this.getOperationFormat();

View File

@ -11,6 +11,7 @@
.c-condition {
flex-direction: column;
min-width: 400px;
> * + * {
margin-top: $interiorMarginSm;
@ -24,10 +25,13 @@
/***************************** HEADER */
&__header {
$h: 22px;
display: flex;
align-items: flex-start;
align-items: start;
align-content: stretch;
overflow: hidden;
min-height: $h;
line-height: $h;
> * {
flex: 0 0 auto;
@ -36,6 +40,11 @@
}
}
}
&__drag-grippy {
transform: translateY(50%);
}
&__name {
font-weight: bold;
align-self: baseline; // Fixes bold line-height offset problem

View File

@ -0,0 +1,163 @@
<template>
<li class="c-tree__item-h">
<div
class="c-tree__item"
:class="{ 'is-alias': isAlias, 'is-navigated-object': navigated }"
@click="handleItemSelected(node.object, node)"
>
<view-control
v-model="expanded"
class="c-tree__item__view-control"
:enabled="hasChildren"
:propagate="false"
/>
<div class="c-tree__item__label c-object-label">
<div
class="c-tree__item__type-icon c-object-label__type-icon"
:class="typeClass"
></div>
<div class="c-tree__item__name c-object-label__name">{{ node.object.name }}</div>
</div>
</div>
<ul
v-if="expanded"
class="c-tree"
>
<li
v-if="isLoading && !loaded"
class="c-tree__item-h"
>
<div class="c-tree__item loading">
<span class="c-tree__item__label">Loading...</span>
</div>
</li>
<condition-set-dialog-tree-item
v-for="child in children"
:key="child.id"
:node="child"
:selected-item="selectedItem"
:handle-item-selected="handleItemSelected"
/>
</ul>
</li>
</template>
<script>
import viewControl from '@/ui/components/viewControl.vue';
export default {
name: 'ConditionSetDialogTreeItem',
inject: ['openmct'],
components: {
viewControl
},
props: {
node: {
type: Object,
required: true
},
selectedItem: {
type: Object,
default() {
return undefined;
}
},
handleItemSelected: {
type: Function,
default() {
return (item) => {};
}
}
},
data() {
return {
hasChildren: false,
isLoading: false,
loaded: false,
children: [],
expanded: false
}
},
computed: {
navigated() {
const itemId = this.selectedItem && this.selectedItem.itemId;
const isSelectedObject = itemId && this.openmct.objects.areIdsEqual(this.node.object.identifier, itemId);
if (isSelectedObject && this.node.objectPath && this.node.objectPath.length > 1) {
const isParent = this.openmct.objects.areIdsEqual(this.node.objectPath[1].identifier, this.selectedItem.parentId);
return isSelectedObject && isParent;
}
return isSelectedObject;
},
isAlias() {
let parent = this.node.objectPath[1];
if (!parent) {
return false;
}
let parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
return parentKeyString !== this.node.object.location;
},
typeClass() {
let type = this.openmct.types.get(this.node.object.type);
if (!type) {
return 'icon-object-unknown';
}
return type.definition.cssClass;
}
},
watch: {
expanded() {
if (!this.hasChildren) {
return;
}
if (!this.loaded && !this.isLoading) {
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('add', this.addChild);
this.composition.on('remove', this.removeChild);
this.composition.load().then(this.finishLoading);
this.isLoading = true;
}
}
},
mounted() {
this.domainObject = this.node.object;
let removeListener = this.openmct.objects.observe(this.domainObject, '*', (newObject) => {
this.domainObject = newObject;
});
this.$once('hook:destroyed', removeListener);
if (this.openmct.composition.get(this.node.object)) {
this.hasChildren = true;
}
},
beforeDestroy() {
this.expanded = false;
},
destroyed() {
if (this.composition) {
this.composition.off('add', this.addChild);
this.composition.off('remove', this.removeChild);
delete this.composition;
}
},
methods: {
addChild(child) {
this.children.push({
id: this.openmct.objects.makeKeyString(child.identifier),
object: child,
objectPath: [child].concat(this.node.objectPath),
navigateToParent: this.navigateToPath
});
},
removeChild(identifier) {
let removeId = this.openmct.objects.makeKeyString(identifier);
this.children = this.children
.filter(c => c.id !== removeId);
},
finishLoading() {
this.isLoading = false;
this.loaded = true;
}
}
}
</script>

View File

@ -0,0 +1,150 @@
<template>
<div class="u-contents">
<div class="c-overlay__top-bar">
<div class="c-overlay__dialog-title">Select Condition Set</div>
</div>
<div class="c-overlay__contents-main c-selector c-tree-and-search">
<div class="c-tree-and-search__search">
<search ref="shell-search"
class="c-search"
:value="searchValue"
@input="searchTree"
@clear="searchTree"
/>
</div>
<!-- loading -->
<div v-if="isLoading"
class="c-tree-and-search__loading loading"
></div>
<!-- end loading -->
<div v-if="(allTreeItems.length === 0) || (searchValue && filteredTreeItems.length === 0)"
class="c-tree-and-search__no-results"
>
No results found
</div>
<!-- main tree -->
<ul v-if="!isLoading"
v-show="!searchValue"
class="c-tree-and-search__tree c-tree"
>
<condition-set-dialog-tree-item
v-for="treeItem in allTreeItems"
:key="treeItem.id"
:node="treeItem"
:selected-item="selectedItem"
:handle-item-selected="handleItemSelection"
/>
</ul>
<!-- end main tree -->
<!-- search tree -->
<ul v-if="searchValue"
class="c-tree-and-search__tree c-tree"
>
<condition-set-dialog-tree-item
v-for="treeItem in filteredTreeItems"
:key="treeItem.id"
:node="treeItem"
:selected-item="selectedItem"
:handle-item-selected="handleItemSelection"
/>
</ul>
<!-- end search tree -->
</div>
</div>
</template>
<script>
import search from '@/ui/components/search.vue';
import ConditionSetDialogTreeItem from './ConditionSetDialogTreeItem.vue';
export default {
inject: ['openmct'],
name: 'ConditionSetSelectorDialog',
components: {
search,
ConditionSetDialogTreeItem
},
data() {
return {
expanded: false,
searchValue: '',
allTreeItems: [],
filteredTreeItems: [],
isLoading: false,
selectedItem: undefined
}
},
mounted() {
this.searchService = this.openmct.$injector.get('searchService');
this.getAllChildren();
},
methods: {
getAllChildren() {
this.isLoading = true;
this.openmct.objects.get('ROOT')
.then(root => {
return this.openmct.composition.get(root).load()
})
.then(children => {
this.isLoading = false;
this.allTreeItems = children.map(c => {
return {
id: this.openmct.objects.makeKeyString(c.identifier),
object: c,
objectPath: [c],
navigateToParent: '/browse'
};
});
});
},
getFilteredChildren() {
this.searchService.query(this.searchValue).then(children => {
this.filteredTreeItems = children.hits.map(child => {
let context = child.object.getCapability('context'),
object = child.object.useCapability('adapter'),
objectPath = [],
navigateToParent;
if (context) {
objectPath = context.getPath().slice(1)
.map(oldObject => oldObject.useCapability('adapter'))
.reverse();
navigateToParent = '/browse/' + objectPath.slice(1)
.map((parent) => this.openmct.objects.makeKeyString(parent.identifier))
.join('/');
}
return {
id: this.openmct.objects.makeKeyString(object.identifier),
object,
objectPath,
navigateToParent
}
});
});
},
searchTree(value) {
this.searchValue = value;
if (this.searchValue !== '') {
this.getFilteredChildren();
}
},
handleItemSelection(item, node) {
if (item && item.type === 'conditionSet') {
const parentId = (node.objectPath && node.objectPath.length > 1) ? node.objectPath[1].identifier : undefined;
this.selectedItem = {
itemId: item.identifier,
parentId
};
this.$emit('conditionSetSelected', item);
}
}
}
}
</script>

View File

@ -1,69 +0,0 @@
<template>
<div>
<div v-if="conditionStyle"
class="holder c-c-button-wrapper align-left"
>
<div>{{ conditionStyle.conditionName }}</div>
<span :style="conditionStyle.style">ABC</span>
<toolbar-color-picker v-if="conditionStyle.style.border"
:options="borderColorOption"
@change="updateStyleValue"
/>
<toolbar-color-picker v-if="conditionStyle.style.backgroundColor"
:options="backgroundColorOption"
@change="updateStyleValue"
/>
</div>
</div>
</template>
<script>
import ToolbarColorPicker from "@/ui/toolbar/components/toolbar-color-picker.vue";
export default {
components: {
ToolbarColorPicker
},
inject: [
'openmct'
],
props: {
conditionStyle: {
type: Object,
required: true
}
},
data() {
return {
condition: null
}
},
computed: {
borderColorOption() {
return {
icon: 'icon-line-horz',
title: 'Set border color',
value: this.conditionStyle.style.border.replace('1px solid ', ''),
property: 'border'
}
},
backgroundColorOption() {
return {
icon: 'icon-paint-bucket',
title: 'Set background color',
value: this.conditionStyle.style.backgroundColor,
property: 'backgroundColor'
}
}
},
methods: {
updateStyleValue(value, item) {
if (item.property === 'border') {
value = '1px solid ' + value;
}
this.conditionStyle.style[item.property] = value;
this.$emit('persist', this.conditionStyle)
}
}
}
</script>

View File

@ -1,43 +1,117 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2020, 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>
<div v-if="!conditionalStyles.length"
class="holder c-c-button-wrapper align-left"
>
<button
class="c-c-button c-c-button--minor add-criteria-button"
@click="addConditionSet"
>
<span class="c-c-button__label">Use conditional styling</span>
</button>
</div>
<div v-else>
<div class="holder c-c-button-wrapper align-left">
<button
class="c-c-button c-c-button--minor add-criteria-button"
@click="removeConditionSet"
<div class="c-inspector__styles c-inspect-styles">
<template v-if="!conditionSetDomainObject">
<div class="c-inspect-styles__header">
Object Style
</div>
<div class="c-inspect-styles__content">
<div v-if="staticStyle"
class="c-inspect-styles__style"
>
<span class="c-c-button__label">Remove conditional styling</span>
<style-editor class="c-inspect-styles__editor"
:style-item="staticStyle"
:is-editing="isEditing"
@persist="updateStaticStyle"
/>
</div>
<button
id="addConditionSet"
class="c-button c-button--major c-toggle-styling-button labeled"
@click="addConditionSet"
>
<span class="c-cs-button__label">Use Conditional Styling...</span>
</button>
</div>
<ul>
<li v-for="conditionStyle in conditionalStyles"
:key="conditionStyle.conditionId"
</template>
<template v-else>
<div class="c-inspect-styles__header">
Conditional Object Styles
</div>
<div class="c-inspect-styles__content c-inspect-styles__condition-set">
<a v-if="conditionSetDomainObject"
class="c-object-label icon-conditional"
:href="navigateToPath"
@click="navigateOrPreview"
>
<conditional-style :condition-style="conditionStyle"
@persist="updateConditionalStyle"
<span class="c-object-label__name">{{ conditionSetDomainObject.name }}</span>
</a>
<template v-if="isEditing">
<button
id="changeConditionSet"
class="c-button labeled"
@click="addConditionSet"
>
<span class="c-button__label">Change...</span>
</button>
<button class="c-click-icon icon-x"
title="Remove conditional styles"
@click="removeConditionSet"
></button>
</template>
</div>
<div v-if="conditionsLoaded"
class="c-inspect-styles__conditions"
>
<div v-for="(conditionStyle, index) in conditionalStyles"
:key="index"
class="c-inspect-styles__condition"
>
<condition-error :show-label="true"
:condition="getCondition(conditionStyle.conditionId)"
/>
</li>
</ul>
</div>
<condition-description :show-label="true"
:condition="getCondition(conditionStyle.conditionId)"
/>
<style-editor class="c-inspect-styles__editor"
:style-item="conditionStyle"
:is-editing="isEditing"
@persist="updateConditionalStyle"
/>
</div>
</div>
</template>
</div>
</template>
<script>
import ConditionalStyle from "./ConditionalStyle.vue";
import StyleEditor from "./StyleEditor.vue";
import ConditionSetSelectorDialog from "./ConditionSetSelectorDialog.vue";
import ConditionDescription from "@/plugins/condition/components/ConditionDescription.vue";
import ConditionError from "@/plugins/condition/components/ConditionError.vue";
import Vue from 'vue';
import PreviewAction from "@/ui/preview/PreviewAction.js";
export default {
name: 'ConditionalStylesView',
components: {
ConditionalStyle
ConditionDescription,
ConditionError,
StyleEditor
},
inject: [
'openmct',
@ -53,112 +127,204 @@ export default {
default() {
return undefined;
}
},
canHide: {
type: Boolean,
default: false
}
},
data() {
return {
conditionalStyles: []
conditionalStyles: [],
staticStyle: undefined,
conditionSetDomainObject: undefined,
isEditing: this.openmct.editor.isEditing(),
conditions: undefined,
conditionsLoaded: false,
navigateToPath: ''
}
},
destroyed() {
this.openmct.editor.off('isEditing', this.setEditState);
},
mounted() {
if (this.domainObject.configuration && this.domainObject.configuration.conditionalStyle) {
if (this.itemId) {
let conditionalStyle = this.domainObject.configuration.conditionalStyle[this.itemId];
if (conditionalStyle) {
this.conditionalStyles = conditionalStyle.styles || [];
}
} else {
this.conditionalStyles = this.domainObject.configuration.conditionalStyle.styles || [];
this.previewAction = new PreviewAction(this.openmct);
if (this.domainObject.configuration && this.domainObject.configuration.objectStyles) {
let objectStyles = this.itemId ? this.domainObject.configuration.objectStyles[this.itemId] : this.domainObject.configuration.objectStyles;
this.initializeStaticStyle(objectStyles);
if (objectStyles && objectStyles.conditionSetIdentifier) {
this.openmct.objects.get(objectStyles.conditionSetIdentifier).then(this.initialize);
this.conditionalStyles = objectStyles.styles;
}
} else {
this.initializeStaticStyle();
}
this.openmct.editor.on('isEditing', this.setEditState);
},
methods: {
addConditionSet() {
//TODO: this.conditionSetIdentifier will be set by the UI before calling this
this.conditionSetIdentifier = {
namespace: '',
key: "81088c8a-4b80-41fe-9d07-fda8b22d6f5f"
};
initialize(conditionSetDomainObject) {
//If there are new conditions in the conditionSet we need to set those styles to default
this.conditionSetDomainObject = conditionSetDomainObject;
this.enableConditionSetNav();
this.initializeConditionalStyles();
},
setEditState(isEditing) {
this.isEditing = isEditing;
},
addConditionSet() {
let conditionSetDomainObject;
const handleItemSelection = (item) => {
if (item) {
conditionSetDomainObject = item;
}
};
const dismissDialog = (overlay, initialize) => {
overlay.dismiss();
if (initialize && conditionSetDomainObject) {
this.conditionSetDomainObject = conditionSetDomainObject;
this.conditionalStyles = [];
this.initializeConditionalStyles();
}
};
let vm = new Vue({
provide: {
openmct: this.openmct
},
components: {ConditionSetSelectorDialog},
data() {
return {
handleItemSelection
}
},
template: '<condition-set-selector-dialog @conditionSetSelected="handleItemSelection"></condition-set-selector-dialog>'
}).$mount();
let overlay = this.openmct.overlays.overlay({
element: vm.$el,
size: 'small',
buttons: [
{
label: 'OK',
emphasis: 'true',
callback: () => dismissDialog(overlay, true)
},
{
label: 'Cancel',
callback: () => dismissDialog(overlay, false)
}
],
onDestroy: () => vm.$destroy()
});
},
enableConditionSetNav() {
this.openmct.objects.getOriginalPath(this.conditionSetDomainObject.identifier).then(
(objectPath) => {
this.objectPath = objectPath;
this.navigateToPath = '#/browse/' + this.objectPath
.map(o => o && this.openmct.objects.makeKeyString(o.identifier))
.reverse()
.join('/');
}
);
},
navigateOrPreview(event) {
// If editing, display condition set in Preview overlay; otherwise nav to it while browsing
if (this.openmct.editor.isEditing()) {
event.preventDefault();
this.previewAction.invoke(this.objectPath);
}
},
removeConditionSet() {
//TODO: Handle the case where domainObject has items with styles but we're trying to remove the styles on the domainObject itself
this.conditionSetIdentifier = '';
this.conditionSetDomainObject = undefined;
this.conditionalStyles = [];
let domainObjectConditionalStyle = (this.domainObject.configuration && this.domainObject.configuration.conditionalStyle) || {};
if (domainObjectConditionalStyle) {
if (this.itemId) {
domainObjectConditionalStyle[this.itemId] = undefined;
delete domainObjectConditionalStyle[this.itemId];
} else {
domainObjectConditionalStyle.conditionSetIdentifier = undefined;
delete domainObjectConditionalStyle.conditionSetIdentifier;
domainObjectConditionalStyle.styles = undefined;
delete domainObjectConditionalStyle.styles;
}
if (_.isEmpty(domainObjectConditionalStyle)) {
domainObjectConditionalStyle = undefined;
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
if (this.itemId) {
domainObjectStyles[this.itemId].conditionSetIdentifier = undefined;
delete domainObjectStyles[this.itemId].conditionSetIdentifier;
domainObjectStyles[this.itemId].styles = undefined;
delete domainObjectStyles[this.itemId].styles;
if (_.isEmpty(domainObjectStyles[this.itemId])) {
delete domainObjectStyles[this.itemId];
}
} else {
domainObjectStyles.conditionSetIdentifier = undefined;
delete domainObjectStyles.conditionSetIdentifier;
domainObjectStyles.styles = undefined;
delete domainObjectStyles.styles;
}
if (_.isEmpty(domainObjectStyles)) {
domainObjectStyles = undefined;
}
this.persist(domainObjectConditionalStyle);
this.persist(domainObjectStyles);
},
initializeConditionalStyles() {
this.openmct.objects.get(this.conditionSetIdentifier).then((conditionSetDomainObject) => {
conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
this.conditionalStyles.push({
conditionId: conditionConfiguration.id,
conditionName: conditionConfiguration.name,
style: Object.assign({}, this.initialStyles)
});
});
let domainObjectConditionalStyle = (this.domainObject.configuration && this.domainObject.configuration.conditionalStyle) || {};
let conditionalStyle = {
conditionSetIdentifier: this.conditionSetIdentifier,
styles: this.conditionalStyles
};
if (this.itemId) {
this.persist({
...domainObjectConditionalStyle,
[this.itemId]: conditionalStyle
});
if (!this.conditions) {
this.conditions = {};
}
this.conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
this.conditions[conditionConfiguration.id] = conditionConfiguration;
let foundStyle = this.findStyleByConditionId(conditionConfiguration.id);
if (foundStyle) {
foundStyle.style = Object.assign((this.canHide ? { isStyleInvisible: '' } : {}), this.initialStyles, foundStyle.style);
} else {
this.persist({
...domainObjectConditionalStyle,
...conditionalStyle
this.conditionalStyles.splice(index, 0, {
conditionId: conditionConfiguration.id,
style: Object.assign((this.canHide ? { isStyleInvisible: '' } : {}), this.initialStyles)
});
}
});
this.conditionsLoaded = true;
this.persist(this.getDomainObjectConditionalStyle());
},
initializeStaticStyle(objectStyles) {
let staticStyle = objectStyles && objectStyles.staticStyle;
this.staticStyle = staticStyle || {
style: Object.assign({}, this.initialStyles)
};
},
findStyleByConditionId(id) {
return this.conditionalStyles.find(conditionalStyle => conditionalStyle.conditionId === id);
},
updateStaticStyle(staticStyle) {
this.staticStyle = staticStyle;
this.persist(this.getDomainObjectConditionalStyle());
},
updateConditionalStyle(conditionStyle) {
let found = this.findStyleByConditionId(conditionStyle.conditionId);
if (found) {
found.style = conditionStyle.style;
let domainObjectConditionalStyle = this.domainObject.configuration.conditionalStyle || {};
if (this.itemId) {
let itemConditionalStyle = domainObjectConditionalStyle[this.itemId];
if (itemConditionalStyle) {
this.persist({
...domainObjectConditionalStyle,
[this.itemId]: {
...itemConditionalStyle,
styles: this.conditionalStyles
}
});
}
} else {
domainObjectConditionalStyle.styles = this.conditionalStyles;
this.persist(domainObjectConditionalStyle);
}
this.persist(this.getDomainObjectConditionalStyle());
}
},
persist(conditionalStyle) {
this.openmct.objects.mutate(this.domainObject, 'configuration.conditionalStyle', conditionalStyle);
getDomainObjectConditionalStyle() {
let objectStyle = {
styles: this.conditionalStyles,
staticStyle: this.staticStyle
};
if (this.conditionSetDomainObject) {
objectStyle.conditionSetIdentifier = this.conditionSetDomainObject.identifier;
}
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
if (this.itemId) {
domainObjectStyles[this.itemId] = objectStyle;
} else {
//we're deconstructing here to ensure that if an item within a domainObject already had a style we don't lose it
domainObjectStyles = {
...domainObjectStyles,
...objectStyle
}
}
return domainObjectStyles;
},
getCondition(id) {
return this.conditions ? this.conditions[id] : {};
},
persist(style) {
this.openmct.objects.mutate(this.domainObject, 'configuration.objectStyles', style);
}
}
}

View File

@ -0,0 +1,179 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2020, 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-style">
<span class="c-style-thumb"
:class="{ 'is-style-invisible': styleItem.style.isStyleInvisible }"
:style="[styleItem.style.imageUrl ? { backgroundImage:'url(' + styleItem.style.imageUrl + ')'} : styleItem.style ]"
>
<span class="c-style-thumb__text"
:class="{ 'hide-nice': !styleItem.style.color }"
>
ABC
</span>
</span>
<span class="c-toolbar">
<toolbar-color-picker v-if="styleItem.style.border"
class="c-style__toolbar-button--border-color u-menu-to--center"
:options="borderColorOption"
@change="updateStyleValue"
/>
<toolbar-color-picker v-if="styleItem.style.backgroundColor"
class="c-style__toolbar-button--background-color u-menu-to--center"
:options="backgroundColorOption"
@change="updateStyleValue"
/>
<toolbar-color-picker v-if="styleItem.style.color"
class="c-style__toolbar-button--color u-menu-to--center"
:options="colorOption"
@change="updateStyleValue"
/>
<toolbar-button v-if="styleItem.style.imageUrl !== undefined"
class="c-style__toolbar-button--image-url"
:options="imageUrlOption"
@change="updateStyleValue"
/>
<toolbar-toggle-button v-if="styleItem.style.isStyleInvisible !== undefined"
class="c-style__toolbar-button--toggle-visible"
:options="isStyleInvisibleOption"
@change="updateStyleValue"
/>
</span>
</div>
</template>
<script>
import ToolbarColorPicker from "@/ui/toolbar/components/toolbar-color-picker.vue";
import ToolbarButton from "@/ui/toolbar/components/toolbar-button.vue";
import ToolbarToggleButton from "@/ui/toolbar/components/toolbar-toggle-button.vue";
import {STYLE_CONSTANTS} from "@/plugins/condition/utils/constants";
export default {
name: 'StyleEditor',
components: {
ToolbarButton,
ToolbarColorPicker,
ToolbarToggleButton
},
inject: [
'openmct'
],
props: {
isEditing: {
type: Boolean
},
styleItem: {
type: Object,
required: true
}
},
computed: {
borderColorOption() {
return {
icon: 'icon-line-horz',
title: STYLE_CONSTANTS.borderColorTitle,
value: this.styleItem.style.border.replace('1px solid ', ''),
property: 'border',
isEditing: this.isEditing
}
},
backgroundColorOption() {
return {
icon: 'icon-paint-bucket',
title: STYLE_CONSTANTS.backgroundColorTitle,
value: this.styleItem.style.backgroundColor,
property: 'backgroundColor',
isEditing: this.isEditing
}
},
colorOption() {
return {
icon: 'icon-font',
title: STYLE_CONSTANTS.textColorTitle,
value: this.styleItem.style.color,
property: 'color',
isEditing: this.isEditing
}
},
imageUrlOption() {
return {
icon: 'icon-image',
title: STYLE_CONSTANTS.imagePropertiesTitle,
dialog: {
name: "Image Properties",
sections: [
{
rows: [
{
key: "url",
control: "textfield",
name: "Image URL",
"cssClass": "l-input-lg"
}
]
}
]
},
property: 'imageUrl',
formKeys: ['url'],
value: {url: this.styleItem.style.imageUrl},
isEditing: this.isEditing
}
},
isStyleInvisibleOption() {
return {
value: this.styleItem.style.isStyleInvisible,
property: 'isStyleInvisible',
isEditing: this.isEditing,
options: [
{
value: '',
icon: 'icon-eye-disabled',
title: STYLE_CONSTANTS.visibilityHidden
},
{
value: STYLE_CONSTANTS.isStyleInvisible,
icon: 'icon-eye-open',
title: STYLE_CONSTANTS.visibilityVisible
}
]
}
}
},
methods: {
updateStyleValue(value, item) {
if (item.property === 'border') {
value = '1px solid ' + value;
}
if (value && (value.url !== undefined)) {
this.styleItem.style[item.property] = value.url;
} else {
this.styleItem.style[item.property] = value;
}
this.$emit('persist', this.styleItem);
}
}
}
</script>

View File

@ -0,0 +1,100 @@
/********************************************* INSPECTOR STYLES TAB */
.c-inspect-styles {
> * + * {
margin-top: $interiorMargin;
}
&__content,
&__conditions,
&__condition {
> * + * {
margin-top: $interiorMargin;
}
}
&__content {
display: flex;
flex-direction: column;
}
&__condition-set {
display: flex;
flex-direction: row;
align-items: center;
.c-object-label {
flex: 1 1 auto;
}
.c-button {
flex: 0 0 auto;
}
}
&__style,
&__condition {
padding: $interiorMargin;
}
&__condition {
@include discreteItem();
}
.c-style {
padding: 2px; // Allow a bit of room for thumb box-shadow
&__condition-desc {
@include ellipsize();
}
}
}
.c-inspect-styles__style {
.is-editing & {
border-bottom: 1px solid $colorInteriorBorder;
}
}
.l-shell:not(.is-editing) .c-inspect-styles {
.c-toolbar {
// Disabled-look toolbar when not editing
pointer-events: none;
cursor: inherit;
// Hide control buttons, like image URL
[class*='--image-url'] {
display: none;
}
// Make buttons look disabled by knocking back icon, not swatch element
.c-icon-button {
&:before {
opacity: $controlDisabledOpacity;
}
}
}
}
.c-toggle-styling-button {
display: none;
.is-editing & {
display: block;
align-self: flex-end;
}
}
.is-style-invisible {
display: none !important;
.is-editing & {
display: block !important;
opacity: 0.2;
}
&.c-style-thumb {
display: block !important;
@include bgCheckerboard($size: 10px, $imp: true);
opacity: 1;
}
}

View File

@ -2,3 +2,22 @@ export const TRIGGER = {
ANY: 'any',
ALL: 'all'
};
export const STYLE_CONSTANTS = {
isStyleInvisible: 'is-style-invisible',
borderColorTitle: 'Set border color',
textColorTitle: 'Set text color',
backgroundColorTitle: 'Set background color',
imagePropertiesTitle: 'Edit image properties',
visibilityHidden: 'Hidden',
visibilityVisible: 'Visible'
};
export const ERROR = {
'TELEMETRY_NOT_FOUND': {
errorText: 'Telemetry not found for criterion'
},
'CONDITION_NOT_FOUND': {
errorText: 'Condition not found'
}
};

View File

@ -8,7 +8,7 @@ export const OPERATIONS = [
appliesTo: ['number'],
inputCount: 1,
getDescription: function (values) {
return ' is ' + values[0];
return ' is ' + values.join(', ');
}
},
{
@ -20,7 +20,7 @@ export const OPERATIONS = [
appliesTo: ['number'],
inputCount: 1,
getDescription: function (values) {
return ' is not ' + values[0];
return ' is not ' + values.join(', ');
}
},
{
@ -32,7 +32,7 @@ export const OPERATIONS = [
appliesTo: ['number'],
inputCount: 1,
getDescription: function (values) {
return ' > ' + values[0];
return ' > ' + values.join(', ');
}
},
{
@ -44,7 +44,7 @@ export const OPERATIONS = [
appliesTo: ['number'],
inputCount: 1,
getDescription: function (values) {
return ' < ' + values[0];
return ' < ' + values.join(', ');
}
},
{
@ -56,7 +56,7 @@ export const OPERATIONS = [
appliesTo: ['number'],
inputCount: 1,
getDescription: function (values) {
return ' >= ' + values[0];
return ' >= ' + values.join(', ');
}
},
{
@ -68,7 +68,7 @@ export const OPERATIONS = [
appliesTo: ['number'],
inputCount: 1,
getDescription: function (values) {
return ' <= ' + values[0];
return ' <= ' + values.join(', ');
}
},
{
@ -80,7 +80,7 @@ export const OPERATIONS = [
appliesTo: ['number'],
inputCount: 2,
getDescription: function (values) {
return ' is between ' + values[0] + ' and ' + values[1];
return ' is between ' + values.join(', ') + ' and ' + values[1];
}
},
{
@ -92,7 +92,7 @@ export const OPERATIONS = [
appliesTo: ['number'],
inputCount: 2,
getDescription: function (values) {
return ' is not between ' + values[0] + ' and ' + values[1];
return ' is not between ' + values.join(', ') + ' and ' + values[1];
}
},
{
@ -104,7 +104,7 @@ export const OPERATIONS = [
appliesTo: ['string'],
inputCount: 1,
getDescription: function (values) {
return ' contains ' + values[0];
return ' contains ' + values.join(', ');
}
},
{
@ -116,7 +116,7 @@ export const OPERATIONS = [
appliesTo: ['string'],
inputCount: 1,
getDescription: function (values) {
return ' does not contain ' + values[0];
return ' does not contain ' + values.join(', ');
}
},
{
@ -128,7 +128,7 @@ export const OPERATIONS = [
appliesTo: ['string'],
inputCount: 1,
getDescription: function (values) {
return ' starts with ' + values[0];
return ' starts with ' + values.join(', ');
}
},
{
@ -140,7 +140,7 @@ export const OPERATIONS = [
appliesTo: ['string'],
inputCount: 1,
getDescription: function (values) {
return ' ends with ' + values[0];
return ' ends with ' + values.join(', ');
}
},
{
@ -152,7 +152,7 @@ export const OPERATIONS = [
appliesTo: ['string'],
inputCount: 1,
getDescription: function (values) {
return ' is exactly ' + values[0];
return ' is exactly ' + values.join(', ');
}
},
{
@ -188,7 +188,7 @@ export const OPERATIONS = [
appliesTo: ['enum'],
inputCount: 1,
getDescription: function (values) {
return ' is ' + values[0];
return ' is ' + values.join(', ');
}
},
{
@ -200,7 +200,7 @@ export const OPERATIONS = [
appliesTo: ['enum'],
inputCount: 1,
getDescription: function (values) {
return ' is not ' + values[0];
return ' is not ' + values.join(', ');
}
}
];

View File

@ -2,15 +2,19 @@ export const getStyleProp = (key, defaultValue) => {
let styleProp = undefined;
switch(key) {
case 'fill': styleProp = {
backgroundColor: defaultValue || 'none'
backgroundColor: defaultValue || 'transparent'
};
break;
case 'stroke': styleProp = {
border: '1px solid ' + defaultValue || 'none'
border: '1px solid ' + (defaultValue || 'transparent')
};
break;
case 'color': styleProp = {
color: defaultValue || 'inherit'
color: defaultValue || 'transparent'
};
break;
case 'url': styleProp = {
imageUrl: defaultValue || 'transparent'
};
break;
}

View File

@ -23,20 +23,20 @@
<template>
<div
v-if="isEditing"
class="c-properties"
class="c-inspect-properties"
>
<div class="c-properties__header">
<div class="c-inspect-properties__header">
Alphanumeric Format
</div>
<ul class="c-properties__section">
<li class="c-properties__row">
<ul class="c-inspect-properties__section">
<li class="c-inspect-properties__row">
<div
class="c-properties__label"
class="c-inspect-properties__label"
title="Printf formatting for the selected telemetry"
>
<label for="telemetryPrintfFormat">Format</label>
</div>
<div class="c-properties__value">
<div class="c-inspect-properties__value">
<input
id="telemetryPrintfFormat"
type="text"

View File

@ -29,6 +29,7 @@
>
<div
class="c-box-view"
:class="[styleClass]"
:style="style"
></div>
</layout-frame>
@ -36,7 +37,7 @@
<script>
import LayoutFrame from './LayoutFrame.vue'
import conditionalStylesMixin from '../mixins/conditionalStyles-mixin';
import conditionalStylesMixin from '../mixins/objectlStyles-mixin';
export default {
makeDefinition() {
@ -73,14 +74,13 @@ export default {
},
computed: {
style() {
if (this.itemStyle) {
return this.itemStyle;
} else {
return {
backgroundColor: this.item.fill,
border: '1px solid ' + this.item.stroke
};
}
return Object.assign({
backgroundColor: this.item.fill,
border: '1px solid ' + this.item.stroke
}, this.itemStyle);
},
styleClass() {
return this.itemStyle && this.itemStyle.isStyleInvisible;
}
},
watch: {

View File

@ -29,6 +29,7 @@
>
<div
class="c-image-view"
:class="[styleClass]"
:style="style"
></div>
</layout-frame>
@ -36,7 +37,7 @@
<script>
import LayoutFrame from './LayoutFrame.vue'
import conditionalStylesMixin from "../mixins/conditionalStyles-mixin";
import conditionalStylesMixin from "../mixins/objectlStyles-mixin";
export default {
makeDefinition(openmct, gridSize, element) {
@ -74,9 +75,12 @@ export default {
computed: {
style() {
return {
backgroundImage: 'url(' + this.item.url + ')',
border: this.itemStyle ? this.itemStyle.border : '1px solid ' + this.item.stroke
}
backgroundImage: this.itemStyle ? ('url(' + this.itemStyle.imageUrl + ')') : 'url(' + this.item.url + ')',
border: (this.itemStyle && this.itemStyle.border) ? this.itemStyle.border : ('1px solid ' + this.item.stroke)
};
},
styleClass() {
return this.itemStyle && this.itemStyle.isStyleInvisible;
}
},
watch: {

View File

@ -23,6 +23,7 @@
<template>
<div
class="l-layout__frame c-frame no-frame"
:class="[styleClass]"
:style="style"
>
<svg
@ -60,7 +61,7 @@
<script>
import conditionalStylesMixin from "../mixins/conditionalStyles-mixin";
import conditionalStylesMixin from "../mixins/objectlStyles-mixin";
const START_HANDLE_QUADRANTS = {
1: 'c-frame-edit__handle--sw',
@ -145,6 +146,9 @@ export default {
height: `${height}px`
};
},
styleClass() {
return this.itemStyle && this.itemStyle.isStyleInvisible;
},
startHandleClass() {
return START_HANDLE_QUADRANTS[this.vectorQuadrant];
},

View File

@ -36,7 +36,8 @@
<div
v-if="showLabel"
class="c-telemetry-view__label"
:style="conditionalStyle"
:class="[styleClass]"
:style="objectStyle"
>
<div class="c-telemetry-view__label-text">
{{ domainObject.name }}
@ -47,8 +48,8 @@
v-if="showValue"
:title="fieldName"
class="c-telemetry-view__value"
:class="[telemetryClass]"
:style="!telemetryClass && conditionalStyle"
:class="[telemetryClass, !telemetryClass && styleClass]"
:style="!telemetryClass && objectStyle"
>
<div class="c-telemetry-view__value-text">
{{ telemetryValue }}
@ -113,7 +114,7 @@ export default {
formats: undefined,
domainObject: undefined,
currentObjectPath: undefined,
conditionalStyle: ''
objectStyle: ''
}
},
computed: {
@ -133,6 +134,9 @@ export default {
fontSize: this.item.size
}
},
styleClass() {
return this.objectStyle && this.objectStyle.isStyleInvisible;
},
fieldName() {
return this.valueMetadata && this.valueMetadata.name;
},
@ -192,7 +196,6 @@ export default {
if (this.styleRuleManager) {
this.styleRuleManager.destroy();
this.styleRuleManager.off('conditionalStyleUpdated', this.updateStyle.bind(this));
delete this.styleRuleManager;
}
@ -238,7 +241,7 @@ export default {
},
setObject(domainObject) {
this.domainObject = domainObject;
this.initConditionalStyles();
this.initObjectStyles();
this.keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
this.limitEvaluator = this.openmct.telemetry.limitEvaluator(this.domainObject);
@ -264,20 +267,27 @@ export default {
showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
},
initConditionalStyles() {
this.styleRuleManager = new StyleRuleManager(this.domainObject.configuration.conditionalStyle, this.openmct);
this.styleRuleManager.on('conditionalStyleUpdated', this.updateStyle.bind(this));
initObjectStyles() {
this.styleRuleManager = new StyleRuleManager(this.domainObject.configuration.objectStyles, this.openmct, this.updateStyle.bind(this));
if (this.unlistenStyles) {
this.unlistenStyles();
}
this.unlistenStyles = this.openmct.objects.observe(this.domainObject, 'configuration.conditionalStyle', (newConditionalStyle) => {
//Updating conditional styles in the inspector view will trigger this so that the changes are reflected immediately
this.styleRuleManager.updateConditionalStyleConfig(newConditionalStyle);
this.unlistenStyles = this.openmct.objects.observe(this.domainObject, 'configuration.objectStyles', (newObjectStyle) => {
//Updating object styles in the inspector view will trigger this so that the changes are reflected immediately
this.styleRuleManager.updateObjectStyleConfig(newObjectStyle);
});
},
updateStyle(styleObj) {
this.conditionalStyle = styleObj;
let keys = Object.keys(styleObj);
keys.forEach(key => {
if ((typeof styleObj[key] === 'string') && (styleObj[key].indexOf('transparent') > -1)) {
if (styleObj[key]) {
styleObj[key] = '';
}
}
});
this.objectStyle = styleObj;
}
}
}

View File

@ -29,6 +29,7 @@
>
<div
class="c-text-view"
:class="[styleClass]"
:style="style"
>
{{ item.text }}
@ -38,7 +39,7 @@
<script>
import LayoutFrame from './LayoutFrame.vue'
import conditionalStylesMixin from "../mixins/conditionalStyles-mixin";
import conditionalStylesMixin from "../mixins/objectlStyles-mixin";
export default {
makeDefinition(openmct, gridSize, element) {
@ -78,16 +79,15 @@ export default {
},
computed: {
style() {
if (this.itemStyle) {
return this.itemStyle;
} else {
return {
backgroundColor: this.item.fill,
borderColor: this.item.stroke,
color: this.item.color,
fontSize: this.item.size
};
}
return Object.assign({
backgroundColor: this.item.fill,
border: '1px solid ' + this.item.stroke,
color: this.item.color,
fontSize: this.item.size
}, this.itemStyle);
},
styleClass() {
return this.itemStyle && this.itemStyle.isStyleInvisible;
}
},
watch: {

View File

@ -1,54 +0,0 @@
import StyleRuleManager from "@/plugins/condition/StyleRuleManager";
export default {
inject: ['openmct'],
data() {
return {
itemStyle: this.itemStyle
}
},
mounted() {
this.domainObject = this.$parent.domainObject;
this.itemId = this.item.id;
this.conditionalStyle = this.getConditionalStyleForItem(this.domainObject.configuration.conditionalStyle);
this.initConditionalStyles();
},
destroyed() {
if (this.stopListeningConditionalStyles) {
this.stopListeningConditionalStyles();
}
},
methods: {
getConditionalStyleForItem(conditionalStyle) {
if (conditionalStyle) {
return conditionalStyle[this.itemId];
} else {
return undefined;
}
},
initConditionalStyles() {
if (!this.styleRuleManager) {
this.styleRuleManager = new StyleRuleManager(this.conditionalStyle, this.openmct);
this.styleRuleManager.on('conditionalStyleUpdated', this.updateStyle.bind(this));
} else {
this.styleRuleManager.updateConditionalStyleConfig(this.conditionalStyle);
}
if (this.stopListeningConditionalStyles) {
this.stopListeningConditionalStyles();
}
this.stopListeningConditionalStyles = this.openmct.objects.observe(this.domainObject, 'configuration.conditionalStyle', (newConditionalStyle) => {
//Updating conditional styles in the inspector view will trigger this so that the changes are reflected immediately
let newItemConditionalStyle = this.getConditionalStyleForItem(newConditionalStyle);
if (this.conditionalStyle !== newItemConditionalStyle) {
this.conditionalStyle = newItemConditionalStyle;
this.styleRuleManager.updateConditionalStyleConfig(this.conditionalStyle);
}
});
},
updateStyle(style) {
this.itemStyle = style;
}
}
};

View File

@ -0,0 +1,59 @@
import StyleRuleManager from "@/plugins/condition/StyleRuleManager";
export default {
inject: ['openmct'],
data() {
return {
itemStyle: this.itemStyle
}
},
mounted() {
this.domainObject = this.$parent.domainObject;
this.itemId = this.item.id;
this.objectStyle = this.getObjectStyleForItem(this.domainObject.configuration.objectStyles);
this.initObjectStyles();
},
destroyed() {
if (this.stopListeningObjectStyles) {
this.stopListeningObjectStyles();
}
},
methods: {
getObjectStyleForItem(objectStyle) {
if (objectStyle) {
return objectStyle[this.itemId] ? Object.assign({}, objectStyle[this.itemId]) : undefined;
} else {
return undefined;
}
},
initObjectStyles() {
if (!this.styleRuleManager) {
this.styleRuleManager = new StyleRuleManager(this.objectStyle, this.openmct, this.updateStyle.bind(this));
} else {
this.styleRuleManager.updateObjectStyleConfig(this.objectStyle);
}
if (this.stopListeningObjectStyles) {
this.stopListeningObjectStyles();
}
this.stopListeningObjectStyles = this.openmct.objects.observe(this.domainObject, 'configuration.objectStyles', (newObjectStyle) => {
//Updating object styles in the inspector view will trigger this so that the changes are reflected immediately
let newItemObjectStyle = this.getObjectStyleForItem(newObjectStyle);
if (this.objectStyle !== newItemObjectStyle) {
this.objectStyle = newItemObjectStyle;
this.styleRuleManager.updateObjectStyleConfig(this.objectStyle);
}
});
},
updateStyle(style) {
this.itemStyle = style;
let keys = Object.keys(this.itemStyle);
keys.forEach((key) => {
if ((typeof this.itemStyle[key] === 'string') && (this.itemStyle[key].indexOf('transparent') > -1)) {
delete this.itemStyle[key];
}
});
}
}
};

View File

@ -1,17 +1,17 @@
<template>
<div class="c-properties__section c-filter-settings">
<div class="c-inspect-properties__section c-filter-settings">
<li
v-for="(filter, index) in filterField.filters"
:key="index"
class="c-properties__row c-filter-settings__setting"
class="c-inspect-properties__row c-filter-settings__setting"
>
<div
class="c-properties__label label"
class="c-inspect-properties__label label"
:disabled="useGlobal"
>
{{ filterField.name }} =
</div>
<div class="c-properties__value value">
<div class="c-inspect-properties__value value">
<!-- EDITING -->
<!-- String input, editing -->
<template v-if="!filter.possibleValues && isEditing">

View File

@ -26,17 +26,17 @@
</div>
<div v-if="expanded">
<ul class="c-properties">
<ul class="c-inspect-properties">
<div
v-if="!isEditing && persistedFilters.useGlobal"
class="c-properties__label span-all"
class="c-inspect-properties__label span-all"
>
Uses global filter
</div>
<div
v-if="isEditing"
class="c-properties__label span-all"
class="c-inspect-properties__label span-all"
>
<toggle-switch
:id="keyString"

View File

@ -23,7 +23,7 @@
</div>
<ul
v-if="expanded"
class="c-properties"
class="c-inspect-properties"
>
<filter-field
v-for="metadatum in globalMetadata"

View File

@ -7,7 +7,7 @@
}
.c-filter-tree {
// Filters UI uses a tree-based structure
.c-properties {
.c-inspect-properties {
// Add extra margin to account for filter-indicator
margin-left: 38px;
}

View File

@ -1,18 +1,18 @@
<template>
<div class="c-properties">
<div class="c-inspect-properties">
<template v-if="isEditing">
<div class="c-properties__header">
<div class="c-inspect-properties__header">
Table Column Size
</div>
<ul class="c-properties__section">
<li class="c-properties__row">
<ul class="c-inspect-properties__section">
<li class="c-inspect-properties__row">
<div
class="c-properties__label"
class="c-inspect-properties__label"
title="Auto-size table"
>
<label for="AutoSizeControl">Auto-size</label>
</div>
<div class="c-properties__value">
<div class="c-inspect-properties__value">
<input
id="AutoSizeControl"
type="checkbox"
@ -22,22 +22,22 @@
</div>
</li>
</ul>
<div class="c-properties__header">
<div class="c-inspect-properties__header">
Table Column Visibility
</div>
<ul class="c-properties__section">
<ul class="c-inspect-properties__section">
<li
v-for="(title, key) in headers"
:key="key"
class="c-properties__row"
class="c-inspect-properties__row"
>
<div
class="c-properties__label"
class="c-inspect-properties__label"
title="Show or hide column"
>
<label :for="key + 'ColumnControl'">{{ title }}</label>
</div>
<div class="c-properties__value">
<div class="c-inspect-properties__value">
<input
:id="key + 'ColumnControl'"
type="checkbox"

View File

@ -100,10 +100,12 @@ $colorStatusErrorFilter: invert(10%) sepia(96%) saturate(4360%) hue-rotate(351de
$colorStatusBtnBg: #666; // Where is this used?
$colorStatusPartialBg: #3f5e8b;
$colorStatusCompleteBg: #457638;
$colorAlert: #ff3c00;
$colorAlert: #ff8a0d;
$colorAlertFg: #fff;
$colorWarningHi: #ff0000;
$colorWarningHiFg: #ffdad0;
$colorError: #ff3c00;
$colorErrorFg: #fff;
$colorWarningHi: #990000;
$colorWarningHiFg: #FF9594;
$colorWarningLo: #ff9900;
$colorWarningLoFg: #523400;
$colorDiagnostic: #a4b442;
@ -215,6 +217,7 @@ $colorSelectBg: $colorBtnBg; // This must be a solid color, not a gradient, due
$colorSelectFg: $colorBtnFg;
$colorSelectArw: lighten($colorBtnBg, 20%);
$shdwSelect: rgba(black, 0.5) 0 0.5px 3px;
$controlDisabledOpacity: 0.2;
// Menus
$colorMenuBg: pullForward($colorBodyBg, 15%);
@ -320,7 +323,7 @@ $shdwItemText: none;
$colorTabBorder: pullForward($colorBodyBg, 10%);
$colorTabBodyBg: $colorBodyBg;
$colorTabBodyFg: pullForward($colorBodyFg, 20%);
$colorTabHeaderBg: pullForward($colorBodyBg, 10%);
$colorTabHeaderBg: rgba($colorBodyFg, 0.2);
$colorTabHeaderFg: $colorBodyFg;
$colorTabHeaderBorder: $colorBodyBg;
$colorTabGroupHeaderBg: pullForward($colorBodyBg, 5%);

View File

@ -104,10 +104,12 @@ $colorStatusErrorFilter: invert(10%) sepia(96%) saturate(4360%) hue-rotate(351de
$colorStatusBtnBg: #666; // Where is this used?
$colorStatusPartialBg: #3f5e8b;
$colorStatusCompleteBg: #457638;
$colorAlert: #ff3c00;
$colorAlert: #ff8a0d;
$colorAlertFg: #fff;
$colorWarningHi: #ff0000;
$colorWarningHiFg: #ffdad0;
$colorError: #ff3c00;
$colorErrorFg: #fff;
$colorWarningHi: #990000;
$colorWarningHiFg: #FF9594;
$colorWarningLo: #ff9900;
$colorWarningLoFg: #523400;
$colorDiagnostic: #a4b442;
@ -219,6 +221,7 @@ $colorSelectBg: $colorBtnBg; // This must be a solid color, not a gradient, due
$colorSelectFg: $colorBtnFg;
$colorSelectArw: lighten($colorBtnBg, 20%);
$shdwSelect: rgba(black, 0.5) 0 0.5px 3px;
$controlDisabledOpacity: 0.2;
// Menus
$colorMenuBg: pullForward($colorBodyBg, 15%);
@ -324,7 +327,7 @@ $shdwItemText: none;
$colorTabBorder: pullForward($colorBodyBg, 10%);
$colorTabBodyBg: $colorBodyBg;
$colorTabBodyFg: pullForward($colorBodyFg, 20%);
$colorTabHeaderBg: pullForward($colorBodyBg, 10%);
$colorTabHeaderBg: rgba($colorBodyFg, 0.2);
$colorTabHeaderFg: $colorBodyFg;
$colorTabHeaderBorder: $colorBodyBg;
$colorTabGroupHeaderBg: pullForward($colorBodyBg, 5%);

View File

@ -100,8 +100,10 @@ $colorStatusErrorFilter: invert(8%) sepia(96%) saturate(4511%) hue-rotate(352deg
$colorStatusBtnBg: #666; // Where is this used?
$colorStatusPartialBg: #c9d6ff;
$colorStatusCompleteBg: #a4e4b4;
$colorAlert: #ff3c00;
$colorAlert: #ff8a0d;
$colorAlertFg: #fff;
$colorError: #ff3c00;
$colorErrorFg: #fff;
$colorWarningHi: #990000;
$colorWarningHiFg: #FF9594;
$colorWarningLo: #ff9900;
@ -215,6 +217,7 @@ $colorSelectBg: $colorBtnBg; // This must be a solid color, not a gradient, due
$colorSelectFg: $colorBtnFg;
$colorSelectArw: lighten($colorBtnBg, 20%);
$shdwSelect: none;
$controlDisabledOpacity: 0.3;
// Menus
$colorMenuBg: pushBack($colorBodyBg, 10%);
@ -320,8 +323,8 @@ $shdwItemText: none;
$colorTabBorder: pullForward($colorBodyBg, 10%);
$colorTabBodyBg: $colorBodyBg;
$colorTabBodyFg: pullForward($colorBodyFg, 20%);
$colorTabHeaderBg: pullForward($colorBodyBg, 10%);
$colorTabHeaderFg: pullForward($colorBodyFg, 20%);
$colorTabHeaderBg: rgba($colorBodyFg, 0.2);
$colorTabHeaderFg: $colorBodyFg;
$colorTabHeaderBorder: $colorBodyBg;
$colorTabGroupHeaderBg: pullForward($colorBodyBg, 5%);
$colorTabGroupHeaderFg: pullForward($colorTabGroupHeaderBg, 40%);

View File

@ -94,9 +94,6 @@ $tableResizeColHitareaD: 6px;
$mobileMenuIconD: 24px; // Used
$mobileTreeItemH: 35px; // Used
/************************** VISUAL */
$controlDisabledOpacity: 0.5;
/************************** UI ELEMENTS */
/*************** Progress Bar */
$colorProgressBarHolder: rgba(black, 0.1);
@ -148,6 +145,7 @@ $glyph-icon-filter-outline: '\e927';
$glyph-icon-suitcase: '\e928';
$glyph-icon-cursor-lock: '\e929';
$glyph-icon-flag: '\e92a';
$glyph-icon-eye-disabled: '\e92b';
$glyph-icon-arrows-right-left: '\ea00';
$glyph-icon-arrows-up-down: '\ea01';
$glyph-icon-bullet: '\ea02';

View File

@ -229,6 +229,7 @@ section {
&.is-expanded {
flex: 1 1 100%;
max-height: max-content;
}
.c-section__header {
@ -785,7 +786,25 @@ select {
}
}
/***************************************************** SLIDERS */
/******************************************************** STYLE EDITING */
.c-style {
display: flex;
flex: 1 1 auto;
align-items: center;
> * + * { margin-left: $interiorMargin; }
}
.c-style-thumb {
background-size: cover;
border: 1px solid transparent;
border-radius: $basicCr;
box-shadow: rgba($colorBodyFg, 0.4) 0 0 3px;
flex: 0 0 auto;
padding: $interiorMargin $interiorMarginLg;
}
/******************************************************** SLIDERS */
.c-slider {
@include cControl();
> * + * { margin-left: $interiorMargin; }

View File

@ -35,6 +35,22 @@ div {
display: contents;
}
.u-menu-to {
&--left {
.c-menu {
left: auto !important;
right: 0;
}
}
&--center {
.c-menu {
left: 50% !important;
transform: translateX(-50%);
}
}
}
.u-space {
// Provides a separator space between elements
&--right {

View File

@ -82,6 +82,7 @@
.icon-suitcase { @include glyphBefore($glyph-icon-suitcase); }
.icon-cursor-lock { @include glyphBefore($glyph-icon-cursor-lock); }
.icon-flag { @include glyphBefore($glyph-icon-flag); }
.icon-eye-disabled { @include glyphBefore($glyph-icon-eye-disabled); }
.icon-arrows-right-left { @include glyphBefore($glyph-icon-arrows-right-left); }
.icon-arrows-up-down { @include glyphBefore($glyph-icon-arrows-up-down); }
.icon-bullet { @include glyphBefore($glyph-icon-bullet); }

View File

@ -67,15 +67,12 @@
}
&__object-name--w {
align-items: center;
display: flex;
flex: 0 1 auto;
@include headerFont(1.4em);
min-width: 0;
&:before {
// Icon
opacity: 0.5;
margin-right: $interiorMargin;
}
}

View File

@ -127,6 +127,24 @@
background-size: $bgSize;
}
@mixin bgCheckerboard($c: $colorBodyFg, $opacity: 0.3, $size: 32px, $imp: false) {
$color: rgba($c, $opacity);
$bgPos: floor($size / 2);
$impStr: null;
@if $imp {
$impStr: !important;
}
background-image:
linear-gradient(45deg, $color 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, $color 75%),
linear-gradient(45deg, transparent 75%, $color 75%),
linear-gradient(45deg, $color 25%, transparent 25%) $impStr;
background-size: $size $size;
background-position:0 0, 0 0, -1*$bgPos -1*$bgPos, $bgPos $bgPos;
}
@mixin disabled() {
opacity: $controlDisabledOpacity;
pointer-events: none !important;
@ -403,9 +421,9 @@
}
}
@mixin cClickIcon() {
@include cControl();
color: $colorBodyFg;
cursor: pointer;
padding: 4px; // Bigger hit area
opacity: 0.6;

View File

@ -40,7 +40,7 @@
display: inline-block;
font-family: symbolsfont;
font-size: 0.8em;
margin-right: $interiorMargin;
margin-right: $interiorMarginSm;
@if $glyph != null {
content: $glyph $impStr;
}
@ -71,6 +71,30 @@
&.is-limit--lwr:before { content: $glyph-icon-arrow-down !important; }
}
@mixin uIndicator($bg, $fg, $glyph) {
background: $bg;
color: $fg;
&[class*='--with-icon'] {
&:before {
color: $fg;
display: inline-block;
font-family: symbolsfont;
margin-right: $interiorMarginSm;
@if $glyph != null {
content: $glyph;
}
}
}
&[class*='--block'] {
border-radius: $controlCr;
display: inline-block;
padding: 2px $interiorMargin;
}
}
/*************************************************** STYLES */
*:not(tr) {
&.is-limit--yellow {
@ -173,3 +197,5 @@ tr {
}
}
.u-alert { @include uIndicator($colorAlert, $colorAlertFg, $glyph-icon-alert-triangle); }
.u-error { @include uIndicator($colorError, $colorErrorFg, $glyph-icon-alert-triangle); }

View File

@ -2,7 +2,7 @@
"metadata": {
"name": "Open MCT Symbols 16px",
"lastOpened": 0,
"created": 1581619121103
"created": 1585006719465
},
"iconSets": [
{
@ -351,13 +351,21 @@
"code": 59690,
"tempChar": ""
},
{
"order": 177,
"id": 152,
"name": "icon-eye-disabled",
"prevSize": 24,
"code": 59691,
"tempChar": ""
},
{
"order": 27,
"id": 105,
"name": "icon-arrows-right-left",
"prevSize": 24,
"code": 59904,
"tempChar": ""
"tempChar": ""
},
{
"order": 26,
@ -365,7 +373,7 @@
"name": "icon-arrows-up-down",
"prevSize": 24,
"code": 59905,
"tempChar": ""
"tempChar": ""
},
{
"order": 68,
@ -373,7 +381,7 @@
"name": "icon-bullet",
"prevSize": 24,
"code": 59906,
"tempChar": ""
"tempChar": ""
},
{
"order": 150,
@ -381,7 +389,7 @@
"prevSize": 24,
"code": 59907,
"name": "icon-calendar",
"tempChar": ""
"tempChar": ""
},
{
"order": 45,
@ -389,7 +397,7 @@
"name": "icon-chain-links",
"prevSize": 24,
"code": 59908,
"tempChar": ""
"tempChar": ""
},
{
"order": 73,
@ -397,7 +405,7 @@
"name": "icon-download",
"prevSize": 24,
"code": 59909,
"tempChar": ""
"tempChar": ""
},
{
"order": 39,
@ -405,7 +413,7 @@
"name": "icon-duplicate",
"prevSize": 24,
"code": 59910,
"tempChar": ""
"tempChar": ""
},
{
"order": 50,
@ -413,7 +421,7 @@
"name": "icon-folder-new",
"prevSize": 24,
"code": 59911,
"tempChar": ""
"tempChar": ""
},
{
"order": 138,
@ -421,7 +429,7 @@
"name": "icon-fullscreen-collapse",
"prevSize": 24,
"code": 59912,
"tempChar": ""
"tempChar": ""
},
{
"order": 139,
@ -429,7 +437,7 @@
"name": "icon-fullscreen-expand",
"prevSize": 24,
"code": 59913,
"tempChar": ""
"tempChar": ""
},
{
"order": 122,
@ -437,7 +445,7 @@
"name": "icon-layers",
"prevSize": 24,
"code": 59914,
"tempChar": ""
"tempChar": ""
},
{
"order": 151,
@ -445,7 +453,7 @@
"name": "icon-line-horz",
"prevSize": 24,
"code": 59915,
"tempChar": ""
"tempChar": ""
},
{
"order": 100,
@ -453,7 +461,7 @@
"name": "icon-magnify",
"prevSize": 24,
"code": 59916,
"tempChar": ""
"tempChar": ""
},
{
"order": 99,
@ -461,7 +469,7 @@
"name": "icon-magnify-in",
"prevSize": 24,
"code": 59917,
"tempChar": ""
"tempChar": ""
},
{
"order": 101,
@ -469,7 +477,7 @@
"name": "icon-magnify-out-v2",
"prevSize": 24,
"code": 59918,
"tempChar": ""
"tempChar": ""
},
{
"order": 103,
@ -477,7 +485,7 @@
"name": "icon-menu",
"prevSize": 24,
"code": 59919,
"tempChar": ""
"tempChar": ""
},
{
"order": 124,
@ -485,7 +493,7 @@
"name": "icon-move",
"prevSize": 24,
"code": 59920,
"tempChar": ""
"tempChar": ""
},
{
"order": 7,
@ -493,7 +501,7 @@
"name": "icon-new-window",
"prevSize": 24,
"code": 59921,
"tempChar": ""
"tempChar": ""
},
{
"order": 63,
@ -501,7 +509,7 @@
"name": "icon-paint-bucket-v2",
"prevSize": 24,
"code": 59922,
"tempChar": ""
"tempChar": ""
},
{
"order": 15,
@ -509,7 +517,7 @@
"name": "icon-pencil",
"prevSize": 24,
"code": 59923,
"tempChar": ""
"tempChar": ""
},
{
"order": 54,
@ -517,7 +525,7 @@
"name": "icon-pencil-edit-in-place",
"prevSize": 24,
"code": 59924,
"tempChar": ""
"tempChar": ""
},
{
"order": 40,
@ -525,7 +533,7 @@
"name": "icon-play",
"prevSize": 24,
"code": 59925,
"tempChar": ""
"tempChar": ""
},
{
"order": 125,
@ -533,7 +541,7 @@
"name": "icon-pause",
"prevSize": 24,
"code": 59926,
"tempChar": ""
"tempChar": ""
},
{
"order": 119,
@ -541,7 +549,7 @@
"name": "icon-plot-resource",
"prevSize": 24,
"code": 59927,
"tempChar": ""
"tempChar": ""
},
{
"order": 48,
@ -549,7 +557,7 @@
"name": "icon-pointer-left",
"prevSize": 24,
"code": 59928,
"tempChar": ""
"tempChar": ""
},
{
"order": 47,
@ -557,7 +565,7 @@
"name": "icon-pointer-right",
"prevSize": 24,
"code": 59929,
"tempChar": ""
"tempChar": ""
},
{
"order": 85,
@ -565,7 +573,7 @@
"name": "icon-refresh",
"prevSize": 24,
"code": 59930,
"tempChar": ""
"tempChar": ""
},
{
"order": 55,
@ -573,7 +581,7 @@
"name": "icon-save",
"prevSize": 24,
"code": 59931,
"tempChar": ""
"tempChar": ""
},
{
"order": 56,
@ -581,7 +589,7 @@
"name": "icon-save-as",
"prevSize": 24,
"code": 59932,
"tempChar": ""
"tempChar": ""
},
{
"order": 58,
@ -589,7 +597,7 @@
"name": "icon-sine",
"prevSize": 24,
"code": 59933,
"tempChar": ""
"tempChar": ""
},
{
"order": 113,
@ -597,7 +605,7 @@
"name": "icon-font",
"prevSize": 24,
"code": 59934,
"tempChar": ""
"tempChar": ""
},
{
"order": 41,
@ -605,7 +613,7 @@
"name": "icon-thumbs-strip",
"prevSize": 24,
"code": 59935,
"tempChar": ""
"tempChar": ""
},
{
"order": 146,
@ -613,7 +621,7 @@
"name": "icon-two-parts-both",
"prevSize": 24,
"code": 59936,
"tempChar": ""
"tempChar": ""
},
{
"order": 145,
@ -621,7 +629,7 @@
"name": "icon-two-parts-one-only",
"prevSize": 24,
"code": 59937,
"tempChar": ""
"tempChar": ""
},
{
"order": 82,
@ -629,7 +637,7 @@
"name": "icon-resync",
"prevSize": 24,
"code": 59938,
"tempChar": ""
"tempChar": ""
},
{
"order": 86,
@ -637,7 +645,7 @@
"name": "icon-reset",
"prevSize": 24,
"code": 59939,
"tempChar": ""
"tempChar": ""
},
{
"order": 61,
@ -645,7 +653,7 @@
"name": "icon-x-in-circle",
"prevSize": 24,
"code": 59940,
"tempChar": ""
"tempChar": ""
},
{
"order": 84,
@ -653,7 +661,7 @@
"name": "icon-brightness",
"prevSize": 24,
"code": 59941,
"tempChar": ""
"tempChar": ""
},
{
"order": 83,
@ -661,7 +669,7 @@
"name": "icon-contrast",
"prevSize": 24,
"code": 59942,
"tempChar": ""
"tempChar": ""
},
{
"order": 87,
@ -669,7 +677,7 @@
"name": "icon-expand",
"prevSize": 24,
"code": 59943,
"tempChar": ""
"tempChar": ""
},
{
"order": 89,
@ -677,7 +685,7 @@
"name": "icon-list-view",
"prevSize": 24,
"code": 59944,
"tempChar": ""
"tempChar": ""
},
{
"order": 133,
@ -685,7 +693,7 @@
"name": "icon-grid-snap-to",
"prevSize": 24,
"code": 59945,
"tempChar": ""
"tempChar": ""
},
{
"order": 132,
@ -693,7 +701,7 @@
"name": "icon-grid-snap-no",
"prevSize": 24,
"code": 59946,
"tempChar": ""
"tempChar": ""
},
{
"order": 94,
@ -701,7 +709,7 @@
"name": "icon-frame-show",
"prevSize": 24,
"code": 59947,
"tempChar": ""
"tempChar": ""
},
{
"order": 95,
@ -709,7 +717,7 @@
"name": "icon-frame-hide",
"prevSize": 24,
"code": 59948,
"tempChar": ""
"tempChar": ""
},
{
"order": 97,
@ -717,7 +725,7 @@
"name": "icon-import",
"prevSize": 24,
"code": 59949,
"tempChar": ""
"tempChar": ""
},
{
"order": 96,
@ -725,7 +733,7 @@
"name": "icon-export",
"prevSize": 24,
"code": 59950,
"tempChar": ""
"tempChar": ""
},
{
"order": 114,
@ -733,7 +741,7 @@
"name": "icon-font-size",
"prevSize": 24,
"code": 59951,
"tempChar": ""
"tempChar": ""
},
{
"order": 163,
@ -741,7 +749,7 @@
"name": "icon-clear-data",
"prevSize": 24,
"code": 59952,
"tempChar": ""
"tempChar": ""
},
{
"order": 173,
@ -749,7 +757,7 @@
"name": "icon-history",
"prevSize": 24,
"code": 59953,
"tempChar": ""
"tempChar": ""
},
{
"order": 144,
@ -757,7 +765,7 @@
"name": "icon-activity",
"prevSize": 24,
"code": 60160,
"tempChar": ""
"tempChar": ""
},
{
"order": 104,
@ -765,7 +773,7 @@
"name": "icon-activity-mode",
"prevSize": 24,
"code": 60161,
"tempChar": ""
"tempChar": ""
},
{
"order": 137,
@ -773,7 +781,7 @@
"name": "icon-autoflow-tabular",
"prevSize": 24,
"code": 60162,
"tempChar": ""
"tempChar": ""
},
{
"order": 115,
@ -781,7 +789,7 @@
"name": "icon-clock",
"prevSize": 24,
"code": 60163,
"tempChar": ""
"tempChar": ""
},
{
"order": 2,
@ -789,7 +797,7 @@
"name": "icon-database",
"prevSize": 24,
"code": 60164,
"tempChar": ""
"tempChar": ""
},
{
"order": 3,
@ -797,7 +805,7 @@
"name": "icon-database-query",
"prevSize": 24,
"code": 60165,
"tempChar": ""
"tempChar": ""
},
{
"order": 67,
@ -805,7 +813,7 @@
"name": "icon-dataset",
"prevSize": 24,
"code": 60166,
"tempChar": ""
"tempChar": ""
},
{
"order": 59,
@ -813,7 +821,7 @@
"name": "icon-datatable",
"prevSize": 24,
"code": 60167,
"tempChar": ""
"tempChar": ""
},
{
"order": 136,
@ -821,7 +829,7 @@
"name": "icon-dictionary",
"prevSize": 24,
"code": 60168,
"tempChar": ""
"tempChar": ""
},
{
"order": 51,
@ -829,7 +837,7 @@
"name": "icon-folder",
"prevSize": 24,
"code": 60169,
"tempChar": ""
"tempChar": ""
},
{
"order": 147,
@ -837,7 +845,7 @@
"name": "icon-image",
"prevSize": 24,
"code": 60170,
"tempChar": ""
"tempChar": ""
},
{
"order": 4,
@ -845,7 +853,7 @@
"name": "icon-layout",
"prevSize": 24,
"code": 60171,
"tempChar": ""
"tempChar": ""
},
{
"order": 24,
@ -853,7 +861,7 @@
"name": "icon-object",
"prevSize": 24,
"code": 60172,
"tempChar": ""
"tempChar": ""
},
{
"order": 52,
@ -861,7 +869,7 @@
"name": "icon-object-unknown",
"prevSize": 24,
"code": 60173,
"tempChar": ""
"tempChar": ""
},
{
"order": 105,
@ -869,7 +877,7 @@
"name": "icon-packet",
"prevSize": 24,
"code": 60174,
"tempChar": ""
"tempChar": ""
},
{
"order": 126,
@ -877,7 +885,7 @@
"name": "icon-page",
"prevSize": 24,
"code": 60175,
"tempChar": ""
"tempChar": ""
},
{
"order": 130,
@ -885,7 +893,7 @@
"name": "icon-plot-overlay",
"prevSize": 24,
"code": 60176,
"tempChar": ""
"tempChar": ""
},
{
"order": 80,
@ -893,7 +901,7 @@
"name": "icon-plot-stacked",
"prevSize": 24,
"code": 60177,
"tempChar": ""
"tempChar": ""
},
{
"order": 134,
@ -901,7 +909,7 @@
"name": "icon-session",
"prevSize": 24,
"code": 60178,
"tempChar": ""
"tempChar": ""
},
{
"order": 109,
@ -909,7 +917,7 @@
"name": "icon-tabular",
"prevSize": 24,
"code": 60179,
"tempChar": ""
"tempChar": ""
},
{
"order": 107,
@ -917,7 +925,7 @@
"name": "icon-tabular-lad",
"prevSize": 24,
"code": 60180,
"tempChar": ""
"tempChar": ""
},
{
"order": 106,
@ -925,7 +933,7 @@
"name": "icon-tabular-lad-set",
"prevSize": 24,
"code": 60181,
"tempChar": ""
"tempChar": ""
},
{
"order": 70,
@ -933,7 +941,7 @@
"name": "icon-tabular-realtime",
"prevSize": 24,
"code": 60182,
"tempChar": ""
"tempChar": ""
},
{
"order": 60,
@ -941,7 +949,7 @@
"name": "icon-tabular-scrolling",
"prevSize": 24,
"code": 60183,
"tempChar": ""
"tempChar": ""
},
{
"order": 131,
@ -949,7 +957,7 @@
"name": "icon-telemetry",
"prevSize": 24,
"code": 60184,
"tempChar": ""
"tempChar": ""
},
{
"order": 108,
@ -957,7 +965,7 @@
"name": "icon-timeline",
"prevSize": 24,
"code": 60185,
"tempChar": ""
"tempChar": ""
},
{
"order": 81,
@ -965,7 +973,7 @@
"name": "icon-timer",
"prevSize": 24,
"code": 60186,
"tempChar": ""
"tempChar": ""
},
{
"order": 69,
@ -973,7 +981,7 @@
"name": "icon-topic",
"prevSize": 24,
"code": 60187,
"tempChar": ""
"tempChar": ""
},
{
"order": 79,
@ -981,7 +989,7 @@
"name": "icon-box-with-dashed-lines-v2",
"prevSize": 24,
"code": 60188,
"tempChar": ""
"tempChar": ""
},
{
"order": 90,
@ -989,7 +997,7 @@
"name": "icon-summary-widget",
"prevSize": 24,
"code": 60189,
"tempChar": ""
"tempChar": ""
},
{
"order": 92,
@ -997,7 +1005,7 @@
"name": "icon-notebook",
"prevSize": 24,
"code": 60190,
"tempChar": ""
"tempChar": ""
},
{
"order": 168,
@ -1005,7 +1013,7 @@
"name": "icon-tabs-view",
"prevSize": 24,
"code": 60191,
"tempChar": ""
"tempChar": ""
},
{
"order": 117,
@ -1013,7 +1021,7 @@
"name": "icon-flexible-layout",
"prevSize": 24,
"code": 60192,
"tempChar": ""
"tempChar": ""
},
{
"order": 166,
@ -1021,7 +1029,7 @@
"name": "icon-generator-sine",
"prevSize": 24,
"code": 60193,
"tempChar": ""
"tempChar": ""
},
{
"order": 167,
@ -1029,7 +1037,7 @@
"name": "icon-generator-event",
"prevSize": 24,
"code": 60194,
"tempChar": ""
"tempChar": ""
},
{
"order": 165,
@ -1037,7 +1045,7 @@
"name": "icon-gauge-v2",
"prevSize": 24,
"code": 60195,
"tempChar": ""
"tempChar": ""
},
{
"order": 170,
@ -1045,7 +1053,7 @@
"name": "icon-spectra",
"prevSize": 24,
"code": 60196,
"tempChar": ""
"tempChar": ""
},
{
"order": 171,
@ -1053,7 +1061,7 @@
"name": "icon-telemetry-spectra",
"prevSize": 24,
"code": 60197,
"tempChar": ""
"tempChar": ""
},
{
"order": 172,
@ -1061,7 +1069,7 @@
"name": "icon-pushbutton",
"prevSize": 24,
"code": 60198,
"tempChar": ""
"tempChar": ""
},
{
"order": 174,
@ -1069,7 +1077,7 @@
"name": "icon-conditional",
"prevSize": 24,
"code": 60199,
"tempChar": ""
"tempChar": ""
}
],
"id": 0,
@ -1644,6 +1652,25 @@
"isMulticolor": false,
"isMulticolor2": false
},
{
"id": 152,
"paths": [
"M209.46 608.68q-7.46-9.86-14.26-20.28c-14.737-21.984-27.741-47.184-37.759-73.847l-0.841-2.553c11.078-29.259 24.068-54.443 39.51-77.869l-0.91 1.469c23.221-34.963 50.705-64.8 82.207-89.793l0.793-0.607c57.663-45.719 130.179-75.053 209.311-79.947l1.069-0.053 114.48-140.88c-27.366-5.017-58.869-7.898-91.041-7.92l-0.019-0c-245.8 0-452.2 168-510.8 395.6 21.856 82.93 60.906 154.847 113.325 214.773l-0.525-0.613z",
"M814.76 415.080q7.52 10 14.44 20.52c14.737 21.984 27.741 47.184 37.759 73.847l0.841 2.553c-10.859 29.216-23.863 54.416-39.447 77.748l0.847-1.348c-23.221 34.963-50.705 64.8-82.207 89.793l-0.793 0.607c-57.762 45.834-130.437 75.216-209.743 80.049l-1.057 0.051-114.46 140.86c27.346 4.988 58.817 7.84 90.955 7.84 0.037 0 0.074-0 0.111-0l-0.005 0c245.8 0 452.2-168 510.8-395.6-21.856-82.93-60.906-154.847-113.325-214.773l0.525 0.613z",
"M832 0l-832 1024h192l832-1024h-192z"
],
"attrs": [
{},
{},
{}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 16,
"tags": [
"icon-eye-disabled"
]
},
{
"id": 105,
"paths": [

1
src/styles/fonts/Open-MCT-Symbols-16px.svg Executable file → Normal file
View File

@ -50,6 +50,7 @@
<glyph unicode="&#xe928;" glyph-name="icon-suitcase" d="M768 704c-0.080 70.66-57.34 127.92-127.993 128h-256.007c-70.66-0.080-127.92-57.34-128-127.993v-128.007h-64v-768h640v768h-64zM384 703.88l0.12 0.12 255.88-0.12v-127.88h-256zM0 512v-640c0.102-35.305 28.695-63.898 63.99-64h64.010v768h-64c-35.305-0.102-63.898-28.695-64-63.99v-0.010zM960 576h-64v-768h64c35.305 0.102 63.898 28.695 64 63.99v640.010c-0.102 35.305-28.695 63.898-63.99 64h-0.010z" />
<glyph unicode="&#xe929;" glyph-name="icon-cursor-locked" horiz-adv-x="768" d="M704 512h-64v64c0 141.385-114.615 256-256 256s-256-114.615-256-256v0-64h-64c-35.301-0.113-63.887-28.699-64-63.989v-576.011c0.113-35.301 28.699-63.887 63.989-64h640.011c35.301 0.113 63.887 28.699 64 63.989v576.011c-0.113 35.301-28.699 63.887-63.989 64h-0.011zM256 576c0 70.692 57.308 128 128 128s128-57.308 128-128v0-64h-256zM533.4-64l-128 128-43-85-170.4 383.6 383.6-170.2-85-43 128-128z" />
<glyph unicode="&#xe92a;" glyph-name="icon-flag" d="M192 192h832l-192 320 192 320h-896c-70.606-0.215-127.785-57.394-128-127.979v-896.021h192z" />
<glyph unicode="&#xe92b;" glyph-name="icon-eye-disabled" d="M209.46 223.32q-7.46 9.86-14.26 20.28c-14.737 21.984-27.741 47.184-37.759 73.847l-0.841 2.553c11.078 29.259 24.068 54.443 39.51 77.869l-0.91-1.469c23.221 34.963 50.705 64.8 82.207 89.793l0.793 0.607c57.663 45.719 130.179 75.053 209.311 79.947l1.069 0.053 114.48 140.88c-27.366 5.017-58.869 7.898-91.041 7.92h-0.019c-245.8 0-452.2-168-510.8-395.6 21.856-82.93 60.906-154.847 113.325-214.773l-0.525 0.613zM814.76 416.92q7.52-10 14.44-20.52c14.737-21.984 27.741-47.184 37.759-73.847l0.841-2.553c-10.859-29.216-23.863-54.416-39.447-77.748l0.847 1.348c-23.221-34.963-50.705-64.8-82.207-89.793l-0.793-0.607c-57.762-45.834-130.437-75.216-209.743-80.049l-1.057-0.051-114.46-140.86c27.346-4.988 58.817-7.84 90.955-7.84 0.037 0 0.074 0 0.111 0h-0.005c245.8 0 452.2 168 510.8 395.6-21.856 82.93-60.906 154.847-113.325 214.773l0.525-0.613zM832 832l-832-1024h192l832 1024h-192z" />
<glyph unicode="&#xea00;" glyph-name="icon-arrows-right-left" d="M1024 320l-448-512v1024zM448 832l-448-512 448-512z" />
<glyph unicode="&#xea01;" glyph-name="icon-arrows-up-down" d="M512 832l512-448h-1024zM0 256l512-448 512 448z" />
<glyph unicode="&#xea02;" glyph-name="icon-bullet" d="M832 80c0-44-36-80-80-80h-480c-44 0-80 36-80 80v480c0 44 36 80 80 80h480c44 0 80-36 80-80v-480z" />

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 52 KiB

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

Binary file not shown.

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

Binary file not shown.

View File

@ -2,6 +2,7 @@
@import "../api/overlays/components/overlay-component.scss";
@import "../plugins/condition/components/condition.scss";
@import "../plugins/condition/components/condition-set.scss";
@import "../plugins/condition/components/inspector/conditional-styles.scss";
@import "../plugins/displayLayout/components/box-view.scss";
@import "../plugins/displayLayout/components/display-layout.scss";
@import "../plugins/displayLayout/components/edit-marquee.scss";

View File

@ -5,6 +5,7 @@
<script>
import _ from "lodash"
import StyleRuleManager from "@/plugins/condition/StyleRuleManager";
import {STYLE_CONSTANTS} from "@/plugins/condition/utils/constants";
export default {
inject: ["openmct"],
@ -37,13 +38,12 @@ export default {
this.unlisten();
}
if (this.stopListeningConditionalStyles) {
this.stopListeningConditionalStyles();
if (this.stopListeningStyles) {
this.stopListeningStyles();
}
if (this.styleRuleManager) {
this.styleRuleManager.destroy();
this.styleRuleManager.off('conditionalStyleUpdated', this.updateStyle.bind(this));
delete this.styleRuleManager;
}
},
@ -60,7 +60,7 @@ export default {
this.$el.addEventListener('drop', this.addObjectToParent);
if (this.currentObject) {
//This is to apply styles to subobjects in a layout
this.initConditionalStyles();
this.initObjectStyles();
}
},
@ -102,8 +102,19 @@ export default {
}
let keys = Object.keys(styleObj);
keys.forEach(key => {
this.$el.style[key] = styleObj[key];
})
if ((typeof styleObj[key] === 'string') && (styleObj[key].indexOf('transparent') > -1)) {
if (this.$el.style[key]) {
this.$el.style[key] = '';
}
} else {
if (!styleObj.isStyleInvisible && this.$el.classList.contains(STYLE_CONSTANTS.isStyleInvisible)) {
this.$el.classList.remove(STYLE_CONSTANTS.isStyleInvisible);
} else if (styleObj.isStyleInvisible && !this.$el.classList.contains(styleObj.isStyleInvisible)) {
this.$el.classList.add(styleObj.isStyleInvisible);
}
this.$el.style[key] = styleObj[key];
}
});
},
updateView(immediatelySelect) {
this.clear();
@ -181,25 +192,24 @@ export default {
this.viewKey = viewKey;
this.initConditionalStyles();
this.initObjectStyles();
this.updateView(immediatelySelect);
},
initConditionalStyles() {
initObjectStyles() {
if (!this.styleRuleManager) {
this.styleRuleManager = new StyleRuleManager((this.currentObject.configuration && this.currentObject.configuration.conditionalStyle), this.openmct);
this.styleRuleManager.on('conditionalStyleUpdated', this.updateStyle.bind(this));
this.styleRuleManager = new StyleRuleManager((this.currentObject.configuration && this.currentObject.configuration.objectStyles), this.openmct, this.updateStyle.bind(this));
} else {
this.styleRuleManager.updateConditionalStyleConfig(this.currentObject.configuration && this.currentObject.configuration.conditionalStyle);
this.styleRuleManager.updateObjectStyleConfig(this.currentObject.configuration && this.currentObject.configuration.objectStyles);
}
if (this.stopListeningConditionalStyles) {
this.stopListeningConditionalStyles();
if (this.stopListeningStyles) {
this.stopListeningStyles();
}
this.stopListeningConditionalStyles = this.openmct.objects.observe(this.currentObject, 'configuration.conditionalStyle', (newConditionalStyle) => {
//Updating conditional styles in the inspector view will trigger this so that the changes are reflected immediately
this.styleRuleManager.updateConditionalStyleConfig(newConditionalStyle);
this.stopListeningStyles = this.openmct.objects.observe(this.currentObject, 'configuration.objectStyles', (newObjectStyle) => {
//Updating styles in the inspector view will trigger this so that the changes are reflected immediately
this.styleRuleManager.updateObjectStyleConfig(newObjectStyle);
});
},
loadComposition() {

View File

@ -1,28 +1,42 @@
.c-object-label {
// <a> tag and draggable element that holds type icon and name.
// Used mostly in trees and lists
border-radius: $controlCr;
display: flex;
align-items: center;
flex: 1 1 auto;
flex: 0 1 auto;
overflow: hidden;
padding: $interiorMarginSm 1px;
white-space: nowrap;
&__name {
@include ellipsize();
display: inline;
color: $colorItemTreeFg;
}
&__type-icon,
&:before {
// Type icon. Must be an HTML entity to allow inclusion of alias indicator.
display: block;
flex: 0 0 auto;
font-size: 1.1em;
opacity: 0.6;
margin-right: $interiorMargin;
}
}
.c-tree .c-object-label {
border-radius: $controlCr;
padding: $interiorMarginSm 1px;
&__name {
display: inline;
width: 100%;
}
&__type-icon {
// Type icon. Must be an HTML entity to allow inclusion of alias indicator.
display: block;
flex: 0 0 auto;
font-size: 1.3em;
margin-right: $interiorMarginSm;
color: $colorItemTreeIcon;
font-size: 1.25em;
margin-right: $interiorMarginSm;
opacity: 1;
width: $treeTypeIconW;
}
}

View File

@ -5,7 +5,7 @@
'c-disclosure-triangle--expanded' : value,
'is-enabled' : enabled
}"
@click="$emit('input', !value)"
@click="handleClick"
></span>
</template>
@ -21,6 +21,18 @@ export default {
// Used as such in the tree - when a node doesn't have children, set disabled to true.
type: Boolean,
default: false
},
propagate: {
type: Boolean,
default: true
}
},
methods: {
handleClick(event) {
this.$emit('input', !this.value);
if (!this.propagate) {
event.stopPropagation();
}
}
}
}

View File

@ -1,44 +1,40 @@
<template>
<div class="c-inspector">
<div class="c-inspector__tabs">
<div v-if="showStyles"
class="c-inspector__tabs__holder"
<object-name />
<div v-if="showStyles"
class="c-inspector__tabs c-tabs"
>
<div v-for="tabbedView in tabbedViews"
:key="tabbedView.key"
class="c-inspector__tab c-tab"
:class="{'is-current': isCurrent(tabbedView)}"
@click="updateCurrentTab(tabbedView)"
>
<div v-for="tabbedView in tabbedViews"
:key="tabbedView.key"
class="c-inspector__tabs__header"
@click="updateCurrentTab(tabbedView)"
>
<span class="c-inspector__tabs__label c-tab"
:class="{'is-current': isCurrent(tabbedView)}"
>{{ tabbedView.name }}</span>
</div>
{{ tabbedView.name }}
</div>
<div class="c-inspector__tabs__contents">
<multipane v-if="currentTabbedView.key === '__properties'"
class="c-inspector"
type="vertical"
>
<pane class="c-inspector__properties">
<properties />
<location />
<inspector-views />
</pane>
<pane
v-if="isEditing && hasComposition"
class="c-inspector__elements"
handle="before"
label="Elements"
>
<elements />
</pane>
</multipane>
<pane v-else
class="c-inspector__styles"
>
<styles-inspector-view />
</div>
<div class="c-inspector__content">
<multipane v-if="currentTabbedView.key === '__properties'"
type="vertical"
>
<pane class="c-inspector__properties">
<properties />
<location />
<inspector-views />
</pane>
</div>
<pane
v-if="isEditing && hasComposition"
class="c-inspector__elements"
handle="before"
label="Elements"
>
<elements />
</pane>
</multipane>
<template v-else>
<styles-inspector-view />
</template>
</div>
</div>
</template>
@ -49,6 +45,7 @@ import pane from '../layout/pane.vue';
import Elements from './Elements.vue';
import Location from './Location.vue';
import Properties from './Properties.vue';
import ObjectName from './ObjectName.vue';
import InspectorViews from './InspectorViews.vue';
import _ from "lodash";
import StylesInspectorView from "./StylesInspectorView.vue";
@ -62,6 +59,7 @@ export default {
pane,
Elements,
Properties,
ObjectName,
Location,
InspectorViews
},
@ -112,7 +110,10 @@ export default {
let type = this.openmct.types.get(object.type);
this.showStyles = (this.excludeObjectTypes.indexOf(object.type) < 0) && type.definition.creatable;
}
this.updateCurrentTab(this.tabbedViews[0]);
if (!this.currentTabbedView.key || (!this.showStyles && this.currentTabbedView.key === this.tabbedViews[1].key))
{
this.updateCurrentTab(this.tabbedViews[0]);
}
}
},
updateCurrentTab(view) {

View File

@ -1,20 +1,20 @@
<template>
<div class="c-properties c-properties--location">
<div class="c-inspect-properties c-inspect-properties--location">
<div
class="c-properties__header"
class="c-inspect-properties__header"
title="The location of this linked object."
>
Original Location
</div>
<ul
v-if="!multiSelect"
class="c-properties__section"
class="c-inspect-properties__section"
>
<li
v-if="originalPath.length"
class="c-properties__row"
class="c-inspect-properties__row"
>
<ul class="c-properties__value c-location">
<ul class="c-inspect-properties__value c-location">
<li
v-for="pathObject in orderedOriginalPath"
:key="pathObject.key"
@ -30,7 +30,7 @@
</ul>
<div
v-if="multiSelect"
class="c-properties__row--span-all"
class="c-inspect-properties__row--span-all"
>
No location to display for multiple items
</div>

View File

@ -0,0 +1,76 @@
<template>
<div class="c-inspector__header">
<div v-if="!multiSelect && !singleSelectNonObject"
class="c-inspector__selected-w c-object-label"
:class="typeCssClass"
>
<span class="c-inspector__selected c-object-label__name">{{ item.name }}</span>
</div>
<div v-if="singleSelectNonObject"
class="c-inspector__selected-w c-object-label"
:class="typeCssClass"
>
<span class="c-inspector__selected c-object-label__name c-inspector__selected--non-domain-object">Layout Object</span>
</div>
<div v-if="multiSelect"
class="c-inspector__multiple-selected-w"
>
{{ itemsSelected }} items selected
</div>
</div>
</template>
<script>
export default {
inject: ['openmct'],
data() {
return {
domainObject: {},
multiSelect: false,
itemsSelected: 0
}
},
computed: {
item() {
return this.domainObject || {};
},
type() {
return this.openmct.types.get(this.item.type);
},
typeCssClass() {
if (this.type.definition.cssClass === undefined) {
return 'icon-object';
}
return this.type.definition.cssClass;
},
singleSelectNonObject() {
return !this.item.identifier && !this.multiSelect;
}
},
mounted() {
this.openmct.selection.on('change', this.updateSelection);
this.updateSelection(this.openmct.selection.get());
},
beforeDestroy() {
this.openmct.selection.off('change', this.updateSelection);
},
methods: {
updateSelection(selection) {
if (selection.length === 0 || selection[0].length === 0) {
this.domainObject = {};
return;
}
if (selection.length > 1) {
this.multiSelect = true;
this.domainObject = {};
this.itemsSelected = selection.length;
return;
} else {
this.multiSelect = false;
this.domainObject = selection[0][0].context.item;
}
}
}
}
</script>

View File

@ -1,72 +1,72 @@
<template>
<div class="c-properties c-properties--properties">
<div class="c-properties__header">
Properties
<div class="c-inspector__properties c-inspect-properties">
<div class="c-inspect-properties__header">
Details
</div>
<ul
v-if="!multiSelect && !singleSelectNonObject"
class="c-properties__section"
class="c-inspect-properties__section"
>
<li class="c-properties__row">
<div class="c-properties__label">
<li class="c-inspect-properties__row">
<div class="c-inspect-properties__label">
Title
</div>
<div class="c-properties__value">
<div class="c-inspect-properties__value">
{{ item.name }}
</div>
</li>
<li class="c-properties__row">
<div class="c-properties__label">
<li class="c-inspect-properties__row">
<div class="c-inspect-properties__label">
Type
</div>
<div class="c-properties__value">
<div class="c-inspect-properties__value">
{{ typeName }}
</div>
</li>
<li
v-if="item.created"
class="c-properties__row"
class="c-inspect-properties__row"
>
<div class="c-properties__label">
<div class="c-inspect-properties__label">
Created
</div>
<div class="c-properties__value">
<div class="c-inspect-properties__value">
{{ formatTime(item.created) }}
</div>
</li>
<li
v-if="item.modified"
class="c-properties__row"
class="c-inspect-properties__row"
>
<div class="c-properties__label">
<div class="c-inspect-properties__label">
Modified
</div>
<div class="c-properties__value">
<div class="c-inspect-properties__value">
{{ formatTime(item.modified) }}
</div>
</li>
<li
v-for="prop in typeProperties"
:key="prop.name"
class="c-properties__row"
class="c-inspect-properties__row"
>
<div class="c-properties__label">
<div class="c-inspect-properties__label">
{{ prop.name }}
</div>
<div class="c-properties__value">
<div class="c-inspect-properties__value">
{{ prop.value }}
</div>
</li>
</ul>
<div
v-if="multiSelect"
class="c-properties__row--span-all"
class="c-inspect-properties__row--span-all"
>
No properties to display for multiple items
</div>
<div
v-if="singleSelectNonObject"
class="c-properties__row--span-all"
class="c-inspect-properties__row--span-all"
>
No properties to display for this item
</div>

View File

@ -1,10 +1,7 @@
<template>
<div></div>
<div class="u-contents"></div>
</template>
<style>
</style>
<script>
import ConditionalStylesView from '../../plugins/condition/components/inspector/ConditionalStylesView.vue';
import Vue from 'vue';
@ -34,17 +31,18 @@ export default {
},
updateSelection(selection) {
if (selection.length > 0 && selection[0].length > 0) {
let isChildItem = false;
let domainObject = selection[0][0].context.item;
let layoutItem = {};
let styleProps = this.getStyleProperties({
fill: 'inherit',
stroke: 'inherit',
color: 'inherit'
fill: 'transparent',
stroke: 'transparent',
color: 'transparent'
});
if (selection[0].length > 1) {
isChildItem = true;
//If there are more than 1 items in the selection[0] list, the first one could either be a sub domain object OR a layout drawing control.
//The second item in the selection[0] list is the container object (usually a layout)
domainObject = selection[0][0].context.item;
if (!domainObject) {
styleProps = {};
layoutItem = selection[0][0].context.layoutItem;
@ -58,7 +56,6 @@ export default {
this.component = undefined;
this.$el.innerHTML = '';
}
let viewContainer = document.createElement('div');
this.$el.append(viewContainer);
this.component = new Vue({
@ -73,10 +70,11 @@ export default {
data() {
return {
layoutItem,
styleProps
styleProps,
isChildItem
}
},
template: '<conditional-styles-view :item-id="layoutItem.id" :initial-styles="styleProps"></conditional-styles-view>'
template: '<conditional-styles-view :can-hide="isChildItem" :item-id="layoutItem.id" :initial-styles="styleProps"></conditional-styles-view>'
});
}
}

View File

@ -1,21 +1,46 @@
.c-inspector {
height: 100%;
display: flex;
flex: 1 1 auto;
flex-direction: column;
> [class*="__"] {
min-height: 50px;
> * {
// Thi is on purpose: want extra margin on top object-name element
margin-top: $interiorMargin;
}
+ [class*="__"] {
margin-top: $interiorMargin;
&__selected-w,
&__multiple-selected-w {
@include headerFont(1.1em);
padding: $interiorMarginSm 0;
}
&__multiple-selected-w {
$p: $interiorMarginLg;
background: rgba($colorWarningLo, 0.3);
border-radius: $basicCr;
display: inline-block;
font-style: italic;
padding-left: $p;
padding-right: $p;
}
&__selected {
@include ellipsize();
flex: 1 1 auto;
&--non-domain-object {
font-style: italic;
}
}
> .l-pane__contents {
overflow: auto;
&__tabs {
flex: 0 0 auto;
font-size: 0.8em;
text-transform: uppercase;
}
> * {
// Fend off scrollbar
margin-right: $interiorMarginSm;
}
}
&__content {
flex: 1 1 auto;
}
&__elements {
@ -58,67 +83,41 @@
margin-left: $treeItemIndent;
}
&__tabs {
$h: 20px;
@include abs();
display: flex;
flex-flow: column nowrap;
> * + * {
margin-top: $interiorMargin;
}
&__holder {
display: flex;
min-height: $h;
&__header {
&:before {
margin-right: $interiorMarginSm;
opacity: 0.7;
}
}
}
&__contents {
flex: 1 1 auto;
display: flex;
flex-direction: column;
&--hidden {
height: 1000px;
width: 1000px;
position: absolute;
left: -9999px;
top: -9999px;
}
.l-multipane {
.l-pane {
min-height: 50px;
}
}
}
.c-properties {
display: grid;
grid-row-gap: 0;
grid-template-columns: 1fr 2fr;
align-items: start;
min-width: 150px;
.c-inspect-properties,
.c-inspect-styles {
[class*="header"] {
@include propertiesHeader();
flex: 0 0 auto;
font-size: .85em;
text-transform: uppercase;
&:not(:first-child) {
// Allow multiple headers within a component
margin-top: $interiorMarginLg;
}
}
}
/********************************************* INSPECTOR PROPERTIES TAB */
.c-inspect-properties {
display: grid;
grid-row-gap: $interiorMarginSm;
grid-template-columns: 1fr 2fr;
align-items: start;
min-width: 150px;
[class*="span-all"],
[class*="header"] {
grid-column: 1 / 3;
}
+ .c-properties {
+ .c-inspect-properties {
margin-top: $interiorMarginLg;
}
@ -136,11 +135,6 @@
}
}
&__header {
font-size: .85em;
text-transform: uppercase;
}
&__label,
&__value {
padding: 3px $interiorMarginLg 3px 0;
@ -164,6 +158,7 @@
}
}
}
/********************************************* LEGACY SUPPORT */
.c-inspector {
// FilterField.vue

View File

@ -7,11 +7,11 @@
@click="goToParent"
></button>
<div
class="l-browse-bar__object-name--w"
class="l-browse-bar__object-name--w c-object-label"
:class="type.cssClass"
>
<span
class="l-browse-bar__object-name c-input-inline"
class="l-browse-bar__object-name c-object-label__name c-input-inline"
contenteditable
@blur="updateName"
@keydown.enter.prevent

View File

@ -35,9 +35,15 @@
display: flex;
flex-flow: column nowrap;
overflow-x: hidden;
}
}
&__pane-tree,
&__pane-main {
.l-pane__contents {
> * {
flex: 0 0 auto;
+ * {
margin-top: $interiorMarginLg;
}

View File

@ -1,6 +1,7 @@
.c-tree-and-search {
display: flex;
flex-direction: column;
flex: 1 1 auto;
padding-right: $interiorMarginSm;
overflow: auto;
@ -136,3 +137,11 @@
}
}
}
.c-selector {
.c-tree-and-search__tree.c-tree {
border: 1px solid $colorInteriorBorder;
border-radius: $controlCr;
padding: $interiorMargin;
}
}

View File

@ -15,6 +15,9 @@
&--vertical {
height: 100%;
> .l-pane .l-pane__contents {
padding-right: $interiorMarginSm; // Fend off scrollbar
}
}
}
@ -90,9 +93,6 @@
// Don't pad all nested __contents
padding: 0;
}
> [class*="__"] + [class*="__"] {
}
}
/************************************************ DESKTOP STYLES */
@ -263,6 +263,8 @@
}
&[class*="--vertical"] {
// l-pane--vertical
> .l-pane__handle {
cursor: row-resize;
left: 0;

View File

@ -36,7 +36,7 @@ export default {
},
methods: {
onClick(event) {
if (this.options.dialog) {
if ((this.options.isEditing === undefined || this.options.isEditing) && this.options.dialog) {
this.openmct.$injector.get('dialogService')
.getUserInput(this.options.dialog, this.options.value)
.then(value => {

View File

@ -4,7 +4,7 @@
class="c-icon-button c-icon-button--swatched"
:class="[options.icon, {'c-icon-button--mixed': nonSpecific}]"
:title="options.title"
@click="toggle"
@click="handleClick"
>
<div
class="c-swatch"
@ -146,6 +146,11 @@ export default {
if (color.value !== this.options.value) {
this.$emit('change', color.value, this.options);
}
},
handleClick(event) {
if ((this.options.isEditing === undefined) || this.options.isEditing) {
this.toggle(event);
}
}
}
}

View File

@ -32,7 +32,9 @@ export default {
},
methods: {
cycle() {
this.$emit('change', this.nextValue.value, this.options);
if (this.options.isEditing === undefined || this.options.isEditing) {
this.$emit('change', this.nextValue.value, this.options);
}
}
}
};