mirror of
https://github.com/nasa/openmct.git
synced 2025-06-16 14:18:16 +00:00
[Notebook] Press Enter to save notebook entries (#3580)
Co-authored-by: Deep Tailor <deep.j.tailor@nasa.gov>
This commit is contained in:
@ -97,7 +97,8 @@
|
|||||||
:selected-page="getSelectedPage()"
|
:selected-page="getSelectedPage()"
|
||||||
:selected-section="getSelectedSection()"
|
:selected-section="getSelectedSection()"
|
||||||
:read-only="false"
|
:read-only="false"
|
||||||
@updateEntries="updateEntries"
|
@deleteEntry="deleteEntry"
|
||||||
|
@updateEntry="updateEntry"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -111,7 +112,7 @@ import Search from '@/ui/components/search.vue';
|
|||||||
import SearchResults from './SearchResults.vue';
|
import SearchResults from './SearchResults.vue';
|
||||||
import Sidebar from './Sidebar.vue';
|
import Sidebar from './Sidebar.vue';
|
||||||
import { clearDefaultNotebook, getDefaultNotebook, setDefaultNotebook, setDefaultNotebookSection, setDefaultNotebookPage } from '../utils/notebook-storage';
|
import { clearDefaultNotebook, getDefaultNotebook, setDefaultNotebook, setDefaultNotebookSection, setDefaultNotebookPage } from '../utils/notebook-storage';
|
||||||
import { addNotebookEntry, createNewEmbed, getNotebookEntries, mutateObject } from '../utils/notebook-entries';
|
import { addNotebookEntry, createNewEmbed, getEntryPosById, getNotebookEntries, mutateObject } from '../utils/notebook-entries';
|
||||||
import objectUtils from 'objectUtils';
|
import objectUtils from 'objectUtils';
|
||||||
|
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'lodash';
|
||||||
@ -244,6 +245,37 @@ export default {
|
|||||||
section
|
section
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
deleteEntry(entryId) {
|
||||||
|
const self = this;
|
||||||
|
const entryPos = getEntryPosById(entryId, this.internalDomainObject, this.selectedSection, this.selectedPage);
|
||||||
|
if (entryPos === -1) {
|
||||||
|
this.openmct.notifications.alert('Warning: unable to delete entry');
|
||||||
|
console.error(`unable to delete entry ${entryId} from section ${this.selectedSection}, page ${this.selectedPage}`);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dialog = this.openmct.overlays.dialog({
|
||||||
|
iconClass: 'alert',
|
||||||
|
message: 'This action will permanently delete this entry. Do you wish to continue?',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
label: "Ok",
|
||||||
|
emphasis: true,
|
||||||
|
callback: () => {
|
||||||
|
const entries = getNotebookEntries(self.internalDomainObject, self.selectedSection, self.selectedPage);
|
||||||
|
entries.splice(entryPos, 1);
|
||||||
|
self.updateEntries(entries);
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Cancel",
|
||||||
|
callback: () => dialog.dismiss()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
},
|
||||||
dragOver(event) {
|
dragOver(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.dataTransfer.dropEffect = "copy";
|
event.dataTransfer.dropEffect = "copy";
|
||||||
@ -540,6 +572,13 @@ export default {
|
|||||||
|
|
||||||
setDefaultNotebookSection(section);
|
setDefaultNotebookSection(section);
|
||||||
},
|
},
|
||||||
|
updateEntry(entry) {
|
||||||
|
const entries = getNotebookEntries(this.internalDomainObject, this.selectedSection, this.selectedPage);
|
||||||
|
const entryPos = getEntryPosById(entry.id, this.internalDomainObject, this.selectedSection, this.selectedPage);
|
||||||
|
entries[entryPos] = entry;
|
||||||
|
|
||||||
|
this.updateEntries(entries);
|
||||||
|
},
|
||||||
updateEntries(entries) {
|
updateEntries(entries) {
|
||||||
const configuration = this.internalDomainObject.configuration;
|
const configuration = this.internalDomainObject.configuration;
|
||||||
const notebookEntries = configuration.entries || {};
|
const notebookEntries = configuration.entries || {};
|
||||||
|
@ -12,11 +12,15 @@
|
|||||||
<div class="c-ne__content">
|
<div class="c-ne__content">
|
||||||
<div :id="entry.id"
|
<div :id="entry.id"
|
||||||
class="c-ne__text"
|
class="c-ne__text"
|
||||||
:class="{'c-ne__input' : !readOnly }"
|
tabindex="0"
|
||||||
|
:class="{ 'c-ne__input' : !readOnly }"
|
||||||
:contenteditable="!readOnly"
|
:contenteditable="!readOnly"
|
||||||
@blur="updateEntryValue($event, entry.id)"
|
@blur="updateEntryValue($event)"
|
||||||
@focus="updateCurrentEntryValue($event, entry.id)"
|
@keydown.enter.exact.prevent
|
||||||
>{{ entry.text }}</div>
|
@keyup.enter.exact.prevent="forceBlur($event)"
|
||||||
|
v-text="entry.text"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
<div class="c-snapshots c-ne__embeds">
|
<div class="c-snapshots c-ne__embeds">
|
||||||
<NotebookEmbed v-for="embed in entry.embeds"
|
<NotebookEmbed v-for="embed in entry.embeds"
|
||||||
:key="embed.id"
|
:key="embed.id"
|
||||||
@ -33,6 +37,7 @@
|
|||||||
>
|
>
|
||||||
<button class="c-icon-button c-icon-button--major icon-trash"
|
<button class="c-icon-button c-icon-button--major icon-trash"
|
||||||
title="Delete this entry"
|
title="Delete this entry"
|
||||||
|
tabindex="-1"
|
||||||
@click="deleteEntry"
|
@click="deleteEntry"
|
||||||
>
|
>
|
||||||
</button>
|
</button>
|
||||||
@ -57,7 +62,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import NotebookEmbed from './NotebookEmbed.vue';
|
import NotebookEmbed from './NotebookEmbed.vue';
|
||||||
import { createNewEmbed, getEntryPosById, getNotebookEntries } from '../utils/notebook-entries';
|
import { createNewEmbed } from '../utils/notebook-entries';
|
||||||
import Moment from 'moment';
|
import Moment from 'moment';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -103,11 +108,6 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
currentEntryValue: ''
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
createdOnDate() {
|
createdOnDate() {
|
||||||
return this.formatTime(this.entry.createdOn, 'YYYY-MM-DD');
|
return this.formatTime(this.entry.createdOn, 'YYYY-MM-DD');
|
||||||
@ -117,10 +117,20 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.updateEntries = this.updateEntries.bind(this);
|
|
||||||
this.dropOnEntry = this.dropOnEntry.bind(this);
|
this.dropOnEntry = this.dropOnEntry.bind(this);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
addNewEmbed(objectPath) {
|
||||||
|
const bounds = this.openmct.time.bounds();
|
||||||
|
const snapshotMeta = {
|
||||||
|
bounds,
|
||||||
|
link: null,
|
||||||
|
objectPath,
|
||||||
|
openmct: this.openmct
|
||||||
|
};
|
||||||
|
const newEmbed = createNewEmbed(snapshotMeta);
|
||||||
|
this.entry.embeds.push(newEmbed);
|
||||||
|
},
|
||||||
cancelEditMode(event) {
|
cancelEditMode(event) {
|
||||||
const isEditing = this.openmct.editor.isEditing();
|
const isEditing = this.openmct.editor.isEditing();
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
@ -132,63 +142,23 @@ export default {
|
|||||||
event.dataTransfer.dropEffect = "copy";
|
event.dataTransfer.dropEffect = "copy";
|
||||||
},
|
},
|
||||||
deleteEntry() {
|
deleteEntry() {
|
||||||
const self = this;
|
this.$emit('deleteEntry', this.entry.id);
|
||||||
const entryPosById = self.entryPosById(self.entry.id);
|
|
||||||
if (entryPosById === -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dialog = this.openmct.overlays.dialog({
|
|
||||||
iconClass: 'alert',
|
|
||||||
message: 'This action will permanently delete this entry. Do you wish to continue?',
|
|
||||||
buttons: [
|
|
||||||
{
|
|
||||||
label: "Ok",
|
|
||||||
emphasis: true,
|
|
||||||
callback: () => {
|
|
||||||
const entries = getNotebookEntries(self.domainObject, self.selectedSection, self.selectedPage);
|
|
||||||
entries.splice(entryPosById, 1);
|
|
||||||
self.updateEntries(entries);
|
|
||||||
dialog.dismiss();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Cancel",
|
|
||||||
callback: () => {
|
|
||||||
dialog.dismiss();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
dropOnEntry($event) {
|
dropOnEntry($event) {
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
|
|
||||||
const snapshotId = $event.dataTransfer.getData('openmct/snapshot/id');
|
const snapshotId = $event.dataTransfer.getData('openmct/snapshot/id');
|
||||||
if (snapshotId.length) {
|
if (snapshotId.length) {
|
||||||
this.moveSnapshot(snapshotId);
|
const snapshot = this.snapshotContainer.getSnapshot(snapshotId);
|
||||||
|
this.snapshotContainer.removeSnapshot(snapshotId);
|
||||||
return;
|
this.entry.embeds.push(snapshot);
|
||||||
}
|
} else {
|
||||||
|
|
||||||
const data = $event.dataTransfer.getData('openmct/domain-object-path');
|
const data = $event.dataTransfer.getData('openmct/domain-object-path');
|
||||||
const objectPath = JSON.parse(data);
|
const objectPath = JSON.parse(data);
|
||||||
const entryPos = this.entryPosById(this.entry.id);
|
this.addNewEmbed(objectPath);
|
||||||
const bounds = this.openmct.time.bounds();
|
}
|
||||||
const snapshotMeta = {
|
|
||||||
bounds,
|
this.$emit('updateEntry', this.entry);
|
||||||
link: null,
|
|
||||||
objectPath,
|
|
||||||
openmct: this.openmct
|
|
||||||
};
|
|
||||||
const newEmbed = createNewEmbed(snapshotMeta);
|
|
||||||
const entries = getNotebookEntries(this.domainObject, this.selectedSection, this.selectedPage);
|
|
||||||
const currentEntryEmbeds = entries[entryPos].embeds;
|
|
||||||
currentEntryEmbeds.push(newEmbed);
|
|
||||||
this.updateEntries(entries);
|
|
||||||
},
|
|
||||||
entryPosById(entryId) {
|
|
||||||
return getEntryPosById(entryId, this.domainObject, this.selectedSection, this.selectedPage);
|
|
||||||
},
|
},
|
||||||
findPositionInArray(array, id) {
|
findPositionInArray(array, id) {
|
||||||
let position = -1;
|
let position = -1;
|
||||||
@ -203,15 +173,12 @@ export default {
|
|||||||
|
|
||||||
return position;
|
return position;
|
||||||
},
|
},
|
||||||
|
forceBlur(event) {
|
||||||
|
event.target.blur();
|
||||||
|
},
|
||||||
formatTime(unixTime, timeFormat) {
|
formatTime(unixTime, timeFormat) {
|
||||||
return Moment.utc(unixTime).format(timeFormat);
|
return Moment.utc(unixTime).format(timeFormat);
|
||||||
},
|
},
|
||||||
moveSnapshot(snapshotId) {
|
|
||||||
const snapshot = this.snapshotContainer.getSnapshot(snapshotId);
|
|
||||||
this.entry.embeds.push(snapshot);
|
|
||||||
this.updateEntry(this.entry);
|
|
||||||
this.snapshotContainer.removeSnapshot(snapshotId);
|
|
||||||
},
|
|
||||||
navigateToPage() {
|
navigateToPage() {
|
||||||
this.$emit('changeSectionPage', {
|
this.$emit('changeSectionPage', {
|
||||||
sectionId: this.result.section.id,
|
sectionId: this.result.section.id,
|
||||||
@ -227,15 +194,8 @@ export default {
|
|||||||
removeEmbed(id) {
|
removeEmbed(id) {
|
||||||
const embedPosition = this.findPositionInArray(this.entry.embeds, id);
|
const embedPosition = this.findPositionInArray(this.entry.embeds, id);
|
||||||
this.entry.embeds.splice(embedPosition, 1);
|
this.entry.embeds.splice(embedPosition, 1);
|
||||||
this.updateEntry(this.entry);
|
|
||||||
},
|
|
||||||
updateCurrentEntryValue($event) {
|
|
||||||
if (this.readOnly) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const target = $event.target;
|
this.$emit('updateEntry', this.entry);
|
||||||
this.currentEntryValue = target ? target.textContent : '';
|
|
||||||
},
|
},
|
||||||
updateEmbed(newEmbed) {
|
updateEmbed(newEmbed) {
|
||||||
this.entry.embeds.some(e => {
|
this.entry.embeds.some(e => {
|
||||||
@ -247,44 +207,14 @@ export default {
|
|||||||
return found;
|
return found;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.updateEntry(this.entry);
|
this.$emit('updateEntry', this.entry);
|
||||||
},
|
},
|
||||||
updateEntry(newEntry) {
|
updateEntryValue($event) {
|
||||||
const entries = getNotebookEntries(this.domainObject, this.selectedSection, this.selectedPage);
|
const value = $event.target.innerText;
|
||||||
entries.some(entry => {
|
if (value !== this.entry.text && value.match(/\S/)) {
|
||||||
const found = (entry.id === newEntry.id);
|
this.entry.text = value;
|
||||||
if (found) {
|
this.$emit('updateEntry', this.entry);
|
||||||
entry = newEntry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return found;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.updateEntries(entries);
|
|
||||||
},
|
|
||||||
updateEntryValue($event, entryId) {
|
|
||||||
if (!this.domainObject || !this.selectedSection || !this.selectedPage) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const target = $event.target;
|
|
||||||
if (!target) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const entryPos = this.entryPosById(entryId);
|
|
||||||
const value = target.textContent.trim();
|
|
||||||
if (this.currentEntryValue !== value) {
|
|
||||||
target.textContent = value;
|
|
||||||
|
|
||||||
const entries = getNotebookEntries(this.domainObject, this.selectedSection, this.selectedPage);
|
|
||||||
entries[entryPos].text = value;
|
|
||||||
|
|
||||||
this.updateEntries(entries);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
updateEntries(entries) {
|
|
||||||
this.$emit('updateEntries', entries);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -292,6 +292,8 @@
|
|||||||
&:focus {
|
&:focus {
|
||||||
background: $colorInputBg;
|
background: $colorInputBg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__section-and-page {
|
&__section-and-page {
|
||||||
|
Reference in New Issue
Block a user