mirror of
https://github.com/nasa/openmct.git
synced 2025-03-25 13:28:38 +00:00
Cancel annotation selections if you click outside the plot component (#6476)
* resolve conflicts * resolve conflicts * more selectively add listeners * add and fix tests * address PR review comments * test(e2e): stabilize flaky overlayPlot test --------- Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com> Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov>
This commit is contained in:
parent
a1ac209d74
commit
00353cdccf
@ -268,6 +268,9 @@ async function getCanvasPixelsWithData(page) {
|
||||
* @param {import('@playwright/test').Page} page
|
||||
*/
|
||||
async function assertLimitLinesExistAndAreVisible(page) {
|
||||
// Wait for plot series data to load
|
||||
await expect(page.locator('.js-series-data-loaded')).toBeVisible();
|
||||
// Wait for limit lines to be created
|
||||
await page.waitForSelector('.js-limit-area', { state: 'attached' });
|
||||
const limitLineCount = await page.locator('.c-plot-limit-line').count();
|
||||
// There should be 10 limit lines created by default
|
||||
|
@ -28,6 +28,14 @@ const { test, expect } = require('../../../../pluginFixtures');
|
||||
const { createDomainObjectWithDefaults, setRealTimeMode, setFixedTimeMode } = require('../../../../appActions');
|
||||
|
||||
test.describe('Plot Tagging', () => {
|
||||
/**
|
||||
* Given a canvas and a set of points, tags the points on the canvas.
|
||||
* @param {import('@playwright/test').Page} page
|
||||
* @param {HTMLCanvasElement} canvas a telemetry item with a plot
|
||||
* @param {Number} xEnd a telemetry item with a plot
|
||||
* @param {Number} yEnd a telemetry item with a plot
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async function createTags({page, canvas, xEnd, yEnd}) {
|
||||
await canvas.hover({trial: true});
|
||||
|
||||
@ -64,12 +72,20 @@ test.describe('Plot Tagging', () => {
|
||||
await page.getByText('Science').click();
|
||||
}
|
||||
|
||||
async function testTelemetryItem(page, canvas, telemetryItem) {
|
||||
/**
|
||||
* Given a telemetry item (e.g., a Sine Wave Generator) with a plot, tests that the plot can be tagged.
|
||||
* @param {import('@playwright/test').Page} page
|
||||
* @param {import('../../../../appActions').CreatedObjectInfo} telemetryItem a telemetry item with a plot
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async function testTelemetryItem(page, telemetryItem) {
|
||||
// Check that telemetry item also received the tag
|
||||
await page.goto(telemetryItem.url);
|
||||
|
||||
await expect(page.getByText('No tags to display for this item')).toBeVisible();
|
||||
|
||||
const canvas = page.locator('canvas').nth(1);
|
||||
|
||||
//Wait for canvas to stablize.
|
||||
await canvas.hover({trial: true});
|
||||
|
||||
@ -85,19 +101,31 @@ test.describe('Plot Tagging', () => {
|
||||
await expect(page.getByText('Driving')).toBeHidden();
|
||||
}
|
||||
|
||||
async function basicTagsTests(page, canvas) {
|
||||
// Search for Science
|
||||
/**
|
||||
* Given a page, tests that tags are searchable, deletable, and persist across reloads.
|
||||
* @param {import('@playwright/test').Page} page
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async function basicTagsTests(page) {
|
||||
// Search for Driving
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc');
|
||||
await expect(page.locator('[aria-label="Search Result"]').nth(0)).toContainText("Science");
|
||||
await expect(page.locator('[aria-label="Search Result"]').nth(0)).not.toContainText("Drilling");
|
||||
|
||||
// Clicking elsewhere should cause annotation selection to be cleared
|
||||
await expect(page.getByText('No tags to display for this item')).toBeVisible();
|
||||
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('driv');
|
||||
// click on the search result
|
||||
await page.getByRole('searchbox', { name: 'OpenMCT Search' }).getByText(/Sine Wave/).first().click();
|
||||
|
||||
// Delete Driving
|
||||
await page.hover('[aria-label="Tag"]:has-text("Driving")');
|
||||
await page.locator('[aria-label="Remove tag Driving"]').click();
|
||||
|
||||
await expect(page.locator('[aria-label="Tags Inspector"]')).toContainText("Science");
|
||||
await expect(page.locator('[aria-label="Tags Inspector"]')).not.toContainText("Driving");
|
||||
// Search for Science
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc');
|
||||
await expect(page.locator('[aria-label="Search Result"]').nth(0)).toContainText("Science");
|
||||
await expect(page.locator('[aria-label="Search Result"]').nth(0)).not.toContainText("Drilling");
|
||||
|
||||
// Search for Driving
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
|
||||
@ -109,12 +137,13 @@ test.describe('Plot Tagging', () => {
|
||||
page.reload(),
|
||||
page.waitForLoadState('networkidle')
|
||||
]);
|
||||
// wait for plot progress bar to disappear
|
||||
await page.locator('.l-view-section.c-progress-bar').waitFor({ state: 'detached' });
|
||||
// wait for plots to load
|
||||
await expect(page.locator('.js-series-data-loaded')).toBeVisible();
|
||||
|
||||
await page.getByText('Annotations').click();
|
||||
await expect(page.getByText('No tags to display for this item')).toBeVisible();
|
||||
|
||||
const canvas = page.locator('canvas').nth(1);
|
||||
// click on the tagged plot point
|
||||
await canvas.click({
|
||||
position: {
|
||||
@ -171,8 +200,8 @@ test.describe('Plot Tagging', () => {
|
||||
// changing to fixed time mode rebuilds canvas?
|
||||
canvas = page.locator('canvas').nth(1);
|
||||
|
||||
await basicTagsTests(page, canvas);
|
||||
await testTelemetryItem(page, canvas, alphaSineWave);
|
||||
await basicTagsTests(page);
|
||||
await testTelemetryItem(page, alphaSineWave);
|
||||
|
||||
// set to real time mode
|
||||
await setRealTimeMode(page);
|
||||
@ -182,8 +211,8 @@ test.describe('Plot Tagging', () => {
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc');
|
||||
// click on the search result
|
||||
await page.getByRole('searchbox', { name: 'OpenMCT Search' }).getByText('Alpha Sine Wave').first().click();
|
||||
// wait for plot progress bar to disappear
|
||||
await page.locator('.l-view-section.c-progress-bar').waitFor({ state: 'detached' });
|
||||
// wait for plots to load
|
||||
await expect(page.locator('.js-series-data-loaded')).toBeVisible();
|
||||
// expect plot to be paused
|
||||
await expect(page.locator('[title="Resume displaying real-time data"]')).toBeVisible();
|
||||
|
||||
@ -202,7 +231,7 @@ test.describe('Plot Tagging', () => {
|
||||
xEnd: 700,
|
||||
yEnd: 480
|
||||
});
|
||||
await basicTagsTests(page, canvas);
|
||||
await basicTagsTests(page);
|
||||
});
|
||||
|
||||
test('Tags work with Stacked Plots', async ({ page }) => {
|
||||
@ -232,7 +261,7 @@ test.describe('Plot Tagging', () => {
|
||||
xEnd: 700,
|
||||
yEnd: 215
|
||||
});
|
||||
await basicTagsTests(page, canvas);
|
||||
await testTelemetryItem(page, canvas, alphaSineWave);
|
||||
await basicTagsTests(page);
|
||||
await testTelemetryItem(page, alphaSineWave);
|
||||
});
|
||||
});
|
||||
|
@ -43,7 +43,7 @@
|
||||
</div>
|
||||
<div
|
||||
v-if="!hideOptions && filteredOptions.length > 0"
|
||||
class="c-menu c-input--autocomplete__options"
|
||||
class="c-menu c-input--autocomplete__options js-autocomplete-options"
|
||||
aria-label="Autocomplete Options"
|
||||
@blur="hideOptions = true"
|
||||
>
|
||||
|
@ -22,7 +22,9 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="loaded"
|
||||
ref="plot"
|
||||
class="gl-plot"
|
||||
:class="{ 'js-series-data-loaded' : seriesDataLoaded }"
|
||||
>
|
||||
<slot></slot>
|
||||
<div class="plot-wrapper-axis-and-display-area flex-elem grows">
|
||||
@ -347,6 +349,9 @@ export default {
|
||||
const parentLeftTickWidth = this.parentYTickWidth.leftTickWidth;
|
||||
|
||||
return parentLeftTickWidth || leftTickWidth;
|
||||
},
|
||||
seriesDataLoaded() {
|
||||
return ((this.pending === 0) && this.loaded);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -412,6 +417,7 @@ export default {
|
||||
this.openmct.selection.off('change', this.updateSelection);
|
||||
document.removeEventListener('keydown', this.handleKeyDown);
|
||||
document.removeEventListener('keyup', this.handleKeyUp);
|
||||
document.body.removeEventListener('click', this.cancelSelection);
|
||||
this.destroy();
|
||||
},
|
||||
methods: {
|
||||
@ -444,6 +450,19 @@ export default {
|
||||
//This section is common to all entry points for annotation display
|
||||
this.prepareExistingAnnotationSelection(selectedAnnotations);
|
||||
},
|
||||
cancelSelection(event) {
|
||||
if (this.$refs?.plot) {
|
||||
const clickedInsidePlot = this.$refs.plot.contains(event.target);
|
||||
const clickedInsideInspector = event.target.closest('.js-inspector') !== null;
|
||||
const clickedOption = event.target.closest('.js-autocomplete-options') !== null;
|
||||
if (!clickedInsidePlot && !clickedInsideInspector && !clickedOption) {
|
||||
this.rectangles = [];
|
||||
this.annotationSelections = [];
|
||||
this.selectPlot();
|
||||
document.body.removeEventListener('click', this.cancelSelection);
|
||||
}
|
||||
}
|
||||
},
|
||||
waitForAxesToLoad() {
|
||||
return new Promise(resolve => {
|
||||
// When there is no plot data, the ranges can be undefined
|
||||
@ -1276,6 +1295,8 @@ export default {
|
||||
}
|
||||
|
||||
this.openmct.selection.select(selection, true);
|
||||
|
||||
document.body.addEventListener('click', this.cancelSelection);
|
||||
},
|
||||
selectNewPlotAnnotations(boundingBoxPerYAxis, pointsInBox, event) {
|
||||
let targetDomainObjects = {};
|
||||
|
@ -21,7 +21,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div class="c-inspector">
|
||||
<div class="c-inspector js-inspector">
|
||||
<object-name />
|
||||
<InspectorTabs
|
||||
:selection="selection"
|
||||
|
Loading…
x
Reference in New Issue
Block a user