mirror of
https://github.com/nasa/openmct.git
synced 2025-06-23 01:18:57 +00:00
Merge branch 'topic-core-refactor' into misc-ui-8
This commit is contained in:
@ -103,7 +103,7 @@
|
||||
|
||||
&__local-controls {
|
||||
position: absolute;
|
||||
top: 0; right: 0;
|
||||
top: $interiorMargin; right: $interiorMargin;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@
|
||||
}
|
||||
|
||||
&.has-complex-content {
|
||||
.c-so-view__view-large { display: block; }
|
||||
> .c-so-view__view-large { display: block; }
|
||||
}
|
||||
|
||||
/*************************** OBJECT VIEW */
|
||||
|
@ -59,7 +59,8 @@ export default {
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
navigateToPath: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -102,7 +102,8 @@ export default {
|
||||
this.elements = [];
|
||||
this.elementsCache = {};
|
||||
this.listeners = [];
|
||||
this.parentObject = selection[0].context.item;
|
||||
this.parentObject = selection && selection[0] && selection[0][0].context.item;
|
||||
|
||||
if (this.mutationUnobserver) {
|
||||
this.mutationUnobserver();
|
||||
}
|
||||
|
@ -199,8 +199,8 @@
|
||||
},
|
||||
methods: {
|
||||
refreshComposition(selection) {
|
||||
if (selection[0]) {
|
||||
let parentObject = selection[0].context.item;
|
||||
if (selection.length > 0 && selection[0].length > 0) {
|
||||
let parentObject = selection[0][0].context.item;
|
||||
|
||||
this.hasComposition = !!(parentObject && this.openmct.composition.get(parentObject));
|
||||
}
|
||||
|
@ -7,30 +7,44 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
mounted() {
|
||||
this.openmct.selection.on('change', this.updateSelection);
|
||||
this.updateSelection();
|
||||
this.updateSelection(this.openmct.selection.get());
|
||||
},
|
||||
destroyed() {
|
||||
this.openmct.selection.off('change', this.updateSelection);
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selection: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateSelection() {
|
||||
let selection = this.openmct.selection.get();
|
||||
updateSelection(selection) {
|
||||
if (_.isEqual(this.selection, selection)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.selection = selection;
|
||||
|
||||
if (this.selectedViews) {
|
||||
this.selectedViews.forEach(selectedView => {
|
||||
selectedView.destroy();
|
||||
});
|
||||
this.$el.innerHTML = '';
|
||||
}
|
||||
this.viewContainers = [];
|
||||
|
||||
if (selection.length > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedViews = this.openmct.inspectorViews.get(selection);
|
||||
this.selectedViews.forEach(selectedView => {
|
||||
let viewContainer = document.createElement('div');
|
||||
this.viewContainers.push(viewContainer);
|
||||
|
||||
this.$el.append(viewContainer)
|
||||
selectedView.show(viewContainer);
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
<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">
|
||||
<ul class="c-properties__section" v-if="!multiSelect">
|
||||
<li class="c-properties__row" v-if="originalPath.length">
|
||||
<ul class="c-properties__value c-location">
|
||||
<li v-for="pathObject in orderedOriginalPath"
|
||||
@ -15,6 +15,7 @@
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="c-properties__row--span-all" v-if="multiSelect">No location to display for multiple items</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -72,6 +73,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
domainObject: {},
|
||||
multiSelect: false,
|
||||
originalPath: [],
|
||||
keyString: ''
|
||||
}
|
||||
@ -106,16 +108,27 @@ export default {
|
||||
this.keyString = '';
|
||||
},
|
||||
updateSelection(selection) {
|
||||
if (!selection.length) {
|
||||
if (!selection.length || !selection[0].length) {
|
||||
this.clearData();
|
||||
return;
|
||||
} else if (!selection[0].context.item && selection[1] && selection[1].context.item) {
|
||||
this.setOriginalPath([selection[1].context.item], true);
|
||||
}
|
||||
|
||||
if (selection.length > 1) {
|
||||
this.multiSelect = true;
|
||||
return;
|
||||
} else {
|
||||
this.multiSelect = false;
|
||||
}
|
||||
|
||||
this.domainObject = selection[0][0].context.item;
|
||||
let parentObject = selection[0][1];
|
||||
|
||||
if (!this.domainObject && parentObject && parentObject.context.item) {
|
||||
this.setOriginalPath([parentObject.context.item], true);
|
||||
this.keyString = '';
|
||||
return;
|
||||
}
|
||||
|
||||
this.domainObject = selection[0].context.item;
|
||||
|
||||
let keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
|
||||
if (keyString && this.keyString !== keyString) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="c-properties c-properties--properties">
|
||||
<div class="c-properties__header">Properties</div>
|
||||
<ul class="c-properties__section">
|
||||
<ul class="c-properties__section" v-if="!multiSelect">
|
||||
<li class="c-properties__row">
|
||||
<div class="c-properties__label">Title</div>
|
||||
<div class="c-properties__value">{{ item.name }}</div>
|
||||
@ -25,6 +25,7 @@
|
||||
<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>
|
||||
</template>
|
||||
|
||||
@ -35,7 +36,8 @@ export default {
|
||||
inject: ['openmct'],
|
||||
data() {
|
||||
return {
|
||||
domainObject: {}
|
||||
domainObject: {},
|
||||
multiSelect: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -90,11 +92,19 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
updateSelection(selection) {
|
||||
if (selection.length === 0) {
|
||||
if (selection.length === 0 || selection[0].length === 0) {
|
||||
this.domainObject = {};
|
||||
return;
|
||||
}
|
||||
this.domainObject = selection[0].context.item;
|
||||
|
||||
if (selection.length > 1) {
|
||||
this.multiSelect = true;
|
||||
this.domainObject = {};
|
||||
return;
|
||||
} else {
|
||||
this.multiSelect = false;
|
||||
this.domainObject = selection[0][0].context.item;
|
||||
}
|
||||
},
|
||||
formatTime(unixTime) {
|
||||
return Moment.utc(unixTime).format('YYYY-MM-DD[\n]HH:mm:ss') + ' UTC';
|
||||
|
@ -43,7 +43,8 @@
|
||||
</div>
|
||||
<!-- Action buttons -->
|
||||
<div class="l-browse-bar__actions">
|
||||
<button class="l-browse-bar__actions__notebook-entry c-button icon-notebook"
|
||||
<button v-if="notebookEnabled"
|
||||
class="l-browse-bar__actions__notebook-entry c-button icon-notebook"
|
||||
title="New Notebook entry"
|
||||
@click="snapshot()">
|
||||
</button>
|
||||
@ -118,7 +119,10 @@ const PLACEHOLDER_OBJECT = {};
|
||||
label: 'Ok',
|
||||
emphasis: true,
|
||||
callback: () => {
|
||||
this.openmct.editor.cancel();
|
||||
this.openmct.editor.cancel().then(() => {
|
||||
//refresh object view
|
||||
this.openmct.layout.$refs.browseObject.show(this.domainObject, this.viewKey, false);
|
||||
});
|
||||
dialog.dismiss();
|
||||
}
|
||||
},
|
||||
@ -167,7 +171,8 @@ const PLACEHOLDER_OBJECT = {};
|
||||
showSaveMenu: false,
|
||||
domainObject: PLACEHOLDER_OBJECT,
|
||||
viewKey: undefined,
|
||||
isEditing: this.openmct.editor.isEditing()
|
||||
isEditing: this.openmct.editor.isEditing(),
|
||||
notebookEnabled: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -213,7 +218,11 @@ const PLACEHOLDER_OBJECT = {};
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
this.notebookSnapshot = new NotebookSnapshot(this.openmct);
|
||||
|
||||
if (this.openmct.types.get('notebook')) {
|
||||
this.notebookSnapshot = new NotebookSnapshot(this.openmct);
|
||||
this.notebookEnabled = true;
|
||||
}
|
||||
|
||||
document.addEventListener('click', this.closeViewAndSaveMenu);
|
||||
window.addEventListener('beforeunload', this.promptUserbeforeNavigatingAway);
|
||||
@ -222,7 +231,20 @@ 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);
|
||||
}
|
||||
|
@ -348,7 +348,7 @@
|
||||
toggleHasToolbar(selection) {
|
||||
let structure = undefined;
|
||||
|
||||
if (!selection[0]) {
|
||||
if (!selection || !selection[0]) {
|
||||
structure = [];
|
||||
} else {
|
||||
structure = this.openmct.toolbars.get(selection);
|
||||
|
@ -211,7 +211,8 @@
|
||||
return {
|
||||
id: this.openmct.objects.makeKeyString(c.identifier),
|
||||
object: c,
|
||||
objectPath: [c]
|
||||
objectPath: [c],
|
||||
navigateToParent: '/browse'
|
||||
};
|
||||
});
|
||||
});
|
||||
|
@ -7,7 +7,8 @@
|
||||
v-model="expanded">
|
||||
</view-control>
|
||||
<object-label :domainObject="node.object"
|
||||
:objectPath="node.objectPath">
|
||||
:objectPath="node.objectPath"
|
||||
:navigateToPath="navigateToPath">
|
||||
</object-label>
|
||||
</div>
|
||||
<ul v-if="expanded" class="c-tree">
|
||||
@ -36,13 +37,12 @@
|
||||
node: Object
|
||||
},
|
||||
data() {
|
||||
this.pathToObject = this.buildPathString(this.node.objectPath);
|
||||
|
||||
this.navigateToPath = this.buildPathString(this.node.navigateToParent)
|
||||
return {
|
||||
hasChildren: false,
|
||||
isLoading: false,
|
||||
loaded: false,
|
||||
isNavigated: this.pathToObject === this.openmct.router.currentLocation.path,
|
||||
isNavigated: this.navigateToPath === this.openmct.router.currentLocation.path,
|
||||
children: [],
|
||||
expanded: false
|
||||
}
|
||||
@ -103,7 +103,8 @@
|
||||
this.children.push({
|
||||
id: this.openmct.objects.makeKeyString(child.identifier),
|
||||
object: child,
|
||||
objectPath: [child].concat(this.node.objectPath)
|
||||
objectPath: [child].concat(this.node.objectPath),
|
||||
navigateToParent: this.navigateToPath
|
||||
});
|
||||
},
|
||||
removeChild(identifier) {
|
||||
@ -115,15 +116,13 @@
|
||||
this.isLoading = false;
|
||||
this.loaded = true;
|
||||
},
|
||||
buildPathString(path) {
|
||||
return '/browse/' + path.map(o => o && this.openmct.objects.makeKeyString(o.identifier))
|
||||
.reverse()
|
||||
.join('/');
|
||||
buildPathString(parentPath) {
|
||||
return [parentPath, this.openmct.objects.makeKeyString(this.node.object.identifier)].join('/');
|
||||
},
|
||||
highlightIfNavigated(newPath, oldPath){
|
||||
if (newPath === this.pathToObject) {
|
||||
if (newPath === this.navigateToPath) {
|
||||
this.isNavigated = true;
|
||||
} else if (oldPath === this.pathToObject) {
|
||||
} else if (oldPath === this.navigateToPath) {
|
||||
this.isNavigated = false;
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,9 @@ export default {
|
||||
if (!this.objectPath.length) {
|
||||
return;
|
||||
}
|
||||
if (this.navigateToPath) {
|
||||
return '#' + this.navigateToPath;
|
||||
}
|
||||
return '#/browse/' + this.objectPath
|
||||
.map(o => o && this.openmct.objects.makeKeyString(o.identifier))
|
||||
.reverse()
|
||||
|
@ -42,14 +42,13 @@
|
||||
this.removeListeners();
|
||||
this.domainObjectsById = {};
|
||||
|
||||
if (!selection[0]) {
|
||||
if (selection.length === 0 || !selection[0][0]) {
|
||||
this.structure = [];
|
||||
return;
|
||||
}
|
||||
|
||||
let structure = this.openmct.toolbars.get(selection) || [];
|
||||
this.structure = structure.map(item => {
|
||||
let toolbarItem = {...item};
|
||||
this.structure = structure.map(toolbarItem => {
|
||||
let domainObject = toolbarItem.domainObject;
|
||||
let formKeys = [];
|
||||
toolbarItem.control = "toolbar-" + toolbarItem.control;
|
||||
@ -64,12 +63,7 @@
|
||||
}
|
||||
|
||||
if (domainObject) {
|
||||
if (formKeys.length > 0) {
|
||||
toolbarItem.value = this.getFormValue(domainObject, toolbarItem);
|
||||
} else {
|
||||
toolbarItem.value = _.get(domainObject, this.getItemProperty(item));
|
||||
}
|
||||
|
||||
toolbarItem.value = this.getValue(domainObject, toolbarItem);
|
||||
this.registerListener(domainObject);
|
||||
}
|
||||
|
||||
@ -89,21 +83,12 @@
|
||||
observeObject(domainObject, id) {
|
||||
let unobserveObject = this.openmct.objects.observe(domainObject, '*', function(newObject) {
|
||||
this.domainObjectsById[id].newObject = JSON.parse(JSON.stringify(newObject));
|
||||
this.scheduleToolbarUpdate();
|
||||
this.updateToolbarAfterMutation();
|
||||
}.bind(this));
|
||||
this.unObserveObjects.push(unobserveObject);
|
||||
},
|
||||
scheduleToolbarUpdate() {
|
||||
if (this.toolbarUpdateScheduled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.toolbarUpdateScheduled = true;
|
||||
setTimeout(this.updateToolbarAfterMutation.bind(this));
|
||||
},
|
||||
updateToolbarAfterMutation() {
|
||||
this.structure = this.structure.map(item => {
|
||||
let toolbarItem = {...item};
|
||||
this.structure = this.structure.map(toolbarItem => {
|
||||
let domainObject = toolbarItem.domainObject;
|
||||
|
||||
if (domainObject) {
|
||||
@ -112,12 +97,7 @@
|
||||
|
||||
if (newObject) {
|
||||
toolbarItem.domainObject = newObject;
|
||||
|
||||
if (toolbarItem.formKeys) {
|
||||
toolbarItem.value = this.getFormValue(newObject, toolbarItem);
|
||||
} else {
|
||||
toolbarItem.value = _.get(newObject, this.getItemProperty(item));
|
||||
}
|
||||
toolbarItem.value = this.getValue(newObject, toolbarItem);
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,17 +110,58 @@
|
||||
delete tracker.newObject;
|
||||
}
|
||||
});
|
||||
this.toolbarUpdateScheduled = false;
|
||||
},
|
||||
getValue(domainObject, toolbarItem) {
|
||||
let value = undefined;
|
||||
let applicableSelectedItems = toolbarItem.applicableSelectedItems;
|
||||
|
||||
if (!applicableSelectedItems) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (toolbarItem.formKeys) {
|
||||
value = this.getFormValue(domainObject, toolbarItem);
|
||||
} else {
|
||||
let values = [];
|
||||
applicableSelectedItems.forEach(selectionPath => {
|
||||
values.push(_.get(domainObject, this.getItemProperty(toolbarItem, selectionPath)));
|
||||
});
|
||||
|
||||
// If all values are the same, use it, otherwise mark the item as non-specific.
|
||||
if (values.every(value => value === values[0])) {
|
||||
value = values[0];
|
||||
toolbarItem.nonSpecific = false;
|
||||
} else {
|
||||
toolbarItem.nonSpecific = true;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
getFormValue(domainObject, toolbarItem) {
|
||||
let value = {};
|
||||
let values = {};
|
||||
toolbarItem.formKeys.map(key => {
|
||||
value[key] = _.get(domainObject, this.getItemProperty(toolbarItem) + "." + key);
|
||||
values[key] = [];
|
||||
toolbarItem.applicableSelectedItems.forEach(selectionPath => {
|
||||
values[key].push(_.get(domainObject, this.getItemProperty(toolbarItem, selectionPath) + "." + key));
|
||||
});
|
||||
});
|
||||
|
||||
for (const key in values) {
|
||||
if (values[key].every(value => value === values[key][0])) {
|
||||
value[key] = values[key][0];
|
||||
toolbarItem.nonSpecific = false;
|
||||
} else {
|
||||
toolbarItem.nonSpecific = true;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
getItemProperty(item) {
|
||||
return (typeof item.property === "function") ? item.property() : item.property;
|
||||
getItemProperty(item, selectionPath) {
|
||||
return (typeof item.property === "function") ? item.property(selectionPath) : item.property;
|
||||
},
|
||||
removeListeners() {
|
||||
if (this.unObserveObjects) {
|
||||
@ -152,14 +173,12 @@
|
||||
},
|
||||
updateObjectValue(value, item) {
|
||||
let changedItemId = this.openmct.objects.makeKeyString(item.domainObject.identifier);
|
||||
this.structure = this.structure.map((s) => {
|
||||
let toolbarItem = {...s};
|
||||
let domainObject = toolbarItem.domainObject;
|
||||
|
||||
if (domainObject) {
|
||||
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||
this.structure = this.structure.map(toolbarItem => {
|
||||
if (toolbarItem.domainObject) {
|
||||
let id = this.openmct.objects.makeKeyString(toolbarItem.domainObject.identifier);
|
||||
|
||||
if (changedItemId === id && this.getItemProperty(item) === this.getItemProperty(s)) {
|
||||
if (changedItemId === id && _.isEqual(toolbarItem, item)) {
|
||||
toolbarItem.value = value;
|
||||
}
|
||||
}
|
||||
@ -173,12 +192,17 @@
|
||||
this.structure.map(s => {
|
||||
if (s.formKeys) {
|
||||
s.formKeys.forEach(key => {
|
||||
this.openmct.objects.mutate(item.domainObject, this.getItemProperty(item) + "." + key, value[key]);
|
||||
item.applicableSelectedItems.forEach(selectionPath => {
|
||||
this.openmct.objects.mutate(item.domainObject,
|
||||
this.getItemProperty(item, selectionPath) + "." + key, value[key]);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.openmct.objects.mutate(item.domainObject, this.getItemProperty(item), value);
|
||||
item.applicableSelectedItems.forEach(selectionPath => {
|
||||
this.openmct.objects.mutate(item.domainObject, this.getItemProperty(item, selectionPath), value);
|
||||
});
|
||||
}
|
||||
},
|
||||
triggerMethod(item, event) {
|
||||
|
@ -4,14 +4,14 @@
|
||||
:title="options.title"
|
||||
:class="{
|
||||
[options.icon]: true,
|
||||
'c-icon-button--caution': options.modifier === 'caution'
|
||||
'c-icon-button--caution': options.modifier === 'caution',
|
||||
'c-icon-button--mixed': nonSpecific
|
||||
}"
|
||||
@click="onClick">
|
||||
<div class="c-icon-button__label"
|
||||
v-if="options.label">
|
||||
{{ options.label }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -22,6 +22,11 @@ export default {
|
||||
props: {
|
||||
options: Object
|
||||
},
|
||||
computed: {
|
||||
nonSpecific() {
|
||||
return this.options.nonSpecific === true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick(event) {
|
||||
if (this.options.dialog) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="c-ctrl-wrapper">
|
||||
<div class="c-icon-button c-icon-button--swatched"
|
||||
:class="options.icon"
|
||||
:class="[options.icon, {'c-icon-button--mixed': nonSpecific}]"
|
||||
:title="options.title"
|
||||
@click="toggle">
|
||||
<div class="c-swatch" :style="{
|
||||
@ -36,6 +36,11 @@ export default {
|
||||
props: {
|
||||
options: Object
|
||||
},
|
||||
computed: {
|
||||
nonSpecific() {
|
||||
return this.options.nonSpecific === true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
select(color) {
|
||||
if (color.value !== this.options.value) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="c-ctrl-wrapper">
|
||||
<div class="c-icon-button c-icon-button--menu"
|
||||
:class="options.icon"
|
||||
:class="[options.icon, {'c-click-icon--mixed': nonSpecific}]"
|
||||
:title="options.title"
|
||||
@click="toggle">
|
||||
<div class="c-button__label">{{ selectedName }}</div>
|
||||
@ -47,7 +47,11 @@ export default {
|
||||
if (selectedOption) {
|
||||
return selectedOption.name || selectedOption.value
|
||||
}
|
||||
return '';
|
||||
// If no selected option, then options are non-specific
|
||||
return '??px';
|
||||
},
|
||||
nonSpecific() {
|
||||
return this.options.nonSpecific === true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div class="c-ctrl-wrapper">
|
||||
<div class="c-icon-button"
|
||||
:title="nextValue.title"
|
||||
:class="nextValue.icon"
|
||||
:class="[nextValue.icon, {'c-click-icon--mixed': nonSpecific}]"
|
||||
@click="cycle">
|
||||
</div>
|
||||
</div>
|
||||
@ -23,6 +23,9 @@ export default {
|
||||
nextIndex = 0;
|
||||
}
|
||||
return this.options.options[nextIndex];
|
||||
},
|
||||
nonSpecific() {
|
||||
return this.options.nonSpecific === true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
Reference in New Issue
Block a user