From 1ca5271c3e80c1d24a176499c7a467dafc7de261 Mon Sep 17 00:00:00 2001 From: Michael Rogers Date: Fri, 20 May 2022 12:26:54 -0500 Subject: [PATCH 01/13] e2e test for image thumbnail visibility and size - 5106 (#5232) * e2e test for timage thumbnail visibility and size * Lint fix * Remove URL comment * Added comment and assigned selectors to var --- .../imagery/exampleImagery.e2e.spec.js | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js b/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js index ef31628c61..ed12d6b14b 100644 --- a/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js +++ b/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js @@ -344,6 +344,97 @@ test('Example Imagery in Display layout', async ({ page }) => { expect(backgroundImageUrl2 >= backgroundImageUrl1); }); +test.describe('Example imagery thumbnails resize in display layouts', () => { + + test('Resizing the layout changes thumbnail visibility and size', async ({ page }) => { + await page.goto('/', { waitUntil: 'networkidle' }); + + const thumbsWrapperLocator = await page.locator('.c-imagery__thumbs-wrapper'); + // Click button:has-text("Create") + await page.locator('button:has-text("Create")').click(); + + // Click li:has-text("Display Layout") + await page.locator('li:has-text("Display Layout")').click(); + const displayLayoutTitleField = page.locator('text=Properties Title Notes Horizontal grid (px) Vertical grid (px) Horizontal size ( >> input[type="text"]'); + await displayLayoutTitleField.click(); + + await displayLayoutTitleField.fill('Thumbnail Display Layout'); + + // Click text=OK + await Promise.all([ + page.waitForNavigation(), + page.locator('text=OK').click() + ]); + + // Click text=Snapshot Save and Finish Editing Save and Continue Editing >> button >> nth=1 + await page.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button').nth(1).click(); + + // Click text=Save and Finish Editing + await page.locator('text=Save and Finish Editing').click(); + + // Click button:has-text("Create") + await page.locator('button:has-text("Create")').click(); + + // Click li:has-text("Example Imagery") + await page.locator('li:has-text("Example Imagery")').click(); + + const imageryTitleField = page.locator('text=Properties Title Notes Images url list (comma separated) Image load delay (milli >> input[type="text"]'); + // Click text=Properties Title Notes Images url list (comma separated) Image load delay (milli >> input[type="text"] + await imageryTitleField.click(); + + // Fill text=Properties Title Notes Images url list (comma separated) Image load delay (milli >> input[type="text"] + await imageryTitleField.fill('Thumbnail Example Imagery'); + + // Click text=OK + await Promise.all([ + page.waitForNavigation(), + page.locator('text=OK').click() + ]); + + // Click text=Thumbnail Example Imagery Imagery Layout Snapshot >> button >> nth=0 + await Promise.all([ + page.waitForNavigation(), + page.locator('text=Thumbnail Example Imagery Imagery Layout Snapshot >> button').first().click() + ]); + + // Edit mode + await page.locator('text=Thumbnail Display Layout Snapshot >> button').nth(3).click(); + + // Click on example imagery to expose toolbar + await page.locator('text=Thumbnail Example Imagery Snapshot Large View').click(); + + // expect thumbnails not be visible when first added + await expect.soft(thumbsWrapperLocator.isHidden()).toBeTruthy(); + + // Resize the example imagery vertically to change the thumbnail visibility + /* + The following arbitrary values are added to observe the separate visual + conditions of the thumbnails (hidden, small thumbnails, regular thumbnails). + Specifically, height is set to 50px for small thumbs and 100px for regular + */ + // Click #mct-input-id-103 + await page.locator('#mct-input-id-103').click(); + + // Fill #mct-input-id-103 + await page.locator('#mct-input-id-103').fill('50'); + + expect(thumbsWrapperLocator.isVisible()).toBeTruthy(); + await expect(thumbsWrapperLocator).toHaveClass(/is-small-thumbs/); + + // Resize the example imagery vertically to change the thumbnail visibility + // Click #mct-input-id-103 + await page.locator('#mct-input-id-103').click(); + + // Fill #mct-input-id-103 + await page.locator('#mct-input-id-103').fill('100'); + + expect(thumbsWrapperLocator.isVisible()).toBeTruthy(); + await expect(thumbsWrapperLocator).not.toHaveClass(/is-small-thumbs/); + + }); + +}); + test.describe('Example Imagery in Flexible layout', () => { test.fixme('Can use Mouse Wheel to zoom in and out of previous image'); test.fixme('Can use alt+drag to move around image once zoomed in'); From 48916564e4aed5c609b9fd4b89f2e2cc44c078c2 Mon Sep 17 00:00:00 2001 From: Shefali Joshi Date: Fri, 20 May 2022 11:41:01 -0700 Subject: [PATCH 02/13] Refactor plot actions to save space (#5201) * Move image export actions to 3-dot menu * Move cursor guide and toggle grid lines to local controls for plots (on hover) * toggle cursor and gridlines affect all plots in a stacked plot * Fix tests * Better message when exporting plots, fixed typo Co-authored-by: Joe Pea Co-authored-by: Charles Hacskaylo --- src/exporters/ImageExporter.js | 2 +- src/plugins/plot/MctPlot.vue | 42 ++++++++++++-- src/plugins/plot/Plot.vue | 52 +++-------------- src/plugins/plot/PlotViewProvider.js | 9 ++- src/plugins/plot/actions/ViewActions.js | 57 +++++++++++++++++++ src/plugins/plot/actions/utils.js | 3 + .../overlayPlot/OverlayPlotViewProvider.js | 9 ++- src/plugins/plot/plugin.js | 6 +- src/plugins/plot/pluginSpec.js | 14 ++--- src/plugins/plot/stackedPlot/StackedPlot.vue | 57 +++++-------------- .../plot/stackedPlot/StackedPlotItem.vue | 12 +++- .../stackedPlot/StackedPlotViewProvider.js | 9 ++- 12 files changed, 168 insertions(+), 104 deletions(-) create mode 100644 src/plugins/plot/actions/ViewActions.js create mode 100644 src/plugins/plot/actions/utils.js diff --git a/src/exporters/ImageExporter.js b/src/exporters/ImageExporter.js index 5ff877cc61..22a9ed2e2e 100644 --- a/src/exporters/ImageExporter.js +++ b/src/exporters/ImageExporter.js @@ -51,7 +51,7 @@ class ImageExporter { const overlays = this.openmct.overlays; const dialog = overlays.dialog({ iconClass: 'info', - message: 'Caputuring an image', + message: 'Capturing image, please wait...', buttons: [ { label: 'Cancel', diff --git a/src/plugins/plot/MctPlot.vue b/src/plugins/plot/MctPlot.vue index ea5d8dd398..8ae4f08bf5 100644 --- a/src/plugins/plot/MctPlot.vue +++ b/src/plugins/plot/MctPlot.vue @@ -154,6 +154,22 @@ > +
+ + +
@@ -213,16 +229,16 @@ export default { }; } }, - gridLines: { + initGridLines: { type: Boolean, default() { return true; } }, - cursorGuide: { + initCursorGuide: { type: Boolean, default() { - return true; + return false; } }, plotTickWidth: { @@ -252,7 +268,9 @@ export default { isTimeOutOfSync: false, showLimitLineLabels: undefined, isFrozenOnMouseDown: false, - hasSameRangeValue: true + hasSameRangeValue: true, + cursorGuide: this.initCursorGuide, + gridLines: this.initGridLines }; }, computed: { @@ -273,6 +291,14 @@ export default { return this.plotTickWidth || this.tickWidth; } }, + watch: { + initGridLines(newGridLines) { + this.gridLines = newGridLines; + }, + initCursorGuide(newCursorGuide) { + this.cursorGuide = newCursorGuide; + } + }, mounted() { document.addEventListener('keydown', this.handleKeyDown); document.addEventListener('keyup', this.handleKeyUp); @@ -1130,6 +1156,14 @@ export default { }, legendHoverChanged(data) { this.showLimitLineLabels = data; + }, + toggleCursorGuide() { + this.cursorGuide = !this.cursorGuide; + this.$emit('cursorGuide', this.cursorGuide); + }, + toggleGridLines() { + this.gridLines = !this.gridLines; + this.$emit('gridLines', this.gridLines); } } }; diff --git a/src/plugins/plot/Plot.vue b/src/plugins/plot/Plot.vue index beb3b92456..2decf3a029 100644 --- a/src/plugins/plot/Plot.vue +++ b/src/plugins/plot/Plot.vue @@ -24,41 +24,6 @@ ref="plotWrapper" class="c-plot holder holder-plot has-control-bar" > -
- - - - - - -
' + template: '' }); }, + getViewContext() { + if (!component) { + return {}; + } + + return component.$refs.plotComponent.getViewContext(); + }, destroy: function () { component.$destroy(); component = undefined; diff --git a/src/plugins/plot/actions/ViewActions.js b/src/plugins/plot/actions/ViewActions.js new file mode 100644 index 0000000000..7ebf7fe726 --- /dev/null +++ b/src/plugins/plot/actions/ViewActions.js @@ -0,0 +1,57 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +import {isPlotView} from "@/plugins/plot/actions/utils"; + +const exportPNG = { + name: 'Export as PNG', + key: 'export-as-png', + description: 'Export This View\'s Data as PNG', + cssClass: 'c-icon-button icon-download', + group: 'view', + invoke(objectPath, view) { + view.getViewContext().exportPNG(); + } +}; + +const exportJPG = { + name: 'Export as JPG', + key: 'export-as-jpg', + description: 'Export This View\'s Data as JPG', + cssClass: 'c-icon-button icon-download', + group: 'view', + invoke(objectPath, view) { + view.getViewContext().exportJPG(); + } +}; + +const viewActions = [ + exportPNG, + exportJPG +]; + +viewActions.forEach(action => { + action.appliesTo = (objectPath, view = {}) => { + return isPlotView(view); + }; +}); + +export default viewActions; diff --git a/src/plugins/plot/actions/utils.js b/src/plugins/plot/actions/utils.js new file mode 100644 index 0000000000..2bebbecf4d --- /dev/null +++ b/src/plugins/plot/actions/utils.js @@ -0,0 +1,3 @@ +export function isPlotView(view) { + return view.key === 'plot-single' || view.key === 'plot-overlay' || view.key === 'plot-stacked'; +} diff --git a/src/plugins/plot/overlayPlot/OverlayPlotViewProvider.js b/src/plugins/plot/overlayPlot/OverlayPlotViewProvider.js index 3a70da2848..e34bb59d2e 100644 --- a/src/plugins/plot/overlayPlot/OverlayPlotViewProvider.js +++ b/src/plugins/plot/overlayPlot/OverlayPlotViewProvider.js @@ -65,9 +65,16 @@ export default function OverlayPlotViewProvider(openmct) { } }; }, - template: '' + template: '' }); }, + getViewContext() { + if (!component) { + return {}; + } + + return component.$refs.plotComponent.getViewContext(); + }, destroy: function () { component.$destroy(); component = undefined; diff --git a/src/plugins/plot/plugin.js b/src/plugins/plot/plugin.js index 93c3122ca5..89f6f005b7 100644 --- a/src/plugins/plot/plugin.js +++ b/src/plugins/plot/plugin.js @@ -25,6 +25,7 @@ import StackedPlotViewProvider from './stackedPlot/StackedPlotViewProvider'; import PlotsInspectorViewProvider from './inspector/PlotsInspectorViewProvider'; import OverlayPlotCompositionPolicy from './overlayPlot/OverlayPlotCompositionPolicy'; import StackedPlotCompositionPolicy from './stackedPlot/StackedPlotCompositionPolicy'; +import PlotViewActions from "./actions/ViewActions"; export default function () { return function install(openmct) { @@ -67,6 +68,9 @@ export default function () { openmct.composition.addPolicy(new OverlayPlotCompositionPolicy(openmct).allow); openmct.composition.addPolicy(new StackedPlotCompositionPolicy(openmct).allow); + + PlotViewActions.forEach(action => { + openmct.actions.register(action); + }); }; } - diff --git a/src/plugins/plot/pluginSpec.js b/src/plugins/plot/pluginSpec.js index f1a0e475b5..a78107ffee 100644 --- a/src/plugins/plot/pluginSpec.js +++ b/src/plugins/plot/pluginSpec.js @@ -724,16 +724,16 @@ describe("the plugin", function () { }); it("turns on cursor Guides all telemetry objects", (done) => { - expect(plotViewComponentObject.cursorGuide).toBeFalse(); - plotViewComponentObject.toggleCursorGuide(); + expect(plotViewComponentObject.$children[0].cursorGuide).toBeFalse(); + plotViewComponentObject.$children[0].cursorGuide = true; Vue.nextTick(() => { - expect(plotViewComponentObject.$children[0].component.$children[0].cursorGuide).toBeTrue(); + expect(plotViewComponentObject.$children[0].cursorGuide).toBeTrue(); done(); }); }); it("shows grid lines for all telemetry objects", () => { - expect(plotViewComponentObject.gridLines).toBeTrue(); + expect(plotViewComponentObject.$children[0].gridLines).toBeTrue(); let gridLinesContainer = element.querySelectorAll(".gl-plot-display-area .js-ticks"); let visible = 0; gridLinesContainer.forEach(el => { @@ -745,10 +745,10 @@ describe("the plugin", function () { }); it("hides grid lines for all telemetry objects", (done) => { - expect(plotViewComponentObject.gridLines).toBeTrue(); - plotViewComponentObject.toggleGridLines(); + expect(plotViewComponentObject.$children[0].gridLines).toBeTrue(); + plotViewComponentObject.$children[0].gridLines = false; Vue.nextTick(() => { - expect(plotViewComponentObject.gridLines).toBeFalse(); + expect(plotViewComponentObject.$children[0].gridLines).toBeFalse(); let gridLinesContainer = element.querySelectorAll(".gl-plot-display-area .js-ticks"); let visible = 0; gridLinesContainer.forEach(el => { diff --git a/src/plugins/plot/stackedPlot/StackedPlot.vue b/src/plugins/plot/stackedPlot/StackedPlot.vue index 1c63a0413d..1d409d1990 100644 --- a/src/plugins/plot/stackedPlot/StackedPlot.vue +++ b/src/plugins/plot/stackedPlot/StackedPlot.vue @@ -22,41 +22,6 @@