mirror of
https://github.com/nasa/openmct.git
synced 2024-12-24 07:16:39 +00:00
Set location hash if query parameters or path have changed (#7306)
* refactor to es6 class * change URL on path or params change * add test for url * put into edit mode for test * es6 module export * a11y: add `status` role to clock component * a11y: add label to overlay * a11y: update roles for search results * a11y: add `dialog` role and label for PreviewContainer * refactor(e2e): get rid of a bunch of `page.locator()`s * refactor(e2e): spruce up locators * test: fix unit tests * fix tests with new aria labels * fix tests with new aria labels * fix tests with new aria labels --------- Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov>
This commit is contained in:
parent
dfba4e23c5
commit
64d4ddd80e
@ -91,27 +91,30 @@ test.describe('Notification Overlay', () => {
|
||||
// Create a new Display Layout object
|
||||
await createDomainObjectWithDefaults(page, { type: 'Display Layout' });
|
||||
|
||||
// Dismiss notification banner
|
||||
await page.getByRole('button', { name: 'Dismiss' }).click();
|
||||
|
||||
// Click on the button "Review 1 Notification"
|
||||
await page.click('button[aria-label="Review 1 Notification"]');
|
||||
await page.getByRole('button', { name: 'Review 1 Notification' }).click();
|
||||
|
||||
// Verify that Notification List is open
|
||||
expect(await page.locator('div[role="dialog"]').isVisible()).toBe(true);
|
||||
await expect(page.getByRole('dialog', { name: 'Overlay' })).toBeVisible();
|
||||
|
||||
// Wait until there is no Notification Banner
|
||||
await page.waitForSelector('div[role="alert"]', { state: 'detached' });
|
||||
await expect(page.getByRole('alert')).not.toBeAttached();
|
||||
|
||||
// Click on the "Close" button of the Notification List
|
||||
await page.click('button[aria-label="Close"]');
|
||||
await page.getByRole('button', { name: 'Close' }).click();
|
||||
|
||||
// On the Display Layout object, click on the "Edit" button
|
||||
await page.click('button[title="Edit"]');
|
||||
await page.getByRole('button', { name: 'Edit' }).click();
|
||||
|
||||
// Click on the "Save" button
|
||||
await page.click('button[title="Save"]');
|
||||
await page.getByRole('button', { name: 'Save' }).click();
|
||||
|
||||
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
|
||||
|
||||
// Verify that Notification List is NOT open
|
||||
expect(await page.locator('div[role="dialog"]').isVisible()).toBe(false);
|
||||
await expect(page.getByRole('dialog', { name: 'Overlay' })).toBeHidden();
|
||||
});
|
||||
});
|
||||
|
@ -290,7 +290,7 @@ test.describe('Flexible Layout Toolbar Actions @localStorage', () => {
|
||||
await page.getByTitle('Add Container').click();
|
||||
expect(await containerHandles.count()).toEqual(3);
|
||||
await page.getByTitle('Remove Container').click();
|
||||
await expect(page.getByRole('dialog')).toHaveText(
|
||||
await expect(page.getByRole('dialog', { name: 'Overlay' })).toHaveText(
|
||||
'This action will permanently delete this container from this Flexible Layout. Do you want to continue?'
|
||||
);
|
||||
await page.getByRole('button', { name: 'OK' }).click();
|
||||
@ -300,7 +300,7 @@ test.describe('Flexible Layout Toolbar Actions @localStorage', () => {
|
||||
expect(await page.getByRole('group', { name: 'Frame' }).count()).toEqual(2);
|
||||
await page.getByRole('group', { name: 'Child Layout 1' }).click();
|
||||
await page.getByTitle('Remove Frame').click();
|
||||
await expect(page.getByRole('dialog')).toHaveText(
|
||||
await expect(page.getByRole('dialog', { name: 'Overlay' })).toHaveText(
|
||||
'This action will remove this frame from this Flexible Layout. Do you want to continue?'
|
||||
);
|
||||
await page.getByRole('button', { name: 'OK' }).click();
|
||||
|
@ -185,16 +185,20 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
|
||||
//Partial match for "Science" should only return Science
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Sc');
|
||||
await expect(page.locator('[aria-label="Search Result"]').first()).toContainText('Science');
|
||||
await expect(page.locator('[aria-label="Search Result"]').first()).not.toContainText('Driving');
|
||||
await expect(page.locator('[aria-label="Search Result"]').first()).not.toContainText(
|
||||
await expect(page.locator('[aria-label="Annotation Search Result"]').first()).toContainText(
|
||||
'Science'
|
||||
);
|
||||
await expect(page.locator('[aria-label="Annotation Search Result"]').first()).not.toContainText(
|
||||
'Driving'
|
||||
);
|
||||
await expect(page.locator('[aria-label="Annotation Search Result"]').first()).not.toContainText(
|
||||
'Drilling'
|
||||
);
|
||||
|
||||
//Searching for a tag which does not exist should return an empty result
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Xq');
|
||||
await expect(page.locator('text=No results found')).toBeVisible();
|
||||
await expect(page.getByText('No results found')).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -88,43 +88,53 @@ test.describe('Tagging in Notebooks @addInit', () => {
|
||||
|
||||
await page.locator('[placeholder="Type to select tag"]').click();
|
||||
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
|
||||
await page.getByRole('search').getByLabel('Search Input').click();
|
||||
|
||||
await expect(page.locator('button:has-text("Add Tag")')).toBeVisible();
|
||||
|
||||
// Test canceling adding a tag after we just click "Add Tag"
|
||||
await page.locator('button:has-text("Add Tag")').click();
|
||||
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
|
||||
await page.getByRole('search').getByLabel('Search Input').click();
|
||||
|
||||
await expect(page.locator('button:has-text("Add Tag")')).toBeVisible();
|
||||
});
|
||||
test('Can search for tags and preview works properly', async ({ page }) => {
|
||||
await createNotebookEntryAndTags(page);
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc');
|
||||
await expect(page.locator('[aria-label="Search Result"]')).toContainText('Science');
|
||||
await expect(page.locator('[aria-label="Search Result"]')).not.toContainText('Driving');
|
||||
await page.getByRole('search').getByLabel('Search Input').click();
|
||||
await page.getByRole('search').getByLabel('Search Input').fill('sc');
|
||||
await expect(page.getByRole('listitem', { name: 'Annotation Search Result' })).toContainText(
|
||||
'Science'
|
||||
);
|
||||
await expect(
|
||||
page.getByRole('listitem', { name: 'Annotation Search Result' })
|
||||
).not.toContainText('Driving');
|
||||
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Sc');
|
||||
await expect(page.locator('[aria-label="Search Result"]')).toContainText('Science');
|
||||
await expect(page.locator('[aria-label="Search Result"]')).not.toContainText('Driving');
|
||||
await page.getByRole('search').getByLabel('Search Input').click();
|
||||
await page.getByRole('search').getByLabel('Search Input').fill('Sc');
|
||||
await expect(page.getByRole('listitem', { name: 'Annotation Search Result' })).toContainText(
|
||||
'Science'
|
||||
);
|
||||
await expect(
|
||||
page.getByRole('listitem', { name: 'Annotation Search Result' })
|
||||
).not.toContainText('Driving');
|
||||
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Xq');
|
||||
await expect(page.locator('text=No results found')).toBeVisible();
|
||||
await page.getByRole('search').getByLabel('Search Input').click();
|
||||
await page.getByRole('search').getByLabel('Search Input').fill('Xq');
|
||||
await expect(page.getByText('No results found')).toBeVisible();
|
||||
|
||||
await createDomainObjectWithDefaults(page, {
|
||||
type: 'Display Layout'
|
||||
});
|
||||
|
||||
// Go back into edit mode for the display layout
|
||||
await page.locator('button[title="Edit"]').click();
|
||||
await page.getByRole('button', { name: 'Edit' }).click();
|
||||
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Sc');
|
||||
await expect(page.locator('[aria-label="Search Result"]')).toContainText('Science');
|
||||
await page.getByRole('search').getByLabel('Search Input').click();
|
||||
await page.getByRole('search').getByLabel('Search Input').fill('Sc');
|
||||
await expect(page.getByRole('listitem', { name: 'Annotation Search Result' })).toContainText(
|
||||
'Science'
|
||||
);
|
||||
await page.getByText('Entry 0').click();
|
||||
await expect(page.locator('.js-preview-window')).toBeVisible();
|
||||
});
|
||||
@ -138,8 +148,10 @@ test.describe('Tagging in Notebooks @addInit', () => {
|
||||
await expect(page.locator('[aria-label="Tags Inspector"]')).toContainText('Science');
|
||||
await expect(page.locator('[aria-label="Tags Inspector"]')).not.toContainText('Driving');
|
||||
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc');
|
||||
await expect(page.locator('[aria-label="Search Result"]')).not.toContainText('Driving');
|
||||
await page.getByRole('search').getByLabel('Search Input').fill('sc');
|
||||
await expect(
|
||||
page.getByRole('listitem', { name: 'Annotation Search Result' })
|
||||
).not.toContainText('Driving');
|
||||
});
|
||||
|
||||
test('Can delete entries without tags', async ({ page }) => {
|
||||
@ -172,12 +184,12 @@ test.describe('Tagging in Notebooks @addInit', () => {
|
||||
await page.locator('button:has-text("OK")').click();
|
||||
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Unnamed');
|
||||
await expect(page.locator('text=No results found')).toBeVisible();
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sci');
|
||||
await expect(page.locator('text=No results found')).toBeVisible();
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('dri');
|
||||
await expect(page.locator('text=No results found')).toBeVisible();
|
||||
await page.getByRole('search').getByLabel('Search Input').fill('Unnamed');
|
||||
await expect(page.getByText('No results found')).toBeVisible();
|
||||
await page.getByRole('search').getByLabel('Search Input').fill('sci');
|
||||
await expect(page.getByText('No results found')).toBeVisible();
|
||||
await page.getByRole('search').getByLabel('Search Input').fill('dri');
|
||||
await expect(page.getByText('No results found')).toBeVisible();
|
||||
});
|
||||
test('Tags persist across reload', async ({ page }) => {
|
||||
//Go to baseURL
|
||||
|
@ -29,12 +29,15 @@ import { createDomainObjectWithDefaults } from '../../appActions.js';
|
||||
import { expect, test } from '../../pluginFixtures.js';
|
||||
|
||||
test.describe('Grand Search', () => {
|
||||
const searchResultSelector = '.c-gsearch-result__title';
|
||||
const searchResultDropDownSelector = '.c-gsearch__results';
|
||||
let grandSearchInput;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
grandSearchInput = page
|
||||
.getByLabel('OpenMCT Search')
|
||||
.getByRole('searchbox', { name: 'Search Input' });
|
||||
|
||||
// Go to baseURL
|
||||
await page.goto('./', { waitUntil: 'networkidle' });
|
||||
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||
});
|
||||
|
||||
test('Can search for objects, and subsequent search dropdown behaves properly', async ({
|
||||
@ -45,103 +48,124 @@ test.describe('Grand Search', () => {
|
||||
|
||||
const createdObjects = await createObjectsForSearch(page);
|
||||
|
||||
// Click [aria-label="OpenMCT Search"] input[type="search"]
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
|
||||
// Fill [aria-label="OpenMCT Search"] input[type="search"]
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Cl');
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(
|
||||
// Go back into edit mode for the display layout
|
||||
await page.getByRole('button', { name: 'Edit' }).click();
|
||||
|
||||
await grandSearchInput.click();
|
||||
await grandSearchInput.fill('Cl');
|
||||
|
||||
await expect(page.getByLabel('Object Search Result').first()).toContainText(
|
||||
`Clock A ${myItemsFolderName} Red Folder Blue Folder`
|
||||
);
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=1')).toContainText(
|
||||
await expect(page.getByLabel('Object Search Result').nth(1)).toContainText(
|
||||
`Clock B ${myItemsFolderName} Red Folder Blue Folder`
|
||||
);
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=2')).toContainText(
|
||||
await expect(page.getByLabel('Object Search Result').nth(2)).toContainText(
|
||||
`Clock C ${myItemsFolderName} Red Folder Blue Folder`
|
||||
);
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=3')).toContainText(
|
||||
await expect(page.getByLabel('Object Search Result').nth(3)).toContainText(
|
||||
`Clock D ${myItemsFolderName} Red Folder Blue Folder`
|
||||
);
|
||||
// Click the Elements pool to dismiss the search menu
|
||||
await page.getByRole('tab', { name: 'Elements' }).click();
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden();
|
||||
await expect(page.getByLabel('Object Search Result').first()).toBeHidden();
|
||||
|
||||
await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').click();
|
||||
await page.locator('[aria-label="Clock A clock result"] >> text=Clock A').click();
|
||||
await expect(page.locator('.js-preview-window')).toBeVisible();
|
||||
await grandSearchInput.click();
|
||||
await page.getByLabel('OpenMCT Search').getByText('Clock A').click();
|
||||
await expect(page.getByRole('dialog', { name: 'Preview Container' })).toBeVisible();
|
||||
|
||||
// Click [aria-label="Close"]
|
||||
await page.locator('[aria-label="Close"]').click();
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeVisible();
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(
|
||||
// Close the Preview window
|
||||
await page.getByRole('button', { name: 'Close' }).click();
|
||||
await expect(page.getByLabel('Object Search Result').first()).toBeVisible();
|
||||
await expect(page.getByLabel('Object Search Result').first()).toContainText(
|
||||
`Clock A ${myItemsFolderName} Red Folder Blue Folder`
|
||||
);
|
||||
|
||||
// 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 page.getByLabel('Object Search Result').first().click();
|
||||
await expect(page.getByLabel('Object Search Result').first()).toBeHidden();
|
||||
|
||||
// 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 grandSearchInput.fill('foo');
|
||||
await expect(page.getByLabel('Object Search Result').first()).toBeHidden();
|
||||
|
||||
// Click text=Snapshot Save and Finish Editing Save and Continue Editing >> button >> nth=1
|
||||
await page
|
||||
.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button')
|
||||
.nth(1)
|
||||
.click();
|
||||
await page.getByRole('button', { name: 'Save' }).click();
|
||||
|
||||
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
|
||||
// Click [aria-label="OpenMCT Search"] [aria-label="Search Input"]
|
||||
await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').click();
|
||||
await grandSearchInput.click();
|
||||
// Fill [aria-label="OpenMCT Search"] [aria-label="Search Input"]
|
||||
await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').fill('Cl');
|
||||
await grandSearchInput.fill('Cl');
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.locator('[aria-label="Clock A clock result"] >> text=Clock A').click()
|
||||
page.getByLabel('OpenMCT Search').getByText('Clock A').click()
|
||||
]);
|
||||
await expect(page.locator('.is-object-type-clock')).toBeVisible();
|
||||
await expect(page.getByRole('status', { name: 'Clock' })).toBeVisible();
|
||||
|
||||
await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').fill('Disp');
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(
|
||||
await grandSearchInput.fill('Disp');
|
||||
await expect(page.getByLabel('Object Search Result').first()).toContainText(
|
||||
createdObjects.displayLayout.name
|
||||
);
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).not.toContainText('Folder');
|
||||
await expect(page.getByLabel('Object Search Result').first()).not.toContainText('Folder');
|
||||
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Clock C');
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(
|
||||
await grandSearchInput.fill('Clock C');
|
||||
await expect(page.getByLabel('Object Search Result').first()).toContainText(
|
||||
`Clock C ${myItemsFolderName} Red Folder Blue Folder`
|
||||
);
|
||||
|
||||
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Cloc');
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(
|
||||
await grandSearchInput.fill('Cloc');
|
||||
await expect(page.getByLabel('Object Search Result').first()).toContainText(
|
||||
`Clock A ${myItemsFolderName} Red Folder Blue Folder`
|
||||
);
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=1')).toContainText(
|
||||
await expect(page.getByLabel('Object Search Result').nth(1)).toContainText(
|
||||
`Clock B ${myItemsFolderName} Red Folder Blue Folder`
|
||||
);
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=2')).toContainText(
|
||||
await expect(page.getByLabel('Object Search Result').nth(2)).toContainText(
|
||||
`Clock C ${myItemsFolderName} Red Folder Blue Folder`
|
||||
);
|
||||
await expect(page.locator('[aria-label="Search Result"] >> nth=3')).toContainText(
|
||||
await expect(page.getByLabel('Object Search Result').nth(3)).toContainText(
|
||||
`Clock D ${myItemsFolderName} Red Folder Blue Folder`
|
||||
);
|
||||
|
||||
await grandSearchInput.click();
|
||||
await grandSearchInput.fill('Sine');
|
||||
});
|
||||
|
||||
test('Clicking on a search result changes the URL even if the same type is already selected', async ({
|
||||
page
|
||||
}) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/nasa/openmct/issues/7303'
|
||||
});
|
||||
|
||||
const { sineWaveGeneratorAlpha, sineWaveGeneratorBeta } = await createObjectsForSearch(page);
|
||||
await grandSearchInput.click();
|
||||
await grandSearchInput.fill('Sine');
|
||||
await waitForSearchCompletion(page);
|
||||
await page.getByLabel('OpenMCT Search').getByText('Sine Wave Generator Alpha').click();
|
||||
const alphaPattern = new RegExp(sineWaveGeneratorAlpha.url.substring(1));
|
||||
await expect(page).toHaveURL(alphaPattern);
|
||||
await grandSearchInput.click();
|
||||
await page.getByLabel('OpenMCT Search').getByText('Sine Wave Generator Beta').click();
|
||||
const betaPattern = new RegExp(sineWaveGeneratorBeta.url.substring(1));
|
||||
await expect(page).toHaveURL(betaPattern);
|
||||
});
|
||||
|
||||
test('Validate empty search result', async ({ page }) => {
|
||||
// Invalid search for objects
|
||||
await page.type('input[type=search]', 'not found');
|
||||
await grandSearchInput.fill('not found');
|
||||
|
||||
// Wait for search to complete
|
||||
await waitForSearchCompletion(page);
|
||||
|
||||
// Get the search results
|
||||
const searchResults = page.locator(searchResultSelector);
|
||||
const searchResults = page.getByRole('listitem', { name: 'Object Search Result' });
|
||||
|
||||
// Verify that no results are found
|
||||
expect(await searchResults.count()).toBe(0);
|
||||
|
||||
// Verify proper message appears
|
||||
await expect(page.locator('text=No results found')).toBeVisible();
|
||||
await expect(page.getByText('No results found')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Validate single object in search result @couchdb', async ({ page }) => {
|
||||
@ -153,18 +177,18 @@ test.describe('Grand Search', () => {
|
||||
});
|
||||
|
||||
// Full search for object
|
||||
await page.type('input[type=search]', folderName);
|
||||
await grandSearchInput.fill(folderName);
|
||||
|
||||
// Wait for search to complete
|
||||
await waitForSearchCompletion(page);
|
||||
|
||||
// Get the search results
|
||||
const searchResults = page.locator(searchResultSelector);
|
||||
const searchResults = page.getByLabel('Object Search Result');
|
||||
|
||||
// Verify that one result is found
|
||||
await expect(searchResults).toBeVisible();
|
||||
expect(await searchResults.count()).toBe(1);
|
||||
await expect(searchResults).toHaveText(folderName);
|
||||
await expect(searchResults).toContainText(folderName);
|
||||
});
|
||||
|
||||
test('Search results are debounced @couchdb', async ({ page }) => {
|
||||
@ -185,7 +209,7 @@ test.describe('Grand Search', () => {
|
||||
});
|
||||
|
||||
// Full search for object
|
||||
await page.type('input[type=search]', 'Clock', { delay: 100 });
|
||||
await grandSearchInput.pressSequentially('Clock', { delay: 100 });
|
||||
|
||||
// Wait for search to finish
|
||||
await waitForSearchCompletion(page);
|
||||
@ -194,9 +218,7 @@ test.describe('Grand Search', () => {
|
||||
// 1. batched request for latest telemetry using the bulk API
|
||||
expect(networkRequests.length).toBe(1);
|
||||
|
||||
const searchResultDropDown = await page.locator(searchResultDropDownSelector);
|
||||
|
||||
await expect(searchResultDropDown).toContainText('Clock A');
|
||||
await expect(page.getByRole('list', { name: 'Object Results' })).toContainText('Clock A');
|
||||
});
|
||||
|
||||
test('Slowly typing after search debounce will abort requests @couchdb', async ({ page }) => {
|
||||
@ -246,27 +268,40 @@ test.describe('Grand Search', () => {
|
||||
});
|
||||
|
||||
// Partial search for objects
|
||||
await page.type('input[type=search]', 'e928a26e');
|
||||
await grandSearchInput.fill('e928a26e');
|
||||
|
||||
// Wait for search to finish
|
||||
await waitForSearchCompletion(page);
|
||||
|
||||
const searchResultDropDown = page.locator(searchResultDropDownSelector);
|
||||
const searchResultDropDown = page.getByRole('dialog', { name: 'Search Results' });
|
||||
|
||||
// Verify that the search result/s correctly match the search query
|
||||
await expect(searchResultDropDown).toContainText(folderName1);
|
||||
await expect(searchResultDropDown).toContainText(folderName2);
|
||||
|
||||
// Get the search results
|
||||
const searchResults = page.locator(searchResultSelector);
|
||||
const objectSearchResults = page.getByLabel('Object Search Result');
|
||||
// Verify that two results are found
|
||||
expect(await searchResults.count()).toBe(2);
|
||||
expect(await objectSearchResults.count()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Wait for search to complete
|
||||
*
|
||||
* @param {import('@playwright/test').Page} page
|
||||
*/
|
||||
async function waitForSearchCompletion(page) {
|
||||
// Wait loading spinner to disappear
|
||||
await page.waitForSelector('.search-finished');
|
||||
await expect(
|
||||
page
|
||||
.getByRole('list', { name: 'Object Results' })
|
||||
.or(
|
||||
page
|
||||
.getByRole('list', { name: 'Annotation Results' })
|
||||
.or(page.getByText('No results found'))
|
||||
)
|
||||
).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -306,13 +341,20 @@ async function createObjectsForSearch(page) {
|
||||
parent: blueFolder.uuid
|
||||
});
|
||||
|
||||
const sineWaveGeneratorAlpha = await createDomainObjectWithDefaults(page, {
|
||||
type: 'Sine Wave Generator',
|
||||
name: 'Sine Wave Generator Alpha'
|
||||
});
|
||||
|
||||
const sineWaveGeneratorBeta = await createDomainObjectWithDefaults(page, {
|
||||
type: 'Sine Wave Generator',
|
||||
name: 'Sine Wave Generator Beta'
|
||||
});
|
||||
|
||||
const displayLayout = await createDomainObjectWithDefaults(page, {
|
||||
type: 'Display Layout'
|
||||
});
|
||||
|
||||
// Go back into edit mode for the display layout
|
||||
await page.locator('button[title="Edit"]').click();
|
||||
|
||||
return {
|
||||
redFolder,
|
||||
blueFolder,
|
||||
@ -320,6 +362,8 @@ async function createObjectsForSearch(page) {
|
||||
clockB,
|
||||
clockC,
|
||||
clockD,
|
||||
displayLayout
|
||||
displayLayout,
|
||||
sineWaveGeneratorAlpha,
|
||||
sineWaveGeneratorBeta
|
||||
};
|
||||
}
|
||||
|
@ -45,19 +45,21 @@ test.describe("Visual - Check Notification Info Banner of 'Save successful' @a11
|
||||
name: 'Default Clock'
|
||||
});
|
||||
// Click on the div with role="alert" that has "Save successful" text
|
||||
await page.locator('div[role="alert"]:has-text("Save successful")').click();
|
||||
await page.getByRole('alert').filter({ hasText: 'Save successful' }).click();
|
||||
// Verify there is a div with role="dialog"
|
||||
expect(await page.locator('div[role="dialog"]').isVisible()).toBe(true);
|
||||
await expect(page.getByRole('dialog', { name: 'Overlay' })).toBeVisible();
|
||||
// Verify the div with role="dialog" contains text "Save successful"
|
||||
expect(await page.locator('div[role="dialog"]').innerText()).toContain('Save successful');
|
||||
expect(await page.getByRole('dialog', { name: 'Overlay' }).innerText()).toContain(
|
||||
'Save successful'
|
||||
);
|
||||
await percySnapshot(page, `Notification banner shows Save successful (theme: '${theme}')`);
|
||||
// Verify there is a button with text "Dismiss"
|
||||
expect(await page.locator('button:has-text("Dismiss")').isVisible()).toBe(true);
|
||||
await expect(page.getByText('Dismiss', { exact: true })).toBeVisible();
|
||||
await percySnapshot(page, `Notification banner shows Dismiss (theme: '${theme}')`);
|
||||
// Click on button with text "Dismiss"
|
||||
await page.locator('button:has-text("Dismiss")').click();
|
||||
await page.getByText('Dismiss', { exact: true }).click();
|
||||
// Verify there is no div with role="dialog"
|
||||
expect(await page.locator('div[role="dialog"]').isVisible()).toBe(false);
|
||||
await expect(page.getByRole('dialog', { name: 'Overlay' })).toBeHidden();
|
||||
await percySnapshot(page, `Notification banner dismissed (theme: '${theme}')`);
|
||||
});
|
||||
test.afterEach(async ({ page }, testInfo) => {
|
||||
|
@ -338,7 +338,7 @@ export class MCT extends EventEmitter {
|
||||
component.$nextTick(() => {
|
||||
this.layout = component;
|
||||
this.app = appLayout;
|
||||
Browse(this);
|
||||
this.browseRoutes = new Browse(this);
|
||||
window.addEventListener('beforeunload', this.destroy);
|
||||
this.router.start();
|
||||
this.emit('start');
|
||||
|
@ -34,6 +34,7 @@
|
||||
class="c-overlay__contents js-notebook-snapshot-item-wrapper"
|
||||
tabindex="0"
|
||||
aria-modal="true"
|
||||
aria-label="Overlay"
|
||||
role="dialog"
|
||||
></div>
|
||||
<div v-if="buttons" class="c-overlay__button-bar">
|
||||
|
@ -22,7 +22,13 @@
|
||||
|
||||
<template>
|
||||
<div class="u-contents">
|
||||
<div class="c-clock l-time-display u-style-receiver js-style-receiver">
|
||||
<div
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
aria-atomic="true"
|
||||
aria-label="Clock"
|
||||
class="c-clock l-time-display u-style-receiver js-style-receiver"
|
||||
>
|
||||
<div class="c-clock__timezone">
|
||||
{{ timeZoneAbbr }}
|
||||
</div>
|
||||
|
@ -23,11 +23,11 @@
|
||||
<template>
|
||||
<div
|
||||
class="c-gsearch-result c-gsearch-result--annotation"
|
||||
aria-label="Search Result"
|
||||
role="presentation"
|
||||
aria-label="Annotation Search Result"
|
||||
role="listitem"
|
||||
>
|
||||
<div class="c-gsearch-result__type-icon" :class="resultTypeIcon"></div>
|
||||
<div class="c-gsearch-result__body" aria-label="Annotation Search Result">
|
||||
<div class="c-gsearch-result__body">
|
||||
<div class="c-gsearch-result__title" @click="clickedResult">
|
||||
{{ getResultName }}
|
||||
</div>
|
||||
|
@ -272,15 +272,15 @@ describe('GrandSearch', () => {
|
||||
it('should render an annotation search result', async () => {
|
||||
await grandSearchComponent.$refs.root.searchEverything('S');
|
||||
await nextTick();
|
||||
const annotationResults = document.querySelectorAll('[aria-label="Search Result"]');
|
||||
expect(annotationResults.length).toBe(2);
|
||||
expect(annotationResults[1].innerText).toContain('Driving');
|
||||
const annotationResults = document.querySelectorAll('[aria-label="Annotation Search Result"]');
|
||||
expect(annotationResults.length).toBe(1);
|
||||
expect(annotationResults[0].innerText).toContain('Driving');
|
||||
});
|
||||
|
||||
it('should render no annotation search results if no match', async () => {
|
||||
await grandSearchComponent.$refs.root.searchEverything('Qbert');
|
||||
await nextTick();
|
||||
const annotationResults = document.querySelectorAll('[aria-label="Search Result"]');
|
||||
const annotationResults = document.querySelectorAll('[aria-label="Annotation Search Result"]');
|
||||
expect(annotationResults.length).toBe(0);
|
||||
});
|
||||
|
||||
@ -288,10 +288,9 @@ describe('GrandSearch', () => {
|
||||
await grandSearchComponent.$refs.root.searchEverything('Folder');
|
||||
grandSearchComponent.$refs.root.openmct.router.path = [mockDisplayLayout];
|
||||
await nextTick();
|
||||
const searchResults = document.querySelectorAll('[name="Test Folder"]');
|
||||
expect(searchResults.length).toBe(1);
|
||||
expect(searchResults[0].innerText).toContain('Folder');
|
||||
searchResults[0].click();
|
||||
const folderResult = document.querySelector('[name="Test Folder"]');
|
||||
expect(folderResult).not.toBeNull();
|
||||
folderResult.click();
|
||||
const previewWindow = document.querySelector('.js-preview-window');
|
||||
expect(previewWindow.innerText).toContain('Snapshot');
|
||||
});
|
||||
@ -300,7 +299,7 @@ describe('GrandSearch', () => {
|
||||
await grandSearchComponent.$refs.root.searchEverything('Dri');
|
||||
grandSearchComponent.$refs.root.openmct.router.path = [mockDisplayLayout];
|
||||
await nextTick();
|
||||
const annotationResults = document.querySelectorAll('[aria-label="Search Result"]');
|
||||
const annotationResults = document.querySelectorAll('[aria-label="Annotation Search Result"]');
|
||||
expect(annotationResults.length).toBe(1);
|
||||
expect(annotationResults[0].innerText).toContain('Driving');
|
||||
annotationResults[0].click();
|
||||
|
@ -23,8 +23,8 @@
|
||||
<template>
|
||||
<div
|
||||
class="c-gsearch-result c-gsearch-result--object"
|
||||
aria-label="Search Result"
|
||||
role="presentation"
|
||||
aria-label="Object Search Result"
|
||||
role="listitem"
|
||||
>
|
||||
<div class="c-gsearch-result__type-icon" :class="resultTypeIcon"></div>
|
||||
<div
|
||||
|
@ -21,14 +21,15 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="c-gsearch__dropdown">
|
||||
<div role="dialog" aria-label="Search Results Dropdown" class="c-gsearch__dropdown">
|
||||
<div v-show="resultsShown" class="c-gsearch__results-wrapper">
|
||||
<div class="c-gsearch__results" :class="{ 'search-finished': !searchLoading }">
|
||||
<div
|
||||
v-if="objectResults && objectResults.length"
|
||||
v-if="objectResults?.length"
|
||||
ref="objectResults"
|
||||
class="c-gsearch__results-section"
|
||||
role="listbox"
|
||||
role="list"
|
||||
aria-label="Object Results"
|
||||
>
|
||||
<div class="c-gsearch__results-section-title">Object Results</div>
|
||||
<object-search-result
|
||||
@ -39,7 +40,12 @@
|
||||
@click="selectedResult"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="annotationResults && annotationResults.length" ref="annotationResults">
|
||||
<div
|
||||
v-if="annotationResults?.length"
|
||||
ref="annotationResults"
|
||||
role="list"
|
||||
aria-label="Annotation Results"
|
||||
>
|
||||
<div class="c-gsearch__results-section-title">Annotation Results</div>
|
||||
<annotation-search-result
|
||||
v-for="annotationResult in annotationResults"
|
||||
|
@ -20,7 +20,7 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<template>
|
||||
<div class="l-preview-window js-preview-window">
|
||||
<div role="dialog" aria-label="Preview Container" class="l-preview-window js-preview-window">
|
||||
<PreviewHeader
|
||||
ref="previewHeader"
|
||||
:current-view="currentViewProvider"
|
||||
|
@ -306,10 +306,11 @@ class ApplicationRouter extends EventEmitter {
|
||||
*
|
||||
* @param {string} newPath new path of url
|
||||
* @param {string} oldPath old path of url
|
||||
* @returns {boolean} true if path changed, false otherwise
|
||||
*/
|
||||
doPathChange(newPath, oldPath) {
|
||||
if (newPath === oldPath) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
let route = this.routes.filter((r) => r.matcher.test(newPath))[0];
|
||||
@ -320,6 +321,8 @@ class ApplicationRouter extends EventEmitter {
|
||||
this.openmct.telemetry.abortAllRequests();
|
||||
|
||||
this.emit('change:path', newPath, oldPath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -328,10 +331,11 @@ class ApplicationRouter extends EventEmitter {
|
||||
*
|
||||
* @param {object} newParams new params of url
|
||||
* @param {object} oldParams old params of url
|
||||
* @returns {boolean} true if params changed, false otherwise
|
||||
*/
|
||||
doParamsChange(newParams, oldParams) {
|
||||
if (_.isEqual(newParams, oldParams)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
let changedParams = {};
|
||||
@ -347,6 +351,7 @@ class ApplicationRouter extends EventEmitter {
|
||||
});
|
||||
|
||||
this.emit('change:params', newParams, oldParams, changedParams);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -368,9 +373,13 @@ class ApplicationRouter extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
this.doPathChange(newLocation.path, oldLocation.path);
|
||||
const pathChanged = this.doPathChange(newLocation.path, oldLocation.path);
|
||||
|
||||
this.doParamsChange(newLocation.params, oldLocation.params);
|
||||
const paramsChanged = this.doParamsChange(newLocation.params, oldLocation.params, pathChanged);
|
||||
if (pathChanged || paramsChanged) {
|
||||
// If either path or parameters have changed, we update the URL in the address bar.
|
||||
this.set(newLocation.path, newLocation.getQueryString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,153 +1,167 @@
|
||||
export default function install(openmct) {
|
||||
let navigateCall = 0;
|
||||
let browseObject;
|
||||
let unobserve = undefined;
|
||||
let currentObjectPath;
|
||||
let isRoutingInProgress = false;
|
||||
/*****************************************************************************
|
||||
* 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.
|
||||
*****************************************************************************/
|
||||
|
||||
openmct.router.route(/^\/browse\/?$/, navigateToFirstChildOfRoot);
|
||||
openmct.router.route(/^\/browse\/(.*)$/, (path, results, params) => {
|
||||
isRoutingInProgress = true;
|
||||
let navigatePath = results[1];
|
||||
clearMutationListeners();
|
||||
export default class Browse {
|
||||
#navigateCall = 0;
|
||||
#browseObject = null;
|
||||
#unobserve = undefined;
|
||||
#currentObjectPath = undefined;
|
||||
#isRoutingInProgress = false;
|
||||
#openmct;
|
||||
|
||||
navigateToPath(navigatePath, params.view);
|
||||
});
|
||||
constructor(openmct) {
|
||||
this.#openmct = openmct;
|
||||
this.#openmct.router.route(/^\/browse\/?$/, this.#navigateToFirstChildOfRoot.bind(this));
|
||||
this.#openmct.router.route(/^\/browse\/(.*)$/, this.#handleBrowseRoute.bind(this));
|
||||
this.#openmct.router.on('change:params', this.#onParamsChanged.bind(this));
|
||||
}
|
||||
|
||||
openmct.router.on('change:params', onParamsChanged);
|
||||
|
||||
function onParamsChanged(newParams, oldParams, changed) {
|
||||
if (isRoutingInProgress) {
|
||||
#onParamsChanged(newParams, oldParams, changed) {
|
||||
if (this.#isRoutingInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (changed.view && browseObject) {
|
||||
let provider = openmct.objectViews.getByProviderKey(changed.view);
|
||||
viewObject(browseObject, provider);
|
||||
if (changed.view && this.#browseObject) {
|
||||
const provider = this.#openmct.objectViews.getByProviderKey(changed.view);
|
||||
this.#viewObject(this.#browseObject, provider);
|
||||
}
|
||||
}
|
||||
|
||||
function viewObject(object, viewProvider) {
|
||||
currentObjectPath = openmct.router.path;
|
||||
#viewObject(object, viewProvider) {
|
||||
this.#currentObjectPath = this.#openmct.router.path;
|
||||
|
||||
openmct.layout.$refs.browseObject.show(object, viewProvider.key, true, currentObjectPath);
|
||||
openmct.layout.$refs.browseBar.domainObject = object;
|
||||
|
||||
openmct.layout.$refs.browseBar.viewKey = viewProvider.key;
|
||||
this.#openmct.layout.$refs.browseObject.show(
|
||||
object,
|
||||
viewProvider.key,
|
||||
true,
|
||||
this.#currentObjectPath
|
||||
);
|
||||
this.#openmct.layout.$refs.browseBar.domainObject = object;
|
||||
this.#openmct.layout.$refs.browseBar.viewKey = viewProvider.key;
|
||||
}
|
||||
|
||||
function updateDocumentTitleOnNameMutation(newName) {
|
||||
#updateDocumentTitleOnNameMutation(newName) {
|
||||
if (typeof newName === 'string' && newName !== document.title) {
|
||||
document.title = newName;
|
||||
openmct.layout.$refs.browseBar.domainObject = {
|
||||
...openmct.layout.$refs.browseBar.domainObject,
|
||||
this.#openmct.layout.$refs.browseBar.domainObject = {
|
||||
...this.#openmct.layout.$refs.browseBar.domainObject,
|
||||
name: newName
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function navigateToPath(path, currentViewKey) {
|
||||
navigateCall++;
|
||||
let currentNavigation = navigateCall;
|
||||
async #navigateToPath(path, currentViewKey) {
|
||||
this.#navigateCall++;
|
||||
const currentNavigation = this.#navigateCall;
|
||||
|
||||
if (unobserve) {
|
||||
unobserve();
|
||||
unobserve = undefined;
|
||||
if (this.#unobserve) {
|
||||
this.#unobserve();
|
||||
this.#unobserve = undefined;
|
||||
}
|
||||
|
||||
//Split path into object identifiers
|
||||
if (!Array.isArray(path)) {
|
||||
path = path.split('/');
|
||||
}
|
||||
|
||||
return pathToObjects(path).then((objects) => {
|
||||
isRoutingInProgress = false;
|
||||
|
||||
if (currentNavigation !== navigateCall) {
|
||||
let objects = await this.#pathToObjects(path);
|
||||
if (currentNavigation !== this.#navigateCall) {
|
||||
return; // Prevent race.
|
||||
}
|
||||
|
||||
this.#isRoutingInProgress = false;
|
||||
objects = objects.reverse();
|
||||
|
||||
openmct.router.path = objects;
|
||||
openmct.router.emit('afterNavigation');
|
||||
browseObject = objects[0];
|
||||
|
||||
openmct.layout.$refs.browseBar.domainObject = browseObject;
|
||||
if (!browseObject) {
|
||||
openmct.layout.$refs.browseObject.clear();
|
||||
|
||||
this.#openmct.router.path = objects;
|
||||
this.#browseObject = objects[0];
|
||||
this.#openmct.router.emit('afterNavigation');
|
||||
this.#openmct.layout.$refs.browseBar.domainObject = this.#browseObject;
|
||||
if (!this.#browseObject) {
|
||||
this.#openmct.layout.$refs.browseObject.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
let currentProvider = openmct.objectViews.getByProviderKey(currentViewKey);
|
||||
document.title = browseObject.name; //change document title to current object in main view
|
||||
// assign listener to global for later clearing
|
||||
unobserve = openmct.objects.observe(browseObject, 'name', updateDocumentTitleOnNameMutation);
|
||||
|
||||
if (currentProvider && currentProvider.canView(browseObject, openmct.router.path)) {
|
||||
viewObject(browseObject, currentProvider);
|
||||
|
||||
document.title = this.#browseObject.name; //change document title to current object in main view
|
||||
this.#unobserve = this.#openmct.objects.observe(
|
||||
this.#browseObject,
|
||||
'name',
|
||||
this.#updateDocumentTitleOnNameMutation.bind(this)
|
||||
);
|
||||
const currentProvider = this.#openmct.objectViews.getByProviderKey(currentViewKey);
|
||||
if (currentProvider && currentProvider.canView(this.#browseObject, this.#openmct.router.path)) {
|
||||
this.#viewObject(this.#browseObject, currentProvider);
|
||||
return;
|
||||
}
|
||||
|
||||
let defaultProvider = openmct.objectViews.get(browseObject, openmct.router.path)[0];
|
||||
const routerPath = this.#openmct.router.path;
|
||||
const retrievedObjectViews = this.#openmct.objectViews.get(this.#browseObject, routerPath);
|
||||
const defaultProvider = retrievedObjectViews?.[0];
|
||||
if (defaultProvider) {
|
||||
openmct.router.updateParams({
|
||||
view: defaultProvider.key
|
||||
});
|
||||
this.#openmct.router.updateParams({ view: defaultProvider.key });
|
||||
} else {
|
||||
openmct.router.updateParams({
|
||||
view: undefined
|
||||
});
|
||||
openmct.layout.$refs.browseObject.clear();
|
||||
this.#openmct.router.updateParams({ view: undefined });
|
||||
this.#openmct.layout.$refs.browseObject.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function pathToObjects(path) {
|
||||
#pathToObjects(path) {
|
||||
return Promise.all(
|
||||
path.map((keyString) => {
|
||||
let identifier = openmct.objects.parseKeyString(keyString);
|
||||
if (openmct.objects.supportsMutation(identifier)) {
|
||||
return openmct.objects.getMutable(identifier);
|
||||
} else {
|
||||
return openmct.objects.get(identifier);
|
||||
}
|
||||
const identifier = this.#openmct.objects.parseKeyString(keyString);
|
||||
return this.#openmct.objects.supportsMutation(identifier)
|
||||
? this.#openmct.objects.getMutable(identifier)
|
||||
: this.#openmct.objects.get(identifier);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function navigateToFirstChildOfRoot() {
|
||||
openmct.objects
|
||||
.get('ROOT')
|
||||
.then((rootObject) => {
|
||||
const composition = openmct.composition.get(rootObject);
|
||||
async #navigateToFirstChildOfRoot() {
|
||||
try {
|
||||
const rootObject = await this.#openmct.objects.get('ROOT');
|
||||
const composition = this.#openmct.composition.get(rootObject);
|
||||
if (!composition) {
|
||||
return;
|
||||
}
|
||||
|
||||
composition
|
||||
.load()
|
||||
.then((children) => {
|
||||
let lastChild = children[children.length - 1];
|
||||
const children = await composition.load();
|
||||
const lastChild = children[children.length - 1];
|
||||
if (lastChild) {
|
||||
let lastChildId = openmct.objects.makeKeyString(lastChild.identifier);
|
||||
openmct.router.setPath(`#/browse/${lastChildId}`);
|
||||
const lastChildId = this.#openmct.objects.makeKeyString(lastChild.identifier);
|
||||
this.#openmct.router.setPath(`#/browse/${lastChildId}`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
}
|
||||
|
||||
function clearMutationListeners() {
|
||||
if (openmct.router.path !== undefined) {
|
||||
openmct.router.path.forEach((pathObject) => {
|
||||
#clearMutationListeners() {
|
||||
if (this.#openmct.router.path) {
|
||||
this.#openmct.router.path.forEach((pathObject) => {
|
||||
if (pathObject.isMutable) {
|
||||
openmct.objects.destroyMutable(pathObject);
|
||||
this.#openmct.objects.destroyMutable(pathObject);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#handleBrowseRoute(path, results, params) {
|
||||
this.#isRoutingInProgress = true;
|
||||
const navigatePath = results[1];
|
||||
this.#clearMutationListeners();
|
||||
this.#navigateToPath(navigatePath, params.view);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user