Compare commits
	
		
			28 Commits
		
	
	
		
			release/2.
			...
			nb-embed-e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 98836b256f | ||
|   | 4dee94480c | ||
|   | 17fee67e08 | ||
|   | 3bd12a1db4 | ||
|   | 3e45b2ccd7 | ||
|   | 4b08aa93e6 | ||
|   | e48f419db7 | ||
|   | f6e0224099 | ||
|   | df3b8b55d9 | ||
|   | fcf950cf43 | ||
|   | 54f06d36a5 | ||
|   | a742c35ff9 | ||
|   | 332540598b | ||
|   | 06d1efc008 | ||
|   | d196cafb9c | ||
|   | 081eeb8a1f | ||
|   | 97245781e5 | ||
|   | ede591d768 | ||
|   | 945f220727 | ||
|   | bd9ed3de87 | ||
|   | eb50e93cd9 | ||
|   | b72bad16d9 | ||
|   | a4d2290274 | ||
|   | 9a3806b117 | ||
|   | ba26e38837 | ||
|   | 29a747405e | ||
|   | 305d566ee7 | ||
|   | 95e6a5b3ad | 
| @@ -24,8 +24,6 @@ | ||||
| This test suite is dedicated to tests which verify the basic operations surrounding Notebooks. | ||||
| */ | ||||
|  | ||||
| // FIXME: Remove this eslint exception once tests are implemented | ||||
| // eslint-disable-next-line no-unused-vars | ||||
| const { test, expect } = require('../../../../pluginFixtures'); | ||||
| const { expandTreePaneItemByName, createDomainObjectWithDefaults } = require('../../../../appActions'); | ||||
| const nbUtils = require('../../../../helper/notebookUtils'); | ||||
| @@ -266,70 +264,3 @@ test.describe('Notebook entry tests', () => { | ||||
|     test.fixme('new entries persist through navigation events without save', async ({ page }) => {}); | ||||
|     test.fixme('previous and new entries can be deleted', async ({ page }) => {}); | ||||
| }); | ||||
|  | ||||
| test.describe('Snapshot Menu tests', () => { | ||||
|     test.fixme('When no default notebook is selected, Snapshot Menu dropdown should only have a single option', async ({ page }) => { | ||||
|         // There should be no default notebook | ||||
|         // Clear default notebook if exists using `localStorage.setItem('notebook-storage', null);` | ||||
|         // refresh page | ||||
|         // Click on 'Notebook Snaphot Menu' | ||||
|         // 'save to Notebook Snapshots' should be only option there | ||||
|     }); | ||||
|     test.fixme('When default notebook is updated selected, Snapshot Menu dropdown should list it as the newest option', async ({ page }) => { | ||||
|         // Create 2a notebooks | ||||
|         // Set Notebook A as Default | ||||
|         // Open Snapshot Menu and note that Notebook A is listed | ||||
|         // Close Snapshot Menu | ||||
|         // Set Default Notebook to Notebook B | ||||
|         // Open Snapshot Notebook and note that Notebook B is listed | ||||
|         // Select Default Notebook Option and verify that Snapshot is added to Notebook B | ||||
|     }); | ||||
|     test.fixme('Can add Snapshots via Snapshot Menu and details are correct', async ({ page }) => { | ||||
|         //Note this should be a visual test, too | ||||
|         // Create Telemetry object | ||||
|         // Create A notebook with many pages and sections. | ||||
|         // Set page and section defaults to be between first and last of many. i.e. 3 of 5 | ||||
|         // Navigate to Telemetry object | ||||
|         // Select Default Notebook Option and verify that Snapshot is added to Notebook A | ||||
|         // Verify Snapshot Details appear correctly | ||||
|     }); | ||||
|     test.fixme('Snapshots adjust time conductor', async ({ page }) => { | ||||
|         // Create Telemetry object | ||||
|         // Set Telemetry object's timeconductor to Fixed time with Start and Endtimes are recorded | ||||
|         // Embed Telemetry object into notebook | ||||
|         // Set Time Conductor to Local clock | ||||
|         // Click into embedded telemetry object and verify object appears with same fixed time from record | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| test.describe('Snapshot Container tests', () => { | ||||
|     test.fixme('5 Snapshots can be added to a container', async ({ page }) => {}); | ||||
|     test.fixme('5 Snapshots can be added to a container and Deleted with Delete All action', async ({ page }) => {}); | ||||
|     test.fixme('A snapshot can be Deleted from Container', async ({ page }) => {}); | ||||
|     test.fixme('A snapshot can be Previewed from Container', async ({ page }) => {}); | ||||
|     test.fixme('A snapshot Container can be open and closed', async ({ page }) => {}); | ||||
|     test.fixme('Can add object to Snapshot container and pull into notebook and create a new entry', async ({ page }) => { | ||||
|         //Create Notebook | ||||
|         //Create Telemetry Object | ||||
|         //From Telemetry Object, use 'save to Notebook Snapshots' | ||||
|         //Snapshots indicator should blink, click on it to view snapshots | ||||
|         //Navigate to Notebook | ||||
|         //Drag and Drop onto droppable area for new entry | ||||
|         //New Entry created with given snapshot added | ||||
|         //Snapshot removed from container? | ||||
|     }); | ||||
|     test.fixme('Can add object to Snapshot container and pull into notebook and existing entry', async ({ page }) => { | ||||
|         //Create Notebook | ||||
|         //Create Telemetry Object | ||||
|         //From Telemetry Object, use 'save to Notebook Snapshots' | ||||
|         //Snapshots indicator should blink, click on it to view snapshots | ||||
|         //Navigate to Notebook | ||||
|         //Drag and Drop into exiting entry | ||||
|         //Existing Entry updated with given snapshot | ||||
|         //Snapshot removed from container? | ||||
|     }); | ||||
|     test.fixme('Verify Embedded options for PNG, JPG, and Annotate work correctly', async ({ page }) => { | ||||
|         //Add snapshot to container | ||||
|         //Verify PNG, JPG, and Annotate buttons work correctly | ||||
|     }); | ||||
| }); | ||||
|   | ||||
| @@ -0,0 +1,134 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2022, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| /* | ||||
| This test suite is dedicated to tests which verify the basic operations surrounding Notebooks. | ||||
| */ | ||||
|  | ||||
| const { test, expect } = require('../../../../pluginFixtures'); | ||||
| // const { expandTreePaneItemByName, createDomainObjectWithDefaults } = require('../../../../appActions'); | ||||
| // const nbUtils = require('../../../../helper/notebookUtils'); | ||||
|  | ||||
| test.describe('Snapshot Menu tests', () => { | ||||
|     test.fixme('When no default notebook is selected, Snapshot Menu dropdown should only have a single option', async ({ page }) => { | ||||
|         // There should be no default notebook | ||||
|         // Clear default notebook if exists using `localStorage.setItem('notebook-storage', null);` | ||||
|         // refresh page | ||||
|         // Click on 'Notebook Snaphot Menu' | ||||
|         // 'save to Notebook Snapshots' should be only option there | ||||
|     }); | ||||
|     test.fixme('When default notebook is updated selected, Snapshot Menu dropdown should list it as the newest option', async ({ page }) => { | ||||
|         // Create 2a notebooks | ||||
|         // Set Notebook A as Default | ||||
|         // Open Snapshot Menu and note that Notebook A is listed | ||||
|         // Close Snapshot Menu | ||||
|         // Set Default Notebook to Notebook B | ||||
|         // Open Snapshot Notebook and note that Notebook B is listed | ||||
|         // Select Default Notebook Option and verify that Snapshot is added to Notebook B | ||||
|     }); | ||||
|     test.fixme('Can add Snapshots via Snapshot Menu and details are correct', async ({ page }) => { | ||||
|         //Note this should be a visual test, too | ||||
|         // Create Telemetry object | ||||
|         // Create A notebook with many pages and sections. | ||||
|         // Set page and section defaults to be between first and last of many. i.e. 3 of 5 | ||||
|         // Navigate to Telemetry object | ||||
|         // Select Default Notebook Option and verify that Snapshot is added to Notebook A | ||||
|         // Verify Snapshot Details appear correctly | ||||
|     }); | ||||
|     test.fixme('Snapshots adjust time conductor', async ({ page }) => { | ||||
|         // Create Telemetry object | ||||
|         // Set Telemetry object's timeconductor to Fixed time with Start and Endtimes are recorded | ||||
|         // Embed Telemetry object into notebook | ||||
|         // Set Time Conductor to Local clock | ||||
|         // Click into embedded telemetry object and verify object appears with same fixed time from record | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| test.describe('Snapshot Container tests', () => { | ||||
|     test.beforeEach(async ({ page }) => { | ||||
|         //Navigate to baseURL | ||||
|         await page.goto('./', { waitUntil: 'networkidle' }); | ||||
|  | ||||
|         // Create Notebook | ||||
|         // const notebook = await createDomainObjectWithDefaults(page, { | ||||
|         //     type: 'Notebook', | ||||
|         //     name: "Test Notebook" | ||||
|         // }); | ||||
|         // // Create Overlay Plot | ||||
|         // const snapShotObject = await createDomainObjectWithDefaults(page, { | ||||
|         //     type: 'Overlay Plot', | ||||
|         //     name: "Dropped Overlay Plot" | ||||
|         // }); | ||||
|  | ||||
|         await page.getByRole('button', { name: ' Snapshot ' }).click(); | ||||
|         await page.getByRole('menuitem', { name: ' Save to Notebook Snapshots' }).click(); | ||||
|         await page.getByRole('button', { name: 'Show' }).click(); | ||||
|  | ||||
|     }); | ||||
|     test.fixme('5 Snapshots can be added to a container', async ({ page }) => {}); | ||||
|     test.fixme('5 Snapshots can be added to a container and Deleted with Delete All action', async ({ page }) => {}); | ||||
|     test.fixme('A snapshot can be Deleted from Container with 3 dot action menu', async ({ page }) => {}); | ||||
|     test.fixme('A snapshot can be Viewed, Annotated, display deleted, and saved from Container with 3 dot action menu', async ({ page }) => { | ||||
|         await page.locator('.c-snapshot.c-ne__embed').first().getByTitle('More options').click(); | ||||
|         await page.getByRole('menuitem', { name: ' View Snapshot' }).click(); | ||||
|         await expect(page.locator('.c-overlay__outer')).toBeVisible(); | ||||
|         await page.getByTitle('Annotate').click(); | ||||
|         await expect(page.locator('#snap-annotation-canvas')).toBeVisible(); | ||||
|         await page.getByRole('button', { name: '' }).click(); | ||||
|         // await expect(page.locator('#snap-annotation-canvas')).not.toBeVisible(); | ||||
|         await page.getByRole('button', { name: 'Save' }).click(); | ||||
|         await page.getByRole('button', { name: 'Done' }).click(); | ||||
|         //await expect(await page.locator) | ||||
|     }); | ||||
|     test('A snapshot can be Quick Viewed from Container with 3 dot action menu', async ({ page }) => { | ||||
|         await page.locator('.c-snapshot.c-ne__embed').first().getByTitle('More options').click(); | ||||
|         await page.getByRole('menuitem', { name: 'Quick View' }).click(); | ||||
|         await expect(page.locator('.c-overlay__outer')).toBeVisible(); | ||||
|     }); | ||||
|     test.fixme('A snapshot can be Navigated To from Container with 3 dot action menu', async ({ page }) => {}); | ||||
|     test.fixme('A snapshot can be Navigated To Item in Time from Container with 3 dot action menu', async ({ page }) => {}); | ||||
|     test.fixme('A snapshot Container can be open and closed', async ({ page }) => {}); | ||||
|     test.fixme('Can add object to Snapshot container and pull into notebook and create a new entry', async ({ page }) => { | ||||
|         //Create Notebook | ||||
|         //Create Telemetry Object | ||||
|         //From Telemetry Object, use 'save to Notebook Snapshots' | ||||
|         //Snapshots indicator should blink, click on it to view snapshots | ||||
|         //Navigate to Notebook | ||||
|         //Drag and Drop onto droppable area for new entry | ||||
|         //New Entry created with given snapshot added | ||||
|         //Snapshot removed from container? | ||||
|     }); | ||||
|     test.fixme('Can add object to Snapshot container and pull into notebook and existing entry', async ({ page }) => { | ||||
|         //Create Notebook | ||||
|         //Create Telemetry Object | ||||
|         //From Telemetry Object, use 'save to Notebook Snapshots' | ||||
|         //Snapshots indicator should blink, click on it to view snapshots | ||||
|         //Navigate to Notebook | ||||
|         //Drag and Drop into exiting entry | ||||
|         //Existing Entry updated with given snapshot | ||||
|         //Snapshot removed from container? | ||||
|     }); | ||||
|     test.fixme('Verify Embedded options for PNG, JPG, and Annotate work correctly', async ({ page }) => { | ||||
|         //Add snapshot to container | ||||
|         //Verify PNG, JPG, and Annotate buttons work correctly | ||||
|     }); | ||||
| }); | ||||
| @@ -152,7 +152,7 @@ test.describe('Restricted Notebook with a page locked and with an embed @addInit | ||||
|  | ||||
|     test('Allows embeds to be deleted if page unlocked @addInit', async ({ page }) => { | ||||
|         // Click .c-ne__embed__name .c-popup-menu-button | ||||
|         await page.locator('.c-ne__embed__name .c-popup-menu-button').click(); // embed popup menu | ||||
|         await page.locator('.c-ne__embed__name .c-icon-button').click(); // embed popup menu | ||||
|  | ||||
|         const embedMenu = page.locator('body >> .c-menu'); | ||||
|         await expect(embedMenu).toContainText('Remove This Embed'); | ||||
| @@ -161,7 +161,7 @@ test.describe('Restricted Notebook with a page locked and with an embed @addInit | ||||
|     test('Disallows embeds to be deleted if page locked @addInit', async ({ page }) => { | ||||
|         await lockPage(page); | ||||
|         // Click .c-ne__embed__name .c-popup-menu-button | ||||
|         await page.locator('.c-ne__embed__name .c-popup-menu-button').click(); // embed popup menu | ||||
|         await page.locator('.c-ne__embed__name .c-icon-button').click(); // embed popup menu | ||||
|  | ||||
|         const embedMenu = page.locator('body >> .c-menu'); | ||||
|         await expect(embedMenu).not.toContainText('Remove This Embed'); | ||||
|   | ||||
| @@ -12,14 +12,15 @@ | ||||
|             <a | ||||
|                 class="c-ne__embed__link" | ||||
|                 :class="embed.cssClass" | ||||
|                 @click="changeLocation" | ||||
|                 @click="navigateToItemInTime" | ||||
|             >{{ embed.name }}</a> | ||||
|             <PopupMenu :popup-menu-items="popupMenuItems" /> | ||||
|             <button | ||||
|                 class="c-ne__embed__actions c-icon-button icon-3-dots" | ||||
|                 title="More options" | ||||
|                 @click.prevent.stop="showMenuItems($event)" | ||||
|             ></button> | ||||
|         </div> | ||||
|         <div | ||||
|             v-if="embed.snapshot" | ||||
|             class="c-ne__embed__time" | ||||
|         > | ||||
|         <div class="c-ne__embed__time"> | ||||
|             {{ createdOn }} | ||||
|         </div> | ||||
|     </div> | ||||
| @@ -32,17 +33,14 @@ 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 PopupMenu from './PopupMenu.vue'; | ||||
| import Vue from 'vue'; | ||||
|  | ||||
| export default { | ||||
|     components: { | ||||
|         PopupMenu | ||||
|     }, | ||||
|     inject: ['openmct', 'snapshotContainer'], | ||||
|     props: { | ||||
|         embed: { | ||||
| @@ -72,7 +70,7 @@ export default { | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             popupMenuItems: [] | ||||
|             menuActions: [] | ||||
|         }; | ||||
|     }, | ||||
|     computed: { | ||||
| @@ -88,37 +86,88 @@ export default { | ||||
|     watch: { | ||||
|         isLocked(value) { | ||||
|             if (value === true) { | ||||
|                 let index = this.popupMenuItems.findIndex((item) => item.id === 'removeEmbed'); | ||||
|                 let index = this.menuActions.findIndex((item) => item.id === 'removeEmbed'); | ||||
|  | ||||
|                 this.$delete(this.popupMenuItems, index); | ||||
|                 this.$delete(this.menuActions, index); | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.addPopupMenuItems(); | ||||
|     async mounted() { | ||||
|         this.objectPath = []; | ||||
|         await this.setEmbedObjectPath(); | ||||
|         this.addMenuActions(); | ||||
|         this.imageExporter = new ImageExporter(this.openmct); | ||||
|     }, | ||||
|     methods: { | ||||
|         addPopupMenuItems() { | ||||
|             const removeEmbed = { | ||||
|                 id: 'removeEmbed', | ||||
|                 cssClass: 'icon-trash', | ||||
|                 name: this.removeActionString, | ||||
|                 callback: this.getRemoveDialog.bind(this) | ||||
|             }; | ||||
|             const preview = { | ||||
|                 id: 'preview', | ||||
|                 cssClass: 'icon-eye-open', | ||||
|                 name: 'Preview', | ||||
|                 callback: this.previewEmbed.bind(this) | ||||
|         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.popupMenuItems = [preview]; | ||||
|             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() | ||||
|                 }; | ||||
|  | ||||
|             if (!this.isLocked) { | ||||
|                 this.popupMenuItems.unshift(removeEmbed); | ||||
|                 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({ | ||||
| @@ -179,7 +228,11 @@ export default { | ||||
|                     painterroInstance.show(object.configuration.fullSizeImageURL); | ||||
|                 }); | ||||
|         }, | ||||
|         changeLocation() { | ||||
|         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(); | ||||
|   | ||||
| @@ -31,15 +31,28 @@ | ||||
|     @click="selectEntry($event, entry)" | ||||
| > | ||||
|     <div class="c-ne__time-and-content"> | ||||
|         <div class="c-ne__time-and-creator"> | ||||
|             <span class="c-ne__created-date">{{ createdOnDate }}</span> | ||||
|             <span class="c-ne__created-time">{{ createdOnTime }}</span> | ||||
|  | ||||
|         <div class="c-ne__time-and-creator-and-delete"> | ||||
|             <div class="c-ne__time-and-creator"> | ||||
|                 <span class="c-ne__created-date">{{ createdOnDate }}</span> | ||||
|                 <span class="c-ne__created-time">{{ createdOnTime }}</span> | ||||
|                 <span | ||||
|                     v-if="entry.createdBy" | ||||
|                     class="c-ne__creator" | ||||
|                 > | ||||
|                     <span class="icon-person"></span> {{ entry.createdBy }} | ||||
|                 </span> | ||||
|             </div> | ||||
|             <span | ||||
|                 v-if="entry.createdBy" | ||||
|                 class="c-ne__creator" | ||||
|                 v-if="!readOnly && !isLocked" | ||||
|                 class="c-ne__local-controls--hidden" | ||||
|             > | ||||
|                 <span class="icon-person"></span> {{ entry.createdBy }} | ||||
|                 <button | ||||
|                     class="c-ne__remove c-icon-button c-icon-button--major icon-trash" | ||||
|                     title="Delete this entry" | ||||
|                     tabindex="-1" | ||||
|                     @click="deleteEntry" | ||||
|                 > | ||||
|                 </button> | ||||
|             </span> | ||||
|         </div> | ||||
|         <div class="c-ne__content"> | ||||
| @@ -94,30 +107,26 @@ | ||||
|                 </div> | ||||
|             </div> | ||||
|  | ||||
|             <div class="c-snapshots c-ne__embeds"> | ||||
|                 <NotebookEmbed | ||||
|                     v-for="embed in entry.embeds" | ||||
|                     :key="embed.id" | ||||
|                     :embed="embed" | ||||
|                     :is-locked="isLocked" | ||||
|                     @removeEmbed="removeEmbed" | ||||
|                     @updateEmbed="updateEmbed" | ||||
|                 /> | ||||
|             <div | ||||
|                 :class="{'c-scrollcontainer': enableEmbedsWrapperScroll }" | ||||
|             > | ||||
|                 <div | ||||
|                     ref="embedsWrapper" | ||||
|                     class="c-snapshots c-ne__embeds-wrapper" | ||||
|                 > | ||||
|                     <NotebookEmbed | ||||
|                         v-for="embed in entry.embeds" | ||||
|                         ref="embeds" | ||||
|                         :key="embed.id" | ||||
|                         :embed="embed" | ||||
|                         :is-locked="isLocked" | ||||
|                         @removeEmbed="removeEmbed" | ||||
|                         @updateEmbed="updateEmbed" | ||||
|                     /> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
|     <div | ||||
|         v-if="!readOnly && !isLocked" | ||||
|         class="c-ne__local-controls--hidden" | ||||
|     > | ||||
|         <button | ||||
|             class="c-icon-button c-icon-button--major icon-trash" | ||||
|             title="Delete this entry" | ||||
|             tabindex="-1" | ||||
|             @click="deleteEntry" | ||||
|         > | ||||
|         </button> | ||||
|     </div> | ||||
|     <div | ||||
|         v-if="readOnly" | ||||
|         class="c-ne__section-and-page" | ||||
| @@ -147,6 +156,8 @@ import TextHighlight from '../../../utils/textHighlight/TextHighlight.vue'; | ||||
| import { createNewEmbed } from '../utils/notebook-entries'; | ||||
| import { saveNotebookImageDomainObject, updateNamespaceOfDomainObject } from '../utils/notebook-image'; | ||||
|  | ||||
| import _ from 'lodash'; | ||||
|  | ||||
| import Moment from 'moment'; | ||||
|  | ||||
| const UNKNOWN_USER = 'Unknown'; | ||||
| @@ -211,6 +222,11 @@ export default { | ||||
|             required: true | ||||
|         } | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             enableEmbedsWrapperScroll: false | ||||
|         }; | ||||
|     }, | ||||
|     computed: { | ||||
|         createdOnDate() { | ||||
|             return this.formatTime(this.entry.createdOn, 'YYYY-MM-DD'); | ||||
| @@ -246,8 +262,21 @@ export default { | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.manageEmbedLayout = _.debounce(this.manageEmbedLayout, 400); | ||||
|  | ||||
|         if (this.$refs.embedsWrapper) { | ||||
|             this.embedsWrapperResizeObserver = new ResizeObserver(this.manageEmbedLayout); | ||||
|             this.embedsWrapperResizeObserver.observe(this.$refs.embedsWrapper); | ||||
|         } | ||||
|  | ||||
|         this.manageEmbedLayout(); | ||||
|         this.dropOnEntry = this.dropOnEntry.bind(this); | ||||
|     }, | ||||
|     beforeDestroy() { | ||||
|         if (this.embedsWrapperResizeObserver) { | ||||
|             this.embedsWrapperResizeObserver.unobserve(this.$refs.embedsWrapper); | ||||
|         } | ||||
|     }, | ||||
|     methods: { | ||||
|         async addNewEmbed(objectPath) { | ||||
|             const bounds = this.openmct.time.bounds(); | ||||
| @@ -259,6 +288,8 @@ export default { | ||||
|             }; | ||||
|             const newEmbed = await createNewEmbed(snapshotMeta); | ||||
|             this.entry.embeds.push(newEmbed); | ||||
|  | ||||
|             this.manageEmbedLayout(); | ||||
|         }, | ||||
|         cancelEditMode(event) { | ||||
|             const isEditing = this.openmct.editor.isEditing(); | ||||
| @@ -279,6 +310,17 @@ export default { | ||||
|         deleteEntry() { | ||||
|             this.$emit('deleteEntry', this.entry.id); | ||||
|         }, | ||||
|         manageEmbedLayout() { | ||||
|             if (this.$refs.embeds) { | ||||
|                 const embedsWrapperLength = this.$refs.embedsWrapper.clientWidth; | ||||
|                 const embedsTotalWidth = this.$refs.embeds.reduce((total, embed) => { | ||||
|                     return embed.$el.clientWidth + total; | ||||
|                 }, 0); | ||||
|  | ||||
|                 this.enableEmbedsWrapperScroll = embedsTotalWidth > embedsWrapperLength; | ||||
|             } | ||||
|  | ||||
|         }, | ||||
|         async dropOnEntry($event) { | ||||
|             $event.stopImmediatePropagation(); | ||||
|  | ||||
| @@ -336,6 +378,8 @@ export default { | ||||
|             this.entry.embeds.splice(embedPosition, 1); | ||||
|  | ||||
|             this.timestampAndUpdate(); | ||||
|  | ||||
|             this.manageEmbedLayout(); | ||||
|         }, | ||||
|         updateEmbed(newEmbed) { | ||||
|             this.entry.embeds.some(e => { | ||||
|   | ||||
| @@ -463,6 +463,8 @@ $transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3); | ||||
| $createBtnTextTransform: uppercase; | ||||
| $colorDiscreteItemBg: rgba($colorBodyFg,0.1); | ||||
| $colorDiscreteItemCurrentBg: rgba($colorOk,0.3); | ||||
| $scrollContainer: $colorBodyBg; | ||||
| ; | ||||
|  | ||||
| @mixin discreteItem() { | ||||
|     background: $colorDiscreteItemBg; | ||||
|   | ||||
| @@ -467,6 +467,7 @@ $transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3); | ||||
| $createBtnTextTransform: uppercase; | ||||
| $colorDiscreteItemBg: rgba($colorBodyFg,0.1); | ||||
| $colorDiscreteItemCurrentBg: rgba($colorOk,0.3); | ||||
| $scrollContainer: $colorBodyBg; | ||||
|  | ||||
| @mixin discreteItem() { | ||||
|     background: rgba($colorBodyFg,0.1); | ||||
|   | ||||
| @@ -463,6 +463,7 @@ $transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3); | ||||
| $createBtnTextTransform: uppercase; | ||||
| $colorDiscreteItemBg: rgba($colorBodyFg,0.1); | ||||
| $colorDiscreteItemCurrentBg: rgba($colorOk,0.3); | ||||
| $scrollContainer: rgba(102, 102, 102, 0.1); | ||||
|  | ||||
| @mixin discreteItem() { | ||||
|     background: $colorDiscreteItemBg; | ||||
|   | ||||
| @@ -327,3 +327,6 @@ $bg-icon-timelist: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://ww | ||||
| $bg-icon-plot-scatter: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cg data-name='Layer 2'%3e%3cpath d='M96 0C43.2 0 0 43.2 0 96v320c0 52.8 43.2 96 96 96h320c52.8 0 96-43.2 96-96V96c0-52.8-43.2-96-96-96ZM64 176a48 48 0 1 1 48 48 48 48 0 0 1-48-48Zm80 240a48 48 0 1 1 48-48 48 48 0 0 1-48 48Zm128-96a48 48 0 1 1 48-48 48 48 0 0 1-48 48Zm0-160a48 48 0 1 1 48-48 48 48 0 0 1-48 48Zm128 256a48 48 0 1 1 48-48 48 48 0 0 1-48 48Z' data-name='Layer 1'/%3e%3c/g%3e%3c/svg%3e"); | ||||
| $bg-icon-notebook-shift-log: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath d='M448 55.36c0-39.95-27.69-63.66-61.54-52.68L0 128h448V55.36ZM448 160H0v288c0 35.2 28.8 64 64 64h384c35.2 0 64-28.8 64-64V224c0-35.2-28.8-64-64-64ZM128 416H64v-64h64v64Zm0-96H64v-64h64v64Zm320 96H192v-64h256v64Zm0-96H192v-64h256v64Z'/%3e%3c/svg%3e"); | ||||
| $bg-icon-telemetry-aggregate: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cg data-name='Layer 2'%3e%3cg data-name='Layer 3'%3e%3cpath d='M39 197.72c7-20.72 18.74-50.4 34.6-74.18C92.91 94.65 114.79 80 138.67 80s45.75 14.65 65 43.54c15.86 23.78 27.57 53.46 34.6 74.18 15.44 45.48 31.56 67.49 39 73.27 7.47-5.78 23.6-27.79 39-73.27 7-20.72 18.74-50.4 34.61-74.18q13.9-20.85 29.56-31.75A207.78 207.78 0 0 0 208 0C93.12 0 0 93.12 0 208a208.14 208.14 0 0 0 7.39 55.09c8.39-10.87 20.2-31.67 31.61-65.37Z'/%3e%3cpath d='M377 218.28c-7 20.72-18.74 50.4-34.6 74.18-19.28 28.89-41.16 43.54-65 43.54s-45.75-14.65-65-43.54c-15.86-23.78-27.57-53.46-34.6-74.18-15.44-45.48-31.57-67.49-39-73.27-7.47 5.78-23.6 27.79-39 73.27-7.19 20.72-18.9 50.4-34.8 74.18q-13.9 20.85-29.56 31.75A207.78 207.78 0 0 0 208 416c114.88 0 208-93.12 208-208a208.14 208.14 0 0 0-7.39-55.09c-8.39 10.87-20.2 31.67-31.61 65.37Z'/%3e%3cpath d='M460.78 167.31A258.4 258.4 0 0 1 464 208a255.84 255.84 0 0 1-256 256 258.4 258.4 0 0 1-40.69-3.22A207.23 207.23 0 0 0 304 512c114.88 0 208-93.12 208-208a207.23 207.23 0 0 0-51.22-136.69Z'/%3e%3c/g%3e%3c/g%3e%3c/svg%3e"); | ||||
| $bg-icon-trash: url("data:image/svg+xml;charset=UTF-8,%3csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='512px' height='512px' viewBox='0 0 512 512' enable-background='new 0 0 512 512' xml:space='preserve'%3e%3cpath d='M416,64h-96.18V32c0-17.6-14.4-32-32-32h-64c-17.6,0-32,14.4-32,32v32H96c-52.8,0-96,36-96,80s0,80,0,80h32v192 c0,52.8,43.2,96,96,96h256c52.8,0,96-43.2,96-96V224h32c0,0,0-36,0-80S468.8,64,416,64z M160,416H96V224h64V416z M288,416h-64V224 h64V416z M416,416h-64V224h64V416z'/%3e%3c/svg%3e"); | ||||
| $bg-icon-eye-open: url("data:image/svg+xml;charset=UTF-8,%3csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 512 512' style='enable-background:new 0 0 512 512;' xml:space='preserve'%3e%3cstyle type='text/css'%3e .st0%7bfill:%2300A14B;%7d %3c/style%3e%3ctitle%3eicon-eye-open-v2%3c/title%3e%3cg%3e%3cpath class='st0' d='M256,58.2c-122.9,0-226.1,84-255.4,197.8C29.9,369.7,133.1,453.8,256,453.8s226.1-84,255.4-197.8 C482.1,142.3,378.9,58.2,256,58.2z M414.6,294.2c-11.3,17.2-25.3,32.4-41.5,45.2c-16.4,12.9-34.5,22.8-54,29.7 c-20.2,7.1-41.4,10.7-63,10.7s-42.9-3.6-63-10.7c-19.5-6.9-37.7-16.9-54-29.7c-16.2-12.8-30.2-27.9-41.5-45.2 c-7.9-12-14.4-24.8-19.3-38.2c5-13.4,11.5-26.2,19.3-38.2c11.3-17.2,25.3-32.4,41.5-45.2c16.4-12.9,34.5-22.8,54-29.7 c20.2-7.1,41.4-10.7,63-10.7s42.9,3.6,63,10.7c19.5,6.9,37.7,16.9,54,29.7c16.2,12.8,30.2,27.9,41.5,45.2 c7.9,12,14.4,24.8,19.3,38.2C429,269.4,422.5,282.2,414.6,294.2z'/%3e%3ccircle class='st0' cx='256' cy='256' r='96'/%3e%3c/g%3e%3c/svg%3e"); | ||||
| $bg-icon-camera: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3ctitle%3eicon-camera-v2%3c/title%3e%3cpath d='M448,128H384L320,0H192L128,128H64A64.2,64.2,0,0,0,0,192V448a64.2,64.2,0,0,0,64,64H448a64.2,64.2,0,0,0,64-64V192A64.2,64.2,0,0,0,448,128ZM256,432A128,128,0,1,1,384,304,128,128,0,0,1,256,432Z'/%3e%3c/svg%3e"); | ||||
|   | ||||
| @@ -462,6 +462,15 @@ input[type=number].c-input-number--no-spinners { | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-scrollcontainer{ | ||||
|     @include nice-input(); | ||||
|     margin-top: $interiorMargin; | ||||
|     background: $scrollContainer; | ||||
|     border-radius: $controlCr; | ||||
|     overflow: auto; | ||||
|     padding: $interiorMarginSm; | ||||
| } | ||||
|  | ||||
| // SELECTS | ||||
| select { | ||||
|     @include appearanceNone(); | ||||
|   | ||||
| @@ -265,3 +265,6 @@ | ||||
| .bg-icon-plot-scatter { @include glyphBg($bg-icon-plot-scatter); } | ||||
| .bg-icon-notebook-shift-log { @include glyphBg($bg-icon-notebook-shift-log); } | ||||
| .bg-icon-telemetry-aggregate { @include glyphBg($bg-icon-telemetry-aggregate); } | ||||
| .bg-icon-trash { @include glyphBg($bg-icon-trash); } | ||||
| .bg-icon-eye-open { @include glyphBg($bg-icon-eye-open); } | ||||
| .bg-icon-camera { @include glyphBg($bg-icon-camera); } | ||||
|   | ||||
| @@ -303,11 +303,25 @@ | ||||
|         opacity: 0.7; | ||||
|     } | ||||
|  | ||||
|     &__time-and-creator, | ||||
|     &__time-and-creator-and-delete, | ||||
|     &__input { | ||||
|         padding: $p; | ||||
|     } | ||||
|  | ||||
|     &__input{ | ||||
|         word-break: break-word; | ||||
|     } | ||||
|     &__time-and-creator-and-delete{ | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|  | ||||
|         > * + *{ | ||||
|             float: right; | ||||
|             margin-left: auto; | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     &__creator [class*='icon'] { | ||||
|         font-size: 0.95em; | ||||
|     } | ||||
| @@ -315,6 +329,7 @@ | ||||
|     &__time-and-content { | ||||
|         display: block; | ||||
|         flex: 1 1 auto; | ||||
|         overflow: visible; | ||||
|  | ||||
|         > * + * { | ||||
|             margin-top: $interiorMarginSm; | ||||
| @@ -332,9 +347,10 @@ | ||||
|     } | ||||
|  | ||||
|     &__content { | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         flex: 1 1 auto; | ||||
|         margin-right: $interiorMarginSm; | ||||
|         margin-top: $interiorMargin; | ||||
|  | ||||
|         > [class*="__"] + [class*="__"] { | ||||
|             margin-top: $interiorMarginSm; | ||||
| @@ -358,7 +374,8 @@ | ||||
|         @include inlineInput; | ||||
|         padding-left: $p; | ||||
|         padding-right: $p; | ||||
|  | ||||
|         overflow: unset; | ||||
|         margin-bottom: $interiorMargin; | ||||
|         @include hover { | ||||
|             &:not(:focus, .locked) { | ||||
|                 background: rgba($colorBodyFg, 0.1); | ||||
| @@ -394,12 +411,17 @@ | ||||
|             opacity: 0.7; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     &__remove{ | ||||
|         float: right; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| /****************************** EMBEDS */ | ||||
| @mixin snapThumb() { | ||||
|     // LEGACY: TODO: refactor when .snap-thumb in New Entry dialog is refactored | ||||
|     $d: 30px; | ||||
|     $d: 40px; | ||||
|     border: 1px solid $colorInteriorBorder; | ||||
|     cursor: pointer; | ||||
|     width: $d; | ||||
| @@ -417,21 +439,24 @@ | ||||
|     // LEGACY, | ||||
|     @include snapThumb(); | ||||
| } | ||||
| .c-ne__embeds-wrapper{ | ||||
|     max-height: 75px; | ||||
|     padding-left: $interiorMargin; | ||||
|     padding-top: $interiorMargin; | ||||
|     display: flex; | ||||
| } | ||||
|  | ||||
| .c-ne__embed { | ||||
|     @include discreteItemInnerElem(); | ||||
|     display: inline-flex; | ||||
|     flex: 0 0 auto; | ||||
|     padding: $interiorMargin; | ||||
|  | ||||
|     [class*="__"] + [class*="__"] { | ||||
|         margin-left: $interiorMargin; | ||||
|     } | ||||
|     border: 1px solid $colorInteriorBorder; | ||||
|  | ||||
|     &__info { | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|  | ||||
|         margin-left: $interiorMargin; | ||||
|         a { | ||||
|             color: $colorKey; | ||||
|         } | ||||
| @@ -445,9 +470,10 @@ | ||||
|     } | ||||
|  | ||||
|     &__link { | ||||
|         flex: 1 1 auto; | ||||
|         &:before { | ||||
|             display: block; | ||||
|             font-size: 0.85em; | ||||
|             font-size: 1em; | ||||
|             margin-right: $interiorMarginSm; | ||||
|         } | ||||
|     } | ||||
| @@ -460,6 +486,24 @@ | ||||
|     &__snap-thumb { | ||||
|         @include snapThumb(); | ||||
|     } | ||||
|     &__actions{ | ||||
|         margin: $interiorMarginSm; | ||||
|     } | ||||
|     &__actions-menu { | ||||
|         width: 55vh; | ||||
|         max-width: 500px;  | ||||
|         height: 130px; | ||||
|         z-index: 70; | ||||
|         [class*="__icon"] { | ||||
|             filter: $colorKeyFilter; | ||||
|             margin: 0%; | ||||
|             height: 4vh; | ||||
|         } | ||||
|         [class*="__item-description"] { | ||||
|             min-width: 200px;          | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| /****************************** SNAPSHOTTING */ | ||||
| @@ -700,6 +744,7 @@ body.mobile { | ||||
|     .c-notebook__entry { | ||||
|         [class*="local-controls"] { | ||||
|             display: none; | ||||
|             height: fit-content; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -37,7 +37,7 @@ | ||||
|         title="Add new tag" | ||||
|         @click="addTag" | ||||
|     > | ||||
|         <div class="c-icon-button__label">Add Tag</div> | ||||
|         <div class="c-icon-button__label c-tag-btn__label">Add Tag</div> | ||||
|     </button> | ||||
| </div> | ||||
| </template> | ||||
|   | ||||
| @@ -54,6 +54,10 @@ | ||||
|   } | ||||
| } | ||||
|  | ||||
| .c-tag-btn__label { | ||||
|   overflow: visible!important; | ||||
| } | ||||
|  | ||||
| /******************************* HOVERS */ | ||||
| .has-tag-applier { | ||||
|   // Apply this class to all components that should trigger tag removal btn on hover | ||||
|   | ||||
		Reference in New Issue
	
	Block a user