mirror of
https://github.com/nasa/openmct.git
synced 2025-06-18 23:28:14 +00:00
Added editing support to the View API (#2279)
* Added edit to view API * Fixed listener deregistration bug
This commit is contained in:
committed by
Pegah Sarram
parent
d0ab59f9da
commit
853764d863
@ -39,6 +39,7 @@ export default class Editor extends EventEmitter {
|
|||||||
* Initiate an editing session. This will start a transaction during
|
* Initiate an editing session. This will start a transaction during
|
||||||
* which any persist operations will be deferred until either save()
|
* which any persist operations will be deferred until either save()
|
||||||
* or finish() are called.
|
* or finish() are called.
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
edit() {
|
edit() {
|
||||||
if (this.editing === true) {
|
if (this.editing === true) {
|
||||||
@ -59,6 +60,8 @@ export default class Editor extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* Save any unsaved changes from this editing session. This will
|
* Save any unsaved changes from this editing session. This will
|
||||||
* end the current transaction.
|
* end the current transaction.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
save() {
|
save() {
|
||||||
return this.getTransactionService().commit().then((result)=>{
|
return this.getTransactionService().commit().then((result)=>{
|
||||||
@ -72,6 +75,8 @@ export default class Editor extends EventEmitter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* End the currently active transaction and discard unsaved changes.
|
* End the currently active transaction and discard unsaved changes.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
cancel() {
|
cancel() {
|
||||||
this.getTransactionService().cancel();
|
this.getTransactionService().cancel();
|
||||||
|
@ -47,7 +47,8 @@
|
|||||||
:key="frame.id"
|
:key="frame.id"
|
||||||
:frame="frame"
|
:frame="frame"
|
||||||
:index="i"
|
:index="i"
|
||||||
:containerIndex="index">
|
:containerIndex="index"
|
||||||
|
:isEditing="isEditing">
|
||||||
</frame-component>
|
</frame-component>
|
||||||
|
|
||||||
<drop-hint
|
<drop-hint
|
||||||
@ -65,7 +66,8 @@
|
|||||||
:orientation="rowsLayout ? 'horizontal' : 'vertical'"
|
:orientation="rowsLayout ? 'horizontal' : 'vertical'"
|
||||||
@init-move="startFrameResizing"
|
@init-move="startFrameResizing"
|
||||||
@move="frameResizing"
|
@move="frameResizing"
|
||||||
@end-move="endFrameResizing">
|
@end-move="endFrameResizing"
|
||||||
|
:isEditing="isEditing">
|
||||||
</resize-handle>
|
</resize-handle>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@ -77,14 +79,12 @@ import FrameComponent from './frame.vue';
|
|||||||
import Frame from '../utils/frame';
|
import Frame from '../utils/frame';
|
||||||
import ResizeHandle from './resizeHandle.vue';
|
import ResizeHandle from './resizeHandle.vue';
|
||||||
import DropHint from './dropHint.vue';
|
import DropHint from './dropHint.vue';
|
||||||
import isEditingMixin from '../mixins/isEditing';
|
|
||||||
|
|
||||||
const MIN_FRAME_SIZE = 5;
|
const MIN_FRAME_SIZE = 5;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject:['openmct'],
|
inject:['openmct'],
|
||||||
props: ['container', 'index', 'rowsLayout'],
|
props: ['container', 'index', 'rowsLayout', 'isEditing'],
|
||||||
mixins: [isEditingMixin],
|
|
||||||
components: {
|
components: {
|
||||||
FrameComponent,
|
FrameComponent,
|
||||||
ResizeHandle,
|
ResizeHandle,
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
:index="index"
|
:index="index"
|
||||||
:container="container"
|
:container="container"
|
||||||
:rowsLayout="rowsLayout"
|
:rowsLayout="rowsLayout"
|
||||||
|
:isEditing="isEditing"
|
||||||
@move-frame="moveFrame"
|
@move-frame="moveFrame"
|
||||||
@new-frame="setFrameLocation"
|
@new-frame="setFrameLocation"
|
||||||
@persist="persist">
|
@persist="persist">
|
||||||
@ -64,6 +65,7 @@
|
|||||||
:key="index"
|
:key="index"
|
||||||
:index="index"
|
:index="index"
|
||||||
:orientation="rowsLayout ? 'vertical' : 'horizontal'"
|
:orientation="rowsLayout ? 'vertical' : 'horizontal'"
|
||||||
|
:isEditing="isEditing"
|
||||||
@init-move="startContainerResizing"
|
@init-move="startContainerResizing"
|
||||||
@move="containerResizing"
|
@move="containerResizing"
|
||||||
@end-move="endContainerResizing">
|
@end-move="endContainerResizing">
|
||||||
@ -420,7 +422,6 @@ import Container from '../utils/container';
|
|||||||
import Frame from '../utils/frame';
|
import Frame from '../utils/frame';
|
||||||
import ResizeHandle from './resizeHandle.vue';
|
import ResizeHandle from './resizeHandle.vue';
|
||||||
import DropHint from './dropHint.vue';
|
import DropHint from './dropHint.vue';
|
||||||
import isEditingMixin from '../mixins/isEditing';
|
|
||||||
|
|
||||||
const MIN_CONTAINER_SIZE = 5;
|
const MIN_CONTAINER_SIZE = 5;
|
||||||
|
|
||||||
@ -465,7 +466,6 @@ function sizeToFill(items) {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct', 'layoutObject'],
|
inject: ['openmct', 'layoutObject'],
|
||||||
mixins: [isEditingMixin],
|
|
||||||
components: {
|
components: {
|
||||||
ContainerComponent,
|
ContainerComponent,
|
||||||
ResizeHandle,
|
ResizeHandle,
|
||||||
@ -477,6 +477,9 @@ export default {
|
|||||||
newFrameLocation: []
|
newFrameLocation: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
props: {
|
||||||
|
isEditing: Boolean
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
layoutDirectionStr() {
|
layoutDirectionStr() {
|
||||||
if (this.rowsLayout) {
|
if (this.rowsLayout) {
|
||||||
|
@ -51,12 +51,10 @@
|
|||||||
<script>
|
<script>
|
||||||
import ResizeHandle from './resizeHandle.vue';
|
import ResizeHandle from './resizeHandle.vue';
|
||||||
import ObjectFrame from '../../../ui/components/ObjectFrame.vue';
|
import ObjectFrame from '../../../ui/components/ObjectFrame.vue';
|
||||||
import isEditingMixin from '../mixins/isEditing';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
props: ['frame', 'index', 'containerIndex'],
|
props: ['frame', 'index', 'containerIndex', 'isEditing'],
|
||||||
mixins: [isEditingMixin],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
domainObject: undefined,
|
domainObject: undefined,
|
||||||
|
@ -29,11 +29,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import isEditingMixin from '../mixins/isEditing';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['orientation', 'index'],
|
props: ['orientation', 'index', 'isEditing'],
|
||||||
mixins: [isEditingMixin],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
initialPos: 0,
|
initialPos: 0,
|
||||||
|
@ -42,8 +42,13 @@ define([
|
|||||||
let component;
|
let component;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
show: function (element) {
|
show: function (element, isEditing) {
|
||||||
component = new Vue({
|
component = new Vue({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isEditing: isEditing
|
||||||
|
}
|
||||||
|
},
|
||||||
components: {
|
components: {
|
||||||
FlexibleLayoutComponent: FlexibleLayoutComponent.default
|
FlexibleLayoutComponent: FlexibleLayoutComponent.default
|
||||||
},
|
},
|
||||||
@ -64,6 +69,9 @@ define([
|
|||||||
type: 'flexible-layout'
|
type: 'flexible-layout'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
onEditModeChange: function (isEditing) {
|
||||||
|
component.isEditing = isEditing;
|
||||||
|
},
|
||||||
destroy: function (element) {
|
destroy: function (element) {
|
||||||
component.$destroy();
|
component.$destroy();
|
||||||
component = undefined;
|
component = undefined;
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
export default {
|
|
||||||
inject: ['openmct'],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
isEditing: this.openmct.editor.isEditing()
|
|
||||||
};
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.openmct.editor.on('isEditing', this.toggleEditing);
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
this.openmct.editor.off('isEditing', this.toggleEditing);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
toggleEditing(value) {
|
|
||||||
this.isEditing = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
@ -24,16 +24,10 @@ define([
|
|||||||
return domainObject.type === 'summary-widget';
|
return domainObject.type === 'summary-widget';
|
||||||
},
|
},
|
||||||
view: function (domainObject) {
|
view: function (domainObject) {
|
||||||
var statusService = openmct.$injector.get('statusService');
|
|
||||||
var objectId = objectUtils.makeKeyString(domainObject.identifier);
|
|
||||||
var statuses = statusService.listStatuses(objectId);
|
|
||||||
var isEditing = statuses.indexOf('editing') !== -1;
|
|
||||||
|
|
||||||
if (isEditing) {
|
|
||||||
return new SummaryWidgetEditView(domainObject, openmct);
|
|
||||||
} else {
|
|
||||||
return new SummaryWidgetView(domainObject, openmct);
|
return new SummaryWidgetView(domainObject, openmct);
|
||||||
}
|
},
|
||||||
|
edit: function (domainObject) {
|
||||||
|
return new SummaryWidgetEditView(domainObject, openmct);
|
||||||
},
|
},
|
||||||
priority: function (domainObject) {
|
priority: function (domainObject) {
|
||||||
if (domainObject.type === 'summary-widget') {
|
if (domainObject.type === 'summary-widget') {
|
||||||
|
@ -47,8 +47,13 @@ define([
|
|||||||
let table = new TelemetryTable(domainObject, openmct);
|
let table = new TelemetryTable(domainObject, openmct);
|
||||||
let component;
|
let component;
|
||||||
return {
|
return {
|
||||||
show: function (element) {
|
show: function (element, isEditing) {
|
||||||
component = new Vue({
|
component = new Vue({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isEditing: false
|
||||||
|
}
|
||||||
|
},
|
||||||
components: {
|
components: {
|
||||||
TableComponent: TableComponent.default,
|
TableComponent: TableComponent.default,
|
||||||
},
|
},
|
||||||
@ -58,9 +63,12 @@ define([
|
|||||||
table
|
table
|
||||||
},
|
},
|
||||||
el: element,
|
el: element,
|
||||||
template: '<table-component></table-component>'
|
template: '<table-component :isEditing="isEditing"></table-component>'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
onEditModeChange(isEditing) {
|
||||||
|
component.isEditing = isEditing;
|
||||||
|
},
|
||||||
destroy: function (element) {
|
destroy: function (element) {
|
||||||
component.$destroy();
|
component.$destroy();
|
||||||
component = undefined;
|
component = undefined;
|
||||||
|
@ -73,18 +73,14 @@ const MOVE_COLUMN_DT_TYPE = 'movecolumnfromindex';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
isEditing: this.openmct.editor.isEditing()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
headerKey: String,
|
headerKey: String,
|
||||||
headerIndex: Number,
|
headerIndex: Number,
|
||||||
isHeaderTitle: Boolean,
|
isHeaderTitle: Boolean,
|
||||||
sortOptions: Object,
|
sortOptions: Object,
|
||||||
columnWidth: Number,
|
columnWidth: Number,
|
||||||
hotzone: Boolean
|
hotzone: Boolean,
|
||||||
|
isEditing: Boolean
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isSortable() {
|
isSortable() {
|
||||||
@ -167,16 +163,7 @@ export default {
|
|||||||
},
|
},
|
||||||
sort() {
|
sort() {
|
||||||
this.$emit("sort");
|
this.$emit("sort");
|
||||||
},
|
|
||||||
toggleEditMode(isEditing) {
|
|
||||||
this.isEditing = isEditing;
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.openmct.editor.on('isEditing', this.toggleEditMode);
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
this.openmct.editor.off('isEditing', this.toggleEditMode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
@ -48,6 +48,7 @@
|
|||||||
@resizeColumnEnd="updateConfiguredColumnWidths"
|
@resizeColumnEnd="updateConfiguredColumnWidths"
|
||||||
:columnWidth="columnWidths[key]"
|
:columnWidth="columnWidths[key]"
|
||||||
:sortOptions="sortOptions"
|
:sortOptions="sortOptions"
|
||||||
|
:isEditing="isEditing"
|
||||||
>{{title}}</table-column-header>
|
>{{title}}</table-column-header>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="c-telemetry-table__headers__filter">
|
<tr class="c-telemetry-table__headers__filter">
|
||||||
@ -61,7 +62,9 @@
|
|||||||
@dropTargetActive="dropTargetActive"
|
@dropTargetActive="dropTargetActive"
|
||||||
@reorderColumn="reorderColumn"
|
@reorderColumn="reorderColumn"
|
||||||
@resizeColumnEnd="updateConfiguredColumnWidths"
|
@resizeColumnEnd="updateConfiguredColumnWidths"
|
||||||
:columnWidth="columnWidths[key]">
|
:columnWidth="columnWidths[key]"
|
||||||
|
:isEditing="isEditing"
|
||||||
|
>
|
||||||
<search class="c-table__search"
|
<search class="c-table__search"
|
||||||
v-model="filters[key]"
|
v-model="filters[key]"
|
||||||
v-on:input="filterChanged(key)"
|
v-on:input="filterChanged(key)"
|
||||||
@ -260,6 +263,12 @@ export default {
|
|||||||
search
|
search
|
||||||
},
|
},
|
||||||
inject: ['table', 'openmct', 'csvExporter'],
|
inject: ['table', 'openmct', 'csvExporter'],
|
||||||
|
props: {
|
||||||
|
isEditing: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
let configuration = this.table.configuration.getConfiguration();
|
let configuration = this.table.configuration.getConfiguration();
|
||||||
|
|
||||||
|
@ -12,6 +12,9 @@ export default {
|
|||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.clear();
|
this.clear();
|
||||||
|
if (this.releaseEditModeHandler) {
|
||||||
|
this.releaseEditModeHandler();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
view(newView, oldView) {
|
view(newView, oldView) {
|
||||||
@ -37,6 +40,11 @@ export default {
|
|||||||
if (this.currentView) {
|
if (this.currentView) {
|
||||||
this.currentView.destroy();
|
this.currentView.destroy();
|
||||||
this.$el.innerHTML = '';
|
this.$el.innerHTML = '';
|
||||||
|
|
||||||
|
if (this.releaseEditModeHandler) {
|
||||||
|
this.releaseEditModeHandler();
|
||||||
|
delete this.releaseEditModeHandler;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
delete this.viewContainer;
|
delete this.viewContainer;
|
||||||
delete this.currentView;
|
delete this.currentView;
|
||||||
@ -46,6 +54,13 @@ export default {
|
|||||||
delete this.removeSelectable;
|
delete this.removeSelectable;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
invokeEditModeHandler(editMode) {
|
||||||
|
this.currentView.onEditModeChange(editMode);
|
||||||
|
},
|
||||||
|
toggleEditView(editMode) {
|
||||||
|
this.clear();
|
||||||
|
this.updateView(true);
|
||||||
|
},
|
||||||
updateView(immediatelySelect) {
|
updateView(immediatelySelect) {
|
||||||
this.clear();
|
this.clear();
|
||||||
if (!this.currentObject) {
|
if (!this.currentObject) {
|
||||||
@ -55,14 +70,32 @@ export default {
|
|||||||
this.viewContainer.classList.add('c-object-view','u-contents');
|
this.viewContainer.classList.add('c-object-view','u-contents');
|
||||||
this.$el.append(this.viewContainer);
|
this.$el.append(this.viewContainer);
|
||||||
let provider = this.openmct.objectViews.getByProviderKey(this.viewKey);
|
let provider = this.openmct.objectViews.getByProviderKey(this.viewKey);
|
||||||
|
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
provider = this.openmct.objectViews.get(this.currentObject)[0];
|
provider = this.openmct.objectViews.get(this.currentObject)[0];
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.currentView = provider.view(this.currentObject);
|
|
||||||
this.currentView.show(this.viewContainer);
|
|
||||||
|
if (provider.edit) {
|
||||||
|
if (this.openmct.editor.isEditing()) {
|
||||||
|
this.currentView = provider.edit(this.currentObject);
|
||||||
|
} else {
|
||||||
|
this.currentView = provider.view(this.currentObject, false);
|
||||||
|
}
|
||||||
|
this.openmct.editor.on('isEditing', this.toggleEditView);
|
||||||
|
this.releaseEditModeHandler = () => this.openmct.editor.off('isEditing', this.toggleEditView);
|
||||||
|
} else {
|
||||||
|
this.currentView = provider.view(this.currentObject, this.openmct.editor.isEditing());
|
||||||
|
|
||||||
|
if (this.currentView.onEditModeChange) {
|
||||||
|
this.openmct.editor.on('isEditing', this.invokeEditModeHandler);
|
||||||
|
this.releaseEditModeHandler = () => this.openmct.editor.off('isEditing', this.invokeEditModeHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.currentView.show(this.viewContainer, this.openmct.editor.isEditing());
|
||||||
|
|
||||||
if (immediatelySelect) {
|
if (immediatelySelect) {
|
||||||
this.removeSelectable = openmct.selection.selectable(
|
this.removeSelectable = openmct.selection.selectable(
|
||||||
|
@ -84,7 +84,7 @@
|
|||||||
mounted() {
|
mounted() {
|
||||||
let viewProvider = this.openmct.objectViews.get(this.domainObject)[0];
|
let viewProvider = this.openmct.objectViews.get(this.domainObject)[0];
|
||||||
this.view = viewProvider.view(this.domainObject);
|
this.view = viewProvider.view(this.domainObject);
|
||||||
this.view.show(this.$refs.objectView);
|
this.view.show(this.$refs.objectView, false);
|
||||||
},
|
},
|
||||||
destroy() {
|
destroy() {
|
||||||
this.view.destroy();
|
this.view.destroy();
|
||||||
|
@ -120,6 +120,19 @@ define([], function () {
|
|||||||
* @memberof module:openmct.View#
|
* @memberof module:openmct.View#
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether or not the application is in edit mode. This supports
|
||||||
|
* views that have distinct visual and behavioral elements when the
|
||||||
|
* navigated object is being edited.
|
||||||
|
*
|
||||||
|
* For cases where a completely separate view is desired for editing purposes,
|
||||||
|
* see {@link openmct.ViewProvider#edit}
|
||||||
|
*
|
||||||
|
* @param {boolean} isEditing
|
||||||
|
* @method show
|
||||||
|
* @memberof module:openmct.View#
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release any resources associated with this view.
|
* Release any resources associated with this view.
|
||||||
*
|
*
|
||||||
@ -172,7 +185,15 @@ define([], function () {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An optional function that defines whether or not this view can be used to edit a given object.
|
* An optional function that defines whether or not this view can be used to edit a given object.
|
||||||
* If not provided, will default to `false` and the view will not support editing.
|
* If not provided, will default to `false` and the view will not support editing. To support editing,
|
||||||
|
* return true from this function and then -
|
||||||
|
* * Return a {@link openmct.View} from the `view` function, using the `onEditModeChange` callback to
|
||||||
|
* add and remove editing elements from the view
|
||||||
|
* OR
|
||||||
|
* * Return a {@link openmct.View} from the `view` function defining a read-only view.
|
||||||
|
* AND
|
||||||
|
* * Define an {@link openmct.ViewProvider#Edit} function on the view provider that returns an
|
||||||
|
* editing-specific view.
|
||||||
*
|
*
|
||||||
* @method canEdit
|
* @method canEdit
|
||||||
* @memberof module:openmct.ViewProvider#
|
* @memberof module:openmct.ViewProvider#
|
||||||
@ -211,6 +232,19 @@ define([], function () {
|
|||||||
* @returns {module:openmct.View} a view of this domain object
|
* @returns {module:openmct.View} a view of this domain object
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide an edit-mode specific view of this object.
|
||||||
|
*
|
||||||
|
* If optionally specified, this function will be called when the application
|
||||||
|
* enters edit mode. This will cause the active non-edit mode view and its
|
||||||
|
* dom element to be destroyed.
|
||||||
|
*
|
||||||
|
* @method edit
|
||||||
|
* @memberof module:openmct.ViewProvider#
|
||||||
|
* @param {*} object the object to be edit
|
||||||
|
* @returns {module:openmct.View} an editable view of this domain object
|
||||||
|
*/
|
||||||
|
|
||||||
return ViewRegistry;
|
return ViewRegistry;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user