Skip to content

Reflow the app-mode test case details page: result history first, header and banner aligned - #32966

Merged
ShaileshParmar11 merged 18 commits into
mainfrom
feat/tcd-0-ai-mode-page-shell
Sep 11, 2026
Merged

Reflow the app-mode test case details page: result history first, header and banner aligned#32966
ShaileshParmar11 merged 18 commits into
mainfrom
feat/tcd-0-ai-mode-page-shell

Conversation

@ShaileshParmar11

@ShaileshParmar11 ShaileshParmar11 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Describe your changes:

Fixes open-metadata/openmetadata-collate#6416

TCD-0, part of epic open-metadata/openmetadata-collate#6074.

Cross-repo form is deliberate: the tracking issue lives in the Collate repo, and a bare #6416 here would autolink an unrelated merged PR in this repo.

I reflowed the app-mode test case details page so its main column follows the redesign: the result history sits directly under the last-run banner, and the description moves into the right rail alongside the other metadata cards. Previously the chart was the fifth block in the column — you scrolled past Description, Parameter and the SQL section to reach it.

The description's placement was confirmed with product: the redesign does not show it at all, and the side panel was preferred over the bottom of the main column "so it matches the other elements". It keeps its edit affordance, permission gate and change-summary entry; rail order is Description, Tags, Glossary Terms, Data Products, with TCD-10a inserting the Configuration card above them.

While verifying that, two pre-existing 16px misalignments became obvious and are fixed here:

  • The last-run banner was inset 16px on both sides relative to the chart card and rail beneath it (190→1446 against the grid's 174→1462). Its wrapper carried tw:px-4 while the result-tab grid has no horizontal padding.
  • ObservabilityPageShell gave its content region tw:p-4 but left its header slot unpadded, so every page built on it rendered the header 16px wider than its content (375 against 391). Visible wherever both are bordered cards — this page and the Incident Manager.

Nothing is removed. No API, schema, or data change. Params and the SQL section stay in the main column: the redesign puts them in the right rail, but the rail is 331px and a tableDiff test's table2 value renders at 440px, so that move waits on the Configuration card's design (TCD-10a).

Type of change:

  • Improvement

High-level design:

Five files, four of them small. The reflow is a JSX re-order inside TestCaseResultTab; the two alignment fixes are one Tailwind class each.

ObservabilityPageShell is shared, so the header fix shifts the header card inward on five pages: test case details, incident manager, data quality, alerts, test library. I chose padding the header slot over un-padding the content region because it moves one element rather than reflowing every page's content, so no page loses width. Measured all five as flush afterwards. Two further consumers — test suite detail and alert detail — were not reachable with seeded data; test suite detail passes an identically shaped bordered card and benefits the same way. Pipeline observability does not use this shell.

data-testid="test-case-rail" is added to the rail container, which had no stable handle; later tickets in the epic mount the Configuration and Test Suites cards into it.

Classic mode (/test-case/:fqn) is intentionally untouched, but it shares the reflowed tab body, so it inherits the main-column order. Its header and tab strip keep today's look.

Tests:

Use cases covered

  • Opening a test case in app mode shows the result history directly beneath the last-run banner, with the description in the right rail
  • The banner, the header card and the tab body content all share the same left and right edges
  • The rail renders beside the main column; the collapse toggle continues to work
  • Collate's getAdditionalComponents extension still mounts, below the result history
  • Classic mode, the version page and the dimension route all still render

Unit tests

  • Added.
  • TestCaseResultTab.test.tsx — main-column order (chart above the parameters), the description rendering inside the rail rather than the main column, and two cases covering the Collate getAdditionalComponents seam, which was previously mocked to [] and therefore never exercised.
  • 52 tests in the result-tab suite, 317 across the result tab plus components/observability.

Backend integration tests

  • Not applicable (no backend changes).

Ingestion integration tests

  • Not applicable (no ingestion changes).

Playwright (UI) tests

  • Added playwright/e2e/Features/DataQuality/TestCaseDetailsPage.spec.ts — the shared app-mode details-page spec the rest of the epic extends. Self-contained: builds its own table, test case and result via the API rather than depending on the seeded dataset.
  • 4 tests, each verified to fail against pre-change code: order reports the chart at y=723 below the parameters at y=518; banner alignment reports x=407 against the grid's 391; header alignment reports 375 against 391.
  • Regression: the 21 existing tests in TestCaseResultPermissions, TestCaseIncidentPermissions and FailedTestCaseSampleData all pass — they assert test-case-result-tab-container, entity-page-header, chart-container and graph-container through the reflowed tab.
  • yarn lint:playwright — 0 errors.

Manual testing performed

  1. Ran the UI dev server against a local server and opened /observability/test-case/…/test-case-results for a Success case (table_column_count_equals) and a Failed case with an incident (diff_columns).
  2. Measured bounding boxes for the banner, header card, main column and rail — banner and header now share the grid's edges exactly; confirmed the description renders inside the rail and wraps cleanly at 331px.
  3. Checked app mode at 1440px and 1024px: no horizontal page scroll at either.
  4. Checked classic mode, the version page and the dimension route: all render, no horizontal scroll.
  5. Verified alignment on all five reachable ObservabilityPageShell pages.

Pre-existing issue found, not fixed here: the test case version page throws Cannot read properties of undefined (reading '0'). It reproduces on main without this branch, so it is out of scope — worth its own issue.

UI screen recording / screenshots:

Before/after screenshots to be attached. The visible changes are the chart moving from fifth in the column to directly beneath the banner, the description moving into the right rail, and the two 16px edges closing.

Checklist:

  • I have read the CONTRIBUTING document.

  • My PR is linked to its tracking issue above (Collate repo — see note on the Fixes keyword).

  • I have commented on my code, particularly in hard-to-understand areas.

  • For JSON Schema changes: not applicable, no schema changes.

  • For UI changes: screenshots to be attached.

  • I have added tests (unit + Playwright) and listed them above.

  • I have added tests around the new logic.

🤖 Generated with Claude Code

Copilot AI lite review requested due to automatic review settings September 8, 2026 15:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

❌ PR checklist incomplete

This PR cannot be merged until the following are addressed on its linked issue:

  • No GitHub issue is linked. Link an issue in the Development section of the PR (or add Fixes #12345 to the description). For a same-org cross-repo issue, add Fixes open-metadata/<repo>#123 to the description.

The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically.

Maintainers can bypass this check by adding the skip-pr-checks label.

@github-actions github-actions Bot added safe to test Add this label to run secure Github workflows on PRs UI UI specific issues labels Sep 8, 2026
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

⚠️ UI Checkstyle passed — lint findings in changed files

🔍 ESLint findings in this PR's files — 0 error(s), 6 warning(s)

Errors block the build. Warnings do not yet — they are rules whose backlog is still
being worked down, listed so this PR does not add to it. See docs/ui-code-quality-gate.md.

0 error(s), 6 warning(s) across 2 changed file(s).

Count Rule
5 openmetadata-imports/no-lower-layer-page-imports
1 react-hooks/exhaustive-deps
All findings
Location Rule Message
🟡 src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.component.tsx:26:1 openmetadata-imports/no-lower-layer-page-imports Pages are route-level composition modules. Move the shared implementation/type to a lower layer instead of importing a page from here.
🟡 src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.component.tsx:342:6 react-hooks/exhaustive-deps React Hook useMemo has a missing dependency: 't'. Either include it or remove the dependency array.
🟡 src/components/observability/TestCaseDetail/TestCaseDetail.tsx:33:1 openmetadata-imports/no-lower-layer-page-imports Pages are route-level composition modules. Move the shared implementation/type to a lower layer instead of importing a page from here.
🟡 src/components/observability/TestCaseDetail/TestCaseDetail.tsx:34:1 openmetadata-imports/no-lower-layer-page-imports Pages are route-level composition modules. Move the shared implementation/type to a lower layer instead of importing a page from here.
🟡 src/components/observability/TestCaseDetail/TestCaseDetail.tsx:35:1 openmetadata-imports/no-lower-layer-page-imports Pages are route-level composition modules. Move the shared implementation/type to a lower layer instead of importing a page from here.
🟡 src/components/observability/TestCaseDetail/TestCaseDetail.tsx:40:1 openmetadata-imports/no-lower-layer-page-imports Pages are route-level composition modules. Move the shared implementation/type to a lower layer instead of importing a page from here.

Fix locally (fast - only checks files changed in this branch):

make ui-checkstyle-changed

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 70%
70.63% (95764/135575) 55.22% (56760/102785) 56.58% (18934/33463)

ShaileshParmar11 and others added 2 commits September 9, 2026 15:02
731fbd5 added `playwright/utils/appMode.ts`, but `playwright/e2e/Utils/appMode.ts`
already existed and does strictly more: it seeds the session tuple *and* stubs the
boot `GET /users/{id}/preferences`. That second half is load-bearing —
`AuthProvider.hydrateAndResolveAppMode` runs before the first render and
unconditionally overwrites the seeded tuple with
`resolveEffectiveAppMode(userPref, ...)`, so with no server preference the seed is
lost and the tab boots Classic. The duplicate also wrote a `source: 'manual'` field
that the current `writeAppMode` shape no longer has.

So the details-page spec was seeding a tuple that got thrown away, and would have
reached the `/observability/*` routes only on an account that already preferred AI
mode. Point it at the real helper and delete the copy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four tests flip `isTabExpanded` to true to make the right rail visible, but the
`afterEach` reset only restored the other mutated store fields, so the flag leaked
into every following test. Nothing asserts on it today, which is why the suite still
passes — the reset closes the order dependence before it bites.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Three of the review comments:

* `TableClass` moves into `beforeAll`. Its generated entity name is fixed at
  construction, so a module-scope instance means a retry that reuses the worker
  re-runs `create` with the same name and gets a 409. Declared with `!` since
  TypeScript cannot see that `beforeAll` assigns before any test reads it.

* `openDetailsPage`'s body moves to `playwright/utils/testCases.ts` as
  `openTestCaseDetailsPage(page, fqn)`, next to `verifyTestCaseLastRunBanner`.
  It takes the FQN rather than closing over the spec's `table`, and it does not
  seed the app mode — that stays in the spec, so the helper works for either
  mode and `playwright/utils` keeps its one-way dependency on `playwright/e2e`
  (no util imports from `e2e/` today).

* All five `test.slow()` calls are gone. The per-test timeout is 60s
  (`playwright.config.ts:517`) and each test is a single navigation plus
  assertions, so tripling it was blanket application — which is what the
  rule about `test.slow()` belonging only in the test that needs it is for.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

bd0295d moved `TableClass` construction into `beforeAll` but the edit that
added the assignment silently did not apply, so `table` stayed `undefined` and
`table.create` threw for every test in the spec. The `!` added in that same
commit is what hid it — a definite-assignment assertion tells TypeScript to
stop checking, so `tsc` had nothing to report.

Caught by review on #32966.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Conflicts came from #32982, which added a class-base gate on the shared
test-result graph while this branch moved that same graph to the top of the
main column.

* `TestCaseResultTab.component.tsx` — the graph keeps this branch's position
  and takes main's gate: `shouldRenderTestSummary(testCaseData,
  shouldRenderDefaultGraph)`. Git saw main "adding" the block at the old
  location only because this branch had removed it there, so that copy is
  dropped rather than duplicated — one `TestSummary` remains.

* `TestCaseResultTab.test.tsx` — both sides added a declaration and a reset in
  the same two places; both are kept.

One thing the textual merge could not see: #32982 moved the class base behind a
`default` export, so `jest.requireMock('./TestCaseResultTabClassBase')` in the
extension-components suite now resolves one level higher than the mock. It is
repointed at `.default`, which the tests would otherwise fail on despite a
clean merge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

🔄 Playwright impact map auto-refreshed

This PR touched specs or UI source that changed the source→spec routing map. I regenerated .github/playwright/impact-map.generated.json and pushed the diff to this branch.

- source entries: 760 → 761
- 1 added, 0 removed, 15 changed spec-list

New source→spec entries:
  openmetadata-ui/src/main/resources/ui/src/pages/TableDetailsPageV1/TableAliases/TableAliases.component.tsx

Entries whose spec list changed:
  openmetadata-ui/src/main/resources/ui/playwright/constant/config.ts
  openmetadata-ui/src/main/resources/ui/playwright/constant/sidebar.ts
  openmetadata-ui/src/main/resources/ui/playwright/e2e/Utils/appMode.ts
  openmetadata-ui/src/main/resources/ui/playwright/e2e/fixtures/pages.ts
  openmetadata-ui/src/main/resources/ui/playwright/support/entity/TableClass.ts
  openmetadata-ui/src/main/resources/ui/playwright/support/tag/ClassificationClass.ts
  openmetadata-ui/src/main/resources/ui/playwright/support/team/TeamClass.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/admin.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/common.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts
  … and 5 more

What is this file? It is the auto-generated half of Playwright's PR planner. It routes "if source X changes, run specs Y" by walking spec imports and cross-referencing getByTestId strings. Hand-authored routing in impact-map.json always wins on conflict.

What if I want to regenerate locally instead? Run this before pushing your next change to skip the bot commit:

python3 .github/scripts/generate_playwright_impact_map.py
git add .github/playwright/impact-map.generated.json
git commit --amend --no-edit  # or a separate commit

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

🔄 Playwright impact map auto-refreshed

This PR touched specs or UI source that changed the source→spec routing map. I regenerated .github/playwright/impact-map.generated.json and pushed the diff to this branch.

- source entries: 761 → 761
- 0 added, 0 removed, 13 changed spec-list

Entries whose spec list changed:
  openmetadata-ui/src/main/resources/ui/playwright/constant/config.ts
  openmetadata-ui/src/main/resources/ui/playwright/constant/service.ts
  openmetadata-ui/src/main/resources/ui/playwright/support/entity/service/DashboardServiceClass.ts
  openmetadata-ui/src/main/resources/ui/playwright/support/entity/service/DatabaseServiceClass.ts
  openmetadata-ui/src/main/resources/ui/playwright/support/entity/service/MessagingServiceClass.ts
  openmetadata-ui/src/main/resources/ui/playwright/support/fixtures/base.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/common.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/service.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/serviceIngestion.ts
  … and 3 more

What is this file? It is the auto-generated half of Playwright's PR planner. It routes "if source X changes, run specs Y" by walking spec imports and cross-referencing getByTestId strings. Hand-authored routing in impact-map.json always wins on conflict.

What if I want to regenerate locally instead? Run this before pushing your next change to skip the bot commit:

python3 .github/scripts/generate_playwright_impact_map.py
git add .github/playwright/impact-map.generated.json
git commit --amend --no-edit  # or a separate commit

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

The banner wrapper carried `tw:pt-4` and nothing below it, so the banner's
bottom edge and the tab body grid's top edge measured at the same y — a 0px
gap where every other vertical relationship on that grid is 10px
(`tw:gap-2.5`).

This is not a regression from d2b8875 — `main` has `tw:px-4 tw:pt-4`, so the
bottom gap never existed. That commit removed only the horizontal inset, which
is what made the omission obvious: once the banner lines up with the cards
beneath it, and the reflow puts the result-history card directly under it, the
two read as touching.

`tw:pb-2.5` matches the grid's own gap, so the banner sits in the same rhythm
as the cards rather than being a special case. Measured after: banner bottom
408, grid top 418.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@gitar-bot

gitar-bot Bot commented Sep 10, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 3 resolved / 3 findings

Reflows the app-mode test case details page to show result history directly beneath the last-run banner with description moved to the right rail, and fixes two pre-existing 16px alignment misalignments in the banner and ObservabilityPageShell header. Addresses test leaks in isTabExpanded, removes duplicate enableAiAppMode helper, and fixes table instantiation in beforeAll. Comprehensive test coverage added including Playwright specs; all 21 existing regression tests pass.

✅ 3 resolved
Quality: Test leaks isTabExpanded; order-dependent side-panel tests

📄 openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.test.tsx:185-199 📄 openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.test.tsx:681-691
mockUseTestCaseStore is a shared mutable object and afterEach (lines 180-187) never resets isTabExpanded, which defaults to false. Once 'Should render component' (line 192) sets it to true, every later test inherits true. 'renders the result history chart above the parameters' (line 681) never sets it itself yet asserts on parameter-container, which only renders when resolveIsSidePanelVisible is true (showSidePanel ?? isTabExpanded, showSidePanel is undefined here). So that test passes only because of leaked state and will fail if run in isolation or reordered. Reset isTabExpanded in afterEach and set it explicitly in the test that needs the panel visible.

Quality: Duplicate enableAiAppMode helper diverges from canonical one

📄 openmetadata-ui/src/main/resources/ui/playwright/utils/appMode.ts:29-36 📄 openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/DataQuality/TestCaseDetailsPage.spec.ts:17
A brand-new playwright/utils/appMode.ts reimplements enableAiAppMode, which already exists at playwright/e2e/Utils/appMode.ts and is the canonical helper imported by every other AppMode spec (AppModeCrossDevice, AppModeResolver, AppModeRouteIsolation, etc.). Only this new spec imports the duplicate. The two implementations diverge: the canonical one also stubs the boot GET /users/{id}/preferences response and seeds the cross-tab omAppModeHint, plus a per-page dedupe guard, whereas the new one only seeds the session tuple. The new version happens to work today because hydrateAndResolveAppMode skips the boot write for a tuple with source !== 'boot' (confirmed in AuthProvider.tsx), but relying on that single signal without the preferences stub is less robust and the two files will drift. Delete the new file and import enableAiAppMode from ../../Utils/appMode like the sibling specs.

Bug: table is never instantiated in beforeAll — all tests crash

📄 openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/DataQuality/TestCaseDetailsPage.spec.ts:27 📄 openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/DataQuality/TestCaseDetailsPage.spec.ts:41-46
table is declared as let table!: TableClass; and the comment says it is "Created in beforeAll", but beforeAll never runs table = new TableClass(). It goes straight to await table.create(apiContext) on line 46, so table is undefined and every test in this spec throws Cannot read properties of undefined (reading 'create') during setup. The definite-assignment assertion (!) suppresses the compile error that would have caught this. Add table = new TableClass(); as the first line of the beforeAll callback.

Options

Display: compact → Counting what did not apply, without listing it.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

🚦 Removed from the merge queue — failed_checks (2026-09-10T20:43:17Z)

Blocked the queue: playwright-summary

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

safe to test Add this label to run secure Github workflows on PRs UI UI specific issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants