Compare commits
1 Commits
maelstrom2
...
fix-failin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3dc6dac12d |
@@ -1,487 +0,0 @@
|
||||
export default {
|
||||
'telemetry': {
|
||||
type: 'folder',
|
||||
name: 'Maelstrom Telemetry',
|
||||
type: 'folder',
|
||||
location: 'ROOT',
|
||||
composition: [
|
||||
{
|
||||
namespace: 'maelstrom',
|
||||
key: 'velocity'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'acceleration-ms-2'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'acceleration-g'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'distance'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'distance-m'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'roll'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'pitch'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'yaw'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'event-index'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'event-time-str'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'ring'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'next-los'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'evr-1'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'evr-2'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'evr-3'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'evr-4'
|
||||
},{
|
||||
namespace: 'maelstrom',
|
||||
key: 'evr-5'
|
||||
}
|
||||
]
|
||||
},
|
||||
'velocity': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'Velocity',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "Velocity",
|
||||
"units": "ms",
|
||||
"format": "float",
|
||||
"source": "velocity",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'acceleration-ms-2': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'Acceleration (ms^-2)',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "Acceleration",
|
||||
"units": "ms^-2",
|
||||
"format": "float",
|
||||
"source": "acceleration-ms-2",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'acceleration-g': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'Acceleration (G)',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "Acceleration",
|
||||
"units": "ms^-2",
|
||||
"format": "float",
|
||||
"source": "acceleration-g",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'distance': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'Distance (km)',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "Distance",
|
||||
"units": "km",
|
||||
"format": "float",
|
||||
"source": "distance-km",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'distance-m': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'Distance (m)',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "Distance Meters",
|
||||
"units": "m",
|
||||
"format": "float",
|
||||
"source": "distance-m",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'roll': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'Roll',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "Roll",
|
||||
"units": "degrees",
|
||||
"format": "float",
|
||||
"source": "roll",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'pitch': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'Pitch',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "Pitch",
|
||||
"units": "degrees",
|
||||
"format": "float",
|
||||
"source": "pitch",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'yaw': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'Yaw',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "Yaw",
|
||||
"units": "degrees",
|
||||
"format": "float",
|
||||
"source": "yaw",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'event-index': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'Event Index',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "Event Index",
|
||||
"units": "i",
|
||||
"format": "float",
|
||||
"source": "event-index",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'event-time-str': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'Event Time Str',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "Event Time Str",
|
||||
"units": "",
|
||||
"format": "string",
|
||||
"source": "event-time-str",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'ring': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'Ring',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "Ring",
|
||||
"units": "",
|
||||
"format": "int",
|
||||
"source": "ring",
|
||||
"hints": {
|
||||
"range": 24
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'next-los': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'Next LOS',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "Next LOS",
|
||||
"units": "",
|
||||
"format": "string",
|
||||
"source": "next-los",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'evr-1': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'EVR 1',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "EVR-1",
|
||||
"units": "",
|
||||
"format": "string",
|
||||
"source": "evr-1",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'evr-2': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'EVR 2',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "EVR-2",
|
||||
"units": "",
|
||||
"format": "string",
|
||||
"source": "evr-2",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'evr-3': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'EVR 3',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "EVR-3",
|
||||
"units": "",
|
||||
"format": "string",
|
||||
"source": "evr-3",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'evr-4': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'EVR 4',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "EVR-4",
|
||||
"units": "",
|
||||
"format": "string",
|
||||
"source": "evr-4",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
},
|
||||
'evr-5': {
|
||||
type: 'maelstrom-telemetry',
|
||||
location: 'maelstrom:telemetry',
|
||||
name: 'EVR 5',
|
||||
telemetry: {
|
||||
values: [{
|
||||
"key": "value",
|
||||
"name": "EVR-5",
|
||||
"units": "",
|
||||
"format": "string",
|
||||
"source": "evr-5",
|
||||
"hints": {
|
||||
"range": 1
|
||||
}
|
||||
}, {
|
||||
"key": "utc",
|
||||
"source": "event_time",
|
||||
"name": "Time",
|
||||
"format": "utc-diy",
|
||||
"hints": {
|
||||
"domain": 1
|
||||
}
|
||||
}
|
||||
]}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -45,8 +45,6 @@
|
||||
].forEach(
|
||||
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
|
||||
);
|
||||
openmct.install(openmct.plugins.Bignumbers());
|
||||
openmct.install(openmct.plugins.Gauge());
|
||||
openmct.install(openmct.plugins.MyItems());
|
||||
openmct.install(openmct.plugins.LocalStorage());
|
||||
openmct.install(openmct.plugins.Generator());
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License atw
|
||||
* 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
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'./components/bignumbers.vue',
|
||||
'vue'
|
||||
], function (
|
||||
BignumbersComponent,
|
||||
Vue
|
||||
) {
|
||||
function Bignumbers(openmct) {
|
||||
return {
|
||||
key: 'bignumbers',
|
||||
name: 'Bignumbers',
|
||||
cssClass: 'icon-telemetry',
|
||||
canView: function (domainObject) {
|
||||
return domainObject.type === 'bignumbers';
|
||||
},
|
||||
canEdit: function (domainObject) {
|
||||
return domainObject.type === 'bignumbers';
|
||||
},
|
||||
view: function (domainObject) {
|
||||
let component;
|
||||
|
||||
return {
|
||||
show: function (element) {
|
||||
component = new Vue({
|
||||
components: {
|
||||
BignumbersComponent: BignumbersComponent.default
|
||||
},
|
||||
provide: {
|
||||
openmct,
|
||||
domainObject,
|
||||
composition: openmct.composition.get(domainObject)
|
||||
},
|
||||
el: element,
|
||||
template: '<bignumbers-component></bignumbers-component>'
|
||||
});
|
||||
},
|
||||
destroy: function (element) {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
}
|
||||
};
|
||||
},
|
||||
priority: function () {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
return Bignumbers;
|
||||
});
|
||||
@@ -1,131 +0,0 @@
|
||||
<template>
|
||||
<div class="c-bignumbers">
|
||||
<svg class="c-bignumbers__int" viewBox="0 0 52 32">
|
||||
<text textLength=100% lengthAdjust=spacingAndGlyphs x="0" y="32">{{ this.curValInt }}</text>
|
||||
</svg>
|
||||
<svg class="c-bignumbers__dec" viewBox="0 0 40 20">
|
||||
<text textLength=100% lengthAdjust=spacing x="0" y="20">.{{ this.curValDec }}</text>
|
||||
</svg>
|
||||
<svg class="c-bignumbers__units" viewBox="0 0 45 11">
|
||||
<text textLength=100% lengthAdjust=spacingAndGlyphs x="0" y="11">{{ this.units }}</text>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
.c-bignumbers {
|
||||
$w1: 53%;
|
||||
|
||||
@include abs();
|
||||
bottom: auto;
|
||||
padding-bottom: 33%;
|
||||
|
||||
&__int,
|
||||
&__dec,
|
||||
&__units {
|
||||
position: absolute;
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
&__int,
|
||||
&__dec {
|
||||
font-family: $heroFont;
|
||||
}
|
||||
|
||||
&__int {
|
||||
font-size: 51px;
|
||||
opacity: 0.8;
|
||||
width: $w1;
|
||||
}
|
||||
|
||||
&__dec {
|
||||
left: $w1;
|
||||
font-size: 32px;
|
||||
opacity: 0.4;
|
||||
width: 100% - $w1;
|
||||
}
|
||||
|
||||
&__units {
|
||||
font-size: 9px;
|
||||
font-family: $headerFont;
|
||||
left: $w1;
|
||||
bottom: 0;
|
||||
opacity: 0.2;
|
||||
width: 99% - $w1; // Font has different char spacing, so use reduced width
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "bignumbers",
|
||||
inject: ['openmct', 'domainObject', 'composition'],
|
||||
data: function () {
|
||||
let config = this.domainObject.configuration,
|
||||
units = config.units;
|
||||
console.log(config);
|
||||
return {
|
||||
curValInt: 0,
|
||||
curValDec: 0,
|
||||
units: units
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getInt: function(val, digits) {
|
||||
// Extract integer portion of val and zero-pad it if its length < digits
|
||||
return this.zeroPad(Math.floor(val), digits);
|
||||
},
|
||||
getDec: function(val, digits) {
|
||||
// Extract decimal portion of val to the specified number of digits
|
||||
return Number.parseFloat(val).toFixed(digits).split('.')[1];
|
||||
},
|
||||
zeroPad: function(val, length) {
|
||||
// Zero pads an integer and returns it as a string
|
||||
let s = Math.abs(val).toString();
|
||||
if (s.length < length) {
|
||||
for (let i = 0; i <= (length - s.length); i++) {
|
||||
s = '0' + s;
|
||||
}
|
||||
}
|
||||
if (val < 0) {
|
||||
s = '-' + s;
|
||||
}
|
||||
return s;
|
||||
},
|
||||
updateValue(datum) {
|
||||
let cv = this.formats[this.valueKey].format(datum);
|
||||
this.curValInt = this.getInt(cv, 3);
|
||||
this.curValDec = this.getDec(cv, 3);
|
||||
},
|
||||
subscribe(domainObject) {
|
||||
this.metadata = this.openmct.telemetry.getMetadata(domainObject);
|
||||
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
|
||||
|
||||
this.valueKey = this
|
||||
.metadata
|
||||
.valuesForHints(['range'])[0].key;
|
||||
this.unsubscribe = this.openmct
|
||||
.telemetry
|
||||
.subscribe(domainObject, this.updateValue.bind(this), {});
|
||||
this.openmct
|
||||
.telemetry
|
||||
.request(domainObject, {strategy: 'latest'})
|
||||
.then((values) => values.forEach(this.updateValue));
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
mounted() {
|
||||
this.composition.on('add', this.subscribe);
|
||||
this.composition.load();
|
||||
},
|
||||
destroyed() {
|
||||
this.composition.off('add', this.subscribe);
|
||||
this.unsubscribe();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,58 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'./bignumbers'
|
||||
], function (
|
||||
Bignumbers
|
||||
) {
|
||||
return function plugin() {
|
||||
return function install(openmct) {
|
||||
openmct.objectViews.addProvider(new Bignumbers(openmct));
|
||||
|
||||
openmct.types.addType('bignumbers', {
|
||||
name: "Big Numbers",
|
||||
creatable: true,
|
||||
description: "Display the value of a telemetry element with units in a stylized numeric view.",
|
||||
cssClass: 'icon-telemetry',
|
||||
initialize(domainObject) {
|
||||
domainObject.composition = [];
|
||||
domainObject.configuration = {
|
||||
units: ''
|
||||
};
|
||||
},
|
||||
form: [
|
||||
{
|
||||
name: "Units",
|
||||
control: "textfield",
|
||||
cssClass: "",
|
||||
key: "units",
|
||||
property: [
|
||||
"configuration",
|
||||
"units"
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
};
|
||||
});
|
||||
@@ -1,19 +1,20 @@
|
||||
<template>
|
||||
<div class="u-contents c-filter-settings">
|
||||
<li class="grid-row c-filter-settings__setting"
|
||||
<div class="c-properties__section c-filter-settings">
|
||||
<li class="c-properties__row c-filter-settings__setting"
|
||||
v-for="(filter, index) in filterField.filters"
|
||||
:key="index">
|
||||
<div class="grid-cell label">
|
||||
<div class="c-properties__label label"
|
||||
:disabled="useGlobal">
|
||||
{{ filterField.name }} =
|
||||
</div>
|
||||
<div class="grid-cell value">
|
||||
<div class="c-properties__value value">
|
||||
<!-- EDITING -->
|
||||
<!-- String input, editing -->
|
||||
<template v-if="!filter.possibleValues && isEditing">
|
||||
<input class="c-input--flex"
|
||||
type="text"
|
||||
placeholder="Enter Value"
|
||||
:id="`${filter}filterControl`"
|
||||
:disabled="useGlobal"
|
||||
:value="persistedValue(filter)"
|
||||
@change="updateFilterValue($event, filter)">
|
||||
</template>
|
||||
@@ -21,15 +22,16 @@
|
||||
<!-- Checkbox list, editing -->
|
||||
<template v-if="filter.possibleValues && isEditing">
|
||||
<div class="c-checkbox-list__row"
|
||||
v-for="value in filter.possibleValues"
|
||||
:key="value">
|
||||
v-for="option in filter.possibleValues"
|
||||
:key="option.value">
|
||||
<input class="c-checkbox-list__input"
|
||||
type="checkbox"
|
||||
:id="`${value}filterControl`"
|
||||
@change="onUserSelect($event, filter.comparator, value)"
|
||||
:checked="isChecked(filter.comparator, value)">
|
||||
:id="`${option.value}filterControl`"
|
||||
:disabled="useGlobal"
|
||||
@change="updateFilterValue($event, filter.comparator, option.value)"
|
||||
:checked="isChecked(filter.comparator, option.value)">
|
||||
<span class="c-checkbox-list__value">
|
||||
{{ value }}
|
||||
{{ option.label }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -42,9 +44,8 @@
|
||||
|
||||
<!-- Checkbox list, NOT editing -->
|
||||
<template v-if="filter.possibleValues && !isEditing">
|
||||
<span
|
||||
v-if="persistedFilters[filter.comparator]">
|
||||
{{persistedFilters[filter.comparator].join(', ')}}
|
||||
<span v-if="persistedFilters[filter.comparator]">
|
||||
{{ getFilterLabels(filter) }}
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
@@ -52,26 +53,14 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
.c-filter-settings {
|
||||
&__setting {
|
||||
.grid-cell.label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: [
|
||||
'openmct'
|
||||
],
|
||||
props: {
|
||||
filterField: Object,
|
||||
filterField: Object,
|
||||
useGlobal: Boolean,
|
||||
persistedFilters: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
@@ -81,7 +70,6 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expanded: false,
|
||||
isEditing: this.openmct.editor.isEditing()
|
||||
}
|
||||
},
|
||||
@@ -89,9 +77,6 @@ export default {
|
||||
toggleIsEditing(isEditing) {
|
||||
this.isEditing = isEditing;
|
||||
},
|
||||
onUserSelect(event, comparator, value){
|
||||
this.$emit('onUserSelect', this.filterField.key, comparator, value, event.target.checked);
|
||||
},
|
||||
isChecked(comparator, value) {
|
||||
if (this.persistedFilters[comparator] && this.persistedFilters[comparator].includes(value)) {
|
||||
return true;
|
||||
@@ -102,8 +87,25 @@ export default {
|
||||
persistedValue(comparator) {
|
||||
return this.persistedFilters && this.persistedFilters[comparator];
|
||||
},
|
||||
updateFilterValue(event, comparator) {
|
||||
this.$emit('onTextEnter', this.filterField.key, comparator, event.target.value);
|
||||
updateFilterValue(event, comparator, value) {
|
||||
if (value !== undefined) {
|
||||
this.$emit('filterSelected', this.filterField.key, comparator, value, event.target.checked);
|
||||
} else {
|
||||
this.$emit('filterTextValueChanged', this.filterField.key, comparator, event.target.value);
|
||||
}
|
||||
},
|
||||
getFilterLabels(filter) {
|
||||
return this.persistedFilters[filter.comparator].reduce((accum, filterValue) => {
|
||||
accum.push(filter.possibleValues.reduce((label, possibleValue) => {
|
||||
if (filterValue === possibleValue.value) {
|
||||
label = possibleValue.label;
|
||||
}
|
||||
|
||||
return label;
|
||||
}, ''));
|
||||
|
||||
return accum;
|
||||
}, []).join(', ');
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<template>
|
||||
<li>
|
||||
<li class="c-tree__item-h">
|
||||
<div class="c-tree__item menus-to-left"
|
||||
@click="toggleExpanded">
|
||||
<div class="c-filter-tree-item__filter-indicator"
|
||||
:class="{'icon-filter': hasActiveFilters }"></div>
|
||||
<span class="c-disclosure-triangle is-enabled flex-elem"
|
||||
:class="{'c-disclosure-triangle--expanded': expanded}"></span>
|
||||
<div class="c-tree__item__label">
|
||||
<div class="c-tree__item__label c-object-label">
|
||||
<div class="c-object-label">
|
||||
<div class="c-object-label__type-icon"
|
||||
:class="objectCssClass">
|
||||
@@ -13,30 +15,47 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="grid-properties" v-if="expanded">
|
||||
<filter-field
|
||||
v-for="field in filterObject.valuesWithFilters"
|
||||
:key="field.key"
|
||||
:filterField="field"
|
||||
:persistedFilters="persistedFilters[field.key]"
|
||||
@onUserSelect="collectUserSelects"
|
||||
@onTextEnter="updateTextFilter">
|
||||
</filter-field>
|
||||
</ul>
|
||||
|
||||
<div v-if="expanded">
|
||||
<ul class="c-properties">
|
||||
<div class="c-properties__label span-all"
|
||||
v-if="!isEditing && persistedFilters.useGlobal">
|
||||
Uses global filter
|
||||
</div>
|
||||
|
||||
<div class="c-properties__label span-all"
|
||||
v-if="isEditing">
|
||||
<toggle-switch
|
||||
:id="keyString"
|
||||
@change="useGlobalFilter"
|
||||
:checked="persistedFilters.useGlobal">
|
||||
</toggle-switch>
|
||||
Use global filter
|
||||
</div>
|
||||
<filter-field
|
||||
v-if="(!persistedFilters.useGlobal && !isEditing) || isEditing"
|
||||
v-for="metadatum in filterObject.metadataWithFilters"
|
||||
:key="metadatum.key"
|
||||
:filterField="metadatum"
|
||||
:useGlobal="persistedFilters.useGlobal"
|
||||
:persistedFilters="updatedFilters[metadatum.key]"
|
||||
@filterSelected="updateFiltersWithSelectedValue"
|
||||
@filterTextValueChanged="updateFiltersWithTextValue">
|
||||
</filter-field>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import FilterField from './FilterField.vue';
|
||||
import ToggleSwitch from '../../../ui/components/ToggleSwitch.vue';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
components: {
|
||||
FilterField
|
||||
FilterField,
|
||||
ToggleSwitch
|
||||
},
|
||||
props: {
|
||||
filterObject: Object,
|
||||
@@ -51,58 +70,74 @@ export default {
|
||||
return {
|
||||
expanded: false,
|
||||
objectCssClass: undefined,
|
||||
updatedFilters: this.persistedFilters
|
||||
updatedFilters: JSON.parse(JSON.stringify(this.persistedFilters)),
|
||||
isEditing: this.openmct.editor.isEditing()
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
persistedFilters: {
|
||||
handler: function checkFilters(newpersistedFilters) {
|
||||
this.updatedFilters = JSON.parse(JSON.stringify(newpersistedFilters));
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasActiveFilters() {
|
||||
// Should be true when the user has entered any filter values.
|
||||
return Object.values(this.persistedFilters).some(comparator => {
|
||||
return (typeof(comparator) === 'object' && !_.isEmpty(comparator));
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleExpanded() {
|
||||
this.expanded = !this.expanded;
|
||||
},
|
||||
collectUserSelects(key, comparator, valueName, value) {
|
||||
updateFiltersWithSelectedValue(key, comparator, valueName, value) {
|
||||
let filterValue = this.updatedFilters[key];
|
||||
|
||||
if (filterValue && filterValue[comparator]) {
|
||||
if (value === false) {
|
||||
let filteredValueName = filterValue[comparator].filter(v => v !== valueName);
|
||||
|
||||
if (filteredValueName.length === 0) {
|
||||
delete this.updatedFilters[key];
|
||||
} else {
|
||||
filterValue[comparator] = filteredValueName;
|
||||
}
|
||||
} else {
|
||||
if (filterValue[comparator]) {
|
||||
if (value === true) {
|
||||
filterValue[comparator].push(valueName);
|
||||
} else {
|
||||
if (filterValue[comparator].length === 1) {
|
||||
this.$set(this.updatedFilters, key, {});
|
||||
} else {
|
||||
filterValue[comparator] = filterValue[comparator].filter(v => v !== valueName);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!this.updatedFilters[key]) {
|
||||
this.$set(this.updatedFilters, key, {});
|
||||
}
|
||||
this.$set(this.updatedFilters[key], comparator, [value ? valueName : undefined]);
|
||||
this.$set(this.updatedFilters[key], comparator, [valueName]);
|
||||
}
|
||||
|
||||
this.$emit('updateFilters', this.keyString, this.updatedFilters);
|
||||
},
|
||||
updateTextFilter(key, comparator, value) {
|
||||
updateFiltersWithTextValue(key, comparator, value) {
|
||||
if (value.trim() === '') {
|
||||
if (this.updatedFilters[key]) {
|
||||
delete this.updatedFilters[key];
|
||||
this.$emit('updateFilters', this.keyString, this.updatedFilters);
|
||||
}
|
||||
return;
|
||||
this.$set(this.updatedFilters, key, {});
|
||||
} else {
|
||||
this.$set(this.updatedFilters[key], comparator, value);
|
||||
}
|
||||
|
||||
if (!this.updatedFilters[key]) {
|
||||
this.$set(this.updatedFilters, key, {});
|
||||
this.$set(this.updatedFilters[key], comparator, '');
|
||||
}
|
||||
this.updatedFilters[key][comparator] = value;
|
||||
this.$emit('updateFilters', this.keyString, this.updatedFilters);
|
||||
}
|
||||
},
|
||||
useGlobalFilter(checked) {
|
||||
this.updatedFilters.useGlobal = checked;
|
||||
this.$emit('updateFilters', this.keyString, this.updatedFilters, checked);
|
||||
},
|
||||
toggleIsEditing(isEditing) {
|
||||
this.isEditing = isEditing;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
let type = this.openmct.types.get(this.filterObject.domainObject.type) || {};
|
||||
this.keyString = this.openmct.objects.makeKeyString(this.filterObject.domainObject.identifier);
|
||||
this.objectCssClass = type.definition.cssClass;
|
||||
this.openmct.editor.on('isEditing', this.toggleIsEditing);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.openmct.editor.off('isEditing', this.toggleIsEditing);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
<template>
|
||||
<ul class="tree c-tree c-properties__section" v-if="Object.keys(children).length">
|
||||
<h2 class="c-properties__header">Filters</h2>
|
||||
<ul class="c-tree c-filter-tree" v-if="Object.keys(children).length">
|
||||
<h2>Data Filters</h2>
|
||||
<div class="c-filter-indication"
|
||||
v-if="hasActiveFilters">{{ label }}
|
||||
</div>
|
||||
<global-filters
|
||||
:globalFilters="globalFilters"
|
||||
:globalMetadata="globalMetadata"
|
||||
@persistGlobalFilters="persistGlobalFilters">
|
||||
</global-filters>
|
||||
<filter-object
|
||||
v-for="(child, key) in children"
|
||||
:key="key"
|
||||
@@ -12,80 +20,230 @@
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
.c-inspector {
|
||||
.c-filter-indication {
|
||||
border-radius: $smallCr;
|
||||
font-size: inherit;
|
||||
padding: $interiorMarginSm $interiorMargin;
|
||||
text-transform: inherit;
|
||||
}
|
||||
.c-filter-tree {
|
||||
// Filters UI uses a tree-based structure
|
||||
.c-properties {
|
||||
// Add extra margin to account for filter-indicator
|
||||
margin-left: 38px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import FilterObject from './FilterObject.vue';
|
||||
import FilterObject from './FilterObject.vue';
|
||||
import GlobalFilters from './GlobalFilters.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FilterObject
|
||||
},
|
||||
inject: [
|
||||
'openmct'
|
||||
],
|
||||
data() {
|
||||
let providedObject = this.openmct.selection.get()[0][0].context.item;
|
||||
let persistedFilters = {};
|
||||
const FILTER_VIEW_TITLE = 'Filters applied';
|
||||
const FILTER_VIEW_TITLE_MIXED = 'Mixed filters applied';
|
||||
const USE_GLOBAL = 'useGlobal';
|
||||
|
||||
if (providedObject.configuration && providedObject.configuration.filters) {
|
||||
persistedFilters = providedObject.configuration.filters;
|
||||
}
|
||||
export default {
|
||||
components: {
|
||||
FilterObject,
|
||||
GlobalFilters
|
||||
},
|
||||
inject: [
|
||||
'openmct'
|
||||
],
|
||||
data() {
|
||||
let providedObject = this.openmct.selection.get()[0][0].context.item;
|
||||
let configuration = providedObject.configuration;
|
||||
|
||||
return {
|
||||
providedObject,
|
||||
persistedFilters,
|
||||
children: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addChildren(child) {
|
||||
let keyString = this.openmct.objects.makeKeyString(child.identifier),
|
||||
metadata = this.openmct.telemetry.getMetadata(child),
|
||||
valuesWithFilters = metadata.valueMetadatas.filter((value) => value.filters),
|
||||
childObject = {
|
||||
name: child.name,
|
||||
domainObject: child,
|
||||
valuesWithFilters
|
||||
};
|
||||
|
||||
if (childObject.valuesWithFilters.length) {
|
||||
this.$set(this.children, keyString, childObject);
|
||||
} else {
|
||||
return;
|
||||
return {
|
||||
persistedFilters: (configuration && configuration.filters) || {},
|
||||
globalFilters: (configuration && configuration.globalFilters) || {},
|
||||
globalMetadata: {},
|
||||
providedObject,
|
||||
children: {}
|
||||
}
|
||||
},
|
||||
removeChildren(identifier) {
|
||||
let keyString = this.openmct.objects.makeKeyString(identifier);
|
||||
this.$delete(this.children, keyString);
|
||||
delete this.persistedFilters[keyString];
|
||||
this.mutateConfigurationFilters();
|
||||
computed: {
|
||||
hasActiveFilters() {
|
||||
// Should be true when the user has entered any filter values.
|
||||
return Object.values(this.persistedFilters).some(filters => {
|
||||
return Object.values(filters).some(comparator => {
|
||||
return (typeof(comparator) === 'object' && !_.isEmpty(comparator));
|
||||
});
|
||||
});
|
||||
},
|
||||
hasMixedFilters() {
|
||||
// Should be true when filter values are mixed.
|
||||
let filtersToCompare = _.omit(this.persistedFilters[Object.keys(this.persistedFilters)[0]], [USE_GLOBAL]);
|
||||
return Object.values(this.persistedFilters).some(filters => {
|
||||
return !_.isEqual(filtersToCompare, _.omit(filters, [USE_GLOBAL]));
|
||||
});
|
||||
},
|
||||
label() {
|
||||
if (this.hasActiveFilters) {
|
||||
if (this.hasMixedFilters) {
|
||||
return FILTER_VIEW_TITLE_MIXED;
|
||||
} else {
|
||||
return FILTER_VIEW_TITLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
persistFilters(keyString, userSelects) {
|
||||
this.persistedFilters[keyString] = userSelects;
|
||||
this.mutateConfigurationFilters();
|
||||
methods: {
|
||||
addChildren(domainObject) {
|
||||
let keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||
let metadata = this.openmct.telemetry.getMetadata(domainObject);
|
||||
let metadataWithFilters = metadata.valueMetadatas.filter(value => value.filters);
|
||||
let hasFiltersWithKeyString = this.persistedFilters[keyString] !== undefined;
|
||||
let mutateFilters = false;
|
||||
let childObject = {
|
||||
name: domainObject.name,
|
||||
domainObject: domainObject,
|
||||
metadataWithFilters
|
||||
};
|
||||
|
||||
if (metadataWithFilters.length) {
|
||||
this.$set(this.children, keyString, childObject);
|
||||
|
||||
metadataWithFilters.forEach(metadatum => {
|
||||
if (!this.globalFilters[metadatum.key]) {
|
||||
this.$set(this.globalFilters, metadatum.key, {});
|
||||
}
|
||||
|
||||
if (!this.globalMetadata[metadatum.key]) {
|
||||
this.$set(this.globalMetadata, metadatum.key, metadatum);
|
||||
}
|
||||
|
||||
if (!hasFiltersWithKeyString) {
|
||||
if (!this.persistedFilters[keyString]) {
|
||||
this.$set(this.persistedFilters, keyString, {});
|
||||
this.$set(this.persistedFilters[keyString], 'useGlobal', true);
|
||||
mutateFilters = true;
|
||||
}
|
||||
|
||||
this.$set(this.persistedFilters[keyString], metadatum.key, this.globalFilters[metadatum.key]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (mutateFilters) {
|
||||
this.mutateConfigurationFilters();
|
||||
}
|
||||
},
|
||||
removeChildren(identifier) {
|
||||
let keyString = this.openmct.objects.makeKeyString(identifier);
|
||||
let globalFiltersToRemove = this.getGlobalFiltersToRemove(keyString);
|
||||
|
||||
if (globalFiltersToRemove.length > 0) {
|
||||
globalFiltersToRemove.forEach(key => {
|
||||
this.$delete(this.globalFilters, key);
|
||||
this.$delete(this.globalMetadata, key);
|
||||
});
|
||||
this.mutateConfigurationGlobalFilters();
|
||||
}
|
||||
|
||||
this.$delete(this.children, keyString);
|
||||
this.$delete(this.persistedFilters, keyString);
|
||||
this.mutateConfigurationFilters();
|
||||
},
|
||||
getGlobalFiltersToRemove(keyString) {
|
||||
let filtersToRemove = new Set();
|
||||
|
||||
this.children[keyString].metadataWithFilters.forEach(metadatum => {
|
||||
let keepFilter = false
|
||||
Object.keys(this.children).forEach(childKeyString => {
|
||||
if (childKeyString !== keyString) {
|
||||
let filterMatched = this.children[childKeyString].metadataWithFilters.some(childMetadatum => childMetadatum.key === metadatum.key);
|
||||
|
||||
if (filterMatched) {
|
||||
keepFilter = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!keepFilter) {
|
||||
filtersToRemove.add(metadatum.key);
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(filtersToRemove);
|
||||
},
|
||||
persistFilters(keyString, updatedFilters, useGlobalValues) {
|
||||
this.persistedFilters[keyString] = updatedFilters;
|
||||
|
||||
if (useGlobalValues) {
|
||||
Object.keys(this.persistedFilters[keyString]).forEach(key => {
|
||||
if (typeof(this.persistedFilters[keyString][key]) === 'object') {
|
||||
this.persistedFilters[keyString][key] = this.globalFilters[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.mutateConfigurationFilters();
|
||||
},
|
||||
updatePersistedFilters(filters) {
|
||||
this.persistedFilters = filters;
|
||||
},
|
||||
persistGlobalFilters(key, filters) {
|
||||
this.globalFilters[key] = filters[key];
|
||||
this.mutateConfigurationGlobalFilters();
|
||||
let mutateFilters = false;
|
||||
|
||||
Object.keys(this.children).forEach(keyString => {
|
||||
if (this.persistedFilters[keyString].useGlobal !== false && this.containsField(keyString, key)) {
|
||||
if (!this.persistedFilters[keyString][key]) {
|
||||
this.$set(this.persistedFilters[keyString], key, {});
|
||||
}
|
||||
|
||||
this.$set(this.persistedFilters[keyString], key, filters[key]);
|
||||
mutateFilters = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (mutateFilters) {
|
||||
this.mutateConfigurationFilters();
|
||||
}
|
||||
},
|
||||
updateGlobalFilters(filters) {
|
||||
this.globalFilters = filters;
|
||||
},
|
||||
containsField(keyString, field) {
|
||||
let hasField = false;
|
||||
this.children[keyString].metadataWithFilters.forEach(metadatum => {
|
||||
if (metadatum.key === field) {
|
||||
hasField = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
return hasField;
|
||||
},
|
||||
mutateConfigurationFilters() {
|
||||
this.openmct.objects.mutate(this.providedObject, 'configuration.filters', this.persistedFilters);
|
||||
},
|
||||
mutateConfigurationGlobalFilters() {
|
||||
this.openmct.objects.mutate(this.providedObject, 'configuration.globalFilters', this.globalFilters);
|
||||
}
|
||||
},
|
||||
updatePersistedFilters(filters) {
|
||||
this.persistedFilters = filters;
|
||||
mounted(){
|
||||
this.composition = this.openmct.composition.get(this.providedObject);
|
||||
this.composition.on('add', this.addChildren);
|
||||
this.composition.on('remove', this.removeChildren);
|
||||
this.composition.load();
|
||||
this.unobserve = this.openmct.objects.observe(this.providedObject, 'configuration.filters', this.updatePersistedFilters);
|
||||
this.unobserveGlobalFilters = this.openmct.objects.observe(this.providedObject, 'configuration.globalFilters', this.updateGlobalFilters);
|
||||
this.unobserveAllMutation = this.openmct.objects.observe(this.providedObject, '*', (mutatedObject) => this.providedObject = mutatedObject);
|
||||
},
|
||||
mutateConfigurationFilters() {
|
||||
this.openmct.objects.mutate(this.providedObject, 'configuration.filters', this.persistedFilters);
|
||||
beforeDestroy() {
|
||||
this.composition.off('add', this.addChildren);
|
||||
this.composition.off('remove', this.removeChildren);
|
||||
this.unobserve();
|
||||
this.unobserveGlobalFilters();
|
||||
this.unobserveAllMutation();
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
this.composition = this.openmct.composition.get(this.providedObject);
|
||||
this.composition.on('add', this.addChildren);
|
||||
this.composition.on('remove', this.removeChildren);
|
||||
this.composition.load();
|
||||
this.unobserve = this.openmct.objects.observe(this.providedObject, 'configuration.filters', this.updatePersistedFilters);
|
||||
this.unobserveAllMutation = this.openmct.objects.observe(this.providedObject, '*', (mutatedObject) => this.providedObject = mutatedObject);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.composition.off('add', this.addChildren);
|
||||
this.composition.off('remove', this.removeChildren);
|
||||
this.unobserve();
|
||||
this.unobserveAllMutation();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
134
src/plugins/filters/components/GlobalFilters.vue
Normal file
134
src/plugins/filters/components/GlobalFilters.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<li class="c-tree__item-h">
|
||||
<div class="c-tree__item menus-to-left"
|
||||
@click="toggleExpanded">
|
||||
<div class="c-filter-tree-item__filter-indicator"
|
||||
:class="{'icon-filter': hasActiveGlobalFilters }"></div>
|
||||
<span class="c-disclosure-triangle is-enabled flex-elem"
|
||||
:class="{'c-disclosure-triangle--expanded': expanded}"></span>
|
||||
<div class="c-tree__item__label c-object-label">
|
||||
<div class="c-object-label">
|
||||
<div class="c-object-label__type-icon icon-gear"></div>
|
||||
<div class="c-object-label__name flex-elem grows">Global Filtering</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="c-properties" v-if="expanded">
|
||||
<filter-field
|
||||
v-for="metadatum in globalMetadata"
|
||||
:key="metadatum.key"
|
||||
:filterField="metadatum"
|
||||
:persistedFilters="updatedFilters[metadatum.key]"
|
||||
@filterSelected="updateFiltersWithSelectedValue"
|
||||
@filterTextValueChanged="updateFiltersWithTextValue">
|
||||
</filter-field>
|
||||
</ul>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
.c-filter-indication {
|
||||
// Appears as a block element beneath tables
|
||||
@include userSelectNone();
|
||||
background: $colorFilterBg;
|
||||
color: $colorFilterFg;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 0.9em;
|
||||
margin-top: $interiorMarginSm;
|
||||
padding: 2px;
|
||||
text-transform: uppercase;
|
||||
|
||||
&:before {
|
||||
font-family: symbolsfont-12px;
|
||||
content: $glyph-icon-filter;
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
.c-filter-tree-item {
|
||||
&__filter-indicator {
|
||||
color: $colorFilter;
|
||||
width: 1.2em; // Set width explicitly for layout reasons: will either have class icon-filter, or none.
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import FilterField from './FilterField.vue';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
components: {
|
||||
FilterField
|
||||
},
|
||||
props: {
|
||||
globalMetadata: Object,
|
||||
globalFilters: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expanded: false,
|
||||
updatedFilters: JSON.parse(JSON.stringify(this.globalFilters))
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasActiveGlobalFilters() {
|
||||
return Object.values(this.globalFilters).some(field => {
|
||||
return Object.values(field).some(comparator => {
|
||||
return (comparator && (comparator !== '' || comparator.length > 0));
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
globalFilters: {
|
||||
handler: function checkFilters(newGlobalFilters) {
|
||||
this.updatedFilters = JSON.parse(JSON.stringify(newGlobalFilters));
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleExpanded() {
|
||||
this.expanded = !this.expanded;
|
||||
},
|
||||
updateFiltersWithSelectedValue(key, comparator, valueName, value) {
|
||||
let filterValue = this.updatedFilters[key];
|
||||
|
||||
if (filterValue[comparator]) {
|
||||
if (value === true) {
|
||||
filterValue[comparator].push(valueName);
|
||||
} else {
|
||||
if (filterValue[comparator].length === 1) {
|
||||
this.$set(this.updatedFilters, key, {});
|
||||
} else {
|
||||
filterValue[comparator] = filterValue[comparator].filter(v => v !== valueName);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.$set(this.updatedFilters[key], comparator, [valueName]);
|
||||
}
|
||||
|
||||
this.$emit('persistGlobalFilters', key, this.updatedFilters);
|
||||
},
|
||||
updateFiltersWithTextValue(key, comparator, value) {
|
||||
if (value.trim() === '') {
|
||||
this.$set(this.updatedFilters, key, {});
|
||||
} else {
|
||||
this.$set(this.updatedFilters[key], comparator, value);
|
||||
}
|
||||
|
||||
this.$emit('persistGlobalFilters', key, this.updatedFilters);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -21,7 +21,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'./filtersInspectorViewProvider'
|
||||
'./FiltersInspectorViewProvider'
|
||||
], function (
|
||||
FiltersInspectorViewProvider
|
||||
) {
|
||||
|
||||
@@ -1,202 +0,0 @@
|
||||
<template>
|
||||
<div class="c-gauge">
|
||||
<div class="c-gauge__wrapper">
|
||||
<svg class="c-gauge__range" viewBox="0 0 512 512">
|
||||
<text class="c-gauge__curval" transform="translate(256 310)" text-anchor="middle">{{ this.curVal }}</text>
|
||||
<text font-size="35" transform="translate(105 455) rotate(-45)"
|
||||
v-if="displayMinMax">{{ this.rangeLow }}</text>
|
||||
<text font-size="35" transform="translate(407 455) rotate(45)" text-anchor="end"
|
||||
v-if="displayMinMax">{{ this.rangeHigh }}</text>
|
||||
</svg>
|
||||
|
||||
<div class="c-dial">
|
||||
<svg class="c-dial__bg" viewBox="0 0 512 512">
|
||||
<g>
|
||||
<path d="M256,0C114.6,0,0,114.6,0,256S114.6,512,256,512,512,397.4,512,256,397.4,0,256,0Zm0,412A156,156,0,1,1,412,256,155.9,155.9,0,0,1,256,412Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<svg class="c-dial__limit" viewBox="0 0 512 512"
|
||||
v-if="degLimit < 270"
|
||||
:class="{
|
||||
'c-limit-clip--90': this.degLimit > 90,
|
||||
'c-limit-clip--180': this.degLimit >= 180
|
||||
}">
|
||||
<path d="M100,256A156,156,0,1,1,366.3,366.3L437,437a255.2,255.2,0,0,0,75-181C512,114.6,397.4,0,256,0S0,114.6,0,256A255.2,255.2,0,0,0,75,437l70.7-70.7A155.5,155.5,0,0,1,100,256Z"
|
||||
:style="`transform: rotate(${this.degLimit}deg)`"/>
|
||||
</svg>
|
||||
|
||||
<svg class="c-dial__value" viewBox="0 0 512 512"
|
||||
v-if="this.degValue > 0"
|
||||
:class="{
|
||||
'c-dial-clip--90': this.degValue < 90,
|
||||
'c-dial-clip--180': this.degValue >= 90 && this.degValue < 180
|
||||
}">
|
||||
<path d="M256,31A224.3,224.3,0,0,0,98.3,95.5l48.4,49.2a156,156,0,1,1-1,221.6L96.9,415.1A224.4,224.4,0,0,0,256,481c124.3,0,225-100.7,225-225S380.3,31,256,31Z"
|
||||
:style="`transform: rotate(${this.degValue}deg)`"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
.c-gauge {
|
||||
@include abs();
|
||||
overflow: hidden;
|
||||
|
||||
&__wrapper {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
padding-bottom: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__value {
|
||||
position: absolute;
|
||||
top: 50%; left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 3vw;
|
||||
}
|
||||
|
||||
&__range {
|
||||
$o: 21%;
|
||||
position: absolute;
|
||||
fill: rgba(#fff, 0.8);
|
||||
}
|
||||
|
||||
&__curval {
|
||||
font-family: $heroFont;
|
||||
font-size: 170px;
|
||||
}
|
||||
}
|
||||
|
||||
.c-dial {
|
||||
// Dial elements
|
||||
@include abs();
|
||||
clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 50%, 0 100%);
|
||||
|
||||
svg,
|
||||
&__ticks,
|
||||
&__bg,
|
||||
&__limit,
|
||||
&__value {
|
||||
@include abs();
|
||||
}
|
||||
|
||||
svg {
|
||||
path {
|
||||
transform-origin: center;
|
||||
}
|
||||
}
|
||||
|
||||
&__limit {
|
||||
&.c-limit-clip--90 {
|
||||
clip-path: polygon(0 0, 100% 0, 100% 100%);
|
||||
}
|
||||
|
||||
&.c-limit-clip--180 {
|
||||
clip-path: polygon(100% 0, 100% 100%, 0 100%);
|
||||
}
|
||||
|
||||
path {
|
||||
fill: rgba(orange, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
&__value {
|
||||
&.c-dial-clip--90 {
|
||||
clip-path: polygon(0 0, 50% 50%, 0 100%);
|
||||
}
|
||||
|
||||
&.c-dial-clip--180 {
|
||||
clip-path: polygon(0 0, 100% 0, 0 100%);
|
||||
}
|
||||
|
||||
path {
|
||||
fill: rgba(#fff, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
&__bg {
|
||||
g {
|
||||
fill: rgba(#fff, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "gaugeRadial",
|
||||
inject: ['openmct', 'domainObject', 'composition'],
|
||||
data: function () {
|
||||
let config = this.domainObject.configuration,
|
||||
rangeLow = config.min,
|
||||
rangeHigh = config.max,
|
||||
displayMinMax = config.displayMinMax,
|
||||
limit = config.limit,
|
||||
decimals = config.decimals;
|
||||
|
||||
return {
|
||||
rangeLow,
|
||||
rangeHigh,
|
||||
displayMinMax: displayMinMax.indexOf('Yes') !== -1,
|
||||
limit1: limit,
|
||||
decimals,
|
||||
curVal: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
round: function(val, decimals) {
|
||||
let precision = Math.pow(10, decimals);
|
||||
return Math.round(val * precision)/precision;
|
||||
},
|
||||
valToPercent: function(vValue) {
|
||||
// Don't let the current value exceed the high range, or the dial won't display right
|
||||
if (vValue >= this.rangeHigh) { return 100; }
|
||||
return ((vValue - this.rangeLow) / (this.rangeHigh - this.rangeLow)) * 100;
|
||||
},
|
||||
percentToDegrees: function(vPercent) {
|
||||
return this.round((vPercent/100)*270, 2);
|
||||
},
|
||||
updateValue(datum) {
|
||||
this.curVal = this.round(this.formats[this.valueKey].format(datum), this.decimals);
|
||||
},
|
||||
subscribe(domainObject) {
|
||||
this.metadata = this.openmct.telemetry.getMetadata(domainObject);
|
||||
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
|
||||
|
||||
this.valueKey = this
|
||||
.metadata
|
||||
.valuesForHints(['range'])[0].key;
|
||||
this.unsubscribe = this.openmct
|
||||
.telemetry
|
||||
.subscribe(domainObject, this.updateValue.bind(this), {});
|
||||
this.openmct
|
||||
.telemetry
|
||||
.request(domainObject, {strategy: 'latest'})
|
||||
.then((values) => values.forEach(this.updateValue));
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
degValue: function() {
|
||||
return this.percentToDegrees(this.valToPercent(this.curVal));
|
||||
},
|
||||
degLimit: function() {
|
||||
return this.percentToDegrees(this.valToPercent(this.limit1));
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.composition.on('add', this.subscribe);
|
||||
this.composition.load();
|
||||
},
|
||||
destroyed() {
|
||||
this.composition.off('add', this.subscribe);
|
||||
this.unsubscribe();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,71 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'./components/gaugeRadial.vue',
|
||||
'vue'
|
||||
], function (
|
||||
GaugeComponent,
|
||||
Vue
|
||||
) {
|
||||
function Gauge(openmct) {
|
||||
return {
|
||||
key: 'gauge',
|
||||
name: 'Gauge',
|
||||
cssClass: 'icon-gauge',
|
||||
canView: function (domainObject) {
|
||||
return domainObject.type === 'gauge';
|
||||
},
|
||||
canEdit: function (domainObject) {
|
||||
return domainObject.type === 'gauge';
|
||||
},
|
||||
view: function (domainObject) {
|
||||
let component;
|
||||
|
||||
return {
|
||||
show: function (element) {
|
||||
component = new Vue({
|
||||
components: {
|
||||
GaugeComponent: GaugeComponent.default
|
||||
},
|
||||
provide: {
|
||||
openmct,
|
||||
domainObject,
|
||||
composition: openmct.composition.get(domainObject)
|
||||
},
|
||||
el: element,
|
||||
template: '<gauge-component></gauge-component>'
|
||||
});
|
||||
},
|
||||
destroy: function (element) {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
}
|
||||
};
|
||||
},
|
||||
priority: function () {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
return Gauge;
|
||||
});
|
||||
@@ -1,102 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'./gauge'
|
||||
], function (
|
||||
Gauge
|
||||
) {
|
||||
return function plugin() {
|
||||
return function install(openmct) {
|
||||
openmct.objectViews.addProvider(new Gauge(openmct));
|
||||
|
||||
openmct.types.addType('gauge', {
|
||||
name: "Gauge",
|
||||
creatable: true,
|
||||
description: "Graphically visualize a telemetry element's current value between a minimum and maximum.",
|
||||
cssClass: 'icon-gauge',
|
||||
initialize(domainObject) {
|
||||
domainObject.composition = [];
|
||||
domainObject.configuration = {
|
||||
min: 0,
|
||||
max: 100,
|
||||
displayMinMax: 'Yes',
|
||||
limit: 90,
|
||||
decimals: 1
|
||||
};
|
||||
},
|
||||
form: [
|
||||
{
|
||||
name: "Minimum Value",
|
||||
control: "numberfield",
|
||||
cssClass: "l-input-sm l-numeric",
|
||||
key: "min",
|
||||
property: [
|
||||
"configuration",
|
||||
"min"
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Maximum Value",
|
||||
control: "numberfield",
|
||||
cssClass: "l-input-sm l-numeric",
|
||||
key: "max",
|
||||
property: [
|
||||
"configuration",
|
||||
"max"
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Display Min/Max",
|
||||
control: "textfield",
|
||||
cssClass: "l-input-sm",
|
||||
key: "displayMinMax",
|
||||
property: [
|
||||
"configuration",
|
||||
"displayMinMax"
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Limit",
|
||||
control: "numberfield",
|
||||
cssClass: "l-input-sm l-numeric",
|
||||
key: "min",
|
||||
property: [
|
||||
"configuration",
|
||||
"limit"
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Decimals",
|
||||
control: "numberfield",
|
||||
cssClass: "l-input-sm l-numeric",
|
||||
key: "decimals",
|
||||
property: [
|
||||
"configuration",
|
||||
"decimals"
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
};
|
||||
});
|
||||
@@ -44,9 +44,7 @@ define([
|
||||
'./filters/plugin',
|
||||
'./objectMigration/plugin',
|
||||
'./goToOriginalAction/plugin',
|
||||
'./clearData/plugin',
|
||||
'./gauge/plugin',
|
||||
'./bignumbers/plugin'
|
||||
'./clearData/plugin'
|
||||
], function (
|
||||
_,
|
||||
UTCTimeSystem,
|
||||
@@ -71,9 +69,7 @@ define([
|
||||
Filters,
|
||||
ObjectMigration,
|
||||
GoToOriginalAction,
|
||||
ClearData,
|
||||
Gauge,
|
||||
Bignumbers
|
||||
ClearData
|
||||
) {
|
||||
var bundleMap = {
|
||||
LocalStorage: 'platform/persistence/local',
|
||||
@@ -105,6 +101,7 @@ define([
|
||||
* to exclusively.
|
||||
*/
|
||||
plugins.AutoflowView = AutoflowPlugin;
|
||||
|
||||
plugins.Conductor = TimeConductorPlugin.default;
|
||||
|
||||
plugins.CouchDB = function (url) {
|
||||
@@ -172,8 +169,6 @@ define([
|
||||
plugins.ObjectMigration = ObjectMigration.default;
|
||||
plugins.GoToOriginalAction = GoToOriginalAction.default;
|
||||
plugins.ClearData = ClearData;
|
||||
plugins.Gauge = Gauge;
|
||||
plugins.Bignumbers = Bignumbers;
|
||||
|
||||
return plugins;
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div v-if="filterNames.length > 0"
|
||||
:title=title
|
||||
class="c-filter-indication"
|
||||
:class="{ 'c-filter-indication--mixed': mixed }">
|
||||
:class="{ 'c-filter-indication--mixed': hasMixedFilters }">
|
||||
<span class="c-filter-indication__mixed">{{ label }}</span>
|
||||
<span v-for="(name, index) in filterNames"
|
||||
class="c-filter-indication__label">
|
||||
@@ -33,7 +33,6 @@
|
||||
}
|
||||
|
||||
&__mixed {
|
||||
font-weight: bold;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
|
||||
@@ -58,119 +57,109 @@
|
||||
const FILTER_INDICATOR_LABEL_MIXED = 'Mixed Filters:';
|
||||
const FILTER_INDICATOR_TITLE = 'Data filters are being applied to this view.';
|
||||
const FILTER_INDICATOR_TITLE_MIXED = 'A mix of data filter values are being applied to this view.';
|
||||
const USE_GLOBAL = 'useGlobal';
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'table'],
|
||||
data() {
|
||||
return {
|
||||
filterNames: [],
|
||||
filteredTelemetry: {},
|
||||
mixed: false,
|
||||
label: '',
|
||||
title: ''
|
||||
filteredTelemetry: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isTelemetryObject(domainObject) {
|
||||
return domainObject.hasOwnProperty('telemetry');
|
||||
computed: {
|
||||
hasMixedFilters() {
|
||||
let filtersToCompare = _.omit(this.filteredTelemetry[Object.keys(this.filteredTelemetry)[0]], [USE_GLOBAL]);
|
||||
return Object.values(this.filteredTelemetry).some(filters => {
|
||||
return !_.isEqual(filtersToCompare, _.omit(filters, [USE_GLOBAL]));
|
||||
});
|
||||
},
|
||||
label() {
|
||||
if (this.hasMixedFilters) {
|
||||
return FILTER_INDICATOR_LABEL_MIXED;
|
||||
} else {
|
||||
return FILTER_INDICATOR_LABEL;
|
||||
}
|
||||
},
|
||||
title() {
|
||||
if (this.hasMixedFilters) {
|
||||
return FILTER_INDICATOR_TITLE_MIXED;
|
||||
} else {
|
||||
return FILTER_INDICATOR_TITLE;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setFilterNames() {
|
||||
let names = [];
|
||||
let composition = this.openmct.composition.get(this.table.configuration.domainObject);
|
||||
|
||||
this.composition && this.composition.load().then((domainObjects) => {
|
||||
composition && composition.load().then((domainObjects) => {
|
||||
domainObjects.forEach(telemetryObject => {
|
||||
let keyString= this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
let metadataValues = this.openmct.telemetry.getMetadata(telemetryObject).values();
|
||||
let filters = this.filteredTelemetry[keyString];
|
||||
this.telemetryKeyStrings.add(keyString);
|
||||
|
||||
if (filters !== undefined) {
|
||||
let metadataValues = this.openmct.telemetry.getMetadata(telemetryObject).values();
|
||||
Object.keys(filters).forEach(key => {
|
||||
metadataValues.forEach(metadaum => {
|
||||
|
||||
if (key === metadaum.key) {
|
||||
names.push(metadaum.name);
|
||||
}
|
||||
});
|
||||
});
|
||||
names.push(this.getFilterNamesFromMetadata(filters, metadataValues));
|
||||
}
|
||||
});
|
||||
this.filterNames = Array.from(new Set(names));
|
||||
|
||||
names = _.flatten(names);
|
||||
this.filterNames = names.length === 0 ? names : Array.from(new Set(names));
|
||||
});
|
||||
},
|
||||
getFilterNamesFromMetadata(filters, metadataValues) {
|
||||
let filterNames = [];
|
||||
filters = _.omit(filters, [USE_GLOBAL]);
|
||||
|
||||
Object.keys(filters).forEach(key => {
|
||||
if (!_.isEmpty(filters[key])) {
|
||||
metadataValues.forEach(metadatum => {
|
||||
if (key === metadatum.key) {
|
||||
if (typeof metadatum.filters[0] === "object") {
|
||||
filterNames.push(this.getFilterLabels(filters[key], metadatum));
|
||||
} else {
|
||||
filterNames.push(metadatum.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return _.flatten(filterNames);
|
||||
},
|
||||
getFilterLabels(filterObject, metadatum, ) {
|
||||
let filterLabels = [];
|
||||
Object.values(filterObject).forEach(comparator => {
|
||||
comparator.forEach(filterValue => {
|
||||
metadatum.filters[0].possibleValues.forEach(option => {
|
||||
if (option.value === filterValue) {
|
||||
filterLabels.push(option.label);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return filterLabels;
|
||||
},
|
||||
handleConfigurationChanges(configuration) {
|
||||
if (!_.eq(this.filteredTelemetry, configuration.filters)) {
|
||||
this.updateFilters(configuration.filters || {});
|
||||
}
|
||||
},
|
||||
checkFiltersForMixedValues() {
|
||||
let valueToCompare = this.filteredTelemetry[Object.keys(this.filteredTelemetry)[0]];
|
||||
let mixed = false;
|
||||
|
||||
Object.values(this.filteredTelemetry).forEach(value => {
|
||||
if (!_.isEqual(valueToCompare, value)) {
|
||||
mixed = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// If the filtered telemetry is not mixed at this point, check the number of available objects
|
||||
// with the number of filtered telemetry. If they are not equal, the filters must be mixed.
|
||||
if (mixed === false && _.size(this.filteredTelemetry) !== this.telemetryKeyStrings.size) {
|
||||
mixed = true;
|
||||
}
|
||||
|
||||
this.mixed = mixed;
|
||||
},
|
||||
setLabels() {
|
||||
if (this.mixed) {
|
||||
this.label = FILTER_INDICATOR_LABEL_MIXED;
|
||||
this.title = FILTER_INDICATOR_TITLE_MIXED;
|
||||
} else {
|
||||
this.label = FILTER_INDICATOR_LABEL;
|
||||
this.title = FILTER_INDICATOR_TITLE;
|
||||
}
|
||||
},
|
||||
updateFilters(filters) {
|
||||
this.filteredTelemetry = JSON.parse(JSON.stringify(filters));
|
||||
this.setFilterNames();
|
||||
this.updateIndicatorLabel();
|
||||
},
|
||||
addChildren(child) {
|
||||
let keyString = this.openmct.objects.makeKeyString(child.identifier);
|
||||
this.telemetryKeyStrings.add(keyString);
|
||||
this.updateIndicatorLabel();
|
||||
},
|
||||
removeChildren(identifier) {
|
||||
let keyString = this.openmct.objects.makeKeyString(identifier);
|
||||
this.telemetryKeyStrings.delete(keyString);
|
||||
this.updateIndicatorLabel();
|
||||
},
|
||||
updateIndicatorLabel() {
|
||||
this.checkFiltersForMixedValues();
|
||||
this.setLabels();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let filters = this.table.configuration.getConfiguration().filters || {};
|
||||
this.telemetryKeyStrings = new Set();
|
||||
this.composition = this.openmct.composition.get(this.table.configuration.domainObject);
|
||||
|
||||
if (this.composition) {
|
||||
this.composition.on('add', this.addChildren);
|
||||
this.composition.on('remove', this.removeChildren);
|
||||
}
|
||||
|
||||
this.table.configuration.on('change', this.handleConfigurationChanges);
|
||||
this.updateFilters(filters);
|
||||
},
|
||||
destroyed() {
|
||||
this.table.configuration.off('change', this.handleConfigurationChanges);
|
||||
|
||||
if (this.composition) {
|
||||
this.composition.off('add', this.addChildren);
|
||||
this.composition.off('remove', this.removeChildren);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
<div class="c-properties__header">Table Column Size</div>
|
||||
<ul class="c-properties__section">
|
||||
<li class="c-properties__row">
|
||||
<div class="c-properties__label" title="Show or Hide Column"><label for="AutoSizeControl">Auto-size</label></div>
|
||||
<div class="c-properties__label" title="Auto-size table"><label for="AutoSizeControl">Auto-size</label></div>
|
||||
<div class="c-properties__value"><input type="checkbox" id="AutoSizeControl" :checked="configuration.autosize !== false" @change="toggleAutosize()"></div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="c-properties__header">Table Column Visibility</div>
|
||||
<ul class="c-properties__section">
|
||||
<li class="c-properties__row" v-for="(title, key) in headers">
|
||||
<div class="c-properties__label" title="Show or Hide Column"><label :for="key + 'ColumnControl'">{{title}}</label></div>
|
||||
<div class="c-properties__label" title="Show or hide column"><label :for="key + 'ColumnControl'">{{title}}</label></div>
|
||||
<div class="c-properties__value"><input type="checkbox" :id="key + 'ColumnControl'" :checked="configuration.hiddenColumns[key] !== true" @change="toggleColumn(key)"></div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -116,6 +116,7 @@ $colorOk: #33cc33;
|
||||
$colorOkFg: #fff;
|
||||
$colorFilterBg: #44449c;
|
||||
$colorFilterFg: #8984e9;
|
||||
$colorFilter: $colorFilterFg; // Standalone against $colorBodyBg
|
||||
|
||||
// States
|
||||
$colorPausedBg: #ff9900;
|
||||
|
||||
@@ -36,10 +36,9 @@ $bodyFont: 'Chakra Petch', sans-serif;
|
||||
|
||||
@mixin headerFont($size: 1em) {
|
||||
font-family: $headerFont;
|
||||
font-size: $size;
|
||||
line-height: $size;
|
||||
font-size: $size * 0.8; // This font is comparatively large, so reduce it a bit
|
||||
text-transform: uppercase;
|
||||
word-spacing: 0.4em;
|
||||
word-spacing: 0.25em;
|
||||
}
|
||||
|
||||
@mixin bodyFont($size: 1em) {
|
||||
@@ -69,15 +68,12 @@ $shdwBtns: rgba(black, 0.2) 0 1px 2px;
|
||||
$shdwBtnsOverlay: rgba(black, 0.5) 0 1px 5px;
|
||||
|
||||
// Base colors
|
||||
$colorBodyBg: #000000;
|
||||
$colorBodyBg: #393939;
|
||||
$colorBodyFg: #ccc;
|
||||
$colorBodyFgEm: #fff;
|
||||
$colorGenBg: #222;
|
||||
$colorHeadBg: transparent;
|
||||
$colorHeadBg: #262626;
|
||||
$colorHeadFg: $colorBodyFg;
|
||||
$colorStatusBarBg: $colorHeadBg;
|
||||
$colorStatusBarFg: rgba(white, 0.5);
|
||||
$colorStatusBarFgHov: #aaa;
|
||||
$colorKey: #0099cc;
|
||||
$colorKeyFg: #fff;
|
||||
$colorKeyHov: #26d8ff;
|
||||
@@ -124,6 +120,7 @@ $colorOk: #33cc33;
|
||||
$colorOkFg: #fff;
|
||||
$colorFilterBg: #44449c;
|
||||
$colorFilterFg: #8984e9;
|
||||
$colorFilter: $colorFilterFg; // Standalone against $colorBodyBg
|
||||
|
||||
// States
|
||||
$colorPausedBg: #ff9900;
|
||||
@@ -189,7 +186,7 @@ $colorIconAliasForKeyFilter: #aaa;
|
||||
$colorTabsHolderBg: rgba(black, 0.2);
|
||||
|
||||
// Buttons and Controls
|
||||
$colorBtnBg: pullForward($colorBodyBg, 30%);
|
||||
$colorBtnBg: pullForward($colorBodyBg, 10%);
|
||||
$colorBtnBgHov: pullForward($colorBtnBg, 10%);
|
||||
$colorBtnFg: pullForward($colorBodyFg, 10%);
|
||||
$colorBtnReverseFg: pullForward($colorBtnFg, 10%);
|
||||
|
||||
@@ -42,31 +42,6 @@ $bodyFont: $heroFont;
|
||||
font-size: $size;
|
||||
}
|
||||
|
||||
// FONTS
|
||||
@import url('https://fonts.googleapis.com/css?family=Chakra+Petch:400,600,700|Michroma|Teko:400,700');
|
||||
|
||||
$heroFont: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
$headerFont: $heroFont;
|
||||
$bodyFont: $heroFont;
|
||||
|
||||
@mixin heroFont($size: 1em) {
|
||||
$mult: 1;
|
||||
font-family: $heroFont;
|
||||
font-size: $size * $mult;
|
||||
}
|
||||
|
||||
@mixin headerFont($size: 1em) {
|
||||
$mult: 1;
|
||||
font-family: $headerFont;
|
||||
font-size: $size * $mult;
|
||||
}
|
||||
|
||||
@mixin bodyFont($size: 1em) {
|
||||
$mult: 1;
|
||||
font-family: $bodyFont;
|
||||
font-size: $size * $mult;
|
||||
}
|
||||
|
||||
// Functions
|
||||
@function buttonBg($c: $colorBtnBg) {
|
||||
@return $c;
|
||||
@@ -141,6 +116,7 @@ $colorOk: #33cc33;
|
||||
$colorOkFg: #fff;
|
||||
$colorFilterBg: #a29fe2;
|
||||
$colorFilterFg: #fff;
|
||||
$colorFilter: $colorFilterBg; // Standalone against $colorBodyBg
|
||||
|
||||
// States
|
||||
$colorPausedBg: #ff9900;
|
||||
|
||||
@@ -93,7 +93,7 @@ $mobileMenuIconD: 24px; // Used
|
||||
$mobileTreeItemH: 35px; // Used
|
||||
|
||||
/************************** VISUAL */
|
||||
$controlDisabledOpacity: 0.3;
|
||||
$controlDisabledOpacity: 0.5;
|
||||
|
||||
/************************** UI ELEMENTS */
|
||||
/*************** Progress Bar */
|
||||
|
||||
@@ -202,6 +202,11 @@ body.desktop .has-local-controls {
|
||||
}
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
opacity: 0.5;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/******************************************************** STATES */
|
||||
@mixin spinner($b: 5px, $c: $colorKey) {
|
||||
animation-name: rotation-centered;
|
||||
|
||||
@@ -50,14 +50,14 @@
|
||||
}
|
||||
|
||||
/************************** EFFECTS */
|
||||
@mixin pulse($animName: 'pulse', $dur: 500ms, $iteration: infinite, $prop: opacity, $val0: 0, $val100: 1, $direction: alternate) {
|
||||
@keyframes #{$animName} {
|
||||
0% { #{$prop}: $val0; }
|
||||
100% { #{$prop}: $val100; }
|
||||
@mixin pulse($animName: pulse, $dur: 500ms, $iteration: infinite, $opacity0: 0.5, $opacity100: 1) {
|
||||
@keyframes pulse {
|
||||
0% { opacity: $opacity0; }
|
||||
100% { opacity: $opacity100; }
|
||||
}
|
||||
animation-name: $animName;
|
||||
animation-duration: $dur;
|
||||
animation-direction: $direction;
|
||||
animation-direction: alternate;
|
||||
animation-iteration-count: $iteration;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
@@ -1,447 +0,0 @@
|
||||
/**************************************************** CONSTANTS, MIXINS */
|
||||
$bgKey: #222632;
|
||||
$redKeyBg: #990000;
|
||||
$redKeyBrdr: #ff0000;
|
||||
$redKeyFg: rgba(white, 0.8);
|
||||
$ylwKeyBg: #cc6b36;
|
||||
$ylwKeyBrdr: #ffbf1a;
|
||||
$ylwKeyFg: rgba(white, 0.8);
|
||||
|
||||
@mixin widgetOk() {
|
||||
background-color: #bbb !important;
|
||||
border-color: #fff !important;
|
||||
color: #333 !important;
|
||||
}
|
||||
|
||||
@mixin widgetRed() {
|
||||
background-color: $redKeyBg !important;
|
||||
border-color: $redKeyBrdr !important;
|
||||
color: $redKeyFg !important;
|
||||
}
|
||||
|
||||
@mixin widgetYellow() {
|
||||
$c: $ylwKeyFg;
|
||||
background-color: $ylwKeyBg !important;
|
||||
border-color: $ylwKeyBrdr !important;
|
||||
color: $ylwKeyFg !important;
|
||||
}
|
||||
|
||||
/**************************************************** OVERRIDES */
|
||||
body {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.c-telemetry-view__value {
|
||||
justify-content: center;
|
||||
&[class*='is-limit'] {
|
||||
background: transparent !important;
|
||||
color: inherit !important;
|
||||
&:before { display: none; }
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************** CONVENIENCE */
|
||||
.u-inspectable[s-selected] {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.c-table.c-telemetry-table {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
|
||||
.widget-rule-content .t-rule-message-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/**************************************************** TIME CONDUCTOR */
|
||||
.c-conductor {
|
||||
&__controls {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.c-conductor__controls { display: flex !important; }
|
||||
}
|
||||
|
||||
[class*='__label'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&__end-fixed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&__end-delta {
|
||||
&:after {
|
||||
content: '';
|
||||
display: block;
|
||||
background: url('../ui/layout/assets/images/logo-app.svg') center no-repeat;
|
||||
background-size: contain;
|
||||
width: 100px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
&-input {
|
||||
input {
|
||||
&.c-input--datetime,
|
||||
&.c-input--hrs-min-sec {
|
||||
color: $colorTime;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
&.c-input--hrs-min-sec {
|
||||
width: 80px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************** MAIN LAYOUT */
|
||||
.l-shell {
|
||||
&:not(.is-editing) {
|
||||
.l-shell__head,
|
||||
.l-shell__main-view-browse-bar {
|
||||
background: none !important;
|
||||
height: $interiorMargin;
|
||||
overflow: hidden;
|
||||
padding: 0 !important;
|
||||
position: absolute;
|
||||
width: 30%;
|
||||
z-index: 100;
|
||||
|
||||
* { opacity: 0; }
|
||||
|
||||
&:hover {
|
||||
background: #666 !important;
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
padding: $interiorMargin !important;
|
||||
|
||||
* { opacity: 1; }
|
||||
}
|
||||
}
|
||||
|
||||
.l-shell__pane-main .l-pane__contents > * + * {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.l-shell__main-container {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.l-shell__main-view-browse-bar {
|
||||
top: -3px; right: 0;
|
||||
}
|
||||
|
||||
&__main > .l-pane {
|
||||
padding-left: $interiorMargin !important;
|
||||
padding-right: $interiorMargin !important;
|
||||
}
|
||||
|
||||
&__status { display: none !important; }
|
||||
}
|
||||
|
||||
.l-pane {
|
||||
&__contents {
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
&--collapsed {
|
||||
$d: 5px;
|
||||
flex-basis: $d !important;
|
||||
min-width: $d !important;
|
||||
min-height: $d !important;
|
||||
|
||||
.l-pane__label {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.l-pane__collapse-button {
|
||||
&:before { display: none !important; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************** STYLING BY TITLE */
|
||||
*[title*='font-euro'] {
|
||||
@include headerFont();
|
||||
}
|
||||
|
||||
*[title*='key-widget'] {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
*[title*='alert-red'] {
|
||||
.c-sw__icon {
|
||||
color: red !important;
|
||||
}
|
||||
}
|
||||
|
||||
*[title*='alert-yellow'] {
|
||||
.c-sw__icon {
|
||||
color: $ylwKeyBg !important;
|
||||
}
|
||||
}
|
||||
|
||||
*[title*='widget-ok'] {
|
||||
@include widgetOk();
|
||||
}
|
||||
|
||||
*[title*='widget-yellow'] {
|
||||
@include widgetYellow();
|
||||
}
|
||||
|
||||
*[title*='widget-red'] {
|
||||
@include widgetRed();
|
||||
}
|
||||
|
||||
*[title*='pulse-slow'] {
|
||||
@include pulse($animName: pulseSlow, $dur: 1000ms, $prop: filter, $val0: brightness(1.2), $val100: brightness(0.6), $direction: normal);
|
||||
.c-sw__icon {
|
||||
@include pulse($animName: pulseWarningIcon, $dur: 500ms, $prop: opacity, $val0: 0.1, $val100: 1, $direction: normal);
|
||||
}
|
||||
}
|
||||
|
||||
*[title*='pulse-fast'] {
|
||||
@include pulse($animName: pulseSlow, $dur: 250ms, $prop: filter, $val0: brightness(1.5), $val100: brightness(0.9), $direction: normal);
|
||||
}
|
||||
|
||||
*[title*='pulse-warning'] {
|
||||
@include pulse($animName: pulseWarning, $dur: 1500ms, $prop: filter, $val0: brightness(1.2), $val100: brightness(0.7), $direction: normal);
|
||||
}
|
||||
|
||||
*[title*='Bg Widget'] {
|
||||
// Widgets that provide a flashing red bg for components
|
||||
.c-summary-widget {
|
||||
$b: 5px;
|
||||
border: none !important;
|
||||
border-radius: $b * 4;
|
||||
&[title*='widget-yellow'] {
|
||||
opacity: 0.3;
|
||||
box-shadow: $ylwKeyBg 0px 0px $b $b;
|
||||
}
|
||||
|
||||
&[title*='widget-red'] {
|
||||
opacity: 0.4;
|
||||
box-shadow: $redKeyBg 0px 0px $b $b;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**************************************************** SECTIONS */
|
||||
/************* SYS OVW WIDGETS */
|
||||
*[title*='Sys Ovw'] {
|
||||
*[title*='Widget'] {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
*[title*='sys-ok'] {
|
||||
@include widgetOk();
|
||||
}
|
||||
|
||||
*[title*='post-ring'] {
|
||||
@include widgetRed();
|
||||
}
|
||||
}
|
||||
|
||||
/************* ATTITUDE */
|
||||
*[title*='Attitude'] {
|
||||
*[title*='RPY'] {
|
||||
background: black;
|
||||
padding: 3px;
|
||||
border-radius: 5px;
|
||||
|
||||
.l-control-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.l-view-section {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.gl-plot-axis-area.gl-plot-y {
|
||||
width: 22px !important;
|
||||
}
|
||||
|
||||
.gl-plot-wrapper-display-area-and-x-axis {
|
||||
left: 24px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************* VELOCITY COMPONENT */
|
||||
*[title*='-not-attained'] {
|
||||
@include widgetRed();
|
||||
}
|
||||
|
||||
/************* ACCELERATION COMPONENT */
|
||||
|
||||
/************* BOOST PHASE WIDGETS */
|
||||
*[title*='boost-phase-widget'] {
|
||||
.c-summary-widget {
|
||||
border-width: 2px;
|
||||
padding: 5px 0;
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*[title*='boost-phase-widget-left'] {
|
||||
.c-summary-widget {
|
||||
$c: #999;
|
||||
align-items: start;
|
||||
background: rgba($c, 0.1) !important;
|
||||
border-left: none;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
top: 25px; right: 0; bottom: 3%; left: 40%;
|
||||
}
|
||||
|
||||
&:before {
|
||||
@include bgStripes($c: $c, $a: 0.1, $bgsize: 20px, $angle: 0deg);
|
||||
}
|
||||
|
||||
&:after {
|
||||
@include bgStripes($c: $c, $a: 0.1, $bgsize: 63px, $angle: 0deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*[title*='boost-phase-widget-right'] {
|
||||
.c-summary-widget {
|
||||
$c: #555;
|
||||
border-right: none;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
|
||||
&:before {
|
||||
//background: deeppink;
|
||||
@include bgTicks($c: $c, $repeatDir: 'y');
|
||||
background-size: 100% 45px;
|
||||
top: 0px; right: 0; bottom: 0; left: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*[title*='Boost Phase Ring Widgets'] {
|
||||
*[title*='Ring Widget'] {
|
||||
//filter: saturate(0.7);
|
||||
}
|
||||
|
||||
*[title*='ring-ok'] {
|
||||
@include widgetOk();
|
||||
}
|
||||
|
||||
*[title*='bad-ring'] {
|
||||
@include widgetRed();
|
||||
}
|
||||
|
||||
*[title*='post-ring'] {
|
||||
@include widgetYellow();
|
||||
}
|
||||
}
|
||||
|
||||
/************* BOTTOM SYSTEM WIDGETS */
|
||||
*[title*='system-widget'] {
|
||||
background: $bgKey !important;
|
||||
border-width: 2px !important;
|
||||
justify-content: left !important;
|
||||
|
||||
.c-sw__icon {
|
||||
$m: $interiorMarginSm;
|
||||
position: absolute;
|
||||
bottom: $m;
|
||||
right: $m;
|
||||
}
|
||||
}
|
||||
|
||||
*[title*="Bottom System Widgets"] {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
*[title*='system-widget--hero'] {
|
||||
// Current "tab" in interface
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
*[title*='system-widget--subtle'] {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/**************************************************** INDIVIDUAL ELEMENTS */
|
||||
/************* PASSENGER NOTICE */
|
||||
*[title*='passenger-notice'] {
|
||||
font-size: 1.4em;
|
||||
.c-sw__icon {
|
||||
font-size: 2.1em;
|
||||
margin-right: $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*[title*='pulse-passenger-notice--nominal'] {
|
||||
@include pulse($animName: pulseNominal, $dur: 1000ms, $prop: filter, $val0: brightness(1.4), $val100:brightness(1.0), $direction: alternate);
|
||||
}
|
||||
|
||||
*[title*='pulse-passenger-notice--warning'] {
|
||||
@include pulse($animName: pulseWarning, $dur: 750ms, $prop: background-color, $val0: #aa0000, $val100: #340000, $direction: normal);
|
||||
}
|
||||
|
||||
*[title*='Main Console'] {
|
||||
$r: $basicCr;
|
||||
background: $bgKey;
|
||||
border-radius: $r;
|
||||
border-bottom: 2px solid rgb(102,102,102);
|
||||
}
|
||||
|
||||
*[title*='Event Time Str'] {
|
||||
@include heroFont(1.2em);
|
||||
line-height: .8em;
|
||||
}
|
||||
|
||||
|
||||
*[title*="Sys Ovw LAD Table"] {
|
||||
.c-lad-table {
|
||||
tr {
|
||||
background-color: black;
|
||||
color: rgba(white, 0.3);
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
align-items: center;
|
||||
height: 41px;
|
||||
border-radius: 5px;
|
||||
font-size: 0.75em;
|
||||
margin-bottom: 4px;
|
||||
overflow: hidden;
|
||||
padding: 3px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
thead,
|
||||
tr td:nth-child(1),
|
||||
tr td:nth-child(2) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
td {
|
||||
display: block;
|
||||
width: auto;
|
||||
white-space: normal;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,5 +34,3 @@
|
||||
@import "legacy";
|
||||
@import "legacy-plots";
|
||||
@import "legacy-messages";
|
||||
@import "theme-maelstrom";
|
||||
@import "movie-maelstrom";
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
@import "constants";
|
||||
@import "constants-mobile.scss";
|
||||
//@import "constants-espresso"; // TEMP
|
||||
//@import "constants-snow"; // TEMP
|
||||
@import "constants-maelstrom";
|
||||
@import "constants-snow"; // TEMP
|
||||
//@import "constants-maelstrom";
|
||||
@import "mixins";
|
||||
@import "animations";
|
||||
@@ -1,19 +0,0 @@
|
||||
/************* FRAMES */
|
||||
.c-so-view {
|
||||
&__header {
|
||||
transform: translateY(3px);
|
||||
}
|
||||
|
||||
&__header__name {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
&:not(.c-so-view--no-frame) {
|
||||
$bc: #666;
|
||||
$bLR: 3px solid transparent;
|
||||
$br: 20px;
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
align-items: center;
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
padding: $interiorMarginSm;
|
||||
padding: $interiorMarginSm 1px;
|
||||
white-space: nowrap;
|
||||
|
||||
&__name {
|
||||
|
||||
78
src/ui/components/ToggleSwitch.vue
Normal file
78
src/ui/components/ToggleSwitch.vue
Normal file
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<label class="c-toggle-switch">
|
||||
<input type="checkbox"
|
||||
:id="id"
|
||||
:checked="checked"
|
||||
@change="onUserSelect($event)"/>
|
||||
<span class="c-toggle-switch__slider"></span>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
.c-toggle-switch {
|
||||
$d: 12px;
|
||||
$m: 2px;
|
||||
$br: $d/1.5;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
display: inline;
|
||||
vertical-align: middle;
|
||||
|
||||
&__slider {
|
||||
background: $colorBtnBg; // TODO: make discrete theme constants for these colors
|
||||
border-radius: $br;
|
||||
//box-shadow: inset rgba($colorBtnFg, 0.4) 0 0 0 1px;
|
||||
display: inline-block;
|
||||
height: $d + ($m*2);
|
||||
position: relative;
|
||||
transform: translateY(2px); // TODO: get this to work without this kind of hack!
|
||||
width: $d*2 + $m*2;
|
||||
|
||||
&:before {
|
||||
// Knob
|
||||
background: $colorBtnFg; // TODO: make discrete theme constants for these colors
|
||||
border-radius: floor($br * 0.8);
|
||||
box-shadow: rgba(black, 0.4) 0 0 2px;
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: $d; width: $d;
|
||||
top: $m; left: $m; right: auto;
|
||||
transition: transform 100ms ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
||||
&:checked {
|
||||
+ .c-toggle-switch__slider {
|
||||
background: $colorKey; // TODO: make discrete theme constants for these colors
|
||||
&:before {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
id: String,
|
||||
checked: Boolean
|
||||
},
|
||||
methods: {
|
||||
onUserSelect(event) {
|
||||
this.$emit('change', event.target.checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -106,8 +106,10 @@
|
||||
display: contents;
|
||||
}
|
||||
|
||||
&__row + &__row {
|
||||
> [class*="__"] {
|
||||
&__row + &__row,
|
||||
&__section + &__section {
|
||||
[class*="__label"],
|
||||
[class*="__value"] {
|
||||
// Row borders, effected via border-top on child elements of the row
|
||||
border-top: 1px solid $colorInspectorSectionHeaderBg;
|
||||
}
|
||||
|
||||
@@ -81,6 +81,10 @@
|
||||
padding: $interiorMargin - $aPad;
|
||||
transition: background 150ms ease;
|
||||
|
||||
> * + * {
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $colorItemTreeHoverBg;
|
||||
.c-tree__item__type-icon:before {
|
||||
@@ -116,10 +120,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__view-control {
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
|
||||
// Object labels in trees
|
||||
&__label {
|
||||
// <a> tag that holds type icon and name.
|
||||
|
||||
Reference in New Issue
Block a user