* added new menu and actions to notebook embed as well as new information on embed * fix method name case * Add action messages. Fix margins * Added bg icons. Change sizing of icons and thumbnails. Add scrolling to overflow embeds * Rename embed wrapper * adding dynamce class for scrolling the embeds wrapper based on need * Add styling to embed scrolling container * Change tag margin for better spacing between rows. Class rename. Minor styling changes to embed container. Change supermenu icon size * Change action menu size * Fix inner shadows. Revert tag code change. Create new theme constants. Make embed container constant * Fix scroll and snow theme colors * Fix overflow bug in entries and embed container. Refactor code so that containers optimize space of each entry * Fix lint error * Fix so embed container goes full width * Fix input container to extend full width. Fix margin between notebook elements * Addressed PR review comments. * Address PR changes. Fix text overflow for long words. * address pr review comments * fixing tests * first pass * i've wasted too much time on this Co-authored-by: Rukmini Bose <rukmini.bose15@gmail.com> Co-authored-by: rukmini-bose <48999852+rukmini-bose@users.noreply.github.com> Co-authored-by: John Hill <john.c.hill@nasa.gov>
385 lines
13 KiB
Vue
385 lines
13 KiB
Vue
<template>
|
|
<div class="c-snapshot c-ne__embed">
|
|
<div
|
|
v-if="embed.snapshot"
|
|
class="c-ne__embed__snap-thumb"
|
|
@click="openSnapshot()"
|
|
>
|
|
<img :src="thumbnailImage">
|
|
</div>
|
|
<div class="c-ne__embed__info">
|
|
<div class="c-ne__embed__name">
|
|
<a
|
|
class="c-ne__embed__link"
|
|
:class="embed.cssClass"
|
|
@click="navigateToItemInTime"
|
|
>{{ embed.name }}</a>
|
|
<button
|
|
class="c-ne__embed__actions c-icon-button icon-3-dots"
|
|
title="More options"
|
|
@click.prevent.stop="showMenuItems($event)"
|
|
></button>
|
|
</div>
|
|
<div class="c-ne__embed__time">
|
|
{{ createdOn }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import Moment from 'moment';
|
|
import PreviewAction from '../../../ui/preview/PreviewAction';
|
|
import RemoveDialog from '../utils/removeDialog';
|
|
import PainterroInstance from '../utils/painterroInstance';
|
|
import SnapshotTemplate from './snapshot-template.html';
|
|
import objectPathToUrl from '@/tools/url';
|
|
|
|
import { updateNotebookImageDomainObject } from '../utils/notebook-image';
|
|
import ImageExporter from '../../../exporters/ImageExporter';
|
|
|
|
import Vue from 'vue';
|
|
|
|
export default {
|
|
inject: ['openmct', 'snapshotContainer'],
|
|
props: {
|
|
embed: {
|
|
type: Object,
|
|
default() {
|
|
return {};
|
|
}
|
|
},
|
|
isLocked: {
|
|
type: Boolean,
|
|
default() {
|
|
return false;
|
|
}
|
|
},
|
|
isSnapshotContainer: {
|
|
type: Boolean,
|
|
default() {
|
|
return false;
|
|
}
|
|
},
|
|
removeActionString: {
|
|
type: String,
|
|
default() {
|
|
return 'Remove This Embed';
|
|
}
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
menuActions: []
|
|
};
|
|
},
|
|
computed: {
|
|
createdOn() {
|
|
return this.formatTime(this.embed.createdOn, 'YYYY-MM-DD HH:mm:ss');
|
|
},
|
|
thumbnailImage() {
|
|
return this.embed.snapshot.thumbnailImage
|
|
? this.embed.snapshot.thumbnailImage.src
|
|
: this.embed.snapshot.src;
|
|
}
|
|
},
|
|
watch: {
|
|
isLocked(value) {
|
|
if (value === true) {
|
|
let index = this.menuActions.findIndex((item) => item.id === 'removeEmbed');
|
|
|
|
this.$delete(this.menuActions, index);
|
|
}
|
|
}
|
|
},
|
|
async mounted() {
|
|
this.objectPath = [];
|
|
await this.setEmbedObjectPath();
|
|
this.addMenuActions();
|
|
this.imageExporter = new ImageExporter(this.openmct);
|
|
},
|
|
methods: {
|
|
showMenuItems(event) {
|
|
const x = event.x;
|
|
const y = event.y;
|
|
|
|
const menuOptions = {
|
|
menuClass: 'c-ne__embed__actions-menu',
|
|
placement: this.openmct.menus.menuPlacement.TOP_RIGHT
|
|
};
|
|
|
|
this.openmct.menus.showSuperMenu(x, y, this.menuActions, menuOptions);
|
|
},
|
|
addMenuActions() {
|
|
if (this.embed.snapshot) {
|
|
const viewSnapshot = {
|
|
id: 'viewSnapshot',
|
|
cssClass: 'icon-camera',
|
|
name: 'View Snapshot',
|
|
description: 'View the snapshot image taken in the form of a jpeg.',
|
|
onItemClicked: () => this.openSnapshot()
|
|
};
|
|
|
|
this.menuActions = [viewSnapshot];
|
|
}
|
|
|
|
const navigateToItem = {
|
|
id: 'navigateToItem',
|
|
cssClass: this.embed.cssClass,
|
|
name: 'Navigate to Item',
|
|
description: 'Navigate to the item with the current time settings.',
|
|
onItemClicked: () => this.navigateToItem()
|
|
};
|
|
|
|
const navigateToItemInTime = {
|
|
id: 'navigateToItemInTime',
|
|
cssClass: this.embed.cssClass,
|
|
name: 'Navigate to Item in Time',
|
|
description: 'Navigate to the item in its time frame when captured.',
|
|
onItemClicked: () => this.navigateToItemInTime()
|
|
};
|
|
|
|
const quickView = {
|
|
id: 'quickView',
|
|
cssClass: 'icon-eye-open',
|
|
name: 'Quick View',
|
|
description: 'Full screen overlay view of the item.',
|
|
onItemClicked: () => this.previewEmbed()
|
|
};
|
|
|
|
this.menuActions = this.menuActions.concat([quickView, navigateToItem, navigateToItemInTime]);
|
|
|
|
if (!this.isLocked) {
|
|
const removeEmbed = {
|
|
id: 'removeEmbed',
|
|
cssClass: 'icon-trash',
|
|
name: this.removeActionString,
|
|
description: 'Permanently delete this embed from this Notebook entry.',
|
|
onItemClicked: this.getRemoveDialog.bind(this)
|
|
};
|
|
|
|
this.menuActions.push(removeEmbed);
|
|
}
|
|
|
|
},
|
|
async setEmbedObjectPath() {
|
|
this.objectPath = await this.openmct.objects.getOriginalPath(this.embed.domainObject.identifier);
|
|
|
|
if (this.objectPath.length > 0 && this.objectPath[this.objectPath.length - 1].type === 'root') {
|
|
this.objectPath.pop();
|
|
}
|
|
},
|
|
annotateSnapshot() {
|
|
const annotateVue = new Vue({
|
|
template: '<div id="snap-annotation"></div>'
|
|
}).$mount();
|
|
|
|
const painterroInstance = new PainterroInstance(annotateVue.$el);
|
|
const annotateOverlay = this.openmct.overlays.overlay({
|
|
element: annotateVue.$el,
|
|
size: 'large',
|
|
dismissable: false,
|
|
buttons: [
|
|
{
|
|
label: 'Cancel',
|
|
callback: () => {
|
|
painterroInstance.dismiss();
|
|
annotateOverlay.dismiss();
|
|
}
|
|
},
|
|
{
|
|
label: 'Save',
|
|
emphasis: true,
|
|
callback: () => {
|
|
painterroInstance.save((snapshotObject) => {
|
|
annotateOverlay.dismiss();
|
|
this.snapshotOverlay.dismiss();
|
|
this.updateSnapshot(snapshotObject);
|
|
this.openSnapshotOverlay(snapshotObject.fullSizeImage.src);
|
|
});
|
|
}
|
|
}
|
|
],
|
|
onDestroy: () => {
|
|
annotateVue.$destroy(true);
|
|
}
|
|
});
|
|
|
|
painterroInstance.intialize();
|
|
|
|
const fullSizeImageObjectIdentifier = this.embed.snapshot.fullSizeImageObjectIdentifier;
|
|
if (!fullSizeImageObjectIdentifier) {
|
|
// legacy image data stored in embed
|
|
painterroInstance.show(this.embed.snapshot.src);
|
|
|
|
return;
|
|
}
|
|
|
|
if (this.isSnapshotContainer) {
|
|
const snapshot = this.snapshotContainer.getSnapshot(this.embed.id);
|
|
const fullSizeImageURL = snapshot.notebookImageDomainObject.configuration.fullSizeImageURL;
|
|
painterroInstance.show(fullSizeImageURL);
|
|
|
|
return;
|
|
}
|
|
|
|
this.openmct.objects.get(fullSizeImageObjectIdentifier)
|
|
.then(object => {
|
|
painterroInstance.show(object.configuration.fullSizeImageURL);
|
|
});
|
|
},
|
|
navigateToItem() {
|
|
const url = objectPathToUrl(this.openmct, this.objectPath);
|
|
this.openmct.router.navigate(url);
|
|
},
|
|
navigateToItemInTime() {
|
|
const hash = this.embed.historicLink;
|
|
|
|
const bounds = this.openmct.time.bounds();
|
|
const isTimeBoundChanged = this.embed.bounds.start !== bounds.start
|
|
|| this.embed.bounds.end !== bounds.end;
|
|
const isFixedTimespanMode = !this.openmct.time.clock();
|
|
|
|
this.openmct.time.stopClock();
|
|
let message = '';
|
|
if (isTimeBoundChanged) {
|
|
this.openmct.time.bounds({
|
|
start: this.embed.bounds.start,
|
|
end: this.embed.bounds.end
|
|
});
|
|
message = 'Time bound values changed';
|
|
}
|
|
|
|
if (!isFixedTimespanMode) {
|
|
message = 'Time bound values changed to fixed timespan mode';
|
|
}
|
|
|
|
if (message.length) {
|
|
this.openmct.notifications.alert(message);
|
|
}
|
|
|
|
if (this.openmct.editor.isEditing()) {
|
|
this.previewEmbed();
|
|
} else {
|
|
const relativeHash = hash.slice(hash.indexOf('#'));
|
|
const url = new URL(relativeHash, `${location.protocol}//${location.host}${location.pathname}`);
|
|
this.openmct.router.navigate(url.hash);
|
|
}
|
|
},
|
|
formatTime(unixTime, timeFormat) {
|
|
return Moment.utc(unixTime).format(timeFormat);
|
|
},
|
|
getRemoveDialog() {
|
|
const options = {
|
|
name: this.removeActionString,
|
|
callback: this.removeEmbed.bind(this)
|
|
};
|
|
const removeDialog = new RemoveDialog(this.openmct, options);
|
|
removeDialog.show();
|
|
},
|
|
openSnapshot() {
|
|
const fullSizeImageObjectIdentifier = this.embed.snapshot.fullSizeImageObjectIdentifier;
|
|
if (!fullSizeImageObjectIdentifier) {
|
|
// legacy image data stored in embed
|
|
this.openSnapshotOverlay(this.embed.snapshot.src);
|
|
|
|
return;
|
|
}
|
|
|
|
if (this.isSnapshotContainer) {
|
|
const snapshot = this.snapshotContainer.getSnapshot(this.embed.id);
|
|
const fullSizeImageURL = snapshot.notebookImageDomainObject.configuration.fullSizeImageURL;
|
|
this.openSnapshotOverlay(fullSizeImageURL);
|
|
|
|
return;
|
|
}
|
|
|
|
this.openmct.objects.get(fullSizeImageObjectIdentifier)
|
|
.then(object => {
|
|
this.openSnapshotOverlay(object.configuration.fullSizeImageURL);
|
|
});
|
|
},
|
|
openSnapshotOverlay(src) {
|
|
const self = this;
|
|
|
|
this.snapshot = new Vue({
|
|
data: () => {
|
|
return {
|
|
createdOn: this.createdOn,
|
|
name: this.embed.name,
|
|
cssClass: this.embed.cssClass,
|
|
src
|
|
};
|
|
},
|
|
methods: {
|
|
formatTime: self.formatTime,
|
|
annotateSnapshot: self.annotateSnapshot,
|
|
exportImage: self.exportImage
|
|
},
|
|
template: SnapshotTemplate
|
|
}).$mount();
|
|
|
|
this.snapshotOverlay = this.openmct.overlays.overlay({
|
|
element: this.snapshot.$el,
|
|
onDestroy: () => this.snapshot.$destroy(true),
|
|
size: 'large',
|
|
autoHide: false,
|
|
dismissable: true,
|
|
buttons: [
|
|
{
|
|
label: 'Done',
|
|
emphasis: true,
|
|
callback: () => {
|
|
this.snapshotOverlay.dismiss();
|
|
}
|
|
}
|
|
]
|
|
});
|
|
},
|
|
exportImage(type) {
|
|
let element = this.snapshot.$refs['snapshot-image'];
|
|
|
|
if (type === 'png') {
|
|
this.imageExporter.exportPNG(element, this.embed.name);
|
|
} else {
|
|
this.imageExporter.exportJPG(element, this.embed.name);
|
|
}
|
|
},
|
|
previewEmbed() {
|
|
const self = this;
|
|
const previewAction = new PreviewAction(self.openmct);
|
|
this.openmct.objects.get(self.embed.domainObject.identifier)
|
|
.then(domainObject => previewAction.invoke([domainObject]));
|
|
},
|
|
removeEmbed(success) {
|
|
if (!success) {
|
|
return;
|
|
}
|
|
|
|
this.$emit('removeEmbed', this.embed.id);
|
|
},
|
|
updateEmbed(embed) {
|
|
this.$emit('updateEmbed', embed);
|
|
},
|
|
updateSnapshot(snapshotObject) {
|
|
this.embed.snapshot.thumbnailImage = snapshotObject.thumbnailImage;
|
|
|
|
this.updateNotebookImageDomainObjectSnapshot(snapshotObject);
|
|
this.updateEmbed(this.embed);
|
|
},
|
|
updateNotebookImageDomainObjectSnapshot(snapshotObject) {
|
|
if (this.isSnapshotContainer) {
|
|
const snapshot = this.snapshotContainer.getSnapshot(this.embed.id);
|
|
|
|
snapshot.embedObject.snapshot.thumbnailImage = snapshotObject.thumbnailImage;
|
|
snapshot.notebookImageDomainObject.configuration.fullSizeImageURL = snapshotObject.fullSizeImage.src;
|
|
|
|
this.snapshotContainer.updateSnapshot(snapshot);
|
|
} else {
|
|
updateNotebookImageDomainObject(this.openmct, this.embed.snapshot.fullSizeImageObjectIdentifier, snapshotObject.fullSizeImage);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
</script>
|