From 87ba9fcbc0780cd7a98e11b0dee92d0dcca73004 Mon Sep 17 00:00:00 2001 From: "Rukmini Bose (Ruki)" <48999852+rukmini-bose@users.noreply.github.com> Date: Fri, 8 Mar 2024 12:22:09 -0800 Subject: [PATCH 1/7] [Mobile] Make Time Conductor Usable Again (#7515) * Initial changes to refactor Time Conductor * Finish refactor using grid-template * Finish total refactor of Time Conductor * Initial mobile changes * Fix TC on mobile by changing grid template * Fix more mobile stuff * Add ellipsize to TC popup options and rearrange popup inputs and labels * Small final changes so TC is adaptive to extreme cases * Add e2e mobile test --------- Co-authored-by: John Hill --- e2e/tests/mobile/smoke.e2e.spec.js | 96 ++++++----- src/plugins/timeConductor/TimePopupFixed.vue | 22 +-- .../timeConductor/TimePopupRealtime.vue | 26 ++- src/plugins/timeConductor/conductor.scss | 149 +++++++++++++++++- 4 files changed, 230 insertions(+), 63 deletions(-) diff --git a/e2e/tests/mobile/smoke.e2e.spec.js b/e2e/tests/mobile/smoke.e2e.spec.js index d787b5c987b..cd0ad707a4f 100644 --- a/e2e/tests/mobile/smoke.e2e.spec.js +++ b/e2e/tests/mobile/smoke.e2e.spec.js @@ -34,42 +34,62 @@ Make no assumptions about the order that elements appear in the DOM. */ import { expect, test } from '../../pluginFixtures.js'; -test('Verify that My Items Tree appears @mobile', async ({ page, openmctConfig }) => { - const { myItemsFolderName } = openmctConfig; - //Go to baseURL - await page.goto('./'); - //My Items to be visible - await expect(page.getByRole('treeitem', { name: `${myItemsFolderName}` })).toBeVisible(); -}); -test('Verify that user can search @mobile', async ({ page }) => { - //For now, this test is going to be hardcoded against './test-data/display_layout_with_child_layouts.json' - await page.goto('./'); - await page.getByRole('searchbox', { name: 'Search Input' }).click(); - await page.getByRole('searchbox', { name: 'Search Input' }).fill('Parent Display Layout'); - //Search Results appear in search modal - await expect(page.getByLabel('Object Results').getByText('Parent Display Layout')).toBeVisible(); - //Clicking on the search result takes you to the object - await page.getByLabel('Object Results').getByText('Parent Display Layout').click(); - await page.getByTitle('Collapse Browse Pane').click(); - await expect(page.getByRole('main').getByText('Parent Display Layout')).toBeVisible(); -}); -test('Remove Object and confirmation dialog @mobile', async ({ page }) => { - await page.goto('./'); - await page.getByRole('searchbox', { name: 'Search Input' }).click(); - await page.getByRole('searchbox', { name: 'Search Input' }).fill('Parent Display Layout'); - //Search Results appear in search modal - //Clicking on the search result takes you to the object - await page.getByLabel('Object Results').getByText('Parent Display Layout').click(); - await page.getByTitle('Collapse Browse Pane').click(); - await expect(page.getByRole('main').getByText('Parent Display Layout')).toBeVisible(); - //Verify both objects are in view - await expect(await page.getByLabel('Child Layout 1 Layout')).toBeVisible(); - await expect(await page.getByLabel('Child Layout 2 Layout')).toBeVisible(); - //Remove First Object to bring up confirmation dialog - await page.getByLabel('View menu items').nth(1).click(); - await page.getByLabel('Remove').click(); - await page.getByRole('button', { name: 'OK' }).click(); - //Verify that the object is removed - await expect(await page.getByLabel('Child Layout 1 Layout')).toBeVisible(); - expect(await page.getByLabel('Child Layout 2 Layout').count()).toBe(0); + +test.describe('Smoke tests for @mobile', () => { + test.beforeEach(async ({ page }) => { + //For now, this test is going to be hardcoded against './test-data/display_layout_with_child_layouts.json' + await page.goto('./'); + }); + + test('Verify that My Items Tree appears @mobile', async ({ page }) => { + //My Items to be visible + await expect(page.getByRole('treeitem', { name: 'My Items' })).toBeVisible(); + }); + + test('Verify that user can search @mobile', async ({ page }) => { + await page.getByRole('searchbox', { name: 'Search Input' }).click(); + await page.getByRole('searchbox', { name: 'Search Input' }).fill('Parent Display Layout'); + //Search Results appear in search modal + await expect( + page.getByLabel('Object Results').getByText('Parent Display Layout') + ).toBeVisible(); + //Clicking on the search result takes you to the object + await page.getByLabel('Object Results').getByText('Parent Display Layout').click(); + await page.getByTitle('Collapse Browse Pane').click(); + await expect(page.getByRole('main').getByText('Parent Display Layout')).toBeVisible(); + }); + + test('Verify that user can change time conductor @mobile', async ({ page }) => { + //Collapse Browse Pane to get more Time Conductor space + await page.getByLabel('Collapse Browse Pane').click(); + //Open Time Conductor and change to Real Time Mode and set offset hour by 1 hour + // Disabling line because we're intentionally obscuring the text + // eslint-disable-next-line playwright/no-force-option + await page.getByLabel('Time Conductor Mode').click({ force: true }); + await page.getByLabel('Time Conductor Mode Menu').click(); + await page.getByLabel('Real-Time').click(); + await page.getByLabel('Start offset hours').fill('01'); + await page.getByLabel('Submit time offsets').click(); + await expect(page.getByLabel('Start offset: 01:30:00')).toBeVisible(); + }); + + test('Remove Object and confirmation dialog @mobile', async ({ page }) => { + await page.getByRole('searchbox', { name: 'Search Input' }).click(); + await page.getByRole('searchbox', { name: 'Search Input' }).fill('Parent Display Layout'); + //Search Results appear in search modal + //Clicking on the search result takes you to the object + await page.getByLabel('Object Results').getByText('Parent Display Layout').click(); + await page.getByTitle('Collapse Browse Pane').click(); + await expect(page.getByRole('main').getByText('Parent Display Layout')).toBeVisible(); + //Verify both objects are in view + await expect(await page.getByLabel('Child Layout 1 Layout')).toBeVisible(); + await expect(await page.getByLabel('Child Layout 2 Layout')).toBeVisible(); + //Remove First Object to bring up confirmation dialog + await page.getByLabel('View menu items').nth(1).click(); + await page.getByLabel('Remove').click(); + await page.getByRole('button', { name: 'OK' }).click(); + //Verify that the object is removed + await expect(await page.getByLabel('Child Layout 1 Layout')).toBeVisible(); + expect(await page.getByLabel('Child Layout 2 Layout').count()).toBe(0); + }); }); diff --git a/src/plugins/timeConductor/TimePopupFixed.vue b/src/plugins/timeConductor/TimePopupFixed.vue index 3eb19124240..ff88e3524e8 100644 --- a/src/plugins/timeConductor/TimePopupFixed.vue +++ b/src/plugins/timeConductor/TimePopupFixed.vue @@ -1,14 +1,14 @@ diff --git a/src/api/menu/components/SuperMenu.vue b/src/api/menu/components/SuperMenu.vue index 1bbdaf940e0..cd8d72f7be3 100644 --- a/src/api/menu/components/SuperMenu.vue +++ b/src/api/menu/components/SuperMenu.vue @@ -38,8 +38,8 @@ :key="action.name" role="menuitem" :aria-disabled="action.isDisabled" + aria-describedby="item-description" :class="action.cssClass" - :title="action.description" @click="action.onItemClicked" @mouseover="toggleItemDescription(action)" @mouseleave="toggleItemDescription()" @@ -64,7 +64,7 @@ role="menuitem" :class="action.cssClass" :aria-label="action.name" - :title="action.description" + aria-describedby="item-description" @click="action.onItemClicked" @mouseover="toggleItemDescription(action)" @mouseleave="toggleItemDescription()" @@ -74,13 +74,13 @@
  • No actions defined.
  • -
    -
    +
    +
    - {{ hoveredItem.name }} + {{ hoveredItemName }}
    -
    - {{ hoveredItem.description }} +
    + {{ hoveredItemDescription }}
    @@ -90,26 +90,39 @@ import popupMenuMixin from '../mixins/popupMenuMixin.js'; export default { mixins: [popupMenuMixin], inject: ['options'], - data: function () { + data() { return { - hoveredItem: {} + hoveredItem: null }; }, computed: { optionsLabel() { const label = this.options.label ? `${this.options.label} Super Menu` : 'Super Menu'; return label; + }, + itemDescriptionIconClass() { + const iconClass = ['l-item-description__icon']; + if (this.hoveredItem) { + iconClass.push('bg-' + this.hoveredItem.cssClass); + } + return iconClass; + }, + hoveredItemName() { + return this.hoveredItem?.name ?? ''; + }, + hoveredItemDescription() { + return this.hoveredItem?.description ?? ''; } }, methods: { - toggleItemDescription(action = {}) { + toggleItemDescription(action = null) { const hoveredItem = { - name: action.name, - description: action.description, - cssClass: action.cssClass + name: action?.name, + description: action?.description, + cssClass: action?.cssClass }; - this.hoveredItem = Object.assign({}, this.hoveredItem, hoveredItem); + this.hoveredItem = hoveredItem; } } }; diff --git a/src/plugins/LADTable/components/LadRow.vue b/src/plugins/LADTable/components/LadRow.vue index ea7e525435b..2adf23743de 100644 --- a/src/plugins/LADTable/components/LadRow.vue +++ b/src/plugins/LADTable/components/LadRow.vue @@ -58,7 +58,7 @@ const CONTEXT_MENU_ACTIONS = ['viewDatumAction', 'viewHistoricalData', 'remove']; const BLANK_VALUE = '---'; -import identifierToString from '/src/tools/url.js'; +import { objectPathToUrl } from '/src/tools/url.js'; import PreviewAction from '@/ui/preview/PreviewAction.js'; import tooltipHelpers from '../../../api/tooltips/tooltipMixins.js'; @@ -260,7 +260,7 @@ export default { event.preventDefault(); this.preview(this.objectPath); } else { - const resultUrl = identifierToString(this.openmct, this.objectPath); + const resultUrl = objectPathToUrl(this.openmct, this.objectPath); this.openmct.router.navigate(resultUrl); } }, diff --git a/src/plugins/clock/components/ClockIndicator.vue b/src/plugins/clock/components/ClockIndicator.vue index 2342679da3a..8521934b5ce 100644 --- a/src/plugins/clock/components/ClockIndicator.vue +++ b/src/plugins/clock/components/ClockIndicator.vue @@ -25,6 +25,7 @@ aria-label="Clock Indicator" class="c-indicator t-indicator-clock icon-clock no-minify c-indicator--not-clickable" role="complementary" + aria-live="off" > {{ timeTextValue }} diff --git a/src/plugins/inspectorDataVisualization/NumericDataInspectorView.vue b/src/plugins/inspectorDataVisualization/NumericDataInspectorView.vue index 049e5fbb6ab..92a43eb1f63 100644 --- a/src/plugins/inspectorDataVisualization/NumericDataInspectorView.vue +++ b/src/plugins/inspectorDataVisualization/NumericDataInspectorView.vue @@ -25,7 +25,18 @@
    Numeric Data
    -
    +
    + + + +
    {{ noNumericDataText }} @@ -33,13 +44,15 @@