Merge branch 'master' of https://github.com/nasa/openmct into timelist-expanded-view

This commit is contained in:
Shefali 2024-01-25 11:59:31 -08:00
commit dc6945333f
18 changed files with 453 additions and 91 deletions

View File

@ -5,20 +5,20 @@ executors:
- image: mcr.microsoft.com/playwright:v1.39.0-focal
environment:
NODE_ENV: development # Needed to ensure 'dist' folder created and devDependencies installed
PERCY_POSTINSTALL_BROWSER: 'true' # Needed to store the percy browser in cache deps
PERCY_LOGLEVEL: 'debug' # Enable DEBUG level logging for Percy (Issue: https://github.com/nasa/openmct/issues/5742)
PERCY_POSTINSTALL_BROWSER: "true" # Needed to store the percy browser in cache deps
PERCY_LOGLEVEL: "debug" # Enable DEBUG level logging for Percy (Issue: https://github.com/nasa/openmct/issues/5742)
ubuntu:
machine:
image: ubuntu-2204:current
docker_layer_caching: true
parameters:
BUST_CACHE:
description: 'Set this with the CircleCI UI Trigger Workflow button (boolean = true) to bust the cache!'
description: "Set this with the CircleCI UI Trigger Workflow button (boolean = true) to bust the cache!"
default: false
type: boolean
commands:
build_and_install:
description: 'All steps used to build and install. Will use cache if found'
description: "All steps used to build and install. Will use cache if found"
parameters:
node-version:
type: string
@ -30,7 +30,7 @@ commands:
node-version: << parameters.node-version >>
- run: npm install --no-audit --progress=false
restore_cache_cmd:
description: 'Custom command for restoring cache with the ability to bust cache. When BUST_CACHE is set to true, jobs will not restore cache'
description: "Custom command for restoring cache with the ability to bust cache. When BUST_CACHE is set to true, jobs will not restore cache"
parameters:
node-version:
type: string
@ -42,7 +42,7 @@ commands:
- restore_cache:
key: deps--{{ arch }}--{{ .Branch }}--<< parameters.node-version >>--{{ checksum "package.json" }}-{{ checksum ".circleci/config.yml" }}
save_cache_cmd:
description: 'Custom command for saving cache.'
description: "Custom command for saving cache."
parameters:
node-version:
type: string
@ -53,7 +53,7 @@ commands:
- ~/.npm
- node_modules
generate_and_store_version_and_filesystem_artifacts:
description: 'Track important packages and files'
description: "Track important packages and files"
steps:
- run: |
[[ $EUID -ne 0 ]] && (sudo mkdir -p /tmp/artifacts && sudo chmod 777 /tmp/artifacts) || (mkdir -p /tmp/artifacts && chmod 777 /tmp/artifacts)
@ -64,7 +64,7 @@ commands:
- store_artifacts:
path: /tmp/artifacts/
generate_e2e_code_cov_report:
description: 'Generate e2e code coverage artifacts and publish to codecov.io. Needed to that we can ignore the exit code status of the npm run test'
description: "Generate e2e code coverage artifacts and publish to codecov.io. Needed to that we can ignore the exit code status of the npm run test"
parameters:
suite:
type: string
@ -129,7 +129,7 @@ jobs:
node-version: lts/hydrogen
- when: #Only install chrome-beta when running the 'full' suite to save $$$
condition:
equal: ['full', <<parameters.suite>>]
equal: ["full", <<parameters.suite>>]
steps:
- run: npx playwright install chrome-beta
- run: SHARD="$((${CIRCLE_NODE_INDEX}+1))"; npm run test:e2e:<<parameters.suite>> -- --shard=${SHARD}/${CIRCLE_NODE_TOTAL}
@ -251,8 +251,6 @@ workflows:
- e2e-test:
name: e2e-stable
suite: stable
- mem-test
- perf-test
- visual-a11y-tests:
name: visual-test-ci
suite: ci
@ -278,7 +276,7 @@ workflows:
- e2e-couchdb
triggers:
- schedule:
cron: '0 0 * * *'
cron: "0 0 * * *"
filters:
branches:
only:

58
.github/workflows/e2e-perf.yml vendored Normal file
View File

@ -0,0 +1,58 @@
name: 'e2e-perf'
on:
push:
branches: master
workflow_dispatch:
pull_request:
types:
- labeled
- opened
schedule:
- cron: '0 0 * * *'
jobs:
e2e-full:
if: contains(github.event.pull_request.labels.*.name, 'pr:e2e:perf') || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 'lts/hydrogen'
- name: Cache NPM dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npx playwright@1.39.0 install
- run: npm install --cache ~/.npm --no-audit --progress=false
- run: npm run test:perf:localhost
- run: npm run test:perf:contract
- run: npm run test:perf:memory
- name: Archive test results
if: success() || failure()
uses: actions/upload-artifact@v3
with:
path: test-results
- name: Remove pr:e2e:perf label (if present)
if: always()
uses: actions/github-script@v6
with:
script: |
const { owner, repo, number } = context.issue;
const labelToRemove = 'pr:e2e:perf';
try {
await github.rest.issues.removeLabel({
owner,
repo,
issue_number: number,
name: labelToRemove
});
} catch (error) {
core.warning(`Failed to remove ' + labelToRemove + ' label: ${error.message}`);
}

View File

@ -161,6 +161,13 @@ test.describe('Display Layout', () => {
const trimmedDisplayValue = displayLayoutValue.trim();
expect(trimmedDisplayValue).toBe(formattedTelemetryValue);
// ensure we can right click on the alpha-numeric widget and view historical data
await page.getByLabel('Sine', { exact: true }).click({
button: 'right'
});
await page.getByLabel('View Historical Data').click();
await expect(page.getByLabel('Plot Container Style Target')).toBeVisible();
});
test('alpha-numeric widget telemetry value exactly matches latest telemetry value received in fixed time', async ({
page

View File

@ -63,78 +63,80 @@ test.describe('Overlay Plot', () => {
await expect(seriesColorSwatch).toHaveCSS('background-color', 'rgb(255, 166, 61)');
});
test('Limit lines persist when series is moved to another Y Axis and on refresh', async ({
page
}) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/nasa/openmct/issues/6338'
});
// Create an Overlay Plot with a default SWG
const overlayPlot = await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot'
});
//skipping due to https://github.com/nasa/openmct/issues/7405
test.fixme(
'Limit lines persist when series is moved to another Y Axis and on refresh',
async ({ page }) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/nasa/openmct/issues/6338'
});
// Create an Overlay Plot with a default SWG
const overlayPlot = await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot'
});
const swgA = await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator',
parent: overlayPlot.uuid
});
const swgA = await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator',
parent: overlayPlot.uuid
});
await page.goto(overlayPlot.url);
await page.goto(overlayPlot.url);
// Assert that no limit lines are shown by default
await page.waitForSelector('.js-limit-area', { state: 'attached' });
expect(await page.locator('.c-plot-limit-line').count()).toBe(0);
// Assert that no limit lines are shown by default
await page.waitForSelector('.js-limit-area', { state: 'attached' });
expect(await page.locator('.c-plot-limit-line').count()).toBe(0);
// Enter edit mode
await page.getByLabel('Edit Object').click();
// Enter edit mode
await page.getByLabel('Edit Object').click();
// Expand the "Sine Wave Generator" plot series options and enable limit lines
await page.getByRole('tab', { name: 'Config' }).click();
await page
.getByRole('list', { name: 'Plot Series Properties' })
.locator('span')
.first()
.click();
await page
.getByRole('list', { name: 'Plot Series Properties' })
.locator('[title="Display limit lines"]~div input')
.check();
// Expand the "Sine Wave Generator" plot series options and enable limit lines
await page.getByRole('tab', { name: 'Config' }).click();
await page
.getByRole('list', { name: 'Plot Series Properties' })
.locator('span')
.first()
.click();
await page
.getByRole('list', { name: 'Plot Series Properties' })
.locator('[title="Display limit lines"]~div input')
.check();
await assertLimitLinesExistAndAreVisible(page);
await assertLimitLinesExistAndAreVisible(page);
// Save (exit edit mode)
await page.locator('button[title="Save"]').click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
// Save (exit edit mode)
await page.locator('button[title="Save"]').click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
await assertLimitLinesExistAndAreVisible(page);
await assertLimitLinesExistAndAreVisible(page);
await page.reload();
await page.reload();
await assertLimitLinesExistAndAreVisible(page);
await assertLimitLinesExistAndAreVisible(page);
// Enter edit mode
await page.getByLabel('Edit Object').click();
// Enter edit mode
await page.getByLabel('Edit Object').click();
await page.getByRole('tab', { name: 'Elements' }).click();
await page.getByRole('tab', { name: 'Elements' }).click();
// Drag Sine Wave Generator series from Y Axis 1 into Y Axis 2
await page
.locator(`#inspector-elements-tree >> text=${swgA.name}`)
.dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]'));
// Drag Sine Wave Generator series from Y Axis 1 into Y Axis 2
await page
.locator(`#inspector-elements-tree >> text=${swgA.name}`)
.dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]'));
await assertLimitLinesExistAndAreVisible(page);
await assertLimitLinesExistAndAreVisible(page);
// Save (exit edit mode)
await page.locator('button[title="Save"]').click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
// Save (exit edit mode)
await page.locator('button[title="Save"]').click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
await assertLimitLinesExistAndAreVisible(page);
await assertLimitLinesExistAndAreVisible(page);
await page.reload();
await page.reload();
await assertLimitLinesExistAndAreVisible(page);
});
await assertLimitLinesExistAndAreVisible(page);
}
);
test('The elements pool supports dragging series into multiple y-axis buckets', async ({
page

View File

@ -0,0 +1,125 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2023, 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 { createDomainObjectWithDefaults, expandEntireTree } from '../../../../appActions.js';
import { expect, test } from '../../../../pluginFixtures.js';
test.describe('Reload action', () => {
test.beforeEach(async ({ page }) => {
await page.goto('./', { waitUntil: 'domcontentloaded' });
const displayLayout = await createDomainObjectWithDefaults(page, {
type: 'Display Layout'
});
const alphaTable = await createDomainObjectWithDefaults(page, {
type: 'Telemetry Table',
name: 'Alpha Table'
});
const betaTable = await createDomainObjectWithDefaults(page, {
type: 'Telemetry Table',
name: 'Beta Table'
});
await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator',
parent: alphaTable.uuid,
customParameters: {
'[aria-label="Data Rate (hz)"]': '0.001'
}
});
await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator',
parent: betaTable.uuid,
customParameters: {
'[aria-label="Data Rate (hz)"]': '0.001'
}
});
await page.goto(displayLayout.url);
// Expand all folders
await expandEntireTree(page);
await page.getByLabel('Edit Object', { exact: true }).click();
await page.dragAndDrop(`text='Alpha Table'`, '.l-layout__grid-holder', {
targetPosition: { x: 0, y: 0 }
});
await page.dragAndDrop(`text='Beta Table'`, '.l-layout__grid-holder', {
targetPosition: { x: 0, y: 250 }
});
await page.locator('button[title="Save"]').click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
});
test('can reload display layout and its children', async ({ page }) => {
const beforeReloadAlphaTelemetryValue = await page
.getByLabel('Alpha Table table content')
.getByLabel('wavelengths table cell')
.first()
.getAttribute('title');
const beforeReloadBetaTelemetryValue = await page
.getByLabel('Beta Table table content')
.getByLabel('wavelengths table cell')
.first()
.getAttribute('title');
// reload alpha
await page.getByTitle('View menu items').first().click();
await page.getByRole('menuitem', { name: /Reload/ }).click();
const afterReloadAlphaTelemetryValue = await page
.getByLabel('Alpha Table table content')
.getByLabel('wavelengths table cell')
.first()
.getAttribute('title');
const afterReloadBetaTelemetryValue = await page
.getByLabel('Beta Table table content')
.getByLabel('wavelengths table cell')
.first()
.getAttribute('title');
expect(beforeReloadAlphaTelemetryValue).not.toEqual(afterReloadAlphaTelemetryValue);
expect(beforeReloadBetaTelemetryValue).toEqual(afterReloadBetaTelemetryValue);
// now reload parent
await page.getByTitle('More actions').click();
await page.getByRole('menuitem', { name: /Reload/ }).click();
const fullReloadAlphaTelemetryValue = await page
.getByLabel('Alpha Table table content')
.getByLabel('wavelengths table cell')
.first()
.getAttribute('title');
const fullReloadBetaTelemetryValue = await page
.getByLabel('Beta Table table content')
.getByLabel('wavelengths table cell')
.first()
.getAttribute('title');
expect(fullReloadAlphaTelemetryValue).not.toEqual(afterReloadAlphaTelemetryValue);
expect(fullReloadBetaTelemetryValue).not.toEqual(afterReloadBetaTelemetryValue);
});
});

View File

@ -50,7 +50,7 @@ test.describe('Tabs View', () => {
page.goto(tabsView.url);
// select first tab
await page.getByLabel(`${table.name} tab`).click();
await page.getByLabel(`${table.name} tab`, { exact: true }).click();
// ensure table header visible
await expect(page.getByRole('searchbox', { name: 'message filter input' })).toBeVisible();
@ -58,7 +58,7 @@ test.describe('Tabs View', () => {
await expect(page.locator('canvas[id=webglContext]')).toBeHidden();
// select second tab
await page.getByLabel(`${notebook.name} tab`).click();
await page.getByLabel(`${notebook.name} tab`, { exact: true }).click();
// ensure notebook visible
await expect(page.locator('.c-notebook__drag-area')).toBeVisible();
@ -67,7 +67,7 @@ test.describe('Tabs View', () => {
await expect(page.locator('canvas[id=webglContext]')).toBeHidden();
// select third tab
await page.getByLabel(`${sineWaveGenerator.name} tab`).click();
await page.getByLabel(`${sineWaveGenerator.name} tab`, { exact: true }).click();
// expect sine wave generator visible
await expect(page.locator('.c-plot')).toBeVisible();
@ -78,7 +78,7 @@ test.describe('Tabs View', () => {
await expect(page.locator('canvas').nth(1)).toBeVisible();
// now try to select the first tab again
await page.getByLabel(`${table.name} tab`).click();
await page.getByLabel(`${table.name} tab`, { exact: true }).click();
// ensure table header visible
await expect(page.getByRole('searchbox', { name: 'message filter input' })).toBeVisible();

View File

@ -64,10 +64,9 @@ test.describe('Telemetry Table', () => {
// Get the most recent telemetry date
const latestTelemetryDate = await page
.locator('table.c-telemetry-table__body > tbody > tr')
.getByLabel('table content')
.getByLabel('utc table cell')
.last()
.locator('td')
.nth(1)
.getAttribute('title');
// Verify that it is <= our new end bound
@ -91,7 +90,7 @@ test.describe('Telemetry Table', () => {
await page.getByRole('searchbox', { name: 'message filter input' }).click();
await page.getByRole('searchbox', { name: 'message filter input' }).fill('Roger');
let cells = await page.getByRole('cell', { name: /Roger/ }).all();
let cells = await page.getByRole('cell').getByText(/Roger/).all();
// ensure we've got more than one cell
expect(cells.length).toBeGreaterThan(1);
// ensure the text content of each cell contains the search term
@ -103,7 +102,10 @@ test.describe('Telemetry Table', () => {
await page.getByRole('searchbox', { name: 'message filter input' }).click();
await page.getByRole('searchbox', { name: 'message filter input' }).fill('Dodger');
cells = await page.getByRole('cell', { name: /Dodger/ }).all();
cells = await page
.getByRole('cell')
.getByText(/Dodger/)
.all();
// ensure we've got more than one cell
expect(cells.length).toBe(0);
// ensure the text content of each cell contains the search term
@ -135,7 +137,7 @@ test.describe('Telemetry Table', () => {
await page.getByRole('searchbox', { name: 'message filter input' }).click();
await page.getByRole('searchbox', { name: 'message filter input' }).fill('/[Rr]oger/');
let cells = await page.getByRole('cell', { name: /Roger/ }).all();
let cells = await page.getByRole('cell').getByText(/Roger/).all();
// ensure we've got more than one cell
expect(cells.length).toBeGreaterThan(1);
// ensure the text content of each cell contains the search term
@ -147,7 +149,10 @@ test.describe('Telemetry Table', () => {
await page.getByRole('searchbox', { name: 'message filter input' }).click();
await page.getByRole('searchbox', { name: 'message filter input' }).fill('/[Dd]oger/');
cells = await page.getByRole('cell', { name: /Dodger/ }).all();
cells = await page
.getByRole('cell')
.getByText(/Dodger/)
.all();
// ensure we've got more than one cell
expect(cells.length).toBe(0);
// ensure the text content of each cell contains the search term

View File

@ -24,7 +24,7 @@ import { createDomainObjectWithDefaults, waitForPlotsToRender } from '../../appA
import { expect, test } from '../../pluginFixtures.js';
test.describe('Tabs View', () => {
test('Renders tabbed elements nicely', async ({ page }) => {
test('Renders tabbed elements only when visible', async ({ page }) => {
// Code to hook into the requestAnimationFrame function and log each call
let animationCalls = [];
await page.exposeFunction('logCall', (callCount) => {
@ -64,24 +64,24 @@ test.describe('Tabs View', () => {
page.goto(tabsView.url);
// select first tab
await page.getByLabel(`${table.name} tab`).click();
await page.getByLabel(`${table.name} tab`, { exact: true }).click();
// ensure table header visible
await expect(page.getByRole('searchbox', { name: 'message filter input' })).toBeVisible();
// select second tab
await page.getByLabel(`${notebook.name} tab`).click();
await page.getByLabel(`${notebook.name} tab`, { exact: true }).click();
// expect notebook visible
await expect(page.locator('.c-notebook__drag-area')).toBeVisible();
// select third tab
await page.getByLabel(`${sineWaveGenerator.name} tab`).click();
await page.getByLabel(`${sineWaveGenerator.name} tab`, { exact: true }).click();
// ensure sine wave generator visible
expect(await page.locator('.c-plot').isVisible()).toBe(true);
// now select notebook and clear animation calls
await page.getByLabel(`${notebook.name} tab`).click();
await page.getByLabel(`${notebook.name} tab`, { exact: true }).click();
animationCalls = [];
// expect notebook visible
await expect(page.locator('.c-notebook__drag-area')).toBeVisible();
@ -89,7 +89,7 @@ test.describe('Tabs View', () => {
// select sine wave generator and clear animation calls
animationCalls = [];
await page.getByLabel(`${sineWaveGenerator.name} tab`).click();
await page.getByLabel(`${sineWaveGenerator.name} tab`, { exact: true }).click();
// ensure sine wave generator visible
await waitForPlotsToRender(page);

View File

@ -0,0 +1,93 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2024, 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 percySnapshot from '@percy/playwright';
import { createDomainObjectWithDefaults, setRealTimeMode } from '../../appActions.js';
import { VISUAL_URL } from '../../constants.js';
import { expect, test } from '../../pluginFixtures.js';
test.describe('Visual - Example Imagery', () => {
let exampleImagery;
let parentLayout;
test.beforeEach(async ({ page }) => {
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
parentLayout = await createDomainObjectWithDefaults(page, {
type: 'Display Layout',
name: 'Parent Layout'
});
exampleImagery = await createDomainObjectWithDefaults(page, {
type: 'Example Imagery',
name: 'Example Imagery Test',
parent: parentLayout.uuid
});
// Modify Example Imagery to create a really stable Example Imagery
await page.goto(exampleImagery.url, { waitUntil: 'domcontentloaded' });
await page.getByRole('button', { name: 'More actions' }).click();
await page.getByRole('menuitem', { name: 'Edit Properties...' }).click();
await page
.locator('#imageLocation-textarea')
.fill(
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg,https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg'
);
await page.getByRole('button', { name: 'Save' }).click();
await page.reload({ waitUntil: 'domcontentloaded' });
await page.getByTitle('Collapse Browse Pane').click();
await page.getByTitle('Collapse Inspect Pane').click();
});
test('Example Imagery in Fixed Time', async ({ page, theme }) => {
await page.goto(exampleImagery.url, { waitUntil: 'domcontentloaded' });
await expect(page.getByLabel('Image Wrapper')).toBeVisible();
await percySnapshot(page, `Example Imagery in Fixed Time (theme: ${theme})`);
await page.getByLabel('Image Wrapper').hover();
await percySnapshot(page, `Example Imagery Hover in Fixed Time (theme: ${theme})`);
});
test('Example Imagery in Real Time', async ({ page, theme }) => {
await page.goto(exampleImagery.url, { waitUntil: 'domcontentloaded' });
await setRealTimeMode(page, true);
//Temporary to close the dialog
await page.getByLabel('Submit time offsets').click();
await expect(page.getByLabel('Image Wrapper')).toBeVisible();
await percySnapshot(page, `Example Imagery in Real Time (theme: ${theme})`);
});
test('Example Imagery in Display Layout', async ({ page, theme }) => {
await page.goto(parentLayout.url, { waitUntil: 'domcontentloaded' });
await expect(page.getByLabel('Image Wrapper')).toBeVisible();
await percySnapshot(page, `Example Imagery in Display Layout (theme: ${theme})`);
});
});

View File

@ -251,6 +251,7 @@ export class MCT extends EventEmitter {
this.install(this.plugins.FlexibleLayout());
this.install(this.plugins.GoToOriginalAction());
this.install(this.plugins.OpenInNewTabAction());
this.install(this.plugins.ReloadAction());
this.install(this.plugins.WebPage());
this.install(this.plugins.Condition());
this.install(this.plugins.ConditionWidget());

View File

@ -84,12 +84,7 @@ import LayoutFrame from './LayoutFrame.vue';
const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5];
const DEFAULT_POSITION = [1, 1];
const CONTEXT_MENU_ACTIONS = [
'copyToClipboard',
'copyToNotebook',
'viewHistoricalData',
'renderWhenVisible'
];
const CONTEXT_MENU_ACTIONS = ['copyToClipboard', 'copyToNotebook', 'viewHistoricalData'];
export default {
makeDefinition(openmct, gridSize, domainObject, position) {

View File

@ -145,7 +145,7 @@
v-if="relatedTelemetry.hasRelatedTelemetry && isSpacecraftPositionFresh"
class="c-imagery__age icon-check c-imagery--new no-animation"
>
POS
ROV
</div>
<!-- camera position fresh -->

View File

@ -65,6 +65,7 @@ import PerformanceIndicator from './performanceIndicator/plugin.js';
import CouchDBPlugin from './persistence/couch/plugin.js';
import PlanLayout from './plan/plugin.js';
import PlotPlugin from './plot/plugin.js';
import ReloadAction from './reloadAction/plugin.js';
import RemoteClock from './remoteClock/plugin.js';
import StaticRootPlugin from './staticRootPlugin/plugin.js';
import SummaryWidget from './summaryWidget/plugin.js';
@ -141,6 +142,7 @@ plugins.Filters = Filters;
plugins.ObjectMigration = ObjectMigration;
plugins.GoToOriginalAction = GoToOriginalAction;
plugins.OpenInNewTabAction = OpenInNewTabAction;
plugins.ReloadAction = ReloadAction;
plugins.ClearData = ClearData;
plugins.WebPage = WebPagePlugin;
plugins.Espresso = Espresso;

View File

@ -0,0 +1,37 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2023, 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.
*****************************************************************************/
export default class ReloadAction {
constructor(openmct) {
this.name = 'Reload';
this.key = 'reload';
this.description = 'Reload this object and its children';
this.group = 'action';
this.priority = 10;
this.cssClass = 'icon-refresh';
this.openmct = openmct;
}
invoke(objectPath, view) {
const domainObject = objectPath[0];
this.openmct.objectViews.emit('reload', domainObject);
}
}

View File

@ -0,0 +1,28 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2023, 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 ReloadAction from './ReloadAction.js';
export default function plugin() {
return function install(openmct) {
openmct.actions.register(new ReloadAction(openmct));
};
}

View File

@ -22,8 +22,8 @@
<template>
<td
ref="tableCell"
:aria-label="formattedValue"
:title="formattedValue"
:aria-label="`${columnKey} table cell ${formattedValue}`"
@click="selectCell($event.currentTarget, columnKey)"
@mouseover.ctrl="showToolTip"
@mouseleave="hideToolTip"

View File

@ -222,6 +222,7 @@
ref="contentTable"
class="c-table__body c-telemetry-table__body js-telemetry-table__content"
:style="{ height: totalHeight + 'px' }"
:aria-label="`${table.domainObject.name} table content`"
>
<tbody>
<telemetry-table-row

View File

@ -33,6 +33,7 @@ import StyleRuleManager from '@/plugins/condition/StyleRuleManager';
import { STYLE_CONSTANTS } from '@/plugins/condition/utils/constants';
import stalenessMixin from '@/ui/mixins/staleness-mixin';
import objectUtils from '../../api/objects/object-utils.js';
import VisibilityObserver from '../../utils/visibility/VisibilityObserver.js';
export default {
@ -184,6 +185,7 @@ export default {
this.triggerUnsubscribeFromStaleness(this.domainObject);
this.openmct.objectViews.off('clearData', this.clearData);
this.openmct.objectViews.off('reload', this.reload);
if (this.contextActionEvent) {
this.openmct.objectViews.off(this.contextActionEvent, this.performContextAction);
}
@ -218,6 +220,13 @@ export default {
this.clear();
this.updateView(true);
},
reload(domainObjectToReload) {
if (objectUtils.equals(domainObjectToReload, this.domainObject)) {
this.updateView(true);
this.initObjectStyles();
this.triggerStalenessSubscribe(this.domainObject);
}
},
triggerStalenessSubscribe(object) {
if (this.openmct.telemetry.isTelemetryObject(object)) {
this.subscribeToStaleness(object);
@ -316,6 +325,7 @@ export default {
this.domainObject.identifier
)}`;
this.openmct.objectViews.on('clearData', this.clearData);
this.openmct.objectViews.on('reload', this.reload);
this.openmct.objectViews.on(this.contextActionEvent, this.performContextAction);
this.$nextTick(() => {