Feature/eslint plugin vue (#2548)

* Use eslint-plugin-vue to lint vue files
This commit is contained in:
David Tsay 2019-12-04 12:39:09 -08:00 committed by Andrew Henry
parent 14ce5e159b
commit 14a0f84c1b
99 changed files with 5818 additions and 4877 deletions

View File

@ -5,9 +5,16 @@ module.exports = {
"jasmine": true, "jasmine": true,
"amd": true "amd": true
}, },
"extends": "eslint:recommended", "globals": {
"parser": "babel-eslint", "_": "readonly"
},
"extends": [
"eslint:recommended",
"plugin:vue/recommended"
],
"parser": "vue-eslint-parser",
"parserOptions": { "parserOptions": {
"parser": "babel-eslint",
"allowImportExportEverywhere": true, "allowImportExportEverywhere": true,
"ecmaVersion": 2015, "ecmaVersion": 2015,
"ecmaFeatures": { "ecmaFeatures": {
@ -58,7 +65,38 @@ module.exports = {
} }
], ],
"dot-notation": "error", "dot-notation": "error",
"indent": ["error", 4] "indent": ["error", 4],
"vue/html-indent": [
"error",
4,
{
"attribute": 1,
"baseIndent": 0,
"closeBracket": 0,
"alignAttributesVertically": true,
"ignores": []
}
],
"vue/html-self-closing": ["error",
{
"html": {
"void": "never",
"normal": "never",
"component": "always"
},
"svg": "always",
"math": "always"
}
],
"vue/max-attributes-per-line": ["error", {
"singleline": 1,
"multiline": {
"max": 1,
"allowFirstLine": true
}
}],
"vue/multiline-html-element-content-newline": "off",
"vue/singleline-html-element-content-newline": "off"
}, },
"overrides": [ "overrides": [
{ {

View File

@ -23,6 +23,7 @@
"d3-time": "1.0.x", "d3-time": "1.0.x",
"d3-time-format": "2.1.x", "d3-time-format": "2.1.x",
"eslint": "5.2.0", "eslint": "5.2.0",
"eslint-plugin-vue": "^6.0.0",
"eventemitter3": "^1.2.0", "eventemitter3": "^1.2.0",
"exports-loader": "^0.7.0", "exports-loader": "^0.7.0",
"express": "^4.13.1", "express": "^4.13.1",
@ -74,8 +75,8 @@
}, },
"scripts": { "scripts": {
"start": "node app.js", "start": "node app.js",
"lint": "eslint platform example src openmct.js", "lint": "eslint platform example src/**/*.{js,vue} openmct.js",
"lint:fix": "eslint platform example src openmct.js --fix", "lint:fix": "eslint platform example src/**/*.{js,vue} openmct.js --fix",
"build:prod": "NODE_ENV=production webpack", "build:prod": "NODE_ENV=production webpack",
"build:dev": "webpack", "build:dev": "webpack",
"build:watch": "webpack --watch", "build:watch": "webpack --watch",

View File

@ -1,14 +1,18 @@
<template> <template>
<div class="c-menu"> <div class="c-menu">
<ul> <ul>
<li v-for="action in actions" <li
v-for="action in actions"
:key="action.name" :key="action.name"
:class="action.cssClass" :class="action.cssClass"
:title="action.description" :title="action.description"
@click="action.invoke(objectPath)"> @click="action.invoke(objectPath)"
>
{{ action.name }} {{ action.name }}
</li> </li>
<li v-if="actions.length === 0">No actions defined.</li> <li v-if="actions.length === 0">
No actions defined.
</li>
</ul> </ul>
</div> </div>
</template> </template>

View File

@ -1,23 +1,31 @@
<template> <template>
<div class="c-message"> <div class="c-message">
<!--Uses flex-row --> <!--Uses flex-row -->
<div class="c-message__icon" <div
:class="['u-icon-bg-color-' + iconClass]"></div> class="c-message__icon"
:class="['u-icon-bg-color-' + iconClass]"
></div>
<div class="c-message__text"> <div class="c-message__text">
<!-- Uses flex-column --> <!-- Uses flex-column -->
<div class="c-message__title" <div
v-if="title"> v-if="title"
class="c-message__title"
>
{{ title }} {{ title }}
</div> </div>
<div class="c-message__hint" <div
v-if="hint"> v-if="hint"
class="c-message__hint"
>
{{ hint }} {{ hint }}
<span v-if="timestamp">[{{ timestamp }}]</span> <span v-if="timestamp">[{{ timestamp }}]</span>
</div> </div>
<div class="c-message__action-text" <div
v-if="message"> v-if="message"
class="c-message__action-text"
>
{{ message }} {{ message }}
</div> </div>
<slot></slot> <slot></slot>

View File

@ -1,25 +1,54 @@
<template> <template>
<div class="c-overlay"> <div class="c-overlay">
<div class="c-overlay__blocker" <div
@click="destroy"> class="c-overlay__blocker"
</div> @click="destroy"
></div>
<div class="c-overlay__outer"> <div class="c-overlay__outer">
<button class="c-click-icon c-overlay__close-button icon-x-in-circle" <button
v-if="dismissable" v-if="dismissable"
@click="destroy"> class="c-click-icon c-overlay__close-button icon-x-in-circle"
</button> @click="destroy"
<div class="c-overlay__contents" ref="element" tabindex="0"></div> ></button>
<div class="c-overlay__button-bar" v-if="buttons"> <div
<button class="c-button" ref="element"
tabindex="0" class="c-overlay__contents"
ref="buttons" ></div>
<div
v-if="buttons"
class="c-overlay__button-bar"
>
<button
v-for="(button, index) in buttons" v-for="(button, index) in buttons"
:key="index" :key="index"
@focus="focusIndex=index" class="c-button"
:class="{'c-button--major': focusIndex===index}" :class="{'c-button--major': button.emphasis}"
@click="buttonClickHandler(button.callback)"> @click="buttonClickHandler(button.callback)"
>
{{ button.label }} {{ button.label }}
</button> </button>
<div
ref="element"
class="c-overlay__contents"
tabindex="0"
></div>
<div
v-if="buttons"
class="c-overlay__button-bar"
>
<button
v-for="(button, index) in buttons"
ref="buttons"
:key="index"
class="c-button"
tabindex="0"
:class="{'c-button--major': focusIndex===index}"
@focus="focusIndex=index"
@click="buttonClickHandler(button.callback)"
>
{{ button.label }}
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -200,7 +229,7 @@
this.$emit('destroy'); this.$emit('destroy');
}, },
getElementForFocus: function () { getElementForFocus: function () {
const defaultElement = this.$refs.element;; const defaultElement = this.$refs.element;
if (!this.$refs.buttons) { if (!this.$refs.buttons) {
return defaultElement; return defaultElement;
} }

View File

@ -1,6 +1,6 @@
<template> <template>
<dialog-component> <dialog-component>
<progress-component :model="model"></progress-component> <progress-component :model="model" />
</dialog-component> </dialog-component>
</template> </template>
@ -14,9 +14,14 @@ import DialogComponent from './DialogComponent.vue';
export default { export default {
components: { components: {
DialogComponent: DialogComponent, DialogComponent: DialogComponent,
ProgressComponent: ProgressComponent, ProgressComponent: ProgressComponent
}, },
inject:['iconClass', 'title', 'hint', 'timestamp', 'message'], inject:['iconClass', 'title', 'hint', 'timestamp', 'message'],
props:['model'] props: {
model: {
type: Object,
required: true
}
}
} }
</script> </script>

View File

@ -44,6 +44,7 @@ define([
return { return {
show: function (element) { show: function (element) {
component = new Vue({ component = new Vue({
el: element,
components: { components: {
LadTableSet: LadTableSet.default LadTableSet: LadTableSet.default
}, },
@ -52,7 +53,6 @@ define([
domainObject, domainObject,
objectPath objectPath
}, },
el: element,
template: '<lad-table-set></lad-table-set>' template: '<lad-table-set></lad-table-set>'
}); });
}, },

View File

@ -44,6 +44,7 @@ define([
return { return {
show: function (element) { show: function (element) {
component = new Vue({ component = new Vue({
el: element,
components: { components: {
LadTableComponent: LadTableComponent.default LadTableComponent: LadTableComponent.default
}, },
@ -52,7 +53,6 @@ define([
domainObject, domainObject,
objectPath objectPath
}, },
el: element,
template: '<lad-table-component></lad-table-component>' template: '<lad-table-component></lad-table-component>'
}); });
}, },

View File

@ -44,7 +44,12 @@ const CONTEXT_MENU_ACTIONS = [
export default { export default {
inject: ['openmct', 'objectPath'], inject: ['openmct', 'objectPath'],
props: ['domainObject'], props: {
domainObject: {
type: Object,
required: true
}
},
data() { data() {
let currentObjectPath = this.objectPath.slice(); let currentObjectPath = this.objectPath.slice();
currentObjectPath.unshift(this.domainObject); currentObjectPath.unshift(this.domainObject);
@ -57,6 +62,47 @@ export default {
currentObjectPath currentObjectPath
} }
}, },
mounted() {
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
this.limitEvaluator = this.openmct
.telemetry
.limitEvaluator(this.domainObject);
this.stopWatchingMutation = this.openmct
.objects
.observe(
this.domainObject,
'*',
this.updateName
);
this.openmct.time.on('timeSystem', this.updateTimeSystem);
this.timestampKey = this.openmct.time.timeSystem().key;
this.valueMetadata = this
.metadata
.valuesForHints(['range'])[0];
this.valueKey = this.valueMetadata.key
this.unsubscribe = this.openmct
.telemetry
.subscribe(this.domainObject, this.updateValues);
this.openmct
.telemetry
.request(this.domainObject, {strategy: 'latest'})
.then((array) => this.updateValues(array[array.length - 1]));
},
destroyed() {
this.stopWatchingMutation();
this.unsubscribe();
this.openmct.off('timeSystem', this.updateTimeSystem);
},
methods: { methods: {
updateValues(datum) { updateValues(datum) {
this.timestamp = this.formats[this.timestampKey].format(datum); this.timestamp = this.formats[this.timestampKey].format(datum);
@ -88,47 +134,6 @@ export default {
showContextMenu(event) { showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS); this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
} }
},
mounted() {
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
this.limitEvaluator = openmct
.telemetry
.limitEvaluator(this.domainObject);
this.stopWatchingMutation = openmct
.objects
.observe(
this.domainObject,
'*',
this.updateName
);
this.openmct.time.on('timeSystem', this.updateTimeSystem);
this.timestampKey = this.openmct.time.timeSystem().key;
this.valueMetadata = this
.metadata
.valuesForHints(['range'])[0];
this.valueKey = this.valueMetadata.key
this.unsubscribe = this.openmct
.telemetry
.subscribe(this.domainObject, this.updateValues);
this.openmct
.telemetry
.request(this.domainObject, {strategy: 'latest'})
.then((array) => this.updateValues(array[array.length - 1]));
},
destroyed() {
this.stopWatchingMutation();
this.unsubscribe();
this.openmct.off('timeSystem', this.updateTimeSystem);
} }
} }
</script> </script>

View File

@ -33,14 +33,13 @@
<lad-row <lad-row
v-for="item in items" v-for="item in items"
:key="item.key" :key="item.key"
:domainObject="item.domainObject"> :domain-object="item.domainObject"
</lad-row> />
</tbody> </tbody>
</table> </table>
</template> </template>
<script> <script>
import lodash from 'lodash';
import LadRow from './LADRow.vue'; import LadRow from './LADRow.vue';
export default { export default {
@ -53,6 +52,18 @@ export default {
items: [] items: []
} }
}, },
mounted() {
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('add', this.addItem);
this.composition.on('remove', this.removeItem);
this.composition.on('reorder', this.reorder);
this.composition.load();
},
destroyed() {
this.composition.off('add', this.addItem);
this.composition.off('remove', this.removeItem);
this.composition.off('reorder', this.reorder);
},
methods: { methods: {
addItem(domainObject) { addItem(domainObject) {
let item = {}; let item = {};
@ -72,18 +83,6 @@ export default {
this.$set(this.items, reorderEvent.newIndex, oldItems[reorderEvent.oldIndex]); this.$set(this.items, reorderEvent.newIndex, oldItems[reorderEvent.oldIndex]);
}); });
} }
},
mounted() {
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('add', this.addItem);
this.composition.on('remove', this.removeItem);
this.composition.on('reorder', this.reorder);
this.composition.load();
},
destroyed() {
this.composition.off('add', this.addItem);
this.composition.off('remove', this.removeItem);
this.composition.off('reorder', this.reorder);
} }
} }
</script> </script>

View File

@ -31,16 +31,21 @@
</thead> </thead>
<tbody> <tbody>
<template <template
v-for="primary in primaryTelemetryObjects"> v-for="primary in primaryTelemetryObjects"
<tr class="c-table__group-header" >
:key="primary.key"> <tr
<td colspan="10">{{primary.domainObject.name}}</td> :key="primary.key"
class="c-table__group-header"
>
<td colspan="10">
{{ primary.domainObject.name }}
</td>
</tr> </tr>
<lad-row <lad-row
v-for="secondary in secondaryTelemetryObjects[primary.key]" v-for="secondary in secondaryTelemetryObjects[primary.key]"
:key="secondary.key" :key="secondary.key"
:domainObject="secondary.domainObject"> :domain-object="secondary.domainObject"
</lad-row> />
</template> </template>
</tbody> </tbody>
</table> </table>
@ -51,7 +56,6 @@
</style> </style>
<script> <script>
import lodash from 'lodash';
import LadRow from './LADRow.vue'; import LadRow from './LADRow.vue';
export default { export default {
@ -66,6 +70,22 @@
compositions: [] compositions: []
} }
}, },
mounted() {
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('add', this.addPrimary);
this.composition.on('remove', this.removePrimary);
this.composition.on('reorder', this.reorderPrimary);
this.composition.load();
},
destroyed() {
this.composition.off('add', this.addPrimary);
this.composition.off('remove', this.removePrimary);
this.composition.off('reorder', this.reorderPrimary);
this.compositions.forEach(c => {
c.composition.off('add', c.addCallback);
c.composition.off('remove', c.removeCallback);
});
},
methods: { methods: {
addPrimary(domainObject) { addPrimary(domainObject) {
let primary = {}; let primary = {};
@ -75,7 +95,7 @@
this.$set(this.secondaryTelemetryObjects, primary.key, []); this.$set(this.secondaryTelemetryObjects, primary.key, []);
this.primaryTelemetryObjects.push(primary); this.primaryTelemetryObjects.push(primary);
let composition = openmct.composition.get(primary.domainObject), let composition = this.openmct.composition.get(primary.domainObject),
addCallback = this.addSecondary(primary), addCallback = this.addSecondary(primary),
removeCallback = this.removeSecondary(primary); removeCallback = this.removeSecondary(primary);
@ -121,23 +141,6 @@
this.$set(this.secondaryTelemetryObjects, primary.key, array); this.$set(this.secondaryTelemetryObjects, primary.key, array);
} }
} }
},
mounted() {
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('add', this.addPrimary);
this.composition.on('remove', this.removePrimary);
this.composition.on('reorder', this.reorderPrimary);
this.composition.load();
},
destroyed() {
this.composition.off('add', this.addPrimary);
this.composition.off('remove', this.removePrimary);
this.composition.off('reorder', this.reorderPrimary);
this.compositions.forEach(c => {
c.composition.off('add', c.addCallback);
c.composition.off('remove', c.removeCallback);
});
} }
} }
</script> </script>

View File

@ -55,11 +55,11 @@ define([
openmct, openmct,
objectPath objectPath
}, },
el: element,
components: { components: {
AlphanumericFormatView: AlphanumericFormatView.default AlphanumericFormatView: AlphanumericFormatView.default
}, },
template: '<alphanumeric-format-view></alphanumeric-format-view>', template: '<alphanumeric-format-view></alphanumeric-format-view>'
el: element
}); });
}, },
destroy: function () { destroy: function () {

View File

@ -21,19 +21,28 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="c-properties" v-if="isEditing"> <div
<div class="c-properties__header">Alphanumeric Format</div> v-if="isEditing"
class="c-properties"
>
<div class="c-properties__header">
Alphanumeric Format
</div>
<ul class="c-properties__section"> <ul class="c-properties__section">
<li class="c-properties__row"> <li class="c-properties__row">
<div class="c-properties__label" title="Printf formatting for the selected telemetry"> <div
class="c-properties__label"
title="Printf formatting for the selected telemetry"
>
<label for="telemetryPrintfFormat">Format</label> <label for="telemetryPrintfFormat">Format</label>
</div> </div>
<div class="c-properties__value"> <div class="c-properties__value">
<input id="telemetryPrintfFormat" <input
id="telemetryPrintfFormat"
type="text" type="text"
@change="formatTelemetry"
:value="telemetryFormat" :value="telemetryFormat"
:placeholder="nonMixedFormat ? '' : 'Mixed'" :placeholder="nonMixedFormat ? '' : 'Mixed'"
@change="formatTelemetry"
> >
</div> </div>
</li> </li>
@ -45,13 +54,21 @@
export default { export default {
inject: ['openmct'], inject: ['openmct'],
data() { data() {
let selectionPath = this.openmct.selection.get()[0];
return { return {
isEditing: this.openmct.editor.isEditing(), isEditing: this.openmct.editor.isEditing(),
telemetryFormat: undefined, telemetryFormat: undefined,
nonMixedFormat: false nonMixedFormat: false
} }
}, },
mounted() {
this.openmct.editor.on('isEditing', this.toggleEdit);
this.openmct.selection.on('change', this.handleSelection);
this.handleSelection(this.openmct.selection.get());
},
destroyed() {
this.openmct.editor.off('isEditing', this.toggleEdit);
this.openmct.selection.off('change', this.handleSelection);
},
methods: { methods: {
toggleEdit(isEditing) { toggleEdit(isEditing) {
this.isEditing = isEditing; this.isEditing = isEditing;
@ -75,15 +92,6 @@
this.telemetryFormat = this.nonMixedFormat ? format : ''; this.telemetryFormat = this.nonMixedFormat ? format : '';
} }
},
mounted() {
this.openmct.editor.on('isEditing', this.toggleEdit);
this.openmct.selection.on('change', this.handleSelection);
this.handleSelection(this.openmct.selection.get());
},
destroyed() {
this.openmct.editor.off('isEditing', this.toggleEdit);
this.openmct.selection.off('change', this.handleSelection);
} }
} }

View File

@ -21,13 +21,16 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<layout-frame :item="item" <layout-frame
:item="item"
:grid-size="gridSize" :grid-size="gridSize"
@move="(gridDelta) => $emit('move', gridDelta)" @move="(gridDelta) => $emit('move', gridDelta)"
@endMove="() => $emit('endMove')"> @endMove="() => $emit('endMove')"
<div class="c-box-view" >
:style="style"> <div
</div> class="c-box-view"
:style="style"
></div>
</layout-frame> </layout-frame>
</template> </template>
@ -63,9 +66,20 @@
LayoutFrame LayoutFrame
}, },
props: { props: {
item: Object, item: {
gridSize: Array, type: Object,
index: Number, required: true
},
gridSize: {
type: Array,
required: true,
validator: (arr) => arr && arr.length === 2
&& arr.every(el => typeof el === 'number')
},
index: {
type: Number,
required: true
},
initSelect: Boolean initSelect: Boolean
}, },
computed: { computed: {
@ -100,4 +114,3 @@
} }
} }
</script> </script>

View File

@ -21,41 +21,48 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="l-layout" <div
class="l-layout"
:class="{
'is-multi-selected': selectedLayoutItems.length > 1
}"
@dragover="handleDragOver" @dragover="handleDragOver"
@click.capture="bypassSelection" @click.capture="bypassSelection"
@drop="handleDrop" @drop="handleDrop"
:class="{ >
'is-multi-selected': selectedLayoutItems.length > 1
}">
<!-- Background grid --> <!-- Background grid -->
<div class="l-layout__grid-holder c-grid"> <div class="l-layout__grid-holder c-grid">
<div class="c-grid__x l-grid l-grid-x" <div
v-if="gridSize[0] >= 3" v-if="gridSize[0] >= 3"
:style="[{ backgroundSize: gridSize[0] + 'px 100%' }]"> class="c-grid__x l-grid l-grid-x"
</div> :style="[{ backgroundSize: gridSize[0] + 'px 100%' }]"
<div class="c-grid__y l-grid l-grid-y" ></div>
<div
v-if="gridSize[1] >= 3" v-if="gridSize[1] >= 3"
:style="[{ backgroundSize: '100%' + gridSize[1] + 'px' }]"></div> class="c-grid__y l-grid l-grid-y"
:style="[{ backgroundSize: '100%' + gridSize[1] + 'px' }]"
></div>
</div> </div>
<component v-for="(item, index) in layoutItems" <component
:is="item.type" :is="item.type"
:item="item" v-for="(item, index) in layoutItems"
:key="item.id" :key="item.id"
:gridSize="gridSize" :item="item"
:initSelect="initSelectIndex === index" :grid-size="gridSize"
:init-select="initSelectIndex === index"
:index="index" :index="index"
:multiSelect="selectedLayoutItems.length > 1" :multi-select="selectedLayoutItems.length > 1"
@move="move" @move="move"
@endMove="endMove" @endMove="endMove"
@endLineResize='endLineResize' @endLineResize="endLineResize"
@formatChanged='updateTelemetryFormat'> @formatChanged="updateTelemetryFormat"
</component> />
<edit-marquee v-if='showMarquee' <edit-marquee
:gridSize="gridSize" v-if="showMarquee"
:selectedLayoutItems="selectedLayoutItems" :grid-size="gridSize"
@endResize="endResize"> :selected-layout-items="selectedLayoutItems"
</edit-marquee> @endResize="endResize"
/>
</div> </div>
</template> </template>
@ -175,6 +182,13 @@
} }
export default { export default {
components: components,
props: {
domainObject: {
type: Object,
required: true
}
},
data() { data() {
let domainObject = JSON.parse(JSON.stringify(this.domainObject)); let domainObject = JSON.parse(JSON.stringify(this.domainObject));
return { return {
@ -203,8 +217,23 @@
} }
}, },
inject: ['openmct', 'options', 'objectPath'], inject: ['openmct', 'options', 'objectPath'],
props: ['domainObject'], mounted() {
components: components, this.unlisten = this.openmct.objects.observe(this.internalDomainObject, '*', function (obj) {
this.internalDomainObject = JSON.parse(JSON.stringify(obj));
}.bind(this));
this.openmct.selection.on('change', this.setSelection);
this.initializeItems();
this.composition = this.openmct.composition.get(this.internalDomainObject);
this.composition.on('add', this.addChild);
this.composition.on('remove', this.removeChild);
this.composition.load();
},
destroyed: function () {
this.openmct.selection.off('change', this.setSelection);
this.composition.off('add', this.addChild);
this.composition.off('remove', this.removeChild);
this.unlisten();
},
methods: { methods: {
addElement(itemType, element) { addElement(itemType, element) {
this.addItem(itemType + '-view', element); this.addItem(itemType + '-view', element);
@ -281,11 +310,10 @@
}); });
} }
let layoutItems = this.layoutItems.map(item => { this.layoutItems.forEach(item => {
if (this.initialPositions[item.id]) { if (this.initialPositions[item.id]) {
this.updateItemPosition(item, gridDelta); this.updateItemPosition(item, gridDelta);
} }
return item;
}); });
}, },
updateItemPosition(item, gridDelta) { updateItemPosition(item, gridDelta) {
@ -492,7 +520,6 @@
orderItem(position, selectedItems) { orderItem(position, selectedItems) {
let delta = ORDERS[position]; let delta = ORDERS[position];
let indices = []; let indices = [];
let newIndex = -1;
let items = []; let items = [];
Object.assign(items, this.layoutItems); Object.assign(items, this.layoutItems);
@ -564,23 +591,6 @@
item.format = format; item.format = format;
this.mutate(`configuration.items[${index}]`, item); this.mutate(`configuration.items[${index}]`, item);
} }
},
mounted() {
this.unlisten = this.openmct.objects.observe(this.internalDomainObject, '*', function (obj) {
this.internalDomainObject = JSON.parse(JSON.stringify(obj));
}.bind(this));
this.openmct.selection.on('change', this.setSelection);
this.initializeItems();
this.composition = this.openmct.composition.get(this.internalDomainObject);
this.composition.on('add', this.addChild);
this.composition.on('remove', this.removeChild);
this.composition.load();
},
destroyed: function () {
this.openmct.selection.off('change', this.setSelection);
this.composition.off('add', this.addChild);
this.composition.off('remove', this.removeChild);
this.unlisten();
} }
} }
</script> </script>

View File

@ -22,15 +22,26 @@
<template> <template>
<!-- Resize handles --> <!-- Resize handles -->
<div class="c-frame-edit" :style="style"> <div
<div class="c-frame-edit__handle c-frame-edit__handle--nw" class="c-frame-edit"
@mousedown="startResize([1,1], [-1,-1], $event)"></div> :style="marqueeStyle"
<div class="c-frame-edit__handle c-frame-edit__handle--ne" >
@mousedown="startResize([0,1], [1,-1], $event)"></div> <div
<div class="c-frame-edit__handle c-frame-edit__handle--sw" class="c-frame-edit__handle c-frame-edit__handle--nw"
@mousedown="startResize([1,0], [-1,1], $event)"></div> @mousedown="startResize([1,1], [-1,-1], $event)"
<div class="c-frame-edit__handle c-frame-edit__handle--se" ></div>
@mousedown="startResize([0,0], [1,1], $event)"></div> <div
class="c-frame-edit__handle c-frame-edit__handle--ne"
@mousedown="startResize([0,1], [1,-1], $event)"
></div>
<div
class="c-frame-edit__handle c-frame-edit__handle--sw"
@mousedown="startResize([1,0], [-1,1], $event)"
></div>
<div
class="c-frame-edit__handle c-frame-edit__handle--se"
@mousedown="startResize([0,0], [1,1], $event)"
></div>
</div> </div>
</template> </template>
@ -100,8 +111,16 @@
export default { export default {
inject: ['openmct'], inject: ['openmct'],
props: { props: {
selectedLayoutItems: Array, selectedLayoutItems: {
gridSize: Array type: Array,
default: undefined
},
gridSize: {
type: Array,
required: true,
validator: (arr) => arr && arr.length === 2
&& arr.every(el => typeof el === 'number')
}
}, },
data() { data() {
return { return {
@ -109,7 +128,7 @@
} }
}, },
computed: { computed: {
style() { marqueePosition() {
let x = Number.POSITIVE_INFINITY; let x = Number.POSITIVE_INFINITY;
let y = Number.POSITIVE_INFINITY; let y = Number.POSITIVE_INFINITY;
let width = Number.NEGATIVE_INFINITY; let width = Number.NEGATIVE_INFINITY;
@ -145,24 +164,23 @@
height = height - y; height = height - y;
} }
this.marqueePosition = { return {
x: x, x: x,
y: y, y: y,
width: width, width: width,
height: height height: height
} }
return this.getMarqueeStyle(x, y, width, height); },
marqueeStyle() {
return {
left: (this.gridSize[0] * this.marqueePosition.x) + 'px',
top: (this.gridSize[1] * this.marqueePosition.y) + 'px',
width: (this.gridSize[0] * this.marqueePosition.width) + 'px',
height: (this.gridSize[1] * this.marqueePosition.height) + 'px'
};
} }
}, },
methods: { methods: {
getMarqueeStyle(x, y, width, height) {
return {
left: (this.gridSize[0] * x) + 'px',
top: (this.gridSize[1] * y) + 'px',
width: (this.gridSize[0] * width) + 'px',
height: (this.gridSize[1] * height) + 'px'
};
},
updatePosition(event) { updatePosition(event) {
let currentPosition = [event.pageX, event.pageY]; let currentPosition = [event.pageX, event.pageY];
this.initialPosition = this.initialPosition || currentPosition; this.initialPosition = this.initialPosition || currentPosition;

View File

@ -21,13 +21,16 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<layout-frame :item="item" <layout-frame
:item="item"
:grid-size="gridSize" :grid-size="gridSize"
@move="(gridDelta) => $emit('move', gridDelta)" @move="(gridDelta) => $emit('move', gridDelta)"
@endMove="() => $emit('endMove')"> @endMove="() => $emit('endMove')"
<div class="c-image-view" >
:style="style"> <div
</div> class="c-image-view"
:style="style"
></div>
</layout-frame> </layout-frame>
</template> </template>
@ -61,15 +64,26 @@
}; };
}, },
inject: ['openmct'], inject: ['openmct'],
props: {
item: Object,
gridSize: Array,
index: Number,
initSelect: Boolean
},
components: { components: {
LayoutFrame LayoutFrame
}, },
props: {
item: {
type: Object,
required: true
},
gridSize: {
type: Array,
required: true,
validator: (arr) => arr && arr.length === 2
&& arr.every(el => typeof el === 'number')
},
index: {
type: Number,
required: true
},
initSelect: Boolean
},
computed: { computed: {
style() { style() {
return { return {

View File

@ -21,18 +21,20 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="l-layout__frame c-frame" <div
class="l-layout__frame c-frame"
:class="{ :class="{
'no-frame': !item.hasFrame, 'no-frame': !item.hasFrame,
'u-inspectable': inspectable 'u-inspectable': inspectable
}" }"
:style="style"> :style="style"
>
<slot></slot> <slot></slot>
<div class="c-frame-edit__move" <div
@mousedown="startMove([1,1], [0,0], $event)"> class="c-frame-edit__move"
</div> @mousedown="startMove([1,1], [0,0], $event)"
></div>
</div> </div>
</template> </template>
@ -178,8 +180,16 @@
export default { export default {
inject: ['openmct'], inject: ['openmct'],
props: { props: {
item: Object, item: {
gridSize: Array type: Object,
required: true
},
gridSize: {
type: Array,
required: true,
validator: (arr) => arr && arr.length === 2
&& arr.every(el => typeof el === 'number')
}
}, },
computed: { computed: {
style() { style() {

View File

@ -21,24 +21,39 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="l-layout__frame c-frame no-frame" <div
:style="style"> class="l-layout__frame c-frame no-frame"
<svg width="100%" height="100%"> :style="style"
<line v-bind="linePosition" >
<svg
width="100%"
height="100%"
>
<line
v-bind="linePosition"
:stroke="item.stroke" :stroke="item.stroke"
stroke-width="2"> stroke-width="2"
</line> />
</svg> </svg>
<div class="c-frame-edit__move" <div
@mousedown="startDrag($event)"></div> class="c-frame-edit__move"
<div class="c-frame-edit" v-if="showFrameEdit"> @mousedown="startDrag($event)"
<div class="c-frame-edit__handle" ></div>
<div
v-if="showFrameEdit"
class="c-frame-edit"
>
<div
class="c-frame-edit__handle"
:class="startHandleClass" :class="startHandleClass"
@mousedown="startDrag($event, 'start')"></div> @mousedown="startDrag($event, 'start')"
<div class="c-frame-edit__handle" ></div>
<div
class="c-frame-edit__handle"
:class="endHandleClass" :class="endHandleClass"
@mousedown="startDrag($event, 'end')"></div> @mousedown="startDrag($event, 'end')"
></div>
</div> </div>
</div> </div>
</template> </template>
@ -71,10 +86,21 @@
}, },
inject: ['openmct'], inject: ['openmct'],
props: { props: {
item: Object, item: {
gridSize: Array, type: Object,
required: true
},
gridSize: {
type: Array,
required: true,
validator: (arr) => arr && arr.length === 2
&& arr.every(el => typeof el === 'number')
},
initSelect: Boolean, initSelect: Boolean,
index: Number, index: {
type: Number,
required: true
},
multiSelect: Boolean multiSelect: Boolean
}, },
data() { data() {
@ -106,7 +132,7 @@
left: `${left}px`, left: `${left}px`,
top: `${top}px`, top: `${top}px`,
width: `${width}px`, width: `${width}px`,
height: `${height}px`, height: `${height}px`
}; };
}, },
startHandleClass() { startHandleClass() {
@ -129,39 +155,46 @@
return 3; return 3;
}, },
linePosition() { linePosition() {
if (this.vectorQuadrant === 1) { return this.vectorQuadrant % 2 !== 0
return { // odd vectorQuadrant slopes up
? {
x1: '0%', x1: '0%',
y1: '100%', y1: '100%',
x2: '100%', x2: '100%',
y2: '0%' y2: '0%'
};
} }
if (this.vectorQuadrant === 4) { // even vectorQuadrant slopes down
return { : {
x1: '0%', x1: '0%',
y1: '0%', y1: '0%',
x2: '100%', x2: '100%',
y2: '100%' y2: '100%'
}; };
} }
if (this.vectorQuadrant === 2) { },
return { watch: {
x1: '0%', index(newIndex) {
y1: '0%', if (!this.context) {
x2: '100%', return;
y2: '100%' }
this.context.index = newIndex;
}
},
mounted() {
this.openmct.selection.on('change', this.setSelection);
this.context = {
layoutItem: this.item,
index: this.index
}; };
this.removeSelectable = this.openmct.selection.selectable(
this.$el, this.context, this.initSelect);
},
destroyed() {
if (this.removeSelectable) {
this.removeSelectable();
} }
if (this.vectorQuadrant === 3) { this.openmct.selection.off('change', this.setSelection);
return {
x1: '100%',
y1: '0%',
x2: '0%',
y2: '100%'
};
}
}
}, },
methods: { methods: {
startDrag(event, position) { startDrag(event, position) {
@ -235,30 +268,6 @@
return Math.round(v / this.gridSize[i]); return Math.round(v / this.gridSize[i]);
}); });
} }
},
watch: {
index(newIndex) {
if (!this.context) {
return;
}
this.context.index = newIndex;
}
},
mounted() {
this.openmct.selection.on('change', this.setSelection);
this.context = {
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el, this.context, this.initSelect);
},
destroyed() {
if (this.removeSelectable) {
this.removeSelectable();
}
this.openmct.selection.off('change', this.setSelection);
} }
} }
</script> </script>

View File

@ -20,18 +20,21 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
<template> <template>
<layout-frame :item="item" <layout-frame
:item="item"
:grid-size="gridSize" :grid-size="gridSize"
:title="domainObject && domainObject.name" :title="domainObject && domainObject.name"
@move="(gridDelta) => $emit('move', gridDelta)" @move="(gridDelta) => $emit('move', gridDelta)"
@endMove="() => $emit('endMove')"> @endMove="() => $emit('endMove')"
<object-frame v-if="domainObject" >
<object-frame
v-if="domainObject"
ref="objectFrame"
:domain-object="domainObject" :domain-object="domainObject"
:object-path="currentObjectPath" :object-path="currentObjectPath"
:has-frame="item.hasFrame" :has-frame="item.hasFrame"
:show-edit-view="false" :show-edit-view="false"
ref="objectFrame"> />
</object-frame>
</layout-frame> </layout-frame>
</template> </template>
@ -72,11 +75,26 @@
}; };
}, },
inject: ['openmct', 'objectPath'], inject: ['openmct', 'objectPath'],
components: {
ObjectFrame,
LayoutFrame
},
props: { props: {
item: Object, item: {
gridSize: Array, type: Object,
required: true
},
gridSize: {
type: Array,
required: true,
validator: (arr) => arr && arr.length === 2
&& arr.every(el => typeof el === 'number')
},
initSelect: Boolean, initSelect: Boolean,
index: Number index: {
type: Number,
required: true
}
}, },
data() { data() {
return { return {
@ -84,10 +102,6 @@
currentObjectPath: [] currentObjectPath: []
} }
}, },
components: {
ObjectFrame,
LayoutFrame
},
watch: { watch: {
index(newIndex) { index(newIndex) {
if (!this.context) { if (!this.context) {
@ -97,6 +111,15 @@
this.context.index = newIndex; this.context.index = newIndex;
} }
}, },
mounted() {
this.openmct.objects.get(this.item.identifier)
.then(this.setObject);
},
destroyed() {
if (this.removeSelectable) {
this.removeSelectable();
}
},
methods: { methods: {
setObject(domainObject) { setObject(domainObject) {
this.domainObject = domainObject; this.domainObject = domainObject;
@ -111,15 +134,6 @@
this.$el, this.context, this.initSelect); this.$el, this.context, this.initSelect);
}); });
} }
},
mounted() {
this.openmct.objects.get(this.item.identifier)
.then(this.setObject);
},
destroyed() {
if (this.removeSelectable) {
this.removeSelectable();
}
} }
} }
</script> </script>

View File

@ -21,24 +21,36 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<layout-frame :item="item" <layout-frame
:item="item"
:grid-size="gridSize" :grid-size="gridSize"
@move="(gridDelta) => $emit('move', gridDelta)" @move="(gridDelta) => $emit('move', gridDelta)"
@endMove="() => $emit('endMove')"> @endMove="() => $emit('endMove')"
<div class="c-telemetry-view" >
:style="styleObject" <div
v-if="domainObject" v-if="domainObject"
@contextmenu.prevent="showContextMenu"> class="c-telemetry-view"
<div v-if="showLabel" :style="styleObject"
class="c-telemetry-view__label"> @contextmenu.prevent="showContextMenu"
<div class="c-telemetry-view__label-text">{{ domainObject.name }}</div> >
<div
v-if="showLabel"
class="c-telemetry-view__label"
>
<div class="c-telemetry-view__label-text">
{{ domainObject.name }}
</div>
</div> </div>
<div v-if="showValue" <div
v-if="showValue"
:title="fieldName" :title="fieldName"
class="c-telemetry-view__value" class="c-telemetry-view__value"
:class="[telemetryClass]"> :class="[telemetryClass]"
<div class="c-telemetry-view__value-text">{{ telemetryValue }}</div> >
<div class="c-telemetry-view__value-text">
{{ telemetryValue }}
</div>
</div> </div>
</div> </div>
</layout-frame> </layout-frame>
@ -106,15 +118,34 @@
}; };
}, },
inject: ['openmct', 'objectPath'], inject: ['openmct', 'objectPath'],
props: {
item: Object,
gridSize: Array,
initSelect: Boolean,
index: Number
},
components: { components: {
LayoutFrame LayoutFrame
}, },
props: {
item: {
type: Object,
required: true
},
gridSize: {
type: Array,
required: true,
validator: (arr) => arr && arr.length === 2
&& arr.every(el => typeof el === 'number')
},
initSelect: Boolean,
index: {
type: Number,
required: true
}
},
data() {
return {
datum: undefined,
formats: undefined,
domainObject: undefined,
currentObjectPath: undefined
}
},
computed: { computed: {
showLabel() { showLabel() {
let displayMode = this.item.displayMode; let displayMode = this.item.displayMode;
@ -161,14 +192,6 @@
return alarm && alarm.cssClass; return alarm && alarm.cssClass;
} }
}, },
data() {
return {
datum: undefined,
formats: undefined,
domainObject: undefined,
currentObjectPath: undefined
}
},
watch: { watch: {
index(newIndex) { index(newIndex) {
if (!this.context) { if (!this.context) {
@ -181,6 +204,20 @@
this.context.layoutItem = newItem; this.context.layoutItem = newItem;
} }
}, },
mounted() {
this.openmct.objects.get(this.item.identifier)
.then(this.setObject);
this.openmct.time.on("bounds", this.refreshData);
},
destroyed() {
this.removeSubscription();
if (this.removeSelectable) {
this.removeSelectable();
}
this.openmct.time.off("bounds", this.refreshData);
},
methods: { methods: {
requestHistoricalData() { requestHistoricalData() {
let bounds = this.openmct.time.bounds(); let bounds = this.openmct.time.bounds();
@ -246,20 +283,6 @@
showContextMenu(event) { showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS); this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
} }
},
mounted() {
this.openmct.objects.get(this.item.identifier)
.then(this.setObject);
this.openmct.time.on("bounds", this.refreshData);
},
destroyed() {
this.removeSubscription();
if (this.removeSelectable) {
this.removeSelectable();
}
this.openmct.time.off("bounds", this.refreshData);
} }
} }

View File

@ -21,12 +21,16 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<layout-frame :item="item" <layout-frame
:item="item"
:grid-size="gridSize" :grid-size="gridSize"
@move="(gridDelta) => $emit('move', gridDelta)" @move="(gridDelta) => $emit('move', gridDelta)"
@endMove="() => $emit('endMove')"> @endMove="() => $emit('endMove')"
<div class="c-text-view" >
:style="style"> <div
class="c-text-view"
:style="style"
>
{{ item.text }} {{ item.text }}
</div> </div>
</layout-frame> </layout-frame>
@ -64,15 +68,26 @@
}; };
}, },
inject: ['openmct'], inject: ['openmct'],
props: {
item: Object,
gridSize: Array,
index: Number,
initSelect: Boolean
},
components: { components: {
LayoutFrame LayoutFrame
}, },
props: {
item: {
type: Object,
required: true
},
gridSize: {
type: Array,
required: true,
validator: (arr) => arr && arr.length === 2
&& arr.every(el => typeof el === 'number')
},
index: {
type: Number,
required: true
},
initSelect: Boolean
},
computed: { computed: {
style() { style() {
return { return {
@ -107,4 +122,3 @@
} }
} }
</script> </script>

View File

@ -42,22 +42,22 @@ export default function DisplayLayoutPlugin(options) {
return { return {
show(container) { show(container) {
component = new Vue({ component = new Vue({
el: container,
components: { components: {
Layout Layout
}, },
template: '<layout ref="displayLayout" :domain-object="domainObject"></layout>',
provide: { provide: {
openmct, openmct,
objectUtils, objectUtils,
options, options,
objectPath objectPath
}, },
el: container,
data() { data() {
return { return {
domainObject: domainObject domainObject: domainObject
}; };
} },
template: '<layout ref="displayLayout" :domain-object="domainObject"></layout>'
}); });
}, },
getSelectionContext() { getSelectionContext() {

View File

@ -48,11 +48,11 @@ define([
provide: { provide: {
openmct openmct
}, },
el: element,
components: { components: {
FiltersView: FiltersView.default FiltersView: FiltersView.default
}, },
template: '<filters-view></filters-view>', template: '<filters-view></filters-view>'
el: element
}); });
}, },
destroy: function () { destroy: function () {

View File

@ -1,35 +1,45 @@
<template> <template>
<div class="c-properties__section c-filter-settings"> <div class="c-properties__section c-filter-settings">
<li class="c-properties__row c-filter-settings__setting" <li
v-for="(filter, index) in filterField.filters" v-for="(filter, index) in filterField.filters"
:key="index"> :key="index"
<div class="c-properties__label label" class="c-properties__row c-filter-settings__setting"
:disabled="useGlobal"> >
<div
class="c-properties__label label"
:disabled="useGlobal"
>
{{ filterField.name }} = {{ filterField.name }} =
</div> </div>
<div class="c-properties__value value"> <div class="c-properties__value value">
<!-- EDITING --> <!-- EDITING -->
<!-- String input, editing --> <!-- String input, editing -->
<template v-if="!filter.possibleValues && isEditing"> <template v-if="!filter.possibleValues && isEditing">
<input class="c-input--flex" <input
type="text"
:id="`${filter}filterControl`" :id="`${filter}filterControl`"
class="c-input--flex"
type="text"
:disabled="useGlobal" :disabled="useGlobal"
:value="persistedValue(filter)" :value="persistedValue(filter)"
@change="updateFilterValue($event, filter)"> @change="updateFilterValue($event, filter)"
>
</template> </template>
<!-- Checkbox list, editing --> <!-- Checkbox list, editing -->
<template v-if="filter.possibleValues && isEditing"> <template v-if="filter.possibleValues && isEditing">
<div class="c-checkbox-list__row" <div
v-for="option in filter.possibleValues" v-for="option in filter.possibleValues"
:key="option.value"> :key="option.value"
<input class="c-checkbox-list__input" class="c-checkbox-list__row"
type="checkbox" >
<input
:id="`${option.value}filterControl`" :id="`${option.value}filterControl`"
class="c-checkbox-list__input"
type="checkbox"
:disabled="useGlobal" :disabled="useGlobal"
:checked="isChecked(filter.comparator, option.value)"
@change="updateFilterValue($event, filter.comparator, option.value)" @change="updateFilterValue($event, filter.comparator, option.value)"
:checked="isChecked(filter.comparator, option.value)"> >
<span class="c-checkbox-list__value"> <span class="c-checkbox-list__value">
{{ option.label }} {{ option.label }}
</span> </span>
@ -59,7 +69,10 @@ export default {
'openmct' 'openmct'
], ],
props: { props: {
filterField: Object, filterField: {
type: Object,
required: true
},
useGlobal: Boolean, useGlobal: Boolean,
persistedFilters: { persistedFilters: {
type: Object, type: Object,
@ -73,6 +86,12 @@ export default {
isEditing: this.openmct.editor.isEditing() isEditing: this.openmct.editor.isEditing()
} }
}, },
mounted() {
this.openmct.editor.on('isEditing', this.toggleIsEditing);
},
beforeDestroy() {
this.openmct.editor.off('isEditing', this.toggleIsEditing);
},
methods: { methods: {
toggleIsEditing(isEditing) { toggleIsEditing(isEditing) {
this.isEditing = isEditing; this.isEditing = isEditing;
@ -107,12 +126,6 @@ export default {
return accum; return accum;
}, []).join(', '); }, []).join(', ');
} }
},
mounted() {
this.openmct.editor.on('isEditing', this.toggleIsEditing);
},
beforeDestroy() {
this.openmct.editor.off('isEditing', this.toggleIsEditing);
} }
} }
</script> </script>

View File

@ -1,47 +1,59 @@
<template> <template>
<li class="c-tree__item-h"> <li class="c-tree__item-h">
<div class="c-tree__item menus-to-left" <div
@click="toggleExpanded"> class="c-tree__item menus-to-left"
<div class="c-filter-tree-item__filter-indicator" @click="toggleExpanded"
:class="{'icon-filter': hasActiveFilters }"></div> >
<span class="c-disclosure-triangle is-enabled flex-elem" <div
:class="{'c-disclosure-triangle--expanded': expanded}"></span> 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 c-object-label"> <div class="c-tree__item__label c-object-label">
<div class="c-object-label"> <div class="c-object-label">
<div class="c-object-label__type-icon" <div
:class="objectCssClass"> class="c-object-label__type-icon"
:class="objectCssClass"
></div>
<div class="c-object-label__name flex-elem grows">
{{ filterObject.name }}
</div> </div>
<div class="c-object-label__name flex-elem grows">{{ filterObject.name }}</div>
</div> </div>
</div> </div>
</div> </div>
<div v-if="expanded"> <div v-if="expanded">
<ul class="c-properties"> <ul class="c-properties">
<div class="c-properties__label span-all" <div
v-if="!isEditing && persistedFilters.useGlobal"> v-if="!isEditing && persistedFilters.useGlobal"
class="c-properties__label span-all"
>
Uses global filter Uses global filter
</div> </div>
<div class="c-properties__label span-all" <div
v-if="isEditing"> v-if="isEditing"
class="c-properties__label span-all"
>
<toggle-switch <toggle-switch
:id="keyString" :id="keyString"
:checked="persistedFilters.useGlobal"
@change="useGlobalFilter" @change="useGlobalFilter"
:checked="persistedFilters.useGlobal"> />
</toggle-switch>
Use global filter Use global filter
</div> </div>
<filter-field <filter-field
v-if="(!persistedFilters.useGlobal && !isEditing) || isEditing" v-for="metadatum in activeFilters"
v-for="metadatum in filterObject.metadataWithFilters"
:key="metadatum.key" :key="metadatum.key"
:filterField="metadatum" :filter-field="metadatum"
:useGlobal="persistedFilters.useGlobal" :use-global="persistedFilters.useGlobal"
:persistedFilters="updatedFilters[metadatum.key]" :persisted-filters="updatedFilters[metadatum.key]"
@filterSelected="updateFiltersWithSelectedValue" @filterSelected="updateFiltersWithSelectedValue"
@filterTextValueChanged="updateFiltersWithTextValue"> @filterTextValueChanged="updateFiltersWithTextValue"
</filter-field> />
</ul> </ul>
</div> </div>
</li> </li>
@ -58,7 +70,10 @@ export default {
ToggleSwitch ToggleSwitch
}, },
props: { props: {
filterObject: Object, filterObject: {
type: Object,
required: true
},
persistedFilters: { persistedFilters: {
type: Object, type: Object,
default: () => { default: () => {
@ -74,6 +89,23 @@ export default {
isEditing: this.openmct.editor.isEditing() isEditing: this.openmct.editor.isEditing()
} }
}, },
computed: {
// do not show filter fields if using global filter
// if editing however, show all filter fields
activeFilters() {
if (!this.isEditing && this.persistedFilters.useGlobal) {
return []
}
return this.filterObject.metadataWithFilters
},
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));
});
}
},
watch: { watch: {
persistedFilters: { persistedFilters: {
handler: function checkFilters(newpersistedFilters) { handler: function checkFilters(newpersistedFilters) {
@ -82,13 +114,14 @@ export default {
deep: true deep: true
} }
}, },
computed: { mounted() {
hasActiveFilters() { let type = this.openmct.types.get(this.filterObject.domainObject.type) || {};
// Should be true when the user has entered any filter values. this.keyString = this.openmct.objects.makeKeyString(this.filterObject.domainObject.identifier);
return Object.values(this.persistedFilters).some(comparator => { this.objectCssClass = type.definition.cssClass;
return (typeof(comparator) === 'object' && !_.isEmpty(comparator)); this.openmct.editor.on('isEditing', this.toggleIsEditing);
}); },
} beforeDestroy() {
this.openmct.editor.off('isEditing', this.toggleIsEditing);
}, },
methods: { methods: {
toggleExpanded() { toggleExpanded() {
@ -128,16 +161,7 @@ export default {
}, },
toggleIsEditing(isEditing) { toggleIsEditing(isEditing) {
this.isEditing = 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> </script>

View File

@ -1,21 +1,27 @@
<template> <template>
<ul class="c-tree c-filter-tree" v-if="Object.keys(children).length"> <ul
v-if="Object.keys(children).length"
class="c-tree c-filter-tree"
>
<h2>Data Filters</h2> <h2>Data Filters</h2>
<div class="c-filter-indication" <div
v-if="hasActiveFilters">{{ label }} v-if="hasActiveFilters"
class="c-filter-indication"
>
{{ label }}
</div> </div>
<global-filters <global-filters
:globalFilters="globalFilters" :global-filters="globalFilters"
:globalMetadata="globalMetadata" :global-metadata="globalMetadata"
@persistGlobalFilters="persistGlobalFilters"> @persistGlobalFilters="persistGlobalFilters"
</global-filters> />
<filter-object <filter-object
v-for="(child, key) in children" v-for="(child, key) in children"
:key="key" :key="key"
:filterObject="child" :filter-object="child"
:persistedFilters="persistedFilters[key]" :persisted-filters="persistedFilters[key]"
@updateFilters="persistFilters"> @updateFilters="persistFilters"
</filter-object> />
</ul> </ul>
</template> </template>
@ -91,8 +97,25 @@
return FILTER_VIEW_TITLE; return FILTER_VIEW_TITLE;
} }
} }
return '';
} }
}, },
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);
},
beforeDestroy() {
this.composition.off('add', this.addChildren);
this.composition.off('remove', this.removeChildren);
this.unobserve();
this.unobserveGlobalFilters();
this.unobserveAllMutation();
},
methods: { methods: {
addChildren(domainObject) { addChildren(domainObject) {
let keyString = this.openmct.objects.makeKeyString(domainObject.identifier); let keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
@ -228,22 +251,6 @@
mutateConfigurationGlobalFilters() { mutateConfigurationGlobalFilters() {
this.openmct.objects.mutate(this.providedObject, 'configuration.globalFilters', this.globalFilters); this.openmct.objects.mutate(this.providedObject, 'configuration.globalFilters', this.globalFilters);
} }
},
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);
},
beforeDestroy() {
this.composition.off('add', this.addChildren);
this.composition.off('remove', this.removeChildren);
this.unobserve();
this.unobserveGlobalFilters();
this.unobserveAllMutation();
} }
} }
</script> </script>

View File

@ -1,27 +1,38 @@
<template> <template>
<li class="c-tree__item-h"> <li class="c-tree__item-h">
<div class="c-tree__item menus-to-left" <div
@click="toggleExpanded"> class="c-tree__item menus-to-left"
<div class="c-filter-tree-item__filter-indicator" @click="toggleExpanded"
:class="{'icon-filter': hasActiveGlobalFilters }"></div> >
<span class="c-disclosure-triangle is-enabled flex-elem" <div
:class="{'c-disclosure-triangle--expanded': expanded}"></span> 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-tree__item__label c-object-label">
<div class="c-object-label"> <div class="c-object-label">
<div class="c-object-label__type-icon icon-gear"></div> <div class="c-object-label__type-icon icon-gear"></div>
<div class="c-object-label__name flex-elem grows">Global Filtering</div> <div class="c-object-label__name flex-elem grows">
Global Filtering
</div> </div>
</div> </div>
</div> </div>
<ul class="c-properties" v-if="expanded"> </div>
<ul
v-if="expanded"
class="c-properties"
>
<filter-field <filter-field
v-for="metadatum in globalMetadata" v-for="metadatum in globalMetadata"
:key="metadatum.key" :key="metadatum.key"
:filterField="metadatum" :filter-field="metadatum"
:persistedFilters="updatedFilters[metadatum.key]" :persisted-filters="updatedFilters[metadatum.key]"
@filterSelected="updateFiltersWithSelectedValue" @filterSelected="updateFiltersWithSelectedValue"
@filterTextValueChanged="updateFiltersWithTextValue"> @filterTextValueChanged="updateFiltersWithTextValue"
</filter-field> />
</ul> </ul>
</li> </li>
</template> </template>
@ -67,7 +78,10 @@
FilterField FilterField
}, },
props: { props: {
globalMetadata: Object, globalMetadata: {
type: Object,
required: true
},
globalFilters: { globalFilters: {
type: Object, type: Object,
default: () => { default: () => {

View File

@ -21,13 +21,17 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="c-fl-container" <div
class="c-fl-container"
:style="[{'flex-basis': sizeString}]" :style="[{'flex-basis': sizeString}]"
:class="{'is-empty': !frames.length}"> :class="{'is-empty': !frames.length}"
<div class="c-fl-container__header" >
<div
v-show="isEditing" v-show="isEditing"
class="c-fl-container__header"
draggable="true" draggable="true"
@dragstart="startContainerDrag"> @dragstart="startContainerDrag"
>
<span class="c-fl-container__size-indicator">{{ sizeString }}</span> <span class="c-fl-container__size-indicator">{{ sizeString }}</span>
</div> </div>
@ -35,40 +39,40 @@
class="c-fl-frame__drop-hint" class="c-fl-frame__drop-hint"
:index="-1" :index="-1"
:allow-drop="allowDrop" :allow-drop="allowDrop"
@object-drop-to="moveOrCreateNewFrame"> @object-drop-to="moveOrCreateNewFrame"
</drop-hint> />
<div class="c-fl-container__frames-holder"> <div class="c-fl-container__frames-holder">
<template <template
v-for="(frame, i) in frames"> v-for="(frame, i) in frames"
>
<frame-component <frame-component
class="c-fl-container__frame"
:key="frame.id" :key="frame.id"
class="c-fl-container__frame"
:frame="frame" :frame="frame"
:index="i" :index="i"
:containerIndex="index" :container-index="index"
:isEditing="isEditing"> :is-editing="isEditing"
</frame-component> />
<drop-hint <drop-hint
class="c-fl-frame__drop-hint"
:key="i" :key="i"
class="c-fl-frame__drop-hint"
:index="i" :index="i"
:allowDrop="allowDrop" :allow-drop="allowDrop"
@object-drop-to="moveOrCreateNewFrame"> @object-drop-to="moveOrCreateNewFrame"
</drop-hint> />
<resize-handle <resize-handle
v-if="(i !== frames.length - 1)" v-if="(i !== frames.length - 1)"
:key="i" :key="i"
:index="i" :index="i"
:orientation="rowsLayout ? 'horizontal' : 'vertical'" :orientation="rowsLayout ? 'horizontal' : 'vertical'"
:is-editing="isEditing"
@init-move="startFrameResizing" @init-move="startFrameResizing"
@move="frameResizing" @move="frameResizing"
@end-move="endFrameResizing" @end-move="endFrameResizing"
:isEditing="isEditing"> />
</resize-handle>
</template> </template>
</div> </div>
</div> </div>
@ -76,7 +80,6 @@
<script> <script>
import FrameComponent from './frame.vue'; import FrameComponent from './frame.vue';
import Frame from '../utils/frame';
import ResizeHandle from './resizeHandle.vue'; import ResizeHandle from './resizeHandle.vue';
import DropHint from './dropHint.vue'; import DropHint from './dropHint.vue';
@ -84,12 +87,26 @@ const MIN_FRAME_SIZE = 5;
export default { export default {
inject:['openmct'], inject:['openmct'],
props: ['container', 'index', 'rowsLayout', 'isEditing'],
components: { components: {
FrameComponent, FrameComponent,
ResizeHandle, ResizeHandle,
DropHint DropHint
}, },
props: {
container: {
type: Object,
required: true
},
index: {
type: Number,
required: true
},
rowsLayout: Boolean,
isEditing: {
type: Boolean,
default: false
}
},
computed: { computed: {
frames() { frames() {
return this.container.frames; return this.container.frames;
@ -98,6 +115,19 @@ export default {
return `${Math.round(this.container.size)}%` return `${Math.round(this.container.size)}%`
} }
}, },
mounted() {
let context = {
item: this.$parent.domainObject,
addContainer: this.addContainer,
type: 'container',
containerId: this.container.id
}
this.unsubscribeSelection = this.openmct.selection.selectable(this.$el, context, false);
},
beforeDestroy() {
this.unsubscribeSelection();
},
methods: { methods: {
allowDrop(event, index) { allowDrop(event, index) {
if (event.dataTransfer.types.includes('openmct/domain-object-path')) { if (event.dataTransfer.types.includes('openmct/domain-object-path')) {
@ -131,7 +161,7 @@ export default {
insertIndex insertIndex
); );
return; return;
}; }
// move frame. // move frame.
let frameId = event.dataTransfer.getData('frameid'); let frameId = event.dataTransfer.getData('frameid');
let containerIndex = Number(event.dataTransfer.getData('containerIndex')); let containerIndex = Number(event.dataTransfer.getData('containerIndex'));
@ -182,19 +212,6 @@ export default {
startContainerDrag(event) { startContainerDrag(event) {
event.dataTransfer.setData('containerid', this.container.id); event.dataTransfer.setData('containerid', this.container.id);
} }
},
mounted() {
let context = {
item: this.$parent.domainObject,
addContainer: this.addContainer,
type: 'container',
containerId: this.container.id
}
this.unsubscribeSelection = this.openmct.selection.selectable(this.$el, context, false);
},
beforeDestroy() {
this.unsubscribeSelection();
} }
} }
</script> </script>

View File

@ -22,13 +22,14 @@
<template> <template>
<div v-show="isValidTarget"> <div v-show="isValidTarget">
<div class="c-drop-hint c-drop-hint--always-show" <div
class="c-drop-hint c-drop-hint--always-show"
:class="{'is-mouse-over': isMouseOver}" :class="{'is-mouse-over': isMouseOver}"
@dragover.prevent @dragover.prevent
@dragenter="dragenter" @dragenter="dragenter"
@dragleave="dragleave" @dragleave="dragleave"
@drop="dropHandler"> @drop="dropHandler"
</div> ></div>
</div> </div>
</template> </template>
@ -39,7 +40,10 @@
<script> <script>
export default { export default {
props:{ props:{
index: Number, index: {
type: Number,
required: true
},
allowDrop: { allowDrop: {
type: Function, type: Function,
required: true required: true
@ -51,6 +55,16 @@ export default {
isValidTarget: false isValidTarget: false
} }
}, },
mounted() {
document.addEventListener('dragstart', this.dragstart);
document.addEventListener('dragend', this.dragend);
document.addEventListener('drop', this.dragend);
},
destroyed() {
document.removeEventListener('dragstart', this.dragstart);
document.removeEventListener('dragend', this.dragend);
document.removeEventListener('drop', this.dragend);
},
methods: { methods: {
dragenter() { dragenter() {
this.isMouseOver = true; this.isMouseOver = true;
@ -68,16 +82,6 @@ export default {
dragend() { dragend() {
this.isValidTarget = false; this.isValidTarget = false;
} }
},
mounted() {
document.addEventListener('dragstart', this.dragstart);
document.addEventListener('dragend', this.dragend);
document.addEventListener('drop', this.dragend);
},
destroyed() {
document.removeEventListener('dragstart', this.dragstart);
document.removeEventListener('dragend', this.dragend);
document.removeEventListener('drop', this.dragend);
} }
} }
</script> </script>

View File

@ -24,61 +24,63 @@
<div class="c-fl"> <div class="c-fl">
<div <div
id="js-fl-drag-ghost" id="js-fl-drag-ghost"
class="c-fl__drag-ghost"> class="c-fl__drag-ghost"
</div> ></div>
<div class="c-fl__empty" <div
v-if="areAllContainersEmpty()"> v-if="areAllContainersEmpty()"
class="c-fl__empty"
>
<span class="c-fl__empty-message">This Flexible Layout is currently empty</span> <span class="c-fl__empty-message">This Flexible Layout is currently empty</span>
</div> </div>
<div class="c-fl__container-holder" <div
class="c-fl__container-holder"
:class="{ :class="{
'c-fl--rows': rowsLayout === true 'c-fl--rows': rowsLayout === true
}"> }"
>
<template v-for="(container, index) in containers"> <template v-for="(container, index) in containers">
<drop-hint <drop-hint
class="c-fl-frame__drop-hint"
v-if="index === 0 && containers.length > 1" v-if="index === 0 && containers.length > 1"
:key="index" :key="index"
class="c-fl-frame__drop-hint"
:index="-1" :index="-1"
:allow-drop="allowContainerDrop" :allow-drop="allowContainerDrop"
@object-drop-to="moveContainer"> @object-drop-to="moveContainer"
</drop-hint> />
<container-component <container-component
class="c-fl__container"
:key="container.id" :key="container.id"
class="c-fl__container"
:index="index" :index="index"
:container="container" :container="container"
:rowsLayout="rowsLayout" :rows-layout="rowsLayout"
:isEditing="isEditing" :is-editing="isEditing"
@move-frame="moveFrame" @move-frame="moveFrame"
@new-frame="setFrameLocation" @new-frame="setFrameLocation"
@persist="persist"> @persist="persist"
</container-component> />
<resize-handle <resize-handle
v-if="index !== (containers.length - 1)" v-if="index !== (containers.length - 1)"
:key="index" :key="index"
:index="index" :index="index"
:orientation="rowsLayout ? 'vertical' : 'horizontal'" :orientation="rowsLayout ? 'vertical' : 'horizontal'"
:isEditing="isEditing" :is-editing="isEditing"
@init-move="startContainerResizing" @init-move="startContainerResizing"
@move="containerResizing" @move="containerResizing"
@end-move="endContainerResizing"> @end-move="endContainerResizing"
</resize-handle> />
<drop-hint <drop-hint
class="c-fl-frame__drop-hint"
v-if="containers.length > 1" v-if="containers.length > 1"
:key="index" :key="index"
class="c-fl-frame__drop-hint"
:index="index" :index="index"
:allowDrop="allowContainerDrop" :allow-drop="allowContainerDrop"
@object-drop-to="moveContainer"> @object-drop-to="moveContainer"
</drop-hint> />
</template> </template>
</div> </div>
</div> </div>
@ -465,15 +467,15 @@ export default {
ResizeHandle, ResizeHandle,
DropHint DropHint
}, },
props: {
isEditing: Boolean
},
data() { data() {
return { return {
domainObject: this.layoutObject, domainObject: this.layoutObject,
newFrameLocation: [] newFrameLocation: []
} }
}, },
props: {
isEditing: Boolean
},
computed: { computed: {
layoutDirectionStr() { layoutDirectionStr() {
if (this.rowsLayout) { if (this.rowsLayout) {
@ -489,9 +491,24 @@ export default {
return this.domainObject.configuration.rowsLayout; return this.domainObject.configuration.rowsLayout;
} }
}, },
mounted() {
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('remove', this.removeChildObject);
this.composition.on('add', this.addFrame);
this.RemoveAction = new RemoveAction(this.openmct);
this.unobserve = this.openmct.objects.observe(this.domainObject, '*', this.updateDomainObject);
},
beforeDestroy() {
this.composition.off('remove', this.removeChildObject);
this.composition.off('add', this.addFrame);
this.unobserve();
},
methods: { methods: {
areAllContainersEmpty() { areAllContainersEmpty() {
return !!!this.containers.filter(container => container.frames.length).length; return !this.containers.filter(container => container.frames.length).length;
}, },
addContainer() { addContainer() {
let container = new Container(); let container = new Container();
@ -657,21 +674,6 @@ export default {
this.persist(); this.persist();
} }
},
mounted() {
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('remove', this.removeChildObject);
this.composition.on('add', this.addFrame);
this.RemoveAction = new RemoveAction(this.openmct);
this.unobserve = this.openmct.objects.observe(this.domainObject, '*', this.updateDomainObject);
},
beforeDestroy() {
this.composition.off('remove', this.removeChildObject);
this.composition.off('add', this.addFrame);
this.unobserve();
} }
} }
</script> </script>

View File

@ -21,28 +21,32 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="c-fl-frame" <div
class="c-fl-frame"
:style="{ :style="{
'flex-basis': `${frame.size}%` 'flex-basis': `${frame.size}%`
}"> }"
>
<div class="c-frame c-fl-frame__drag-wrapper is-selectable u-inspectable is-moveable" <div
ref="frame"
class="c-frame c-fl-frame__drag-wrapper is-selectable u-inspectable is-moveable"
draggable="true" draggable="true"
@dragstart="initDrag" @dragstart="initDrag"
ref="frame"> >
<object-frame <object-frame
v-if="domainObject" v-if="domainObject"
ref="objectFrame"
:domain-object="domainObject" :domain-object="domainObject"
:object-path="objectPath" :object-path="objectPath"
:has-frame="hasFrame" :has-frame="hasFrame"
:show-edit-view="false" :show-edit-view="false"
ref="objectFrame"> />
</object-frame>
<div class="c-fl-frame__size-indicator" <div
v-if="isEditing" v-if="isEditing"
v-show="frame.size && frame.size < 100"> v-show="frame.size && frame.size < 100"
class="c-fl-frame__size-indicator"
>
{{ frame.size }}% {{ frame.size }}%
</div> </div>
</div> </div>
@ -50,27 +54,56 @@
</template> </template>
<script> <script>
import ResizeHandle from './resizeHandle.vue';
import ObjectFrame from '../../../ui/components/ObjectFrame.vue'; import ObjectFrame from '../../../ui/components/ObjectFrame.vue';
export default { export default {
inject: ['openmct'], inject: ['openmct'],
props: ['frame', 'index', 'containerIndex', 'isEditing'], components: {
ObjectFrame
},
props: {
frame: {
type: Object,
required: true
},
index: {
type: Number,
required: true
},
containerIndex: {
type: Number,
required: true
},
isEditing: {
type: Boolean,
default: false
}
},
data() { data() {
return { return {
domainObject: undefined, domainObject: undefined,
objectPath: undefined objectPath: undefined
} }
}, },
components: {
ResizeHandle,
ObjectFrame
},
computed: { computed: {
hasFrame() { hasFrame() {
return !this.frame.noFrame; return !this.frame.noFrame;
} }
}, },
mounted() {
if (this.frame.domainObjectIdentifier) {
this.openmct.objects.get(this.frame.domainObjectIdentifier).then((object)=>{
this.setDomainObject(object);
});
}
this.dragGhost = document.getElementById('js-fl-drag-ghost');
},
beforeDestroy() {
if (this.unsubscribeSelection) {
this.unsubscribeSelection();
}
},
methods: { methods: {
setDomainObject(object) { setDomainObject(object) {
this.domainObject = object; this.domainObject = object;
@ -105,20 +138,6 @@ export default {
event.dataTransfer.setData('frameid', this.frame.id); event.dataTransfer.setData('frameid', this.frame.id);
event.dataTransfer.setData('containerIndex', this.containerIndex); event.dataTransfer.setData('containerIndex', this.containerIndex);
} }
},
mounted() {
if (this.frame.domainObjectIdentifier) {
this.openmct.objects.get(this.frame.domainObjectIdentifier).then((object)=>{
this.setDomainObject(object);
});
}
this.dragGhost = document.getElementById('js-fl-drag-ghost');
},
beforeDestroy() {
if (this.unsubscribeSelection) {
this.unsubscribeSelection();
}
} }
} }
</script> </script>

View File

@ -21,22 +21,46 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="c-fl-frame__resize-handle" <div
:class="[orientation]"
v-show="isEditing && !isDragging" v-show="isEditing && !isDragging"
@mousedown="mousedown"> class="c-fl-frame__resize-handle"
</div> :class="[orientation]"
@mousedown="mousedown"
></div>
</template> </template>
<script> <script>
export default { export default {
props: ['orientation', 'index', 'isEditing'], props: {
orientation: {
type: String,
required: true
},
index: {
type: Number,
required: true
},
isEditing: {
type: Boolean,
default: false
}
},
data() { data() {
return { return {
initialPos: 0, initialPos: 0,
isDragging: false, isDragging: false
} }
}, },
mounted() {
document.addEventListener('dragstart', this.setDragging);
document.addEventListener('dragend', this.unsetDragging);
document.addEventListener('drop', this.unsetDragging);
},
destroyed() {
document.removeEventListener('dragstart', this.setDragging);
document.removeEventListener('dragend', this.unsetDragging);
document.removeEventListener('drop', this.unsetDragging);
},
methods: { methods: {
mousedown(event) { mousedown(event) {
event.preventDefault(); event.preventDefault();
@ -75,16 +99,6 @@ export default {
unsetDragging(event) { unsetDragging(event) {
this.isDragging = false; this.isDragging = false;
} }
},
mounted() {
document.addEventListener('dragstart', this.setDragging);
document.addEventListener('dragend', this.unsetDragging);
document.addEventListener('drop', this.unsetDragging);
},
destroyed() {
document.removeEventListener('dragstart', this.setDragging);
document.removeEventListener('dragend', this.unsetDragging);
document.removeEventListener('drop', this.unsetDragging);
} }
} }
</script> </script>

View File

@ -44,19 +44,19 @@ define([
return { return {
show: function (element, isEditing) { show: function (element, isEditing) {
component = new Vue({ component = new Vue({
data() {
return {
isEditing: isEditing
}
},
components: {
FlexibleLayoutComponent: FlexibleLayoutComponent.default
},
provide: { provide: {
openmct, openmct,
layoutObject: domainObject layoutObject: domainObject
}, },
el: element, el: element,
components: {
FlexibleLayoutComponent: FlexibleLayoutComponent.default
},
data() {
return {
isEditing: isEditing
}
},
template: '<flexible-layout-component ref="flexibleLayout" :isEditing="isEditing"></flexible-layout-component>' template: '<flexible-layout-component ref="flexibleLayout" :isEditing="isEditing"></flexible-layout-component>'
}); });
}, },

View File

@ -41,6 +41,7 @@ define([
return { return {
show: function (element) { show: function (element) {
component = new Vue({ component = new Vue({
el: element,
components: { components: {
gridViewComponent: GridViewComponent.default gridViewComponent: GridViewComponent.default
}, },
@ -48,7 +49,6 @@ define([
openmct, openmct,
domainObject domainObject
}, },
el: element,
template: '<grid-view-component></grid-view-component>' template: '<grid-view-component></grid-view-component>'
}); });
}, },

View File

@ -43,6 +43,7 @@ define([
return { return {
show: function (element) { show: function (element) {
component = new Vue({ component = new Vue({
el: element,
components: { components: {
listViewComponent: ListViewComponent.default listViewComponent: ListViewComponent.default
}, },
@ -51,7 +52,6 @@ define([
domainObject, domainObject,
Moment Moment
}, },
el: element,
template: '<list-view-component></list-view-component>' template: '<list-view-component></list-view-component>'
}); });
}, },

View File

@ -1,22 +1,35 @@
<template> <template>
<a class="l-grid-view__item c-grid-item" <a
class="l-grid-view__item c-grid-item"
:class="{ 'is-alias': item.isAlias === true }" :class="{ 'is-alias': item.isAlias === true }"
:href="objectLink"> :href="objectLink"
<div class="c-grid-item__type-icon" >
:class="(item.type.cssClass != undefined) ? 'bg-' + item.type.cssClass : 'bg-icon-object-unknown'"> <div
</div> class="c-grid-item__type-icon"
:class="(item.type.cssClass != undefined) ? 'bg-' + item.type.cssClass : 'bg-icon-object-unknown'"
></div>
<div class="c-grid-item__details"> <div class="c-grid-item__details">
<!-- Name and metadata --> <!-- Name and metadata -->
<div class="c-grid-item__name" <div
:title="item.model.name">{{item.model.name}}</div> class="c-grid-item__name"
<div class="c-grid-item__metadata" :title="item.model.name"
:title="item.type.name"> >{{ item.model.name }}</div>
<div
class="c-grid-item__metadata"
:title="item.type.name"
>
<span class="c-grid-item__metadata__type">{{ item.type.name }}</span> <span class="c-grid-item__metadata__type">{{ item.type.name }}</span>
</div> </div>
</div> </div>
<div class="c-grid-item__controls"> <div class="c-grid-item__controls">
<div class="icon-people" title='Shared'></div> <div
<button class="c-icon-button icon-info c-info-button" title='More Info'></button> class="icon-people"
title="Shared"
></div>
<button
class="c-icon-button icon-info c-info-button"
title="More Info"
></button>
<div class="icon-pointer-right c-pointer-icon"></div> <div class="icon-pointer-right c-pointer-icon"></div>
</div> </div>
</a> </a>
@ -154,6 +167,11 @@ import objectLink from '../../../ui/mixins/object-link';
export default { export default {
mixins: [contextMenuGesture, objectLink], mixins: [contextMenuGesture, objectLink],
props: ['item'] props: {
item: {
type: Object,
required: true
}
}
} }
</script> </script>

View File

@ -1,10 +1,11 @@
<template> <template>
<div class="l-grid-view"> <div class="l-grid-view">
<grid-item v-for="(item, index) in items" <grid-item
v-for="(item, index) in items"
:key="index" :key="index"
:item="item" :item="item"
:object-path="item.objectPath"> :object-path="item.objectPath"
</grid-item> />
</div> </div>
</template> </template>

View File

@ -1,16 +1,30 @@
<template> <template>
<tr class="c-list-item" <tr
class="c-list-item"
:class="{ 'is-alias': item.isAlias === true }" :class="{ 'is-alias': item.isAlias === true }"
@click="navigate"> @click="navigate"
>
<td class="c-list-item__name"> <td class="c-list-item__name">
<a :href="objectLink" ref="objectLink"> <a
<div class="c-list-item__type-icon" :class="item.type.cssClass"></div> ref="objectLink"
:href="objectLink"
>
<div
class="c-list-item__type-icon"
:class="item.type.cssClass"
></div>
<div class="c-list-item__name-value">{{ item.model.name }}</div> <div class="c-list-item__name-value">{{ item.model.name }}</div>
</a> </a>
</td> </td>
<td class="c-list-item__type">{{ item.type.name }}</td> <td class="c-list-item__type">
<td class="c-list-item__date-created">{{ formatTime(item.model.persisted, 'YYYY-MM-DD HH:mm:ss:SSS') }}Z</td> {{ item.type.name }}
<td class="c-list-item__date-updated">{{ formatTime(item.model.modified, 'YYYY-MM-DD HH:mm:ss:SSS') }}Z</td> </td>
<td class="c-list-item__date-created">
{{ formatTime(item.model.persisted, 'YYYY-MM-DD HH:mm:ss:SSS') }}Z
</td>
<td class="c-list-item__date-updated">
{{ formatTime(item.model.modified, 'YYYY-MM-DD HH:mm:ss:SSS') }}Z
</td>
</tr> </tr>
</template> </template>
@ -64,7 +78,12 @@ import objectLink from '../../../ui/mixins/object-link';
export default { export default {
mixins: [contextMenuGesture, objectLink], mixins: [contextMenuGesture, objectLink],
props: ['item'], props: {
item: {
type: Object,
required: true
}
},
methods: { methods: {
formatTime(timestamp, format) { formatTime(timestamp, format) {
return moment(timestamp).format(format); return moment(timestamp).format(format);

View File

@ -3,50 +3,59 @@
<table class="c-table__body"> <table class="c-table__body">
<thead class="c-table__header"> <thead class="c-table__header">
<tr> <tr>
<th class="is-sortable" <th
class="is-sortable"
:class="{ :class="{
'is-sorting': sortBy === 'model.name', 'is-sorting': sortBy === 'model.name',
'asc': ascending, 'asc': ascending,
'desc': !ascending 'desc': !ascending
}" }"
@click="sort('model.name', true)"> @click="sort('model.name', true)"
>
Name Name
</th> </th>
<th class="is-sortable" <th
class="is-sortable"
:class="{ :class="{
'is-sorting': sortBy === 'type.name', 'is-sorting': sortBy === 'type.name',
'asc': ascending, 'asc': ascending,
'desc': !ascending 'desc': !ascending
}" }"
@click="sort('type.name', true)"> @click="sort('type.name', true)"
>
Type Type
</th> </th>
<th class="is-sortable" <th
class="is-sortable"
:class="{ :class="{
'is-sorting': sortBy === 'model.persisted', 'is-sorting': sortBy === 'model.persisted',
'asc': ascending, 'asc': ascending,
'desc': !ascending 'desc': !ascending
}" }"
@click="sort('model.persisted', false)"> @click="sort('model.persisted', false)"
>
Created Date Created Date
</th> </th>
<th class="is-sortable" <th
class="is-sortable"
:class="{ :class="{
'is-sorting': sortBy === 'model.modified', 'is-sorting': sortBy === 'model.modified',
'asc': ascending, 'asc': ascending,
'desc': !ascending 'desc': !ascending
}" }"
@click="sort('model.modified', false)"> @click="sort('model.modified', false)"
>
Updated Date Updated Date
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<list-item v-for="item in sortedItems" <list-item
v-for="item in sortedItems"
:key="item.objectKeyString" :key="item.objectKeyString"
:item="item" :item="item"
:object-path="item.objectPath"> :object-path="item.objectPath"
</list-item> />
</tbody> </tbody>
</table> </table>
</div> </div>
@ -93,8 +102,6 @@
</style> </style>
<script> <script>
import lodash from 'lodash';
import compositionLoader from './composition-loader'; import compositionLoader from './composition-loader';
import ListItem from './ListItem.vue'; import ListItem from './ListItem.vue';

View File

@ -23,12 +23,21 @@
<div class="c-about c-about--licenses"> <div class="c-about c-about--licenses">
<h1>Open MCT Third Party Licenses</h1> <h1>Open MCT Third Party Licenses</h1>
<p>This software includes components released under the following licenses:</p> <p>This software includes components released under the following licenses:</p>
<div v-for="(pkg, key) in packages" :key="key" class="c-license"> <div
<h2 class="c-license__name">{{key}}</h2> v-for="(pkg, key) in packages"
:key="key"
class="c-license"
>
<h2 class="c-license__name">
{{ key }}
</h2>
<div class="c-license__details"> <div class="c-license__details">
<span class="c-license__author"><em>Author</em> {{ pkg.publisher }}</span> | <span class="c-license__author"><em>Author</em> {{ pkg.publisher }}</span> |
<span class="c-license__license"><em>License(s)</em> {{ pkg.licenses }}</span> | <span class="c-license__license"><em>License(s)</em> {{ pkg.licenses }}</span> |
<span class="c-license__repo"><em>Repository</em> <a :href="pkg.repository" target="_blank">{{pkg.repository}}</a></span> <span class="c-license__repo"><em>Repository</em> <a
:href="pkg.repository"
target="_blank"
>{{ pkg.repository }}</a></span>
</div> </div>
<div class="c-license__text"> <div class="c-license__text">
<p>{{ pkg.licenseText }}</p> <p>{{ pkg.licenseText }}</p>
@ -49,4 +58,3 @@ export default {
} }
} }
</script> </script>

View File

@ -141,7 +141,6 @@ function (
var self = this, var self = this,
snapshot = new Vue({ snapshot = new Vue({
template: SnapshotTemplate,
data: function () { data: function () {
return { return {
embed: self.embed embed: self.embed
@ -151,7 +150,8 @@ function (
formatTime: self.formatTime, formatTime: self.formatTime,
annotateSnapshot: annotateSnapshot(self.openmct), annotateSnapshot: annotateSnapshot(self.openmct),
findInArray: self.findInArray findInArray: self.findInArray
} },
template: SnapshotTemplate
}); });
var snapshotOverlay = this.openmct.overlays.overlay({ var snapshotOverlay = this.openmct.overlays.overlay({

View File

@ -84,7 +84,6 @@ function (
}; };
var NotebookVue = Vue.extend({ var NotebookVue = Vue.extend({
template: NotebookTemplate,
provide: {openmct: self.openmct, domainObject: self.domainObject}, provide: {openmct: self.openmct, domainObject: self.domainObject},
components: { components: {
'notebook-entry': entryComponent, 'notebook-entry': entryComponent,
@ -111,7 +110,8 @@ function (
newEntry: self.newEntry, newEntry: self.newEntry,
filterBySearch: self.filterBySearch, filterBySearch: self.filterBySearch,
sort: self.sort sort: self.sort
} },
template: NotebookTemplate
}); });
this.NotebookVue = new NotebookVue(); this.NotebookVue = new NotebookVue();

View File

@ -1,42 +1,56 @@
<template> <template>
<div class="c-tabs-view"> <div class="c-tabs-view">
<div class="c-tabs-view__tabs-holder c-tabs" <div
class="c-tabs-view__tabs-holder c-tabs"
:class="{ :class="{
'is-dragging': isDragging, 'is-dragging': isDragging,
'is-mouse-over': allowDrop 'is-mouse-over': allowDrop
}"> }"
<div class="c-drop-hint" >
<div
class="c-drop-hint"
@drop="onDrop" @drop="onDrop"
@dragenter="dragenter" @dragenter="dragenter"
@dragleave="dragleave"> @dragleave="dragleave"
></div>
<div
v-if="!tabsList.length > 0"
class="c-tabs-view__empty-message"
>
Drag objects here to add them to this view.
</div> </div>
<div class="c-tabs-view__empty-message" <button
v-if="!tabsList.length > 0">Drag objects here to add them to this view.</div>
<button class="c-tabs-view__tab c-tab"
v-for="(tab,index) in tabsList" v-for="(tab,index) in tabsList"
:key="index" :key="index"
class="c-tabs-view__tab c-tab"
:class="[ :class="[
{'is-current': isCurrent(tab)}, {'is-current': isCurrent(tab)},
tab.type.definition.cssClass tab.type.definition.cssClass
]" ]"
@click="showTab(tab)"> @click="showTab(tab)"
>
<span class="c-button__label">{{ tab.domainObject.name }}</span> <span class="c-button__label">{{ tab.domainObject.name }}</span>
</button> </button>
</div> </div>
<div class="c-tabs-view__object-holder" <div
v-for="(tab, index) in tabsList" v-for="(tab, index) in tabsList"
:key="index" :key="index"
:class="{'c-tabs-view__object-holder--hidden': !isCurrent(tab)}"> class="c-tabs-view__object-holder"
<div v-if="currentTab" :class="{'c-tabs-view__object-holder--hidden': !isCurrent(tab)}"
>
<div
v-if="currentTab"
class="c-tabs-view__object-name l-browse-bar__object-name--w" class="c-tabs-view__object-name l-browse-bar__object-name--w"
:class="currentTab.type.definition.cssClass"> :class="currentTab.type.definition.cssClass"
>
<div class="l-browse-bar__object-name"> <div class="l-browse-bar__object-name">
{{ currentTab.domainObject.name }} {{ currentTab.domainObject.name }}
</div> </div>
</div> </div>
<object-view class="c-tabs-view__object" <object-view
:object="tab.domainObject"> class="c-tabs-view__object"
</object-view> :object="tab.domainObject"
/>
</div> </div>
</div> </div>
</template> </template>
@ -129,6 +143,25 @@ export default {
allowDrop: false allowDrop: false
}; };
}, },
mounted() {
if (this.composition) {
this.composition.on('add', this.addItem);
this.composition.on('remove', this.removeItem);
this.composition.on('reorder', this.onReorder);
this.composition.load();
}
document.addEventListener('dragstart', this.dragstart);
document.addEventListener('dragend', this.dragend);
},
destroyed() {
this.composition.off('add', this.addItem);
this.composition.off('remove', this.removeItem);
this.composition.off('reorder', this.onReorder);
document.removeEventListener('dragstart', this.dragstart);
document.removeEventListener('dragend', this.dragend);
},
methods:{ methods:{
showTab(tab) { showTab(tab) {
this.currentTab = tab; this.currentTab = tab;
@ -187,25 +220,6 @@ export default {
isCurrent(tab) { isCurrent(tab) {
return _.isEqual(this.currentTab, tab) return _.isEqual(this.currentTab, tab)
} }
},
mounted () {
if (this.composition) {
this.composition.on('add', this.addItem);
this.composition.on('remove', this.removeItem);
this.composition.on('reorder', this.onReorder);
this.composition.load();
}
document.addEventListener('dragstart', this.dragstart);
document.addEventListener('dragend', this.dragend);
},
destroyed() {
this.composition.off('add', this.addItem);
this.composition.off('remove', this.removeItem);
this.composition.off('reorder', this.onReorder);
document.removeEventListener('dragstart', this.dragstart);
document.removeEventListener('dragend', this.dragend);
} }
} }
</script> </script>

View File

@ -44,6 +44,7 @@ define([
return { return {
show: function (element) { show: function (element) {
component = new Vue({ component = new Vue({
el: element,
components: { components: {
TabsComponent: TabsComponent.default TabsComponent: TabsComponent.default
}, },
@ -52,7 +53,6 @@ define([
domainObject, domainObject,
composition: openmct.composition.get(domainObject) composition: openmct.composition.get(domainObject)
}, },
el: element,
template: '<tabs-component></tabs-component>' template: '<tabs-component></tabs-component>'
}); });
}, },

View File

@ -54,11 +54,11 @@ define([
openmct, openmct,
tableConfiguration tableConfiguration
}, },
el: element,
components: { components: {
TableConfiguration: TableConfigurationComponent.default TableConfiguration: TableConfigurationComponent.default
}, },
template: '<table-configuration></table-configuration>', template: '<table-configuration></table-configuration>'
el: element
}); });
}, },
destroy: function () { destroy: function () {

View File

@ -54,20 +54,20 @@ define([
return { return {
show: function (element, editMode) { show: function (element, editMode) {
component = new Vue({ component = new Vue({
el: element,
components: {
TableComponent: TableComponent.default
},
data() { data() {
return { return {
isEditing: editMode isEditing: editMode
} }
}, },
components: {
TableComponent: TableComponent.default
},
provide: { provide: {
openmct, openmct,
table, table,
objectPath objectPath
}, },
el: element,
template: '<table-component :isEditing="isEditing" :enableMarking="true"></table-component>' template: '<table-component :isEditing="isEditing" :enableMarking="true"></table-component>'
}); });
}, },

View File

@ -1,11 +1,16 @@
<template> <template>
<div v-if="filterNames.length > 0" <div
:title=title v-if="filterNames.length > 0"
:title="title"
class="c-filter-indication" class="c-filter-indication"
:class="{ 'c-filter-indication--mixed': hasMixedFilters }"> :class="{ 'c-filter-indication--mixed': hasMixedFilters }"
>
<span class="c-filter-indication__mixed">{{ label }}</span> <span class="c-filter-indication__mixed">{{ label }}</span>
<span v-for="(name, index) in filterNames" <span
class="c-filter-indication__label"> v-for="(name, index) in filterNames"
:key="index"
class="c-filter-indication__label"
>
{{ name }} {{ name }}
</span> </span>
</div> </div>
@ -89,6 +94,14 @@
} }
} }
}, },
mounted() {
let filters = this.table.configuration.getConfiguration().filters || {};
this.table.configuration.on('change', this.handleConfigurationChanges);
this.updateFilters(filters);
},
destroyed() {
this.table.configuration.off('change', this.handleConfigurationChanges);
},
methods: { methods: {
setFilterNames() { setFilterNames() {
let names = []; let names = [];
@ -152,14 +165,6 @@
this.filteredTelemetry = JSON.parse(JSON.stringify(filters)); this.filteredTelemetry = JSON.parse(JSON.stringify(filters));
this.setFilterNames(); this.setFilterNames();
} }
},
mounted() {
let filters = this.table.configuration.getConfiguration().filters || {};
this.table.configuration.on('change', this.handleConfigurationChanges);
this.updateFilters(filters);
},
destroyed() {
this.table.configuration.off('change', this.handleConfigurationChanges);
} }
} }
</script> </script>

View File

@ -20,7 +20,12 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
<template> <template>
<td @click="selectCell($event.currentTarget, columnKey)" :title="formattedValue">{{formattedValue}}</td> <td
:title="formattedValue"
@click="selectCell($event.currentTarget, columnKey)"
>
{{ formattedValue }}
</td>
</template> </template>
<script> <script>
export default { export default {
@ -32,11 +37,20 @@ export default {
}, },
columnKey: { columnKey: {
type: String, type: String,
require: true required: true
}, },
objectPath: { objectPath: {
type: Array, type: Array,
require: false required: true
}
},
computed: {
formattedValue() {
return this.row.getFormattedValue(this.columnKey);
},
isSelectable() {
let column = this.row.columns[this.columnKey];
return column && column.selectable;
} }
}, },
methods: { methods: {
@ -57,15 +71,6 @@ export default {
}], false); }], false);
event.stopPropagation(); event.stopPropagation();
} }
},
},
computed: {
formattedValue() {
return this.row.getFormattedValue(this.columnKey);
},
isSelectable() {
let column = this.row.columns[this.columnKey];
return column && column.selectable;
} }
} }
}; };

View File

@ -29,12 +29,17 @@
drop: columnMoveEnd, drop: columnMoveEnd,
dragleave: hideDropTarget, dragleave: hideDropTarget,
dragover: dragOverColumn dragover: dragOverColumn
} : {}"> } : {}"
<div class="c-telemetry-table__headers__content" :class="[ >
<div
class="c-telemetry-table__headers__content"
:class="[
isSortable ? 'is-sortable' : '', isSortable ? 'is-sortable' : '',
isSortable && sortOptions.key === headerKey ? 'is-sorting' : '', isSortable && sortOptions.key === headerKey ? 'is-sorting' : '',
isSortable && sortOptions.direction].join(' ')"> isSortable && sortOptions.direction].join(' ')"
<div class="c-telemetry-table__resize-hitarea" >
<div
class="c-telemetry-table__resize-hitarea"
@mousedown="resizeColumnStart" @mousedown="resizeColumnStart"
></div> ></div>
<slot></slot> <slot></slot>
@ -42,17 +47,31 @@
</th> </th>
</template> </template>
<script> <script>
import _ from 'lodash';
const MOVE_COLUMN_DT_TYPE = 'movecolumnfromindex'; const MOVE_COLUMN_DT_TYPE = 'movecolumnfromindex';
export default { export default {
inject: ['openmct'], inject: ['openmct'],
props: { props: {
headerKey: String, headerKey: {
headerIndex: Number, type: String,
isHeaderTitle: Boolean, default: undefined
sortOptions: Object, },
columnWidth: Number, headerIndex: {
type: Number,
default: undefined
},
isHeaderTitle: {
type: Boolean,
default: undefined
},
sortOptions: {
type: Object,
default: undefined
},
columnWidth: {
type: Number,
default: undefined
},
hotzone: Boolean, hotzone: Boolean,
isEditing: Boolean isEditing: Boolean
}, },

View File

@ -1,18 +1,50 @@
<template> <template>
<div class="c-properties"> <div class="c-properties">
<template v-if="isEditing"> <template v-if="isEditing">
<div class="c-properties__header">Table Column Size</div> <div class="c-properties__header">
Table Column Size
</div>
<ul class="c-properties__section"> <ul class="c-properties__section">
<li class="c-properties__row"> <li class="c-properties__row">
<div class="c-properties__label" title="Auto-size table"><label for="AutoSizeControl">Auto-size</label></div> <div
<div class="c-properties__value"><input type="checkbox" id="AutoSizeControl" :checked="configuration.autosize !== false" @change="toggleAutosize()"></div> class="c-properties__label"
title="Auto-size table"
>
<label for="AutoSizeControl">Auto-size</label>
</div>
<div class="c-properties__value">
<input
id="AutoSizeControl"
type="checkbox"
:checked="configuration.autosize !== false"
@change="toggleAutosize()"
>
</div>
</li> </li>
</ul> </ul>
<div class="c-properties__header">Table Column Visibility</div> <div class="c-properties__header">
Table Column Visibility
</div>
<ul class="c-properties__section"> <ul class="c-properties__section">
<li class="c-properties__row" v-for="(title, key) in headers"> <li
<div class="c-properties__label" title="Show or hide column"><label :for="key + 'ColumnControl'">{{title}}</label></div> v-for="(title, key) in headers"
<div class="c-properties__value"><input type="checkbox" :id="key + 'ColumnControl'" :checked="configuration.hiddenColumns[key] !== true" @change="toggleColumn(key)"></div> :key="key"
class="c-properties__row"
>
<div
class="c-properties__label"
title="Show or hide column"
>
<label :for="key + 'ColumnControl'">{{ title }}</label>
</div>
<div class="c-properties__value">
<input
:id="key + 'ColumnControl'"
type="checkbox"
:checked="configuration.hiddenColumns[key] !== true"
@change="toggleColumn(key)"
>
</div>
</li> </li>
</ul> </ul>
</template> </template>
@ -34,6 +66,28 @@ export default {
configuration: this.tableConfiguration.getConfiguration() configuration: this.tableConfiguration.getConfiguration()
} }
}, },
mounted() {
this.unlisteners = [];
this.openmct.editor.on('isEditing', this.toggleEdit);
let compositionCollection = this.openmct.composition.get(this.tableConfiguration.domainObject);
compositionCollection.load()
.then((composition) => {
this.addColumnsForAllObjects(composition);
this.updateHeaders(this.tableConfiguration.getAllHeaders());
compositionCollection.on('add', this.addObject);
this.unlisteners.push(compositionCollection.off.bind(compositionCollection, 'add', this.addObject));
compositionCollection.on('remove', this.removeObject);
this.unlisteners.push(compositionCollection.off.bind(compositionCollection, 'remove', this.removeObject));
});
},
destroyed() {
this.tableConfiguration.destroy();
this.openmct.editor.off('isEditing', this.toggleEdit);
this.unlisteners.forEach((unlisten) => unlisten());
},
methods: { methods: {
updateHeaders(headers) { updateHeaders(headers) {
this.headers = headers; this.headers = headers;
@ -70,28 +124,6 @@ export default {
this.tableConfiguration.addSingleColumnForObject(telemetryObject, column); this.tableConfiguration.addSingleColumnForObject(telemetryObject, column);
}); });
} }
},
mounted() {
this.unlisteners = [];
this.openmct.editor.on('isEditing', this.toggleEdit);
let compositionCollection = this.openmct.composition.get(this.tableConfiguration.domainObject);
compositionCollection.load()
.then((composition) => {
this.addColumnsForAllObjects(composition);
this.updateHeaders(this.tableConfiguration.getAllHeaders());
compositionCollection.on('add', this.addObject);
this.unlisteners.push(compositionCollection.off.bind(compositionCollection, 'add', this.addObject));
compositionCollection.on('remove', this.removeObject);
this.unlisteners.push(compositionCollection.off.bind(compositionCollection, 'remove', this.removeObject));
});
},
destroyed() {
this.tableConfiguration.destroy();
this.openmct.editor.off('isEditing', this.toggleEdit);
this.unlisteners.forEach((unlisten) => unlisten());
} }
} }
</script> </script>

View File

@ -20,22 +20,25 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
<template> <template>
<tr :style="{ top: rowTop }" <tr
:style="{ top: rowTop }"
class="noselect" class="noselect"
:class="[ :class="[
rowClass, rowClass,
{'is-selected': marked} {'is-selected': marked}
]" ]"
v-on="listeners"> v-on="listeners"
<component v-for="(title, key) in headers" >
:key="key" <component
:is="componentList[key]" :is="componentList[key]"
:columnKey="key" v-for="(title, key) in headers"
:key="key"
:column-key="key"
:style="columnWidths[key] === undefined ? {} : { width: columnWidths[key] + 'px', 'max-width': columnWidths[key] + 'px'}" :style="columnWidths[key] === undefined ? {} : { width: columnWidths[key] + 'px', 'max-width': columnWidths[key] + 'px'}"
:class="[cellLimitClasses[key], selectableColumns[key] ? 'is-selectable' : '']" :class="[cellLimitClasses[key], selectableColumns[key] ? 'is-selectable' : '']"
:objectPath="objectPath" :object-path="objectPath"
:row="row"> :row="row"
</component> />
</tr> </tr>
</template> </template>
@ -55,21 +58,9 @@
import TableCell from './table-cell.vue'; import TableCell from './table-cell.vue';
export default { export default {
inject: ['openmct', 'objectPath'], inject: ['openmct'],
data: function () { components: {
return { TableCell
rowTop: (this.rowOffset + this.rowIndex) * this.rowHeight + 'px',
rowClass: this.row.getRowClass(),
cellLimitClasses: this.row.getCellLimitClasses(),
componentList: Object.keys(this.headers).reduce((components, header) => {
components[header] = this.row.getCellComponentName(header) || 'table-cell';
return components
}, {}),
selectableColumns : Object.keys(this.row.columns).reduce((selectable, columnKeys) => {
selectable[columnKeys] = this.row.columns[columnKeys].selectable;
return selectable;
}, {})
}
}, },
props: { props: {
headers: { headers: {
@ -86,7 +77,7 @@ export default {
}, },
objectPath: { objectPath: {
type: Array, type: Array,
required: false required: true
}, },
rowIndex: { rowIndex: {
type: Number, type: Number,
@ -109,6 +100,42 @@ export default {
default: false default: false
} }
}, },
data: function () {
return {
rowTop: (this.rowOffset + this.rowIndex) * this.rowHeight + 'px',
rowClass: this.row.getRowClass(),
cellLimitClasses: this.row.getCellLimitClasses(),
componentList: Object.keys(this.headers).reduce((components, header) => {
components[header] = this.row.getCellComponentName(header) || 'table-cell';
return components
}, {}),
selectableColumns : Object.keys(this.row.columns).reduce((selectable, columnKeys) => {
selectable[columnKeys] = this.row.columns[columnKeys].selectable;
return selectable;
}, {})
}
},
computed: {
listeners() {
let listenersObject = {
click: this.markRow
}
if (this.row.getContextMenuActions().length) {
listenersObject.contextmenu = this.showContextMenu;
}
return listenersObject;
}
},
// TODO: use computed properties
watch: {
rowOffset: 'calculateRowTop',
row: {
handler: 'formatRow',
deep: true
}
},
methods: { methods: {
calculateRowTop: function (rowOffset) { calculateRowTop: function (rowOffset) {
this.rowTop = (rowOffset + this.rowIndex) * this.rowHeight + 'px'; this.rowTop = (rowOffset + this.rowIndex) * this.rowHeight + 'px';
@ -163,30 +190,6 @@ export default {
this.openmct.contextMenu._showContextMenuForObjectPath(contextualObjectPath, event.x, event.y, this.row.getContextMenuActions()); this.openmct.contextMenu._showContextMenuForObjectPath(contextualObjectPath, event.x, event.y, this.row.getContextMenuActions());
}); });
} }
},
// TODO: use computed properties
watch: {
rowOffset: 'calculateRowTop',
row: {
handler: 'formatRow',
deep: true
}
},
components: {
TableCell
},
computed: {
listeners() {
let listenersObject = {
click: this.markRow
}
if (this.row.getContextMenuActions().length) {
listenersObject.contextmenu = this.showContextMenu;
}
return listenersObject;
}
} }
} }
</script> </script>

View File

@ -22,33 +22,42 @@
<template> <template>
<div class="c-table-wrapper"> <div class="c-table-wrapper">
<div class="c-table-control-bar c-control-bar"> <div class="c-table-control-bar c-control-bar">
<button class="c-button icon-download labeled" <button
v-if="allowExport" v-if="allowExport"
v-on:click="exportAllDataAsCSV()" class="c-button icon-download labeled"
title="Export This View's Data"> title="Export This View's Data"
@click="exportAllDataAsCSV()"
>
<span class="c-button__label">Export Table Data</span> <span class="c-button__label">Export Table Data</span>
</button> </button>
<button class="c-button icon-download labeled" <button
v-if="allowExport" v-if="allowExport"
v-show="markedRows.length" v-show="markedRows.length"
v-on:click="exportMarkedDataAsCSV()" class="c-button icon-download labeled"
title="Export Marked Rows As CSV"> title="Export Marked Rows As CSV"
@click="exportMarkedDataAsCSV()"
>
<span class="c-button__label">Export Marked Rows</span> <span class="c-button__label">Export Marked Rows</span>
</button> </button>
<button class="c-button icon-x labeled" <button
v-show="markedRows.length" v-show="markedRows.length"
v-on:click="unmarkAllRows()" class="c-button icon-x labeled"
title="Unmark All Rows"> title="Unmark All Rows"
@click="unmarkAllRows()"
>
<span class="c-button__label">Unmark All Rows</span> <span class="c-button__label">Unmark All Rows</span>
</button> </button>
<div v-if="enableMarking" <div
class="c-separator"> v-if="enableMarking"
</div> class="c-separator"
<button v-if="enableMarking" ></div>
<button
v-if="enableMarking"
class="c-button icon-pause pause-play labeled" class="c-button icon-pause pause-play labeled"
:class=" paused ? 'icon-play is-paused' : 'icon-pause'" :class=" paused ? 'icon-play is-paused' : 'icon-pause'"
v-on:click="togglePauseByButton()" :title="paused ? 'Continue Data Flow' : 'Pause Data Flow'"
:title="paused ? 'Continue Data Flow' : 'Pause Data Flow'"> @click="togglePauseByButton()"
>
<span class="c-button__label"> <span class="c-button__label">
{{ paused ? 'Play' : 'Pause' }} {{ paused ? 'Play' : 'Pause' }}
</span> </span>
@ -56,97 +65,135 @@
<slot name="buttons"></slot> <slot name="buttons"></slot>
</div> </div>
<div class="c-table c-telemetry-table c-table--filterable c-table--sortable has-control-bar" <div
class="c-table c-telemetry-table c-table--filterable c-table--sortable has-control-bar"
:class="{ :class="{
'loading': loading, 'loading': loading,
'paused' : paused 'paused' : paused
}"> }"
>
<div :style="{ 'max-width': widthWithScroll, 'min-width': '150px'}">
<slot></slot>
</div>
<div :style="{ 'max-width': widthWithScroll, 'min-width': '150px'}"><slot></slot></div> <div
v-if="isDropTargetActive"
<div v-if="isDropTargetActive" class="c-telemetry-table__drop-target" :style="dropTargetStyle"></div> class="c-telemetry-table__drop-target"
:style="dropTargetStyle"
></div>
<!-- Headers table --> <!-- Headers table -->
<div class="c-telemetry-table__headers-w js-table__headers-w" ref="headersTable" :style="{ 'max-width': widthWithScroll}"> <div
ref="headersTable"
class="c-telemetry-table__headers-w js-table__headers-w"
:style="{ 'max-width': widthWithScroll}"
>
<table class="c-table__headers c-telemetry-table__headers"> <table class="c-table__headers c-telemetry-table__headers">
<thead> <thead>
<tr class="c-telemetry-table__headers__labels"> <tr class="c-telemetry-table__headers__labels">
<table-column-header <table-column-header
v-for="(title, key, headerIndex) in headers" v-for="(title, key, headerIndex) in headers"
:key="key" :key="key"
:headerKey="key" :header-key="key"
:headerIndex="headerIndex" :header-index="headerIndex"
:column-width="columnWidths[key]"
:sort-options="sortOptions"
:is-editing="isEditing"
@sort="allowSorting && sortBy(key)" @sort="allowSorting && sortBy(key)"
@resizeColumn="resizeColumn" @resizeColumn="resizeColumn"
@dropTargetOffsetChanged="setDropTargetOffset" @dropTargetOffsetChanged="setDropTargetOffset"
@dropTargetActive="dropTargetActive" @dropTargetActive="dropTargetActive"
@reorderColumn="reorderColumn" @reorderColumn="reorderColumn"
@resizeColumnEnd="updateConfiguredColumnWidths" @resizeColumnEnd="updateConfiguredColumnWidths"
:columnWidth="columnWidths[key]" >
:sortOptions="sortOptions" <span class="c-telemetry-table__headers__label">{{ title }}</span>
:isEditing="isEditing"
><span class="c-telemetry-table__headers__label">{{title}}</span>
</table-column-header> </table-column-header>
</tr> </tr>
<tr v-if="allowFiltering" class="c-telemetry-table__headers__filter"> <tr
v-if="allowFiltering"
class="c-telemetry-table__headers__filter"
>
<table-column-header <table-column-header
v-for="(title, key, headerIndex) in headers" v-for="(title, key, headerIndex) in headers"
:key="key" :key="key"
:headerKey="key" :header-key="key"
:headerIndex="headerIndex" :header-index="headerIndex"
:column-width="columnWidths[key]"
:is-editing="isEditing"
@resizeColumn="resizeColumn" @resizeColumn="resizeColumn"
@dropTargetOffsetChanged="setDropTargetOffset" @dropTargetOffsetChanged="setDropTargetOffset"
@dropTargetActive="dropTargetActive" @dropTargetActive="dropTargetActive"
@reorderColumn="reorderColumn" @reorderColumn="reorderColumn"
@resizeColumnEnd="updateConfiguredColumnWidths" @resizeColumnEnd="updateConfiguredColumnWidths"
:columnWidth="columnWidths[key]"
:isEditing="isEditing"
> >
<search class="c-table__search" <search
v-model="filters[key]" v-model="filters[key]"
v-on:input="filterChanged(key)" class="c-table__search"
v-on:clear="clearFilter(key)" /> @input="filterChanged(key)"
@clear="clearFilter(key)"
/>
</table-column-header> </table-column-header>
</tr> </tr>
</thead> </thead>
</table> </table>
</div> </div>
<!-- Content table --> <!-- Content table -->
<div class="c-table__body-w c-telemetry-table__body-w js-telemetry-table__body-w" @scroll="scroll" :style="{ 'max-width': widthWithScroll}"> <div
<div class="c-telemetry-table__scroll-forcer" :style="{ width: totalWidth + 'px' }"></div> class="c-table__body-w c-telemetry-table__body-w js-telemetry-table__body-w"
<table class="c-table__body c-telemetry-table__body js-telemetry-table__content" :style="{ 'max-width': widthWithScroll}"
:style="{ height: totalHeight + 'px'}"> @scroll="scroll"
>
<div
class="c-telemetry-table__scroll-forcer"
:style="{ width: totalWidth + 'px' }"
></div>
<table
class="c-table__body c-telemetry-table__body js-telemetry-table__content"
:style="{ height: totalHeight + 'px'}"
>
<tbody> <tbody>
<telemetry-table-row v-for="(row, rowIndex) in visibleRows" <telemetry-table-row
v-for="(row, rowIndex) in visibleRows"
:key="rowIndex"
:headers="headers" :headers="headers"
:columnWidths="columnWidths" :column-widths="columnWidths"
:rowIndex="rowIndex" :row-index="rowIndex"
:objectPath="objectPath" :object-path="objectPath"
:rowOffset="rowOffset" :row-offset="rowOffset"
:rowHeight="rowHeight" :row-height="rowHeight"
:row="row" :row="row"
:marked="row.marked" :marked="row.marked"
@mark="markRow" @mark="markRow"
@unmark="unmarkRow" @unmark="unmarkRow"
@markMultipleConcurrent="markMultipleConcurrentRows"> @markMultipleConcurrent="markMultipleConcurrentRows"
</telemetry-table-row> />
</tbody> </tbody>
</table> </table>
</div> </div>
<!-- Sizing table --> <!-- Sizing table -->
<table class="c-telemetry-table__sizing js-telemetry-table__sizing" :style="sizingTableWidth"> <table
class="c-telemetry-table__sizing js-telemetry-table__sizing"
:style="sizingTableWidth"
>
<tr> <tr>
<template v-for="(title, key) in headers"> <template v-for="(title, key) in headers">
<th :key="key" :style="{ width: configuredColumnWidths[key] + 'px', 'max-width': configuredColumnWidths[key] + 'px'}">{{title}}</th> <th
:key="key"
:style="{ width: configuredColumnWidths[key] + 'px', 'max-width': configuredColumnWidths[key] + 'px'}"
>
{{ title }}
</th>
</template> </template>
</tr> </tr>
<telemetry-table-row v-for="(sizingRowData, objectKeyString) in sizingRows" <telemetry-table-row
v-for="(sizingRowData, objectKeyString) in sizingRows"
:key="objectKeyString" :key="objectKeyString"
:headers="headers" :headers="headers"
:columnWidths="configuredColumnWidths" :column-widths="configuredColumnWidths"
:row="sizingRowData"> :row="sizingRowData"
</telemetry-table-row> :object-path="objectPath"
/>
</table> </table>
<telemetry-filter-indicator></telemetry-filter-indicator> <telemetry-filter-indicator />
</div> </div>
</div><!-- closes c-table-wrapper --> </div><!-- closes c-table-wrapper -->
</template> </template>
@ -343,9 +390,6 @@ const VISIBLE_ROW_COUNT = 100;
const ROW_HEIGHT = 17; const ROW_HEIGHT = 17;
const RESIZE_POLL_INTERVAL = 200; const RESIZE_POLL_INTERVAL = 200;
const AUTO_SCROLL_TRIGGER_HEIGHT = 100; const AUTO_SCROLL_TRIGGER_HEIGHT = 100;
const RESIZE_HOT_ZONE = 10;
const MOVE_TRIGGER_WAIT = 500;
const VERTICAL_SCROLL_WIDTH = 30;
export default { export default {
components: { components: {
@ -440,6 +484,59 @@ export default {
return style; return style;
} }
}, },
created() {
this.filterChanged = _.debounce(this.filterChanged, 500);
},
mounted() {
this.csvExporter = new CSVExporter();
this.rowsAdded = _.throttle(this.rowsAdded, 200);
this.rowsRemoved = _.throttle(this.rowsRemoved, 200);
this.scroll = _.throttle(this.scroll, 100);
this.table.on('object-added', this.addObject);
this.table.on('object-removed', this.removeObject);
this.table.on('outstanding-requests', this.outstandingRequests);
this.table.on('refresh', this.clearRowsAndRerender);
this.table.filteredRows.on('add', this.rowsAdded);
this.table.filteredRows.on('remove', this.rowsRemoved);
this.table.filteredRows.on('sort', this.updateVisibleRows);
this.table.filteredRows.on('filter', this.updateVisibleRows);
//Default sort
this.sortOptions = this.table.filteredRows.sortBy();
this.scrollable = this.$el.querySelector('.js-telemetry-table__body-w');
this.contentTable = this.$el.querySelector('.js-telemetry-table__content');
this.sizingTable = this.$el.querySelector('.js-telemetry-table__sizing');
this.headersHolderEl = this.$el.querySelector('.js-table__headers-w');
this.table.configuration.on('change', this.updateConfiguration);
this.calculateTableSize();
this.pollForResize();
this.calculateScrollbarWidth();
this.table.initialize();
},
destroyed() {
this.table.off('object-added', this.addObject);
this.table.off('object-removed', this.removeObject);
this.table.off('outstanding-requests', this.outstandingRequests);
this.table.off('refresh', this.clearRowsAndRerender);
this.table.filteredRows.off('add', this.rowsAdded);
this.table.filteredRows.off('remove', this.rowsRemoved);
this.table.filteredRows.off('sort', this.updateVisibleRows);
this.table.filteredRows.off('filter', this.updateVisibleRows);
this.table.configuration.off('change', this.updateConfiguration);
clearInterval(this.resizePollHandle);
this.table.configuration.destroy();
this.table.destroy();
},
methods: { methods: {
updateVisibleRows() { updateVisibleRows() {
if (!this.updatingView) { if (!this.updatingView) {
@ -817,60 +914,6 @@ export default {
} }
} }
} }
},
created() {
this.filterChanged = _.debounce(this.filterChanged, 500);
},
mounted() {
console.log("Table mounted");
this.csvExporter = new CSVExporter();
this.rowsAdded = _.throttle(this.rowsAdded, 200);
this.rowsRemoved = _.throttle(this.rowsRemoved, 200);
this.scroll = _.throttle(this.scroll, 100);
this.table.on('object-added', this.addObject);
this.table.on('object-removed', this.removeObject);
this.table.on('outstanding-requests', this.outstandingRequests);
this.table.on('refresh', this.clearRowsAndRerender);
this.table.filteredRows.on('add', this.rowsAdded);
this.table.filteredRows.on('remove', this.rowsRemoved);
this.table.filteredRows.on('sort', this.updateVisibleRows);
this.table.filteredRows.on('filter', this.updateVisibleRows);
//Default sort
this.sortOptions = this.table.filteredRows.sortBy();
this.scrollable = this.$el.querySelector('.js-telemetry-table__body-w');
this.contentTable = this.$el.querySelector('.js-telemetry-table__content');
this.sizingTable = this.$el.querySelector('.js-telemetry-table__sizing');
this.headersHolderEl = this.$el.querySelector('.js-table__headers-w');
this.table.configuration.on('change', this.updateConfiguration);
this.calculateTableSize();
this.pollForResize();
this.calculateScrollbarWidth();
this.table.initialize();
},
destroyed() {
this.table.off('object-added', this.addObject);
this.table.off('object-removed', this.removeObject);
this.table.off('outstanding-requests', this.outstandingRequests);
this.table.off('refresh', this.clearRowsAndRerender);
this.table.filteredRows.off('add', this.rowsAdded);
this.table.filteredRows.off('remove', this.rowsRemoved);
this.table.filteredRows.off('sort', this.updateVisibleRows);
this.table.filteredRows.off('filter', this.updateVisibleRows);
this.table.configuration.off('change', this.updateConfiguration);
clearInterval(this.resizePollHandle);
this.table.configuration.destroy();
this.table.destroy();
} }
} }
</script> </script>

View File

@ -20,39 +20,63 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="c-conductor" <div
:class="[isFixed ? 'is-fixed-mode' : 'is-realtime-mode']"> class="c-conductor"
<form class="u-contents" ref="conductorForm" @submit.prevent="updateTimeFromConductor"> :class="[isFixed ? 'is-fixed-mode' : 'is-realtime-mode']"
>
<form
ref="conductorForm"
class="u-contents"
@submit.prevent="updateTimeFromConductor"
>
<div class="c-conductor__time-bounds"> <div class="c-conductor__time-bounds">
<button class="c-input--submit" type="submit" ref="submitButton"></button> <button
<ConductorModeIcon class="c-conductor__mode-icon"></ConductorModeIcon> ref="submitButton"
class="c-input--submit"
type="submit"
></button>
<ConductorModeIcon class="c-conductor__mode-icon" />
<div class="c-ctrl-wrapper c-conductor-input c-conductor__start-fixed" <div
v-if="isFixed"> v-if="isFixed"
class="c-ctrl-wrapper c-conductor-input c-conductor__start-fixed"
>
<!-- Fixed start --> <!-- Fixed start -->
<div class="c-conductor__start-fixed__label">Start</div> <div class="c-conductor__start-fixed__label">
<input class="c-input--datetime" Start
type="text" autocorrect="off" spellcheck="false" </div>
<input
ref="startDate" ref="startDate"
v-model="formattedBounds.start" v-model="formattedBounds.start"
@change="validateAllBounds(); submitForm()" /> class="c-input--datetime"
type="text"
autocorrect="off"
spellcheck="false"
@change="validateAllBounds(); submitForm()"
>
<date-picker <date-picker
v-if="isFixed && isUTCBased" v-if="isFixed && isUTCBased"
:default-date-time="formattedBounds.start" :default-date-time="formattedBounds.start"
:formatter="timeFormatter" :formatter="timeFormatter"
@date-selected="startDateSelected"></date-picker> @date-selected="startDateSelected"
/>
</div> </div>
<div class="c-ctrl-wrapper c-conductor-input c-conductor__start-delta" <div
v-if="!isFixed"> v-if="!isFixed"
class="c-ctrl-wrapper c-conductor-input c-conductor__start-delta"
>
<!-- RT start --> <!-- RT start -->
<div class="c-direction-indicator icon-minus"></div> <div class="c-direction-indicator icon-minus"></div>
<input class="c-input--hrs-min-sec" <input
type="text" autocorrect="off"
ref="startOffset" ref="startOffset"
spellcheck="false"
v-model="offsets.start" v-model="offsets.start"
@change="validateAllOffsets(); submitForm()"> class="c-input--hrs-min-sec"
type="text"
autocorrect="off"
spellcheck="false"
@change="validateAllOffsets(); submitForm()"
>
</div> </div>
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end-fixed"> <div class="c-ctrl-wrapper c-conductor-input c-conductor__end-fixed">
@ -60,45 +84,57 @@
<div class="c-conductor__end-fixed__label"> <div class="c-conductor__end-fixed__label">
{{ isFixed ? 'End' : 'Updated' }} {{ isFixed ? 'End' : 'Updated' }}
</div> </div>
<input class="c-input--datetime" <input
type="text" autocorrect="off" spellcheck="false"
v-model="formattedBounds.end"
:disabled="!isFixed"
ref="endDate" ref="endDate"
@change="validateAllBounds(); submitForm()"> v-model="formattedBounds.end"
class="c-input--datetime"
type="text"
autocorrect="off"
spellcheck="false"
:disabled="!isFixed"
@change="validateAllBounds(); submitForm()"
>
<date-picker <date-picker
v-if="isFixed && isUTCBased" v-if="isFixed && isUTCBased"
class="c-ctrl-wrapper--menus-left" class="c-ctrl-wrapper--menus-left"
:default-date-time="formattedBounds.end" :default-date-time="formattedBounds.end"
:formatter="timeFormatter" :formatter="timeFormatter"
@date-selected="endDateSelected"></date-picker> @date-selected="endDateSelected"
/>
</div> </div>
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end-delta" <div
v-if="!isFixed"> v-if="!isFixed"
class="c-ctrl-wrapper c-conductor-input c-conductor__end-delta"
>
<!-- RT end --> <!-- RT end -->
<div class="c-direction-indicator icon-plus"></div> <div class="c-direction-indicator icon-plus"></div>
<input class="c-input--hrs-min-sec" <input
ref="endOffset"
v-model="offsets.end"
class="c-input--hrs-min-sec"
type="text" type="text"
autocorrect="off" autocorrect="off"
spellcheck="false" spellcheck="false"
ref="endOffset" @change="validateAllOffsets(); submitForm()"
v-model="offsets.end" >
@change="validateAllOffsets(); submitForm()">
</div> </div>
<conductor-axis <conductor-axis
class="c-conductor__ticks" class="c-conductor__ticks"
:bounds="rawBounds" :bounds="rawBounds"
@panAxis="setViewFromBounds"></conductor-axis> @panAxis="setViewFromBounds"
/>
</div> </div>
<div class="c-conductor__controls"> <div class="c-conductor__controls">
<!-- Mode, time system menu buttons and duration slider --> <!-- Mode, time system menu buttons and duration slider -->
<ConductorMode class="c-conductor__mode-select"></ConductorMode> <ConductorMode class="c-conductor__mode-select" />
<ConductorTimeSystem class="c-conductor__time-system-select"></ConductorTimeSystem> <ConductorTimeSystem class="c-conductor__time-system-select" />
</div> </div>
<input type="submit" class="invisible"> <input
type="submit"
class="invisible"
>
</form> </form>
</div> </div>
</template> </template>
@ -288,7 +324,6 @@
</style> </style>
<script> <script>
import moment from 'moment';
import ConductorMode from './ConductorMode.vue'; import ConductorMode from './ConductorMode.vue';
import ConductorTimeSystem from './ConductorTimeSystem.vue'; import ConductorTimeSystem from './ConductorTimeSystem.vue';
import DatePicker from './DatePicker.vue'; import DatePicker from './DatePicker.vue';
@ -296,11 +331,6 @@ import ConductorAxis from './ConductorAxis.vue';
import ConductorModeIcon from './ConductorModeIcon.vue'; import ConductorModeIcon from './ConductorModeIcon.vue';
const DEFAULT_DURATION_FORMATTER = 'duration'; const DEFAULT_DURATION_FORMATTER = 'duration';
const SECONDS = 1000;
const DAYS = 24 * 60 * 60 * SECONDS;
const YEARS = 365 * DAYS;
const RESIZE_POLL_INTERVAL = 200;
export default { export default {
inject: ['openmct', 'configuration'], inject: ['openmct', 'configuration'],
@ -323,7 +353,7 @@ export default {
durationFormatter: durationFormatter, durationFormatter: durationFormatter,
offsets: { offsets: {
start: offsets && durationFormatter.format(Math.abs(offsets.start)), start: offsets && durationFormatter.format(Math.abs(offsets.start)),
end: offsets && durationFormatter.format(Math.abs(offsets.end)), end: offsets && durationFormatter.format(Math.abs(offsets.end))
}, },
formattedBounds: { formattedBounds: {
start: timeFormatter.format(bounds.start), start: timeFormatter.format(bounds.start),
@ -338,6 +368,14 @@ export default {
showDatePicker: false showDatePicker: false
} }
}, },
mounted() {
this.setTimeSystem(JSON.parse(JSON.stringify(this.openmct.time.timeSystem())));
this.openmct.time.on('bounds', this.setViewFromBounds);
this.openmct.time.on('timeSystem', this.setTimeSystem);
this.openmct.time.on('clock', this.setViewFromClock);
this.openmct.time.on('clockOffsets', this.setViewFromOffsets)
},
methods: { methods: {
setTimeSystem(timeSystem) { setTimeSystem(timeSystem) {
this.timeFormatter = this.getFormatter(timeSystem.timeFormat); this.timeFormatter = this.getFormatter(timeSystem.timeFormat);
@ -491,15 +529,7 @@ export default {
this.formattedBounds.end = this.timeFormatter.format(date); this.formattedBounds.end = this.timeFormatter.format(date);
this.validateAllBounds(); this.validateAllBounds();
this.submitForm(); this.submitForm();
}, }
},
mounted() {
this.setTimeSystem(JSON.parse(JSON.stringify(this.openmct.time.timeSystem())));
this.openmct.time.on('bounds', this.setViewFromBounds);
this.openmct.time.on('timeSystem', this.setTimeSystem);
this.openmct.time.on('clock', this.setViewFromClock);
this.openmct.time.on('clockOffsets', this.setViewFromOffsets)
} }
} }
</script> </script>

View File

@ -20,10 +20,11 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="c-conductor-axis" <div
ref="axisHolder" ref="axisHolder"
@mousedown="dragStart($event)"> class="c-conductor-axis"
</div> @mousedown="dragStart($event)"
></div>
</template> </template>
<style lang="scss"> <style lang="scss">
@ -126,7 +127,42 @@ const PIXELS_PER_TICK_WIDE = 200;
export default { export default {
inject: ['openmct'], inject: ['openmct'],
props: { props: {
bounds: Object bounds: {
type: Object,
required: true
}
},
watch: {
bounds: {
handler(bounds) {
this.setScale();
},
deep: true
}
},
mounted() {
let axisHolder = this.$refs.axisHolder;
let height = axisHolder.offsetHeight;
let vis = d3Selection.select(axisHolder)
.append("svg:svg")
.attr("width", "100%")
.attr("height", height);
this.width = this.$refs.axisHolder.clientWidth;
this.xAxis = d3Axis.axisTop();
this.dragging = false;
// draw x axis with labels. CSS is used to position them.
this.axisElement = vis.append("g");
this.setViewFromTimeSystem(this.openmct.time.timeSystem());
this.setScale();
//Respond to changes in conductor
this.openmct.time.on("timeSystem", this.setViewFromTimeSystem);
setInterval(this.resize, RESIZE_POLL_INTERVAL);
},
destroyed() {
}, },
methods: { methods: {
setScale() { setScale() {
@ -153,9 +189,6 @@ export default {
this.msPerPixel = (bounds.end - bounds.start) / this.width; this.msPerPixel = (bounds.end - bounds.start) / this.width;
}, },
setViewFromTimeSystem(timeSystem) { setViewFromTimeSystem(timeSystem) {
let format = this.getActiveFormatter();
let bounds = this.openmct.time.bounds();
//The D3 scale used depends on the type of time system as d3 //The D3 scale used depends on the type of time system as d3
// supports UTC out of the box. // supports UTC out of the box.
if (timeSystem.isUTCBased) { if (timeSystem.isUTCBased) {
@ -227,38 +260,6 @@ export default {
this.setScale(); this.setScale();
} }
} }
},
watch: {
bounds: {
handler(bounds) {
this.setScale();
},
deep: true
}
},
mounted() {
let axisHolder = this.$refs.axisHolder;
let height = axisHolder.offsetHeight;
let vis = d3Selection.select(axisHolder)
.append("svg:svg")
.attr("width", "100%")
.attr("height", height);
this.width = this.$refs.axisHolder.clientWidth;
this.xAxis = d3Axis.axisTop();
this.dragging = false;
// draw x axis with labels. CSS is used to position them.
this.axisElement = vis.append("g");
this.setViewFromTimeSystem(this.openmct.time.timeSystem());
this.setScale();
//Respond to changes in conductor
this.openmct.time.on("timeSystem", this.setViewFromTimeSystem);
setInterval(this.resize, RESIZE_POLL_INTERVAL);
},
destroyed() {
} }
} }

View File

@ -21,29 +21,39 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up"> <div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up">
<button class="c-button--menu c-mode-button" <button
@click.prevent="toggle"> class="c-button--menu c-mode-button"
@click.prevent="toggle"
>
<span class="c-button__label">{{ selectedMode.name }}</span> <span class="c-button__label">{{ selectedMode.name }}</span>
</button> </button>
<div class="c-menu c-super-menu c-conductor__mode-menu" <div
v-if="open"> v-if="open"
class="c-menu c-super-menu c-conductor__mode-menu"
>
<div class="c-super-menu__menu"> <div class="c-super-menu__menu">
<ul> <ul>
<li v-for="mode in modes" <li
v-for="mode in modes"
:key="mode.key" :key="mode.key"
class="menu-item-a"
:class="mode.cssClass"
@click="setOption(mode)" @click="setOption(mode)"
@mouseover="hoveredMode = mode" @mouseover="hoveredMode = mode"
@mouseleave="hoveredMode = {}" @mouseleave="hoveredMode = {}"
class="menu-item-a" >
:class="mode.cssClass">
{{ mode.name }} {{ mode.name }}
</li> </li>
</ul> </ul>
</div> </div>
<div class="c-super-menu__item-description"> <div class="c-super-menu__item-description">
<div :class="['l-item-description__icon', 'bg-' + hoveredMode.cssClass]"></div> <div :class="['l-item-description__icon', 'bg-' + hoveredMode.cssClass]"></div>
<div class="l-item-description__name">{{hoveredMode.name}}</div> <div class="l-item-description__name">
<div class="l-item-description__description">{{hoveredMode.description}}</div> {{ hoveredMode.name }}
</div>
<div class="l-item-description__description">
{{ hoveredMode.description }}
</div>
</div> </div>
</div> </div>
</div> </div>
@ -87,6 +97,14 @@ export default {
hoveredMode: {} hoveredMode: {}
}; };
}, },
mounted: function () {
this.loadClocksFromConfiguration();
this.openmct.time.on('clock', this.setViewFromClock);
},
destroyed: function () {
this.openmct.time.off('clock', this.setViewFromClock);
},
methods: { methods: {
loadClocksFromConfiguration() { loadClocksFromConfiguration() {
let clocks = this.configuration.menuOptions let clocks = this.configuration.menuOptions
@ -180,14 +198,6 @@ export default {
setViewFromClock(clock) { setViewFromClock(clock) {
this.selectedMode = this.getModeOptionForClock(clock); this.selectedMode = this.getModeOptionForClock(clock);
} }
},
mounted: function () {
this.loadClocksFromConfiguration();
this.openmct.time.on('clock', this.setViewFromClock);
},
destroyed: function () {
this.openmct.time.off('clock', this.setViewFromClock);
} }
} }

View File

@ -20,19 +20,28 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up" <div
v-if="selectedTimeSystem.name"> v-if="selectedTimeSystem.name"
<button class="c-button--menu c-time-system-button" class="c-ctrl-wrapper c-ctrl-wrapper--menus-up"
>
<button
class="c-button--menu c-time-system-button"
:class="selectedTimeSystem.cssClass" :class="selectedTimeSystem.cssClass"
@click.prevent="toggle"> @click.prevent="toggle"
>
<span class="c-button__label">{{ selectedTimeSystem.name }}</span> <span class="c-button__label">{{ selectedTimeSystem.name }}</span>
</button> </button>
<div class="c-menu" v-if="open"> <div
v-if="open"
class="c-menu"
>
<ul> <ul>
<li @click="setTimeSystemFromView(timeSystem)" <li
v-for="timeSystem in timeSystems" v-for="timeSystem in timeSystems"
:key="timeSystem.key" :key="timeSystem.key"
:class="timeSystem.cssClass"> :class="timeSystem.cssClass"
@click="setTimeSystemFromView(timeSystem)"
>
{{ timeSystem.name }} {{ timeSystem.name }}
</li> </li>
</ul> </ul>
@ -54,6 +63,14 @@ export default {
timeSystems: this.getValidTimesystemsForClock(activeClock) timeSystems: this.getValidTimesystemsForClock(activeClock)
}; };
}, },
mounted: function () {
this.openmct.time.on('timeSystem', this.setViewFromTimeSystem);
this.openmct.time.on('clock', this.setViewFromClock);
},
destroyed: function () {
this.openmct.time.off('timeSystem', this.setViewFromTimeSystem);
this.openmct.time.on('clock', this.setViewFromClock);
},
methods: { methods: {
getValidTimesystemsForClock(clock) { getValidTimesystemsForClock(clock) {
return this.configuration.menuOptions return this.configuration.menuOptions
@ -111,14 +128,6 @@ export default {
let activeClock = this.openmct.time.clock(); let activeClock = this.openmct.time.clock();
this.timeSystems = this.getValidTimesystemsForClock(activeClock); this.timeSystems = this.getValidTimesystemsForClock(activeClock);
} }
},
mounted: function () {
this.openmct.time.on('timeSystem', this.setViewFromTimeSystem);
this.openmct.time.on('clock', this.setViewFromClock);
},
destroyed: function () {
this.openmct.time.off('timeSystem', this.setViewFromTimeSystem);
this.openmct.time.on('clock', this.setViewFromClock);
} }
} }

View File

@ -20,36 +20,63 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up c-datetime-picker__wrapper" ref="calendarHolder"> <div
<a class="c-icon-button icon-calendar" ref="calendarHolder"
@click="toggle"></a> class="c-ctrl-wrapper c-ctrl-wrapper--menus-up c-datetime-picker__wrapper"
<div class="c-menu c-menu--mobile-modal c-datetime-picker" >
v-if="open"> <a
class="c-icon-button icon-calendar"
@click="toggle"
></a>
<div
v-if="open"
class="c-menu c-menu--mobile-modal c-datetime-picker"
>
<div class="c-datetime-picker__close-button"> <div class="c-datetime-picker__close-button">
<button class="c-click-icon icon-x-in-circle" <button
@click="toggle"></button> class="c-click-icon icon-x-in-circle"
@click="toggle"
></button>
</div> </div>
<div class="c-datetime-picker__pager c-pager l-month-year-pager"> <div class="c-datetime-picker__pager c-pager l-month-year-pager">
<div class="c-pager__prev c-icon-button icon-arrow-left" <div
@click.stop="changeMonth(-1)"></div> class="c-pager__prev c-icon-button icon-arrow-left"
<div class="c-pager__month-year">{{model.month}} {{model.year}}</div> @click.stop="changeMonth(-1)"
<div class="c-pager__next c-icon-button icon-arrow-right" ></div>
@click.stop="changeMonth(1)"></div> <div class="c-pager__month-year">
{{ model.month }} {{ model.year }}
</div>
<div
class="c-pager__next c-icon-button icon-arrow-right"
@click.stop="changeMonth(1)"
></div>
</div> </div>
<div class="c-datetime-picker__calendar c-calendar"> <div class="c-datetime-picker__calendar c-calendar">
<ul class="c-calendar__row--header l-cal-row"> <ul class="c-calendar__row--header l-cal-row">
<li v-for="day in ['Su','Mo','Tu','We','Th','Fr','Sa']" <li
:key="day">{{day}}</li> v-for="day in ['Su','Mo','Tu','We','Th','Fr','Sa']"
:key="day"
>
{{ day }}
</li>
</ul> </ul>
<ul class="c-calendar__row--body" <ul
v-for="(row, index) in table" v-for="(row, tableIndex) in table"
:key="index"> :key="tableIndex"
<li v-for="(cell, index) in row" class="c-calendar__row--body"
:key="index" >
<li
v-for="(cell, rowIndex) in row"
:key="rowIndex"
:class="{ 'is-in-month': isInCurrentMonth(cell), selected: isSelected(cell) }"
@click="select(cell)" @click="select(cell)"
:class="{ 'is-in-month': isInCurrentMonth(cell), selected: isSelected(cell) }"> >
<div class="c-calendar__day--prime">{{cell.day}}</div> <div class="c-calendar__day--prime">
<div class="c-calendar__day--sub">{{cell.dayOfYear}}</div> {{ cell.day }}
</div>
<div class="c-calendar__day--sub">
{{ cell.dayOfYear }}
</div>
</li> </li>
</ul> </ul>
</div> </div>
@ -184,8 +211,14 @@ export default {
inject: ['openmct'], inject: ['openmct'],
mixins: [toggleMixin], mixins: [toggleMixin],
props: { props: {
defaultDateTime: String, defaultDateTime: {
formatter: Object type: String,
default: undefined
},
formatter: {
type: Object,
required: true
}
}, },
data: function () { data: function () {
return { return {
@ -196,13 +229,17 @@ export default {
}, },
model: { model: {
year: undefined, year: undefined,
month: undefined, month: undefined
}, },
table: undefined, table: undefined,
date: undefined, date: undefined,
time: undefined time: undefined
} }
}, },
mounted: function () {
this.updateFromModel(this.defaultDateTime);
this.updateViewForMonth();
},
methods: { methods: {
generateTable() { generateTable() {
let m = moment.utc({ year: this.picker.year, month: this.picker.month }).day(0), let m = moment.utc({ year: this.picker.year, month: this.picker.month }).day(0),
@ -233,9 +270,7 @@ export default {
}, },
updateFromModel(defaultDateTime) { updateFromModel(defaultDateTime) {
let m; let m = moment.utc(defaultDateTime);
m = moment.utc(defaultDateTime);
this.date = { this.date = {
year: m.year(), year: m.year(),
@ -314,11 +349,7 @@ export default {
optionsFor(key) { optionsFor(key) {
return TIME_OPTIONS[key]; return TIME_OPTIONS[key];
}, }
},
mounted: function () {
this.updateFromModel(this.defaultDateTime);
this.updateViewForMonth();
} }
} }
</script> </script>

View File

@ -37,6 +37,7 @@ export default function WebPage(openmct) {
return { return {
show: function (element) { show: function (element) {
component = new Vue({ component = new Vue({
el: element,
components: { components: {
WebPageComponent: WebPageComponent WebPageComponent: WebPageComponent
}, },
@ -44,7 +45,6 @@ export default function WebPage(openmct) {
openmct, openmct,
domainObject domainObject
}, },
el: element,
template: '<web-page-component></web-page-component>' template: '<web-page-component></web-page-component>'
}); });
}, },

View File

@ -20,33 +20,39 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="c-so-view has-local-controls" <div
class="c-so-view has-local-controls"
:class="{ :class="{
'c-so-view--no-frame': !hasFrame, 'c-so-view--no-frame': !hasFrame,
'has-complex-content': complexContent 'has-complex-content': complexContent
}"> }"
>
<div class="c-so-view__header"> <div class="c-so-view__header">
<div class="c-so-view__header__icon" :class="cssClass"></div> <div
class="c-so-view__header__icon"
:class="cssClass"
></div>
<div class="c-so-view__header__name"> <div class="c-so-view__header__name">
{{ domainObject && domainObject.name }} {{ domainObject && domainObject.name }}
</div> </div>
<context-menu-drop-down <context-menu-drop-down
:object-path="objectPath"> :object-path="objectPath"
</context-menu-drop-down> />
</div> </div>
<div class="c-so-view__local-controls c-so-view__view-large h-local-controls c-local-controls--show-on-hover"> <div class="c-so-view__local-controls c-so-view__view-large h-local-controls c-local-controls--show-on-hover">
<button class="c-button icon-expand" <button
class="c-button icon-expand"
title="View Large" title="View Large"
@click="expand"> @click="expand"
</button> ></button>
</div> </div>
<object-view <object-view
class="c-so-view__object-view"
ref="objectView" ref="objectView"
class="c-so-view__object-view"
:object="domainObject" :object="domainObject"
:show-edit-view="showEditView" :show-edit-view="showEditView"
:object-path="objectPath"> :object-path="objectPath"
</object-view> />
</div> </div>
</template> </template>
@ -143,18 +149,34 @@
export default { export default {
inject: ['openmct'], inject: ['openmct'],
components: {
ObjectView,
ContextMenuDropDown
},
props: { props: {
domainObject: Object, domainObject: {
objectPath: Array, type: Object,
required: true
},
objectPath: {
type: Array,
required: true
},
hasFrame: Boolean, hasFrame: Boolean,
showEditView: { showEditView: {
type: Boolean, type: Boolean,
default: () => true default: true
} }
}, },
components: { data() {
ObjectView, let objectType = this.openmct.types.get(this.domainObject.type),
ContextMenuDropDown, cssClass = objectType && objectType.definition ? objectType.definition.cssClass : 'icon-object-unknown',
complexContent = !SIMPLE_CONTENT_TYPES.includes(this.domainObject.type);
return {
cssClass,
complexContent
}
}, },
methods: { methods: {
expand() { expand() {
@ -173,16 +195,6 @@
getSelectionContext() { getSelectionContext() {
return this.$refs.objectView.getSelectionContext(); return this.$refs.objectView.getSelectionContext();
} }
},
data() {
let objectType = this.openmct.types.get(this.domainObject.type),
cssClass = objectType && objectType.definition ? objectType.definition.cssClass : 'icon-object-unknown',
complexContent = !SIMPLE_CONTENT_TYPES.includes(this.domainObject.type);
return {
cssClass,
complexContent
}
} }
} }
</script> </script>

View File

@ -1,11 +1,15 @@
<template> <template>
<a class="c-tree__item__label c-object-label" <a
class="c-tree__item__label c-object-label"
draggable="true" draggable="true"
:href="objectLink"
@dragstart="dragStart" @dragstart="dragStart"
@click="navigateOrPreview" @click="navigateOrPreview"
:href="objectLink"> >
<div class="c-tree__item__type-icon c-object-label__type-icon" <div
:class="typeClass"></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">{{ observedObject.name }}</div> <div class="c-tree__item__name c-object-label__name">{{ observedObject.name }}</div>
</a> </a>
</template> </template>
@ -53,29 +57,24 @@ export default {
mixins: [ObjectLink, ContextMenuGesture], mixins: [ObjectLink, ContextMenuGesture],
inject: ['openmct'], inject: ['openmct'],
props: { props: {
domainObject: Object, domainObject: {
type: Object,
required: true
},
objectPath: { objectPath: {
type: Array, type: Array,
default() { required: true
return [];
}
}, },
navigateToPath: String navigateToPath: {
type: String,
default: undefined
}
}, },
data() { data() {
return { return {
observedObject: this.domainObject observedObject: this.domainObject
}; };
}, },
mounted() {
if (this.observedObject) {
let removeListener = this.openmct.objects.observe(this.observedObject, '*', (newObject) => {
this.observedObject = newObject;
});
this.$once('hook:destroyed', removeListener);
}
this.previewAction = new PreviewAction(this.openmct);
},
computed: { computed: {
typeClass() { typeClass() {
let type = this.openmct.types.get(this.observedObject.type); let type = this.openmct.types.get(this.observedObject.type);
@ -85,6 +84,15 @@ export default {
return type.definition.cssClass; return type.definition.cssClass;
} }
}, },
mounted() {
if (this.observedObject) {
let removeListener = this.openmct.objects.observe(this.observedObject, '*', (newObject) => {
this.observedObject = newObject;
});
this.$once('hook:destroyed', removeListener);
}
this.previewAction = new PreviewAction(this.openmct);
},
methods: { methods: {
navigateOrPreview(event) { navigateOrPreview(event) {
if (this.openmct.editor.isEditing()) { if (this.openmct.editor.isEditing()) {

View File

@ -1,4 +1,5 @@
<template> <template>
<div></div>
</template> </template>
<script> <script>
@ -7,10 +8,23 @@ import _ from "lodash"
export default { export default {
inject: ["openmct"], inject: ["openmct"],
props: { props: {
view: String, object: {
object: Object, type: Object,
default: undefined
},
showEditView: Boolean, showEditView: Boolean,
objectPath: Array objectPath: {
type: Array,
default: () => {
return [];
}
}
},
watch: {
object(newObject, oldObject) {
this.currentObject = newObject;
this.debounceUpdateView();
}
}, },
destroyed() { destroyed() {
this.clear(); this.clear();
@ -18,16 +32,6 @@ export default {
this.releaseEditModeHandler(); this.releaseEditModeHandler();
} }
}, },
watch: {
view(newView, oldView) {
this.viewKey = newView;
this.debounceUpdateView();
},
object(newObject, oldObject) {
this.currentObject = newObject;
this.debounceUpdateView();
}
},
created() { created() {
this.debounceUpdateView = _.debounce(this.updateView, 10); this.debounceUpdateView = _.debounce(this.updateView, 10);
}, },
@ -114,7 +118,7 @@ export default {
this.currentView.show(this.viewContainer, this.openmct.editor.isEditing()); this.currentView.show(this.viewContainer, this.openmct.editor.isEditing());
if (immediatelySelect) { if (immediatelySelect) {
this.removeSelectable = openmct.selection.selectable( this.removeSelectable = this.openmct.selection.selectable(
this.$el, this.getSelectionContext(), true); this.$el, this.getSelectionContext(), true);
} }

View File

@ -1,13 +1,16 @@
<template> <template>
<div class="c-progress-bar"> <div class="c-progress-bar">
<div class="c-progress-bar__holder"> <div class="c-progress-bar__holder">
<div class="c-progress-bar__bar" <div
class="c-progress-bar__bar"
:class="{'--indeterminate': model.progressPerc === 'unknown'}" :class="{'--indeterminate': model.progressPerc === 'unknown'}"
:style="`width: ${model.progressPerc}%;`"> :style="styleBarWidth"
></div>
</div> </div>
</div> <div
<div class="c-progress-bar__text" v-if="model.progressText !== undefined"
v-if="model.progressText !== undefined"> class="c-progress-bar__text"
>
<span v-if="model.progressPerc > 0">{{ model.progressPerc }}% complete.</span> <span v-if="model.progressPerc > 0">{{ model.progressPerc }}% complete.</span>
{{ model.progressText }} {{ model.progressText }}
</div> </div>
@ -64,6 +67,16 @@
<script> <script>
export default { export default {
props:['model'] props: {
model: {
type: Object,
required: true
}
},
computed: {
styleBarWidth() {
return `width: ${this.model.progressPerc}%;`
}
}
} }
</script> </script>

View File

@ -1,9 +1,11 @@
<template> <template>
<label class="c-toggle-switch"> <label class="c-toggle-switch">
<input type="checkbox" <input
:id="id" :id="id"
type="checkbox"
:checked="checked" :checked="checked"
@change="onUserSelect($event)"/> @change="onUserSelect($event)"
>
<span class="c-toggle-switch__slider"></span> <span class="c-toggle-switch__slider"></span>
</label> </label>
</template> </template>
@ -66,7 +68,10 @@
export default { export default {
inject: ['openmct'], inject: ['openmct'],
props: { props: {
id: String, id: {
type: String,
required: true
},
checked: Boolean checked: Boolean
}, },
methods: { methods: {

View File

@ -1,14 +1,21 @@
<template> <template>
<div class="c-so-view__context-actions c-disclosure-button" <div
@click="showContextMenu"></div> class="c-so-view__context-actions c-disclosure-button"
@click="showContextMenu"
></div>
</template> </template>
<script> <script>
import contextMenu from '../mixins/context-menu-gesture' import contextMenu from '../mixins/context-menu-gesture'
export default { export default {
props: ['objectPath'],
mixins: [contextMenu], mixins: [contextMenu],
props: {
objectPath: {
type: Array,
required: true
}
}
} }
</script> </script>

View File

@ -1,14 +1,20 @@
<template> <template>
<div class="c-search" <div
:class="{ 'is-active': active === true }"> class="c-search"
<input class="c-search__input" :class="{ 'is-active': active === true }"
>
<input
class="c-search__input"
tabindex="10000" tabindex="10000"
type="search" type="search"
v-bind="$attrs" v-bind="$attrs"
v-bind:value="value" :value="value"
v-on="inputListeners"/> v-on="inputListeners"
<a class="c-search__clear-input icon-x-in-circle" >
v-on:click="clearInput"></a> <a
class="c-search__clear-input icon-x-in-circle"
@click="clearInput"
></a>
</div> </div>
</template> </template>
@ -48,7 +54,15 @@
export default { export default {
inheritAttrs: false, inheritAttrs: false,
props: { props: {
value: String value: {
type: String,
default: ''
}
},
data: function () {
return {
active: false
}
}, },
computed: { computed: {
inputListeners: function () { inputListeners: function () {
@ -64,11 +78,6 @@
) )
} }
}, },
data: function() {
return {
active: false
}
},
methods: { methods: {
clearInput() { clearInput() {
// Clear the user's input and set 'active' to false // Clear the user's input and set 'active' to false

View File

@ -1,10 +1,12 @@
<template> <template>
<span class="c-disclosure-triangle" <span
class="c-disclosure-triangle"
:class="{ :class="{
'c-disclosure-triangle--expanded' : value, 'c-disclosure-triangle--expanded' : value,
'is-enabled' : enabled 'is-enabled' : enabled
}" }"
@click="$emit('input', !value)"></span> @click="$emit('input', !value)"
></span>
</template> </template>
<script> <script>

View File

@ -1,29 +1,49 @@
<template> <template>
<div class="c-elements-pool"> <div class="c-elements-pool">
<Search class="c-elements-pool__search" <Search
class="c-elements-pool__search"
:value="currentSearch" :value="currentSearch"
@input="applySearch" @input="applySearch"
@clear="applySearch"> @clear="applySearch"
</Search> />
<div class="c-elements-pool__elements" <div
:class="{'is-dragging': isDragging}"> class="c-elements-pool__elements"
<ul class="c-tree c-elements-pool__tree" id="inspector-elements-tree" :class="{'is-dragging': isDragging}"
v-if="elements.length > 0"> >
<li :key="element.identifier.key" v-for="(element, index) in elements" <ul
v-if="elements.length > 0"
id="inspector-elements-tree"
class="c-tree c-elements-pool__tree"
>
<li
v-for="(element, index) in elements"
:key="element.identifier.key"
@drop="moveTo(index)" @drop="moveTo(index)"
@dragover="allowDrop"> @dragover="allowDrop"
<div class="c-tree__item c-elements-pool__item" >
<div
class="c-tree__item c-elements-pool__item"
draggable="true" draggable="true"
@dragstart="moveFrom(index)"> @dragstart="moveFrom(index)"
<span class="c-elements-pool__grippy" >
v-if="elements.length > 1 && isEditing"> <span
</span> v-if="elements.length > 1 && isEditing"
<object-label :domainObject="element" :objectPath="[element, parentObject]"></object-label> class="c-elements-pool__grippy"
></span>
<object-label
:domain-object="element"
:object-path="[element, parentObject]"
/>
</div> </div>
</li> </li>
<li class="js-last-place" @drop="moveToIndex(elements.length)"></li> <li
class="js-last-place"
@drop="moveToIndex(elements.length)"
></li>
</ul> </ul>
<div v-if="elements.length === 0">No contained elements</div> <div v-if="elements.length === 0">
No contained elements
</div>
</div> </div>
</div> </div>
</template> </template>
@ -95,6 +115,17 @@ export default {
this.openmct.selection.on('change', this.showSelection); this.openmct.selection.on('change', this.showSelection);
this.openmct.editor.on('isEditing', this.setEditState); this.openmct.editor.on('isEditing', this.setEditState);
}, },
destroyed() {
this.openmct.editor.off('isEditing', this.setEditState);
this.openmct.selection.off('change', this.showSelection);
if (this.mutationUnobserver) {
this.mutationUnobserver();
}
if (this.compositionUnlistener) {
this.compositionUnlistener();
}
},
methods: { methods: {
setEditState(isEditing) { setEditState(isEditing) {
this.isEditing = isEditing; this.isEditing = isEditing;
@ -177,17 +208,6 @@ export default {
this.isDragging = false; this.isDragging = false;
document.removeEventListener('dragend', this.hideDragStyling); document.removeEventListener('dragend', this.hideDragStyling);
} }
},
destroyed() {
this.openmct.editor.off('isEditing', this.setEditState);
this.openmct.selection.off('change', this.showSelection);
if (this.mutationUnobserver) {
this.mutationUnobserver();
}
if (this.compositionUnlistener) {
this.compositionUnlistener();
}
} }
} }
</script> </script>

View File

@ -1,15 +1,20 @@
<template> <template>
<multipane class="c-inspector" <multipane
type="vertical"> class="c-inspector"
type="vertical"
>
<pane class="c-inspector__properties"> <pane class="c-inspector__properties">
<properties></properties> <properties />
<location></location> <location />
<inspector-views></inspector-views> <inspector-views />
</pane> </pane>
<pane class="c-inspector__elements" <pane
v-if="isEditing && hasComposition"
class="c-inspector__elements"
handle="before" handle="before"
label="Elements" v-if="isEditing && hasComposition"> label="Elements"
<elements></elements> >
<elements />
</pane> </pane>
</multipane> </multipane>
</template> </template>
@ -183,9 +188,6 @@
export default { export default {
inject: ['openmct'], inject: ['openmct'],
props: {
'isEditing': Boolean
},
components: { components: {
multipane, multipane,
pane, pane,
@ -194,11 +196,21 @@
Location, Location,
InspectorViews InspectorViews
}, },
props: {
'isEditing': Boolean
},
data() { data() {
return { return {
hasComposition: false hasComposition: false
} }
}, },
mounted() {
this.openmct.selection.on('change', this.refreshComposition);
this.refreshComposition(this.openmct.selection.get());
},
destroyed() {
this.openmct.selection.off('change', this.refreshComposition);
},
methods: { methods: {
refreshComposition(selection) { refreshComposition(selection) {
if (selection.length > 0 && selection[0].length > 0) { if (selection.length > 0 && selection[0].length > 0) {
@ -207,13 +219,6 @@
this.hasComposition = !!(parentObject && this.openmct.composition.get(parentObject)); this.hasComposition = !!(parentObject && this.openmct.composition.get(parentObject));
} }
} }
},
mounted() {
this.openmct.selection.on('change', this.refreshComposition);
this.refreshComposition(this.openmct.selection.get());
},
destroyed() {
this.openmct.selection.off('change', this.refreshComposition);
} }
} }
</script> </script>

View File

@ -1,16 +1,18 @@
<template> <template>
<div> <div></div>
</div>
</template> </template>
<style> <style>
</style> </style>
<script> <script>
import _ from 'lodash';
export default { export default {
inject: ['openmct'], inject: ['openmct'],
data() {
return {
selection: []
}
},
mounted() { mounted() {
this.openmct.selection.on('change', this.updateSelection); this.openmct.selection.on('change', this.updateSelection);
this.updateSelection(this.openmct.selection.get()); this.updateSelection(this.openmct.selection.get());
@ -18,11 +20,6 @@ import _ from 'lodash';
destroyed() { destroyed() {
this.openmct.selection.off('change', this.updateSelection); this.openmct.selection.off('change', this.updateSelection);
}, },
data() {
return {
selection: []
}
},
methods: { methods: {
updateSelection(selection) { updateSelection(selection) {
this.selection = selection; this.selection = selection;

View File

@ -1,21 +1,39 @@
<template> <template>
<div class="c-properties c-properties--location"> <div class="c-properties c-properties--location">
<div class="c-properties__header" title="The location of this linked object.">Original Location</div> <div
<ul class="c-properties__section" v-if="!multiSelect"> class="c-properties__header"
<li class="c-properties__row" v-if="originalPath.length"> title="The location of this linked object."
>
Original Location
</div>
<ul
v-if="!multiSelect"
class="c-properties__section"
>
<li
v-if="originalPath.length"
class="c-properties__row"
>
<ul class="c-properties__value c-location"> <ul class="c-properties__value c-location">
<li v-for="pathObject in orderedOriginalPath" <li
v-for="pathObject in orderedOriginalPath"
:key="pathObject.key"
class="c-location__item" class="c-location__item"
:key="pathObject.key"> >
<object-label <object-label
:domainObject="pathObject.domainObject" :domain-object="pathObject.domainObject"
:objectPath="pathObject.objectPath"> :object-path="pathObject.objectPath"
</object-label> />
</li> </li>
</ul> </ul>
</li> </li>
</ul> </ul>
<div class="c-properties__row--span-all" v-if="multiSelect">No location to display for multiple items</div> <div
v-if="multiSelect"
class="c-properties__row--span-all"
>
No location to display for multiple items
</div>
</div> </div>
</template> </template>
@ -78,6 +96,11 @@ export default {
keyString: '' keyString: ''
} }
}, },
computed: {
orderedOriginalPath() {
return this.originalPath.slice().reverse();
}
},
mounted() { mounted() {
this.openmct.selection.on('change', this.updateSelection); this.openmct.selection.on('change', this.updateSelection);
this.updateSelection(this.openmct.selection.get()); this.updateSelection(this.openmct.selection.get());
@ -139,11 +162,6 @@ export default {
.then(this.setOriginalPath); .then(this.setOriginalPath);
} }
} }
},
computed: {
orderedOriginalPath() {
return this.originalPath.reverse();
}
} }
} }
</script> </script>

View File

@ -1,32 +1,75 @@
<template> <template>
<div class="c-properties c-properties--properties"> <div class="c-properties c-properties--properties">
<div class="c-properties__header">Properties</div> <div class="c-properties__header">
<ul class="c-properties__section" v-if="!multiSelect && !singleSelectNonObject"> Properties
</div>
<ul
v-if="!multiSelect && !singleSelectNonObject"
class="c-properties__section"
>
<li class="c-properties__row"> <li class="c-properties__row">
<div class="c-properties__label">Title</div> <div class="c-properties__label">
<div class="c-properties__value">{{ item.name }}</div> Title
</div>
<div class="c-properties__value">
{{ item.name }}
</div>
</li> </li>
<li class="c-properties__row"> <li class="c-properties__row">
<div class="c-properties__label">Type</div> <div class="c-properties__label">
<div class="c-properties__value">{{ typeName }}</div> Type
</div>
<div class="c-properties__value">
{{ typeName }}
</div>
</li> </li>
<li class="c-properties__row" v-if="item.created"> <li
<div class="c-properties__label">Created</div> v-if="item.created"
<div class="c-properties__value c-ne__text">{{ formatTime(item.created) }}</div> class="c-properties__row"
>
<div class="c-properties__label">
Created
</div>
<div class="c-properties__value c-ne__text">
{{ formatTime(item.created) }}
</div>
</li> </li>
<li class="c-properties__row" v-if="item.modified"> <li
<div class="c-properties__label">Modified</div> v-if="item.modified"
<div class="c-properties__value c-ne__text">{{ formatTime(item.modified) }}</div> class="c-properties__row"
>
<div class="c-properties__label">
Modified
</div>
<div class="c-properties__value c-ne__text">
{{ formatTime(item.modified) }}
</div>
</li> </li>
<li class="c-properties__row" <li
v-for="prop in typeProperties" v-for="prop in typeProperties"
:key="prop.name"> :key="prop.name"
<div class="c-properties__label">{{ prop.name }}</div> class="c-properties__row"
<div class="c-properties__value">{{ prop.value }}</div> >
<div class="c-properties__label">
{{ prop.name }}
</div>
<div class="c-properties__value">
{{ prop.value }}
</div>
</li> </li>
</ul> </ul>
<div class="c-properties__row--span-all" v-if="multiSelect">No properties to display for multiple items</div> <div
<div class="c-properties__row--span-all" v-if="singleSelectNonObject">No properties to display for this item</div> v-if="multiSelect"
class="c-properties__row--span-all"
>
No properties to display for multiple items
</div>
<div
v-if="singleSelectNonObject"
class="c-properties__row--span-all"
>
No properties to display for this item
</div>
</div> </div>
</template> </template>
@ -77,8 +120,8 @@ export default {
.map((field) => { .map((field) => {
return { return {
name: field.name, name: field.name,
value: field.path.reduce((object, field) => { value: field.path.reduce((object, key) => {
return object[field]; return object[key];
}, this.item) }, this.item)
}; };
}); });

View File

@ -1,13 +1,25 @@
<template> <template>
<!-- eslint-disable vue/no-v-html -->
<div class="c-about c-about--splash"> <div class="c-about c-about--splash">
<div class="c-about__image c-splash-image"></div> <div class="c-about__image c-splash-image"></div>
<div class="c-about__text s-text"> <div class="c-about__text s-text">
<div class="c-about__text__element" v-if="branding.aboutHtml" v-html="branding.aboutHtml"></div> <div
v-if="branding.aboutHtml"
class="c-about__text__element"
v-html="branding.aboutHtml"
></div>
<div class="c-about__text__element"> <div class="c-about__text__element">
<h1 class="l-title s-title">Open MCT</h1> <h1 class="l-title s-title">
Open MCT
</h1>
<div class="l-description s-description"> <div class="l-description s-description">
<p>Open MCT, Copyright &copy; 2014-2019, United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All rights reserved.</p> <p>Open MCT, Copyright &copy; 2014-2019, United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All rights reserved.</p>
<p>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 <a target="_blank" href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>.</p> <p>
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 <a
target="_blank"
href="http://www.apache.org/licenses/LICENSE-2.0"
>http://www.apache.org/licenses/LICENSE-2.0</a>.
</p>
<p>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.</p> <p>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.</p>
<p>Open MCT includes source code licensed under additional open source licenses. See the Open Source Licenses file included with this distribution or <a @click="showLicenses">click here for third party licensing information</a>.</p> <p>Open MCT includes source code licensed under additional open source licenses. See the Open Source Licenses file included with this distribution or <a @click="showLicenses">click here for third party licensing information</a>.</p>
</div> </div>

View File

@ -20,7 +20,11 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="l-shell__app-logo" @click="launchAbout" ref="aboutLogo"></div> <div
ref="aboutLogo"
class="l-shell__app-logo"
@click="launchAbout"
></div>
</template> </template>
<style lang="scss"> <style lang="scss">
.l-shell__app-logo { .l-shell__app-logo {

View File

@ -1,58 +1,90 @@
<template> <template>
<div class="l-browse-bar"> <div class="l-browse-bar">
<div class="l-browse-bar__start"> <div class="l-browse-bar__start">
<button v-if="hasParent" <button
v-if="hasParent"
class="l-browse-bar__nav-to-parent-button c-icon-button c-icon-button--major icon-pointer-left" class="l-browse-bar__nav-to-parent-button c-icon-button c-icon-button--major icon-pointer-left"
@click="goToParent"></button> @click="goToParent"
<div class="l-browse-bar__object-name--w" ></button>
:class="type.cssClass"> <div
class="l-browse-bar__object-name--w"
:class="type.cssClass"
>
<span <span
class="l-browse-bar__object-name c-input-inline" class="l-browse-bar__object-name c-input-inline"
contenteditable
@blur="updateName" @blur="updateName"
@keydown.enter.prevent @keydown.enter.prevent
@keyup.enter.prevent="updateNameOnEnterKeyPress" @keyup.enter.prevent="updateNameOnEnterKeyPress"
contenteditable> >
{{ domainObject.name }} {{ domainObject.name }}
</span> </span>
</div> </div>
<div class="l-browse-bar__context-actions c-disclosure-button" @click.prevent.stop="showContextMenu"></div> <div
class="l-browse-bar__context-actions c-disclosure-button"
@click.prevent.stop="showContextMenu"
></div>
</div> </div>
<div class="l-browse-bar__end"> <div class="l-browse-bar__end">
<view-switcher <view-switcher
:currentView="currentView" :current-view="currentView"
:views="views" :views="views"
@setView="setView"> @setView="setView"
</view-switcher> />
<!-- Action buttons --> <!-- Action buttons -->
<div class="l-browse-bar__actions"> <div class="l-browse-bar__actions">
<button v-if="notebookEnabled" <button
v-if="notebookEnabled"
class="l-browse-bar__actions__notebook-entry c-button icon-notebook" class="l-browse-bar__actions__notebook-entry c-button icon-notebook"
title="New Notebook entry" title="New Notebook entry"
@click="snapshot()"> @click="snapshot()"
</button> ></button>
<button class="l-browse-bar__actions__edit c-button c-button--major icon-pencil" title="Edit" v-if="isViewEditable & !isEditing" @click="edit()"></button> <button
v-if="isViewEditable & !isEditing"
class="l-browse-bar__actions__edit c-button c-button--major icon-pencil"
title="Edit"
@click="edit()"
></button>
<div class="l-browse-bar__view-switcher c-ctrl-wrapper c-ctrl-wrapper--menus-left" <div
v-if="isEditing"> v-if="isEditing"
<button class="c-button--menu c-button--major icon-save" title="Save" @click.stop="toggleSaveMenu"></button> class="l-browse-bar__view-switcher c-ctrl-wrapper c-ctrl-wrapper--menus-left"
<div class="c-menu" v-show="showSaveMenu"> >
<button
class="c-button--menu c-button--major icon-save"
title="Save"
@click.stop="toggleSaveMenu"
></button>
<div
v-show="showSaveMenu"
class="c-menu"
>
<ul> <ul>
<li @click="saveAndFinishEditing" <li
class="icon-save" class="icon-save"
title="Save and Finish Editing"> title="Save and Finish Editing"
@click="saveAndFinishEditing"
>
Save and Finish Editing Save and Finish Editing
</li> </li>
<li @click="saveAndContinueEditing" <li
class="icon-save" class="icon-save"
title="Save and Continue Editing"> title="Save and Continue Editing"
@click="saveAndContinueEditing"
>
Save and Continue Editing Save and Continue Editing
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
<button class="l-browse-bar__actions c-button icon-x" title="Cancel Editing" v-if="isEditing" @click="promptUserandCancelEditing()"></button> <button
v-if="isEditing"
class="l-browse-bar__actions c-button icon-x"
title="Cancel Editing"
@click="promptUserandCancelEditing()"
></button>
</div> </div>
</div> </div>
</div> </div>
@ -68,6 +100,89 @@ const PLACEHOLDER_OBJECT = {};
components: { components: {
ViewSwitcher ViewSwitcher
}, },
data: function () {
return {
showViewMenu: false,
showSaveMenu: false,
domainObject: PLACEHOLDER_OBJECT,
viewKey: undefined,
isEditing: this.openmct.editor.isEditing(),
notebookEnabled: false
}
},
computed: {
currentView() {
return this.views.filter(v => v.key === this.viewKey)[0] || {};
},
views() {
return this
.openmct
.objectViews
.get(this.domainObject)
.map((p) => {
return {
key: p.key,
cssClass: p.cssClass,
name: p.name
};
});
},
hasParent() {
return this.domainObject !== PLACEHOLDER_OBJECT &&
this.parentUrl !== '#/browse'
},
parentUrl() {
let objectKeyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
let hash = window.location.hash;
return hash.slice(0, hash.lastIndexOf('/' + objectKeyString));
},
type() {
let objectType = this.openmct.types.get(this.domainObject.type);
if (!objectType) {
return {}
}
return objectType.definition;
},
isViewEditable() {
let currentViewKey = this.currentView.key;
if (currentViewKey !== undefined) {
let currentViewProvider = this.openmct.objectViews.getByProviderKey(currentViewKey);
return currentViewProvider.canEdit && currentViewProvider.canEdit(this.domainObject);
}
return false;
}
},
watch: {
domainObject() {
if (this.mutationObserver) {
this.mutationObserver();
}
this.mutationObserver = this.openmct.objects.observe(this.domainObject, '*', (domainObject) => {
this.domainObject = domainObject;
});
}
},
mounted: function () {
if (this.openmct.types.get('notebook')) {
this.notebookSnapshot = new NotebookSnapshot(this.openmct);
this.notebookEnabled = true;
}
document.addEventListener('click', this.closeViewAndSaveMenu);
window.addEventListener('beforeunload', this.promptUserbeforeNavigatingAway);
this.openmct.editor.on('isEditing', (isEditing) => {
this.isEditing = isEditing;
});
},
beforeDestroy: function () {
if (this.mutationObserver) {
this.mutationObserver();
}
document.removeEventListener('click', this.closeViewAndSaveMenu);
window.removeEventListener('click', this.promptUserbeforeNavigatingAway);
},
methods: { methods: {
toggleSaveMenu() { toggleSaveMenu() {
this.showSaveMenu = !this.showSaveMenu; this.showSaveMenu = !this.showSaveMenu;
@ -131,11 +246,10 @@ const PLACEHOLDER_OBJECT = {};
progressPerc: 'unknown', progressPerc: 'unknown',
message: 'Do not navigate away from this page or close this browser tab while this message is displayed.', message: 'Do not navigate away from this page or close this browser tab while this message is displayed.',
iconClass: 'info', iconClass: 'info',
title: 'Saving', title: 'Saving'
}); });
return this.openmct.editor.save() return this.openmct.editor.save().then(()=> {
.then(()=> {
dialog.dismiss(); dialog.dismiss();
this.openmct.notifications.info('Save successful'); this.openmct.notifications.info('Save successful');
}).catch((error) => { }).catch((error) => {
@ -159,89 +273,6 @@ const PLACEHOLDER_OBJECT = {};
goToParent() { goToParent() {
window.location.hash = this.parentUrl; window.location.hash = this.parentUrl;
} }
},
data: function () {
return {
showViewMenu: false,
showSaveMenu: false,
domainObject: PLACEHOLDER_OBJECT,
viewKey: undefined,
isEditing: this.openmct.editor.isEditing(),
notebookEnabled: false
}
},
computed: {
currentView() {
return this.views.filter(v => v.key === this.viewKey)[0] || {};
},
views() {
return this
.openmct
.objectViews
.get(this.domainObject)
.map((p) => {
return {
key: p.key,
cssClass: p.cssClass,
name: p.name
};
});
},
hasParent() {
return this.domainObject !== PLACEHOLDER_OBJECT &&
this.parentUrl !== '#/browse'
},
parentUrl() {
let objectKeyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
let hash = window.location.hash;
return hash.slice(0, hash.lastIndexOf('/' + objectKeyString));
},
type() {
let objectType = this.openmct.types.get(this.domainObject.type);
if (!objectType) {
return {}
}
return objectType.definition;
},
isViewEditable() {
let currentViewKey = this.currentView.key;
if (currentViewKey !== undefined) {
let currentViewProvider = this.openmct.objectViews.getByProviderKey(currentViewKey);
return currentViewProvider.canEdit && currentViewProvider.canEdit(this.domainObject);
}
return false;
}
},
mounted: function () {
if (this.openmct.types.get('notebook')) {
this.notebookSnapshot = new NotebookSnapshot(this.openmct);
this.notebookEnabled = true;
}
document.addEventListener('click', this.closeViewAndSaveMenu);
window.addEventListener('beforeunload', this.promptUserbeforeNavigatingAway);
this.openmct.editor.on('isEditing', (isEditing) => {
this.isEditing = isEditing;
});
},
watch: {
domainObject() {
if (this.mutationObserver) {
this.mutationObserver();
}
this.mutationObserver = this.openmct.objects.observe(this.domainObject, '*', (domainObject) => {
this.domainObject = domainObject;
});
}
},
beforeDestroy: function () {
if (this.mutationObserver) {
this.mutationObserver();
}
document.removeEventListener('click', this.closeViewAndSaveMenu);
window.removeEventListener('click', this.promptUserbeforeNavigatingAway);
} }
} }
</script> </script>

View File

@ -1,27 +1,37 @@
<template> <template>
<div class="c-create-button--w"> <div class="c-create-button--w">
<button class="c-create-button c-button--menu c-button--major icon-plus" <button
@click="open"> class="c-create-button c-button--menu c-button--major icon-plus"
@click="open"
>
<span class="c-button__label">Create</span> <span class="c-button__label">Create</span>
</button> </button>
<div class="c-create-menu c-super-menu" <div
v-if="opened"> v-if="opened"
class="c-create-menu c-super-menu"
>
<div class="c-super-menu__menu"> <div class="c-super-menu__menu">
<ul> <ul>
<li v-for="(item, index) in sortedItems" <li
v-for="(item, index) in sortedItems"
:key="index" :key="index"
:class="item.class" :class="item.class"
:title="item.title" :title="item.title"
@mouseover="showItemDescription(item)" @mouseover="showItemDescription(item)"
@click="create(item)"> @click="create(item)"
>
{{ item.name }} {{ item.name }}
</li> </li>
</ul> </ul>
</div> </div>
<div class="c-super-menu__item-description"> <div class="c-super-menu__item-description">
<div :class="['l-item-description__icon', 'bg-' + selectedMenuItem.class]"></div> <div :class="['l-item-description__icon', 'bg-' + selectedMenuItem.class]"></div>
<div class="l-item-description__name">{{selectedMenuItem.name}}</div> <div class="l-item-description__name">
<div class="l-item-description__description">{{selectedMenuItem.title}}</div> {{ selectedMenuItem.name }}
</div>
<div class="l-item-description__description">
{{ selectedMenuItem.title }}
</div>
</div> </div>
</div> </div>
</div> </div>
@ -65,13 +75,48 @@
import CreateAction from '../../../platform/commonUI/edit/src/creation/CreateAction'; import CreateAction from '../../../platform/commonUI/edit/src/creation/CreateAction';
import objectUtils from '../../api/objects/object-utils'; import objectUtils from '../../api/objects/object-utils';
function convertToLegacyObject(domainObject) {
let keyString = objectUtils.makeKeyString(domainObject.identifier);
let oldModel = objectUtils.toOldFormat(domainObject);
return instantiate(oldModel, keyString);
}
export default { export default {
inject: ['openmct'], inject: ['openmct'],
data: function () {
let items = [];
this.openmct.types.listKeys().forEach(key => {
let menuItem = this.openmct.types.get(key).definition;
if (menuItem.creatable) {
let menuItemTemplate = {
key: key,
name: menuItem.name,
class: menuItem.cssClass,
title: menuItem.description
};
items.push(menuItemTemplate);
}
});
return {
items: items,
selectedMenuItem: {},
opened: false
}
},
computed: {
sortedItems() {
return this.items.slice().sort((a,b) => {
if (a.name < b.name) {
return -1;
} else if (a.name > b.name) {
return 1;
} else {
return 0;
}
});
}
},
destroyed() {
document.removeEventListener('click', this.close);
},
methods: { methods: {
open: function () { open: function () {
if (this.opened) { if (this.opened) {
@ -118,46 +163,6 @@
let oldModel = objectUtils.toOldFormat(domainObject); let oldModel = objectUtils.toOldFormat(domainObject);
return this.openmct.$injector.get('instantiate')(oldModel, keyString); return this.openmct.$injector.get('instantiate')(oldModel, keyString);
} }
},
destroyed () {
document.removeEventListener('click', this.close);
},
data: function() {
let items = [];
this.openmct.types.listKeys().forEach(key => {
let menuItem = this.openmct.types.get(key).definition;
if (menuItem.creatable) {
let menuItemTemplate = {
key: key,
name: menuItem.name,
class: menuItem.cssClass,
title: menuItem.description
};
items.push(menuItemTemplate);
}
});
return {
items: items,
selectedMenuItem: {},
opened: false
}
},
computed: {
sortedItems () {
return this.items.sort((a,b) => {
if (a.name < b.name) {
return -1;
} else if (a.name > b.name) {
return 1;
} else {
return 0;
}
});
}
} }
} }
</script> </script>

View File

@ -1,57 +1,81 @@
<template> <template>
<div class="l-shell" :class="{ <div
class="l-shell"
:class="{
'is-editing': isEditing 'is-editing': isEditing
}"> }"
<div class="l-shell__head" :class="{ >
<div
class="l-shell__head"
:class="{
'l-shell__head--expanded': headExpanded, 'l-shell__head--expanded': headExpanded,
'l-shell__head--minify-indicators': !headExpanded 'l-shell__head--minify-indicators': !headExpanded
}"> }"
<CreateButton class="l-shell__create-button"></CreateButton> >
<indicators class="l-shell__head-section l-shell__indicators"> <CreateButton class="l-shell__create-button" />
</indicators> <indicators class="l-shell__head-section l-shell__indicators" />
<button class="l-shell__head__collapse-button c-button" <button
@click="toggleShellHead"></button> class="l-shell__head__collapse-button c-button"
<notification-banner></notification-banner> @click="toggleShellHead"
></button>
<notification-banner />
<div class="l-shell__head-section l-shell__controls"> <div class="l-shell__head-section l-shell__controls">
<button class="c-icon-button c-icon-button--major icon-new-window" title="Open in a new browser tab" <button
class="c-icon-button c-icon-button--major icon-new-window"
title="Open in a new browser tab"
target="_blank"
@click="openInNewTab" @click="openInNewTab"
target="_blank"> ></button>
</button> <button
<button v-bind:class="['c-icon-button c-icon-button--major', fullScreen ? 'icon-fullscreen-collapse' : 'icon-fullscreen-expand']" :class="['c-icon-button c-icon-button--major', fullScreen ? 'icon-fullscreen-collapse' : 'icon-fullscreen-expand']"
v-bind:title="`${fullScreen ? 'Exit' : 'Enable'} full screen mode`" :title="`${fullScreen ? 'Exit' : 'Enable'} full screen mode`"
@click="fullScreenToggle"> @click="fullScreenToggle"
</button> ></button>
</div> </div>
<app-logo></app-logo> <app-logo />
</div> </div>
<multipane class="l-shell__main" <multipane
type="horizontal"> class="l-shell__main"
<pane class="l-shell__pane-tree" type="horizontal"
>
<pane
class="l-shell__pane-tree"
handle="after" handle="after"
label="Browse" label="Browse"
collapsable> collapsable
<mct-tree class="l-shell__tree"></mct-tree> >
<mct-tree class="l-shell__tree" />
</pane> </pane>
<pane class="l-shell__pane-main"> <pane class="l-shell__pane-main">
<browse-bar class="l-shell__main-view-browse-bar" <browse-bar
ref="browseBar"> ref="browseBar"
</browse-bar> class="l-shell__main-view-browse-bar"
<toolbar v-if="toolbar" class="l-shell__toolbar"></toolbar> />
<object-view class="l-shell__main-container" <toolbar
v-if="toolbar"
class="l-shell__toolbar"
/>
<object-view
ref="browseObject" ref="browseObject"
:showEditView="true" class="l-shell__main-container"
:show-edit-view="true"
data-selectable data-selectable
> />
</object-view> <component
<component class="l-shell__time-conductor" :is="conductorComponent"
:is="conductorComponent"> class="l-shell__time-conductor"
</component> />
</pane> </pane>
<pane class="l-shell__pane-inspector l-pane--holds-multipane" <pane
class="l-shell__pane-inspector l-pane--holds-multipane"
handle="before" handle="before"
label="Inspect" label="Inspect"
collapsable> collapsable
<Inspector :isEditing="isEditing" ref="inspector"></Inspector> >
<Inspector
ref="inspector"
:is-editing="isEditing"
/>
</pane> </pane>
</multipane> </multipane>
</div> </div>
@ -359,13 +383,6 @@
Indicators, Indicators,
NotificationBanner NotificationBanner
}, },
mounted() {
this.openmct.editor.on('isEditing', (isEditing)=>{
this.isEditing = isEditing;
});
this.openmct.selection.on('change', this.toggleHasToolbar);
},
data: function () { data: function () {
let storedHeadProps = window.localStorage.getItem('openmct-shell-head'); let storedHeadProps = window.localStorage.getItem('openmct-shell-head');
let headExpanded = true; let headExpanded = true;
@ -386,6 +403,13 @@
return this.hasToolbar && this.isEditing; return this.hasToolbar && this.isEditing;
} }
}, },
mounted() {
this.openmct.editor.on('isEditing', (isEditing)=>{
this.isEditing = isEditing;
});
this.openmct.selection.on('change', this.toggleHasToolbar);
},
methods: { methods: {
toggleShellHead() { toggleShellHead() {
this.headExpanded = !this.headExpanded; this.headExpanded = !this.headExpanded;

View File

@ -1,6 +1,9 @@
<template> <template>
<div class="c-search c-search--major"> <div class="c-search c-search--major">
<input type="search" placeholder="Search"/> <input
type="search"
placeholder="Search"
>
</div> </div>
</template> </template>

View File

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

View File

@ -1,41 +1,53 @@
<template> <template>
<div class="c-tree-and-search"> <div class="c-tree-and-search">
<div class="c-tree-and-search__search"> <div class="c-tree-and-search__search">
<search class="c-search" ref="shell-search" <search
ref="shell-search"
class="c-search"
:value="searchValue" :value="searchValue"
@input="searchTree" @input="searchTree"
@clear="searchTree"> @clear="searchTree"
</search> />
</div> </div>
<!-- loading --> <!-- loading -->
<div class="c-tree-and-search__loading loading" <div
v-if="isLoading"></div> v-if="isLoading"
class="c-tree-and-search__loading loading"
></div>
<!-- end loading --> <!-- end loading -->
<div class="c-tree-and-search__no-results" <div
v-if="(allTreeItems.length === 0) || (searchValue && filteredTreeItems.length === 0)"> v-if="(allTreeItems.length === 0) || (searchValue && filteredTreeItems.length === 0)"
class="c-tree-and-search__no-results"
>
No results found No results found
</div> </div>
<!-- main tree --> <!-- main tree -->
<ul class="c-tree-and-search__tree c-tree" <ul
v-if="!isLoading" v-if="!isLoading"
v-show="!searchValue"> v-show="!searchValue"
<tree-item v-for="treeItem in allTreeItems" class="c-tree-and-search__tree c-tree"
>
<tree-item
v-for="treeItem in allTreeItems"
:key="treeItem.id" :key="treeItem.id"
:node="treeItem"> :node="treeItem"
</tree-item> />
</ul> </ul>
<!-- end main tree --> <!-- end main tree -->
<!-- search tree --> <!-- search tree -->
<ul class="c-tree-and-search__tree c-tree" <ul
v-if="searchValue"> v-if="searchValue"
<tree-item v-for="treeItem in filteredTreeItems" class="c-tree-and-search__tree c-tree"
>
<tree-item
v-for="treeItem in filteredTreeItems"
:key="treeItem.id" :key="treeItem.id"
:node="treeItem"> :node="treeItem"
</tree-item> />
</ul> </ul>
<!-- end search tree --> <!-- end search tree -->
</div> </div>
@ -190,7 +202,7 @@
export default { export default {
inject: ['openmct'], inject: ['openmct'],
name: 'mct-tree', name: 'MctTree',
components: { components: {
search, search,
treeItem treeItem
@ -203,6 +215,10 @@
isLoading: false isLoading: false
} }
}, },
mounted() {
this.searchService = this.openmct.$injector.get('searchService');
this.getAllChildren();
},
methods: { methods: {
getAllChildren() { getAllChildren() {
this.isLoading = true; this.isLoading = true;
@ -256,10 +272,6 @@
this.getFilteredChildren(); this.getFilteredChildren();
} }
} }
},
mounted() {
this.searchService = this.openmct.$injector.get('searchService');
this.getAllChildren();
} }
} }
</script> </script>

View File

@ -1,9 +1,11 @@
<template> <template>
<div class="l-multipane" <div
class="l-multipane"
:class="{ :class="{
'l-multipane--vertical': type === 'vertical', 'l-multipane--vertical': type === 'vertical',
'l-multipane--horizontal': type === 'horizontal' 'l-multipane--horizontal': type === 'horizontal'
}"> }"
>
<slot></slot> <slot></slot>
</div> </div>
</template> </template>
@ -13,6 +15,7 @@ export default {
props: { props: {
type: { type: {
type: String, type: String,
required: true,
validator: function (value) { validator: function (value) {
return ['vertical', 'horizontal'].indexOf(value) !== -1; return ['vertical', 'horizontal'].indexOf(value) !== -1;
} }

View File

@ -1,5 +1,6 @@
<template> <template>
<div class="l-pane" <div
class="l-pane"
:class="{ :class="{
'l-pane--horizontal-handle-before': type === 'horizontal' && handle === 'before', 'l-pane--horizontal-handle-before': type === 'horizontal' && handle === 'before',
'l-pane--horizontal-handle-after': type === 'horizontal' && handle === 'after', 'l-pane--horizontal-handle-after': type === 'horizontal' && handle === 'after',
@ -8,17 +9,23 @@
'l-pane--collapsed': collapsed, 'l-pane--collapsed': collapsed,
'l-pane--reacts': !handle, 'l-pane--reacts': !handle,
'l-pane--resizing': resizing === true 'l-pane--resizing': resizing === true
}"> }"
<div v-if="handle" >
<div
v-if="handle"
class="l-pane__handle" class="l-pane__handle"
@mousedown="start"> @mousedown="start"
</div> ></div>
<div class="l-pane__header" <div
v-if="label"> v-if="label"
class="l-pane__header"
>
<span class="l-pane__label">{{ label }}</span> <span class="l-pane__label">{{ label }}</span>
<button class="l-pane__collapse-button c-button" <button
v-if="collapsable" v-if="collapsable"
@click="toggleCollapse"></button> class="l-pane__collapse-button c-button"
@click="toggleCollapse"
></button>
</div> </div>
<div class="l-pane__contents"> <div class="l-pane__contents">
<slot></slot> <slot></slot>
@ -350,15 +357,19 @@ export default {
props: { props: {
handle: { handle: {
type: String, type: String,
default: '',
validator: function (value) { validator: function (value) {
return ['before', 'after'].indexOf(value) !== -1; return ['', 'before', 'after'].indexOf(value) !== -1;
} }
}, },
collapsable: { collapsable: {
type: Boolean, type: Boolean,
default: false default: false
}, },
label: String label: {
type: String,
default: ''
}
}, },
data() { data() {
return { return {

View File

@ -17,6 +17,7 @@
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<template> <template>
<div></div>
</template> </template>
<style lang="scss"> <style lang="scss">

View File

@ -17,7 +17,9 @@
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<template> <template>
<div class="c-message-banner" <div
v-if="activeModel.message"
class="c-message-banner"
:class="[ :class="[
activeModel.severity, activeModel.severity,
{ {
@ -25,14 +27,17 @@
'new': !activeModel.minimized 'new': !activeModel.minimized
}]" }]"
@click="maximize()" @click="maximize()"
v-if="activeModel.message"> >
<span class="c-message-banner__message">{{ activeModel.message }}</span> <span class="c-message-banner__message">{{ activeModel.message }}</span>
<progress-bar <progress-bar
v-if="activeModel.progressPerc !== undefined"
class="c-message-banner__progress-bar" class="c-message-banner__progress-bar"
v-if="activeModel.progressPerc !== undefined" :model="activeModel"> :model="activeModel"
</progress-bar> />
<button class="c-message-banner__close-button c-click-icon icon-x-in-circle" <button
@click.stop="dismiss()"></button> class="c-message-banner__close-button c-click-icon icon-x-in-circle"
@click.stop="dismiss()"
></button>
</div> </div>
</template> </template>
@ -118,7 +123,6 @@
<script> <script>
import ProgressBar from '../../components/ProgressBar.vue'; import ProgressBar from '../../components/ProgressBar.vue';
let activeNotification = undefined; let activeNotification = undefined;
let dialogService = undefined;
let maximizedDialog = undefined; let maximizedDialog = undefined;
let minimizeButton = { let minimizeButton = {
label: 'Dismiss', label: 'Dismiss',
@ -157,6 +161,16 @@
} }
} }
}, },
computed: {
progressWidth() {
return {
width: this.activeModel.progress + '%'
};
}
},
mounted() {
this.openmct.notifications.on('notification', this.showNotification);
},
methods: { methods: {
showNotification(notification) { showNotification(notification) {
if (activeNotification) { if (activeNotification) {
@ -226,16 +240,6 @@
}) })
} }
} }
},
computed: {
progressWidth() {
return {
width: this.activeModel.progress + '%'
};
}
},
mounted() {
this.openmct.notifications.on('notification', this.showNotification);
} }
} }

View File

@ -1,27 +1,37 @@
<template> <template>
<li class="c-tree__item-h"> <li class="c-tree__item-h">
<div class="c-tree__item" <div
:class="{ 'is-alias': isAlias, 'is-navigated-object': isNavigated }"> class="c-tree__item"
<view-control class="c-tree__item__view-control" :class="{ 'is-alias': isAlias, 'is-navigated-object': isNavigated }"
>
<view-control
v-model="expanded"
class="c-tree__item__view-control"
:enabled="hasChildren" :enabled="hasChildren"
v-model="expanded"> />
</view-control> <object-label
<object-label :domainObject="node.object" :domain-object="node.object"
:objectPath="node.objectPath" :object-path="node.objectPath"
:navigateToPath="navigateToPath"> :navigate-to-path="navigateToPath"
</object-label> />
</div> </div>
<ul v-if="expanded" class="c-tree"> <ul
<li class="c-tree__item-h" v-if="expanded"
v-if="isLoading && !loaded"> class="c-tree"
>
<li
v-if="isLoading && !loaded"
class="c-tree__item-h"
>
<div class="c-tree__item loading"> <div class="c-tree__item loading">
<span class="c-tree__item__label">Loading...</span> <span class="c-tree__item__label">Loading...</span>
</div> </div>
</li> </li>
<tree-item v-for="child in children" <tree-item
v-for="child in children"
:key="child.id" :key="child.id"
:node="child"> :node="child"
</tree-item> />
</ul> </ul>
</li> </li>
</template> </template>
@ -31,10 +41,17 @@
import ObjectLabel from '../components/ObjectLabel.vue'; import ObjectLabel from '../components/ObjectLabel.vue';
export default { export default {
name: 'tree-item', name: 'TreeItem',
inject: ['openmct'], inject: ['openmct'],
components: {
viewControl,
ObjectLabel
},
props: { props: {
node: Object node: {
type: Object,
required: true
}
}, },
data() { data() {
this.navigateToPath = this.buildPathString(this.node.navigateToParent) this.navigateToPath = this.buildPathString(this.node.navigateToParent)
@ -57,6 +74,20 @@
return parentKeyString !== this.node.object.location; return parentKeyString !== this.node.object.location;
} }
}, },
watch: {
expanded(isExpanded) {
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() { mounted() {
// TODO: should update on mutation. // TODO: should update on mutation.
// TODO: click navigation should not fubar hash quite so much. // TODO: click navigation should not fubar hash quite so much.
@ -85,20 +116,6 @@
delete this.composition; delete this.composition;
} }
}, },
watch: {
expanded(isExpanded) {
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;
}
}
},
methods: { methods: {
addChild(child) { addChild(child) {
this.children.push({ this.children.push({
@ -127,10 +144,6 @@
this.isNavigated = false; this.isNavigated = false;
} }
} }
},
components: {
viewControl,
ObjectLabel
} }
} }
</script> </script>

View File

@ -6,7 +6,10 @@
export default { export default {
inject: ['openmct'], inject: ['openmct'],
props: { props: {
templateKey: String templateKey: {
type: String,
default: undefined
}
}, },
mounted() { mounted() {
let openmct = this.openmct; let openmct = this.openmct;

View File

@ -23,26 +23,29 @@
<div class="l-preview-window"> <div class="l-preview-window">
<div class="l-browse-bar"> <div class="l-browse-bar">
<div class="l-browse-bar__start"> <div class="l-browse-bar__start">
<div class="l-browse-bar__object-name--w" <div
:class="type.cssClass"> class="l-browse-bar__object-name--w"
:class="type.cssClass"
>
<span class="l-browse-bar__object-name"> <span class="l-browse-bar__object-name">
{{ domainObject.name }} {{ domainObject.name }}
</span> </span>
<context-menu-drop-down :object-path="objectPath"></context-menu-drop-down> <context-menu-drop-down :object-path="objectPath" />
</div> </div>
</div> </div>
<div class="l-browse-bar__end"> <div class="l-browse-bar__end">
<div class="l-browse-bar__actions"> <div class="l-browse-bar__actions">
<view-switcher <view-switcher
:views="views" :views="views"
:currentView="currentView" :current-view="currentView"
@setView="setView"> @setView="setView"
</view-switcher> />
<button v-if="notebookEnabled" <button
v-if="notebookEnabled"
class="l-browse-bar__actions__edit c-button icon-notebook" class="l-browse-bar__actions__edit c-button icon-notebook"
title="New Notebook entry" title="New Notebook entry"
@click="snapshot"> @click="snapshot"
</button> ></button>
</div> </div>
</div> </div>
</div> </div>
@ -97,6 +100,17 @@
'openmct', 'openmct',
'objectPath' 'objectPath'
], ],
data() {
let domainObject = this.objectPath[0];
let type = this.openmct.types.get(domainObject.type);
return {
domainObject: domainObject,
type: type,
notebookEnabled: false,
viewKey: undefined
};
},
computed: { computed: {
views() { views() {
return this return this
@ -108,6 +122,18 @@
return this.views.filter(v => v.key === this.viewKey)[0] || {}; return this.views.filter(v => v.key === this.viewKey)[0] || {};
} }
}, },
mounted() {
let view = this.openmct.objectViews.get(this.domainObject)[0];
this.setView(view);
if (this.openmct.types.get('notebook')) {
this.notebookSnapshot = new NotebookSnapshot(this.openmct);
this.notebookEnabled = true;
}
},
destroyed() {
this.view.destroy();
},
methods: { methods: {
snapshot() { snapshot() {
let element = document.getElementsByClassName("l-preview-window__object-view")[0]; let element = document.getElementsByClassName("l-preview-window__object-view")[0];
@ -132,29 +158,6 @@
this.view = this.currentView.view(this.domainObject, this.objectPath); this.view = this.currentView.view(this.domainObject, this.objectPath);
this.view.show(this.viewContainer, false); this.view.show(this.viewContainer, false);
} }
},
data() {
let domainObject = this.objectPath[0];
let type = this.openmct.types.get(domainObject.type);
return {
domainObject: domainObject,
type: type,
notebookEnabled: false,
viewKey: undefined
};
},
mounted() {
let view = this.openmct.objectViews.get(this.domainObject)[0];
this.setView(view);
if (this.openmct.types.get('notebook')) {
this.notebookSnapshot = new NotebookSnapshot(this.openmct);
this.notebookEnabled = true;
}
},
destroyed() {
this.view.destroy();
} }
} }
</script> </script>

View File

@ -1,10 +1,13 @@
<template> <template>
<div class="c-toolbar"> <div class="c-toolbar">
<component v-for="item in structure" <component
:is="item.control" :is="item.control"
v-for="(item, index) in structure"
:key="index"
:options="item" :options="item"
@click="triggerMethod(item, $event)" @click="triggerMethod(item, $event)"
@change="updateObjectValue"></component> @change="updateObjectValue"
/>
</div> </div>
</template> </template>
@ -37,6 +40,14 @@
structure: [] structure: []
}; };
}, },
mounted() {
this.openmct.selection.on('change', this.handleSelection);
this.handleSelection(this.openmct.selection.get());
// Toolbars may change when edit mode is enabled/disabled, so listen
// for edit mode changes and update toolbars if necessary.
this.openmct.editor.on('isEditing', this.handleEditing);
},
methods: { methods: {
handleSelection(selection) { handleSelection(selection) {
this.removeListeners(); this.removeListeners();
@ -133,7 +144,7 @@
} }
// If all values are the same, use it, otherwise mark the item as non-specific. // If all values are the same, use it, otherwise mark the item as non-specific.
if (values.every(value => value === values[0])) { if (values.every(val => val === values[0])) {
value = values[0]; value = values[0];
toolbarItem.nonSpecific = false; toolbarItem.nonSpecific = false;
} else { } else {
@ -169,7 +180,7 @@
}); });
for (const key in values) { for (const key in values) {
if (values[key].every(value => value === values[key][0])) { if (values[key].every(val => val === values[key][0])) {
value[key] = values[key][0]; value[key] = values[key][0];
toolbarItem.nonSpecific = false; toolbarItem.nonSpecific = false;
} else { } else {
@ -250,14 +261,6 @@
this.handleSelection(this.openmct.selection.get()); this.handleSelection(this.openmct.selection.get());
} }
}, },
mounted() {
this.openmct.selection.on('change', this.handleSelection);
this.handleSelection(this.openmct.selection.get());
// Toolbars may change when edit mode is enabled/disabled, so listen
// for edit mode changes and update toolbars if necessary.
this.openmct.editor.on('isEditing', this.handleEditing);
},
detroyed() { detroyed() {
this.openmct.selection.off('change', this.handleSelection); this.openmct.selection.off('change', this.handleSelection);
this.openmct.editor.off('isEditing', this.handleEditing); this.openmct.editor.off('isEditing', this.handleEditing);

View File

@ -1,15 +1,19 @@
<template> <template>
<div class="c-ctrl-wrapper"> <div class="c-ctrl-wrapper">
<div class="c-icon-button" <div
class="c-icon-button"
:title="options.title" :title="options.title"
:class="{ :class="{
[options.icon]: true, [options.icon]: true,
'c-icon-button--caution': options.modifier === 'caution', 'c-icon-button--caution': options.modifier === 'caution',
'c-icon-button--mixed': nonSpecific 'c-icon-button--mixed': nonSpecific
}" }"
@click="onClick"> @click="onClick"
<div class="c-icon-button__label" >
v-if="options.label"> <div
v-if="options.label"
class="c-icon-button__label"
>
{{ options.label }} {{ options.label }}
</div> </div>
</div> </div>
@ -20,7 +24,10 @@
export default { export default {
inject: ['openmct'], inject: ['openmct'],
props: { props: {
options: Object options: {
type: Object,
required: true
}
}, },
computed: { computed: {
nonSpecific() { nonSpecific() {

View File

@ -1,11 +1,13 @@
<template> <template>
<div class="c-custom-checkbox"> <div class="c-custom-checkbox">
<input type="checkbox" <input
:id="uid" :id="uid"
type="checkbox"
:name="options.name" :name="options.name"
:checked="options.value" :checked="options.value"
:disabled="options.disabled" :disabled="options.disabled"
@change="onChange"> @change="onChange"
>
<label :for="uid"> <label :for="uid">
<div class="c-custom-checkbox__box"></div> <div class="c-custom-checkbox__box"></div>
@ -72,7 +74,10 @@ let uniqueId = 100;
export default { export default {
props: { props: {
options: Object options: {
type: Object,
required: true
}
}, },
data() { data() {
uniqueId++; uniqueId++;

View File

@ -1,24 +1,35 @@
<template> <template>
<div class="c-ctrl-wrapper"> <div class="c-ctrl-wrapper">
<div class="c-icon-button c-icon-button--swatched" <div
class="c-icon-button c-icon-button--swatched"
:class="[options.icon, {'c-icon-button--mixed': nonSpecific}]" :class="[options.icon, {'c-icon-button--mixed': nonSpecific}]"
:title="options.title" :title="options.title"
@click="toggle"> @click="toggle"
<div class="c-swatch" :style="{ >
<div
class="c-swatch"
:style="{
background: options.value background: options.value
}"></div> }"
></div>
</div> </div>
<div class="c-menu c-palette c-palette--color" <div
v-if="open"> v-if="open"
<div class="c-palette__item-none" class="c-menu c-palette c-palette--color"
v-if="!this.options.preventNone" >
@click="select({value: 'transparent'})"> <div
v-if="!options.preventNone"
class="c-palette__item-none"
@click="select({value: 'transparent'})"
>
<div class="c-palette__item"></div> <div class="c-palette__item"></div>
None None
</div> </div>
<div class="c-palette__items"> <div class="c-palette__items">
<div class="c-palette__item" <div
v-for="color in colorPalette" v-for="(color, index) in colorPalette"
:key="index"
class="c-palette__item"
:style="{ background: color.value }" :style="{ background: color.value }"
@click="select(color)" @click="select(color)"
></div> ></div>
@ -34,18 +45,9 @@ import toggleMixin from '../../mixins/toggle-mixin';
export default { export default {
mixins: [toggleMixin], mixins: [toggleMixin],
props: { props: {
options: Object options: {
}, type: Object,
computed: { required: true
nonSpecific() {
return this.options.nonSpecific === true;
}
},
methods: {
select(color) {
if (color.value !== this.options.value) {
this.$emit('change', color.value, this.options);
}
} }
}, },
data() { data() {
@ -133,6 +135,18 @@ export default {
{ value: '#4c1130' } { value: '#4c1130' }
] ]
}; };
},
computed: {
nonSpecific() {
return this.options.nonSpecific === true;
}
},
methods: {
select(color) {
if (color.value !== this.options.value) {
this.$emit('change', color.value, this.options);
}
}
} }
} }
</script> </script>

View File

@ -1,13 +1,17 @@
<template> <template>
<div class="c-labeled-input" <div
:title="options.title"> class="c-labeled-input"
:title="options.title"
>
<label :for="uid"> <label :for="uid">
<div class="c-labeled-input__label">{{ options.label }}</div> <div class="c-labeled-input__label">{{ options.label }}</div>
</label> </label>
<input :id="uid" <input
:id="uid"
:type="options.type" :type="options.type"
:value="options.value" :value="options.value"
v-bind="options.attrs"/> v-bind="options.attrs"
>
</div> </div>
</template> </template>
@ -19,6 +23,7 @@ export default {
props: { props: {
options: { options: {
type: Object, type: Object,
required: true,
validator(value) { validator(value) {
return ['number', 'text'].indexOf(value.type) !== -1; return ['number', 'text'].indexOf(value.type) !== -1;
} }

View File

@ -1,19 +1,29 @@
<template> <template>
<div class="c-ctrl-wrapper"> <div class="c-ctrl-wrapper">
<div class="c-icon-button c-icon-button--menu" <div
class="c-icon-button c-icon-button--menu"
:class="options.icon" :class="options.icon"
:title="options.title" :title="options.title"
@click="toggle"> @click="toggle"
<div class="c-icon-button__label" >
v-if="options.label"> <div
v-if="options.label"
class="c-icon-button__label"
>
{{ options.label }} {{ options.label }}
</div> </div>
</div> </div>
<div class="c-menu" v-if="open"> <div
v-if="open"
class="c-menu"
>
<ul> <ul>
<li v-for="option in options.options" <li
v-for="(option, index) in options.options"
:key="index"
:class="option.class"
@click="onClick(option)" @click="onClick(option)"
:class="option.class"> >
{{ option.name }} {{ option.name }}
</li> </li>
</ul> </ul>
@ -28,6 +38,7 @@ export default {
props: { props: {
options: { options: {
type: Object, type: Object,
required: true,
validator(value) { validator(value) {
// must pass valid options array. // must pass valid options array.
return Array.isArray(value.options) && return Array.isArray(value.options) &&

View File

@ -1,16 +1,25 @@
<template> <template>
<div class="c-ctrl-wrapper"> <div class="c-ctrl-wrapper">
<div class="c-icon-button c-icon-button--menu" <div
class="c-icon-button c-icon-button--menu"
:class="[options.icon, {'c-click-icon--mixed': nonSpecific}]" :class="[options.icon, {'c-click-icon--mixed': nonSpecific}]"
:title="options.title" :title="options.title"
@click="toggle"> @click="toggle"
<div class="c-button__label">{{ selectedName }}</div> >
<div class="c-button__label">
{{ selectedName }}
</div> </div>
<div class="c-menu" v-if="open"> </div>
<div
v-if="open"
class="c-menu"
>
<ul> <ul>
<li v-for="option in options.options" <li
v-for="option in options.options"
:key="option.value" :key="option.value"
@click="select(option)"> @click="select(option)"
>
{{ option.name || option.value }} {{ option.name || option.value }}
</li> </li>
</ul> </ul>
@ -26,6 +35,7 @@ export default {
props: { props: {
options: { options: {
type: Object, type: Object,
required: true,
validator(value) { validator(value) {
// must pass valid options array. // must pass valid options array.
return Array.isArray(value.options) && return Array.isArray(value.options) &&
@ -33,14 +43,6 @@ export default {
} }
} }
}, },
methods: {
select(option) {
if (this.options.value === option.value) {
return;
}
this.$emit('change', option.value, this.options);
}
},
computed: { computed: {
selectedName() { selectedName() {
let selectedOption = this.options.options.filter((o) => o.value === this.options.value)[0]; let selectedOption = this.options.options.filter((o) => o.value === this.options.value)[0];
@ -53,6 +55,14 @@ export default {
nonSpecific() { nonSpecific() {
return this.options.nonSpecific === true; return this.options.nonSpecific === true;
} }
},
methods: {
select(option) {
if (this.options.value === option.value) {
return;
}
this.$emit('change', option.value, this.options);
}
} }
} }
</script> </script>

View File

@ -5,7 +5,10 @@
<script> <script>
export default { export default {
props: { props: {
options: Object options: {
type: Object,
required: true
}
} }
} }
</script> </script>

View File

@ -1,10 +1,11 @@
<template> <template>
<div class="c-ctrl-wrapper"> <div class="c-ctrl-wrapper">
<div class="c-icon-button" <div
class="c-icon-button"
:title="nextValue.title" :title="nextValue.title"
:class="[nextValue.icon, {'c-icon-button--mixed': nonSpecific}]" :class="[nextValue.icon, {'c-icon-button--mixed': nonSpecific}]"
@click="cycle"> @click="cycle"
</div> ></div>
</div> </div>
</template> </template>
@ -12,7 +13,8 @@
export default { export default {
props: { props: {
options: { options: {
type: Object type: Object,
required: true
} }
}, },
computed: { computed: {