From 6bbdcd7d7efe25de9c1085703e12ae8b981bc1fb Mon Sep 17 00:00:00 2001 From: Ashish Kolhe <35160958+oasisk@users.noreply.github.com> Date: Thu, 29 Oct 2026 10:39:35 +0000 Subject: [PATCH] fix(ui): sharpen visual polish, keyboard focus and contrast across logs, tables and charts (#15993) Co-authored-by: ktx-vaidehi Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../references/core-controls-table.md | 3 +- scripts/translations/.translation_state.json | 2 + .../Logs/logs-jk-navigation.spec.js | 12 +- .../playwright-tests/Logs/logstable.spec.js | 8 +- web/src/components/CommunitySlackInvite.vue | 2 + web/src/components/ConnectDataSourcePopup.vue | 1 + web/src/components/DateTime.vue | 2 +- web/src/components/DateTimeRail.vue | 2 +- web/src/components/Header.vue | 2 +- web/src/components/MenuLink.vue | 2 +- web/src/components/QueryEditor.vue | 2 +- web/src/components/common/FieldExpansion.vue | 2 +- .../components/common/FieldListPagination.vue | 8 +- .../components/common/FieldValuesPanel.vue | 2 +- .../components/common/GroupedFieldList.vue | 2 +- .../common/sidebar/SearchFieldList.vue | 2 +- .../dashboards/AlertContextMenu.vue | 2 +- .../dashboards/PanelSchemaRenderer.vue | 2 +- .../addPanel/DashboardQueryBuilder.vue | 8 +- .../useResultsLoadingIndicator.spec.ts | 162 ++++++++++++++++++ .../useLogs/useResultsLoadingIndicator.ts | 99 +++++++++++ .../AIObservability/PlaygroundMessageList.vue | 2 +- .../AIObservability/PlaygroundVariableBar.vue | 4 +- .../forms/scorer/ScorerTestPanel.vue | 2 +- web/src/lib/core/Badge/OBadge.vue | 2 +- web/src/lib/core/Button/OButton.spec.ts | 43 +++-- web/src/lib/core/Button/OButton.types.ts | 1 + web/src/lib/core/Button/OButton.vue | 15 +- web/src/lib/core/Button/OButtonGroup.spec.ts | 27 +++ web/src/lib/core/Button/OButtonGroup.vue | 7 +- web/src/lib/core/Card/OCardSection.vue | 2 +- web/src/lib/core/EmptyState/OEmptyState.vue | 4 +- web/src/lib/core/Navbar/ONavGroup.vue | 2 +- web/src/lib/core/PageHeader/OPageHeader.vue | 4 +- .../core/RefreshButton/ORefreshButton.spec.ts | 16 ++ .../RefreshButton/ORefreshButton.types.ts | 2 + .../lib/core/RefreshButton/ORefreshButton.vue | 4 +- web/src/lib/core/Table/OTable.vue | 4 +- .../Table/sub-components/OTableBodyCell.vue | 17 +- .../sub-components/OTableBodyRow.spec.ts | 69 ++++++++ .../Table/sub-components/OTableBodyRow.vue | 37 +++- .../Table/sub-components/OTableHeader.vue | 4 +- .../Table/sub-components/OTablePagination.vue | 2 +- web/src/lib/forms/Combobox/OCombobox.vue | 4 +- web/src/lib/forms/Input/OInput.vue | 4 +- web/src/lib/forms/Select/OSelect.vue | 12 +- web/src/lib/forms/Select/OSelectItem.vue | 2 +- web/src/lib/forms/TagInput/OTagInput.vue | 2 +- web/src/lib/lists/FieldList/OFieldRow.vue | 2 +- web/src/lib/navigation/Tabs/OTab.spec.ts | 63 ++++--- web/src/lib/navigation/Tabs/OTab.vue | 7 +- .../lib/overlay/ContextMenu/OContextMenu.vue | 2 +- .../overlay/ContextMenu/OContextMenuItem.vue | 2 +- web/src/lib/overlay/Dropdown/ODropdown.vue | 2 +- .../lib/overlay/Dropdown/ODropdownItem.vue | 4 +- web/src/lib/overlay/Dropdown/ODropdownSub.vue | 6 +- web/src/lib/overlay/Popover/OPopover.vue | 2 +- web/src/lib/overlay/Tooltip/OTooltip.vue | 2 +- web/src/lib/styles/tokens/base.css | 24 ++- web/src/lib/styles/tokens/colorMath.spec.ts | 4 +- web/src/lib/styles/tokens/component.css | 36 ++-- .../lib/styles/tokens/contrast-manifest.ts | 40 +---- web/src/lib/styles/tokens/contrast.spec.ts | 2 +- web/src/lib/styles/tokens/dark.css | 35 ++-- web/src/lib/styles/tokens/semantic.css | 21 ++- web/src/locales/languages/ar-SA.json | 2 + web/src/locales/languages/de-DE.json | 2 + web/src/locales/languages/en-US.json | 2 + web/src/locales/languages/es-ES.json | 2 + web/src/locales/languages/fr-FR.json | 2 + web/src/locales/languages/it-IT.json | 2 + web/src/locales/languages/ja-JP.json | 2 + web/src/locales/languages/ko-KR.json | 2 + web/src/locales/languages/nl-NL.json | 2 + web/src/locales/languages/pl-PL.json | 2 + web/src/locales/languages/pt-PT.json | 2 + web/src/locales/languages/ru-RU.json | 2 + web/src/locales/languages/tr-TR.json | 2 + web/src/locales/languages/vi-VN.json | 2 + web/src/locales/languages/zh-CN.json | 2 + web/src/locales/languages/zh-TW.json | 2 + web/src/plugins/logs/SearchBar.vue | 14 +- web/src/plugins/logs/SearchResult.spec.ts | 103 +++++++---- web/src/plugins/logs/SearchResult.vue | 48 +++++- .../plugins/profiles/ProfilesLabelFilters.vue | 2 +- web/src/styles/base-elements.css | 12 +- web/src/styles/tailwind.css | 8 + web/src/utils/chartTheme.ts | 2 +- web/src/utils/dashboard/colorPalette.spec.ts | 121 +++++++++++++ web/src/utils/dashboard/colorPalette.ts | 82 ++++++++- .../utils/dashboard/convertPromQLData.spec.ts | 45 ++++- web/src/utils/dashboard/convertPromQLData.ts | 16 +- .../utils/dashboard/convertSQLData.spec.ts | 46 +++++ .../promql/convertPromQLPieChart.spec.ts | 28 +++ .../dashboard/promql/convertPromQLPieChart.ts | 28 +-- .../sql/charts/convertSQLCharts.spec.ts | 1 + .../charts/convertSQLPieDonutChart.spec.ts | 1 + .../sql/charts/convertSQLPieDonutChart.ts | 15 +- .../dashboard/sql/shared/contextBuilder.ts | 15 +- web/src/utils/logs/statusParser.spec.ts | 22 ++- web/src/utils/logs/statusParser.ts | 20 +++ web/src/views/Dashboards/Dashboards.vue | 6 +- web/src/views/EnterpriseFeatures.vue | 4 +- web/src/views/HomeChatHistory.vue | 2 +- web/src/views/HomeView.vue | 31 ++-- 105 files changed, 1263 insertions(+), 316 deletions(-) create mode 100644 web/src/composables/useLogs/useResultsLoadingIndicator.spec.ts create mode 100644 web/src/composables/useLogs/useResultsLoadingIndicator.ts diff --git a/.claude/skills/ui-architect/references/core-controls-table.md b/.claude/skills/ui-architect/references/core-controls-table.md index 0956f57d1c..3192be0e55 100644 --- a/.claude/skills/ui-architect/references/core-controls-table.md +++ b/.claude/skills/ui-architect/references/core-controls-table.md @@ -27,7 +27,7 @@ Authoring reference for O2's core control components (Button, Navbar, RefreshBut **Key props:** - `variant` (default `"primary"`) — one of: `primary`, `secondary`, `outline`, `ghost`, `ghost-primary`, `ghost-muted`, `ghost-subtle`, `ghost-destructive`, `ghost-success`, `ghost-warning`, `ghost-neutral`, `outline-destructive`, `sidebar-toggle`, `panel-collapse`, `sidebar-button`, `destructive`, `ai-gradient`, `on-dark-primary`, `on-dark-ghost`, `warning`, `pending`, `preview-slack`, `preview-teams`, `preview-email`, `preview-action`, `webinar-dismiss`, `pricing-chip`, `outline-primary`, and the four tinted-fill variants `tint-teal`, `tint-purple`, `tint-blue`, `tint-orange` (soft categorical fill for tiles that identify an entity by colour, e.g. a cluster code; not for status) -- `size` (default `"md"`) — one of: `xs`, `chip`, `sm`, `sm-action`, `md`, `lg`, `icon`, `icon-xs`, `icon-xs-circle`, `icon-xs-sq`, `icon-chip`, `icon-sm`, `icon-md`, `icon-lg`, `icon-circle`, `icon-circle-sm`, `icon-toolbar`, `icon-panel`, `sidebar-button`, `sm-toolbar`, `chip-12` +- `size` (default `"md"`) — one of: `xs`, `chip`, `sm`, `sm-action`, `md`, `cta`, `lg`, `icon`, `icon-xs`, `icon-xs-circle`, `icon-xs-sq`, `icon-chip`, `icon-sm`, `icon-md`, `icon-lg`, `icon-circle`, `icon-circle-sm`, `icon-toolbar`, `icon-panel`, `sidebar-button`, `sm-toolbar`, `chip-12` - `iconLeft` (`IconName`) — renders an OIcon before the label; `#icon-left` slot takes precedence if present - `iconRight` (`IconName`) — renders an OIcon after the label; `#icon-right` slot takes precedence if present - `loading` (boolean, default `false`) — shows a centered spinner overlay, keeps dimensions, disables interaction @@ -73,6 +73,7 @@ Authoring reference for O2's core control components (Button, Navbar, RefreshBut - `orientation` (`"horizontal"` | `"vertical"`, default `"horizontal"`) - `align` (`"stretch"` | `"center"` | `"start"` | `"end"`, default `"stretch"`) — cross-axis alignment of children - `radius` (`"sm"` | `"md"` | `"lg"`, default `"md"`) — must match the inner buttons' radius; use `"sm"` when children use `size="chip"` or `size="icon-chip"` +- The group never clips overflow (a clip hides a child's offset focus outline) and lifts the focused child with `z-1`; each child paints its own outer corners, so wrap non-OButton children that need clipping yourself **Slots:** `default` (one or more OButton children) **Emits:** none **Example:** diff --git a/scripts/translations/.translation_state.json b/scripts/translations/.translation_state.json index 3b5462aa53..50767a0af9 100644 --- a/scripts/translations/.translation_state.json +++ b/scripts/translations/.translation_state.json @@ -22179,6 +22179,7 @@ "removeFieldFromTable": "c308c5301db25ec7", "resetFields": "7558552898692240", "resetFilters": "10afa98480f2d06c", + "resultsProgressLabel": "1f6c9561558905ec", "rowDetail": "2ef826b753739aff", "rows": "bc51e9e65d79e1c9", "runQuery": "1837e00c45e8663d", @@ -22190,6 +22191,7 @@ "savedViewsLabel": "edc47cfbced35fc7", "savedViewsNotFound": "d271ae2e71620984", "scanSize": "b41c8c7779b8cc15", + "scannedSoFar": "ff88237fc82a362e", "scheduleSearchJob": "21daedde3d118f2b", "searchCancelledNotice": "2949f29dd9e1046e", "searchDimension": "567db4697413719b", diff --git a/tests/ui-testing/playwright-tests/Logs/logs-jk-navigation.spec.js b/tests/ui-testing/playwright-tests/Logs/logs-jk-navigation.spec.js index d3a76b137d..1eb909c009 100644 --- a/tests/ui-testing/playwright-tests/Logs/logs-jk-navigation.spec.js +++ b/tests/ui-testing/playwright-tests/Logs/logs-jk-navigation.spec.js @@ -31,6 +31,8 @@ const runBtn = '[data-test="logs-search-bar-refresh-btn"]'; const table = '[data-test="logs-search-result-logs-table"]'; const pager = '[data-test="logs-search-result-pagination"]'; const jsonContent = '[data-test="log-detail-json-content"]'; +// Syntax-highlight colours are tuned for white rows, not the selected fill; AC8.2 covers the J/K surfaces, not log colouring. +const activeRowLogText = `${table} [data-active-row] .log-cell-html`; const b64 = (text) => Buffer.from(text, "utf8") @@ -608,6 +610,7 @@ test.describe("Logs J/K navigation (item 4a)", () => { `${logs.logDetailDialog} .select-noof-records`, `${logs.logDetailDialog} label`, `${logs.logDetailDialog} [role="tab"]`, + activeRowLogText, ], ); expect(drawerScan.passes).toBeGreaterThan(0); @@ -615,10 +618,11 @@ test.describe("Logs J/K navigation (item 4a)", () => { await page.keyboard.press("Escape"); await expect(logs.logResultsRow(1)).toBeFocused(); - const rowScan = await axeScan(page, [ - `${table} [data-active-row]`, - logs.logsRowNavLive, - ]); + const rowScan = await axeScan( + page, + [`${table} [data-active-row]`, logs.logsRowNavLive], + [activeRowLogText], + ); expect(rowScan.passes).toBeGreaterThan(0); expect(rowScan.violations).toEqual([]); diff --git a/tests/ui-testing/playwright-tests/Logs/logstable.spec.js b/tests/ui-testing/playwright-tests/Logs/logstable.spec.js index 4944328698..6143d74401 100644 --- a/tests/ui-testing/playwright-tests/Logs/logstable.spec.js +++ b/tests/ui-testing/playwright-tests/Logs/logstable.spec.js @@ -612,11 +612,11 @@ test.describe("Severity Color Mapping Tests - Issue #9439", () => { emergency: '#e53935', // severity 0 → level field alert: '#ea580c', // severity 1 critical: '#f4511e', // severity 2 - error: '#ef5350', // severity 3 - warning: '#dd7b00', // severity 4 + error: '#e53935', // severity 3 + warning: '#c46a00', // severity 4 notice: '#16a34a', // severity 5 - info: '#1e88e5', // severity 6 - debug: '#00a3b7', // severity 7 + info: '#1b80d9', // severity 6 + debug: '#008a9b', // severity 7 }; // Wait for the results table to actually render its per-row status color bars diff --git a/web/src/components/CommunitySlackInvite.vue b/web/src/components/CommunitySlackInvite.vue index 2d029b34d0..3686393670 100644 --- a/web/src/components/CommunitySlackInvite.vue +++ b/web/src/components/CommunitySlackInvite.vue @@ -255,6 +255,7 @@ const joinSlack = () => { @@ -266,6 +267,7 @@ const joinSlack = () => { {{ t("communitySlackInvite.maybeLater") }} diff --git a/web/src/components/ConnectDataSourcePopup.vue b/web/src/components/ConnectDataSourcePopup.vue index 16cb88c21b..25035049ea 100644 --- a/web/src/components/ConnectDataSourcePopup.vue +++ b/web/src/components/ConnectDataSourcePopup.vue @@ -275,6 +275,7 @@ const handleOpenChange = (open: boolean) => { diff --git a/web/src/components/DateTime.vue b/web/src/components/DateTime.vue index 37cf0a2138..1da1a913bb 100644 --- a/web/src/components/DateTime.vue +++ b/web/src/components/DateTime.vue @@ -17,7 +17,7 @@ along with this program. If not, see .