Skip to content

feat(app): hover hint and native link affordance for dashboard table tile row click#2321

Merged
kodiakhq[bot] merged 4 commits into
mainfrom
alex/table-tile-onclick-hover-hint
May 28, 2026
Merged

feat(app): hover hint and native link affordance for dashboard table tile row click#2321
kodiakhq[bot] merged 4 commits into
mainfrom
alex/table-tile-onclick-hover-hint

Conversation

@alex-fedotyev
Copy link
Copy Markdown
Contributor

@alex-fedotyev alex-fedotyev commented May 20, 2026

Summary

When a dashboard table tile is configured with an onClick action (#2140, #2141, #2146, #2148), the row click destination is now discoverable before the user commits to the click.

What's new for users:

  • Hover hint. After ~250ms of hover, a small card above the row reads Search HyperDX Logs or Open dashboard "API Latency Drilldown" (or generic Open in search / Open dashboard when the target is templated or the named source / dashboard no longer exists).
  • Native browser behaviors. The cell wrapper is now a real <a href>. Cmd-click opens the destination in a new tab, middle-click opens it in a new tab, right-click shows the browser context menu with "Open in New Tab" and "Copy Link Address", and the destination URL appears in the status bar on hover.
  • Keyboard navigation. Tab focuses the first clickable cell with a visible focus ring; Enter activates it.

Screenshots

Search action: hovering a row reveals the resolved source name.

Light Dark
Search onClick hover hint, light theme Search onClick hover hint, dark theme

Dashboard action: hovering a row reveals the resolved dashboard name.

Light Dark
Dashboard onClick hover hint, light theme Dashboard onClick hover hint, dark theme

How the implementation changes:

  • packages/app/src/HDXMultiSeriesTableChart.tsx: cell wrapper goes from <div role="link" tabIndex={0}> plus manual onClick / onAuxClick / onMouseDown / onKeyDown handlers to a Next.js <Link href> with prefetch={false}. The HoverCard wraps the whole <tr> at the row body level so the hint position stays stable as the cursor moves across cells; cell-level mounting would flicker per column. Rows whose templates fail to resolve render as a real <button type="button"> (not <a href="#">) so cmd-click / middle-click / right-click "Open in New Tab" can't silently open a meaningless new tab against a # fragment.
  • packages/app/src/components/DBTableChart.tsx: drops the parent onRowClick cmd/middle-click branching; threads new getRowAction (or legacy getRowSearchLink) into Table.
  • packages/common-utils/src/core/linkUrlBuilder.ts: new describeOnClick({ onClick, sourceNamesById, dashboardNamesById }): string helper returns the one-line hint, with an exhaustiveness check on the OnClick discriminator.
  • packages/app/src/hooks/useOnClickLinkBuilder.ts: also builds Map<id, name> for sources and dashboards, computes the row-independent description once, and returns a per-row resolver of shape { url, description, onClickError? }. Per-row results are memoized internally (WeakMap) so cells sharing a row don't rerun handlebars rendering. When a row's templates fail to resolve, url is null and onClickError fires the existing Mantine "Link error" toast on click.
  • Focus ring uses the shared styles/focus.module.scss focusRing style.
  • Cell wrappers carry data-testid="dashboard-table-row-action" on both branches; the e2e page object resolves by testid so future inline column links don't steal the click.
  • The legacy getRowSearchLink drilldown path (used outside dashboards, e.g. the services dashboard) renders as a plain <Link href> without a HoverCard so behavior there is unchanged.

Test plan

  • make ci-lint clean across all 3 workspaces.
  • make ci-unit clean. New HDXMultiSeriesTableChart component test covers both success and failure branches end to end: anchor / button shape, onClickError wiring, row-level HoverCard hint visibility, legacy getRowSearchLink fallback.
  • describeOnClick unit tests cover all 6 OnClickSchema discriminator + name-lookup combinations.
  • useOnClickLinkBuilder hook tests cover: no onClick configured returns null, resolved source name in description, resolved dashboard name in description, row resolution failure encodes as url: null + click handler fires notification, WeakMap caching shares results across cells of the same row.
  • knip clean (no new unused exports).
  • UI verified in the dev stack (screenshots above). Status bar shows the destination URL on the success branch; failure branch (a <button>) shows no status bar URL and clicking fires the existing red Link error toast. Right-click on a success anchor shows the native context menu; cmd-click and middle-click open in a new tab.
  • Both light and dark theme verified.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview, Comment May 28, 2026 3:09pm
hyperdx-storybook Error Error May 28, 2026 3:09pm

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 20, 2026

🦋 Changeset detected

Latest commit: a664160

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@hyperdx/common-utils Patch
@hyperdx/app Patch
@hyperdx/api Patch
@hyperdx/otel-collector Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added the review/tier-3 Standard — full human review required label May 20, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 20, 2026

🟡 Tier 3 — Standard

Introduces new logic, modifies core functionality, or touches areas with non-trivial risk.

Why this tier:

  • Diff size: 357 production lines changed (Tier 2 max: < 250)
  • Cross-layer change: touches frontend (packages/app) + shared utils (packages/common-utils)

Review process: Full human review — logic, architecture, edge cases.
SLA: First-pass feedback within 1 business day.

Stats
  • Production files changed: 5
  • Production lines changed: 357 (+ 423 in test files, excluded from tier calculation)
  • Branch: alex/table-tile-onclick-hover-hint
  • Author: alex-fedotyev

To override this classification, remove the review/tier-3 label and apply a different review/tier-* label. Manual overrides are preserved on subsequent pushes.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 20, 2026

E2E Test Results

All tests passed • 191 passed • 3 skipped • 1216s

Status Count
✅ Passed 191
❌ Failed 0
⚠️ Flaky 4
⏭️ Skipped 3

Tests ran across 4 shards in parallel.

View full report →

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 20, 2026

Deep Review

This PR is a UI-affordance change touching ~600 LOC across a table component, a hook, a helper, and tests. No auth, data, or migration code. After dedup, cross-reviewer corroboration, and default-down regrading, there are no concrete P0/P1 failure modes introduced by the diff — the issues cluster around missing tests for the headline behaviors and several P3 polish items.

✅ No critical issues found.

🟡 P2 -- recommended

  • packages/app/src/__tests__/HDXMultiSeriesTableChart.test.tsx -- the PR's headline UX claims (cmd-click / middle-click open in new tab; Enter activates; focus ring visible) have no direct test; existing unit tests only assert tagName === 'A' and that href is present, which would pass even if a future change added a parent handler that preventDefaults modifier-key navigation.
    • Fix: add a unit test that fires a click with metaKey: true (or ctrlKey on linux) against the rendered anchor and asserts navigation isn't suppressed, plus a fireEvent.keyDown({ key: 'Enter' }) test asserting activation.
    • testing, adversarial, julik-frontend-races, api-contract, kieran-typescript
  • packages/app/src/HDXMultiSeriesTableChart.tsx -- the row-level Mantine Tooltip.Floating exposes the destination hint only via onMouseEnter and does not set aria-describedby on the cell wrapper, so keyboard-only and screen-reader users get no equivalent of the visible "Search HyperDX Logs" / "Open dashboard …" hint that the PR headlines as the user-facing improvement.
    • Fix: add aria-describedby (or aria-label derived from rowAction.description) on the <Link> / <button> so AT users hear the destination before activating, and pair Tooltip.Floating with focus-driven open events.
    • adversarial
  • packages/app/src/__tests__/HDXMultiSeriesTableChart.test.tsx -- there is no assertion that the legacy getRowSearchLink branch returning null falls through to a plain <div> (no anchor, no button); a regression that accidentally renders a Link with href="#" or wires a stale onClickError would not be caught.
    • Fix: add a test that passes getRowSearchLink={() => null} and asserts the cell is not a focusable interactive element.
    • testing
🔵 P3 nitpicks (12)
  • packages/app/src/HDXMultiSeriesTableChart.tsx:62,69,177,382 -- inline comments and prop docs describe wrapping the row in a HoverCard, but the implementation uses Tooltip.Floating; a reader searching HoverCard will not find the wrapping element.
    • Fix: replace the four "HoverCard" mentions with "Tooltip.Floating" (or "hover hint tooltip") so comments match the JSX.
    • testing, project-standards, julik-frontend-races, kieran-typescript
  • packages/common-utils/src/core/linkUrlBuilder.ts:281-284 -- the exhaustiveness branch declares const _exhaustive: never = onClick then return _exhaustive, so if OnClickSchema ever grows a variant at runtime (e.g. an out-of-sync deploy) the function returns undefined cast to string and silently produces an empty hint.
    • Fix: replace return _exhaustive with throw new Error('Unhandled OnClick variant: ' + JSON.stringify(onClick)) (or a shared assertNever) so a schema drift fails loud.
    • maintainability
  • packages/app/src/hooks/useOnClickLinkBuilder.ts:25-29 -- RowAction is a flat { url: string | null; description; onClickError? } rather than a discriminated union, so the cell renderer must reverse-engineer the (url truthy / onClickError present) combination and an implementation regression that drops onClickError from the failure branch still typechecks.
    • Fix: model the type as { kind: 'link'; url; description } | { kind: 'error'; description; onClickError } so the cell renderer can switch on kind and TS enforces both branches set their required fields.
    • kieran-typescript
  • packages/app/src/HDXMultiSeriesTableChart.tsx:395,414-423 -- every <td> carries title={${cell.getValue()}}, so on the success path the browser's native title tooltip fires ~500 ms after Tooltip.Floating mounts the destination hint, leaving two overlapping tooltips with conflicting information; on the failure path only the raw-value title shows, never the destination context.
    • Fix: drop the title attribute on cells whose row resolves to a rowAction (or set it conditionally) so the row-level destination hint is the sole tooltip.
    • adversarial, julik-frontend-races
  • packages/app/src/hooks/useOnClickLinkBuilder.ts:118-135 -- compute() writes description on the failure branch (url: null) even though Tooltip.Floating is suppressed for failure rows, leaving the success-case copy ("Search HyperDX Logs") as a live but dead field that a future a11y refactor could silently surface as a misleading aria-label.
    • Fix: drop description from the failure shape (matches the discriminated-union refactor) or expose a separate failureDescription so the failure branch can't accidentally inherit success copy.
    • kieran-typescript
  • packages/app/src/HDXMultiSeriesTableChart.tsx:189-227 -- the cell wrapper carries both data-testid="dashboard-table-row-action" (shared across branches) and data-shape="link" | "button"; the existing tests already discriminate by tagName === 'A' | 'BUTTON', so data-shape is redundant production-DOM instrumentation that exists only for tests.
    • Fix: drop data-shape and let tests discriminate by tagName; keep the single data-testid for cross-branch e2e selection.
    • maintainability
  • packages/app/styles/focus.module.scss:7-27 -- .cellButton is a single-consumer reset for HDXMultiSeriesTableChart.tsx's failure-row button, sitting next to the shared .focusRing rule and re-declaring the same :focus-visible outline rather than composing it; the shared file is no longer single-purpose.
    • Fix: colocate .cellButton with the table component as a local SCSS module (or composes: focusRing from './focus.module.scss') so the shared file holds only multi-consumer focus styles.
    • maintainability
  • packages/app/src/HDXMultiSeriesTableChart.tsx -- file grows from 365 to ~442 lines, further over the documented 300-line cap; the new cell renderer (<Link> / <button> / Tooltip.Floating branches) is a natural extraction.
    • Fix: extract the row-action cell renderer into a small component (e.g. RowActionCell) in a follow-up; preserve the cap going forward.
    • project-standards
  • packages/app/src/HDXMultiSeriesTableChart.tsx:61-72 -- Table accepts both getRowAction and getRowSearchLink as independently optional props with no type-level mutual exclusion; the precedence rule "getRowAction wins" lives only in DBTableChart's caller-side ternary and a code comment.
    • Fix: model the prop as a union (action?: { kind: 'rowAction'; resolve } | { kind: 'searchLink'; resolve }) so a future caller that passes both gets a TS error instead of a silent ignore.
    • kieran-typescript, maintainability
  • packages/app/src/hooks/__tests__/useOnClickLinkBuilder.test.tsx:89-102 -- the cache test calls result.current!(row) twice within a single render and asserts reference equality; it does not rerender with stable deps, so a regression that broadens the useMemo dep array (e.g. an inline object literal in deps) creates a fresh WeakMap per render and the test still passes.
    • Fix: add a second rerender(...) with the same inputs and same row reference, then assert equality across the rerender; also add a test with two structurally identical but referentially distinct rows asserting independent compute paths.
    • testing, kieran-typescript
  • packages/app/src/HDXMultiSeriesTableChart.tsx:175-215 -- the per-cell focusable wrapper means a 10-row × 6-column tile creates 60 sequential tab stops that all activate the same per-row destination, preserved (and now amplified by the new focus ring) from the prior div role="link" tabIndex={0} pattern.
    • Fix: make only the first interactive cell per row tabbable (tabIndex={-1} on the rest) so keyboard users get one tab stop per row instead of cols.
    • adversarial, julik-frontend-races
  • packages/app/src/__tests__/HDXMultiSeriesTableChart.test.tsx:161 -- the hint negative-case test hard-codes setTimeout(resolve, 250) to give Tooltip.Floating time to mount, which is flake-prone (Mantine internals or JSDOM event-loop changes could break it) and asserts a 250ms-delay invariant the implementation does not have.
    • Fix: replace the fixed 250ms wait with a waitFor guarding the absence of the tooltip text, or rewrite the test to assert that rowAction.url === null means the Tooltip.Floating wrapper isn't rendered at all.
    • testing

Reviewers (11): correctness, testing, maintainability, project-standards, agent-native, learnings-researcher, adversarial, julik-frontend-races, kieran-typescript, api-contract, reliability.

Testing gaps:

  • No unit or e2e test exercises modifier-key (metaKey / ctrlKey) or middle-button click on the new anchor; the headline "native cmd-click opens in new tab" claim is uncovered.
  • No test asserts the focusRing class is applied to the rendered anchor / button (focus-visible CSS is browser-only, but the class composition itself is testable).
  • No test pins the silent-render invariant for the failure branch at scale (e.g. 100 unresolvable rows must produce zero render-time notifications); only the single-row case is covered.
  • E2E [data-testid="dashboard-table-row-action"] matches both success <a> and failure <button>, so a regression where rows silently degrade to the button branch would still pass clickFirstTableRow().first().click() until a downstream URL assertion fires.

@alex-fedotyev
Copy link
Copy Markdown
Contributor Author

Pushed aa16b21d addressing the deep-review findings.

P0 fix: failure rows now render as a real <button type="button"> instead of <a href="#">. Cmd-click, middle-click, and right-click "Open in New Tab" no longer offer a meaningless # target; the error toast still fires on left-click.

P2 fixes:

  • HoverCard now wraps the whole <tr> once at the row body level instead of one HoverCard per cell. Hint position stays stable across horizontal cursor movement; no per-column flicker.
  • getRowAction is computed once per row; the hook caches by row reference (WeakMap) so per-cell calls share the result. No more handlebars + URLSearchParams build per cell per render.
  • <Link> now uses prefetch={false} so virtualized scroll doesn't trigger an N-row prefetch storm against /search? and /dashboards/ routes.
  • New HDXMultiSeriesTableChart component test covers both branches end to end: success anchor, failure button + onClickError wiring, row-level HoverCard hint visibility, legacy getRowSearchLink fallback.

Smaller cleanups picked up along the way:

  • describeOnClick does an explicit exhaustiveness check on the OnClick discriminator (adds a third variant -> type error).
  • onClickError is typed React.MouseEvent<HTMLButtonElement>.
  • Cell wrappers carry data-testid="dashboard-table-row-action" on both branches; the e2e page object resolves by testid.
  • Hook test asserts URL params via URLSearchParams instead of position-coupled regex.

Screenshots in the description show the hover hint working on both search and dashboard targets, in light and dark theme.

@pulpdrew
Copy link
Copy Markdown
Contributor

Given a case where a link is invalid for some rows (typically using a templated dashboard name), the invalid rows are rendered as buttons with different styles than the valid rows which are links. Also odd that in that case the tooltip still shows up

Screenshot 2026-05-21 at 3 22 28 PM

IMO the placement of the tooltip is odd, it should be right where the cursor is instead of in the middle of the row

Screenshot 2026-05-21 at 3 24 33 PM

pulpdrew
pulpdrew previously approved these changes May 21, 2026
Copy link
Copy Markdown
Contributor

@pulpdrew pulpdrew left a comment

Choose a reason for hiding this comment

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

LGTM, with a few suggestions

Comment on lines +200 to +201
// notification toast on left-click; the proper "muted row
// + warning icon" preempt state is tracked as AC8.
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.

nit - comments tied to specific prompts are just clutter

Suggested change
// notification toast on left-click; the proper "muted row
// + warning icon" preempt state is tracked as AC8.
// notification toast on left-click;

@alex-fedotyev
Copy link
Copy Markdown
Contributor Author

Done in dd50d56 (removed the internal AC tracking note from the button fallback comment, per your suggestion).

@alex-fedotyev alex-fedotyev force-pushed the alex/table-tile-onclick-hover-hint branch from dd50d56 to 5def143 Compare May 22, 2026 00:19
alex-fedotyev added a commit that referenced this pull request May 22, 2026
…re rows

Addresses three rendering issues Drew flagged on #2321 after
approval:

- Failure rows now share a single .cellButton SCSS reset with the
  success-row <Link>, so the cell wrapper renders identically
  across branches. The user-agent button defaults (padding, font,
  color, text-align, line-height) were leaking through.
- Hover hint is suppressed when action.url === null. The previous
  state showed an "Open in search" hint on a row whose click would
  only fire an error toast, which lied to the user.
- Row-level HoverCard (position="top") replaced with
  Tooltip.Floating wrapping the <tr>. The hint now follows the
  cursor at the cell rather than anchoring at row-center-top.

Tests updated: the failure-row hint test now asserts the hint is
absent; a success-row positive test was added. Both branches get
a data-shape attribute so the test assertions don't couple to the
CSS-module hash.
@alex-fedotyev
Copy link
Copy Markdown
Contributor Author

Fixed in 19c0204e:

  • Visual parity: shared SCSS reset on the fallback <button> so the wrapper renders identically to the success-row <Link>. The padding / font / color / text-align / line-height that the user-agent button defaults were leaking through are now reset.
  • Hint is suppressed on rows where the templates don't resolve (action.url === null), so the cursor never sees an "Open in search" promise the click won't keep.
  • Row-level HoverCard (position="top") replaced with Tooltip.Floating wrapping the <tr>. The hint now follows the cursor near the cell instead of centering above the row.

One quirk to flag: Mantine v9's Tooltip.Floating doesn't expose an openDelay, so the hint appears instantly instead of after 250ms. Happy to add a small useHover + setTimeout wrapper if you'd prefer the delayed behavior back.

Also re-applied the comment cleanup from dd50d56 (your inline suggestion to drop the internal AC tracking note from the button comment). It was on the branch briefly but the post-approval rebase clobbered it before I could push this fix; folded it into this commit.

ci-lint + ci-unit + knip green locally.

pulpdrew
pulpdrew previously approved these changes May 25, 2026
Copy link
Copy Markdown
Contributor

@pulpdrew pulpdrew left a comment

Choose a reason for hiding this comment

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

LGTM

prefetch={false}
className={interactiveClassName}
data-testid="dashboard-table-row-action"
data-shape="link"
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.

This seems pretty unnecessary. If the tests are already asserting on the element type, this is just saying the same thing as the element type (link or button).

alex-fedotyev added a commit that referenced this pull request May 27, 2026
…re rows

Addresses three rendering issues Drew flagged on #2321 after
approval:

- Failure rows now share a single .cellButton SCSS reset with the
  success-row <Link>, so the cell wrapper renders identically
  across branches. The user-agent button defaults (padding, font,
  color, text-align, line-height) were leaking through.
- Hover hint is suppressed when action.url === null. The previous
  state showed an "Open in search" hint on a row whose click would
  only fire an error toast, which lied to the user.
- Row-level HoverCard (position="top") replaced with
  Tooltip.Floating wrapping the <tr>. The hint now follows the
  cursor at the cell rather than anchoring at row-center-top.

Tests updated: the failure-row hint test now asserts the hint is
absent; a success-row positive test was added. Both branches get
a data-shape attribute so the test assertions don't couple to the
CSS-module hash.
@alex-fedotyev alex-fedotyev force-pushed the alex/table-tile-onclick-hover-hint branch from 19c0204 to 4aebdb7 Compare May 27, 2026 18:25
@alex-fedotyev
Copy link
Copy Markdown
Contributor Author

Rebased onto current main (commit 4aebdb7c). Single conflict in packages/app/tests/e2e/page-objects/DashboardPage.ts between fix-pack 1's JSDoc rewrite (the one that switched the helper to the dashboard-table-row-action testid selector) and main's reorganization for the unified DashboardContainer + source-scoped filters work. Took fix-pack 1's version since it matches the current shape of the cells (testid on both the success anchor and the failure button).

Net change vs the previous tip on that file is the same single hunk you reviewed; everything else is just trailing main forward. Local checks pass: make ci-lint clean, linkUrlBuilder (48 tests) and HDXMultiSeriesTableChart + useOnClickLinkBuilder (11 tests) all green, no new knip findings, tier still 3.

Alex Fedotyev and others added 3 commits May 28, 2026 14:50
…tile row click

When a dashboard table tile is configured with an `onClick` action (search
or dashboard link), the row click destination is now visible before the
user clicks. After ~250ms of hover, a small card appears with text like
`Search HyperDX Logs` or `Open dashboard "API Latency Drilldown"`.

The cell wrapper switches from a manual `<div role="link">` with
hand-rolled cmd-click / middle-click / Enter handlers to a Next.js
`<Link href>`. The browser now handles cmd-click and middle-click
opening in a new tab natively, right-click shows "Open in New Tab" /
"Copy Link Address" in the context menu, the destination URL appears in
the status bar on hover, and keyboard users can Tab to a cell and press
Enter to navigate with a visible focus ring.

The cell wrapper now mirrors the pattern in `DBListBarChart.tsx` (the
only other dashboard chart with a row drilldown HoverCard).

A new `describeOnClick` helper in common-utils renders the one-line
hint. The hook returns the description alongside the URL so future hint
surfaces (chart-header subtitle, scope preview) can reuse the same
string.
P0 fix:
- Failure rows now render as <button type="button"> instead of
  <a href="#">. The previous anchor exposed cmd-click, middle-click,
  and right-click "Open in New Tab" against a # fragment, which the
  React onClick handler couldn't preventDefault on (auxclick doesn't
  fire click). A real button has no native navigation, so those code
  paths now do nothing for failure rows and the error toast still
  fires on left-click.

P2 fixes:
- The HoverCard now wraps the whole <tr> in the body loop instead
  of mounting one HoverCard per cell. Hovering anywhere on the row
  shows a stable hint; cursor movement between cells no longer
  flickers a different dropdown per column.
- getRowAction is now computed once per row and the hook caches by
  row reference (WeakMap). The handlebars + URLSearchParams build
  no longer reruns for every cell on every render.
- <Link> now uses prefetch={false}. Virtualized scroll no longer
  triggers an N-row prefetch storm against /search? and /dashboards
  routes the user usually never opens in bulk.
- Added a component-level test (HDXMultiSeriesTableChart.test.tsx)
  that exercises both success and failure branches end to end:
  asserts the anchor / button shape, the onClickError wiring, the
  row-level HoverCard hint visibility, and the legacy
  getRowSearchLink fallback.

Smaller cleanups:
- describeOnClick now does an explicit exhaustiveness check on the
  OnClick discriminator so adding a third variant fails type-check.
- onClickError is typed as React.MouseEvent<HTMLButtonElement>.
- The cell wrapper carries data-testid="dashboard-table-row-action"
  on both branches; e2e page object resolves by testid so future
  inline column links don't steal the click.
- Hook test asserts URL params via URLSearchParams instead of
  position-coupled regex.
…re rows

Addresses three rendering issues Drew flagged on #2321 after
approval:

- Failure rows now share a single .cellButton SCSS reset with the
  success-row <Link>, so the cell wrapper renders identically
  across branches. The user-agent button defaults (padding, font,
  color, text-align, line-height) were leaking through.
- Hover hint is suppressed when action.url === null. The previous
  state showed an "Open in search" hint on a row whose click would
  only fire an error toast, which lied to the user.
- Row-level HoverCard (position="top") replaced with
  Tooltip.Floating wrapping the <tr>. The hint now follows the
  cursor at the cell rather than anchoring at row-center-top.

Tests updated: the failure-row hint test now asserts the hint is
absent; a success-row positive test was added. Both branches get
a data-shape attribute so the test assertions don't couple to the
CSS-module hash.
@kodiakhq kodiakhq Bot merged commit b5148c8 into main May 28, 2026
18 of 19 checks passed
@kodiakhq kodiakhq Bot deleted the alex/table-tile-onclick-hover-hint branch May 28, 2026 15:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automerge review/tier-3 Standard — full human review required

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants