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,
"amd": true
},
"extends": "eslint:recommended",
"parser": "babel-eslint",
"globals": {
"_": "readonly"
},
"extends": [
"eslint:recommended",
"plugin:vue/recommended"
],
"parser": "vue-eslint-parser",
"parserOptions": {
"parser": "babel-eslint",
"allowImportExportEverywhere": true,
"ecmaVersion": 2015,
"ecmaFeatures": {
@ -58,7 +65,38 @@ module.exports = {
}
],
"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": [
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -44,7 +44,12 @@ const CONTEXT_MENU_ACTIONS = [
export default {
inject: ['openmct', 'objectPath'],
props: ['domainObject'],
props: {
domainObject: {
type: Object,
required: true
}
},
data() {
let currentObjectPath = this.objectPath.slice();
currentObjectPath.unshift(this.domainObject);
@ -57,6 +62,47 @@ export default {
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: {
updateValues(datum) {
this.timestamp = this.formats[this.timestampKey].format(datum);
@ -88,47 +134,6 @@ export default {
showContextMenu(event) {
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>

View File

@ -33,14 +33,13 @@
<lad-row
v-for="item in items"
:key="item.key"
:domainObject="item.domainObject">
</lad-row>
:domain-object="item.domainObject"
/>
</tbody>
</table>
</template>
<script>
import lodash from 'lodash';
import LadRow from './LADRow.vue';
export default {
@ -53,6 +52,18 @@ export default {
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: {
addItem(domainObject) {
let item = {};
@ -72,18 +83,6 @@ export default {
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>

View File

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

View File

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

View File

@ -21,19 +21,28 @@
*****************************************************************************/
<template>
<div class="c-properties" v-if="isEditing">
<div class="c-properties__header">Alphanumeric Format</div>
<div
v-if="isEditing"
class="c-properties"
>
<div class="c-properties__header">
Alphanumeric Format
</div>
<ul class="c-properties__section">
<li class="c-properties__row">
<div class="c-properties__label" title="Printf formatting for the selected telemetry">
<div
class="c-properties__label"
title="Printf formatting for the selected telemetry"
>
<label for="telemetryPrintfFormat">Format</label>
</div>
<div class="c-properties__value">
<input id="telemetryPrintfFormat"
<input
id="telemetryPrintfFormat"
type="text"
@change="formatTelemetry"
:value="telemetryFormat"
:placeholder="nonMixedFormat ? '' : 'Mixed'"
@change="formatTelemetry"
>
</div>
</li>
@ -45,13 +54,21 @@
export default {
inject: ['openmct'],
data() {
let selectionPath = this.openmct.selection.get()[0];
return {
isEditing: this.openmct.editor.isEditing(),
telemetryFormat: undefined,
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: {
toggleEdit(isEditing) {
this.isEditing = isEditing;
@ -75,15 +92,6 @@
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>
<layout-frame :item="item"
<layout-frame
:item="item"
:grid-size="gridSize"
@move="(gridDelta) => $emit('move', gridDelta)"
@endMove="() => $emit('endMove')">
<div class="c-box-view"
:style="style">
</div>
@endMove="() => $emit('endMove')"
>
<div
class="c-box-view"
:style="style"
></div>
</layout-frame>
</template>
@ -63,9 +66,20 @@
LayoutFrame
},
props: {
item: Object,
gridSize: Array,
index: Number,
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: {
@ -100,4 +114,3 @@
}
}
</script>

View File

@ -21,41 +21,48 @@
*****************************************************************************/
<template>
<div class="l-layout"
<div
class="l-layout"
:class="{
'is-multi-selected': selectedLayoutItems.length > 1
}"
@dragover="handleDragOver"
@click.capture="bypassSelection"
@drop="handleDrop"
:class="{
'is-multi-selected': selectedLayoutItems.length > 1
}">
>
<!-- Background 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"
:style="[{ backgroundSize: gridSize[0] + 'px 100%' }]">
</div>
<div class="c-grid__y l-grid l-grid-y"
class="c-grid__x l-grid l-grid-x"
:style="[{ backgroundSize: gridSize[0] + 'px 100%' }]"
></div>
<div
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>
<component v-for="(item, index) in layoutItems"
<component
:is="item.type"
:item="item"
v-for="(item, index) in layoutItems"
:key="item.id"
:gridSize="gridSize"
:initSelect="initSelectIndex === index"
:item="item"
:grid-size="gridSize"
:init-select="initSelectIndex === index"
:index="index"
:multiSelect="selectedLayoutItems.length > 1"
:multi-select="selectedLayoutItems.length > 1"
@move="move"
@endMove="endMove"
@endLineResize='endLineResize'
@formatChanged='updateTelemetryFormat'>
</component>
<edit-marquee v-if='showMarquee'
:gridSize="gridSize"
:selectedLayoutItems="selectedLayoutItems"
@endResize="endResize">
</edit-marquee>
@endLineResize="endLineResize"
@formatChanged="updateTelemetryFormat"
/>
<edit-marquee
v-if="showMarquee"
:grid-size="gridSize"
:selected-layout-items="selectedLayoutItems"
@endResize="endResize"
/>
</div>
</template>
@ -175,6 +182,13 @@
}
export default {
components: components,
props: {
domainObject: {
type: Object,
required: true
}
},
data() {
let domainObject = JSON.parse(JSON.stringify(this.domainObject));
return {
@ -203,8 +217,23 @@
}
},
inject: ['openmct', 'options', 'objectPath'],
props: ['domainObject'],
components: components,
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();
},
methods: {
addElement(itemType, 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]) {
this.updateItemPosition(item, gridDelta);
}
return item;
});
},
updateItemPosition(item, gridDelta) {
@ -492,7 +520,6 @@
orderItem(position, selectedItems) {
let delta = ORDERS[position];
let indices = [];
let newIndex = -1;
let items = [];
Object.assign(items, this.layoutItems);
@ -564,23 +591,6 @@
item.format = format;
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>

View File

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

View File

@ -21,13 +21,16 @@
*****************************************************************************/
<template>
<layout-frame :item="item"
<layout-frame
:item="item"
:grid-size="gridSize"
@move="(gridDelta) => $emit('move', gridDelta)"
@endMove="() => $emit('endMove')">
<div class="c-image-view"
:style="style">
</div>
@endMove="() => $emit('endMove')"
>
<div
class="c-image-view"
:style="style"
></div>
</layout-frame>
</template>
@ -61,15 +64,26 @@
};
},
inject: ['openmct'],
props: {
item: Object,
gridSize: Array,
index: Number,
initSelect: Boolean
},
components: {
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: {
style() {
return {

View File

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

View File

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

View File

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

View File

@ -21,24 +21,36 @@
*****************************************************************************/
<template>
<layout-frame :item="item"
<layout-frame
:item="item"
:grid-size="gridSize"
@move="(gridDelta) => $emit('move', gridDelta)"
@endMove="() => $emit('endMove')">
<div class="c-telemetry-view"
:style="styleObject"
@endMove="() => $emit('endMove')"
>
<div
v-if="domainObject"
@contextmenu.prevent="showContextMenu">
<div v-if="showLabel"
class="c-telemetry-view__label">
<div class="c-telemetry-view__label-text">{{ domainObject.name }}</div>
class="c-telemetry-view"
:style="styleObject"
@contextmenu.prevent="showContextMenu"
>
<div
v-if="showLabel"
class="c-telemetry-view__label"
>
<div class="c-telemetry-view__label-text">
{{ domainObject.name }}
</div>
</div>
<div v-if="showValue"
<div
v-if="showValue"
:title="fieldName"
class="c-telemetry-view__value"
:class="[telemetryClass]">
<div class="c-telemetry-view__value-text">{{ telemetryValue }}</div>
:class="[telemetryClass]"
>
<div class="c-telemetry-view__value-text">
{{ telemetryValue }}
</div>
</div>
</div>
</layout-frame>
@ -106,15 +118,34 @@
};
},
inject: ['openmct', 'objectPath'],
props: {
item: Object,
gridSize: Array,
initSelect: Boolean,
index: Number
},
components: {
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: {
showLabel() {
let displayMode = this.item.displayMode;
@ -161,14 +192,6 @@
return alarm && alarm.cssClass;
}
},
data() {
return {
datum: undefined,
formats: undefined,
domainObject: undefined,
currentObjectPath: undefined
}
},
watch: {
index(newIndex) {
if (!this.context) {
@ -181,6 +204,20 @@
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: {
requestHistoricalData() {
let bounds = this.openmct.time.bounds();
@ -246,20 +283,6 @@
showContextMenu(event) {
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>
<layout-frame :item="item"
<layout-frame
:item="item"
:grid-size="gridSize"
@move="(gridDelta) => $emit('move', gridDelta)"
@endMove="() => $emit('endMove')">
<div class="c-text-view"
:style="style">
@endMove="() => $emit('endMove')"
>
<div
class="c-text-view"
:style="style"
>
{{ item.text }}
</div>
</layout-frame>
@ -64,15 +68,26 @@
};
},
inject: ['openmct'],
props: {
item: Object,
gridSize: Array,
index: Number,
initSelect: Boolean
},
components: {
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: {
style() {
return {
@ -107,4 +122,3 @@
}
}
</script>

View File

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

View File

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

View File

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

View File

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

View File

@ -1,21 +1,27 @@
<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>
<div class="c-filter-indication"
v-if="hasActiveFilters">{{ label }}
<div
v-if="hasActiveFilters"
class="c-filter-indication"
>
{{ label }}
</div>
<global-filters
:globalFilters="globalFilters"
:globalMetadata="globalMetadata"
@persistGlobalFilters="persistGlobalFilters">
</global-filters>
:global-filters="globalFilters"
:global-metadata="globalMetadata"
@persistGlobalFilters="persistGlobalFilters"
/>
<filter-object
v-for="(child, key) in children"
:key="key"
:filterObject="child"
:persistedFilters="persistedFilters[key]"
@updateFilters="persistFilters">
</filter-object>
:filter-object="child"
:persisted-filters="persistedFilters[key]"
@updateFilters="persistFilters"
/>
</ul>
</template>
@ -91,8 +97,25 @@
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: {
addChildren(domainObject) {
let keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
@ -228,22 +251,6 @@
mutateConfigurationGlobalFilters() {
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>

View File

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

View File

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

View File

@ -22,13 +22,14 @@
<template>
<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}"
@dragover.prevent
@dragenter="dragenter"
@dragleave="dragleave"
@drop="dropHandler">
</div>
@drop="dropHandler"
></div>
</div>
</template>
@ -39,7 +40,10 @@
<script>
export default {
props:{
index: Number,
index: {
type: Number,
required: true
},
allowDrop: {
type: Function,
required: true
@ -51,6 +55,16 @@ export default {
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: {
dragenter() {
this.isMouseOver = true;
@ -68,16 +82,6 @@ export default {
dragend() {
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>

View File

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

View File

@ -21,28 +21,32 @@
*****************************************************************************/
<template>
<div class="c-fl-frame"
<div
class="c-fl-frame"
:style="{
'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"
@dragstart="initDrag"
ref="frame">
>
<object-frame
v-if="domainObject"
ref="objectFrame"
:domain-object="domainObject"
:object-path="objectPath"
:has-frame="hasFrame"
:show-edit-view="false"
ref="objectFrame">
</object-frame>
/>
<div class="c-fl-frame__size-indicator"
<div
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 }}%
</div>
</div>
@ -50,27 +54,56 @@
</template>
<script>
import ResizeHandle from './resizeHandle.vue';
import ObjectFrame from '../../../ui/components/ObjectFrame.vue';
export default {
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() {
return {
domainObject: undefined,
objectPath: undefined
}
},
components: {
ResizeHandle,
ObjectFrame
},
computed: {
hasFrame() {
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: {
setDomainObject(object) {
this.domainObject = object;
@ -105,20 +138,6 @@ export default {
event.dataTransfer.setData('frameid', this.frame.id);
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>

View File

@ -21,22 +21,46 @@
*****************************************************************************/
<template>
<div class="c-fl-frame__resize-handle"
:class="[orientation]"
<div
v-show="isEditing && !isDragging"
@mousedown="mousedown">
</div>
class="c-fl-frame__resize-handle"
:class="[orientation]"
@mousedown="mousedown"
></div>
</template>
<script>
export default {
props: ['orientation', 'index', 'isEditing'],
props: {
orientation: {
type: String,
required: true
},
index: {
type: Number,
required: true
},
isEditing: {
type: Boolean,
default: false
}
},
data() {
return {
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: {
mousedown(event) {
event.preventDefault();
@ -75,16 +99,6 @@ export default {
unsetDragging(event) {
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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,16 +1,30 @@
<template>
<tr class="c-list-item"
<tr
class="c-list-item"
:class="{ 'is-alias': item.isAlias === true }"
@click="navigate">
@click="navigate"
>
<td class="c-list-item__name">
<a :href="objectLink" ref="objectLink">
<div class="c-list-item__type-icon" :class="item.type.cssClass"></div>
<a
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>
</a>
</td>
<td class="c-list-item__type">{{ item.type.name }}</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>
<td class="c-list-item__type">
{{ item.type.name }}
</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>
</template>
@ -64,7 +78,12 @@ import objectLink from '../../../ui/mixins/object-link';
export default {
mixins: [contextMenuGesture, objectLink],
props: ['item'],
props: {
item: {
type: Object,
required: true
}
},
methods: {
formatTime(timestamp, format) {
return moment(timestamp).format(format);

View File

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

View File

@ -23,12 +23,21 @@
<div class="c-about c-about--licenses">
<h1>Open MCT Third Party Licenses</h1>
<p>This software includes components released under the following licenses:</p>
<div v-for="(pkg, key) in packages" :key="key" class="c-license">
<h2 class="c-license__name">{{key}}</h2>
<div
v-for="(pkg, key) in packages"
:key="key"
class="c-license"
>
<h2 class="c-license__name">
{{ key }}
</h2>
<div class="c-license__details">
<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__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 class="c-license__text">
<p>{{ pkg.licenseText }}</p>
@ -49,4 +58,3 @@ export default {
}
}
</script>

View File

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

View File

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

View File

@ -1,42 +1,56 @@
<template>
<div class="c-tabs-view">
<div class="c-tabs-view__tabs-holder c-tabs"
<div
class="c-tabs-view__tabs-holder c-tabs"
:class="{
'is-dragging': isDragging,
'is-mouse-over': allowDrop
}">
<div class="c-drop-hint"
}"
>
<div
class="c-drop-hint"
@drop="onDrop"
@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 class="c-tabs-view__empty-message"
v-if="!tabsList.length > 0">Drag objects here to add them to this view.</div>
<button class="c-tabs-view__tab c-tab"
<button
v-for="(tab,index) in tabsList"
:key="index"
class="c-tabs-view__tab c-tab"
:class="[
{'is-current': isCurrent(tab)},
tab.type.definition.cssClass
]"
@click="showTab(tab)">
@click="showTab(tab)"
>
<span class="c-button__label">{{ tab.domainObject.name }}</span>
</button>
</div>
<div class="c-tabs-view__object-holder"
<div
v-for="(tab, index) in tabsList"
:key="index"
:class="{'c-tabs-view__object-holder--hidden': !isCurrent(tab)}">
<div v-if="currentTab"
class="c-tabs-view__object-holder"
:class="{'c-tabs-view__object-holder--hidden': !isCurrent(tab)}"
>
<div
v-if="currentTab"
class="c-tabs-view__object-name l-browse-bar__object-name--w"
:class="currentTab.type.definition.cssClass">
:class="currentTab.type.definition.cssClass"
>
<div class="l-browse-bar__object-name">
{{ currentTab.domainObject.name }}
</div>
</div>
<object-view class="c-tabs-view__object"
:object="tab.domainObject">
</object-view>
<object-view
class="c-tabs-view__object"
:object="tab.domainObject"
/>
</div>
</div>
</template>
@ -129,6 +143,25 @@ export default {
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:{
showTab(tab) {
this.currentTab = tab;
@ -187,25 +220,6 @@ export default {
isCurrent(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>

View File

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

View File

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

View File

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

View File

@ -1,11 +1,16 @@
<template>
<div v-if="filterNames.length > 0"
:title=title
<div
v-if="filterNames.length > 0"
:title="title"
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 v-for="(name, index) in filterNames"
class="c-filter-indication__label">
<span
v-for="(name, index) in filterNames"
:key="index"
class="c-filter-indication__label"
>
{{ name }}
</span>
</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: {
setFilterNames() {
let names = [];
@ -152,14 +165,6 @@
this.filteredTelemetry = JSON.parse(JSON.stringify(filters));
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>

View File

@ -20,7 +20,12 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<td @click="selectCell($event.currentTarget, columnKey)" :title="formattedValue">{{formattedValue}}</td>
<td
:title="formattedValue"
@click="selectCell($event.currentTarget, columnKey)"
>
{{ formattedValue }}
</td>
</template>
<script>
export default {
@ -32,11 +37,20 @@ export default {
},
columnKey: {
type: String,
require: true
required: true
},
objectPath: {
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: {
@ -57,15 +71,6 @@ export default {
}], false);
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,
dragleave: hideDropTarget,
dragover: dragOverColumn
} : {}">
<div class="c-telemetry-table__headers__content" :class="[
} : {}"
>
<div
class="c-telemetry-table__headers__content"
:class="[
isSortable ? 'is-sortable' : '',
isSortable && sortOptions.key === headerKey ? 'is-sorting' : '',
isSortable && sortOptions.direction].join(' ')">
<div class="c-telemetry-table__resize-hitarea"
isSortable && sortOptions.direction].join(' ')"
>
<div
class="c-telemetry-table__resize-hitarea"
@mousedown="resizeColumnStart"
></div>
<slot></slot>
@ -42,17 +47,31 @@
</th>
</template>
<script>
import _ from 'lodash';
const MOVE_COLUMN_DT_TYPE = 'movecolumnfromindex';
export default {
inject: ['openmct'],
props: {
headerKey: String,
headerIndex: Number,
isHeaderTitle: Boolean,
sortOptions: Object,
columnWidth: Number,
headerKey: {
type: String,
default: undefined
},
headerIndex: {
type: Number,
default: undefined
},
isHeaderTitle: {
type: Boolean,
default: undefined
},
sortOptions: {
type: Object,
default: undefined
},
columnWidth: {
type: Number,
default: undefined
},
hotzone: Boolean,
isEditing: Boolean
},

View File

@ -1,18 +1,50 @@
<template>
<div class="c-properties">
<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">
<li class="c-properties__row">
<div class="c-properties__label" title="Auto-size table"><label for="AutoSizeControl">Auto-size</label></div>
<div class="c-properties__value"><input type="checkbox" id="AutoSizeControl" :checked="configuration.autosize !== false" @change="toggleAutosize()"></div>
<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>
</ul>
<div class="c-properties__header">Table Column Visibility</div>
<div class="c-properties__header">
Table Column Visibility
</div>
<ul class="c-properties__section">
<li class="c-properties__row" v-for="(title, key) in headers">
<div class="c-properties__label" title="Show or hide column"><label :for="key + 'ColumnControl'">{{title}}</label></div>
<div class="c-properties__value"><input type="checkbox" :id="key + 'ColumnControl'" :checked="configuration.hiddenColumns[key] !== true" @change="toggleColumn(key)"></div>
<li
v-for="(title, key) in headers"
: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>
</ul>
</template>
@ -34,6 +66,28 @@ export default {
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: {
updateHeaders(headers) {
this.headers = headers;
@ -70,28 +124,6 @@ export default {
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>

View File

@ -20,22 +20,25 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<tr :style="{ top: rowTop }"
<tr
:style="{ top: rowTop }"
class="noselect"
:class="[
rowClass,
{'is-selected': marked}
]"
v-on="listeners">
<component v-for="(title, key) in headers"
:key="key"
v-on="listeners"
>
<component
: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'}"
:class="[cellLimitClasses[key], selectableColumns[key] ? 'is-selectable' : '']"
:objectPath="objectPath"
:row="row">
</component>
:object-path="objectPath"
:row="row"
/>
</tr>
</template>
@ -55,21 +58,9 @@
import TableCell from './table-cell.vue';
export default {
inject: ['openmct', 'objectPath'],
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;
}, {})
}
inject: ['openmct'],
components: {
TableCell
},
props: {
headers: {
@ -86,7 +77,7 @@ export default {
},
objectPath: {
type: Array,
required: false
required: true
},
rowIndex: {
type: Number,
@ -109,6 +100,42 @@ export default {
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: {
calculateRowTop: function (rowOffset) {
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());
});
}
},
// 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>

View File

@ -22,33 +22,42 @@
<template>
<div class="c-table-wrapper">
<div class="c-table-control-bar c-control-bar">
<button class="c-button icon-download labeled"
<button
v-if="allowExport"
v-on:click="exportAllDataAsCSV()"
title="Export This View's Data">
class="c-button icon-download labeled"
title="Export This View's Data"
@click="exportAllDataAsCSV()"
>
<span class="c-button__label">Export Table Data</span>
</button>
<button class="c-button icon-download labeled"
<button
v-if="allowExport"
v-show="markedRows.length"
v-on:click="exportMarkedDataAsCSV()"
title="Export Marked Rows As CSV">
class="c-button icon-download labeled"
title="Export Marked Rows As CSV"
@click="exportMarkedDataAsCSV()"
>
<span class="c-button__label">Export Marked Rows</span>
</button>
<button class="c-button icon-x labeled"
<button
v-show="markedRows.length"
v-on:click="unmarkAllRows()"
title="Unmark All Rows">
class="c-button icon-x labeled"
title="Unmark All Rows"
@click="unmarkAllRows()"
>
<span class="c-button__label">Unmark All Rows</span>
</button>
<div v-if="enableMarking"
class="c-separator">
</div>
<button v-if="enableMarking"
<div
v-if="enableMarking"
class="c-separator"
></div>
<button
v-if="enableMarking"
class="c-button icon-pause pause-play labeled"
: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">
{{ paused ? 'Play' : 'Pause' }}
</span>
@ -56,97 +65,135 @@
<slot name="buttons"></slot>
</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="{
'loading': loading,
'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" class="c-telemetry-table__drop-target" :style="dropTargetStyle"></div>
<div
v-if="isDropTargetActive"
class="c-telemetry-table__drop-target"
:style="dropTargetStyle"
></div>
<!-- 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">
<thead>
<tr class="c-telemetry-table__headers__labels">
<table-column-header
v-for="(title, key, headerIndex) in headers"
:key="key"
:headerKey="key"
:headerIndex="headerIndex"
:header-key="key"
:header-index="headerIndex"
:column-width="columnWidths[key]"
:sort-options="sortOptions"
:is-editing="isEditing"
@sort="allowSorting && sortBy(key)"
@resizeColumn="resizeColumn"
@dropTargetOffsetChanged="setDropTargetOffset"
@dropTargetActive="dropTargetActive"
@reorderColumn="reorderColumn"
@resizeColumnEnd="updateConfiguredColumnWidths"
:columnWidth="columnWidths[key]"
:sortOptions="sortOptions"
:isEditing="isEditing"
><span class="c-telemetry-table__headers__label">{{title}}</span>
>
<span class="c-telemetry-table__headers__label">{{ title }}</span>
</table-column-header>
</tr>
<tr v-if="allowFiltering" class="c-telemetry-table__headers__filter">
<tr
v-if="allowFiltering"
class="c-telemetry-table__headers__filter"
>
<table-column-header
v-for="(title, key, headerIndex) in headers"
:key="key"
:headerKey="key"
:headerIndex="headerIndex"
:header-key="key"
:header-index="headerIndex"
:column-width="columnWidths[key]"
:is-editing="isEditing"
@resizeColumn="resizeColumn"
@dropTargetOffsetChanged="setDropTargetOffset"
@dropTargetActive="dropTargetActive"
@reorderColumn="reorderColumn"
@resizeColumnEnd="updateConfiguredColumnWidths"
:columnWidth="columnWidths[key]"
:isEditing="isEditing"
>
<search class="c-table__search"
<search
v-model="filters[key]"
v-on:input="filterChanged(key)"
v-on:clear="clearFilter(key)" />
class="c-table__search"
@input="filterChanged(key)"
@clear="clearFilter(key)"
/>
</table-column-header>
</tr>
</thead>
</table>
</div>
<!-- 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 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'}">
<div
class="c-table__body-w c-telemetry-table__body-w js-telemetry-table__body-w"
:style="{ 'max-width': widthWithScroll}"
@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>
<telemetry-table-row v-for="(row, rowIndex) in visibleRows"
<telemetry-table-row
v-for="(row, rowIndex) in visibleRows"
:key="rowIndex"
:headers="headers"
:columnWidths="columnWidths"
:rowIndex="rowIndex"
:objectPath="objectPath"
:rowOffset="rowOffset"
:rowHeight="rowHeight"
:column-widths="columnWidths"
:row-index="rowIndex"
:object-path="objectPath"
:row-offset="rowOffset"
:row-height="rowHeight"
:row="row"
:marked="row.marked"
@mark="markRow"
@unmark="unmarkRow"
@markMultipleConcurrent="markMultipleConcurrentRows">
</telemetry-table-row>
@markMultipleConcurrent="markMultipleConcurrentRows"
/>
</tbody>
</table>
</div>
<!-- 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>
<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>
</tr>
<telemetry-table-row v-for="(sizingRowData, objectKeyString) in sizingRows"
<telemetry-table-row
v-for="(sizingRowData, objectKeyString) in sizingRows"
:key="objectKeyString"
:headers="headers"
:columnWidths="configuredColumnWidths"
:row="sizingRowData">
</telemetry-table-row>
:column-widths="configuredColumnWidths"
:row="sizingRowData"
:object-path="objectPath"
/>
</table>
<telemetry-filter-indicator></telemetry-filter-indicator>
<telemetry-filter-indicator />
</div>
</div><!-- closes c-table-wrapper -->
</template>
@ -343,9 +390,6 @@ const VISIBLE_ROW_COUNT = 100;
const ROW_HEIGHT = 17;
const RESIZE_POLL_INTERVAL = 200;
const AUTO_SCROLL_TRIGGER_HEIGHT = 100;
const RESIZE_HOT_ZONE = 10;
const MOVE_TRIGGER_WAIT = 500;
const VERTICAL_SCROLL_WIDTH = 30;
export default {
components: {
@ -440,6 +484,59 @@ export default {
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: {
updateVisibleRows() {
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>

View File

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

View File

@ -20,10 +20,11 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="c-conductor-axis"
<div
ref="axisHolder"
@mousedown="dragStart($event)">
</div>
class="c-conductor-axis"
@mousedown="dragStart($event)"
></div>
</template>
<style lang="scss">
@ -126,7 +127,42 @@ const PIXELS_PER_TICK_WIDE = 200;
export default {
inject: ['openmct'],
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: {
setScale() {
@ -153,9 +189,6 @@ export default {
this.msPerPixel = (bounds.end - bounds.start) / this.width;
},
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
// supports UTC out of the box.
if (timeSystem.isUTCBased) {
@ -227,38 +260,6 @@ export default {
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>
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up">
<button class="c-button--menu c-mode-button"
@click.prevent="toggle">
<button
class="c-button--menu c-mode-button"
@click.prevent="toggle"
>
<span class="c-button__label">{{ selectedMode.name }}</span>
</button>
<div class="c-menu c-super-menu c-conductor__mode-menu"
v-if="open">
<div
v-if="open"
class="c-menu c-super-menu c-conductor__mode-menu"
>
<div class="c-super-menu__menu">
<ul>
<li v-for="mode in modes"
<li
v-for="mode in modes"
:key="mode.key"
class="menu-item-a"
:class="mode.cssClass"
@click="setOption(mode)"
@mouseover="hoveredMode = mode"
@mouseleave="hoveredMode = {}"
class="menu-item-a"
:class="mode.cssClass">
>
{{ mode.name }}
</li>
</ul>
</div>
<div class="c-super-menu__item-description">
<div :class="['l-item-description__icon', 'bg-' + hoveredMode.cssClass]"></div>
<div class="l-item-description__name">{{hoveredMode.name}}</div>
<div class="l-item-description__description">{{hoveredMode.description}}</div>
<div class="l-item-description__name">
{{ hoveredMode.name }}
</div>
<div class="l-item-description__description">
{{ hoveredMode.description }}
</div>
</div>
</div>
</div>
@ -87,6 +97,14 @@ export default {
hoveredMode: {}
};
},
mounted: function () {
this.loadClocksFromConfiguration();
this.openmct.time.on('clock', this.setViewFromClock);
},
destroyed: function () {
this.openmct.time.off('clock', this.setViewFromClock);
},
methods: {
loadClocksFromConfiguration() {
let clocks = this.configuration.menuOptions
@ -180,14 +198,6 @@ export default {
setViewFromClock(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.
*****************************************************************************/
<template>
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up"
v-if="selectedTimeSystem.name">
<button class="c-button--menu c-time-system-button"
<div
v-if="selectedTimeSystem.name"
class="c-ctrl-wrapper c-ctrl-wrapper--menus-up"
>
<button
class="c-button--menu c-time-system-button"
:class="selectedTimeSystem.cssClass"
@click.prevent="toggle">
@click.prevent="toggle"
>
<span class="c-button__label">{{ selectedTimeSystem.name }}</span>
</button>
<div class="c-menu" v-if="open">
<div
v-if="open"
class="c-menu"
>
<ul>
<li @click="setTimeSystemFromView(timeSystem)"
<li
v-for="timeSystem in timeSystems"
:key="timeSystem.key"
:class="timeSystem.cssClass">
:class="timeSystem.cssClass"
@click="setTimeSystemFromView(timeSystem)"
>
{{ timeSystem.name }}
</li>
</ul>
@ -54,6 +63,14 @@ export default {
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: {
getValidTimesystemsForClock(clock) {
return this.configuration.menuOptions
@ -111,14 +128,6 @@ export default {
let activeClock = this.openmct.time.clock();
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.
*****************************************************************************/
<template>
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up c-datetime-picker__wrapper" ref="calendarHolder">
<a class="c-icon-button icon-calendar"
@click="toggle"></a>
<div class="c-menu c-menu--mobile-modal c-datetime-picker"
v-if="open">
<div
ref="calendarHolder"
class="c-ctrl-wrapper c-ctrl-wrapper--menus-up c-datetime-picker__wrapper"
>
<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">
<button class="c-click-icon icon-x-in-circle"
@click="toggle"></button>
<button
class="c-click-icon icon-x-in-circle"
@click="toggle"
></button>
</div>
<div class="c-datetime-picker__pager c-pager l-month-year-pager">
<div class="c-pager__prev c-icon-button icon-arrow-left"
@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
class="c-pager__prev c-icon-button icon-arrow-left"
@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 class="c-datetime-picker__calendar c-calendar">
<ul class="c-calendar__row--header l-cal-row">
<li v-for="day in ['Su','Mo','Tu','We','Th','Fr','Sa']"
:key="day">{{day}}</li>
<li
v-for="day in ['Su','Mo','Tu','We','Th','Fr','Sa']"
:key="day"
>
{{ day }}
</li>
</ul>
<ul class="c-calendar__row--body"
v-for="(row, index) in table"
:key="index">
<li v-for="(cell, index) in row"
:key="index"
<ul
v-for="(row, tableIndex) in table"
:key="tableIndex"
class="c-calendar__row--body"
>
<li
v-for="(cell, rowIndex) in row"
:key="rowIndex"
:class="{ 'is-in-month': isInCurrentMonth(cell), selected: isSelected(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--sub">{{cell.dayOfYear}}</div>
>
<div class="c-calendar__day--prime">
{{ cell.day }}
</div>
<div class="c-calendar__day--sub">
{{ cell.dayOfYear }}
</div>
</li>
</ul>
</div>
@ -184,8 +211,14 @@ export default {
inject: ['openmct'],
mixins: [toggleMixin],
props: {
defaultDateTime: String,
formatter: Object
defaultDateTime: {
type: String,
default: undefined
},
formatter: {
type: Object,
required: true
}
},
data: function () {
return {
@ -196,13 +229,17 @@ export default {
},
model: {
year: undefined,
month: undefined,
month: undefined
},
table: undefined,
date: undefined,
time: undefined
}
},
mounted: function () {
this.updateFromModel(this.defaultDateTime);
this.updateViewForMonth();
},
methods: {
generateTable() {
let m = moment.utc({ year: this.picker.year, month: this.picker.month }).day(0),
@ -233,9 +270,7 @@ export default {
},
updateFromModel(defaultDateTime) {
let m;
m = moment.utc(defaultDateTime);
let m = moment.utc(defaultDateTime);
this.date = {
year: m.year(),
@ -314,11 +349,7 @@ export default {
optionsFor(key) {
return TIME_OPTIONS[key];
},
},
mounted: function () {
this.updateFromModel(this.defaultDateTime);
this.updateViewForMonth();
}
}
}
</script>

View File

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

View File

@ -20,33 +20,39 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="c-so-view has-local-controls"
<div
class="c-so-view has-local-controls"
:class="{
'c-so-view--no-frame': !hasFrame,
'has-complex-content': complexContent
}">
}"
>
<div class="c-so-view__header">
<div class="c-so-view__header__icon" :class="cssClass"></div>
<div
class="c-so-view__header__icon"
:class="cssClass"
></div>
<div class="c-so-view__header__name">
{{ domainObject && domainObject.name }}
</div>
<context-menu-drop-down
:object-path="objectPath">
</context-menu-drop-down>
:object-path="objectPath"
/>
</div>
<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"
@click="expand">
</button>
@click="expand"
></button>
</div>
<object-view
class="c-so-view__object-view"
ref="objectView"
class="c-so-view__object-view"
:object="domainObject"
:show-edit-view="showEditView"
:object-path="objectPath">
</object-view>
:object-path="objectPath"
/>
</div>
</template>
@ -143,18 +149,34 @@
export default {
inject: ['openmct'],
components: {
ObjectView,
ContextMenuDropDown
},
props: {
domainObject: Object,
objectPath: Array,
domainObject: {
type: Object,
required: true
},
objectPath: {
type: Array,
required: true
},
hasFrame: Boolean,
showEditView: {
type: Boolean,
default: () => true
default: true
}
},
components: {
ObjectView,
ContextMenuDropDown,
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
}
},
methods: {
expand() {
@ -173,16 +195,6 @@
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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,15 +1,20 @@
<template>
<multipane class="c-inspector"
type="vertical">
<multipane
class="c-inspector"
type="vertical"
>
<pane class="c-inspector__properties">
<properties></properties>
<location></location>
<inspector-views></inspector-views>
<properties />
<location />
<inspector-views />
</pane>
<pane class="c-inspector__elements"
<pane
v-if="isEditing && hasComposition"
class="c-inspector__elements"
handle="before"
label="Elements" v-if="isEditing && hasComposition">
<elements></elements>
label="Elements"
>
<elements />
</pane>
</multipane>
</template>
@ -183,9 +188,6 @@
export default {
inject: ['openmct'],
props: {
'isEditing': Boolean
},
components: {
multipane,
pane,
@ -194,11 +196,21 @@
Location,
InspectorViews
},
props: {
'isEditing': Boolean
},
data() {
return {
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: {
refreshComposition(selection) {
if (selection.length > 0 && selection[0].length > 0) {
@ -207,13 +219,6 @@
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>

View File

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

View File

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

View File

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

View File

@ -1,13 +1,25 @@
<template>
<!-- eslint-disable vue/no-v-html -->
<div class="c-about c-about--splash">
<div class="c-about__image c-splash-image"></div>
<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">
<h1 class="l-title s-title">Open MCT</h1>
<h1 class="l-title s-title">
Open MCT
</h1>
<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 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>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>

View File

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

View File

@ -1,58 +1,90 @@
<template>
<div class="l-browse-bar">
<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"
@click="goToParent"></button>
<div class="l-browse-bar__object-name--w"
:class="type.cssClass">
@click="goToParent"
></button>
<div
class="l-browse-bar__object-name--w"
:class="type.cssClass"
>
<span
class="l-browse-bar__object-name c-input-inline"
contenteditable
@blur="updateName"
@keydown.enter.prevent
@keyup.enter.prevent="updateNameOnEnterKeyPress"
contenteditable>
>
{{ domainObject.name }}
</span>
</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 class="l-browse-bar__end">
<view-switcher
:currentView="currentView"
:current-view="currentView"
:views="views"
@setView="setView">
</view-switcher>
@setView="setView"
/>
<!-- Action buttons -->
<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"
title="New Notebook entry"
@click="snapshot()">
</button>
<button class="l-browse-bar__actions__edit c-button c-button--major icon-pencil" title="Edit" v-if="isViewEditable & !isEditing" @click="edit()"></button>
@click="snapshot()"
></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"
v-if="isEditing">
<button class="c-button--menu c-button--major icon-save" title="Save" @click.stop="toggleSaveMenu"></button>
<div class="c-menu" v-show="showSaveMenu">
<div
v-if="isEditing"
class="l-browse-bar__view-switcher c-ctrl-wrapper c-ctrl-wrapper--menus-left"
>
<button
class="c-button--menu c-button--major icon-save"
title="Save"
@click.stop="toggleSaveMenu"
></button>
<div
v-show="showSaveMenu"
class="c-menu"
>
<ul>
<li @click="saveAndFinishEditing"
<li
class="icon-save"
title="Save and Finish Editing">
title="Save and Finish Editing"
@click="saveAndFinishEditing"
>
Save and Finish Editing
</li>
<li @click="saveAndContinueEditing"
<li
class="icon-save"
title="Save and Continue Editing">
title="Save and Continue Editing"
@click="saveAndContinueEditing"
>
Save and Continue Editing
</li>
</ul>
</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>
@ -68,6 +100,89 @@ const PLACEHOLDER_OBJECT = {};
components: {
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: {
toggleSaveMenu() {
this.showSaveMenu = !this.showSaveMenu;
@ -131,11 +246,10 @@ const PLACEHOLDER_OBJECT = {};
progressPerc: 'unknown',
message: 'Do not navigate away from this page or close this browser tab while this message is displayed.',
iconClass: 'info',
title: 'Saving',
title: 'Saving'
});
return this.openmct.editor.save()
.then(()=> {
return this.openmct.editor.save().then(()=> {
dialog.dismiss();
this.openmct.notifications.info('Save successful');
}).catch((error) => {
@ -159,89 +273,6 @@ const PLACEHOLDER_OBJECT = {};
goToParent() {
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>

View File

@ -1,27 +1,37 @@
<template>
<div class="c-create-button--w">
<button class="c-create-button c-button--menu c-button--major icon-plus"
@click="open">
<button
class="c-create-button c-button--menu c-button--major icon-plus"
@click="open"
>
<span class="c-button__label">Create</span>
</button>
<div class="c-create-menu c-super-menu"
v-if="opened">
<div
v-if="opened"
class="c-create-menu c-super-menu"
>
<div class="c-super-menu__menu">
<ul>
<li v-for="(item, index) in sortedItems"
<li
v-for="(item, index) in sortedItems"
:key="index"
:class="item.class"
:title="item.title"
@mouseover="showItemDescription(item)"
@click="create(item)">
@click="create(item)"
>
{{ item.name }}
</li>
</ul>
</div>
<div class="c-super-menu__item-description">
<div :class="['l-item-description__icon', 'bg-' + selectedMenuItem.class]"></div>
<div class="l-item-description__name">{{selectedMenuItem.name}}</div>
<div class="l-item-description__description">{{selectedMenuItem.title}}</div>
<div class="l-item-description__name">
{{ selectedMenuItem.name }}
</div>
<div class="l-item-description__description">
{{ selectedMenuItem.title }}
</div>
</div>
</div>
</div>
@ -65,13 +75,48 @@
import CreateAction from '../../../platform/commonUI/edit/src/creation/CreateAction';
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 {
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: {
open: function () {
if (this.opened) {
@ -118,46 +163,6 @@
let oldModel = objectUtils.toOldFormat(domainObject);
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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,7 +17,9 @@
at runtime from the About dialog for additional information.
-->
<template>
<div class="c-message-banner"
<div
v-if="activeModel.message"
class="c-message-banner"
:class="[
activeModel.severity,
{
@ -25,14 +27,17 @@
'new': !activeModel.minimized
}]"
@click="maximize()"
v-if="activeModel.message">
>
<span class="c-message-banner__message">{{ activeModel.message }}</span>
<progress-bar
v-if="activeModel.progressPerc !== undefined"
class="c-message-banner__progress-bar"
v-if="activeModel.progressPerc !== undefined" :model="activeModel">
</progress-bar>
<button class="c-message-banner__close-button c-click-icon icon-x-in-circle"
@click.stop="dismiss()"></button>
:model="activeModel"
/>
<button
class="c-message-banner__close-button c-click-icon icon-x-in-circle"
@click.stop="dismiss()"
></button>
</div>
</template>
@ -118,7 +123,6 @@
<script>
import ProgressBar from '../../components/ProgressBar.vue';
let activeNotification = undefined;
let dialogService = undefined;
let maximizedDialog = undefined;
let minimizeButton = {
label: 'Dismiss',
@ -157,6 +161,16 @@
}
}
},
computed: {
progressWidth() {
return {
width: this.activeModel.progress + '%'
};
}
},
mounted() {
this.openmct.notifications.on('notification', this.showNotification);
},
methods: {
showNotification(notification) {
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>
<li class="c-tree__item-h">
<div class="c-tree__item"
:class="{ 'is-alias': isAlias, 'is-navigated-object': isNavigated }">
<view-control class="c-tree__item__view-control"
<div
class="c-tree__item"
:class="{ 'is-alias': isAlias, 'is-navigated-object': isNavigated }"
>
<view-control
v-model="expanded"
class="c-tree__item__view-control"
:enabled="hasChildren"
v-model="expanded">
</view-control>
<object-label :domainObject="node.object"
:objectPath="node.objectPath"
:navigateToPath="navigateToPath">
</object-label>
/>
<object-label
:domain-object="node.object"
:object-path="node.objectPath"
:navigate-to-path="navigateToPath"
/>
</div>
<ul v-if="expanded" class="c-tree">
<li class="c-tree__item-h"
v-if="isLoading && !loaded">
<ul
v-if="expanded"
class="c-tree"
>
<li
v-if="isLoading && !loaded"
class="c-tree__item-h"
>
<div class="c-tree__item loading">
<span class="c-tree__item__label">Loading...</span>
</div>
</li>
<tree-item v-for="child in children"
<tree-item
v-for="child in children"
:key="child.id"
:node="child">
</tree-item>
:node="child"
/>
</ul>
</li>
</template>
@ -31,10 +41,17 @@
import ObjectLabel from '../components/ObjectLabel.vue';
export default {
name: 'tree-item',
name: 'TreeItem',
inject: ['openmct'],
components: {
viewControl,
ObjectLabel
},
props: {
node: Object
node: {
type: Object,
required: true
}
},
data() {
this.navigateToPath = this.buildPathString(this.node.navigateToParent)
@ -57,6 +74,20 @@
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() {
// TODO: should update on mutation.
// TODO: click navigation should not fubar hash quite so much.
@ -85,20 +116,6 @@
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: {
addChild(child) {
this.children.push({
@ -127,10 +144,6 @@
this.isNavigated = false;
}
}
},
components: {
viewControl,
ObjectLabel
}
}
</script>

View File

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

View File

@ -23,26 +23,29 @@
<div class="l-preview-window">
<div class="l-browse-bar">
<div class="l-browse-bar__start">
<div class="l-browse-bar__object-name--w"
:class="type.cssClass">
<div
class="l-browse-bar__object-name--w"
:class="type.cssClass"
>
<span class="l-browse-bar__object-name">
{{ domainObject.name }}
</span>
<context-menu-drop-down :object-path="objectPath"></context-menu-drop-down>
<context-menu-drop-down :object-path="objectPath" />
</div>
</div>
<div class="l-browse-bar__end">
<div class="l-browse-bar__actions">
<view-switcher
:views="views"
:currentView="currentView"
@setView="setView">
</view-switcher>
<button v-if="notebookEnabled"
:current-view="currentView"
@setView="setView"
/>
<button
v-if="notebookEnabled"
class="l-browse-bar__actions__edit c-button icon-notebook"
title="New Notebook entry"
@click="snapshot">
</button>
@click="snapshot"
></button>
</div>
</div>
</div>
@ -97,6 +100,17 @@
'openmct',
'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: {
views() {
return this
@ -108,6 +122,18 @@
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: {
snapshot() {
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.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>

View File

@ -1,10 +1,13 @@
<template>
<div class="c-toolbar">
<component v-for="item in structure"
<component
:is="item.control"
v-for="(item, index) in structure"
:key="index"
:options="item"
@click="triggerMethod(item, $event)"
@change="updateObjectValue"></component>
@change="updateObjectValue"
/>
</div>
</template>
@ -37,6 +40,14 @@
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: {
handleSelection(selection) {
this.removeListeners();
@ -133,7 +144,7 @@
}
// 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];
toolbarItem.nonSpecific = false;
} else {
@ -169,7 +180,7 @@
});
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];
toolbarItem.nonSpecific = false;
} else {
@ -250,14 +261,6 @@
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() {
this.openmct.selection.off('change', this.handleSelection);
this.openmct.editor.off('isEditing', this.handleEditing);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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