[Notebook] Press Enter to save notebook entries (#3580)

Co-authored-by: Deep Tailor <deep.j.tailor@nasa.gov>
This commit is contained in:
Nikhil
2021-02-18 09:31:45 -08:00
committed by GitHub
parent b7085f7f62
commit 7623a0648f
3 changed files with 83 additions and 112 deletions

View File

@ -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 || {};

View File

@ -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);
} }
} }
}; };

View File

@ -292,6 +292,8 @@
&:focus { &:focus {
background: $colorInputBg; background: $colorInputBg;
} }
white-space: pre-wrap;
} }
&__section-and-page { &__section-and-page {