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,20 +1,24 @@
<template>
<div class="c-menu">
<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>
</div>
</template>
<script>
export default {
export default {
inject: ['actions', 'objectPath']
}
}
</script>

View File

@ -1,28 +1,36 @@
<template>
<div class="c-message">
<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">
{{title}}
<div
v-if="title"
class="c-message__title"
>
{{ title }}
</div>
<div class="c-message__hint"
v-if="hint">
{{hint}}
<span v-if="timestamp">[{{timestamp}}]</span>
<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">
{{message}}
<div
v-if="message"
class="c-message__action-text"
>
{{ message }}
</div>
<slot></slot>
</div>
</div>
</div>
</template>
<style lang="scss">

View File

@ -1,28 +1,57 @@
<template>
<div class="c-overlay">
<div class="c-overlay__blocker"
@click="destroy">
</div>
<div class="c-overlay">
<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"
: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}"
@click="buttonClickHandler(button.callback)">
{{button.label}}
@focus="focusIndex=index"
@click="buttonClickHandler(button.callback)"
>
{{ button.label }}
</button>
</div>
</div>
</div>
</div>
</template>
<style lang="scss">
@ -174,7 +203,7 @@
</style>
<script>
export default {
export default {
data: function () {
return {
focusIndex: -1
@ -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;
}
@ -219,5 +248,5 @@
return focusButton[0];
}
}
}
}
</script>

View File

@ -1,7 +1,7 @@
<template>
<dialog-component>
<progress-component :model="model"></progress-component>
</dialog-component>
<dialog-component>
<progress-component :model="model" />
</dialog-component>
</template>
<style lang="scss">
@ -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

@ -22,13 +22,13 @@
*****************************************************************************/
<template>
<tr @contextmenu.prevent="showContextMenu">
<td>{{name}}</td>
<td>{{timestamp}}</td>
<tr @contextmenu.prevent="showContextMenu">
<td>{{ name }}</td>
<td>{{ timestamp }}</td>
<td :class="valueClass">
{{value}}
{{ value }}
</td>
</tr>
</tr>
</template>
<style lang="scss">
@ -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,48 +62,16 @@ export default {
currentObjectPath
}
},
methods: {
updateValues(datum) {
this.timestamp = this.formats[this.timestampKey].format(datum);
this.value = this.formats[this.valueKey].format(datum);
var limit = this.limitEvaluator.evaluate(datum, this.valueMetadata);
if (limit) {
this.valueClass = limit.cssClass;
} else {
this.valueClass = '';
}
},
updateName(name){
this.name = name;
},
updateTimeSystem(timeSystem) {
this.value = '---';
this.timestamp = '---';
this.valueClass = '';
this.timestampKey = timeSystem.key;
this.openmct
.telemetry
.request(this.domainObject, {strategy: 'latest'})
.then((array) => this.updateValues(array[array.length - 1]));
},
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
this.limitEvaluator = this.openmct
.telemetry
.limitEvaluator(this.domainObject);
this.stopWatchingMutation = openmct
this.stopWatchingMutation = this.openmct
.objects
.observe(
this.domainObject,
@ -129,6 +102,38 @@ export default {
this.stopWatchingMutation();
this.unsubscribe();
this.openmct.off('timeSystem', this.updateTimeSystem);
},
methods: {
updateValues(datum) {
this.timestamp = this.formats[this.timestampKey].format(datum);
this.value = this.formats[this.valueKey].format(datum);
var limit = this.limitEvaluator.evaluate(datum, this.valueMetadata);
if (limit) {
this.valueClass = limit.cssClass;
} else {
this.valueClass = '';
}
},
updateName(name) {
this.name = name;
},
updateTimeSystem(timeSystem) {
this.value = '---';
this.timestamp = '---';
this.valueClass = '';
this.timestampKey = timeSystem.key;
this.openmct
.telemetry
.request(this.domainObject, {strategy: 'latest'})
.then((array) => this.updateValues(array[array.length - 1]));
},
showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
}
}
}
</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

@ -21,7 +21,7 @@
*****************************************************************************/
<template>
<table class="c-table c-lad-table">
<table class="c-table c-lad-table">
<thead>
<tr>
<th>Name</th>
@ -31,19 +31,24 @@
</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>
</table>
</template>
<style lang="scss">
@ -51,10 +56,9 @@
</style>
<script>
import lodash from 'lodash';
import LadRow from './LADRow.vue';
import LadRow from './LADRow.vue';
export default {
export default {
inject: ['openmct', 'domainObject'],
components: {
LadRow
@ -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

@ -1,9 +1,9 @@
<template>
<div class="c-indicator c-indicator--clickable icon-clear-data s-status-caution">
<div class="c-indicator c-indicator--clickable icon-clear-data s-status-caution">
<span class="label c-indicator__label">
<button @click="globalClearEmit">Clear Data</button>
</span>
</div>
</div>
</template>
<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,37 +21,54 @@
*****************************************************************************/
<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>
</ul>
</div>
</div>
</template>
<script>
export default {
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,16 +92,7 @@
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);
}
}
}
</script>

View File

@ -21,15 +21,18 @@
*****************************************************************************/
<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>
</layout-frame>
</template>
@endMove="() => $emit('endMove')"
>
<div
class="c-box-view"
:style="style"
></div>
</layout-frame>
</template>
<style lang="scss">
@import '~styles/sass-base';
@ -44,10 +47,10 @@
}
</style>
<script>
import LayoutFrame from './LayoutFrame.vue'
<script>
import LayoutFrame from './LayoutFrame.vue'
export default {
export default {
makeDefinition() {
return {
fill: '#717171',
@ -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: {
@ -98,6 +112,5 @@
this.removeSelectable();
}
}
}
</script>
}
</script>

View File

@ -21,42 +21,49 @@
*****************************************************************************/
<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>
</div>
@endLineResize="endLineResize"
@formatChanged="updateTelemetryFormat"
/>
<edit-marquee
v-if="showMarquee"
:grid-size="gridSize"
:selected-layout-items="selectedLayoutItems"
@endResize="endResize"
/>
</div>
</template>
<style lang="scss">
@ -135,36 +142,36 @@
</style>
<script>
import uuid from 'uuid';
import uuid from 'uuid';
import SubobjectView from './SubobjectView.vue'
import TelemetryView from './TelemetryView.vue'
import BoxView from './BoxView.vue'
import TextView from './TextView.vue'
import LineView from './LineView.vue'
import ImageView from './ImageView.vue'
import EditMarquee from './EditMarquee.vue'
import SubobjectView from './SubobjectView.vue'
import TelemetryView from './TelemetryView.vue'
import BoxView from './BoxView.vue'
import TextView from './TextView.vue'
import LineView from './LineView.vue'
import ImageView from './ImageView.vue'
import EditMarquee from './EditMarquee.vue'
const ITEM_TYPE_VIEW_MAP = {
const ITEM_TYPE_VIEW_MAP = {
'subobject-view': SubobjectView,
'telemetry-view': TelemetryView,
'box-view': BoxView,
'line-view': LineView,
'text-view': TextView,
'image-view': ImageView
};
const ORDERS = {
};
const ORDERS = {
top: Number.POSITIVE_INFINITY,
up: 1,
down: -1,
bottom: Number.NEGATIVE_INFINITY
};
const DRAG_OBJECT_TRANSFER_PREFIX = 'openmct/domain-object/';
};
const DRAG_OBJECT_TRANSFER_PREFIX = 'openmct/domain-object/';
let components = ITEM_TYPE_VIEW_MAP;
components['edit-marquee'] = EditMarquee;
let components = ITEM_TYPE_VIEW_MAP;
components['edit-marquee'] = EditMarquee;
function getItemDefinition(itemType, ...options) {
function getItemDefinition(itemType, ...options) {
let itemView = ITEM_TYPE_VIEW_MAP[itemType];
if (!itemView) {
@ -172,9 +179,16 @@
}
return itemView.makeDefinition(...options);
}
}
export default {
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) {
@ -380,7 +408,7 @@
// If the layout already contains the given object, then shortcut the default dragover behavior and
// potentially allow drop. Display layouts allow drag drop of duplicate telemetry objects.
if (this.containsObject(draggedKeyString)){
if (this.containsObject(draggedKeyString)) {
$event.preventDefault();
}
},
@ -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

@ -21,17 +21,28 @@
*****************************************************************************/
<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>
<!-- Resize handles -->
<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>
<style lang="scss">
@ -95,13 +106,21 @@
<script>
import LayoutDrag from './../LayoutDrag'
import LayoutDrag from './../LayoutDrag'
export default {
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;
@ -229,5 +247,5 @@
event.preventDefault();
}
}
}
}
</script>

View File

@ -21,15 +21,18 @@
*****************************************************************************/
<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>
</layout-frame>
</template>
@endMove="() => $emit('endMove')"
>
<div
class="c-image-view"
:style="style"
></div>
</layout-frame>
</template>
<style lang="scss">
@import '~styles/sass-base';
@ -46,10 +49,10 @@
}
</style>
<script>
import LayoutFrame from './LayoutFrame.vue'
<script>
import LayoutFrame from './LayoutFrame.vue'
export default {
export default {
makeDefinition(openmct, gridSize, element) {
return {
stroke: 'transparent',
@ -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 {
@ -100,5 +114,5 @@
this.removeSelectable();
}
}
}
</script>
}
</script>

View File

@ -21,19 +21,21 @@
*****************************************************************************/
<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>
<div
class="c-frame-edit__move"
@mousedown="startMove([1,1], [0,0], $event)"
></div>
</div>
</template>
<style lang="scss">
@ -173,13 +175,21 @@
</style>
<script>
import LayoutDrag from './../LayoutDrag'
import LayoutDrag from './../LayoutDrag'
export default {
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() {
@ -241,5 +251,5 @@
});
}
}
}
}
</script>

View File

@ -21,45 +21,60 @@
*****************************************************************************/
<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>
</div>
@mousedown="startDrag($event, 'end')"
></div>
</div>
</div>
</template>
<script>
<script>
const START_HANDLE_QUADRANTS = {
const START_HANDLE_QUADRANTS = {
1: 'c-frame-edit__handle--sw',
2: 'c-frame-edit__handle--se',
3: 'c-frame-edit__handle--ne',
4: 'c-frame-edit__handle--nw'
};
};
const END_HANDLE_QUADRANTS = {
const END_HANDLE_QUADRANTS = {
1: 'c-frame-edit__handle--ne',
2: 'c-frame-edit__handle--nw',
3: 'c-frame-edit__handle--sw',
4: 'c-frame-edit__handle--se'
};
};
export default {
export default {
makeDefinition() {
return {
x: 5,
@ -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>
}
</script>

View File

@ -20,44 +20,47 @@
* 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>
/>
</layout-frame>
</template>
<script>
import ObjectFrame from '../../../ui/components/ObjectFrame.vue'
import LayoutFrame from './LayoutFrame.vue'
import ObjectFrame from '../../../ui/components/ObjectFrame.vue'
import LayoutFrame from './LayoutFrame.vue'
const MINIMUM_FRAME_SIZE = [320, 180],
const MINIMUM_FRAME_SIZE = [320, 180],
DEFAULT_DIMENSIONS = [10, 10],
DEFAULT_POSITION = [1, 1],
DEFAULT_HIDDEN_FRAME_TYPES = ['hyperlink', 'summary-widget'];
function getDefaultDimensions(gridSize) {
function getDefaultDimensions(gridSize) {
return MINIMUM_FRAME_SIZE.map((min, index) => {
return Math.max(
Math.ceil(min / gridSize[index]),
DEFAULT_DIMENSIONS[index]
);
});
}
}
function hasFrameByDefault(type) {
function hasFrameByDefault(type) {
return DEFAULT_HIDDEN_FRAME_TYPES.indexOf(type) === -1;
}
}
export default {
export default {
makeDefinition(openmct, gridSize, domainObject, position) {
let defaultDimensions = getDefaultDimensions(gridSize);
position = position || DEFAULT_POSITION;
@ -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

@ -20,29 +20,41 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<layout-frame :item="item"
<template>
<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>
</layout-frame>
</template>
</div>
</layout-frame>
</template>
<style lang="scss">
@import '~styles/sass-base';
@ -78,15 +90,15 @@
}
</style>
<script>
import LayoutFrame from './LayoutFrame.vue'
import printj from 'printj'
<script>
import LayoutFrame from './LayoutFrame.vue'
import printj from 'printj'
const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5],
const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5],
DEFAULT_POSITION = [1, 1],
CONTEXT_MENU_ACTIONS = ['viewHistoricalData'];
export default {
export default {
makeDefinition(openmct, gridSize, domainObject, position) {
let metadata = openmct.telemetry.getMetadata(domainObject);
position = position || DEFAULT_POSITION;
@ -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,21 +283,7 @@
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);
}
}
</script>
</script>

View File

@ -20,17 +20,21 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<layout-frame :item="item"
<template>
<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>
</template>
</layout-frame>
</template>
<style lang="scss">
@import '~styles/sass-base';
@ -46,10 +50,10 @@
}
</style>
<script>
import LayoutFrame from './LayoutFrame.vue'
<script>
import LayoutFrame from './LayoutFrame.vue'
export default {
export default {
makeDefinition(openmct, gridSize, element) {
return {
fill: 'transparent',
@ -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 {
@ -105,6 +120,5 @@
this.removeSelectable();
}
}
}
</script>
}
</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"
<div class="c-properties__section c-filter-settings">
<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>
@ -50,7 +60,7 @@
</template>
</div>
</li>
</div>
</div>
</template>
<script>
@ -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,50 +1,62 @@
<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>
<li class="c-tree__item-h">
<div
class="c-tree__item menus-to-left"
@click="toggleExpanded"
>
<div
class="c-filter-tree-item__filter-indicator"
:class="{'icon-filter': hasActiveFilters }"
></div>
<span
class="c-disclosure-triangle is-enabled flex-elem"
:class="{'c-disclosure-triangle--expanded': expanded}"
></span>
<div class="c-tree__item__label 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>
</li>
</template>
<script>
@ -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,22 +1,28 @@
<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>
</ul>
:filter-object="child"
:persisted-filters="persistedFilters[key]"
@updateFilters="persistFilters"
/>
</ul>
</template>
<style lang="scss">
@ -40,14 +46,14 @@
</style>
<script>
import FilterObject from './FilterObject.vue';
import GlobalFilters from './GlobalFilters.vue'
import FilterObject from './FilterObject.vue';
import GlobalFilters from './GlobalFilters.vue'
const FILTER_VIEW_TITLE = 'Filters applied';
const FILTER_VIEW_TITLE_MIXED = 'Mixed filters applied';
const USE_GLOBAL = 'useGlobal';
const FILTER_VIEW_TITLE = 'Filters applied';
const FILTER_VIEW_TITLE_MIXED = 'Mixed filters applied';
const USE_GLOBAL = 'useGlobal';
export default {
export default {
components: {
FilterObject,
GlobalFilters
@ -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,29 +1,40 @@
<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>
<li class="c-tree__item-h">
<div
class="c-tree__item menus-to-left"
@click="toggleExpanded"
>
<div
class="c-filter-tree-item__filter-indicator"
:class="{'icon-filter': hasActiveGlobalFilters }"
></div>
<span
class="c-disclosure-triangle is-enabled flex-elem"
:class="{'c-disclosure-triangle--expanded': expanded}"
></span>
<div class="c-tree__item__label c-object-label">
<div class="c-object-label">
<div class="c-object-label__type-icon icon-gear"></div>
<div class="c-object-label__name flex-elem grows">Global Filtering</div>
<div 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>
</li>
</template>
<style lang="scss">
@ -59,15 +70,18 @@
</style>
<script>
import FilterField from './FilterField.vue';
import FilterField from './FilterField.vue';
export default {
export default {
inject: ['openmct'],
components: {
FilterField
},
props: {
globalMetadata: Object,
globalMetadata: {
type: Object,
required: true
},
globalFilters: {
type: Object,
default: () => {
@ -131,5 +145,5 @@
this.$emit('persistGlobalFilters', key, this.updatedFilters);
}
}
}
}
</script>

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,48 +39,47 @@
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>
</div>
</template>
<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

@ -21,15 +21,16 @@
*****************************************************************************/
<template>
<div v-show="isValidTarget">
<div class="c-drop-hint c-drop-hint--always-show"
<div v-show="isValidTarget">
<div
class="c-drop-hint c-drop-hint--always-show"
:class="{'is-mouse-over': isMouseOver}"
@dragover.prevent
@dragenter="dragenter"
@dragleave="dragleave"
@drop="dropHandler">
</div>
</div>
@drop="dropHandler"
></div>
</div>
</template>
<style lang="scss">
@ -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

@ -21,67 +21,69 @@
*****************************************************************************/
<template>
<div class="c-fl">
<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>
</div>
</template>
<style lang="scss">
@ -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();
@ -589,7 +606,7 @@ export default {
return containerPos !== index && (containerPos - 1) !== index
}
},
persist(index){
persist(index) {
if (index) {
this.openmct.objects.mutate(this.domainObject, `configuration.containers[${index}]`, this.containers[index]);
} else {
@ -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,56 +21,89 @@
*****************************************************************************/
<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">
{{frame.size}}%
</div>
v-show="frame.size && frame.size < 100"
class="c-fl-frame__size-indicator"
>
{{ frame.size }}%
</div>
</div>
</div>
</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,25 +1,38 @@
<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">
<span class="c-grid-item__metadata__type">{{item.type.name}}</span>
<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>
</a>
</template>
<style lang="scss">
@ -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,11 +1,12 @@
<template>
<div class="l-grid-view">
<grid-item v-for="(item, index) in items"
<div class="l-grid-view">
<grid-item
v-for="(item, index) in items"
:key="index"
:item="item"
:object-path="item.objectPath">
</grid-item>
</div>
:object-path="item.objectPath"
/>
</div>
</template>
<style lang="scss">

View File

@ -1,17 +1,31 @@
<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>
<div class="c-list-item__name-value">{{item.model.name}}</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>
</tr>
<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>
<style lang="scss">
@ -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

@ -1,55 +1,64 @@
<template>
<div class="c-table c-table--sortable c-list-view">
<div class="c-table c-table--sortable c-list-view">
<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>
</div>
</template>
<style lang="scss">
@ -93,8 +102,6 @@
</style>
<script>
import lodash from 'lodash';
import compositionLoader from './composition-loader';
import ListItem from './ListItem.vue';
@ -120,7 +127,7 @@ export default {
};
},
computed: {
sortedItems () {
sortedItems() {
let sortedItems = _.sortBy(this.items, this.sortBy);
if (!this.ascending) {
sortedItems = sortedItems.reverse();

View File

@ -20,21 +20,30 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="c-about c-about--licenses">
<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__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>
</div>
<div class="c-license__text">
<p>{{pkg.licenseText}}</p>
</div>
<p>{{ pkg.licenseText }}</p>
</div>
</div>
</div>
</template>
<style lang="sass">
</style>
@ -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,44 +1,58 @@
<template>
<div class="c-tabs-view">
<div class="c-tabs-view__tabs-holder c-tabs"
<div class="c-tabs-view">
<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)">
<span class="c-button__label">{{tab.domainObject.name}}</span>
@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}}
{{ currentTab.domainObject.name }}
</div>
</div>
<object-view class="c-tabs-view__object"
:object="tab.domainObject">
</object-view>
</div>
<object-view
class="c-tabs-view__object"
:object="tab.domainObject"
/>
</div>
</div>
</template>
<style lang="scss">
@ -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;
@ -169,7 +202,7 @@ export default {
onDrop(e) {
this.setCurrentTab = true;
},
dragstart (e) {
dragstart(e) {
if (e.dataTransfer.types.includes('openmct/domain-object-path')) {
this.isDragging = true;
}
@ -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,14 +1,19 @@
<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>
</div>
</template>
<style lang="scss">
@ -53,13 +58,13 @@
</style>
<script>
const FILTER_INDICATOR_LABEL = 'Filters:';
const FILTER_INDICATOR_LABEL_MIXED = 'Mixed Filters:';
const FILTER_INDICATOR_TITLE = 'Data filters are being applied to this view.';
const FILTER_INDICATOR_TITLE_MIXED = 'A mix of data filter values are being applied to this view.';
const USE_GLOBAL = 'useGlobal';
const FILTER_INDICATOR_LABEL = 'Filters:';
const FILTER_INDICATOR_LABEL_MIXED = 'Mixed Filters:';
const FILTER_INDICATOR_TITLE = 'Data filters are being applied to this view.';
const FILTER_INDICATOR_TITLE_MIXED = 'A mix of data filter values are being applied to this view.';
const USE_GLOBAL = 'useGlobal';
export default {
export default {
inject: ['openmct', 'table'],
data() {
return {
@ -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 = [];
@ -129,7 +142,7 @@
return _.flatten(filterNames);
},
getFilterLabels(filterObject, metadatum, ) {
getFilterLabels(filterObject, metadatum,) {
let filterLabels = [];
Object.values(filterObject).forEach(comparator => {
comparator.forEach(filterValue => {
@ -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
},
@ -94,7 +113,7 @@ export default {
return [...event.dataTransfer.types].includes(MOVE_COLUMN_DT_TYPE);
},
dragOverColumn(event) {
if (this.isColumnMoveEvent(event)){
if (this.isColumnMoveEvent(event)) {
event.preventDefault();
this.updateDropOffset(event.currentTarget, event.clientX);
} else {
@ -114,19 +133,19 @@ export default {
this.$emit('dropTargetOffsetChanged', dropOffsetLeft);
this.$emit('dropTargetActive', true);
},
hideDropTarget(){
hideDropTarget() {
this.$emit('dropTargetActive', false);
},
columnMoveEnd(event){
if (this.isColumnMoveEvent(event)){
columnMoveEnd(event) {
if (this.isColumnMoveEvent(event)) {
let toIndex = this.headerIndex;
let fromIndex = event.dataTransfer.getData(MOVE_COLUMN_DT_TYPE);
if (event.offsetX < event.target.offsetWidth / 2) {
if (toIndex > fromIndex){
if (toIndex > fromIndex) {
toIndex--;
}
} else {
if (toIndex < fromIndex){
if (toIndex < fromIndex) {
toIndex++;
}
}

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,131 +22,178 @@
<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'}}
{{ paused ? 'Play' : 'Pause' }}
</span>
</button>
<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) {
@ -527,7 +624,7 @@ export default {
}
this.table.sortBy(this.sortOptions);
},
scroll () {
scroll() {
this.updateVisibleRows();
this.synchronizeScrollX();
@ -557,7 +654,7 @@ export default {
this.table.filteredRows.setColumnFilter(columnKey, '');
this.setHeight();
},
rowsAdded (rows) {
rowsAdded(rows) {
this.setHeight();
let sizingRow;
@ -578,7 +675,7 @@ export default {
this.updateVisibleRows();
},
rowsRemoved (rows) {
rowsRemoved(rows) {
this.setHeight();
this.updateVisibleRows();
},
@ -811,66 +908,12 @@ export default {
let row = allRows[i];
row.marked = true;
if (row !== baseRow){
if (row !== baseRow) {
this.markedRows.push(row);
}
}
}
}
},
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,47 +84,59 @@
<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>
</div>
</template>
<style lang="scss">
@ -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);
@ -347,7 +385,7 @@ export default {
this.isUTCBased = timeSystem.isUTCBased;
},
setOffsetsFromView($event) {
if (this.$refs.conductorForm.checkValidity()){
if (this.$refs.conductorForm.checkValidity()) {
let startOffset = 0 - this.durationFormatter.parse(this.offsets.start);
let endOffset = this.durationFormatter.parse(this.offsets.end);
@ -362,7 +400,7 @@ export default {
}
},
setBoundsFromView($event) {
if (this.$refs.conductorForm.checkValidity()){
if (this.$refs.conductorForm.checkValidity()) {
let start = this.timeFormatter.parse(this.formattedBounds.start);
let end = this.timeFormatter.parse(this.formattedBounds.end);
@ -404,7 +442,7 @@ export default {
[this.$refs.startOffset, this.$refs.endOffset].forEach(this.clearValidationForInput);
}
},
clearValidationForInput(input){
clearValidationForInput(input) {
input.setCustomValidity('');
input.title = '';
},
@ -419,7 +457,7 @@ export default {
formattedDate = this.formattedBounds.end;
}
if (!this.timeFormatter.validate(formattedDate)){
if (!this.timeFormatter.validate(formattedDate)) {
validationResult = 'Invalid date';
} else {
let boundsValues = {
@ -429,7 +467,7 @@ export default {
validationResult = this.openmct.time.validateBounds(boundsValues);
}
if (validationResult !== true){
if (validationResult !== true) {
input.setCustomValidity(validationResult);
input.title = validationResult;
return false;
@ -461,7 +499,7 @@ export default {
validationResult = this.openmct.time.validateOffsets(offsetValues);
}
if (validationResult !== true){
if (validationResult !== true) {
input.setCustomValidity(validationResult);
input.title = validationResult;
return false;
@ -482,24 +520,16 @@ export default {
format: key
}).formatter;
},
startDateSelected(date){
startDateSelected(date) {
this.formattedBounds.start = this.timeFormatter.format(date);
this.validateAllBounds();
this.submitForm();
},
endDateSelected(date){
endDateSelected(date) {
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,106 +127,9 @@ const PIXELS_PER_TICK_WIDE = 200;
export default {
inject: ['openmct'],
props: {
bounds: Object
},
methods: {
setScale() {
let timeSystem = this.openmct.time.timeSystem();
let bounds = this.bounds;
if (timeSystem.isUTCBased) {
this.xScale.domain([new Date(bounds.start), new Date(bounds.end)]);
} else {
this.xScale.domain([bounds.start, bounds.end]);
}
this.xAxis.scale(this.xScale);
this.xScale.range([PADDING, this.width - PADDING * 2]);
this.axisElement.call(this.xAxis);
if (this.width > 1800) {
this.xAxis.ticks(this.width / PIXELS_PER_TICK_WIDE);
} else {
this.xAxis.ticks(this.width / PIXELS_PER_TICK);
}
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) {
this.xScale = d3Scale.scaleUtc();
} else {
this.xScale = d3Scale.scaleLinear();
}
this.xAxis.scale(this.xScale);
this.xAxis.tickFormat(utcMultiTimeFormat);
this.axisElement.call(this.xAxis);
this.setScale();
},
getActiveFormatter() {
let timeSystem = this.openmct.time.timeSystem();
let isFixed = this.openmct.time.clock() === undefined;
if (isFixed) {
return this.getFormatter(timeSystem.timeFormat);
} else {
return this.getFormatter(timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
}
},
getFormatter(key) {
return this.openmct.telemetry.getValueFormatter({
format: key
}).formatter;
},
dragStart($event){
let isFixed = this.openmct.time.clock() === undefined;
if (isFixed){
this.dragStartX = $event.clientX;
document.addEventListener('mousemove', this.drag);
document.addEventListener('mouseup', this.dragEnd, {
once: true
});
}
},
drag($event) {
if (!this.dragging){
this.dragging = true;
requestAnimationFrame(()=>{
let deltaX = $event.clientX - this.dragStartX;
let percX = deltaX / this.width;
let bounds = this.openmct.time.bounds();
let deltaTime = bounds.end - bounds.start;
let newStart = bounds.start - percX * deltaTime;
this.$emit('panAxis',{
start: newStart,
end: newStart + deltaTime
});
this.dragging = false;
})
} else {
console.log('Rejected drag due to RAF cap');
}
},
dragEnd() {
document.removeEventListener('mousemove', this.drag);
this.openmct.time.bounds({
start: this.bounds.start,
end: this.bounds.end
});
},
resize() {
if (this.$refs.axisHolder.clientWidth !== this.width) {
this.width = this.$refs.axisHolder.clientWidth;
this.setScale();
}
bounds: {
type: Object,
required: true
}
},
watch: {
@ -259,6 +163,103 @@ export default {
setInterval(this.resize, RESIZE_POLL_INTERVAL);
},
destroyed() {
},
methods: {
setScale() {
let timeSystem = this.openmct.time.timeSystem();
let bounds = this.bounds;
if (timeSystem.isUTCBased) {
this.xScale.domain([new Date(bounds.start), new Date(bounds.end)]);
} else {
this.xScale.domain([bounds.start, bounds.end]);
}
this.xAxis.scale(this.xScale);
this.xScale.range([PADDING, this.width - PADDING * 2]);
this.axisElement.call(this.xAxis);
if (this.width > 1800) {
this.xAxis.ticks(this.width / PIXELS_PER_TICK_WIDE);
} else {
this.xAxis.ticks(this.width / PIXELS_PER_TICK);
}
this.msPerPixel = (bounds.end - bounds.start) / this.width;
},
setViewFromTimeSystem(timeSystem) {
//The D3 scale used depends on the type of time system as d3
// supports UTC out of the box.
if (timeSystem.isUTCBased) {
this.xScale = d3Scale.scaleUtc();
} else {
this.xScale = d3Scale.scaleLinear();
}
this.xAxis.scale(this.xScale);
this.xAxis.tickFormat(utcMultiTimeFormat);
this.axisElement.call(this.xAxis);
this.setScale();
},
getActiveFormatter() {
let timeSystem = this.openmct.time.timeSystem();
let isFixed = this.openmct.time.clock() === undefined;
if (isFixed) {
return this.getFormatter(timeSystem.timeFormat);
} else {
return this.getFormatter(timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
}
},
getFormatter(key) {
return this.openmct.telemetry.getValueFormatter({
format: key
}).formatter;
},
dragStart($event) {
let isFixed = this.openmct.time.clock() === undefined;
if (isFixed) {
this.dragStartX = $event.clientX;
document.addEventListener('mousemove', this.drag);
document.addEventListener('mouseup', this.dragEnd, {
once: true
});
}
},
drag($event) {
if (!this.dragging) {
this.dragging = true;
requestAnimationFrame(()=>{
let deltaX = $event.clientX - this.dragStartX;
let percX = deltaX / this.width;
let bounds = this.openmct.time.bounds();
let deltaTime = bounds.end - bounds.start;
let newStart = bounds.start - percX * deltaTime;
this.$emit('panAxis',{
start: newStart,
end: newStart + deltaTime
});
this.dragging = false;
})
} else {
console.log('Rejected drag due to RAF cap');
}
},
dragEnd() {
document.removeEventListener('mousemove', this.drag);
this.openmct.time.bounds({
start: this.bounds.start,
end: this.bounds.end
});
},
resize() {
if (this.$refs.axisHolder.clientWidth !== this.width) {
this.width = this.$refs.axisHolder.clientWidth;
this.setScale();
}
}
}
}

View File

@ -20,33 +20,43 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up">
<button class="c-button--menu c-mode-button"
@click.prevent="toggle">
<span class="c-button__label">{{selectedMode.name}}</span>
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up">
<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}}
>
{{ 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>
</template>
<style lang="scss">
@ -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,10 +20,10 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="c-clock-symbol">
<div class="c-clock-symbol">
<div class="hand-little"></div>
<div class="hand-big"></div>
</div>
</div>
</template>
<style lang="scss">

View File

@ -20,24 +20,33 @@
* 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">
<span class="c-button__label">{{selectedTimeSystem.name}}</span>
@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">
{{timeSystem.name}}
:class="timeSystem.cssClass"
@click="setTimeSystemFromView(timeSystem)"
>
{{ timeSystem.name }}
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
@ -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,41 +20,68 @@
* 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>
</div>
</div>
</div>
</template>
<style lang="scss">
@ -166,7 +193,7 @@ const TIME_NAMES = {
'hours': "Hour",
'minutes': "Minute",
'seconds': "Second"
};
};
const MONTHS = moment.months();
const TIME_OPTIONS = (function makeRanges() {
let arr = [];
@ -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

@ -1,7 +1,7 @@
<template>
<div class="l-iframe abs">
<div class="l-iframe abs">
<iframe :src="currentDomainObject.url"></iframe>
</div>
</div>
</template>
<script>

View File

@ -20,34 +20,40 @@
* 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>
</div>
:object-path="objectPath"
/>
</div>
</template>
<style lang="scss">
@ -131,30 +137,46 @@
</style>
<script>
import ObjectView from './ObjectView.vue'
import ContextMenuDropDown from './contextMenuDropDown.vue';
import ObjectView from './ObjectView.vue'
import ContextMenuDropDown from './contextMenuDropDown.vue';
const SIMPLE_CONTENT_TYPES = [
const SIMPLE_CONTENT_TYPES = [
'clock',
'timer',
'summary-widget',
'hyperlink'
];
];
export default {
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,15 +84,24 @@ 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()){
if (this.openmct.editor.isEditing()) {
event.preventDefault();
this.preview();
}
},
preview() {
if (this.previewAction.appliesTo(this.objectPath)){
if (this.previewAction.appliesTo(this.objectPath)) {
this.previewAction.invoke(this.objectPath);
}
},

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,17 +1,20 @@
<template>
<div class="c-progress-bar">
<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}%;`">
</div>
</div>
<div class="c-progress-bar__text"
v-if="model.progressText !== undefined">
<span v-if="model.progressPerc > 0">{{model.progressPerc}}% complete.</span>
{{model.progressText}}
:style="styleBarWidth"
></div>
</div>
<div
v-if="model.progressText !== undefined"
class="c-progress-bar__text"
>
<span v-if="model.progressPerc > 0">{{ model.progressPerc }}% complete.</span>
{{ model.progressText }}
</div>
</div>
</template>
<style lang="scss">
@ -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,11 +1,13 @@
<template>
<label class="c-toggle-switch">
<input type="checkbox"
<label class="c-toggle-switch">
<input
:id="id"
type="checkbox"
:checked="checked"
@change="onUserSelect($event)"/>
@change="onUserSelect($event)"
>
<span class="c-toggle-switch__slider"></span>
</label>
</label>
</template>
<style lang="scss">
@ -63,10 +65,13 @@
</style>
<script>
export default {
export default {
inject: ['openmct'],
props: {
id: String,
id: {
type: String,
required: true
},
checked: Boolean
},
methods: {
@ -74,5 +79,5 @@
this.$emit('change', event.target.checked);
}
}
}
}
</script>

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,15 +1,21 @@
<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>
</div>
:value="value"
v-on="inputListeners"
>
<a
class="c-search__clear-input icon-x-in-circle"
@click="clearInput"
></a>
</div>
</template>
<style lang="scss">
@ -44,11 +50,19 @@
</style>
<script>
/* Emits input and clear events */
export default {
/* Emits input and clear events */
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
@ -76,5 +85,5 @@
this.active = false;
}
}
}
}
</script>

View File

@ -1,14 +1,16 @@
<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>
export default {
export default {
props: {
value: {
type: Boolean,
@ -21,5 +23,5 @@
default: false
}
}
}
}
</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>
@ -89,12 +109,23 @@ export default {
},
mounted() {
let selection = this.openmct.selection.get();
if (selection && selection.length > 0){
if (selection && selection.length > 0) {
this.showSelection(selection);
}
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;
@ -168,7 +199,7 @@ export default {
moveTo(moveToIndex) {
this.composition.reorder(this.moveFromIndex, moveToIndex);
},
moveFrom(index){
moveFrom(index) {
this.isDragging = true;
this.moveFromIndex = index;
document.addEventListener('dragend', this.hideDragStyling);
@ -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,17 +1,22 @@
<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>
</multipane>
</template>
<style lang="scss">
@ -174,18 +179,15 @@
</style>
<script>
import multipane from '../layout/multipane.vue';
import pane from '../layout/pane.vue';
import Elements from './Elements.vue';
import Location from './Location.vue';
import Properties from './Properties.vue';
import InspectorViews from './InspectorViews.vue';
import multipane from '../layout/multipane.vue';
import pane from '../layout/pane.vue';
import Elements from './Elements.vue';
import Location from './Location.vue';
import Properties from './Properties.vue';
import InspectorViews from './InspectorViews.vue';
export default {
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 {
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;
@ -42,5 +39,5 @@ import _ from 'lodash';
});
}
}
}
}
</script>

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,22 +1,34 @@
<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>
<h2>Version Information</h2>
<ul class="t-info l-info s-info">
<li>Version: {{buildInfo.version || 'Unknown'}}</li>
<li>Build Date: {{buildInfo.buildDate || 'Unknown'}}</li>
<li>Revision: {{buildInfo.revision || 'Unknown'}}</li>
<li>Branch: {{buildInfo.branch || 'Unknown'}}</li>
<li>Version: {{ buildInfo.version || 'Unknown' }}</li>
<li>Build Date: {{ buildInfo.buildDate || 'Unknown' }}</li>
<li>Revision: {{ buildInfo.revision || 'Unknown' }}</li>
<li>Branch: {{ buildInfo.branch || 'Unknown' }}</li>
</ul>
</div>
</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 {
@ -38,12 +42,12 @@ export default {
inject: ['openmct'],
mounted() {
let branding = this.openmct.branding();
if (branding.smallLogoImage){
if (branding.smallLogoImage) {
this.$refs.aboutLogo.style.backgroundImage = `url('${branding.smallLogoImage}')`
}
},
methods: {
launchAbout(){
launchAbout() {
let vm = new Vue({
provide: {
openmct: this.openmct

View File

@ -1,61 +1,93 @@
<template>
<div class="l-browse-bar">
<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>
</div>
<button
v-if="isEditing"
class="l-browse-bar__actions c-button icon-x"
title="Cancel Editing"
@click="promptUserandCancelEditing()"
></button>
</div>
</div>
</div>
</template>
<script>
@ -63,103 +95,11 @@ import NotebookSnapshot from '../utils/notebook-snapshot';
import ViewSwitcher from './ViewSwitcher.vue';
const PLACEHOLDER_OBJECT = {};
export default {
export default {
inject: ['openmct'],
components: {
ViewSwitcher
},
methods: {
toggleSaveMenu() {
this.showSaveMenu = !this.showSaveMenu;
},
closeViewAndSaveMenu() {
this.showViewMenu = false;
this.showSaveMenu = false;
},
updateName(event) {
if (event.target.innerText !== this.domainObject.name && event.target.innerText.match(/\S/)) {
this.openmct.objects.mutate(this.domainObject, 'name', event.target.innerText);
} else {
event.target.innerText = this.domainObject.name;
}
},
updateNameOnEnterKeyPress (event) {
event.target.blur();
},
setView(view) {
this.viewKey = view.key;
this.openmct.router.updateParams({
view: this.viewKey
});
},
edit() {
this.openmct.editor.edit();
},
promptUserandCancelEditing() {
let dialog = this.openmct.overlays.dialog({
iconClass: 'alert',
message: 'Any unsaved changes will be lost. Are you sure you want to continue?',
buttons: [
{
label: 'Ok',
emphasis: true,
callback: () => {
this.openmct.editor.cancel().then(() => {
//refresh object view
this.openmct.layout.$refs.browseObject.show(this.domainObject, this.viewKey, true);
});
dialog.dismiss();
}
},
{
label: 'Cancel',
callback: () => {
dialog.dismiss();
}
}
]
});
},
promptUserbeforeNavigatingAway(event) {
if(this.openmct.editor.isEditing()) {
event.preventDefault();
event.returnValue = '';
}
},
saveAndFinishEditing() {
let dialog = this.openmct.overlays.progressDialog({
progressPerc: 'unknown',
message: 'Do not navigate away from this page or close this browser tab while this message is displayed.',
iconClass: 'info',
title: 'Saving',
});
return this.openmct.editor.save()
.then(()=> {
dialog.dismiss();
this.openmct.notifications.info('Save successful');
}).catch((error) => {
dialog.dismiss();
this.openmct.notifications.error('Error saving objects');
console.error(error);
});
},
saveAndContinueEditing() {
this.saveAndFinishEditing().then(() => {
this.openmct.editor.edit();
});
},
showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(this.openmct.router.path, event.clientX, event.clientY);
},
snapshot() {
let element = document.getElementsByClassName("l-shell__main-container")[0];
this.notebookSnapshot.capture(this.domainObject, element);
},
goToParent(){
window.location.hash = this.parentUrl;
}
},
data: function () {
return {
showViewMenu: false,
@ -212,6 +152,16 @@ const PLACEHOLDER_OBJECT = {};
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')) {
@ -226,24 +176,105 @@ const PLACEHOLDER_OBJECT = {};
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);
},
methods: {
toggleSaveMenu() {
this.showSaveMenu = !this.showSaveMenu;
},
closeViewAndSaveMenu() {
this.showViewMenu = false;
this.showSaveMenu = false;
},
updateName(event) {
if (event.target.innerText !== this.domainObject.name && event.target.innerText.match(/\S/)) {
this.openmct.objects.mutate(this.domainObject, 'name', event.target.innerText);
} else {
event.target.innerText = this.domainObject.name;
}
},
updateNameOnEnterKeyPress(event) {
event.target.blur();
},
setView(view) {
this.viewKey = view.key;
this.openmct.router.updateParams({
view: this.viewKey
});
},
edit() {
this.openmct.editor.edit();
},
promptUserandCancelEditing() {
let dialog = this.openmct.overlays.dialog({
iconClass: 'alert',
message: 'Any unsaved changes will be lost. Are you sure you want to continue?',
buttons: [
{
label: 'Ok',
emphasis: true,
callback: () => {
this.openmct.editor.cancel().then(() => {
//refresh object view
this.openmct.layout.$refs.browseObject.show(this.domainObject, this.viewKey, true);
});
dialog.dismiss();
}
},
{
label: 'Cancel',
callback: () => {
dialog.dismiss();
}
}
]
});
},
promptUserbeforeNavigatingAway(event) {
if(this.openmct.editor.isEditing()) {
event.preventDefault();
event.returnValue = '';
}
},
saveAndFinishEditing() {
let dialog = this.openmct.overlays.progressDialog({
progressPerc: 'unknown',
message: 'Do not navigate away from this page or close this browser tab while this message is displayed.',
iconClass: 'info',
title: 'Saving'
});
return this.openmct.editor.save().then(()=> {
dialog.dismiss();
this.openmct.notifications.info('Save successful');
}).catch((error) => {
dialog.dismiss();
this.openmct.notifications.error('Error saving objects');
console.error(error);
});
},
saveAndContinueEditing() {
this.saveAndFinishEditing().then(() => {
this.openmct.editor.edit();
});
},
showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(this.openmct.router.path, event.clientX, event.clientY);
},
snapshot() {
let element = document.getElementsByClassName("l-shell__main-container")[0];
this.notebookSnapshot.capture(this.domainObject, element);
},
goToParent() {
window.location.hash = this.parentUrl;
}
}
}
</script>
<style lang="scss">

View File

@ -1,30 +1,40 @@
<template>
<div class="c-create-button--w">
<button class="c-create-button c-button--menu c-button--major icon-plus"
@click="open">
<div class="c-create-button--w">
<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>
</template>
<style lang="scss">
@ -62,16 +72,51 @@
</style>
<script>
import CreateAction from '../../../platform/commonUI/edit/src/creation/CreateAction';
import objectUtils from '../../api/objects/object-utils';
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 {
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) {
@ -113,51 +158,11 @@
return action.perform();
});
},
convertToLegacy (domainObject) {
convertToLegacy(domainObject) {
let keyString = objectUtils.makeKeyString(domainObject.identifier);
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,60 +1,84 @@
<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>
</div>
</template>
<style lang="scss">
@ -302,20 +326,20 @@
</style>
<script>
import Inspector from '../inspector/Inspector.vue';
import MctTree from './mct-tree.vue';
import ObjectView from '../components/ObjectView.vue';
import MctTemplate from '../legacy/mct-template.vue';
import CreateButton from './CreateButton.vue';
import multipane from './multipane.vue';
import pane from './pane.vue';
import BrowseBar from './BrowseBar.vue';
import Toolbar from '../toolbar/Toolbar.vue';
import AppLogo from './AppLogo.vue';
import Indicators from './status-bar/Indicators.vue';
import NotificationBanner from './status-bar/NotificationBanner.vue';
import Inspector from '../inspector/Inspector.vue';
import MctTree from './mct-tree.vue';
import ObjectView from '../components/ObjectView.vue';
import MctTemplate from '../legacy/mct-template.vue';
import CreateButton from './CreateButton.vue';
import multipane from './multipane.vue';
import pane from './pane.vue';
import BrowseBar from './BrowseBar.vue';
import Toolbar from '../toolbar/Toolbar.vue';
import AppLogo from './AppLogo.vue';
import Indicators from './status-bar/Indicators.vue';
import NotificationBanner from './status-bar/NotificationBanner.vue';
var enterFullScreen = () => {
var enterFullScreen = () => {
var docElm = document.documentElement;
if (docElm.requestFullscreen) {
@ -327,8 +351,8 @@
} else if (docElm.msRequestFullscreen) { /* IE/Edge */
docElm.msRequestFullscreen();
}
};
var exitFullScreen = () => {
};
var exitFullScreen = () => {
if (document.exitFullscreen) {
document.exitFullscreen();
}
@ -341,9 +365,9 @@
else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
}
}
export default {
export default {
inject: ['openmct'],
components: {
Inspector,
@ -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;
@ -423,5 +447,5 @@
this.hasToolbar = structure.length > 0;
}
}
}
}
</script>

View File

@ -1,7 +1,10 @@
<template>
<div class="c-search c-search--major">
<input type="search" placeholder="Search"/>
</div>
<div class="c-search c-search--major">
<input
type="search"
placeholder="Search"
>
</div>
</template>
<style lang="scss">
@ -20,6 +23,6 @@
</style>
<script>
export default {
}
export default {
}
</script>

View File

@ -1,39 +1,60 @@
<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>
</div>
</div>
</div>
</template>
<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,44 +1,56 @@
<template>
<div class="c-tree-and-search">
<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>
</div>
</template>
<style lang="scss">
@ -185,12 +197,12 @@
</style>
<script>
import treeItem from './tree-item.vue'
import search from '../components/search.vue';
import treeItem from './tree-item.vue'
import search from '../components/search.vue';
export default {
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,11 +1,13 @@
<template>
<div class="l-multipane"
<div
class="l-multipane"
:class="{
'l-multipane--vertical': type === 'vertical',
'l-multipane--horizontal': type === 'horizontal'
}">
}"
>
<slot></slot>
</div>
</div>
</template>
<script>
@ -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,22 +9,28 @@
'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>
</div>
</div>
</div>
</template>
<style lang="scss">
@ -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 {
@ -384,7 +395,7 @@ export default {
delete this.dragCollapse;
}
},
trackSize: function() {
trackSize: function () {
if (!this.dragCollapse === true) {
if (this.type === 'vertical') {
this.initial = this.$el.offsetHeight;

View File

@ -17,6 +17,7 @@
at runtime from the About dialog for additional information.
-->
<template>
<div></div>
</template>
<style lang="scss">
@ -152,7 +153,7 @@
</style>
<script>
export default {
export default {
inject: ['openmct'],
mounted() {
@ -160,5 +161,5 @@
this.$el.appendChild(indicator.element);
});
}
}
}
</script>

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>
>
<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>
@ -116,23 +121,22 @@
</style>
<script>
import ProgressBar from '../../components/ProgressBar.vue';
let activeNotification = undefined;
let dialogService = undefined;
let maximizedDialog = undefined;
let minimizeButton = {
import ProgressBar from '../../components/ProgressBar.vue';
let activeNotification = undefined;
let maximizedDialog = undefined;
let minimizeButton = {
label: 'Dismiss',
callback: dismissMaximizedDialog
}
}
function dismissMaximizedDialog() {
function dismissMaximizedDialog() {
if (maximizedDialog) {
maximizedDialog.dismiss();
maximizedDialog = undefined;
}
}
}
function updateMaxProgressBar(progressPerc, progressText) {
function updateMaxProgressBar(progressPerc, progressText) {
if (maximizedDialog) {
maximizedDialog.updateProgress(progressPerc, progressText);
@ -140,9 +144,9 @@
dismissMaximizedDialog();
}
}
}
}
export default {
export default {
inject: ['openmct'],
components: {
ProgressBar: ProgressBar
@ -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,17 +240,7 @@
})
}
}
},
computed: {
progressWidth() {
return {
width: this.activeModel.progress + '%'
};
}
},
mounted() {
this.openmct.notifications.on('notification', this.showNotification);
}
}
}
</script>

View File

@ -1,40 +1,57 @@
<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"
<li class="c-tree__item-h">
<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>
</li>
</template>
<script>
import viewControl from '../components/viewControl.vue';
import ObjectLabel from '../components/ObjectLabel.vue';
import viewControl from '../components/viewControl.vue';
import ObjectLabel from '../components/ObjectLabel.vue';
export default {
name: 'tree-item',
export default {
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,22 +116,8 @@
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) {
addChild(child) {
this.children.push({
id: this.openmct.objects.makeKeyString(child.identifier),
object: child,
@ -113,24 +130,20 @@
this.children = this.children
.filter(c => c.id !== removeId);
},
finishLoading () {
finishLoading() {
this.isLoading = false;
this.loaded = true;
},
buildPathString(parentPath) {
return [parentPath, this.openmct.objects.makeKeyString(this.node.object.identifier)].join('/');
},
highlightIfNavigated(newPath, oldPath){
highlightIfNavigated(newPath, oldPath) {
if (newPath === this.navigateToPath) {
this.isNavigated = true;
} else if (oldPath === this.navigateToPath) {
this.isNavigated = false;
}
}
},
components: {
viewControl,
ObjectLabel
}
}
}
</script>

View File

@ -1,12 +1,15 @@
<template>
<div></div>
<div></div>
</template>
<script>
export default {
inject: ['openmct'],
props: {
templateKey: String
templateKey: {
type: String,
default: undefined
}
},
mounted() {
let openmct = this.openmct;

View File

@ -19,37 +19,40 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="l-preview-window">
<template>
<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>
<div class="l-preview-window__object-view">
<div ref="objectView"></div>
</div>
</div>
</div>
</template>
<style lang="scss">
@import '~styles/sass-base';
@ -83,12 +86,12 @@
}
</style>
<script>
import ContextMenuDropDown from '../../ui/components/contextMenuDropDown.vue';
import ViewSwitcher from '../../ui/layout/ViewSwitcher.vue';
import NotebookSnapshot from '../utils/notebook-snapshot';
<script>
import ContextMenuDropDown from '../../ui/components/contextMenuDropDown.vue';
import ViewSwitcher from '../../ui/layout/ViewSwitcher.vue';
import NotebookSnapshot from '../utils/notebook-snapshot';
export default {
export default {
components: {
ContextMenuDropDown,
ViewSwitcher
@ -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>
}
</script>

View File

@ -1,26 +1,29 @@
<template>
<div class="c-toolbar">
<component v-for="item in structure"
<div class="c-toolbar">
<component
:is="item.control"
v-for="(item, index) in structure"
:key="index"
:options="item"
@click="triggerMethod(item, $event)"
@change="updateObjectValue"></component>
</div>
@change="updateObjectValue"
/>
</div>
</template>
<script>
import toolbarButton from './components/toolbar-button.vue';
import toolbarColorPicker from './components/toolbar-color-picker.vue';
import toolbarCheckbox from './components/toolbar-checkbox.vue';
import toolbarInput from './components/toolbar-input.vue';
import toolbarMenu from './components/toolbar-menu.vue';
import toolbarSelectMenu from './components/toolbar-select-menu.vue';
import toolbarSeparator from './components/toolbar-separator.vue';
import toolbarToggleButton from './components/toolbar-toggle-button.vue';
import toolbarButton from './components/toolbar-button.vue';
import toolbarColorPicker from './components/toolbar-color-picker.vue';
import toolbarCheckbox from './components/toolbar-checkbox.vue';
import toolbarInput from './components/toolbar-input.vue';
import toolbarMenu from './components/toolbar-menu.vue';
import toolbarSelectMenu from './components/toolbar-select-menu.vue';
import toolbarSeparator from './components/toolbar-separator.vue';
import toolbarToggleButton from './components/toolbar-toggle-button.vue';
import _ from 'lodash';
import _ from 'lodash';
export default {
export default {
inject: ['openmct'],
components: {
toolbarButton,
@ -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();
@ -81,7 +92,7 @@
}
},
observeObject(domainObject, id) {
let unobserveObject = this.openmct.objects.observe(domainObject, '*', function(newObject) {
let unobserveObject = this.openmct.objects.observe(domainObject, '*', function (newObject) {
this.domainObjectsById[id].newObject = JSON.parse(JSON.stringify(newObject));
this.updateToolbarAfterMutation();
}.bind(this));
@ -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,18 +261,10 @@
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);
this.removeListeners();
}
}
}
</script>

View File

@ -1,26 +1,33 @@
<template>
<div class="c-ctrl-wrapper">
<div class="c-icon-button"
<div class="c-ctrl-wrapper">
<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>
</div>
</div>
</template>
<script>
export default {
inject: ['openmct'],
props: {
options: Object
options: {
type: Object,
required: true
}
},
computed: {
nonSpecific() {

View File

@ -1,19 +1,21 @@
<template>
<div class="c-custom-checkbox">
<input type="checkbox"
<div class="c-custom-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>
<div class="c-custom-checkbox__label-text">
{{options.name}}
{{ options.name }}
</div>
</label>
</div>
</div>
</template>
<style lang="scss">
@ -72,7 +74,10 @@ let uniqueId = 100;
export default {
props: {
options: Object
options: {
type: Object,
required: true
}
},
data() {
uniqueId++;

View File

@ -1,30 +1,41 @@
<template>
<div class="c-ctrl-wrapper">
<div class="c-icon-button c-icon-button--swatched"
<div class="c-ctrl-wrapper">
<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>
</div>
</div>
</div>
</div>
</template>
<script>
@ -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,14 +1,18 @@
<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"/>
</div>
v-bind="options.attrs"
>
</div>
</template>
<script>
@ -19,6 +23,7 @@ export default {
props: {
options: {
type: Object,
required: true,
validator(value) {
return ['number', 'text'].indexOf(value.type) !== -1;
}

View File

@ -1,24 +1,34 @@
<template>
<div class="c-ctrl-wrapper">
<div class="c-icon-button c-icon-button--menu"
<div class="c-ctrl-wrapper">
<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>
</div>
</div>
</div>
</template>
<script>
@ -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,21 +1,30 @@
<template>
<div class="c-ctrl-wrapper">
<div class="c-icon-button c-icon-button--menu"
<div class="c-ctrl-wrapper">
<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>
</div>
</div>
</div>
</template>
<script>
@ -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

@ -1,11 +1,14 @@
<template>
<div class="c-toolbar__separator"></div>
<div class="c-toolbar__separator"></div>
</template>
<script>
export default {
props: {
options: Object
options: {
type: Object,
required: true
}
}
}
</script>

View File

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