Compare commits

...

38 Commits

Author SHA1 Message Date
Jesse Mazzella
855918408e toRaw object path 2023-07-24 16:33:57 -07:00
Jesse Mazzella
b0ca16fc14 try to fix tree removal problem 2023-07-24 16:03:59 -07:00
Jesse Mazzella
e92b8f9720 fix(#6832): timelist events can tick down 2023-07-24 15:22:00 -07:00
Khalid Adil
fdae0ceb72 Wait for background image to load 2023-07-24 15:22:16 -05:00
Jesse Mazzella
eeff0a7bff fix: remove typo 2023-07-24 11:22:53 -07:00
Jesse Mazzella
23a0ddb97c fix(#3117): can remove item from displayLayout via tree context menu while viewing another item 2023-07-24 10:07:13 -07:00
Jesse Mazzella
724ec423d1 fix(e2e): fix grand search test 2023-07-21 16:52:00 -07:00
Jesse Mazzella
b41c98d4ab fix: replace all instances of $delete with Array.splice() or delete 2023-07-21 14:34:08 -07:00
Jesse Mazzella
76c37ff410 fix(restrictedNotebook): fix issue causing snapshots to not be able to be deleted from a locked page
- Using `this.$delete(arr, index)` does not update the `length` property on the underlying target object, so it can lead to bizarre issues where your array is of length 4 but it has 3 objects in it.
2023-07-21 14:18:24 -07:00
Shefali
c1d1b03b23 Merge branch 'e2e-test-fixes' of https://github.com/nasa/openmct into e2e-test-fixes 2023-07-21 12:30:15 -07:00
Jesse Mazzella
e0fc2ae043 fix(restrictedNotebook): fix issue causing sections not to update on lock 2023-07-21 12:21:58 -07:00
Jesse Mazzella
9a946bcd6f fix(e2e): fix restricted notebook locator 2023-07-21 12:21:39 -07:00
Jesse Mazzella
9f77c03ddb fix(e2e): update snapshots 2023-07-21 11:52:09 -07:00
Shefali
bdf8601091 6826: Fixes padStart error due to using it on a number rather than a string 2023-07-21 10:23:53 -07:00
Jesse Mazzella
2719a283d2 e2e: move test info annotations to within test 2023-07-21 09:31:20 -07:00
Shefali
a1d9842c16 Fix timestrip test 2023-07-21 07:42:35 -07:00
Shefali
c77bbc16eb Fix telemetry table test 2023-07-21 06:50:17 -07:00
Shefali
05a1d53b92 fix autoscale test and snapshot 2023-07-21 06:30:31 -07:00
Shefali
cb93d17742 Fix Inspector tabs remounting on change 2023-07-21 00:34:00 -07:00
Shefali
771158de3b Fix some tests for itc for display layouts 2023-07-20 22:02:04 -07:00
Shefali
8d5219cf09 Improve how time bounds are set in independent time conductor.
Fix tests for flexible layout and timestrip
2023-07-20 21:59:03 -07:00
Shefali
625bdc0ed8 Fix locator for time conductor popups 2023-07-20 16:07:17 -07:00
Khalid Adil
43fa10443d Add fixme to tagging tests, issue described in 6822 2023-07-20 17:44:08 -05:00
Jesse Mazzella
dc0f461d9f test(e2e): fix ITC imagery test 2023-07-20 14:37:04 -07:00
Jesse Mazzella
99cb90987a test(e2e): disable one imagery test due to known bug 2023-07-20 13:33:36 -07:00
Shefali
7db9805976 Don't remove the itc popup from the DOM. Just show/hide it once it's added the first time. 2023-07-20 13:29:34 -07:00
David Tsay
f48afeb179 add fixmes to e2e tests failing due to regressions 2023-07-20 13:10:29 -07:00
Jesse Mazzella
e94cf27c9a fix(e2e): update appActions and tests to use a11y locators for ITC 2023-07-20 12:41:55 -07:00
John Hill
6d68512d99 Add watch mode 2023-07-20 09:03:29 -07:00
Jesse Mazzella
c6ff7f2958 a11y: fix label collisions, specify 'Menu' in label 2023-07-19 17:09:17 -07:00
Jesse Mazzella
3dab216d2c a11y: more accessibility for TC 2023-07-19 17:03:13 -07:00
Jesse Mazzella
2d16e91704 a11y: ARIA for conductor and independent time conductor 2023-07-19 16:53:56 -07:00
Khalid Adil
c400c7c12d Specify global time conductor to fix issues with duplicate selectors with independent time contexts 2023-07-19 18:49:45 -05:00
Shefali
9b4410d540 Fix displayLayout e2e tests 2023-07-19 16:25:28 -07:00
Shefali
6769fb4e3e Fix log plot e2e tests 2023-07-19 16:25:28 -07:00
Shefali
34229d3a86 Remove log statement 2023-07-19 16:25:28 -07:00
Shefali
f9c5e12a59 Ensure realtime uses upstream context when available
Eliminate ambiguity when looking for time conductor locator
2023-07-19 16:25:28 -07:00
Shefali
72c432ffcc clock, timeConductor and appActions fixes 2023-07-19 16:25:28 -07:00
52 changed files with 415 additions and 332 deletions

View File

@@ -314,15 +314,13 @@ async function _isInEditMode(page, identifier) {
*/
async function setTimeConductorMode(page, isFixedTimespan = true) {
// Click 'mode' button
const timeConductorMode = await page.locator('.c-compact-tc');
await timeConductorMode.click();
await timeConductorMode.locator('.js-mode-button').click();
await page.getByRole('button', { name: 'Time Conductor Mode', exact: true }).click();
await page.getByRole('button', { name: 'Time Conductor Mode Menu' }).click();
// Switch time conductor mode
if (isFixedTimespan) {
await page.locator('data-testid=conductor-modeOption-fixed').click();
await page.getByRole('menuitem', { name: /Fixed Timespan/ }).click();
} else {
await page.locator('data-testid=conductor-modeOption-realtime').click();
await page.getByRole('menuitem', { name: /Real-Time/ }).click();
}
}
@@ -344,9 +342,12 @@ async function setRealTimeMode(page) {
/**
* @typedef {Object} OffsetValues
* @property {string | undefined} hours
* @property {string | undefined} mins
* @property {string | undefined} secs
* @property {string | undefined} startHours
* @property {string | undefined} startMins
* @property {string | undefined} startSecs
* @property {string | undefined} endHours
* @property {string | undefined} endMins
* @property {string | undefined} endSecs
*/
/**
@@ -355,19 +356,32 @@ async function setRealTimeMode(page) {
* @param {OffsetValues} offset
* @param {import('@playwright/test').Locator} offsetButton
*/
async function setTimeConductorOffset(page, { hours, mins, secs }) {
// await offsetButton.click();
if (hours) {
await page.fill('.pr-time-input__hrs', hours);
async function setTimeConductorOffset(
page,
{ startHours, startMins, startSecs, endHours, endMins, endSecs }
) {
if (startHours) {
await page.getByRole('spinbutton', { name: 'Start offset hours' }).fill(startHours);
}
if (mins) {
await page.fill('.pr-time-input__mins', mins);
if (startMins) {
await page.getByRole('spinbutton', { name: 'Start offset minutes' }).fill(startMins);
}
if (secs) {
await page.fill('.pr-time-input__secs', secs);
if (startSecs) {
await page.getByRole('spinbutton', { name: 'Start offset seconds' }).fill(startSecs);
}
if (endHours) {
await page.getByRole('spinbutton', { name: 'End offset hours' }).fill(endHours);
}
if (endMins) {
await page.getByRole('spinbutton', { name: 'End offset minutes' }).fill(endMins);
}
if (endSecs) {
await page.getByRole('spinbutton', { name: 'End offset seconds' }).fill(endSecs);
}
// Click the check button
@@ -381,9 +395,8 @@ async function setTimeConductorOffset(page, { hours, mins, secs }) {
*/
async function setStartOffset(page, offset) {
// Click 'mode' button
const timeConductorMode = await page.locator('.c-compact-tc');
await timeConductorMode.click();
await setTimeConductorOffset(page, offset);
await page.getByRole('button', { name: 'Time Conductor Mode', exact: true }).click();
await setTimeConductorOffset(page, offset, false);
}
/**
@@ -393,9 +406,51 @@ async function setStartOffset(page, offset) {
*/
async function setEndOffset(page, offset) {
// Click 'mode' button
const timeConductorMode = await page.locator('.c-compact-tc');
await timeConductorMode.click();
await setTimeConductorOffset(page, offset);
await page.getByRole('button', { name: 'Time Conductor Mode', exact: true }).click();
await setTimeConductorOffset(page, offset, true);
}
async function setTimeConductorBounds(page, startDate, endDate) {
// Bring up the time conductor popup
await page.click('.l-shell__time-conductor.c-compact-tc');
await setTimeBounds(page, startDate, endDate);
await page.keyboard.press('Enter');
}
async function setIndependentTimeConductorBounds(page, startDate, endDate) {
// Activate Independent Time Conductor in Fixed Time Mode
await page.getByRole('switch').click();
// Bring up the time conductor popup
await page.click('.c-conductor-holder--compact .c-compact-tc');
await expect(page.locator('.itc-popout')).toBeVisible();
await setTimeBounds(page, startDate, endDate);
await page.keyboard.press('Enter');
}
async function setTimeBounds(page, startDate, endDate) {
if (startDate) {
// Fill start time
await page
.getByRole('textbox', { name: 'Start date' })
.fill(startDate.toString().substring(0, 10));
await page
.getByRole('textbox', { name: 'Start time' })
.fill(startDate.toString().substring(11, 19));
}
if (endDate) {
// Fill end time
await page.getByRole('textbox', { name: 'End date' }).fill(endDate.toString().substring(0, 10));
await page
.getByRole('textbox', { name: 'End time' })
.fill(endDate.toString().substring(11, 19));
}
}
/**
@@ -509,6 +564,8 @@ module.exports = {
setRealTimeMode,
setStartOffset,
setEndOffset,
setTimeConductorBounds,
setIndependentTimeConductorBounds,
selectInspectorTab,
waitForPlotsToRender
};

View File

@@ -28,10 +28,10 @@ const { createDomainObjectWithDefaults, createNotification } = require('../../ap
const { test, expect } = require('../../pluginFixtures');
test.describe('Notifications List', () => {
test('Notifications can be dismissed individually', async ({ page }) => {
test.fixme('Notifications can be dismissed individually', async ({ page }) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/nasa/openmct/issues/6122'
description: 'https://github.com/nasa/openmct/issues/6820'
});
// Go to baseURL

View File

@@ -21,7 +21,11 @@
*****************************************************************************/
const { test, expect } = require('../../../pluginFixtures');
const { createDomainObjectWithDefaults, createPlanFromJSON } = require('../../../appActions');
const {
createDomainObjectWithDefaults,
createPlanFromJSON,
setIndependentTimeConductorBounds
} = require('../../../appActions');
const testPlan = {
TEST_GROUP: [
@@ -78,9 +82,6 @@ test.describe('Time Strip', () => {
});
// Constant locators
const independentTimeConductorInputs = page.locator(
'.l-shell__main-independent-time-conductor .c-input--datetime'
);
const activityBounds = page.locator('.activity-bounds');
// Goto baseURL
@@ -122,9 +123,7 @@ test.describe('Time Strip', () => {
});
await test.step('TimeStrip can use the Independent Time Conductor', async () => {
// Activate Independent Time Conductor in Fixed Time Mode
await page.click('.c-toggle-switch__slider');
expect(await activityBounds.count()).toEqual(0);
expect(await activityBounds.count()).toEqual(5);
// Set the independent time bounds so that only one event is shown
const startBound = testPlan.TEST_GROUP[0].start;
@@ -132,12 +131,7 @@ test.describe('Time Strip', () => {
const startBoundString = new Date(startBound).toISOString().replace('T', ' ');
const endBoundString = new Date(endBound).toISOString().replace('T', ' ');
await independentTimeConductorInputs.nth(0).fill('');
await independentTimeConductorInputs.nth(0).fill(startBoundString);
await page.keyboard.press('Enter');
await independentTimeConductorInputs.nth(1).fill('');
await independentTimeConductorInputs.nth(1).fill(endBoundString);
await page.keyboard.press('Enter');
await setIndependentTimeConductorBounds(page, startBoundString, endBoundString);
expect(await activityBounds.count()).toEqual(1);
});
@@ -156,9 +150,6 @@ test.describe('Time Strip', () => {
await page.click("button[title='Save']");
await page.click("li[title='Save and Finish Editing']");
// Activate Independent Time Conductor in Fixed Time Mode
await page.click('.c-toggle-switch__slider');
// All events should be displayed at this point because the
// initial independent context bounds will match the global bounds
expect(await activityBounds.count()).toEqual(5);
@@ -169,12 +160,7 @@ test.describe('Time Strip', () => {
const startBoundString = new Date(startBound).toISOString().replace('T', ' ');
const endBoundString = new Date(endBound).toISOString().replace('T', ' ');
await independentTimeConductorInputs.nth(0).fill('');
await independentTimeConductorInputs.nth(0).fill(startBoundString);
await page.keyboard.press('Enter');
await independentTimeConductorInputs.nth(1).fill('');
await independentTimeConductorInputs.nth(1).fill(endBoundString);
await page.keyboard.press('Enter');
await setIndependentTimeConductorBounds(page, startBoundString, endBoundString);
// Verify that two events are displayed
expect(await activityBounds.count()).toEqual(2);

View File

@@ -41,7 +41,7 @@ test.describe('Clock Generator CRUD Operations', () => {
await page.click('button:has-text("Create")');
// Click Clock
await page.click('text=Clock');
await page.getByRole('menuitem').first().click();
// Click .icon-arrow-down
await page.locator('.icon-arrow-down').click();

View File

@@ -25,7 +25,8 @@ const {
createDomainObjectWithDefaults,
setStartOffset,
setFixedTimeMode,
setRealTimeMode
setRealTimeMode,
setIndependentTimeConductorBounds
} = require('../../../../appActions');
test.describe('Display Layout', () => {
@@ -231,20 +232,27 @@ test.describe('Display Layout', () => {
let layoutGridHolder = page.locator('.l-layout__grid-holder');
await exampleImageryTreeItem.dragTo(layoutGridHolder);
//adjust so that we can see the independent time conductor toggle
// Adjust object height
await page.locator('div[title="Resize object height"] > input').click();
await page.locator('div[title="Resize object height"] > input').fill('70');
// Adjust object width
await page.locator('div[title="Resize object width"] > input').click();
await page.locator('div[title="Resize object width"] > input').fill('70');
await page.locator('button[title="Save"]').click();
await page.locator('text=Save and Finish Editing').click();
// flip on independent time conductor
await page.getByTitle('Enable independent Time Conductor').first().locator('label').click();
await page.getByRole('textbox').nth(1).fill('2021-12-30 01:11:00.000Z');
await page.getByRole('textbox').nth(0).fill('2021-12-30 01:01:00.000Z');
await page.getByRole('textbox').nth(1).click();
const startDate = '2021-12-30 01:01:00.000Z';
const endDate = '2021-12-30 01:11:00.000Z';
await setIndependentTimeConductorBounds(page, startDate, endDate);
// check image date
await expect(page.getByText('2021-12-30 01:11:00.000Z').first()).toBeVisible();
// flip it off
await page.getByTitle('Disable independent Time Conductor').first().locator('label').click();
await page.getByRole('switch').click();
// timestamp shouldn't be in the past anymore
await expect(page.getByText('2021-12-30 01:11:00.000Z')).toBeHidden();
});

View File

@@ -21,7 +21,10 @@
*****************************************************************************/
const { test, expect } = require('../../../../pluginFixtures');
const { createDomainObjectWithDefaults } = require('../../../../appActions');
const {
createDomainObjectWithDefaults,
setIndependentTimeConductorBounds
} = require('../../../../appActions');
test.describe('Flexible Layout', () => {
let sineWaveObject;
@@ -187,16 +190,17 @@ test.describe('Flexible Layout', () => {
await page.locator('text=Save and Finish Editing').click();
// flip on independent time conductor
await page.getByTitle('Enable independent Time Conductor').first().locator('label').click();
await page.getByRole('textbox').nth(1).fill('2021-12-30 01:11:00.000Z');
await page.getByRole('textbox').nth(0).fill('2021-12-30 01:01:00.000Z');
await page.getByRole('textbox').nth(1).click();
await setIndependentTimeConductorBounds(
page,
'2021-12-30 01:01:00.000Z',
'2021-12-30 01:11:00.000Z'
);
// check image date
await expect(page.getByText('2021-12-30 01:11:00.000Z').first()).toBeVisible();
// flip it off
await page.getByTitle('Disable independent Time Conductor').first().locator('label').click();
await page.getByRole('switch').click();
// timestamp shouldn't be in the past anymore
await expect(page.getByText('2021-12-30 01:11:00.000Z')).toBeHidden();
});

View File

@@ -27,7 +27,7 @@ but only assume that example imagery is present.
/* globals process */
const { waitForAnimations } = require('../../../../baseFixtures');
const { test, expect } = require('../../../../pluginFixtures');
const { createDomainObjectWithDefaults } = require('../../../../appActions');
const { createDomainObjectWithDefaults, setRealTimeMode } = require('../../../../appActions');
const backgroundImageSelector = '.c-imagery__main-image__background-image';
const panHotkey = process.platform === 'linux' ? ['Shift', 'Alt'] : ['Alt'];
const tagHotkey = ['Shift', 'Alt'];
@@ -46,6 +46,7 @@ test.describe('Example Imagery Object', () => {
// Verify that the created object is focused
await expect(page.locator('.l-browse-bar__object-name')).toContainText(exampleImagery.name);
await page.locator('.c-imagery__main-image__bg').hover({ trial: true });
await page.locator(backgroundImageSelector).waitFor();
});
test('Can use Mouse Wheel to zoom in and out of latest image', async ({ page }) => {
@@ -71,46 +72,62 @@ test.describe('Example Imagery Object', () => {
});
test('Can use independent time conductor to change time', async ({ page }) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/nasa/openmct/issues/6821'
});
// Test independent fixed time with global fixed time
// flip on independent time conductor
await page.getByTitle('Enable independent Time Conductor').locator('label').click();
await page.getByRole('textbox').nth(1).fill('2021-12-30 01:11:00.000Z');
await page.getByRole('textbox').nth(0).fill('2021-12-30 01:01:00.000Z');
await page.getByRole('textbox').nth(1).click();
await page.getByRole('switch', { name: 'Enable Independent Time Conductor' }).click();
await page.getByRole('button', { name: 'Independent Time Conductor Settings' }).click();
await page.getByRole('textbox', { name: 'Start date' }).click();
await page.getByRole('textbox', { name: 'Start date' }).fill('');
await page.getByRole('textbox', { name: 'Start date' }).fill('2021-12-30');
await page.getByRole('textbox', { name: 'Start time' }).click();
await page.getByRole('textbox', { name: 'Start time' }).fill('');
await page.getByRole('textbox', { name: 'Start time' }).fill('01:01:00');
await page.getByRole('textbox', { name: 'End date' }).click();
await page.getByRole('textbox', { name: 'End date' }).fill('');
await page.getByRole('textbox', { name: 'End date' }).fill('2021-12-30');
await page.getByRole('textbox', { name: 'End time' }).click();
await page.getByRole('textbox', { name: 'End time' }).fill('');
await page.getByRole('textbox', { name: 'End time' }).fill('01:11:00');
await page.getByRole('button', { name: 'Submit time bounds' }).click();
// check image date
await expect(page.getByText('2021-12-30 01:11:00.000Z').first()).toBeVisible();
// flip it off
await page.getByTitle('Disable independent Time Conductor').locator('label').click();
await page.getByRole('switch', { name: 'Disable Independent Time Conductor' }).click();
// timestamp shouldn't be in the past anymore
await expect(page.getByText('2021-12-30 01:11:00.000Z')).toBeHidden();
// Test independent fixed time with global realtime
await page.getByRole('button', { name: /Fixed Timespan/ }).click();
await page.getByTestId('conductor-modeOption-realtime').click();
await page.getByTitle('Enable independent Time Conductor').locator('label').click();
await setRealTimeMode(page);
await page.getByRole('switch', { name: 'Enable Independent Time Conductor' }).click();
// check image date to be in the past
await expect(page.getByText('2021-12-30 01:11:00.000Z').first()).toBeVisible();
// flip it off
await page.getByTitle('Disable independent Time Conductor').locator('label').click();
await page.getByRole('switch', { name: 'Disable Independent Time Conductor' }).click();
// timestamp shouldn't be in the past anymore
await expect(page.getByText('2021-12-30 01:11:00.000Z')).toBeHidden();
// Test independent realtime with global realtime
await page.getByTitle('Enable independent Time Conductor').locator('label').click();
await page.getByRole('switch', { name: 'Enable Independent Time Conductor' }).click();
// check image date
await expect(page.getByText('2021-12-30 01:11:00.000Z').first()).toBeVisible();
// change independent time to realtime
await page.getByRole('button', { name: /Fixed Timespan/ }).click();
await page.getByRole('menuitem', { name: /Local Clock/ }).click();
await page.getByRole('button', { name: 'Independent Time Conductor Settings' }).click();
await page.getByRole('button', { name: "Independent Time Conductor Mode Menu" }).click();
await page.getByRole('menuitem', { name: /Real-Time/ }).click();
// timestamp shouldn't be in the past anymore
await expect(page.getByText('2021-12-30 01:11:00.000Z')).toBeHidden();
// back to the past
await page.getByRole('button', { name: "Independent Time Conductor Mode Menu" }).click();
await page
.getByRole('button', { name: /Local Clock/ })
.first()
.click();
.getByRole('menuitem', { name: /Real-Time/ })
.click();
await page.getByRole('button', { name: "Independent Time Conductor Mode Menu" }).click();
await page.getByRole('menuitem', { name: /Fixed Timespan/ }).click();
// check image date to be in the past
await expect(page.getByText('2021-12-30 01:11:00.000Z').first()).toBeVisible();
@@ -247,7 +264,7 @@ test.describe('Example Imagery Object', () => {
test('Uses low fetch priority', async ({ page }) => {
const priority = await page.locator('.js-imageryView-image').getAttribute('fetchpriority');
await expect(priority).toBe('low');
expect(priority).toBe('low');
});
});
@@ -281,7 +298,7 @@ test.describe('Example Imagery in Display Layout', () => {
await setRealTimeMode(page);
// pause/play button
const pausePlayButton = await page.locator('.c-button.pause-play');
const pausePlayButton = page.locator('.c-button.pause-play');
await expect.soft(pausePlayButton).not.toHaveClass(/is-paused/);
@@ -304,7 +321,7 @@ test.describe('Example Imagery in Display Layout', () => {
await setRealTimeMode(page);
// pause/play button
const pausePlayButton = await page.locator('.c-button.pause-play');
const pausePlayButton = page.locator('.c-button.pause-play');
await pausePlayButton.click();
await expect.soft(pausePlayButton).toHaveClass(/is-paused/);
@@ -928,15 +945,3 @@ async function createImageryView(page) {
page.waitForSelector('.c-message-banner__message')
]);
}
/**
* @param {import('@playwright/test').Page} page
*/
async function setRealTimeMode(page) {
await page.locator('.c-compact-tc').click();
await page.waitForSelector('.c-tc-input-popup', { state: 'visible' });
// Click mode dropdown
await page.getByRole('button', { name: ' Fixed Timespan ' }).click();
// Click realtime
await page.getByTestId('conductor-modeOption-realtime').click();
}

View File

@@ -134,7 +134,7 @@ test.describe('Restricted Notebook with at least one entry and with the page loc
// Click the context menu button for the new page
await page.getByTitle('Open context menu').click();
// Delete the page
await page.getByRole('listitem', { name: 'Delete Page' }).click();
await page.getByRole('menuitem', { name: 'Delete Page' }).click();
// Click OK button
await page.getByRole('button', { name: 'Ok' }).click();

View File

@@ -24,7 +24,7 @@
Testsuite for plot autoscale.
*/
const { selectInspectorTab } = require('../../../../appActions');
const { selectInspectorTab, setTimeConductorBounds } = require('../../../../appActions');
const { test, expect } = require('../../../../pluginFixtures');
test.use({
viewport: {
@@ -131,12 +131,7 @@ async function setTimeRange(
// Set a specific time range for consistency, otherwise it will change
// on every test to a range based on the current time.
const timeInputs = page.locator('input.c-input--datetime');
await timeInputs.first().click();
await timeInputs.first().fill(start);
await timeInputs.nth(1).click();
await timeInputs.nth(1).fill(end);
await setTimeConductorBounds(page, start, end);
}
/**

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -26,7 +26,7 @@ necessarily be used for reference when writing new tests in this area.
*/
const { test, expect } = require('../../../../pluginFixtures');
const { selectInspectorTab } = require('../../../../appActions');
const { selectInspectorTab, setTimeConductorBounds } = require('../../../../appActions');
test.describe('Log plot tests', () => {
test('Log Plot ticks are functionally correct in regular and log mode and after refresh', async ({
@@ -87,12 +87,10 @@ async function makeOverlayPlot(page, myItemsFolderName) {
// Set a specific time range for consistency, otherwise it will change
// on every test to a range based on the current time.
const timeInputs = page.locator('input.c-input--datetime');
await timeInputs.first().click();
await timeInputs.first().fill('2022-03-29 22:00:00.000Z');
const start = '2022-03-29 22:00:00.000Z';
const end = '2022-03-29 22:00:30.000Z';
await timeInputs.nth(1).click();
await timeInputs.nth(1).fill('2022-03-29 22:00:30.000Z');
await setTimeConductorBounds(page, start, end);
// create overlay plot

View File

@@ -32,7 +32,7 @@ const {
waitForPlotsToRender
} = require('../../../../appActions');
test.describe('Plot Tagging', () => {
test.describe.fixme('Plot Tagging', () => {
/**
* Given a canvas and a set of points, tags the points on the canvas.
* @param {import('@playwright/test').Page} page
@@ -167,6 +167,10 @@ test.describe('Plot Tagging', () => {
});
test('Tags work with Overlay Plots', async ({ page }) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/nasa/openmct/issues/6822'
});
//Test.slow decorator is currently broken. Needs to be fixed in https://github.com/nasa/openmct/issues/5374
test.slow();

View File

@@ -20,7 +20,10 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
const { createDomainObjectWithDefaults } = require('../../../../appActions');
const {
createDomainObjectWithDefaults,
setTimeConductorBounds
} = require('../../../../appActions');
const { test, expect } = require('../../../../pluginFixtures');
test.describe('Telemetry Table', () => {
@@ -51,18 +54,14 @@ test.describe('Telemetry Table', () => {
await expect(tableWrapper).toHaveClass(/is-paused/);
// Subtract 5 minutes from the current end bound datetime and set it
const endTimeInput = page.locator('input[type="text"].c-input--datetime').nth(1);
await endTimeInput.click();
let endDate = await endTimeInput.inputValue();
// Bring up the time conductor popup
let endDate = await page.locator('[aria-label="End bounds"]').textContent();
endDate = new Date(endDate);
endDate.setUTCMinutes(endDate.getUTCMinutes() - 5);
endDate = endDate.toISOString().replace(/T/, ' ');
await endTimeInput.fill('');
await endTimeInput.fill(endDate);
await page.keyboard.press('Enter');
await setTimeConductorBounds(page, undefined, endDate);
await expect(tableWrapper).not.toHaveClass(/is-paused/);

View File

@@ -25,7 +25,8 @@ const {
setFixedTimeMode,
setRealTimeMode,
setStartOffset,
setEndOffset
setEndOffset,
setTimeConductorBounds
} = require('../../../../appActions');
test.describe('Time conductor operations', () => {
@@ -40,38 +41,36 @@ test.describe('Time conductor operations', () => {
let endDate = 'xxxx-01-01 02:00:00.000Z';
endDate = year + endDate.substring(4);
const startTimeLocator = page.locator('input[type="text"]').first();
const endTimeLocator = page.locator('input[type="text"]').nth(1);
// Click start time
await startTimeLocator.click();
// Click end time
await endTimeLocator.click();
await endTimeLocator.fill(endDate.toString());
await startTimeLocator.fill(startDate.toString());
await setTimeConductorBounds(page, startDate, endDate);
// invalid start date
startDate = year + 1 + startDate.substring(4);
await startTimeLocator.fill(startDate.toString());
await endTimeLocator.click();
await setTimeConductorBounds(page, startDate);
const startDateValidityStatus = await startTimeLocator.evaluate((element) =>
// Bring up the time conductor popup
const timeConductorMode = await page.locator('.c-compact-tc');
await timeConductorMode.click();
const startDateLocator = page.locator('input[type="text"]').first();
const endDateLocator = page.locator('input[type="text"]').nth(2);
await endDateLocator.click();
const startDateValidityStatus = await startDateLocator.evaluate((element) =>
element.checkValidity()
);
expect(startDateValidityStatus).not.toBeTruthy();
// fix to valid start date
startDate = year - 1 + startDate.substring(4);
await startTimeLocator.fill(startDate.toString());
await setTimeConductorBounds(page, startDate);
// invalid end date
endDate = year - 2 + endDate.substring(4);
await endTimeLocator.fill(endDate.toString());
await startTimeLocator.click();
await setTimeConductorBounds(page, undefined, endDate);
const endDateValidityStatus = await endTimeLocator.evaluate((element) =>
await startDateLocator.click();
const endDateValidityStatus = await endDateLocator.evaluate((element) =>
element.checkValidity()
);
expect(endDateValidityStatus).not.toBeTruthy();
@@ -83,11 +82,11 @@ test.describe('Time conductor operations', () => {
test.describe('Time conductor input fields real-time mode', () => {
test('validate input fields in real-time mode', async ({ page }) => {
const startOffset = {
secs: '23'
startSecs: '23'
};
const endOffset = {
secs: '31'
endSecs: '31'
};
// Go to baseURL
@@ -100,15 +99,13 @@ test.describe('Time conductor input fields real-time mode', () => {
await setStartOffset(page, startOffset);
// Verify time was updated on time offset button
await expect(page.locator('data-testid=conductor-start-offset-button')).toContainText(
'00:30:23'
);
await expect(page.locator('.c-compact-tc__setting-value.icon-minus')).toContainText('00:30:23');
// Set end time offset
await setEndOffset(page, endOffset);
// Verify time was updated on preceding time offset button
await expect(page.locator('data-testid=conductor-end-offset-button')).toContainText('00:00:31');
await expect(page.locator('.c-compact-tc__setting-value.icon-plus')).toContainText('00:00:31');
});
/**
@@ -119,12 +116,12 @@ test.describe('Time conductor input fields real-time mode', () => {
page
}) => {
const startOffset = {
mins: '30',
secs: '23'
startMins: '30',
startSecs: '23'
};
const endOffset = {
secs: '01'
endSecs: '01'
};
// Convert offsets to milliseconds
@@ -150,12 +147,10 @@ test.describe('Time conductor input fields real-time mode', () => {
await setRealTimeMode(page);
// Verify updated start time offset persists after mode switch
await expect(page.locator('data-testid=conductor-start-offset-button')).toContainText(
'00:30:23'
);
await expect(page.locator('.c-compact-tc__setting-value.icon-minus')).toContainText('00:30:23');
// Verify updated end time offset persists after mode switch
await expect(page.locator('data-testid=conductor-end-offset-button')).toContainText('00:00:01');
await expect(page.locator('.c-compact-tc__setting-value.icon-plus')).toContainText('00:00:01');
// Verify url parameters persist after mode switch
await page.waitForNavigation({ waitUntil: 'networkidle' });
@@ -203,11 +198,11 @@ test.describe('Time Conductor History', () => {
// with startBound at 2022-01-01 00:00:00.000Z
// and endBound at 2022-01-01 00:00:00.200Z
await page.goto(
'./#/browse/mine?view=grid&tc.mode=fixed&tc.startBound=1640995200000&tc.endBound=1640995200200&tc.timeSystem=utc&hideInspector=true',
{ waitUntil: 'networkidle' }
'./#/browse/mine?view=grid&tc.mode=fixed&tc.startBound=1640995200000&tc.endBound=1640995200200&tc.timeSystem=utc&hideInspector=true'
);
await page.locator("[aria-label='Time Conductor History']").hover({ trial: true });
await page.locator("[aria-label='Time Conductor History']").click();
await page.getByRole('button', { name: 'Time Conductor Settings' }).click();
await page.getByRole('button', { name: 'Time Conductor History' }).hover({ trial: true });
await page.getByRole('button', { name: 'Time Conductor History' }).click();
// Validate history item format
const historyItem = page.locator('text="2022-01-01 00:00:00 + 200ms"');

View File

@@ -59,53 +59,60 @@ test.describe('Recent Objects', () => {
await page.mouse.move(0, 100);
await page.mouse.up();
});
test('Navigated objects show up in recents, object renames and deletions are reflected', async ({
page
}) => {
// Verify that both created objects appear in the list and are in the correct order
await assertInitialRecentObjectsListState();
// Navigate to the folder by clicking on the main object name in the recent objects list item
await page.getByRole('listitem', { name: folderA.name }).getByText(folderA.name).click();
await page.waitForURL(`**/${folderA.uuid}?*`);
expect(recentObjectsList.getByRole('listitem').nth(0).getByText(folderA.name)).toBeTruthy();
// Rename
folderA.name = `${folderA.name}-NEW!`;
await page.locator('.l-browse-bar__object-name').fill('');
await page.locator('.l-browse-bar__object-name').fill(folderA.name);
await page.keyboard.press('Enter');
// Verify rename has been applied in recent objects list item and objects paths
expect(
await page
.getByRole('navigation', {
name: clock.name
})
.locator('a')
.filter({
hasText: folderA.name
})
.count()
).toBeGreaterThan(0);
expect(recentObjectsList.getByRole('listitem', { name: folderA.name })).toBeTruthy();
// Delete
await page.click('button[title="Show selected item in tree"]');
// Delete the folder via the left tree pane treeitem context menu
await page
.getByRole('treeitem', { name: new RegExp(folderA.name) })
.locator('a')
.click({
button: 'right'
test.fixme(
'Navigated objects show up in recents, object renames and deletions are reflected',
async ({ page }) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/nasa/openmct/issues/6818'
});
await page.getByRole('menuitem', { name: /Remove/ }).click();
await page.getByRole('button', { name: 'OK' }).click();
// Verify that the folder and clock are no longer in the recent objects list
await expect(recentObjectsList.getByRole('listitem', { name: folderA.name })).toBeHidden();
await expect(recentObjectsList.getByRole('listitem', { name: clock.name })).toBeHidden();
});
// Verify that both created objects appear in the list and are in the correct order
await assertInitialRecentObjectsListState();
// Navigate to the folder by clicking on the main object name in the recent objects list item
await page.getByRole('listitem', { name: folderA.name }).getByText(folderA.name).click();
await page.waitForURL(`**/${folderA.uuid}?*`);
expect(recentObjectsList.getByRole('listitem').nth(0).getByText(folderA.name)).toBeTruthy();
// Rename
folderA.name = `${folderA.name}-NEW!`;
await page.locator('.l-browse-bar__object-name').fill('');
await page.locator('.l-browse-bar__object-name').fill(folderA.name);
await page.keyboard.press('Enter');
// Verify rename has been applied in recent objects list item and objects paths
expect(
await page
.getByRole('navigation', {
name: clock.name
})
.locator('a')
.filter({
hasText: folderA.name
})
.count()
).toBeGreaterThan(0);
expect(recentObjectsList.getByRole('listitem', { name: folderA.name })).toBeTruthy();
// Delete
await page.click('button[title="Show selected item in tree"]');
// Delete the folder via the left tree pane treeitem context menu
await page
.getByRole('treeitem', { name: new RegExp(folderA.name) })
.locator('a')
.click({
button: 'right'
});
await page.getByRole('menuitem', { name: /Remove/ }).click();
await page.getByRole('button', { name: 'OK' }).click();
// Verify that the folder and clock are no longer in the recent objects list
await expect(recentObjectsList.getByRole('listitem', { name: folderA.name })).toBeHidden();
await expect(recentObjectsList.getByRole('listitem', { name: clock.name })).toBeHidden();
}
);
test('Clicking on an object in the path of a recent object navigates to the object', async ({
page,
openmctConfig

View File

@@ -77,11 +77,11 @@ test.describe('Grand Search', () => {
// Click [aria-label="OpenMCT Search"] a >> nth=0
await page.locator('[aria-label="Search Result"] >> nth=0').click();
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden();
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeInViewport();
// Fill [aria-label="OpenMCT Search"] input[type="search"]
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('foo');
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden();
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).not.toBeInViewport();
// Click text=Snapshot Save and Finish Editing Save and Continue Editing >> button >> nth=1
await page

View File

@@ -98,6 +98,7 @@
"test:e2e:updatesnapshots": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome --grep @snapshot --update-snapshots",
"test:e2e:visual": "percy exec --config ./e2e/.percy.yml -- npx playwright test --config=e2e/playwright-visual.config.js --grep-invert @unstable",
"test:e2e:full": "npx playwright test --config=e2e/playwright-ci.config.js --grep-invert @couchdb",
"test:e2e:watch": "npx playwright test --ui --config=e2e/playwright-ci.config.js",
"test:perf": "npx playwright test --config=e2e/playwright-performance.config.js",
"update-about-dialog-copyright": "perl -pi -e 's/20\\d\\d\\-202\\d/2014\\-2023/gm' ./src/ui/layout/AboutDialog.vue",
"update-copyright-date": "npm run update-about-dialog-copyright && grep -lr --null --include=*.{js,scss,vue,ts,sh,html,md,frag} 'Copyright (c) 20' . | xargs -r0 perl -pi -e 's/Copyright\\s\\(c\\)\\s20\\d\\d\\-20\\d\\d/Copyright \\(c\\)\\ 2014\\-2023/gm'",

View File

@@ -30,7 +30,6 @@
role="menuitem"
:class="[action.cssClass, action.isDisabled ? 'disabled' : '']"
:title="action.description"
:data-testid="action.testId || null"
@click="action.onItemClicked"
>
{{ action.name }}
@@ -53,7 +52,6 @@
role="menuitem"
:class="[action.cssClass, action.isDisabled ? 'disabled' : '']"
:title="action.description"
:data-testid="action.testId || null"
@click="action.onItemClicked"
>
{{ action.name }}

View File

@@ -34,7 +34,6 @@
role="menuitem"
:class="[action.cssClass, action.isDisabled ? 'disabled' : '']"
:title="action.description"
:data-testid="action.testId || null"
@click="action.onItemClicked"
@mouseover="toggleItemDescription(action)"
@mouseleave="toggleItemDescription()"
@@ -59,7 +58,6 @@
role="menuitem"
:class="action.cssClass"
:title="action.description"
:data-testid="action.testId || null"
@click="action.onItemClicked"
@mouseover="toggleItemDescription(action)"
@mouseleave="toggleItemDescription()"

View File

@@ -27,7 +27,7 @@
v-if="dismissable"
aria-label="Close"
class="c-click-icon c-overlay__close-button icon-x"
@click="destroy"
@click.stop="destroy"
></button>
<div
ref="element"
@@ -71,16 +71,16 @@ export default {
});
},
methods: {
destroy: function () {
destroy() {
if (this.dismissable) {
this.dismiss();
}
},
buttonClickHandler: function (method) {
buttonClickHandler(method) {
method();
this.$emit('destroy');
},
getElementForFocus: function () {
getElementForFocus() {
const defaultElement = this.$refs.element;
if (!this.$refs.buttons) {
return defaultElement;

View File

@@ -299,6 +299,14 @@ class IndependentTimeContext extends TimeContext {
return this.mode;
}
isRealTime() {
if (this.upstreamTimeContext) {
return this.upstreamTimeContext.isRealTime(...arguments);
} else {
return super.isRealTime(...arguments);
}
}
/**
* Causes this time context to follow another time context (either the global context, or another upstream time context)
* This allows views to have their own time context which points to the appropriate upstream context as necessary, achieving nesting.

View File

@@ -151,7 +151,7 @@ export default {
);
const ladTable = this.ladTableObjects[index];
this.$delete(this.ladTelemetryObjects, ladTable.key);
delete this.ladTelemetryObjects[ladTable.key];
this.ladTableObjects.splice(index, 1);
this.shouldShowUnitsCheckbox();
@@ -224,7 +224,7 @@ export default {
}
if (!showUnitsCheckbox && this.headers?.units) {
this.$delete(this.headers, 'units');
delete this.headers.units;
}
},
metadataHasUnits(domainObject) {

View File

@@ -178,7 +178,7 @@ export default {
this.unwatchStaleness(combinedKey);
});
this.$delete(this.ladTelemetryObjects, ladTable.key);
delete this.ladTelemetryObjects[ladTable.key];
this.ladTableObjects.splice(index, 1);
},
reorderLadTables(reorderPlan) {

View File

@@ -200,7 +200,7 @@ export default {
this.openmct.objects.areIdsEqual(seriesIdentifier, plotSeries.identifier)
);
if (index >= 0) {
this.$delete(this.plotSeries, index);
this.plotSeries.splice(index, 1);
this.setupOptions();
}
},

View File

@@ -112,7 +112,7 @@ export default {
const foundSeries = seriesIndex > -1;
if (foundSeries) {
this.$delete(this.plotSeries, seriesIndex);
this.plotSeries.splice(seriesIndex, 1);
this.setAxesLabels();
}
},

View File

@@ -143,7 +143,7 @@ export default {
this.openmct.objects.areIdsEqual(seriesIdentifier, plotSeries.identifier)
);
if (index >= 0) {
this.$delete(this.plotSeries, index);
this.plotSeries.splice(index, 1);
this.setupOptions();
}
},

View File

@@ -162,7 +162,7 @@ export default {
showGrid: true,
viewContext: {},
gridDimensions: [0, 0],
layoutItems: this.domainObject.configuration.items
layoutItems: this.domainObject.configuration.items || []
};
},
computed: {
@@ -227,7 +227,7 @@ export default {
this.watchDisplayResize();
},
unmounted: function () {
unmounted() {
this.openmct.selection.off('change', this.setSelection);
this.composition.off('add', this.addChild);
this.composition.off('remove', this.removeChild);
@@ -623,6 +623,7 @@ export default {
return this.openmct.objects.makeKeyString(item.identifier) !== keyString;
}
});
this.layoutItems = layoutItems;
this.mutate('configuration.items', layoutItems);
this.clearSelection();
},

View File

@@ -169,7 +169,7 @@ export default {
if (selected) {
this.selectedFaults[fault.id] = fault;
} else {
this.$delete(this.selectedFaults, fault.id);
delete this.selectedFaults[fault.id];
}
const selectedFaults = Object.values(this.selectedFaults);

View File

@@ -173,14 +173,14 @@ export default {
if (globalFiltersToRemove.length > 0) {
globalFiltersToRemove.forEach((key) => {
this.$delete(this.globalFilters, key);
this.$delete(this.globalMetadata, key);
delete this.globalFilters[key];
delete this.globalMetadata[key];
});
this.mutateConfigurationGlobalFilters();
}
this.$delete(this.children, keyString);
this.$delete(this.persistedFilters, keyString);
delete this.children[keyString];
delete this.persistedFilters[keyString];
this.mutateConfigurationFilters();
},
getGlobalFiltersToRemove(keyString) {

View File

@@ -476,7 +476,6 @@ export default {
{
label: 'Lock Page',
callback: () => {
let sections = this.getSections();
this.selectedPage.isLocked = true;
// cant be default if it's locked
@@ -488,7 +487,7 @@ export default {
this.selectedSection.isLocked = true;
}
mutateObject(this.openmct, this.domainObject, 'configuration.sections', sections);
mutateObject(this.openmct, this.domainObject, 'configuration.sections', this.sections);
if (!this.domainObject.locked) {
mutateObject(this.openmct, this.domainObject, 'locked', true);
@@ -708,9 +707,6 @@ export default {
getSection(id) {
return this.sections.find((s) => s.id === id);
},
getSections() {
return this.domainObject.configuration.sections || [];
},
getSearchResults() {
if (!this.search.length) {
return [];

View File

@@ -106,9 +106,8 @@ export default {
watch: {
isLocked(value) {
if (value === true) {
let index = this.menuActions.findIndex((item) => item.id === 'removeEmbed');
this.$delete(this.menuActions, index);
const index = this.menuActions.findIndex((item) => item.id === 'removeEmbed');
this.menuActions.splice(index, 1);
}
}
},
@@ -140,7 +139,7 @@ export default {
onItemClicked: () => this.openSnapshot()
};
this.menuActions = [viewSnapshot];
this.menuActions.splice(0, this.menuActions.length, viewSnapshot);
}
const navigateToItem = {
@@ -167,7 +166,7 @@ export default {
onItemClicked: () => this.previewEmbed()
};
this.menuActions = this.menuActions.concat([quickView, navigateToItem, navigateToItemInTime]);
this.menuActions.push(...[quickView, navigateToItem, navigateToItemInTime]);
if (!this.isLocked) {
const removeEmbed = {

View File

@@ -232,7 +232,7 @@ export default {
removeChild(childIdentifier) {
const id = this.openmct.objects.makeKeyString(childIdentifier);
this.$delete(this.tickWidthMap, id);
delete this.tickWidthMap[id];
const childObj = this.compositionObjects.filter((c) => {
const identifier = c.keyString;

View File

@@ -49,7 +49,7 @@
@panAxis="pan"
@zoomAxis="zoom"
/>
<div class="c-not-button c-not-button--compact c-compact-tc__gear icon-gear"></div>
<div role="button" class="c-not-button c-not-button--compact c-compact-tc__gear icon-gear" aria-label="Time Conductor Settings"></div>
<conductor-pop-up
v-if="showConductorPopup"

View File

@@ -1,29 +1,38 @@
/***************************************************************************** * Open MCT Web,
Copyright (c) 2014-2023, United States Government * as represented by the Administrator of the
National Aeronautics and Space * Administration. All rights reserved. * * Open MCT Web 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 Web 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.
*****************************************************************************/
<!--
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.
-->
<template>
<div v-if="readOnly === false" ref="clockButton" class="c-tc-input-popup__options">
<div class="c-menu-button c-ctrl-wrapper c-ctrl-wrapper--menus-left">
<button
class="c-button--menu js-clock-button"
:class="[buttonCssClass, selectedClock.cssClass]"
aria-label="Time Conductor Clock Menu"
@click.prevent.stop="showClocksMenu"
>
<span class="c-button__label">{{ selectedClock.name }}</span>
</button>
</div>
</div>
<div v-else class="c-compact-tc__setting-value__elem" :title="`Clock: ${selectedClock.name}`">
<div v-else class="c-compact-tc__setting-value__elem" aria-label="Time Conductor Clock">
{{ selectedClock.name }}
</div>
</template>

View File

@@ -32,6 +32,7 @@
<div
class="c-compact-tc__setting-value u-fade-truncate--lg --no-sep"
:title="`Start bounds: ${formattedBounds.start}`"
aria-label="Start bounds"
>
{{ formattedBounds.start }}
</div>
@@ -39,6 +40,7 @@
<div
class="c-compact-tc__setting-value u-fade-truncate--lg --no-sep"
:title="`End bounds: ${formattedBounds.end}`"
aria-label="End bounds"
>
{{ formattedBounds.end }}
</div>

View File

@@ -26,12 +26,13 @@
class="c-button--menu js-mode-button"
:class="[buttonCssClass, selectedMode.cssClass]"
@click.prevent.stop="showModesMenu"
aria-label="Time Conductor Mode Menu"
>
<span class="c-button__label">{{ selectedMode.name }}</span>
</button>
</div>
</div>
<div v-else class="c-compact-tc__setting-value__elem" :title="`Mode: ${selectedMode.name}`">
<div role="button" v-else class="c-compact-tc__setting-value__elem" aria-label="Time Conductor Mode">
{{ selectedMode.name }}
</div>
</template>

View File

@@ -29,6 +29,7 @@
class="c-button--menu c-time-system-button"
:class="[buttonCssClass]"
@click.prevent.stop="showTimeSystemMenu"
aria-label="Time Conductor Time System"
>
<span class="c-button__label">{{ selectedTimeSystem.name }}</span>
</button>

View File

@@ -1,16 +1,24 @@
/***************************************************************************** * Open MCT Web,
Copyright (c) 2014-2023, United States Government * as represented by the Administrator of the
National Aeronautics and Space * Administration. All rights reserved. * * Open MCT Web 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 Web 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.
*****************************************************************************/
<!--
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.
-->
<template>
<div ref="clockMenuButton" class="c-ctrl-wrapper c-ctrl-wrapper--menus-up">
<div class="c-menu-button c-ctrl-wrapper c-ctrl-wrapper--menus-left">
@@ -18,6 +26,7 @@ available * at runtime from the About dialog for additional information.
v-if="selectedClock"
class="c-icon-button c-button--menu js-clock-button"
:class="[buttonCssClass, selectedClock.cssClass]"
aria-label="Independent Time Conductor Clock Menu"
@click.prevent.stop="showClocksMenu"
>
<span class="c-button__label">{{ selectedClock.name }}</span>
@@ -48,7 +57,7 @@ export default {
}
}
},
data: function () {
data() {
const activeClock = this.getActiveClock();
return {

View File

@@ -25,6 +25,7 @@
<button
class="c-icon-button c-button--menu js-mode-button"
:class="[buttonCssClass, selectedMode.cssClass]"
aria-label="Independent Time Conductor Mode Menu"
@click.prevent.stop="showModesMenu"
>
<span class="c-button__label">{{ selectedMode.name }}</span>

View File

@@ -28,17 +28,17 @@
{ 'is-expanded': independentTCEnabled }
]"
>
<toggle-switch
<ToggleSwitch
id="independentTCToggle"
class="c-toggle-switch--mini"
:checked="independentTCEnabled"
:title="toggleTitle"
:name="toggleTitle"
@change="toggleIndependentTC"
/>
<ConductorModeIcon />
<conductor-inputs-fixed
<ConductorInputsFixed
v-if="showFixedInputs"
class="c-compact-tc__bounds--fixed"
:object-path="objectPath"
@@ -46,7 +46,7 @@
:compact="true"
/>
<conductor-inputs-realtime
<ConductorInputsRealtime
v-if="showRealtimeInputs"
class="c-compact-tc__bounds--real-time"
:object-path="objectPath"
@@ -55,10 +55,12 @@
/>
<div
v-if="independentTCEnabled"
role="button"
class="c-not-button c-not-button--compact c-compact-tc__gear icon-gear"
aria-label="Independent Time Conductor Settings"
></div>
<conductor-pop-up
<ConductorPopUp
v-if="showConductorPopup"
ref="conductorPopup"
:object-path="objectPath"
@@ -145,7 +147,7 @@ export default {
},
computed: {
toggleTitle() {
return `${this.independentTCEnabled ? 'Disable' : 'Enable'} independent Time Conductor`;
return `${this.independentTCEnabled ? 'Disable' : 'Enable'} Independent Time Conductor`;
},
showFixedInputs() {
return this.isFixed && this.independentTCEnabled;

View File

@@ -42,8 +42,11 @@ export default {
methods: {
initializePopup() {
this.conductorPopup = this.$refs.conductorPopup.$el;
document.body.appendChild(this.conductorPopup); // remove from container as it (and it's ancestors) have overflow:hidden
// we need to append it the first time since the popup has overflow:hidden
// then we show/hide based on the flag
if (this.conductorPopup.parentNode !== document.body) {
document.body.appendChild(this.conductorPopup);
}
this.$nextTick(() => {
window.addEventListener('resize', this.positionBox);
document.addEventListener('click', this.handleClickAway);
@@ -97,11 +100,6 @@ export default {
if (!this.conductorPopup) {
return;
}
if (this.conductorPopup.parentNode === document.body) {
document.body.removeChild(this.conductorPopup);
}
this.showConductorPopup = false;
this.conductorPopup = null;
this.positionX = -10000; // reset it off screan

View File

@@ -15,6 +15,7 @@
type="text"
autocorrect="off"
spellcheck="false"
aria-label="Start date"
@change="validateAllBounds('startDate')"
/>
<date-picker
@@ -34,6 +35,7 @@
type="text"
autocorrect="off"
spellcheck="false"
aria-label="Start time"
@change="validateAllBounds('startDate')"
/>
</div>
@@ -48,6 +50,7 @@
type="text"
autocorrect="off"
spellcheck="false"
aria-label="End date"
@change="validateAllBounds('endDate')"
/>
<date-picker
@@ -67,6 +70,7 @@
type="text"
autocorrect="off"
spellcheck="false"
aria-label="End time"
@change="validateAllBounds('endDate')"
/>
</div>
@@ -75,9 +79,10 @@
<button
class="c-button c-button--major icon-check"
:disabled="isDisabled"
aria-label="Submit time bounds"
@click.prevent="submit"
></button>
<button class="c-button icon-x" @click.prevent="hide"></button>
<button class="c-button icon-x" @click.prevent="hide" aria-label="Discard time bounds"></button>
</div>
</form>
</template>

View File

@@ -19,6 +19,7 @@
min="0"
max="23"
title="Enter 0 - 23"
aria-label="Start offset hours"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@@ -37,6 +38,7 @@
max="59"
title="Enter 0 - 59"
step="1"
aria-label="Start offset minutes"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@@ -55,6 +57,7 @@
max="59"
title="Enter 0 - 59"
step="1"
aria-label="Start offset seconds"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@@ -75,6 +78,7 @@
min="0"
max="23"
title="Enter 0 - 23"
aria-label="End offset hours"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@@ -111,6 +115,7 @@
max="59"
title="Enter 0 - 59"
step="1"
aria-label="End offset seconds"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@@ -123,9 +128,14 @@
<button
class="c-button c-button--major icon-check"
:disabled="isDisabled"
aria-label="Submit time offsets"
@click.prevent="submit"
></button>
<button class="c-button icon-x" @click.prevent="hide"></button>
<button
class="c-button icon-x"
aria-label="Discard time offsets"
@click.prevent="hide"
></button>
</div>
</form>
</template>
@@ -167,7 +177,7 @@ export default {
methods: {
format(ref) {
const curVal = this[ref];
this[ref] = curVal.padStart(2, '0');
this[ref] = curVal.toString().padStart(2, '0');
},
validate() {
let disabled = false;

View File

@@ -103,9 +103,8 @@ export default {
},
inject: ['openmct', 'domainObject', 'path', 'composition'],
data() {
this.planObjects = [];
return {
planObjects: [],
viewBounds: undefined,
height: 0,
planActivities: [],
@@ -345,12 +344,13 @@ export default {
let activities = [];
groups.forEach((key) => {
activities = activities.concat(this.planData[key]);
// Create new objects so Vue 3 can detect any changes
activities = activities.concat(JSON.parse(JSON.stringify(this.planData[key])));
});
// filter activities first, then sort by start time
activities = activities.filter(this.filterActivities).sort(this.sortByStartTime);
activities = this.applyStyles(activities);
this.planActivities = activities;
this.planActivities = [...activities];
//We need to wait for the next tick since we need the height of the row from the DOM
this.$nextTick(this.setScrollTop);
},

View File

@@ -23,8 +23,8 @@
<template>
<div class="c-inspector js-inspector">
<object-name />
<InspectorTabs :selection="selection" :is-editing="isEditing" @select-tab="selectTab" />
<InspectorViews :selection="selection" :selected-tab="selectedTab" />
<InspectorTabs :is-editing="isEditing" @select-tab="selectTab" />
<InspectorViews :selected-tab="selectedTab" />
</div>
</template>
@@ -48,20 +48,10 @@ export default {
},
data() {
return {
selection: this.openmct.selection.get(),
selectedTab: undefined
};
},
mounted() {
this.openmct.selection.on('change', this.setSelection);
},
unmounted() {
this.openmct.selection.off('change', this.setSelection);
},
methods: {
setSelection(selection) {
this.selection = selection;
},
selectTab(tab) {
this.selectedTab = tab;
}

View File

@@ -40,21 +40,11 @@
export default {
inject: ['openmct'],
props: {
selection: {
type: Array,
default: () => {
return [];
}
},
isEditing: {
type: Boolean,
required: true
}
},
selection: {
type: Array,
default: []
},
data() {
return {
tabs: [],
@@ -69,12 +59,6 @@ export default {
}
},
watch: {
selection: {
handler() {
this.updateSelection();
},
deep: true
},
visibleTabs: {
handler() {
this.selectDefaultTabIfSelectedNotVisible();
@@ -82,9 +66,16 @@ export default {
deep: true
}
},
mounted() {
this.updateSelection();
this.openmct.selection.on('change', this.updateSelection);
},
unmounted() {
this.openmct.selection.off('change', this.updateSelection);
},
methods: {
updateSelection() {
const inspectorViews = this.openmct.inspectorViews.get(this.selection);
const inspectorViews = this.openmct.inspectorViews.get(this.openmct.selection.get());
this.tabs = inspectorViews.map((view) => {
return {

View File

@@ -31,29 +31,24 @@ export default {
selectedTab: {
type: Object,
default: undefined
},
selection: {
type: Array,
default: () => {
return [];
}
}
},
watch: {
selection: {
handler() {
this.updateSelectionViews();
},
deep: true
},
selectedTab() {
this.clearAndShowViewsForTab();
}
},
mounted() {
this.updateSelectionViews();
this.openmct.selection.on('change', this.updateSelectionViews);
},
unmounted() {
this.openmct.selection.off('change', this.updateSelectionViews);
},
methods: {
updateSelectionViews(selection) {
this.clearViews();
this.selectedViews = this.openmct.inspectorViews.get(this.selection);
this.selectedViews = this.openmct.inspectorViews.get(this.openmct.selection.get());
this.showViewsForTab();
},
clearViews() {

View File

@@ -351,8 +351,10 @@ export default {
this.endItemLoad(parentPath);
this.treeItems.splice(parentIndex + 1, 0, ...childrenItems);
const newTreeItems = [...this.treeItems];
newTreeItems.splice(parentIndex + 1, 0, ...childrenItems);
this.treeItems = [...newTreeItems];
if (!this.isTreeItemOpen(parentItem)) {
this.openTreeItems.push(parentPath);
}
@@ -388,7 +390,9 @@ export default {
return true;
});
this.openTreeItems.splice(pathIndex, 1);
const newOpenTreeItems = [...this.openTreeItems];
newOpenTreeItems.splice(pathIndex, 1);
this.openTreeItems = [...newOpenTreeItems];
this.removeCompositionListenerFor(path);
},
closeTreeItem(item) {
@@ -703,11 +707,13 @@ export default {
});
// Splice in all of the sorted descendants
this.treeItems.splice(
this.treeItems.indexOf(parentItem) + 1,
const newTreeItems = [...this.treeItems];
newTreeItems.splice(
newTreeItems.indexOf(parentItem) + 1,
sortedTreeItems.length,
...sortedTreeItems
);
this.treeItems = [...newTreeItems];
},
buildNavigationPath(objectPath) {
return (
@@ -792,7 +798,9 @@ export default {
}
const removeIndex = this.getTreeItemIndex(item.navigationPath);
this.treeItems.splice(removeIndex, 1);
const newTreeItems = [...this.treeItems];
newTreeItems.splice(removeIndex, 1);
this.treeItems = [...newTreeItems];
},
addItemToTreeBefore(addItem, beforeItem) {
const addIndex = this.getTreeItemIndex(beforeItem.navigationPath);
@@ -805,7 +813,9 @@ export default {
this.addItemToTree(addItem, addIndex + 1);
},
addItemToTree(addItem, index) {
this.treeItems.splice(index, 0, addItem);
const newTreeItems = [...this.treeItems];
newTreeItems.splice(index, 0, addItem);
this.treeItems = [...newTreeItems];
if (this.isTreeItemOpen(addItem)) {
this.openTreeItem(addItem);

View File

@@ -50,7 +50,7 @@ export default {
event.preventDefault();
event.stopPropagation();
let actionsCollection = this.openmct.actions.getActionsCollection(this.objectPath);
let actionsCollection = this.openmct.actions.getActionsCollection(toRaw(this.objectPath));
let actions = actionsCollection.getVisibleActions();
let sortedActions = this.openmct.actions._groupAndSortActions(actions);