mirror of
https://github.com/nasa/openmct.git
synced 2025-04-16 07:26:53 +00:00
TCR fixes 2 (#2286)
* prevent default on dragover in dropHint, to allow drop event to fire * add notebook snapshot to preview * fix for preview image overlay * pin fast-sass-loader version to 1.4.6 * fix saveAs in plot image export * fix elements search in inspector * fix current Search error * fix anonymous render error in layout * navigate and edit on create * remove domainObjects from composition when deleting frames and containers, and also fix a bug whereby a user can add domainObject via drag and drop(composition) but because of the lack of containers, it will not be added to the flexible layout * fix index undefined error when reordering containers * throw an error when user cancels instead of returning false * fixes for toolbar not updating on selection change * fix errors when objects without context are returned by the search aggregator * prompt user before cancelling edit * check transactions before prompting user * add save and continue editing option to save menu * prompt user if in edit mode and is navigating away
This commit is contained in:
parent
1c8f23dea1
commit
402062110d
@ -92,16 +92,7 @@ function (
|
||||
* @memberof platform/commonUI/edit.SaveAction#
|
||||
*/
|
||||
SaveAsAction.prototype.perform = function () {
|
||||
// Discard the current root view (which will be the editing
|
||||
// UI, which will have been pushed atop the Browse UI.)
|
||||
function returnToBrowse(object) {
|
||||
if (object) {
|
||||
object.getCapability("action").perform("navigate");
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
return this.save().then(returnToBrowse);
|
||||
return this.save();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -192,7 +183,7 @@ function (
|
||||
if (reason !== "user canceled") {
|
||||
self.notificationService.error("Save Failed");
|
||||
}
|
||||
return false;
|
||||
throw reason;
|
||||
}
|
||||
|
||||
return getParent(domainObject)
|
||||
|
@ -67,20 +67,29 @@ define(
|
||||
openmct = this.openmct,
|
||||
newObject;
|
||||
|
||||
function onSave() {
|
||||
// openmct.editor.save();
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
openmct.editor.cancel();
|
||||
}
|
||||
|
||||
function navigateAndEdit(object) {
|
||||
let objectPath = object.getCapability('context').getPath(),
|
||||
url = '#/browse/' + objectPath
|
||||
.map(function (o) {
|
||||
return o && openmct.objects.makeKeyString(o.getId())
|
||||
})
|
||||
.join('/');
|
||||
|
||||
window.location.href = url;
|
||||
|
||||
openmct.editor.edit();
|
||||
}
|
||||
|
||||
newModel.type = this.type.getKey();
|
||||
newModel.location = this.parent.getId();
|
||||
newObject = this.parent.useCapability('instantiation', newModel);
|
||||
|
||||
openmct.editor.edit();
|
||||
newObject.getCapability("action").perform("save-as").then(onSave, onCancel);
|
||||
newObject.getCapability("action").perform("save-as").then(navigateAndEdit, onCancel);
|
||||
// TODO: support editing object without saving object first.
|
||||
// Which means we have to toggle createwizard afterwards. For now,
|
||||
// We will disable this.
|
||||
|
@ -29,12 +29,13 @@ define(
|
||||
function SnapshotPreviewController($scope, openmct) {
|
||||
|
||||
$scope.previewImage = function (imageUrl) {
|
||||
let image = document.createElement('img');
|
||||
image.src = imageUrl;
|
||||
let imageDiv = document.createElement('div');
|
||||
imageDiv.classList = 'image-main s-image-main';
|
||||
imageDiv.style.backgroundImage = `url(${imageUrl})`;
|
||||
|
||||
let previewImageOverlay = openmct.overlays.overlay(
|
||||
{
|
||||
element: image,
|
||||
element: imageDiv,
|
||||
size: 'large',
|
||||
buttons: [
|
||||
{
|
||||
|
@ -178,8 +178,12 @@ define([
|
||||
* @method remove
|
||||
*/
|
||||
DefaultCompositionProvider.prototype.remove = function (domainObject, childId) {
|
||||
// TODO: this needs to be synchronized via mutation.
|
||||
throw new Error('Default Provider does not implement removal.');
|
||||
let composition = domainObject.composition.filter(function (child) {
|
||||
return !(childId.namespace === child.namespace &&
|
||||
childId.key === child.key);
|
||||
});
|
||||
|
||||
this.publicAPI.objects.mutate(domainObject, 'composition', composition);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -506,9 +506,27 @@ export default {
|
||||
this.persist();
|
||||
},
|
||||
deleteContainer(containerId) {
|
||||
let container = this.containers.filter(c => c.id === containerId)[0];
|
||||
let containerIndex = this.containers.indexOf(container);
|
||||
let container = this.containers.filter(c => c.id === containerId)[0],
|
||||
containerIndex = this.containers.indexOf(container);
|
||||
|
||||
/*
|
||||
remove associated domainObjects from composition
|
||||
*/
|
||||
container.frames.forEach(f => {
|
||||
this.composition.remove({identifier: f.domainObjectIdentifier});
|
||||
});
|
||||
|
||||
this.containers.splice(containerIndex, 1);
|
||||
|
||||
/*
|
||||
add a container when there are no containers in the FL,
|
||||
to prevent user from not being able to add a frame via
|
||||
drag and drop.
|
||||
*/
|
||||
if (this.containers.length === 0) {
|
||||
this.containers.push(new Container(100));
|
||||
}
|
||||
|
||||
sizeToFill(this.containers);
|
||||
this.persist();
|
||||
},
|
||||
@ -548,6 +566,12 @@ export default {
|
||||
.frames
|
||||
.filter((f => f.id === frameId))[0];
|
||||
let frameIndex = container.frames.indexOf(frame);
|
||||
|
||||
/*
|
||||
remove associated domainObject from composition
|
||||
*/
|
||||
this.composition.remove({identifier: frame.domainObjectIdentifier});
|
||||
|
||||
container.frames.splice(frameIndex, 1);
|
||||
sizeToFill(container.frames);
|
||||
this.persist(containerIndex);
|
||||
@ -620,7 +644,7 @@ export default {
|
||||
} else {
|
||||
this.containers.splice(toIndex, 0, container);
|
||||
}
|
||||
this.persist(index);
|
||||
this.persist();
|
||||
},
|
||||
removeChildObject(identifier) {
|
||||
let removeIdentifier = this.openmct.objects.makeKeyString(identifier);
|
||||
|
@ -57,7 +57,7 @@ define([
|
||||
layoutObject: domainObject
|
||||
},
|
||||
el: element,
|
||||
template: '<flexible-layout-component ref="flexibleLayout"></flexible-layout-component>'
|
||||
template: '<flexible-layout-component ref="flexibleLayout" :isEditing="isEditing"></flexible-layout-component>'
|
||||
});
|
||||
},
|
||||
getSelectionContext: function () {
|
||||
|
@ -204,7 +204,7 @@ function ToolbarProvider(openmct) {
|
||||
addContainer,
|
||||
toggleFrame ? separator: undefined,
|
||||
toggleFrame,
|
||||
deleteFrame || deleteContainer ? separator: undefined,
|
||||
deleteFrame || deleteContainer ? separator : undefined,
|
||||
deleteFrame,
|
||||
deleteContainer
|
||||
];
|
||||
|
@ -30,7 +30,7 @@ define(
|
||||
],
|
||||
function (
|
||||
html2canvas,
|
||||
saveAs
|
||||
{ saveAs }
|
||||
) {
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div class="c-elements-pool">
|
||||
<Search class="c-elements-pool__search" @input="applySearch"></Search>
|
||||
<Search class="c-elements-pool__search"
|
||||
:value="currentSearch"
|
||||
@input="applySearch"
|
||||
@clear="applySearch">
|
||||
</Search>
|
||||
<div class="c-elements-pool__elements">
|
||||
<ul class="tree c-tree c-elements-pool__tree" id="inspector-elements-tree"
|
||||
v-if="elements.length > 0">
|
||||
@ -69,7 +73,8 @@ export default {
|
||||
return {
|
||||
elements: [],
|
||||
isEditing: this.openmct.editor.isEditing(),
|
||||
parentObject: undefined
|
||||
parentObject: undefined,
|
||||
currentSearch: ''
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@ -15,7 +15,7 @@
|
||||
{{ domainObject.name }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="l-browse-bar__context-actions c-disclosure-button" @click="showContextMenu"></div>
|
||||
<div class="l-browse-bar__context-actions c-disclosure-button" @click.prevent.stop="showContextMenu"></div>
|
||||
</div>
|
||||
|
||||
<div class="l-browse-bar__end">
|
||||
@ -24,7 +24,7 @@
|
||||
<button class="c-button--menu"
|
||||
:class="currentView.cssClass"
|
||||
title="Switch view type"
|
||||
@click="toggleViewMenu">
|
||||
@click.stop="toggleViewMenu">
|
||||
<span class="c-button__label">
|
||||
{{ currentView.name }}
|
||||
</span>
|
||||
@ -43,13 +43,32 @@
|
||||
</div>
|
||||
<!-- Action buttons -->
|
||||
<div class="l-browse-bar__actions">
|
||||
<button class="l-browse-bar__actions__edit c-button icon-notebook"
|
||||
<button class="l-browse-bar__actions__notebook-entry c-button icon-notebook"
|
||||
title="New Notebook entry"
|
||||
@click="snapshot()">
|
||||
</button>
|
||||
<button class="l-browse-bar__actions__notebook-entry c-button c-button--major icon-pencil" title="Edit" v-if="isViewEditable & !isEditing" @click="edit()"></button>
|
||||
<button class="l-browse-bar__actions c-button c-button--major icon-save" title="Save and Finish Editing" v-if="isEditing" @click="saveAndFinishEditing()"></button>
|
||||
<button class="l-browse-bar__actions c-button icon-x" title="Cancel Editing" v-if="isEditing" @click="cancelEditing()"></button>
|
||||
<button class="l-browse-bar__actions__edit c-button c-button--major icon-pencil" title="Edit" v-if="isViewEditable & !isEditing" @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">
|
||||
<ul>
|
||||
<li @click="saveAndFinishEditing"
|
||||
class="icon-save"
|
||||
title="Save and Finish Editing">
|
||||
Save and Finish Editing
|
||||
</li>
|
||||
<li @click="saveAndContinueEditing"
|
||||
class="icon-save"
|
||||
title="Save and Continue Editing">
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
@ -62,10 +81,16 @@ const PLACEHOLDER_OBJECT = {};
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
methods: {
|
||||
toggleViewMenu(event) {
|
||||
event.stopPropagation();
|
||||
toggleViewMenu() {
|
||||
this.showViewMenu = !this.showViewMenu;
|
||||
},
|
||||
toggleSaveMenu() {
|
||||
this.showSaveMenu = !this.showSaveMenu;
|
||||
},
|
||||
closeViewAndSaveMenu() {
|
||||
this.showViewMenu = false;
|
||||
this.showSaveMenu = false;
|
||||
},
|
||||
updateName(event) {
|
||||
// TODO: handle isssues with contenteditable text escaping.
|
||||
if (event.target.innerText !== this.domainObject.name) {
|
||||
@ -84,20 +109,48 @@ const PLACEHOLDER_OBJECT = {};
|
||||
edit() {
|
||||
this.openmct.editor.edit();
|
||||
},
|
||||
cancelEditing() {
|
||||
this.openmct.editor.cancel();
|
||||
promptUserandCancelEditing() {
|
||||
let dialog = this.openmct.overlays.dialog({
|
||||
iconClass: 'alert',
|
||||
message: 'Are you sure you want to continue? All unsaved changes will be lost!',
|
||||
buttons: [
|
||||
{
|
||||
label: 'Ok',
|
||||
emphasis: true,
|
||||
callback: () => {
|
||||
this.openmct.editor.cancel();
|
||||
dialog.dismiss();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Cancel',
|
||||
callback: () => {
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
},
|
||||
promptUserbeforeNavigatingAway(event) {
|
||||
if(this.openmct.editor.isEditing()) {
|
||||
event.preventDefault();
|
||||
event.returnValue = '';
|
||||
}
|
||||
},
|
||||
saveAndFinishEditing() {
|
||||
this.openmct.editor.save().then(()=> {
|
||||
return this.openmct.editor.save().then(()=> {
|
||||
this.openmct.notifications.info('Save successful');
|
||||
}).catch((error) => {
|
||||
this.openmct.notifications.error('Error saving objects');
|
||||
console.error(error);
|
||||
});
|
||||
},
|
||||
saveAndContinueEditing() {
|
||||
this.saveAndFinishEditing().then(() => {
|
||||
this.openmct.editor.edit();
|
||||
});
|
||||
},
|
||||
showContextMenu(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.openmct.contextMenu._showContextMenuForObjectPath(this.openmct.router.path, event.clientX, event.clientY);
|
||||
},
|
||||
snapshot() {
|
||||
@ -111,6 +164,7 @@ const PLACEHOLDER_OBJECT = {};
|
||||
data: function () {
|
||||
return {
|
||||
showViewMenu: false,
|
||||
showSaveMenu: false,
|
||||
domainObject: PLACEHOLDER_OBJECT,
|
||||
viewKey: undefined,
|
||||
isEditing: this.openmct.editor.isEditing()
|
||||
@ -161,15 +215,16 @@ const PLACEHOLDER_OBJECT = {};
|
||||
mounted: function () {
|
||||
this.notebookSnapshot = new NotebookSnapshot(this.openmct);
|
||||
|
||||
document.addEventListener('click', () => {
|
||||
if (this.showViewMenu) {
|
||||
this.showViewMenu = false;
|
||||
}
|
||||
});
|
||||
document.addEventListener('click', this.closeViewAndSaveMenu);
|
||||
window.addEventListener('beforeunload', this.promptUserbeforeNavigatingAway);
|
||||
|
||||
this.openmct.editor.on('isEditing', (isEditing) => {
|
||||
this.isEditing = isEditing;
|
||||
});
|
||||
},
|
||||
beforeDestroy: function () {
|
||||
document.removeEventListener('click', this.closeViewAndSaveMenu);
|
||||
window.removeEventListener('click', this.promptUserbeforeNavigatingAway);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -299,26 +299,20 @@
|
||||
this.openmct.editor.on('isEditing', (isEditing)=>{
|
||||
this.isEditing = isEditing;
|
||||
});
|
||||
|
||||
this.openmct.selection.on('change', this.toggleHasToolbar);
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
fullScreen: false,
|
||||
conductorComponent: {},
|
||||
isEditing: false
|
||||
conductorComponent: undefined,
|
||||
isEditing: false,
|
||||
hasToolbar: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
toolbar() {
|
||||
let selection = this.openmct.selection.get();
|
||||
let structure = undefined;
|
||||
|
||||
if (!selection[0]) {
|
||||
structure = [];
|
||||
} else {
|
||||
structure = this.openmct.toolbars.get(selection);
|
||||
}
|
||||
|
||||
return this.isEditing && structure.length > 0;
|
||||
return this.hasToolbar && this.isEditing;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -333,6 +327,17 @@
|
||||
},
|
||||
openInNewTab(event) {
|
||||
window.open(window.location.href);
|
||||
},
|
||||
toggleHasToolbar(selection) {
|
||||
let structure = undefined;
|
||||
|
||||
if (!selection[0]) {
|
||||
structure = [];
|
||||
} else {
|
||||
structure = this.openmct.toolbars.get(selection);
|
||||
}
|
||||
|
||||
this.hasToolbar = structure.length > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -178,15 +178,21 @@
|
||||
getFilteredChildren() {
|
||||
this.searchService.query(this.searchValue).then(children => {
|
||||
this.filteredTreeItems = children.hits.map(child => {
|
||||
let objectPath = child.object.getCapability('context')
|
||||
.getPath().slice(1).map(oldObject => oldObject.useCapability('adapter'))
|
||||
.reverse(),
|
||||
object = child.object.useCapability('adapter');
|
||||
|
||||
let context = child.object.getCapability('context'),
|
||||
object = child.object.useCapability('adapter'),
|
||||
objectPath = [];
|
||||
|
||||
if (context) {
|
||||
objectPath = context.getPath().slice(1)
|
||||
.map(oldObject => oldObject.useCapability('adapter'))
|
||||
.reverse();
|
||||
}
|
||||
|
||||
return {
|
||||
id: this.openmct.objects.makeKeyString(object.identifier),
|
||||
object,
|
||||
objectPath
|
||||
objectPath
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -20,19 +20,31 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
<template>
|
||||
<div class="l-preview-window">
|
||||
<div class="l-preview-window__object-name 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>
|
||||
<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">
|
||||
<span class="l-browse-bar__object-name">
|
||||
{{ domainObject.name }}
|
||||
</span>
|
||||
<context-menu-drop-down :object-path="objectPath"></context-menu-drop-down>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-browse-bar__end">
|
||||
<div class="l-browse-bar__actions">
|
||||
<button class="l-browse-bar__actions__edit c-button icon-notebook"
|
||||
title="New Notebook entry"
|
||||
@click="snapshot">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-preview-window__object-view">
|
||||
<div ref="objectView"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-preview-window__object-view">
|
||||
<div ref="objectView">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
@import '~styles/sass-base';
|
||||
|
||||
@ -63,6 +75,7 @@
|
||||
|
||||
<script>
|
||||
import ContextMenuDropDown from '../../ui/components/contextMenuDropDown.vue';
|
||||
import NotebookSnapshot from '../utils/notebook-snapshot';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -72,6 +85,12 @@
|
||||
'openmct',
|
||||
'objectPath'
|
||||
],
|
||||
methods: {
|
||||
snapshot() {
|
||||
let element = document.getElementsByClassName("l-preview-window__object-view")[0];
|
||||
this.notebookSnapshot.capture(this.domainObject, element);
|
||||
}
|
||||
},
|
||||
data() {
|
||||
let domainObject = this.objectPath[0];
|
||||
let type = this.openmct.types.get(domainObject.type);
|
||||
@ -85,6 +104,7 @@
|
||||
let viewProvider = this.openmct.objectViews.get(this.domainObject)[0];
|
||||
this.view = viewProvider.view(this.domainObject);
|
||||
this.view.show(this.$refs.objectView, false);
|
||||
this.notebookSnapshot = new NotebookSnapshot(this.openmct);
|
||||
},
|
||||
destroy() {
|
||||
this.view.destroy();
|
||||
|
Loading…
x
Reference in New Issue
Block a user